aboutsummaryrefslogtreecommitdiff
path: root/camera/jpeg_10/msm_jpeg_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'camera/jpeg_10/msm_jpeg_sync.c')
-rw-r--r--camera/jpeg_10/msm_jpeg_sync.c1579
1 files changed, 1579 insertions, 0 deletions
diff --git a/camera/jpeg_10/msm_jpeg_sync.c b/camera/jpeg_10/msm_jpeg_sync.c
new file mode 100644
index 00000000..d6b76532
--- /dev/null
+++ b/camera/jpeg_10/msm_jpeg_sync.c
@@ -0,0 +1,1579 @@
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/ratelimit.h>
+#include <lenovo_media/msm_jpeg.h>
+#include <linux/msm-bus.h>
+#include "msm_jpeg_sync.h"
+#include "msm_jpeg_core.h"
+#include "msm_jpeg_platform.h"
+#include "msm_jpeg_common.h"
+#include "cam_hw_ops.h"
+
+#define JPEG_REG_SIZE 0x308
+#define JPEG_DEV_CNT 4
+#define JPEG_DEC_ID 2
+#define UINT32_MAX (0xFFFFFFFFU)
+
+#ifdef CONFIG_COMPAT
+
+#define MSM_JPEG_IOCTL_GET_HW_VERSION32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 1, struct msm_jpeg_hw_cmd32)
+
+#define MSM_JPEG_IOCTL_RESET32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 2, struct msm_jpeg_ctrl_cmd32)
+
+#define MSM_JPEG_IOCTL_STOP32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 3, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_START32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 4, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 5, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_INPUT_GET32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 6, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 8, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_OUTPUT_GET32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 9, struct msm_jpeg_buf32)
+
+#define MSM_JPEG_IOCTL_EVT_GET32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 11, struct msm_jpeg_ctrl_cmd32)
+
+#define MSM_JPEG_IOCTL_HW_CMD32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 13, struct msm_jpeg_hw_cmd32)
+
+#define MSM_JPEG_IOCTL_HW_CMDS32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 14, struct msm_jpeg_hw_cmds32)
+
+#define MSM_JPEG_IOCTL_TEST_DUMP_REGION32 \
+ _IOW(MSM_JPEG_IOCTL_MAGIC, 15, compat_ulong_t)
+
+struct msm_jpeg_ctrl_cmd32 {
+ uint32_t type;
+ uint32_t len;
+ compat_uptr_t value;
+};
+struct msm_jpeg_buf32 {
+ uint32_t type;
+ int fd;
+
+ compat_uptr_t vaddr;
+
+ uint32_t y_off;
+ uint32_t y_len;
+ uint32_t framedone_len;
+
+ uint32_t cbcr_off;
+ uint32_t cbcr_len;
+
+ uint32_t num_of_mcu_rows;
+ uint32_t offset;
+ uint32_t pln2_off;
+ uint32_t pln2_len;
+};
+
+struct msm_jpeg_hw_cmd32 {
+
+ uint32_t type:4;
+
+ /* n microseconds of timeout for WAIT */
+ /* n microseconds of time for DELAY */
+ /* repeat n times for READ/WRITE */
+ /* max is 0xFFF, 4095 */
+ uint32_t n:12;
+ uint32_t offset:16;
+ uint32_t mask;
+ union {
+ uint32_t data; /* for single READ/WRITE/WAIT, n = 1 */
+ compat_uptr_t pdata; /* for multiple READ/WRITE/WAIT, n > 1 */
+ };
+};
+
+struct msm_jpeg_hw_cmds32 {
+ uint32_t m; /* number of elements in the hw_cmd array */
+ struct msm_jpeg_hw_cmd32 hw_cmd[1];
+};
+#endif
+
+
+inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+inline void *msm_jpeg_q_out(struct msm_jpeg_q *q_p)
+{
+ unsigned long flags;
+ struct msm_jpeg_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q, struct msm_jpeg_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ JPEG_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+ q_p->name);
+ }
+
+ return data;
+}
+
+inline int msm_jpeg_q_in(struct msm_jpeg_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_jpeg_q_entry *q_entry_p;
+
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_jpeg_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ JPEG_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+inline int msm_jpeg_q_in_buf(struct msm_jpeg_q *q_p,
+ struct msm_jpeg_core_buf *buf)
+{
+ struct msm_jpeg_core_buf *buf_p;
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_jpeg_core_buf));
+
+ msm_jpeg_q_in(q_p, buf_p);
+ return 0;
+}
+
+inline int msm_jpeg_q_wait(struct msm_jpeg_q *q_p)
+{
+ long tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+ int rc;
+
+ JPEG_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+ JPEG_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ JPEG_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+ q_p->name);
+ } else if (q_p->unblck) {
+ JPEG_DBG("%s:%d] %s unblock is true\n", __func__,
+ __LINE__, q_p->name);
+ q_p->unblck = 0;
+ rc = -ECANCELED;
+ }
+ }
+ return rc;
+}
+
+inline int msm_jpeg_q_wakeup(struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_jpeg_q_unblock(struct msm_jpeg_q *q_p)
+{
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = 1;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline void msm_jpeg_outbuf_q_cleanup(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_q *q_p)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ buf_p = msm_jpeg_q_out(q_p);
+ if (buf_p) {
+ msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl,
+ buf_p->ion_fd);
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(buf_p);
+ }
+ } while (buf_p);
+ q_p->unblck = 0;
+}
+
+inline void msm_jpeg_q_cleanup(struct msm_jpeg_q *q_p)
+{
+ void *data;
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_jpeg_q_out(q_p);
+ if (data) {
+ JPEG_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_jpeg_framedone_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ int rc = 0;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ if (buf_in) {
+ buf_in->vbuf.framedone_len = buf_in->framedone_len;
+ buf_in->vbuf.type = MSM_JPEG_EVT_SESSION_DONE;
+ JPEG_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+ __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len,
+ buf_in->vbuf.framedone_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, buf_in);
+ } else {
+ JPEG_PR_ERR("%s:%d] no output return buffer\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+ return rc;
+}
+
+int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev,
+ void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_ctrl_cmd ctrl_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_jpeg_q_wait(&pgmn_dev->evt_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->evt_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
+ ctrl_cmd.type = buf_p->vbuf.type;
+ kfree(buf_p);
+
+ if (ctrl_cmd.type == MSM_JPEG_EVT_SESSION_DONE) {
+ /* update the bw with zeroth vector */
+ msm_camera_update_bus_vector(pgmn_dev->bus_client, 0);
+ JPEG_BUS_UNVOTED(pgmn_dev);
+ JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__);
+ }
+
+ JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+ (unsigned long) ctrl_cmd.value, ctrl_cmd.len);
+
+ if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+ JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_evt_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->evt_q);
+ return 0;
+}
+
+void msm_jpeg_reset_ack_irq(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_jpeg_err_irq(struct msm_jpeg_device *pgmn_dev,
+ int event)
+{
+ int rc = 0;
+ struct msm_jpeg_core_buf buf;
+
+ JPEG_PR_ERR("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+ buf.vbuf.type = MSM_JPEG_EVT_ERR;
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->evt_q, &buf);
+ if (!rc)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->evt_q);
+
+ if (!rc)
+ JPEG_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+ return;
+}
+
+/*************** output queue ****************/
+
+int msm_jpeg_we_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_jpeg_core_buf *buf_out;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+ } else {
+ JPEG_DBG("%s:%d] no output return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ return rc;
+ }
+
+ buf_out = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_out->y_buffer_addr, buf_out->y_len);
+ rc = msm_jpeg_core_we_buf_update(pgmn_dev, buf_out);
+ kfree(buf_out);
+ } else {
+ msm_jpeg_core_we_buf_reset(pgmn_dev, buf_in);
+ JPEG_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->output_rtn_q);
+
+ return rc;
+}
+
+int msm_jpeg_output_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_jpeg_q_wait(&pgmn_dev->output_rtn_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->output_rtn_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no output buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd);
+ kfree(buf_p);
+
+ JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+ (unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ JPEG_PR_ERR("%s:%d]", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_output_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->output_rtn_q);
+ return 0;
+}
+
+static inline int msm_jpeg_add_u32_check(uint32_t *p, uint32_t n, uint32_t *res)
+{
+ *res = 0;
+
+ while (n--) {
+ if ((*res + *p) < *res)
+ return -EFAULT;
+ *res += *p++;
+ }
+ return 0;
+}
+
+int msm_jpeg_output_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_jpeg_buf buf_cmd;
+ struct msm_jpeg_core_buf *buf_p;
+ uint32_t buf_len_params[10];
+ uint32_t total_len = 0;
+ int n = 0;
+
+ memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_len_params[n++] = buf_cmd.y_len;
+ buf_len_params[n++] = buf_cmd.cbcr_len;
+ buf_len_params[n++] = buf_cmd.pln2_len;
+ buf_len_params[n++] = buf_cmd.offset;
+ buf_len_params[n++] = buf_cmd.y_off;
+ if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+
+ JPEG_DBG("%s:%d] vaddr = 0x%08lx y_len = %d\n, fd = %d",
+ __func__, __LINE__, (unsigned long) buf_cmd.vaddr,
+ buf_cmd.y_len, buf_cmd.fd);
+
+ buf_p->ion_fd = buf_cmd.fd;
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
+ total_len, pgmn_dev->iommu_hdl);
+
+ if (!buf_p->y_buffer_addr) {
+ JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EFAULT;
+ }
+
+ buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off;
+
+ if (buf_cmd.cbcr_len)
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+ buf_cmd.y_len;
+ else
+ buf_p->cbcr_buffer_addr = 0x0;
+
+ if (buf_cmd.pln2_len)
+ buf_p->pln2_addr = buf_p->cbcr_buffer_addr +
+ buf_cmd.cbcr_len;
+ else
+ buf_p->pln2_addr = 0x0;
+
+ JPEG_DBG("%s:%d]After v2p pln0_addr %x pln0_len %d",
+ __func__, __LINE__, buf_p->y_buffer_addr,
+ buf_cmd.y_len);
+
+ JPEG_DBG("pl1_len %d, pln1_addr %x, pln2_adrr %x,pln2_len %d",
+ buf_cmd.cbcr_len, buf_p->cbcr_buffer_addr,
+ buf_p->pln2_addr, buf_cmd.pln2_len);
+
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ buf_p->pln2_len = buf_cmd.pln2_len;
+ buf_p->vbuf = buf_cmd;
+
+ msm_jpeg_q_in(&pgmn_dev->output_buf_q, buf_p);
+ return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_jpeg_fe_pingpong_irq(struct msm_jpeg_device *pgmn_dev,
+ struct msm_jpeg_core_buf *buf_in)
+{
+ struct msm_jpeg_core_buf *buf_out;
+ int rc = 0;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ JPEG_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_jpeg_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+ } else {
+ JPEG_DBG("%s:%d] no input return buffer\n", __func__,
+ __LINE__);
+ rc = -EFAULT;
+ }
+
+ buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ rc = msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
+ kfree(buf_out);
+ msm_jpeg_core_fe_start(pgmn_dev);
+ } else {
+ JPEG_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ rc = -EFAULT;
+ }
+
+ if (buf_in)
+ rc = msm_jpeg_q_wakeup(&pgmn_dev->input_rtn_q);
+
+ return rc;
+}
+
+int msm_jpeg_input_get(struct msm_jpeg_device *pgmn_dev, void __user *to)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_wait(&pgmn_dev->input_rtn_q);
+ buf_p = msm_jpeg_q_out(&pgmn_dev->input_rtn_q);
+
+ if (!buf_p) {
+ JPEG_DBG("%s:%d] no input buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+
+ msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl, buf_p->ion_fd);
+ kfree(buf_p);
+
+ JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+ (unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ JPEG_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_input_get_unblock(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_q_unblock(&pgmn_dev->input_rtn_q);
+ return 0;
+}
+
+int msm_jpeg_input_buf_enqueue(struct msm_jpeg_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_jpeg_core_buf *buf_p;
+ struct msm_jpeg_buf buf_cmd;
+ uint32_t buf_len_params[10];
+ uint32_t total_len = 0;
+ int n = 0;
+
+ memset(&buf_cmd, 0x0, sizeof(struct msm_jpeg_buf));
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_jpeg_buf))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ buf_len_params[n++] = buf_cmd.y_len;
+ buf_len_params[n++] = buf_cmd.cbcr_len;
+ buf_len_params[n++] = buf_cmd.pln2_len;
+ buf_len_params[n++] = buf_cmd.offset;
+ buf_len_params[n++] = buf_cmd.y_off;
+ if (buf_cmd.cbcr_len)
+ buf_len_params[n++] = buf_cmd.cbcr_off;
+ if (buf_cmd.pln2_len)
+ buf_len_params[n++] = buf_cmd.pln2_off;
+
+ if (msm_jpeg_add_u32_check(buf_len_params, n, &total_len) < 0) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_jpeg_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ JPEG_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ JPEG_DBG("%s:%d] 0x%08lx %d\n", __func__, __LINE__,
+ (unsigned long) buf_cmd.vaddr, buf_cmd.y_len);
+
+ buf_p->ion_fd = buf_cmd.fd;
+ buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
+ total_len, pgmn_dev->iommu_hdl);
+
+ if (!buf_p->y_buffer_addr) {
+ JPEG_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EFAULT;
+ }
+
+ buf_p->y_buffer_addr += buf_cmd.offset + buf_cmd.y_off;
+
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ buf_p->pln2_len = buf_cmd.pln2_len;
+ buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+
+ if (buf_cmd.cbcr_len)
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr +
+ buf_cmd.y_len + buf_cmd.cbcr_off;
+ else
+ buf_p->cbcr_buffer_addr = 0x0;
+
+ if (buf_cmd.pln2_len)
+ buf_p->pln2_addr = buf_p->cbcr_buffer_addr +
+ buf_cmd.cbcr_len + buf_cmd.pln2_off;
+ else
+ buf_p->pln2_addr = 0x0;
+
+ JPEG_DBG("%s: y_addr=%x, y_len=%x, cbcr_addr=%x, cbcr_len=%d",
+ __func__, buf_p->y_buffer_addr, buf_p->y_len,
+ buf_p->cbcr_buffer_addr, buf_p->cbcr_len);
+ JPEG_DBG("pln2_addr = %x, pln2_len = %d, fd =%d\n",
+ buf_p->pln2_addr, buf_p->pln2_len, buf_cmd.fd);
+
+ buf_p->vbuf = buf_cmd;
+
+ msm_jpeg_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+ return 0;
+}
+
+int msm_jpeg_irq(int event, void *context, void *data)
+{
+ struct msm_jpeg_device *pgmn_dev =
+ (struct msm_jpeg_device *) context;
+
+ switch (event) {
+ case MSM_JPEG_EVT_SESSION_DONE:
+ msm_jpeg_framedone_irq(pgmn_dev, data);
+ msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_FE:
+ msm_jpeg_fe_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_WE:
+ msm_jpeg_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_RESET_ACK:
+ msm_jpeg_reset_ack_irq(pgmn_dev);
+ break;
+
+ case MSM_JPEG_HW_MASK_COMP_ERR:
+ default:
+ msm_jpeg_err_irq(pgmn_dev, event);
+ break;
+ }
+
+ return 0;
+}
+
+int __msm_jpeg_open(struct msm_jpeg_device *pgmn_dev)
+{
+ int rc;
+ irqreturn_t (*core_irq)(int, void *);
+ mutex_lock(&pgmn_dev->lock);
+ if (pgmn_dev->open_count) {
+ /* only open once */
+ JPEG_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EBUSY;
+ }
+ pgmn_dev->open_count++;
+ if (pgmn_dev->open_count == 1)
+ pgmn_dev->state = MSM_JPEG_INIT;
+
+ mutex_unlock(&pgmn_dev->lock);
+
+ rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+ CAM_AHB_SVS_VOTE);
+ if (rc < 0) {
+ pr_err("%s: failed to vote for AHB\n", __func__);
+ return rc;
+ }
+
+ msm_jpeg_core_irq_install(msm_jpeg_irq);
+ if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC)
+ core_irq = msm_jpeg_core_irq;
+ else
+ core_irq = msm_jpegdma_core_irq;
+
+ /* initialize the platform resources */
+ rc = msm_jpeg_platform_init(core_irq, pgmn_dev);
+ if (rc) {
+ JPEG_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ goto platform_init_fail;
+ }
+ JPEG_DBG("%s:%d] platform resources - base %p, irq %d\n",
+ __func__, __LINE__,
+ pgmn_dev->base, (int)pgmn_dev->jpeg_irq_res->start);
+ msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_buf_q);
+ msm_jpeg_core_init(pgmn_dev);
+
+ JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+
+platform_init_fail:
+ if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+ CAM_AHB_SUSPEND_VOTE) < 0)
+ pr_err("%s: failed to remove vote for AHB\n", __func__);
+ return rc;
+}
+
+int __msm_jpeg_release(struct msm_jpeg_device *pgmn_dev)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pgmn_dev->lock);
+ if (!pgmn_dev->open_count) {
+ JPEG_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EINVAL;
+ }
+ pgmn_dev->open_count--;
+ mutex_unlock(&pgmn_dev->lock);
+
+ msm_jpeg_core_release(pgmn_dev);
+ msm_jpeg_q_cleanup(&pgmn_dev->evt_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->output_buf_q);
+ msm_jpeg_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_jpeg_outbuf_q_cleanup(pgmn_dev, &pgmn_dev->input_buf_q);
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+ if (pgmn_dev->open_count)
+ JPEG_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+ /* release the platform resources */
+ msm_jpeg_platform_release(pgmn_dev);
+
+ JPEG_DBG("%s:%d]\n", __func__, __LINE__);
+
+ if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_JPEG,
+ CAM_AHB_SUSPEND_VOTE) < 0)
+ pr_err("%s: failed to remove vote for AHB\n", __func__);
+
+ return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmd(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_jpeg_hw_cmd hw_cmd;
+ int is_copy_to_user;
+
+ if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_jpeg_hw_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+ pgmn_dev->res_size, pgmn_dev->base);
+ JPEG_DBG(
+ "%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %lx\n",
+ __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+ hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ return is_copy_to_user;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ uint32_t len;
+ uint32_t m;
+ struct msm_jpeg_hw_cmds *hw_cmds_p;
+ struct msm_jpeg_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds)) /
+ sizeof(struct msm_jpeg_hw_cmd)))) {
+ JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_jpeg_hw_cmds) +
+ sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_jpeg_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(hw_cmd_p, m,
+ pgmn_dev->res_size, pgmn_dev->base);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ } else {
+ kfree(hw_cmds_p);
+ return is_copy_to_user;
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+int msm_jpeg_start(struct msm_jpeg_device *pgmn_dev, void * __user arg,
+ int (*hw_ioctl)(struct msm_jpeg_device *, void * __user))
+{
+ struct msm_jpeg_core_buf *buf_out;
+ struct msm_jpeg_core_buf *buf_out_free[2] = {NULL, NULL};
+ int i, rc;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_jpeg_platform_set_dt_config(pgmn_dev);
+
+ /* update the bw with vector index "1" */
+ msm_camera_update_bus_vector(pgmn_dev->bus_client, 1);
+ JPEG_BUS_VOTED(pgmn_dev);
+ JPEG_DBG("%s:%d] Bus Voted\n", __func__, __LINE__);
+
+ pgmn_dev->release_buf = 1;
+ for (i = 0; i < 2; i++) {
+ buf_out = msm_jpeg_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ msm_jpeg_core_fe_buf_update(pgmn_dev, buf_out);
+ kfree(buf_out);
+ } else {
+ JPEG_DBG("%s:%d] no input buffer\n", __func__,
+ __LINE__);
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ buf_out_free[i] = msm_jpeg_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out_free[i]) {
+ msm_jpeg_core_we_buf_update(pgmn_dev, buf_out_free[i]);
+ pgmn_dev->release_buf = 0;
+ } else {
+ JPEG_DBG("%s:%d] no output buffer\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ kfree(buf_out_free[i]);
+
+ JPEG_DBG_HIGH("%s:%d] START\n", __func__, __LINE__);
+ pgmn_dev->state = MSM_JPEG_EXECUTING;
+ /* ensure write is done */
+ wmb();
+ rc = hw_ioctl(pgmn_dev, arg);
+ /* ensure write is done */
+ wmb();
+ JPEG_DBG("%s:%d]", __func__, __LINE__);
+ return rc;
+}
+
+int msm_jpeg_ioctl_reset(struct msm_jpeg_device *pgmn_dev, void * __user arg)
+{
+ int rc;
+ struct msm_jpeg_ctrl_cmd ctrl_cmd, *p_ctrl_cmd;
+
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ p_ctrl_cmd = &ctrl_cmd;
+
+ if (pgmn_dev->state == MSM_JPEG_INIT) {
+ if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ pgmn_dev->op_mode = p_ctrl_cmd->type;
+
+ rc = msm_jpeg_core_reset(pgmn_dev, pgmn_dev->op_mode,
+ pgmn_dev->base, pgmn_dev->res_size);
+ } else {
+ JPEG_PR_ERR("%s:%d] JPEG not been initialized Wrong state\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
+ return rc;
+}
+
+int msm_jpeg_ioctl_test_dump_region(struct msm_jpeg_device *pgmn_dev,
+ unsigned long arg)
+{
+ JPEG_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_jpeg_io_dump(pgmn_dev->base, JPEG_REG_SIZE);
+ return 0;
+}
+
+int msm_jpeg_ioctl_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ long clk_rate;
+ int rc;
+
+ if ((pgmn_dev->state != MSM_JPEG_INIT) &&
+ (pgmn_dev->state != MSM_JPEG_RESET)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (get_user(clk_rate, (unsigned int __user *)arg)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ JPEG_DBG("%s:%d] Requested clk rate %ld\n", __func__, __LINE__,
+ clk_rate);
+ if (clk_rate < 0) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ rc = msm_jpeg_platform_set_clk_rate(pgmn_dev, clk_rate);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+#ifdef CONFIG_COMPAT
+int msm_jpeg_get_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd,
+ void __user *arg)
+{
+ struct msm_jpeg_ctrl_cmd32 ctrl_cmd32;
+ unsigned long temp;
+ if (copy_from_user(&ctrl_cmd32, arg,
+ sizeof(struct msm_jpeg_ctrl_cmd32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ ctrl_cmd->type = ctrl_cmd32.type;
+ ctrl_cmd->len = ctrl_cmd32.len;
+ temp = (unsigned long) ctrl_cmd32.value;
+ ctrl_cmd->value = (void *) temp;
+
+ return 0;
+}
+int msm_jpeg_put_ctrl_cmd32(struct msm_jpeg_ctrl_cmd *ctrl_cmd,
+ void __user *arg)
+{
+ struct msm_jpeg_ctrl_cmd32 ctrl_cmd32;
+ unsigned long temp;
+
+ ctrl_cmd32.type = ctrl_cmd->type;
+ ctrl_cmd32.len = ctrl_cmd->len;
+ temp = (unsigned long) ctrl_cmd->value;
+ ctrl_cmd32.value = (compat_uptr_t) temp;
+
+ if (copy_to_user(arg, &ctrl_cmd32,
+ sizeof(struct msm_jpeg_ctrl_cmd32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_jpeg_get_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf,
+ void __user *arg)
+{
+ struct msm_jpeg_buf32 jpeg_buf32;
+ unsigned long temp;
+ if (copy_from_user(&jpeg_buf32, arg, sizeof(struct msm_jpeg_buf32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ jpeg_buf->type = jpeg_buf32.type;
+ jpeg_buf->fd = jpeg_buf32.fd;
+ temp = (unsigned long) jpeg_buf32.vaddr;
+ jpeg_buf->vaddr = (void *) temp;
+ jpeg_buf->y_off = jpeg_buf32.y_off;
+ jpeg_buf->y_len = jpeg_buf32.y_len;
+ jpeg_buf->framedone_len = jpeg_buf32.framedone_len;
+ jpeg_buf->cbcr_off = jpeg_buf32.cbcr_off;
+ jpeg_buf->cbcr_len = jpeg_buf32.cbcr_len;
+ jpeg_buf->num_of_mcu_rows = jpeg_buf32.num_of_mcu_rows;
+ jpeg_buf->offset = jpeg_buf32.offset;
+ jpeg_buf->pln2_off = jpeg_buf32.pln2_off;
+ jpeg_buf->pln2_len = jpeg_buf32.pln2_len;
+
+ return 0;
+}
+int msm_jpeg_put_jpeg_buf32(struct msm_jpeg_buf *jpeg_buf,
+ void __user *arg)
+{
+ struct msm_jpeg_buf32 jpeg_buf32;
+ unsigned long temp;
+
+ jpeg_buf32.type = jpeg_buf->type;
+ jpeg_buf32.fd = jpeg_buf->fd;
+ temp = (unsigned long) jpeg_buf->vaddr;
+ jpeg_buf32.vaddr = (compat_uptr_t) temp;
+ jpeg_buf32.y_off = jpeg_buf->y_off;
+ jpeg_buf32.y_len = jpeg_buf->y_len;
+ jpeg_buf32.framedone_len = jpeg_buf->framedone_len;
+ jpeg_buf32.cbcr_off = jpeg_buf->cbcr_off;
+ jpeg_buf32.cbcr_len = jpeg_buf->cbcr_len;
+ jpeg_buf32.num_of_mcu_rows = jpeg_buf->num_of_mcu_rows;
+ jpeg_buf32.offset = jpeg_buf->offset;
+ jpeg_buf32.pln2_off = jpeg_buf->pln2_off;
+ jpeg_buf32.pln2_len = jpeg_buf->pln2_len;
+
+ if (copy_to_user(arg, &jpeg_buf32, sizeof(struct msm_jpeg_buf32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+int msm_jpeg_put_hw_cmd32(void __user *arg,
+ struct msm_jpeg_hw_cmd *phw_cmd, int copy)
+{
+ struct msm_jpeg_hw_cmd32 hw_cmd32;
+ struct msm_jpeg_hw_cmd32 *phw_cmd32;
+
+ phw_cmd32 = (struct msm_jpeg_hw_cmd32 *) arg;
+ if (copy)
+ phw_cmd32 = &hw_cmd32;
+
+
+ phw_cmd32->type = phw_cmd->type;
+ phw_cmd32->n = phw_cmd->n;
+ phw_cmd32->offset = phw_cmd->offset;
+ phw_cmd32->mask = phw_cmd->mask;
+ phw_cmd32->data = phw_cmd->data;
+
+ if (copy && copy_to_user(arg, &hw_cmd32, sizeof(hw_cmd32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+int msm_jpeg_get_hw_cmd32(struct msm_jpeg_hw_cmd *phw_cmd,
+ void __user *arg, int copy)
+{
+ struct msm_jpeg_hw_cmd32 hw_cmd32;
+ struct msm_jpeg_hw_cmd32 *phw_cmd32;
+
+ if (copy) {
+ phw_cmd32 = &hw_cmd32;
+ if (copy_from_user(&hw_cmd32, arg, sizeof(hw_cmd32))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ phw_cmd32 = (struct msm_jpeg_hw_cmd32 *) arg;
+ }
+ phw_cmd->type = phw_cmd32->type;
+ phw_cmd->n = phw_cmd32->n;
+ phw_cmd->offset = phw_cmd32->offset;
+ phw_cmd->mask = phw_cmd32->mask;
+ phw_cmd->data = phw_cmd32->data;
+
+ return 0;
+}
+int msm_jpeg_ioctl_hw_cmds32(struct msm_jpeg_device *pgmn_dev,
+ void __user *arg)
+{
+ int is_copy_to_user;
+ uint32_t len, len32;
+ uint32_t m;
+ struct msm_jpeg_hw_cmds32 *phw_cmds32;
+ struct msm_jpeg_hw_cmds *phw_cmds;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ if ((m == 0) || (m > ((UINT32_MAX - sizeof(struct msm_jpeg_hw_cmds32)) /
+ sizeof(struct msm_jpeg_hw_cmd32)))) {
+ JPEG_PR_ERR("%s:%d] m_cmds out of range\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len32 = sizeof(struct msm_jpeg_hw_cmds32) +
+ sizeof(struct msm_jpeg_hw_cmd32) * (m - 1);
+ phw_cmds32 = kmalloc(len32, GFP_KERNEL);
+ if (!phw_cmds32) {
+ JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len32);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(phw_cmds32, arg, len32)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(phw_cmds32);
+ return -EFAULT;
+ }
+ len = sizeof(struct msm_jpeg_hw_cmds) +
+ sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
+ phw_cmds = kmalloc(len, GFP_KERNEL);
+ if (!phw_cmds) {
+ JPEG_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+ kfree(phw_cmds32);
+ return -EFAULT;
+ }
+ (phw_cmds)->m = m;
+ while (m--) {
+ struct msm_jpeg_hw_cmd32 *src;
+ struct msm_jpeg_hw_cmd *dst;
+ src = &phw_cmds32->hw_cmd[m];
+ dst = &(phw_cmds)->hw_cmd[m];
+ msm_jpeg_get_hw_cmd32(dst, src, 0);
+ }
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(phw_cmds->hw_cmd, phw_cmds->m,
+ pgmn_dev->res_size, pgmn_dev->base);
+
+ if (is_copy_to_user >= 0) {
+ m = phw_cmds->m;
+ while (m--) {
+ struct msm_jpeg_hw_cmd *src;
+ struct msm_jpeg_hw_cmd32 *dst;
+ dst = &phw_cmds32->hw_cmd[m];
+ src = &phw_cmds->hw_cmd[m];
+
+ msm_jpeg_put_hw_cmd32(dst, src, 0);
+ }
+ if (copy_to_user(arg, phw_cmds32, len32)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(phw_cmds);
+ kfree(phw_cmds32);
+ return -EFAULT;
+ }
+
+ } else {
+ kfree(phw_cmds);
+ kfree(phw_cmds32);
+ return is_copy_to_user;
+ }
+ kfree(phw_cmds);
+ kfree(phw_cmds32);
+
+ return 0;
+}
+int msm_jpeg_ioctl_hw_cmd32(struct msm_jpeg_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_jpeg_hw_cmd hw_cmd;
+ int is_copy_to_user;
+
+ if (msm_jpeg_get_hw_cmd32(&hw_cmd, arg, 1)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_jpeg_hw_exec_cmds(&hw_cmd, 1,
+ pgmn_dev->res_size, pgmn_dev->base);
+ JPEG_DBG("%s:%d] type %d, n %d, offst %d, mask %x, data %x pdata %lx\n",
+ __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+ hw_cmd.mask, hw_cmd.data, (unsigned long) hw_cmd.pdata);
+
+ if (is_copy_to_user >= 0) {
+ if (msm_jpeg_put_hw_cmd32(arg, &hw_cmd, 1)) {
+ JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else
+ return is_copy_to_user;
+
+
+ return 0;
+}
+
+long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ struct msm_jpeg_ctrl_cmd *pctrl_cmd = NULL, ctrl_cmd;
+ struct msm_jpeg_buf jpeg_buf;
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+
+ switch (cmd) {
+ case MSM_JPEG_IOCTL_GET_HW_VERSION:
+ JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+ case MSM_JPEG_IOCTL_GET_HW_VERSION32:
+ JPEG_DBG("%s:%d] VERSION 1 32bit\n", __func__, __LINE__);
+ rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_RESET:
+ rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_RESET32:
+ rc = msm_jpeg_get_ctrl_cmd32(&ctrl_cmd,
+ (void __user *) arg);
+ if (rc < 0)
+ break;
+
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) &ctrl_cmd);
+ set_fs(old_fs);
+ kfree(pctrl_cmd);
+ break;
+
+ case MSM_JPEG_IOCTL_STOP:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ pgmn_dev->state = MSM_JPEG_STOPPED;
+ break;
+
+ case MSM_JPEG_IOCTL_STOP32:
+ rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg);
+ pgmn_dev->state = MSM_JPEG_STOPPED;
+ break;
+
+ case MSM_JPEG_IOCTL_START:
+ rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+ msm_jpeg_ioctl_hw_cmds);
+ break;
+
+ case MSM_JPEG_IOCTL_START32:
+ rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+ msm_jpeg_ioctl_hw_cmds32);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE32:
+ rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+ if (rc < 0)
+ break;
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+ (void __user *) &jpeg_buf);
+ set_fs(old_fs);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET:
+ rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET32:
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_input_get(pgmn_dev, (void __user *) &jpeg_buf);
+ set_fs(old_fs);
+ if (rc < 0)
+ break;
+ rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+ rc = msm_jpeg_input_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE32:
+ rc = msm_jpeg_get_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+ if (rc < 0)
+ break;
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+ (void __user *) &jpeg_buf);
+ set_fs(old_fs);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET:
+ rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET32:
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_output_get(pgmn_dev, (void __user *) &jpeg_buf);
+ set_fs(old_fs);
+ if (rc < 0)
+ break;
+ rc = msm_jpeg_put_jpeg_buf32(&jpeg_buf, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+ rc = msm_jpeg_output_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET:
+ rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET32:
+ set_fs(KERNEL_DS);
+ rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) &ctrl_cmd);
+ set_fs(old_fs);
+ if (rc < 0)
+ break;
+ msm_jpeg_put_ctrl_cmd32(&ctrl_cmd, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMD32:
+ rc = msm_jpeg_ioctl_hw_cmd32(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMD:
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMDS32:
+ rc = msm_jpeg_ioctl_hw_cmds32(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMDS:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+ rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+ break;
+
+ case MSM_JPEG_IOCTL_TEST_DUMP_REGION32:
+ rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+ break;
+
+ case MSM_JPEG_IOCTL_SET_CLK_RATE:
+ rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ default:
+ JPEG_PR_ERR(KERN_INFO "%s:%d] cmd = %d not supported\n",
+ __func__, __LINE__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+#else
+long __msm_jpeg_compat_ioctl(struct msm_jpeg_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+#endif
+
+long __msm_jpeg_ioctl(struct msm_jpeg_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ switch (cmd) {
+ case MSM_JPEG_IOCTL_GET_HW_VERSION:
+ JPEG_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_RESET:
+ rc = msm_jpeg_ioctl_reset(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_STOP:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ pgmn_dev->state = MSM_JPEG_STOPPED;
+ break;
+
+ case MSM_JPEG_IOCTL_START:
+ rc = msm_jpeg_start(pgmn_dev, (void __user *) arg,
+ msm_jpeg_ioctl_hw_cmds);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_input_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET:
+ rc = msm_jpeg_input_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_INPUT_GET_UNBLOCK:
+ rc = msm_jpeg_input_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_BUF_ENQUEUE:
+ rc = msm_jpeg_output_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET:
+ rc = msm_jpeg_output_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_OUTPUT_GET_UNBLOCK:
+ rc = msm_jpeg_output_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET:
+ rc = msm_jpeg_evt_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_jpeg_evt_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMD:
+ rc = msm_jpeg_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_HW_CMDS:
+ rc = msm_jpeg_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_JPEG_IOCTL_TEST_DUMP_REGION:
+ rc = msm_jpeg_ioctl_test_dump_region(pgmn_dev, arg);
+ break;
+
+ case MSM_JPEG_IOCTL_SET_CLK_RATE:
+ rc = msm_jpeg_ioctl_set_clk_rate(pgmn_dev, (void __user *) arg);
+ break;
+ default:
+ pr_err_ratelimited("%s:%d] cmd = %d not supported\n",
+ __func__, __LINE__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+int __msm_jpeg_init(struct msm_jpeg_device *pgmn_dev)
+{
+ int rc = 0;
+ int idx = 0;
+
+ char *iommu_name[JPEG_DEV_CNT] = {"jpeg_enc0", "jpeg_enc1",
+ "jpeg_dec", "jpeg_dma"};
+
+
+ mutex_init(&pgmn_dev->lock);
+
+ pr_err("%s:%d] Jpeg Device id %d", __func__, __LINE__,
+ pgmn_dev->pdev->id);
+ idx = pgmn_dev->pdev->id;
+ pgmn_dev->idx = idx;
+ pgmn_dev->decode_flag = (idx == JPEG_DEC_ID);
+
+ msm_jpeg_q_init("evt_q", &pgmn_dev->evt_q);
+ msm_jpeg_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+ msm_jpeg_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+ msm_jpeg_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+ msm_jpeg_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+ /*get device context for IOMMU*/
+ rc = cam_smmu_get_handle(iommu_name[idx], &pgmn_dev->iommu_hdl);
+ JPEG_DBG("%s:%d] hdl %d", __func__, __LINE__,
+ pgmn_dev->iommu_hdl);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: No iommu fw context found\n",
+ __func__);
+ goto err_smmu;
+ }
+
+ /* setup all the resources for the jpeg driver */
+ rc = msm_jpeg_platform_setup(pgmn_dev);
+ if (rc < 0) {
+ JPEG_PR_ERR("%s: setup failed\n",
+ __func__);
+ goto err_setup;
+ }
+
+ return rc;
+err_setup:
+err_smmu:
+ mutex_destroy(&pgmn_dev->lock);
+ return -EFAULT;
+}
+
+int __msm_jpeg_exit(struct msm_jpeg_device *pgmn_dev)
+{
+ msm_jpeg_platform_cleanup(pgmn_dev);
+ mutex_destroy(&pgmn_dev->lock);
+ kfree(pgmn_dev);
+ return 0;
+}