msm: add video processing engine (VPE) as a V4L2 subdev in 8960.
Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 1221ead..7dbcafe 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -933,6 +933,18 @@
.flags = IORESOURCE_IRQ,
},
{
+ .name = "vpe",
+ .start = 0x05300000,
+ .end = 0x05300000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "vpe",
+ .start = VPE_IRQ,
+ .end = VPE_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
.name = "vid_buf",
.flags = IORESOURCE_DMA,
},
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 59bde6d..567a290 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -293,6 +293,11 @@
void *data;
};
+struct msm_mctl_pp_params {
+ struct msm_mctl_pp_cmd *cmd;
+ void *data;
+};
+
struct msm_camvpe_fn {
int (*vpe_reg)(struct msm_vpe_callback *);
int (*vpe_cfg_update) (void *);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 35795fc..bd3fffe 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -4,7 +4,7 @@
endif
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 624c15c..e3b97c9 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1449,6 +1449,14 @@
__func__, rc);
return rc;
}
+ rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+ &pcam->mctl.isp_sdev->sd_vpe);
+ if (rc < 0) {
+ mutex_unlock(&pcam->vid_lock);
+ pr_err("%s: vpe v4l2_device_register_subdev failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->pvdev);
@@ -1501,7 +1509,6 @@
pr_err("%s: cannot map vaddr", __func__);
return -EFAULT;
}
- pr_err("%s: phy_addr=0x%x\n", __func__, (uint32_t)phyaddr);
size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
retval = remap_pfn_range(vma, vma->vm_start,
@@ -1531,10 +1538,8 @@
if (pcam_inst->is_mem_map_inst &&
pcam_inst->mem_map.cookie) {
- pr_err("%s: ioremap called, vma=0x%08lx\n",
- __func__, (unsigned long)vma);
rc = msm_addr_remap(pcam_inst, vma);
- pr_err("%s: msm_addr_remap ret=%d\n", __func__, rc);
+ D("%s: msm_addr_remap ret=%d\n", __func__, rc);
return rc;
} else
rc = vb2_mmap(&pcam_inst->vid_bufq, vma);
@@ -1911,7 +1916,9 @@
break;
}
if (ev.type != (V4L2_EVENT_PRIVATE_START +
- MSM_CAM_RESP_DIV_FRAME_EVT_MSG)) {
+ MSM_CAM_RESP_DIV_FRAME_EVT_MSG) &&
+ ev.type != (V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_RESP_MCTL_PP_EVENT)) {
k_isp_event =
(struct msm_isp_stats_event_ctrl *)ev.u.data;
if (ev.type == (V4L2_EVENT_PRIVATE_START +
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c2df360..001ca4b 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -30,6 +30,7 @@
#include <media/videobuf2-msm-mem.h>
#include <media/msm_isp.h>
#include <mach/camera.h>
+#include <media/msm_isp.h>
#define MSM_V4L2_DIMENSION_SIZE 96
#define MAX_DEV_NAME_LEN 50
@@ -87,6 +88,7 @@
struct msm_free_buf {
uint8_t num_planes;
uint32_t ch_paddr[VIDEO_MAX_PLANES];
+ uint32_t vb;
};
struct isp_msg_output {
@@ -103,6 +105,7 @@
NOTIFY_VFE_MSG_STATS, /* arg = struct isp_msg_stats */
NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
+ NOTIFY_VPE_MSG_EVT,
NOTIFY_INVALID
};
@@ -147,13 +150,26 @@
enum v4l2_colorspace colorspace;
};
+struct msm_mctl_pp_frame_info {
+ int user_cmd;
+ struct msm_pp_frame src_frame;
+ struct msm_pp_frame dest_frame;
+ struct msm_mctl_pp_frame_cmd pp_frame_cmd;
+};
+struct msm_mctl_pp_ctrl {
+ int pp_msg_type;
+ struct msm_mctl_pp_frame_info *pp_frame_info;
+
+};
struct msm_mctl_pp_info {
spinlock_t lock;
uint32_t cnt;
uint32_t pp_key;
uint32_t cur_frame_id[MSM_MAX_IMG_MODE];
struct msm_free_buf div_frame[MSM_MAX_IMG_MODE];
+ struct msm_mctl_pp_ctrl pp_ctrl;
+
};
/* "Media Controller" represents a camera steaming session,
* which consists of a "sensor" device and an "isp" device
@@ -204,16 +220,19 @@
char *config_dev_name;
/*int (*isp_init)(struct msm_cam_v4l2_device *pcam);*/
- int (*isp_open)(struct v4l2_subdev *sd, struct msm_sync *sync);
+ int (*isp_open)(struct v4l2_subdev *sd, struct v4l2_subdev *sd_vpe,
+ struct msm_sync *sync);
int (*isp_config)(struct msm_cam_media_controller *pmctl,
unsigned int cmd, unsigned long arg);
int (*isp_notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
-
void (*isp_release)(struct msm_sync *psync);
+ int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
+ struct msm_mctl_pp_cmd, void *data);
/* vfe subdevice */
struct v4l2_subdev sd;
+ struct v4l2_subdev sd_vpe;
};
struct msm_isp_buf_info {
@@ -396,6 +415,52 @@
int msm_isp_subdev_ioctl(struct v4l2_subdev *sd,
struct msm_vfe_cfg_cmd *cfgcmd, void *data);
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev);
+void msm_vpe_subdev_release(struct platform_device *pdev);
+int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
+ struct msm_mctl_pp_cmd *cmd, void *data);
+int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
+ int msg_type);
+int msm_mctl_do_pp(struct msm_cam_media_controller *p_mctl,
+ int msg_type, uint32_t y_phy, uint32_t frame_id);
+int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
+ unsigned int cmd, unsigned long arg);
+int msm_mctl_pp_notify(struct msm_cam_media_controller *pmctl,
+ struct msm_mctl_pp_frame_info *pp_frame_info);
+int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+ int out_type);
+struct msm_frame_buffer *msm_mctl_buf_find(
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
+ int msg_type, struct msm_free_buf *fbuf);
+void msm_mctl_gettimeofday(struct timeval *tv);
+struct msm_frame_buffer *msm_mctl_get_free_buf(
+ struct msm_cam_media_controller *pmctl,
+ int msg_type);
+int msm_mctl_put_free_buf(
+ struct msm_cam_media_controller *pmctl,
+ int msg_type, struct msm_frame_buffer *buf);
+int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl,
+ int msg_type, int *pp_divert_type, int *pp_type);
+int msm_mctl_do_pp_divert(
+ struct msm_cam_media_controller *p_mctl,
+ int msg_type, struct msm_free_buf *fbuf,
+ uint32_t frame_id, int pp_type);
+int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
+ int msg_type,
+ struct msm_frame_buffer *my_buf);
+int msm_mctl_pp_release_free_frame(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg);
+int msm_mctl_pp_reserve_free_frame(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg);
+int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
+ void __user *arg);
+int msm_mctl_pp_done(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index f8f1530..7682d7a 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -137,7 +137,7 @@
/*
* This function executes in interrupt context.
*/
-static int msm_isp_notify(struct v4l2_subdev *sd,
+static int msm_isp_notify_vfe(struct v4l2_subdev *sd,
unsigned int notification, void *arg)
{
int rc = 0;
@@ -244,8 +244,30 @@
return rc;
}
+static int msm_isp_notify_vpe(struct v4l2_subdev *sd, void *arg)
+{
+ struct msm_sync *sync =
+ (struct msm_sync *)v4l2_get_subdev_hostdata(sd);
+ struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
+
+ msm_mctl_pp_notify(&sync->pcam_sync->mctl,
+ (struct msm_mctl_pp_frame_info *)vdata->extdata);
+ return 0;
+}
+
+static int msm_isp_notify(struct v4l2_subdev *sd,
+ unsigned int notification, void *arg)
+{
+ if (notification == NOTIFY_VPE_MSG_EVT)
+ return msm_isp_notify_vpe(sd, arg);
+ else
+ return msm_isp_notify_vfe(sd, notification, arg);
+}
+
/* This function is called by open() function, so we need to init HW*/
-static int msm_isp_open(struct v4l2_subdev *sd, struct msm_sync *sync)
+static int msm_isp_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev *sd_vpe,
+ struct msm_sync *sync)
{
/* init vfe and senor, register sync callbacks for init*/
int rc = 0;
@@ -261,7 +283,12 @@
pr_err("%s: vfe_init failed at %d\n",
__func__, rc);
}
-
+ D("%s: init vpe subdev", __func__);
+ rc = msm_vpe_subdev_init(sd_vpe, sync, sync->pdev);
+ if (rc < 0) {
+ pr_err("%s: vpe_init failed at %d\n",
+ __func__, rc);
+ }
return rc;
}
@@ -269,6 +296,7 @@
{
D("%s\n", __func__);
msm_vfe_subdev_release(psync->pdev);
+ msm_vpe_subdev_release(psync->pdev);
}
static int msm_config_vfe(struct v4l2_subdev *sd,
@@ -688,3 +716,15 @@
vfe_params.data = data;
return v4l2_subdev_call(isp_subdev, core, ioctl, 0, &vfe_params);
}
+
+int msm_isp_subdev_ioctl_vpe(struct v4l2_subdev *isp_subdev,
+ struct msm_mctl_pp_cmd *cmd, void *data)
+{
+ int rc = 0;
+ struct msm_mctl_pp_params parm;
+ parm.cmd = cmd;
+ parm.data = data;
+ rc = v4l2_subdev_call(isp_subdev, core, ioctl, 0, &parm);
+ return rc;
+}
+
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 9b4823b..f684b4f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -162,7 +162,7 @@
/* called by other subdev to notify any changes*/
static int msm_mctl_notify(struct msm_cam_media_controller *p_mctl,
- unsigned int notification, void *arg)
+ unsigned int notification, void *arg)
{
int rc = -EINVAL;
struct msm_camera_sensor_info *sinfo =
@@ -204,76 +204,16 @@
&p_mctl->isp_sdev->sd, notification, arg);
}
break;
- default:
- break;
- }
-
- return rc;
-}
-
-static int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
- void __user *arg)
-{
- int rc = 0;
- unsigned long flags;
- spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- if (copy_from_user(&p_mctl->pp_info.pp_key,
- arg, sizeof(p_mctl->pp_info.pp_key)))
- rc = -EFAULT;
- else
- D("%s: mctl=0x%p, pp_key_setting=0x%x",
- __func__, p_mctl, p_mctl->pp_info.pp_key);
-
- spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- return rc;
-}
-
-static int msm_mctl_pp_done(struct msm_cam_media_controller *p_mctl,
- void __user *arg)
-{
- struct msm_frame frame;
- int msg_type, image_mode, rc = 0;
- int dirty = 0;
- struct msm_free_buf buf;
- unsigned long flags;
-
- if (copy_from_user(&frame, arg, sizeof(frame)))
- return -EFAULT;
- spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- switch (frame.path) {
- case OUTPUT_TYPE_P:
- if (!(p_mctl->pp_info.pp_key & PP_PREV)) {
- rc = -EFAULT;
- goto err;
+ case NOTIFY_VPE_MSG_EVT:
+ if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
+ rc = p_mctl->isp_sdev->isp_notify(
+ &p_mctl->isp_sdev->sd_vpe, notification, arg);
}
- msg_type = VFE_MSG_OUTPUT_P;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
break;
- case OUTPUT_TYPE_S:
- if (!(p_mctl->pp_info.pp_key & PP_SNAP))
- return -EFAULT;
- msg_type = VFE_MSG_OUTPUT_S;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
- break;
- case OUTPUT_TYPE_T:
- case OUTPUT_TYPE_V:
default:
- rc = -EFAULT;
- goto err;
+ break;
}
- memcpy(&buf, &p_mctl->pp_info.div_frame[image_mode], sizeof(buf));
- memset(&p_mctl->pp_info.div_frame[image_mode], 0, sizeof(buf));
- if (p_mctl->pp_info.cur_frame_id[image_mode] !=
- frame.frame_id) {
- /* dirty frame. should not pass to app */
- dirty = 1;
- }
- spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- /* here buf.addr is phy_addr */
- rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty);
- return rc;
-err:
- spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+
return rc;
}
@@ -288,7 +228,7 @@
pr_err("%s: param is NULL", __func__);
return -EINVAL;
}
- D("%s start cmd = %d\n", __func__, _IOC_NR(cmd));
+ D("%s cmd = %d\n", __func__, _IOC_NR(cmd));
/* ... call sensor, ISPIF or VEF subdev*/
switch (cmd) {
@@ -342,13 +282,25 @@
case MSM_CAM_IOCTL_PICT_PP_DONE:
rc = msm_mctl_pp_done(p_mctl, (void __user *)arg);
break;
+ case MSM_CAM_IOCTL_MCTL_POST_PROC:
+ rc = msm_mctl_pp_ioctl(p_mctl, cmd, arg);
+ break;
+ case MSM_CAM_IOCTL_RESERVE_FREE_FRAME:
+ rc = msm_mctl_pp_reserve_free_frame(p_mctl,
+ (void __user *)arg);
+ break;
+ case MSM_CAM_IOCTL_RELEASE_FREE_FRAME:
+ rc = msm_mctl_pp_release_free_frame(p_mctl,
+ (void __user *)arg);
+ break;
/* ISFIF config*/
default:
/* ISP config*/
rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
break;
}
- D("%s: !!! cmd = %d, rc = %d\n", __func__, _IOC_NR(cmd), rc);
+ D("%s: !!! cmd = %d, rc = %d\n",
+ __func__, _IOC_NR(cmd), rc);
return rc;
}
@@ -382,8 +334,8 @@
/* ISP first*/
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
rc = p_mctl->isp_sdev->isp_open(
- &p_mctl->isp_sdev->sd, sync);
-
+ &p_mctl->isp_sdev->sd,
+ &p_mctl->isp_sdev->sd_vpe, sync);
if (rc < 0) {
pr_err("%s: isp init failed: %d\n", __func__, rc);
goto msm_open_done;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 92549b6..617c8b4 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -352,7 +352,7 @@
return 0;
}
-static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
int out_type)
{
switch (out_type) {
@@ -374,7 +374,7 @@
return 0;
}
-static void msm_mctl_gettimeofday(struct timeval *tv)
+void msm_mctl_gettimeofday(struct timeval *tv)
{
struct timespec ts;
@@ -385,7 +385,7 @@
tv->tv_usec = ts.tv_nsec/1000;
}
-static struct msm_frame_buffer *msm_mctl_buf_find(
+struct msm_frame_buffer *msm_mctl_buf_find(
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst, int del_buf,
int msg_type, struct msm_free_buf *fbuf)
@@ -442,115 +442,29 @@
return 0;
}
-static int msm_mctl_buf_divert(
- struct msm_cam_media_controller *pmctl,
- struct msm_cam_v4l2_dev_inst *pcam_inst,
- struct msm_cam_evt_divert_frame *div)
-{
- struct v4l2_event v4l2_evt;
- struct msm_cam_evt_divert_frame *tmp;
- memset(&v4l2_evt, 0, sizeof(v4l2_evt));
- v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
- memcpy(&v4l2_evt.u.data[0], div,
- sizeof(struct msm_cam_evt_divert_frame));
- D("%s inst=%p, img_mode=%d, frame_id=%d,phy=0x%x,len=%d\n",
- __func__, pcam_inst, pcam_inst->image_mode, div->frame_id,
- (uint32_t)div->phy_addr, div->length);
- tmp = (struct msm_cam_evt_divert_frame *)&v4l2_evt.u.data[0];
- v4l2_event_queue(
- pmctl->config_device->config_stat_event_queue.pvdev,
- &v4l2_evt);
- return 0;
-}
-
int msm_mctl_buf_done(struct msm_cam_media_controller *p_mctl,
int msg_type, struct msm_free_buf *fbuf,
uint32_t frame_id)
{
- uint32_t pp_key = 0;
struct msm_cam_v4l2_dev_inst *pcam_inst;
- int idx;
- int del_buf = 0;
- int image_mode = MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT;
- unsigned long flags;
- int path = 0;
+ int idx, rc;
+ int pp_divert_type = 0, pp_type = 0;
-
- idx = msm_mctl_out_type_to_inst_index(
- p_mctl->sync.pcam_sync, msg_type);
- pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
- switch (msg_type) {
- case VFE_MSG_OUTPUT_P:
- pp_key = PP_PREV;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
- path = OUTPUT_TYPE_P;
- break;
- case VFE_MSG_OUTPUT_S:
- pp_key = PP_SNAP;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
- path = OUTPUT_TYPE_S;
- break;
- case VFE_MSG_OUTPUT_T:
- default:
- path = OUTPUT_TYPE_T;
- break;
+ msm_mctl_check_pp(p_mctl, msg_type, &pp_divert_type, &pp_type);
+ D("%s: pp_type=%d, pp_divert_type = %d",
+ __func__, pp_type, pp_divert_type);
+ if (pp_type || pp_divert_type)
+ rc = msm_mctl_do_pp_divert(p_mctl,
+ msg_type, fbuf, frame_id, pp_type);
+ else {
+ idx = msm_mctl_out_type_to_inst_index(
+ p_mctl->sync.pcam_sync, msg_type);
+ pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+ rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+ msg_type, fbuf,
+ &frame_id, 1);
}
- spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- if (p_mctl->pp_info.pp_key & pp_key) {
- int rc = 0;
- struct msm_cam_evt_divert_frame div;
- struct msm_frame_buffer *vb = NULL;
- struct videobuf2_contig_pmem *mem;
-
- p_mctl->pp_info.cur_frame_id[image_mode]++;
- if (!p_mctl->pp_info.cur_frame_id[image_mode])
- p_mctl->pp_info.cur_frame_id[image_mode] = 1;
- if (!p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
- /* no frame in postproc. good to divert the frame up */
- memset(&div, 0, sizeof(div));
- vb = msm_mctl_buf_find(p_mctl, pcam_inst,
- del_buf, msg_type, fbuf);
- if (!vb) {
- spin_unlock_irqrestore(&p_mctl->pp_info.lock,
- flags);
- return -EINVAL;
- }
- vb->vidbuf.v4l2_buf.sequence = frame_id;
- mem = vb2_plane_cookie(&vb->vidbuf, 0);
- div.image_mode = pcam_inst->image_mode;
- div.op_mode = pcam_inst->pcam->op_mode;
- div.inst_idx = pcam_inst->my_index;
- div.node_idx = pcam_inst->pcam->vnode_id;
- div.phy_addr =
- videobuf2_to_pmem_contig(&vb->vidbuf, 0);
- div.phy_offset = mem->addr_offset;
- div.offset = mem->offset;
- div.fd = (int)mem->vaddr;
- div.frame_id =
- p_mctl->pp_info.cur_frame_id[image_mode];
- div.path = path;
- div.length = mem->size;
- msm_mctl_gettimeofday(&div.timestamp);
- vb->vidbuf.v4l2_buf.timestamp = div.timestamp;
- p_mctl->pp_info.div_frame[image_mode].num_planes =
- pcam_inst->plane_info.num_planes;
- p_mctl->pp_info.div_frame[image_mode].ch_paddr[0] =
- div.phy_addr;
- p_mctl->pp_info.div_frame[image_mode].ch_paddr[1] =
- div.phy_addr + div.offset;
- p_mctl->pp_info.div_frame[image_mode].ch_paddr[2] =
- 0;
- rc = msm_mctl_buf_divert(p_mctl, pcam_inst, &div);
- spin_unlock_irqrestore(&p_mctl->pp_info.lock,
- flags);
- return rc;
- }
- }
- spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- return msm_mctl_buf_done_proc(p_mctl, pcam_inst,
- msg_type, fbuf,
- &frame_id, 1);
+ return rc;
}
int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
@@ -600,6 +514,7 @@
free_buf->ch_paddr[1] =
free_buf->ch_paddr[0] + mem->offset;
}
+ free_buf->vb = (uint32_t)buf;
buf->state = MSM_BUFFER_STATE_RESERVED;
D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, "
"ch1 addr=0x%x\n", __func__,
@@ -672,3 +587,98 @@
return rc;
}
+struct msm_frame_buffer *msm_mctl_get_free_buf(
+ struct msm_cam_media_controller *pmctl,
+ int msg_type)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ unsigned long flags = 0;
+ struct msm_frame_buffer *buf = NULL;
+ int rc = -EINVAL, idx;
+
+ idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
+ msg_type);
+ pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+ if (!pcam_inst->streamon) {
+ D("%s: stream 0x%p is off\n", __func__, pcam_inst);
+ return NULL;
+ }
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ if (!list_empty(&pcam_inst->free_vq)) {
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ if (buf->state == MSM_BUFFER_STATE_QUEUED) {
+ buf->state = MSM_BUFFER_STATE_RESERVED;
+ rc = 0;
+ break;
+ }
+ }
+ }
+ if (rc != 0) {
+ D("%s:No free buffer available: inst = 0x%p ",
+ __func__, pcam_inst);
+ buf = NULL;
+ }
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return buf;
+}
+
+int msm_mctl_put_free_buf(
+ struct msm_cam_media_controller *pmctl,
+ int msg_type, struct msm_frame_buffer *my_buf)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ unsigned long flags = 0;
+ int rc = 0, idx;
+ struct msm_frame_buffer *buf = NULL;
+
+ idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
+ msg_type);
+ pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+ if (!pcam_inst->streamon) {
+ D("%s: stream 0x%p is off\n", __func__, pcam_inst);
+ return rc;
+ }
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ if (!list_empty(&pcam_inst->free_vq)) {
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ if (my_buf == buf) {
+ buf->state = MSM_BUFFER_STATE_QUEUED;
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
+ flags);
+ return 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return rc;
+}
+
+int msm_mctl_buf_del(struct msm_cam_media_controller *pmctl,
+ int msg_type,
+ struct msm_frame_buffer *my_buf)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_frame_buffer *buf = NULL;
+ unsigned long flags = 0;
+ int idx;
+
+ idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync,
+ msg_type);
+ pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+ D("%s: idx = %d, pinst=0x%p", __func__, idx, pcam_inst);
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ if (!list_empty(&pcam_inst->free_vq)) {
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ if (my_buf == buf) {
+ list_del_init(&buf->list);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock,
+ flags);
+ return 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ pr_err("%s: buf 0x%p not found", __func__, my_buf);
+ return -EINVAL;
+}
+
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
new file mode 100644
index 0000000..167e721
--- /dev/null
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -0,0 +1,746 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+
+#include "msm.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_mctl_pp_buf_divert(
+ struct msm_cam_media_controller *pmctl,
+ struct msm_cam_v4l2_dev_inst *pcam_inst,
+ struct msm_cam_evt_divert_frame *div)
+{
+ struct v4l2_event v4l2_evt;
+
+ D("%s: msm_cam_evt_divert_frame=%d",
+ __func__, sizeof(struct msm_cam_evt_divert_frame));
+ memset(&v4l2_evt, 0, sizeof(v4l2_evt));
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_RESP_DIV_FRAME_EVT_MSG;
+ memcpy(&v4l2_evt.u.data[0], div,
+ sizeof(struct msm_cam_evt_divert_frame));
+ D("%s inst=%p, img_mode=%d, frame_id=%d,phy=0x%x,len=%d\n",
+ __func__, pcam_inst, pcam_inst->image_mode, div->frame_id,
+ (uint32_t)div->phy_addr, div->length);
+ v4l2_event_queue(
+ pmctl->config_device->config_stat_event_queue.pvdev,
+ &v4l2_evt);
+ return 0;
+}
+
+int msm_mctl_check_pp(struct msm_cam_media_controller *p_mctl,
+ int msg_type, int *pp_divert_type, int *pp_type)
+{
+ int rc = 0;
+ unsigned long flags;
+ uint32_t pp_key = 0;
+ int image_mode = MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT;
+
+ *pp_type = 0;
+ *pp_divert_type = 0;
+ spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+ switch (msg_type) {
+ case VFE_MSG_OUTPUT_P:
+ pp_key = PP_PREV;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ if (p_mctl->pp_info.pp_key & pp_key)
+ *pp_divert_type = OUTPUT_TYPE_P;
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_P)
+ *pp_type = OUTPUT_TYPE_P;
+ break;
+ case VFE_MSG_OUTPUT_S:
+ pp_key = PP_SNAP;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ if (p_mctl->pp_info.pp_key & pp_key)
+ *pp_divert_type = OUTPUT_TYPE_S;
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_S)
+ *pp_type = OUTPUT_TYPE_P;
+ break;
+ case VFE_MSG_OUTPUT_V:
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_V)
+ *pp_type = OUTPUT_TYPE_V;
+ break;
+ case VFE_MSG_OUTPUT_T:
+ if (p_mctl->pp_info.pp_ctrl.pp_msg_type == OUTPUT_TYPE_T)
+ *pp_type = OUTPUT_TYPE_T;
+ break;
+ default:
+ break;
+ }
+ if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0])
+ *pp_divert_type = 0;
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ D("%s: pp_type=%d, pp_divert_type = %d",
+ __func__, *pp_type, *pp_divert_type);
+ return rc;
+}
+
+int msm_mctl_do_pp_divert(
+ struct msm_cam_media_controller *p_mctl,
+ int msg_type, struct msm_free_buf *fbuf,
+ uint32_t frame_id, int pp_type)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ int idx, rc = 0;
+ int del_buf = 0; /* delete from free queue */
+ struct msm_cam_evt_divert_frame div;
+ struct msm_frame_buffer *vb = NULL;
+ struct videobuf2_contig_pmem *mem;
+
+ idx = msm_mctl_out_type_to_inst_index(
+ p_mctl->sync.pcam_sync, msg_type);
+ pcam_inst = p_mctl->sync.pcam_sync->dev_inst[idx];
+ vb = msm_mctl_buf_find(p_mctl, pcam_inst,
+ del_buf, msg_type, fbuf);
+ if (!vb)
+ return -EINVAL;
+ vb->vidbuf.v4l2_buf.sequence = frame_id;
+ mem = vb2_plane_cookie(&vb->vidbuf, 0);
+ div.image_mode = pcam_inst->image_mode;
+ div.op_mode = pcam_inst->pcam->op_mode;
+ div.inst_idx = pcam_inst->my_index;
+ div.node_idx = pcam_inst->pcam->vnode_id;
+ div.phy_addr =
+ videobuf2_to_pmem_contig(&vb->vidbuf, 0);
+ div.phy_offset = mem->addr_offset;
+ div.y_off = 0;
+ div.cbcr_off = mem->offset;
+ div.fd = (int)mem->vaddr;
+ div.vb = (uint32_t)vb;
+ p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
+ if (p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode] == 0)
+ p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
+ div.frame_id =
+ p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode];
+ div.path = mem->buffer_type;
+ div.length = mem->size;
+ msm_mctl_gettimeofday(&div.timestamp);
+ vb->vidbuf.v4l2_buf.timestamp = div.timestamp;
+ div.do_pp = pp_type;
+ if (!pp_type) {
+ p_mctl->pp_info.div_frame[pcam_inst->image_mode].ch_paddr[0] =
+ div.phy_addr;
+ }
+ rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div);
+ return rc;
+}
+
+static int msm_mctl_pp_get_phy_addr(
+ uint32_t frame_handle,
+ struct msm_pp_frame *pp_frame)
+{
+ struct msm_frame_buffer *vb = NULL;
+ struct videobuf2_contig_pmem *mem;
+
+ vb = (struct msm_frame_buffer *)frame_handle;
+ mem = vb2_plane_cookie(&vb->vidbuf, 0);
+ memset(pp_frame, 0, sizeof(struct msm_pp_frame));
+ pp_frame->handle = (uint32_t)vb;
+ pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
+ pp_frame->image_type = (unsigned short)mem->buffer_type;
+ pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
+ /* hard coded for now. Will need to expand to MP case */
+ pp_frame->num_planes = 1;
+ pp_frame->sp.addr_offset = mem->addr_offset;
+ pp_frame->sp.phy_addr = videobuf2_to_pmem_contig(&vb->vidbuf, 0);
+ pp_frame->sp.y_off = 0;
+ pp_frame->sp.cbcr_off = mem->offset;
+ pp_frame->sp.length = mem->size;
+ pp_frame->sp.fd = (int)mem->vaddr;
+ return 0;
+}
+
+static int msm_mctl_pp_copy_timestamp_and_frame_id(
+ uint32_t src_handle, uint32_t dest_handle)
+{
+ struct msm_frame_buffer *src_vb;
+ struct msm_frame_buffer *dest_vb;
+
+ src_vb = (struct msm_frame_buffer *)src_handle;
+ dest_vb = (struct msm_frame_buffer *)dest_handle;
+ dest_vb->vidbuf.v4l2_buf.timestamp =
+ src_vb->vidbuf.v4l2_buf.timestamp;
+ dest_vb->vidbuf.v4l2_buf.sequence =
+ src_vb->vidbuf.v4l2_buf.sequence;
+ D("%s: timestamp=%ld:%ld,frame_id=0x%x", __func__,
+ dest_vb->vidbuf.v4l2_buf.timestamp.tv_sec,
+ dest_vb->vidbuf.v4l2_buf.timestamp.tv_usec,
+ dest_vb->vidbuf.v4l2_buf.sequence);
+ return 0;
+}
+
+int msm_mctl_pp_proc_vpe_cmd(
+ struct msm_cam_media_controller *p_mctl,
+ struct msm_mctl_pp_cmd *pp_cmd)
+{
+ int rc = 0;
+ void __user *argp = (void __user *)pp_cmd->value;
+ switch (pp_cmd->id) {
+ case VPE_CMD_INIT:
+ case VPE_CMD_DEINIT:
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ case VPE_CMD_DISABLE:
+ case VPE_CMD_RESET:
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ case VPE_CMD_ENABLE: {
+ struct msm_vpe_clock_rate clk_rate;
+ if (sizeof(struct msm_vpe_clock_rate) !=
+ pp_cmd->length) {
+ D("%s: vpe cmd size mismatch "
+ "(id=%d, length = %d, expect size = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_clock_rate));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&clk_rate, pp_cmd->value,
+ sizeof(struct msm_vpe_clock_rate))) {
+ D("%s:clk_rate copy failed", __func__);
+ return -EFAULT;
+ }
+ pp_cmd->value = (void *)&clk_rate;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ pp_cmd->value = argp;
+ break;
+ }
+ case VPE_CMD_FLUSH: {
+ struct msm_vpe_flush_frame_buffer flush_buf;
+ if (sizeof(struct msm_vpe_flush_frame_buffer) !=
+ pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_flush_frame_buffer));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(
+ &flush_buf, pp_cmd->value, sizeof(flush_buf)))
+ return -EFAULT;
+ pp_cmd->value = (void *)&flush_buf;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ if (rc == 0) {
+ if (copy_to_user((void *)argp,
+ &flush_buf,
+ sizeof(flush_buf))) {
+ ERR_COPY_TO_USER();
+ rc = -EFAULT;
+ }
+ pp_cmd->value = argp;
+ }
+ }
+ break;
+ case VPE_CMD_OPERATION_MODE_CFG: {
+ struct msm_vpe_op_mode_cfg op_mode_cfg;
+ if (sizeof(struct msm_vpe_op_mode_cfg) !=
+ pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_op_mode_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&op_mode_cfg,
+ pp_cmd->value,
+ sizeof(op_mode_cfg)))
+ return -EFAULT;
+ pp_cmd->value = (void *)&op_mode_cfg;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ }
+ case VPE_CMD_INPUT_PLANE_CFG: {
+ struct msm_vpe_input_plane_cfg input_cfg;
+ if (sizeof(struct msm_vpe_input_plane_cfg) !=
+ pp_cmd->length) {
+ D("%s: mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_input_plane_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(
+ &input_cfg, pp_cmd->value, sizeof(input_cfg)))
+ return -EFAULT;
+ pp_cmd->value = (void *)&input_cfg;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ }
+ case VPE_CMD_OUTPUT_PLANE_CFG: {
+ struct msm_vpe_output_plane_cfg output_cfg;
+ if (sizeof(struct msm_vpe_output_plane_cfg) !=
+ pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_output_plane_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&output_cfg, pp_cmd->value,
+ sizeof(output_cfg))) {
+ D("%s: cannot copy pp_cmd->value, size=%d",
+ __func__, pp_cmd->length);
+ return -EFAULT;
+ }
+ pp_cmd->value = (void *)&output_cfg;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ }
+ case VPE_CMD_INPUT_PLANE_UPDATE: {
+ struct msm_vpe_input_plane_update_cfg input_update_cfg;
+ if (sizeof(struct msm_vpe_input_plane_update_cfg) !=
+ pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_input_plane_update_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&input_update_cfg, pp_cmd->value,
+ sizeof(input_update_cfg)))
+ return -EFAULT;
+ pp_cmd->value = (void *)&input_update_cfg;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ }
+ case VPE_CMD_SCALE_CFG_TYPE: {
+ struct msm_vpe_scaler_cfg scaler_cfg;
+ if (sizeof(struct msm_vpe_scaler_cfg) !=
+ pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(struct msm_vpe_scaler_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&scaler_cfg, pp_cmd->value,
+ sizeof(scaler_cfg)))
+ return -EFAULT;
+ pp_cmd->value = (void *)&scaler_cfg;
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, NULL);
+ break;
+ }
+ case VPE_CMD_ZOOM: {
+ struct msm_mctl_pp_frame_info *zoom;
+ zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
+ GFP_ATOMIC);
+ if (!zoom) {
+ rc = -ENOMEM;
+ break;
+ }
+ if (sizeof(zoom->pp_frame_cmd) != pp_cmd->length) {
+ D("%s: size mismatch(id=%d, len = %d, expected = %d",
+ __func__, pp_cmd->id, pp_cmd->length,
+ sizeof(zoom->pp_frame_cmd));
+ rc = -EINVAL;
+ kfree(zoom);
+ break;
+ }
+ if (copy_from_user(&zoom->pp_frame_cmd, pp_cmd->value,
+ sizeof(zoom->pp_frame_cmd))) {
+ kfree(zoom);
+ return -EFAULT;
+ }
+ D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
+ __func__, zoom->pp_frame_cmd.src_buf_handle,
+ zoom->pp_frame_cmd.dest_buf_handle,
+ zoom->pp_frame_cmd.cookie,
+ zoom->pp_frame_cmd.vpe_output_action,
+ zoom->pp_frame_cmd.path);
+
+ zoom->user_cmd = pp_cmd->id;
+ rc = msm_mctl_pp_get_phy_addr(
+ zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
+ if (rc) {
+ kfree(zoom);
+ break;
+ }
+ rc = msm_mctl_pp_get_phy_addr(
+ zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
+ if (rc) {
+ kfree(zoom);
+ break;
+ }
+ rc = msm_mctl_pp_copy_timestamp_and_frame_id(
+ zoom->pp_frame_cmd.src_buf_handle,
+
+ zoom->pp_frame_cmd.dest_buf_handle);
+ if (rc) {
+ kfree(zoom);
+ break;
+ }
+ rc = msm_isp_subdev_ioctl_vpe(
+ &p_mctl->isp_sdev->sd_vpe, pp_cmd, (void *)zoom);
+ if (rc) {
+ kfree(zoom);
+ break;
+ }
+ break;
+ }
+ default:
+ rc = -1;
+ break;
+ }
+ return rc;
+}
+
+static int msm_mctl_pp_path_to_msg_type(int path)
+{
+ switch (path) {
+ case OUTPUT_TYPE_P:
+ return VFE_MSG_OUTPUT_P;
+ case OUTPUT_TYPE_V:
+ return VFE_MSG_OUTPUT_V;
+ case OUTPUT_TYPE_S:
+ return VFE_MSG_OUTPUT_S;
+ case OUTPUT_TYPE_T:
+ default:
+ return VFE_MSG_OUTPUT_T;
+ }
+}
+
+int msm_mctl_pp_proc_cmd(struct msm_cam_media_controller *p_mctl,
+ struct msm_mctl_pp_cmd *pp_cmd)
+{
+ int rc = 0;
+ struct msm_mctl_pp_frame_buffer pp_buffer;
+ struct msm_frame_buffer *buf = NULL;
+ void __user *argp = (void __user *)pp_cmd->value;
+ int msg_type = VFE_MSG_OUTPUT_V;
+ unsigned long flags;
+
+ switch (pp_cmd->id) {
+ case MCTL_CMD_GET_FRAME_BUFFER: {
+ if (copy_from_user(&pp_buffer, pp_cmd->value,
+ sizeof(pp_buffer)))
+ return -EFAULT;
+ msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
+ buf = msm_mctl_get_free_buf(p_mctl, msg_type);
+ pp_buffer.buf_handle = (uint32_t)buf;
+ if (copy_to_user((void *)argp,
+ &pp_buffer,
+ sizeof(struct msm_mctl_pp_frame_buffer))) {
+ ERR_COPY_TO_USER();
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case MCTL_CMD_PUT_FRAME_BUFFER: {
+ if (copy_from_user(&pp_buffer, pp_cmd->value,
+ sizeof(pp_buffer)))
+ return -EFAULT;
+ msg_type = msm_mctl_pp_path_to_msg_type(pp_buffer.path);
+ buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
+ msm_mctl_put_free_buf(p_mctl, msg_type, buf);
+ break;
+ }
+ case MCTL_CMD_DIVERT_FRAME_PP_PATH: {
+ struct msm_mctl_pp_divert_pp divert_pp;
+ if (copy_from_user(&divert_pp, pp_cmd->value,
+ sizeof(divert_pp)))
+ return -EFAULT;
+ D("%s: PP_PATH, path=%d",
+ __func__, divert_pp.path);
+ spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+ p_mctl->pp_info.pp_ctrl.pp_msg_type = divert_pp.path;
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ D("%s: pp path = %d", __func__,
+ p_mctl->pp_info.pp_ctrl.pp_msg_type);
+ break;
+ }
+ case MCTL_CMD_DIVERT_FRAME_PP_DONE: {
+ struct msm_frame_buffer *buf = NULL;
+ if (copy_from_user(&pp_buffer, pp_cmd->value,
+ sizeof(pp_buffer)))
+ return -EFAULT;
+ buf = (struct msm_frame_buffer *)pp_buffer.buf_handle;
+ msg_type = msm_mctl_pp_path_to_msg_type(
+ pp_buffer.path);
+ if (msm_mctl_buf_del(p_mctl, msg_type, buf) == 0) {
+ vb2_buffer_done(&buf->vidbuf,
+ VB2_BUF_STATE_DONE);
+ }
+ }
+ break;
+ default:
+ rc = -EPERM;
+ break;
+ }
+ return rc;
+}
+
+
+int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = -EINVAL;
+ struct msm_mctl_post_proc_cmd pp_cmd;
+ void __user *argp = (void __user *)arg;
+
+ if (copy_from_user(&pp_cmd, argp, sizeof(pp_cmd)))
+ return -EFAULT;
+
+ switch (pp_cmd.type) {
+ case MSM_PP_CMD_TYPE_VPE:
+ rc = msm_mctl_pp_proc_vpe_cmd(p_mctl, &pp_cmd.cmd);
+ break;
+ case MSM_PP_CMD_TYPE_MCTL:
+ rc = msm_mctl_pp_proc_cmd(p_mctl, &pp_cmd.cmd);
+ break;
+ default:
+ rc = -EPERM;
+ break;
+ }
+ if (!rc) {
+ /* deep copy back the return value */
+ if (copy_to_user((void *)arg,
+ &pp_cmd,
+ sizeof(struct msm_mctl_post_proc_cmd))) {
+ ERR_COPY_TO_USER();
+ rc = -EFAULT;
+ }
+ }
+ return rc;
+}
+
+int msm_mctl_pp_notify(struct msm_cam_media_controller *p_mctl,
+ struct msm_mctl_pp_frame_info *pp_frame_info)
+{
+ struct msm_mctl_pp_frame_cmd *pp_frame_cmd;
+ pp_frame_cmd = &pp_frame_info->pp_frame_cmd;
+
+ D("%s: msm_cam_evt_divert_frame=%d",
+ __func__, sizeof(struct msm_mctl_pp_event_info));
+ if ((MSM_MCTL_PP_VPE_FRAME_TO_APP &
+ pp_frame_cmd->vpe_output_action)) {
+ struct msm_free_buf done_frame;
+ int msg_type =
+ msm_mctl_pp_path_to_msg_type(
+ pp_frame_cmd->path);
+
+ done_frame.ch_paddr[0] =
+ pp_frame_info->dest_frame.sp.phy_addr;
+ done_frame.vb =
+ pp_frame_info->dest_frame.handle;
+ msm_mctl_buf_done_pp(
+ p_mctl, msg_type, &done_frame, 0);
+ pr_err("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x",
+ __func__, done_frame.vb,
+ pp_frame_cmd->path, done_frame.ch_paddr[0]);
+ }
+ if ((MSM_MCTL_PP_VPE_FRAME_ACK &
+ pp_frame_cmd->vpe_output_action)) {
+ struct v4l2_event v4l2_evt;
+ struct msm_mctl_pp_event_info *pp_event_info;
+ memset(&v4l2_evt, 0, sizeof(v4l2_evt));
+ pp_event_info =
+ (struct msm_mctl_pp_event_info *)v4l2_evt.
+ u.data;
+ pp_event_info->event = MCTL_PP_EVENT_CMD_ACK;
+ pp_event_info->ack.cmd = pp_frame_info->user_cmd;
+ pp_event_info->ack.status = 0;
+ pp_event_info->ack.cookie = pp_frame_cmd->cookie;
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ MSM_CAM_RESP_MCTL_PP_EVENT;
+ v4l2_event_queue(
+ p_mctl->config_device->
+ config_stat_event_queue.pvdev,
+ &v4l2_evt);
+ pr_err("%s: ack to daemon, cookie=0x%x, event = 0x%x",
+ __func__, pp_frame_info->pp_frame_cmd.cookie,
+ v4l2_evt.type);
+ }
+ kfree(pp_frame_info); /* free mem */
+ return 0;
+}
+
+int msm_mctl_pp_reserve_free_frame(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg)
+{
+ struct msm_cam_evt_divert_frame frame;
+ int msg_type, image_mode, rc = 0;
+ struct msm_free_buf free_buf;
+ memset(&free_buf, 0, sizeof(struct msm_free_buf));
+ if (copy_from_user(&frame, arg,
+ sizeof(struct msm_cam_evt_divert_frame)))
+ return -EFAULT;
+ switch (frame.path) {
+ case OUTPUT_TYPE_P:
+ msg_type = VFE_MSG_OUTPUT_P;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ break;
+ case OUTPUT_TYPE_S:
+ msg_type = VFE_MSG_OUTPUT_S;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ break;
+ case OUTPUT_TYPE_V:
+ msg_type = VFE_MSG_OUTPUT_V;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+ break;
+ case OUTPUT_TYPE_T:
+ default:
+ rc = -EFAULT;
+ return rc;
+ }
+ rc = msm_mctl_reserve_free_buf(p_mctl, msg_type, &free_buf);
+ if (rc == 0) {
+ frame.phy_addr = free_buf.ch_paddr[0];
+ frame.vb = free_buf.vb;
+ if (copy_to_user((void *)arg,
+ &frame,
+ sizeof(frame))) {
+ ERR_COPY_TO_USER();
+ rc = -EFAULT;
+ }
+ }
+ D("%s: reserve free buf, rc = %d, phy = 0x%x",
+ __func__, rc, free_buf.ch_paddr[0]);
+ return rc;
+}
+
+int msm_mctl_pp_release_free_frame(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg)
+{
+ struct msm_cam_evt_divert_frame frame;
+ int msg_type, image_mode, rc = 0;
+ struct msm_free_buf free_buf;
+
+ if (copy_from_user(&frame, arg,
+ sizeof(struct msm_cam_evt_divert_frame)))
+ return -EFAULT;
+ switch (frame.path) {
+ case OUTPUT_TYPE_P:
+ msg_type = VFE_MSG_OUTPUT_P;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ break;
+ case OUTPUT_TYPE_S:
+ msg_type = VFE_MSG_OUTPUT_S;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ break;
+ case OUTPUT_TYPE_V:
+ msg_type = VFE_MSG_OUTPUT_V;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+ break;
+ case OUTPUT_TYPE_T:
+ default:
+ rc = -EFAULT;
+ return rc;
+ }
+ free_buf.ch_paddr[0] = frame.phy_addr;
+ rc = msm_mctl_release_free_buf(p_mctl, msg_type, &free_buf);
+ D("%s: release free buf, rc = %d, phy = 0x%x",
+ __func__, rc, free_buf.ch_paddr[0]);
+
+ return rc;
+}
+
+int msm_mctl_set_pp_key(struct msm_cam_media_controller *p_mctl,
+ void __user *arg)
+{
+ int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+ if (copy_from_user(&p_mctl->pp_info.pp_key,
+ arg, sizeof(p_mctl->pp_info.pp_key)))
+ rc = -EFAULT;
+ else
+ D("%s: mctl=0x%p, pp_key_setting=0x%x",
+ __func__, p_mctl, p_mctl->pp_info.pp_key);
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ return rc;
+}
+
+int msm_mctl_pp_done(
+ struct msm_cam_media_controller *p_mctl,
+ void __user *arg)
+{
+ struct msm_frame frame;
+ int msg_type, image_mode, rc = 0;
+ int dirty = 0;
+ struct msm_free_buf buf;
+ unsigned long flags;
+
+ if (copy_from_user(&frame, arg, sizeof(frame)))
+ return -EFAULT;
+ spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
+ switch (frame.path) {
+ case OUTPUT_TYPE_P:
+ msg_type = VFE_MSG_OUTPUT_P;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ break;
+ case OUTPUT_TYPE_S:
+ msg_type = VFE_MSG_OUTPUT_S;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ break;
+ case OUTPUT_TYPE_V:
+ msg_type = VFE_MSG_OUTPUT_V;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+ break;
+ case OUTPUT_TYPE_T:
+ default:
+ rc = -EFAULT;
+ goto err;
+ }
+ if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
+ memcpy(&buf,
+ &p_mctl->pp_info.div_frame[image_mode],
+ sizeof(buf));
+ memset(&p_mctl->pp_info.div_frame[image_mode],
+ 0, sizeof(buf));
+ if (p_mctl->pp_info.cur_frame_id[image_mode] !=
+ frame.frame_id) {
+ /* dirty frame. should not pass to app */
+ dirty = 1;
+ }
+ } else
+ buf.ch_paddr[0] = frame.buffer;
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ /* here buf.addr is phy_addr */
+ rc = msm_mctl_buf_done_pp(p_mctl, msg_type, &buf, dirty);
+ return rc;
+err:
+ spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+ return rc;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index a6915ff..81362d1 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -23,7 +23,6 @@
#include "msm.h"
#include "msm_vfe32.h"
-#include "msm_vpe1.h"
#include "msm_ispif.h"
atomic_t irq_cnt;
@@ -2015,13 +2014,6 @@
vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out2.ch1]);
}
vfe32_ctrl->recording_state = VFE_REC_STATE_STARTED;
- if (vpe_ctrl && vpe_ctrl->dis_en) {
- old_val = msm_io_r(
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
- old_val |= RS_CS_ENABLE_MASK;
- msm_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
- }
msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
CDBG("start video triggered .\n");
} else if (vfe32_ctrl->recording_state ==
@@ -3372,12 +3364,4 @@
vfe_syncdata = NULL;
}
-void msm_camvpe_fn_init(struct msm_camvpe_fn *fptr, void *data)
-{
- fptr->vpe_reg = msm_vpe_reg;
- fptr->send_frame_to_vpe = msm_send_frame_to_vpe;
- fptr->vpe_config = msm_vpe_config;
- fptr->vpe_cfg_update = msm_vpe_cfg_update;
- fptr->dis = &(vpe_ctrl->dis_en);
- vpe_ctrl->syncdata = data;
-}
+
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 5cd3d78..c59918d 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -16,44 +16,29 @@
#include <mach/irqs.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include "msm_vpe.h"
#include <linux/pm_qos_params.h>
#include <linux/clk.h>
#include <mach/clk.h>
#include <asm/div64.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include "msm.h"
+#include "msm_vpe.h"
static int vpe_enable(uint32_t);
static int vpe_disable(void);
-static int vpe_update_scaler(struct video_crop_t *pcrop);
-static struct vpe_device_type vpe_device_data;
-static struct vpe_device_type *vpe_device;
-struct vpe_ctrl_type *vpe_ctrl;
-static const char *vpe_general_cmd[] = {
- "VPE_DUMMY_0", /* 0 */
- "VPE_SET_CLK",
- "VPE_RESET",
- "VPE_START",
- "VPE_ABORT",
- "VPE_OPERATION_MODE_CFG", /* 5 */
- "VPE_INPUT_PLANE_CFG",
- "VPE_OUTPUT_PLANE_CFG",
- "VPE_INPUT_PLANE_UPDATE",
- "VPE_SCALE_CFG_TYPE",
- "VPE_ROTATION_CFG_TYPE", /* 10 */
- "VPE_AXI_OUT_CFG",
- "VPE_CMD_DIS_OFFSET_CFG",
- "VPE_ENABLE",
- "VPE_DISABLE",
-};
-static uint32_t orig_src_y, orig_src_cbcr;
+static int vpe_update_scaler(struct msm_pp_crop *pcrop);
+static struct vpe_device_type *vpe_device;
+struct vpe_ctrl_type *vpe_ctrl;
+static void *vpe_syncdata;
+static atomic_t vpe_init_done = ATOMIC_INIT(0);
-#define CHECKED_COPY_FROM_USER(in) { \
- if (copy_from_user((in), (void __user *)cmd->value, \
- cmd->length)) { \
- rc = -EFAULT; \
- break; \
- } \
-}
+static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
+ struct msm_mctl_pp_frame_info *pp_frame_info);
static long long vpe_do_div(long long num, long long den)
{
@@ -64,11 +49,15 @@
static int vpe_start(void)
{
/* enable the frame irq, bit 0 = Display list 0 ROI done */
- msm_io_w(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+ msm_io_w_mb(1, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
+ msm_io_dump(vpe_device->vpebase, 0x120);
msm_io_dump(vpe_device->vpebase + 0x10000, 0x250);
+ msm_io_dump(vpe_device->vpebase + 0x30000, 0x20);
+ msm_io_dump(vpe_device->vpebase + 0x50000, 0x30);
+ msm_io_dump(vpe_device->vpebase + 0x50400, 0x10);
/* this triggers the operation. */
msm_io_w(1, vpe_device->vpebase + VPE_DL0_START_OFFSET);
-
+ wmb();
return 0;
}
@@ -77,21 +66,15 @@
/* initialize local variables for state control, etc.*/
vpe_ctrl->op_mode = 0;
vpe_ctrl->state = VPE_STATE_INIT;
- spin_lock_init(&vpe_ctrl->tasklet_lock);
- spin_lock_init(&vpe_ctrl->state_lock);
- INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
}
static void vpe_config_axi_default(void)
{
msm_io_w(0x25, vpe_device->vpebase + VPE_AXI_ARB_2_OFFSET);
-
CDBG("%s: yaddr %ld cbcraddr %ld", __func__,
vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr);
-
if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr)
return;
-
msm_io_w(vpe_ctrl->out_y_addr,
vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
/* for video CbCr address */
@@ -103,20 +86,17 @@
static int vpe_reset(void)
{
uint32_t vpe_version;
- uint32_t rc;
+ uint32_t rc = 0;
vpe_reset_state_variables();
vpe_version = msm_io_r(vpe_device->vpebase + VPE_HW_VERSION_OFFSET);
CDBG("vpe_version = 0x%x\n", vpe_version);
-
/* disable all interrupts.*/
msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
/* clear all pending interrupts*/
msm_io_w(0x1fffff, vpe_device->vpebase + VPE_INTR_CLEAR_OFFSET);
-
/* write sw_reset to reset the core. */
msm_io_w(0x10, vpe_device->vpebase + VPE_SW_RESET_OFFSET);
-
/* then poll the reset bit, it should be self-cleared. */
while (1) {
rc =
@@ -124,7 +104,6 @@
if (rc == 0)
break;
}
-
/* at this point, hardware is reset. Then pogram to default
values. */
msm_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
@@ -132,31 +111,27 @@
msm_io_w(VPE_CGC_ENABLE_VALUE,
vpe_device->vpebase + VPE_CGC_EN_OFFSET);
-
msm_io_w(1, vpe_device->vpebase + VPE_CMD_MODE_OFFSET);
-
msm_io_w(VPE_DEFAULT_OP_MODE_VALUE,
vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
msm_io_w(VPE_DEFAULT_SCALE_CONFIG,
vpe_device->vpebase + VPE_SCALE_CONFIG_OFFSET);
-
vpe_config_axi_default();
- return 0;
+ return rc;
}
-int msm_vpe_cfg_update(void *pinfo)
+static int msm_vpe_cfg_update(void *pinfo)
{
uint32_t rot_flag, rc = 0;
- struct video_crop_t *pcrop = (struct video_crop_t *)pinfo;
+ struct msm_pp_crop *pcrop = (struct msm_pp_crop *)pinfo;
rot_flag = msm_io_r(vpe_device->vpebase +
VPE_OP_MODE_OFFSET) & 0xE00;
if (pinfo != NULL) {
- CDBG("Crop info in2_w = %d, in2_h = %d "
- "out2_h = %d out2_w = %d\n", pcrop->in2_w,
- pcrop->in2_h,
- pcrop->out2_h, pcrop->out2_w);
+ pr_err("%s: Crop info in2_w = %d, in2_h = %d "
+ "out2_w = %d out2_h = %d\n",
+ __func__, pcrop->src_w, pcrop->src_h,
+ pcrop->dst_w, pcrop->dst_h);
rc = vpe_update_scaler(pcrop);
}
CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag);
@@ -184,6 +159,7 @@
msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
vpe_ctrl->in_h_w = *p;
msm_io_w(*(++p), vpe_device->vpebase + VPE_SRC_XY_OFFSET);
+ CDBG("%s: in_h_w=0x%x", __func__, vpe_ctrl->in_h_w);
}
void vpe_output_plane_config(uint32_t *p)
@@ -204,7 +180,6 @@
temp = msm_io_r(vpe_device->vpebase + VPE_OUT_SIZE_OFFSET);
w = temp & 0xFFF;
h = (temp & 0xFFF0000) >> 16;
-
if (*p++ & 0xE00) {
/* rotation enabled. */
vpe_ctrl->out_w = h;
@@ -214,6 +189,8 @@
vpe_ctrl->out_h = h;
}
vpe_ctrl->dis_en = *p;
+ CDBG("%s: out_w=%d, out_h=%d, dis_en=%d",
+ __func__, vpe_ctrl->out_w, vpe_ctrl->out_h, vpe_ctrl->dis_en);
return 0;
}
@@ -221,7 +198,7 @@
* rotation is enabled, simply swap the destination dimension.
* And then pass the already swapped output size to this
* function. */
-static int vpe_update_scaler(struct video_crop_t *pcrop)
+static int vpe_update_scaler(struct msm_pp_crop *pcrop)
{
uint32_t out_ROI_width, out_ROI_height;
uint32_t src_ROI_width, src_ROI_height;
@@ -240,9 +217,8 @@
uint32_t yscale_filter_sel, xscale_filter_sel;
uint32_t scale_unit_sel_x, scale_unit_sel_y;
uint64_t numerator, denominator;
-
- if ((pcrop->in2_w >= pcrop->out2_w) &&
- (pcrop->in2_h >= pcrop->out2_h)) {
+ if ((pcrop->src_w >= pcrop->dst_w) &&
+ (pcrop->src_h >= pcrop->dst_h)) {
CDBG(" =======VPE no zoom needed.\n");
temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
@@ -267,10 +243,10 @@
msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) | 0x3;
msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
- src_ROI_width = pcrop->in2_w;
- src_ROI_height = pcrop->in2_h;
- out_ROI_width = pcrop->out2_w;
- out_ROI_height = pcrop->out2_h;
+ src_ROI_width = pcrop->src_w;
+ src_ROI_height = pcrop->src_h;
+ out_ROI_width = pcrop->dst_w;
+ out_ROI_height = pcrop->dst_h;
CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
src_ROI_width, src_ROI_height, out_ROI_width,
@@ -279,8 +255,8 @@
msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
- src_x = (out_ROI_width - src_ROI_width)/2;
- src_y = (out_ROI_height - src_ROI_height)/2;
+ src_x = pcrop->src_x;
+ src_y = pcrop->src_y;
CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
@@ -439,868 +415,118 @@
return 1;
}
-static int vpe_update_scaler_with_dis(struct video_crop_t *pcrop,
- struct dis_offset_type *dis_offset)
+static inline void vpe_get_zoom_dis_xy(
+ struct dis_offset_type *dis_offset,
+ struct msm_pp_crop *pcrop,
+ int32_t *zoom_dis_x,
+ int32_t *zoom_dis_y)
{
- uint32_t out_ROI_width, out_ROI_height;
- uint32_t src_ROI_width, src_ROI_height;
-
- uint32_t rc = 0; /* default to no zoom. */
- /*
- * phase_step_x, phase_step_y, phase_init_x and phase_init_y
- * are represented in fixed-point, unsigned 3.29 format
- */
- uint32_t phase_step_x = 0;
- uint32_t phase_step_y = 0;
- uint32_t phase_init_x = 0;
- uint32_t phase_init_y = 0;
-
- uint32_t src_roi, temp;
- int32_t src_x, src_y, src_xy;
- uint32_t yscale_filter_sel, xscale_filter_sel;
- uint32_t scale_unit_sel_x, scale_unit_sel_y;
- uint64_t numerator, denominator;
- int32_t zoom_dis_x, zoom_dis_y;
-
- CDBG("%s: pcrop->in2_w = %d, pcrop->in2_h = %d\n", __func__,
- pcrop->in2_w, pcrop->in2_h);
- CDBG("%s: pcrop->out2_w = %d, pcrop->out2_h = %d\n", __func__,
- pcrop->out2_w, pcrop->out2_h);
-
- if ((pcrop->in2_w >= pcrop->out2_w) &&
- (pcrop->in2_h >= pcrop->out2_h)) {
- CDBG(" =======VPE no zoom needed, DIS is still enabled.\n");
-
- temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET)
- & 0xfffffffc;
- msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
- /* no zoom, use dis offset directly. */
- src_xy = dis_offset->dis_offset_y * (1<<16) +
- dis_offset->dis_offset_x;
-
- msm_io_w(src_xy, vpe_device->vpebase + VPE_SRC_XY_OFFSET);
-
- CDBG("vpe_ctrl->in_h_w = 0x%x\n", vpe_ctrl->in_h_w);
- msm_io_w(vpe_ctrl->in_h_w, vpe_device->vpebase +
- VPE_SRC_SIZE_OFFSET);
- return rc;
- }
- /* If fall through then scaler is needed.*/
-
- CDBG("========VPE zoom needed + DIS enabled.\n");
- /* assumption is both direction need zoom. this can be
- improved. */
- temp = msm_io_r(vpe_device->vpebase +
- VPE_OP_MODE_OFFSET) | 0x3;
- msm_io_w(temp, vpe_device->vpebase +
- VPE_OP_MODE_OFFSET);
- zoom_dis_x = dis_offset->dis_offset_x *
- pcrop->in2_w / pcrop->out2_w;
- zoom_dis_y = dis_offset->dis_offset_y *
- pcrop->in2_h / pcrop->out2_h;
-
- src_x = zoom_dis_x + (pcrop->out2_w-pcrop->in2_w)/2;
- src_y = zoom_dis_y + (pcrop->out2_h-pcrop->in2_h)/2;
-
- out_ROI_width = vpe_ctrl->out_w;
- out_ROI_height = vpe_ctrl->out_h;
-
- src_ROI_width = out_ROI_width * pcrop->in2_w / pcrop->out2_w;
- src_ROI_height = out_ROI_height * pcrop->in2_h / pcrop->out2_h;
-
- /* clamp to output size. This is because along
- processing, we mostly do truncation, therefore
- dis_offset tends to be
- smaller values. The intention was to make sure that the
- offset does not exceed margin. But in the case it could
- result src_roi bigger, due to subtract a smaller value. */
- CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
- src_ROI_width, src_ROI_height, out_ROI_width,
- out_ROI_height);
-
- src_roi = (src_ROI_height << 16) + src_ROI_width;
-
- msm_io_w(src_roi, vpe_device->vpebase + VPE_SRC_SIZE_OFFSET);
-
- CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
-
- src_xy = src_y*(1<<16) + src_x;
- msm_io_w(src_xy, vpe_device->vpebase +
- VPE_SRC_XY_OFFSET);
- CDBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
-
- /* decide whether to use FIR or M/N for scaling */
- if ((out_ROI_width == 1 && src_ROI_width < 4) ||
- (src_ROI_width < 4 * out_ROI_width - 3))
- scale_unit_sel_x = 0;/* use FIR scalar */
- else
- scale_unit_sel_x = 1;/* use M/N scalar */
-
- if ((out_ROI_height == 1 && src_ROI_height < 4) ||
- (src_ROI_height < 4 * out_ROI_height - 3))
- scale_unit_sel_y = 0;/* use FIR scalar */
- else
- scale_unit_sel_y = 1;/* use M/N scalar */
- /* calculate phase step for the x direction */
-
- /* if destination is only 1 pixel wide, the value of
- phase_step_x is unimportant. Assigning phase_step_x
- to src ROI width as an arbitrary value. */
- if (out_ROI_width == 1)
- phase_step_x = (uint32_t) ((src_ROI_width) <<
- SCALER_PHASE_BITS);
- else if (scale_unit_sel_x == 0) { /* if using FIR scalar */
- /* Calculate the quotient ( src_ROI_width - 1 )
- / ( out_ROI_width - 1)with u3.29 precision.
- Quotient is rounded up to the larger
- 29th decimal point. */
- numerator =
- (uint64_t)(src_ROI_width - 1) <<
- SCALER_PHASE_BITS;
- /* never equals to 0 because of the "
- (out_ROI_width == 1 )"*/
- denominator = (uint64_t)(out_ROI_width - 1);
- /* divide and round up to the larger 29th
- decimal point. */
- phase_step_x = (uint32_t) vpe_do_div(
- (numerator + denominator - 1), denominator);
- } else if (scale_unit_sel_x == 1) { /* if M/N scalar */
- /* Calculate the quotient
- ( src_ROI_width ) / ( out_ROI_width)
- with u3.29 precision. Quotient is rounded
- down to the smaller 29th decimal point. */
- numerator = (uint64_t)(src_ROI_width) <<
- SCALER_PHASE_BITS;
- denominator = (uint64_t)(out_ROI_width);
- phase_step_x =
- (uint32_t) vpe_do_div(numerator, denominator);
- }
- /* calculate phase step for the y direction */
-
- /* if destination is only 1 pixel wide, the value of
- phase_step_x is unimportant. Assigning phase_step_x
- to src ROI width as an arbitrary value. */
- if (out_ROI_height == 1)
- phase_step_y =
- (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
- else if (scale_unit_sel_y == 0) { /* if FIR scalar */
- /* Calculate the quotient
- ( src_ROI_height - 1 ) / ( out_ROI_height - 1)
- with u3.29 precision. Quotient is rounded up to the
- larger 29th decimal point. */
- numerator = (uint64_t)(src_ROI_height - 1) <<
- SCALER_PHASE_BITS;
- /* never equals to 0 because of the
- "( out_ROI_height == 1 )" case */
- denominator = (uint64_t)(out_ROI_height - 1);
- /* Quotient is rounded up to the larger 29th
- decimal point. */
- phase_step_y =
- (uint32_t) vpe_do_div(
- (numerator + denominator - 1), denominator);
- } else if (scale_unit_sel_y == 1) { /* if M/N scalar */
- /* Calculate the quotient ( src_ROI_height ) / ( out_ROI_height)
- with u3.29 precision. Quotient is rounded down to the smaller
- 29th decimal point. */
- numerator = (uint64_t)(src_ROI_height) <<
- SCALER_PHASE_BITS;
- denominator = (uint64_t)(out_ROI_height);
- phase_step_y = (uint32_t) vpe_do_div(
- numerator, denominator);
- }
-
- /* decide which set of FIR coefficients to use */
- if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
- xscale_filter_sel = 0;
- else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
- xscale_filter_sel = 1;
- else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
- xscale_filter_sel = 2;
- else
- xscale_filter_sel = 3;
-
- if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
- yscale_filter_sel = 0;
- else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
- yscale_filter_sel = 1;
- else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
- yscale_filter_sel = 2;
- else
- yscale_filter_sel = 3;
-
- /* calculate phase init for the x direction */
-
- /* if using FIR scalar */
- if (scale_unit_sel_x == 0) {
- if (out_ROI_width == 1)
- phase_init_x =
- (uint32_t) ((src_ROI_width - 1) <<
- SCALER_PHASE_BITS);
- else
- phase_init_x = 0;
-
- } else if (scale_unit_sel_x == 1) /* M over N scalar */
- phase_init_x = 0;
-
- /* calculate phase init for the y direction
- if using FIR scalar */
- if (scale_unit_sel_y == 0) {
- if (out_ROI_height == 1)
- phase_init_y =
- (uint32_t) ((src_ROI_height -
- 1) << SCALER_PHASE_BITS);
- else
- phase_init_y = 0;
-
- } else if (scale_unit_sel_y == 1) /* M over N scalar */
- phase_init_y = 0;
-
- CDBG("phase step x = %d, step y = %d.\n",
- phase_step_x, phase_step_y);
- CDBG("phase init x = %d, init y = %d.\n",
- phase_init_x, phase_init_y);
-
- msm_io_w(phase_step_x, vpe_device->vpebase +
- VPE_SCALE_PHASEX_STEP_OFFSET);
-
- msm_io_w(phase_step_y, vpe_device->vpebase +
- VPE_SCALE_PHASEY_STEP_OFFSET);
-
- msm_io_w(phase_init_x, vpe_device->vpebase +
- VPE_SCALE_PHASEX_INIT_OFFSET);
-
- msm_io_w(phase_init_y, vpe_device->vpebase +
- VPE_SCALE_PHASEY_INIT_OFFSET);
-
- return 1;
+ *zoom_dis_x = dis_offset->dis_offset_x *
+ pcrop->src_w / pcrop->dst_w;
+ *zoom_dis_y = dis_offset->dis_offset_y *
+ pcrop->src_h / pcrop->dst_h;
}
-void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
- struct timespec *ts, int output_type)
+int msm_vpe_is_busy(void)
{
- uint32_t temp_pyaddr = 0, temp_pcbcraddr = 0;
-
- CDBG("vpe input, pyaddr = 0x%x, pcbcraddr = 0x%x\n",
- pyaddr, pcbcraddr);
- msm_io_w(pyaddr, vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
- msm_io_w(pcbcraddr, vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
-
+ int busy = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state == VPE_STATE_ACTIVE)
- CDBG(" =====VPE is busy!!! Wrong!========\n");
+ busy = 1;
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ return busy;
+}
+static int msm_send_frame_to_vpe(void)
+{
+ int rc = 0;
+ unsigned long flags;
- if (output_type != OUTPUT_TYPE_ST_R)
- vpe_ctrl->ts = *ts;
-
- if (output_type == OUTPUT_TYPE_ST_L) {
- vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- temp_pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- temp_pcbcraddr = temp_pyaddr + PAD_TO_2K(vpe_ctrl->out_w *
- vpe_ctrl->out_h * 2, vpe_ctrl->pad_2k_bool);
- msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- }
-
- if (vpe_ctrl->dis_en) {
- /* Changing the VPE output CBCR address,
- to make Y/CBCR continuous */
- vpe_ctrl->pcbcr_before_dis = msm_io_r(vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- temp_pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- temp_pcbcraddr = temp_pyaddr + vpe_ctrl->pcbcr_dis_offset;
- msm_io_w(temp_pcbcraddr, vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- }
-
- vpe_ctrl->output_type = output_type;
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
+ msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.sp.y_off),
+ vpe_device->vpebase + VPE_SRCP0_ADDR_OFFSET);
+ msm_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off),
+ vpe_device->vpebase + VPE_SRCP1_ADDR_OFFSET);
+ msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.sp.y_off),
+ vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
+ msm_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off),
+ vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
vpe_ctrl->state = VPE_STATE_ACTIVE;
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
vpe_start();
-}
-
-static int vpe_proc_general(struct msm_vpe_cmd *cmd)
-{
- int rc = 0;
- uint32_t *cmdp = NULL;
- struct msm_queue_cmd *qcmd = NULL;
- struct msm_vpe_buf_info *vpe_buf;
- int turbo_mode = 0;
- struct msm_sync *sync = (struct msm_sync *)vpe_ctrl->syncdata;
- CDBG("vpe_proc_general: cmdID = %s, length = %d\n",
- vpe_general_cmd[cmd->id], cmd->length);
- switch (cmd->id) {
- case VPE_ENABLE:
- cmdp = kmalloc(cmd->length, GFP_ATOMIC);
- if (!cmdp) {
- rc = -ENOMEM;
- goto vpe_proc_general_done;
- }
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- cmd->length)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- turbo_mode = *((int *)(cmd->value));
- rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE)
- : vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
- break;
- case VPE_DISABLE:
- rc = vpe_disable();
- break;
- case VPE_RESET:
- case VPE_ABORT:
- rc = vpe_reset();
- break;
- case VPE_START:
- rc = vpe_start();
- break;
-
- case VPE_INPUT_PLANE_CFG:
- cmdp = kmalloc(cmd->length, GFP_ATOMIC);
- if (!cmdp) {
- rc = -ENOMEM;
- goto vpe_proc_general_done;
- }
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- cmd->length)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- vpe_input_plane_config(cmdp);
- break;
-
- case VPE_OPERATION_MODE_CFG:
- CDBG("cmd->length = %d\n", cmd->length);
- if (cmd->length != VPE_OPERATION_MODE_CFG_LEN) {
- rc = -EINVAL;
- goto vpe_proc_general_done;
- }
- cmdp = kmalloc(VPE_OPERATION_MODE_CFG_LEN,
- GFP_ATOMIC);
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- VPE_OPERATION_MODE_CFG_LEN)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- rc = vpe_operation_config(cmdp);
- CDBG("rc = %d\n", rc);
- break;
-
- case VPE_OUTPUT_PLANE_CFG:
- cmdp = kmalloc(cmd->length, GFP_ATOMIC);
- if (!cmdp) {
- rc = -ENOMEM;
- goto vpe_proc_general_done;
- }
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- cmd->length)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- vpe_output_plane_config(cmdp);
- break;
-
- case VPE_SCALE_CFG_TYPE:
- cmdp = kmalloc(cmd->length, GFP_ATOMIC);
- if (!cmdp) {
- rc = -ENOMEM;
- goto vpe_proc_general_done;
- }
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- cmd->length)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- vpe_update_scale_coef(cmdp);
- break;
-
- case VPE_CMD_DIS_OFFSET_CFG: {
- struct msm_vfe_resp *vdata;
- unsigned long flags;
- /* first get the dis offset and frame id. */
- cmdp = kmalloc(cmd->length, GFP_ATOMIC);
- if (!cmdp) {
- rc = -ENOMEM;
- goto vpe_proc_general_done;
- }
- if (copy_from_user(cmdp,
- (void __user *)(cmd->value),
- cmd->length)) {
- rc = -EFAULT;
- goto vpe_proc_general_done;
- }
- /* get the offset. */
- vpe_ctrl->dis_offset = *(struct dis_offset_type *)cmdp;
- spin_lock_irqsave(&sync->vpe_q.lock, flags);
- if (!list_empty(&sync->vpe_q.list)) {
- sync->vpe_q.len--;
- qcmd = list_first_entry(&sync->vpe_q.list,
- struct msm_queue_cmd, list_vpe_frame);
- list_del_init(&qcmd->list_vpe_frame);
- } else
- qcmd = NULL;
- spin_unlock_irqrestore(&sync->vpe_q.lock, flags);
- if (!qcmd) {
- pr_err("%s: no video frame.\n", __func__);
- kfree(cmdp);
- return -EAGAIN;
- }
- vdata = (struct msm_vfe_resp *)(qcmd->command);
- vpe_buf = &vdata->vpe_bf;
- vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop),
- &(vpe_ctrl->dis_offset));
-
- msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy,
- &(vpe_buf->ts), OUTPUT_TYPE_V);
-
- if (!qcmd || !atomic_read(&qcmd->on_heap)) {
- kfree(cmdp);
- return -EAGAIN;
- }
- if (!atomic_sub_return(1, &qcmd->on_heap))
- kfree(qcmd);
- break;
- }
-
- default:
- break;
- }
-vpe_proc_general_done:
- kfree(cmdp);
return rc;
}
-static void vpe_addr_convert(struct msm_vpe_phy_info *pinfo,
- enum vpe_resp_msg type, void *data, void **ext, int32_t *elen)
+static void vpe_send_outmsg(void)
{
- CDBG("In vpe_addr_convert type = %d\n", type);
- switch (type) {
- case VPE_MSG_OUTPUT_V:
- pinfo->output_id = OUTPUT_TYPE_V;
- break;
- case VPE_MSG_OUTPUT_ST_R:
- /* output_id will be used by user space only. */
- pinfo->output_id = OUTPUT_TYPE_V;
- break;
- default:
- break;
- } /* switch */
-
- CDBG("In vpe_addr_convert output_id = %d\n", pinfo->output_id);
-
- pinfo->y_phy =
- ((struct vpe_message *)data)->_u.msgOut.yBuffer;
- pinfo->cbcr_phy =
- ((struct vpe_message *)data)->_u.msgOut.cbcrBuffer;
- *ext = vpe_ctrl->extdata;
- *elen = vpe_ctrl->extlen;
-}
-
-void vpe_proc_ops(uint8_t id, void *msg, size_t len)
-{
- struct msm_vpe_resp *rp;
-
- rp = vpe_ctrl->resp->vpe_alloc(sizeof(struct msm_vpe_resp),
- vpe_ctrl->syncdata, GFP_ATOMIC);
- if (!rp) {
- CDBG("rp: cannot allocate buffer\n");
- return;
- }
-
- CDBG("vpe_proc_ops, msgId = %d rp->evt_msg.msg_id = %d\n",
- id, rp->evt_msg.msg_id);
- rp->evt_msg.type = MSM_CAMERA_MSG;
- rp->evt_msg.msg_id = id;
- rp->evt_msg.len = len;
- rp->evt_msg.data = msg;
-
- switch (rp->evt_msg.msg_id) {
- case MSG_ID_VPE_OUTPUT_V:
- rp->type = VPE_MSG_OUTPUT_V;
- vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_V,
- rp->evt_msg.data, &(rp->extdata),
- &(rp->extlen));
- break;
-
- case MSG_ID_VPE_OUTPUT_ST_R:
- rp->type = VPE_MSG_OUTPUT_ST_R;
- vpe_addr_convert(&(rp->phy), VPE_MSG_OUTPUT_ST_R,
- rp->evt_msg.data, &(rp->extdata),
- &(rp->extlen));
- break;
-
- case MSG_ID_VPE_OUTPUT_ST_L:
- rp->type = VPE_MSG_OUTPUT_ST_L;
- break;
-
- default:
- rp->type = VPE_MSG_GENERAL;
- break;
- }
- CDBG("%s: time = %ld\n",
- __func__, vpe_ctrl->ts.tv_nsec);
-
- vpe_ctrl->resp->vpe_resp(rp, MSM_CAM_Q_VPE_MSG,
- vpe_ctrl->syncdata,
- &(vpe_ctrl->ts), GFP_ATOMIC);
-}
-
-int vpe_config_axi(struct axidata *ad)
-{
- uint32_t p1;
- struct msm_pmem_region *regp1 = NULL;
- CDBG("vpe_config_axi:bufnum1 = %d.\n", ad->bufnum1);
-
- if (ad->bufnum1 != 1)
- return -EINVAL;
-
- regp1 = &(ad->region[0]);
- /* for video Y address */
- p1 = (regp1->paddr + regp1->info.y_off);
- msm_io_w(p1, vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
- /* for video CbCr address */
- p1 = (regp1->paddr + regp1->info.cbcr_off);
- msm_io_w(p1, vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
-
- return 0;
-}
-
-int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data)
-{
- struct msm_vpe_cmd vpecmd;
- int rc = 0;
- if (copy_from_user(&vpecmd,
- (void __user *)(cmd->value),
- sizeof(vpecmd))) {
- pr_err("%s %d: copy_from_user failed\n", __func__,
- __LINE__);
- return -EFAULT;
- }
- CDBG("%s: cmd_type %d\n", __func__, cmd->cmd_type);
- switch (cmd->cmd_type) {
- case CMD_VPE:
- rc = vpe_proc_general(&vpecmd);
- CDBG(" rc = %d\n", rc);
- break;
-
- case CMD_AXI_CFG_VPE:
- case CMD_AXI_CFG_SNAP_VPE:
- case CMD_AXI_CFG_SNAP_THUMB_VPE: {
- struct axidata *axid;
- axid = data;
- if (!axid)
- return -EFAULT;
- vpe_config_axi(axid);
- break;
- }
- default:
- break;
- }
- CDBG("%s: rc = %d\n", __func__, rc);
- return rc;
-}
-
-void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr, uint32_t pcbcraddr,
- struct timespec *ts, int output_id, struct msm_st_half st_half,
- int frameid)
-{
- struct msm_vpe_buf_info vpe_buf;
- uint32_t input_stride;
-
- vpe_buf.vpe_crop.in2_w = st_half.stCropInfo.in_w;
- vpe_buf.vpe_crop.in2_h = st_half.stCropInfo.in_h;
- vpe_buf.vpe_crop.out2_w = st_half.stCropInfo.out_w;
- vpe_buf.vpe_crop.out2_h = st_half.stCropInfo.out_h;
- vpe_ctrl->dis_offset.dis_offset_x = st_half.pix_x_off;
- vpe_ctrl->dis_offset.dis_offset_y = st_half.pix_y_off;
- vpe_ctrl->dis_offset.frame_id = frameid;
- vpe_ctrl->frame_pack = frame_pack;
- vpe_ctrl->output_type = output_id;
-
- input_stride = (st_half.buf_cbcr_stride * (1<<16)) +
- st_half.buf_y_stride;
-
- msm_io_w(input_stride, vpe_device->vpebase + VPE_SRC_YSTRIDE1_OFFSET);
-
- vpe_update_scaler_with_dis(&(vpe_buf.vpe_crop),
- &(vpe_ctrl->dis_offset));
-
- msm_send_frame_to_vpe(pyaddr, pcbcraddr, ts, output_id);
-}
-
-static void vpe_send_outmsg(uint8_t msgid, uint32_t pyaddr,
- uint32_t pcbcraddr)
-{
- struct vpe_message msg;
- uint8_t outid;
- msg._d = outid = msgid;
- msg._u.msgOut.output_id = msgid;
- msg._u.msgOut.yBuffer = pyaddr;
- msg._u.msgOut.cbcrBuffer = pcbcraddr;
- vpe_proc_ops(outid, &msg, sizeof(struct vpe_message));
- return;
-}
-
-int msm_vpe_reg(struct msm_vpe_callback *presp)
-{
- if (presp && presp->vpe_resp)
- vpe_ctrl->resp = presp;
-
- return 0;
-}
-
-static void vpe_send_msg_no_payload(enum VPE_MESSAGE_ID id)
-{
- struct vpe_message msg;
-
- CDBG("vfe31_send_msg_no_payload\n");
- msg._d = id;
- vpe_proc_ops(id, &msg, 0);
+ unsigned long flags;
+ struct msm_vpe_resp rp;
+ memset(&rp, 0, sizeof(rp));
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
+ rp.type = vpe_ctrl->pp_frame_info->pp_frame_cmd.path;
+ rp.extdata = (void *)vpe_ctrl->pp_frame_info;
+ rp.extlen = sizeof(*vpe_ctrl->pp_frame_info);
+ vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */
+ vpe_ctrl->pp_frame_info = NULL;
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ v4l2_subdev_notify(vpe_ctrl->subdev,
+ NOTIFY_VPE_MSG_EVT, (void *)&rp);
}
static void vpe_do_tasklet(unsigned long data)
{
- unsigned long flags;
- uint32_t pyaddr = 0, pcbcraddr = 0;
- uint32_t src_y, src_cbcr, temp;
+ CDBG("%s: irq_status = 0x%x",
+ __func__, vpe_ctrl->irq_status);
+ if (vpe_ctrl->irq_status & 0x1)
+ vpe_send_outmsg();
- struct vpe_isr_queue_cmd_type *qcmd = NULL;
-
- CDBG("=== vpe_do_tasklet start ===\n");
-
- spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
- qcmd = list_first_entry(&vpe_ctrl->tasklet_q,
- struct vpe_isr_queue_cmd_type, list);
-
- if (!qcmd) {
- spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
- return;
- }
-
- list_del(&qcmd->list);
- spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
-
- /* interrupt to be processed, *qcmd has the payload. */
- if (qcmd->irq_status & 0x1) {
- if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_L) {
- CDBG("vpe left frame done.\n");
- vpe_ctrl->output_type = 0;
- CDBG("vpe send out msg.\n");
- orig_src_y = msm_io_r(vpe_device->vpebase +
- VPE_SRCP0_ADDR_OFFSET);
- orig_src_cbcr = msm_io_r(vpe_device->vpebase +
- VPE_SRCP1_ADDR_OFFSET);
-
- pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- pcbcraddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- CDBG("%s: out_w = %d, out_h = %d\n", __func__,
- vpe_ctrl->out_w, vpe_ctrl->out_h);
-
- if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
- (vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
- msm_io_w(pyaddr + (vpe_ctrl->out_w *
- vpe_ctrl->out_h), vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- msm_io_w(pcbcraddr + (vpe_ctrl->out_w *
- vpe_ctrl->out_h/2),
- vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- } else if ((vpe_ctrl->frame_pack ==
- SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
- SIDE_BY_SIDE_FULL)) {
- msm_io_w(pyaddr + vpe_ctrl->out_w,
- vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- msm_io_w(pcbcraddr + vpe_ctrl->out_w,
- vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- } else
- CDBG("%s: Invalid packing = %d\n", __func__,
- vpe_ctrl->frame_pack);
-
- vpe_send_msg_no_payload(MSG_ID_VPE_OUTPUT_ST_L);
- vpe_ctrl->state = VPE_STATE_INIT;
- kfree(qcmd);
- return;
- } else if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
- src_y = orig_src_y;
- src_cbcr = orig_src_cbcr;
- CDBG("%s: out_w = %d, out_h = %d\n", __func__,
- vpe_ctrl->out_w, vpe_ctrl->out_h);
-
- if ((vpe_ctrl->frame_pack == TOP_DOWN_FULL) ||
- (vpe_ctrl->frame_pack == TOP_DOWN_HALF)) {
- pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET) -
- (vpe_ctrl->out_w * vpe_ctrl->out_h);
- } else if ((vpe_ctrl->frame_pack ==
- SIDE_BY_SIDE_HALF) || (vpe_ctrl->frame_pack ==
- SIDE_BY_SIDE_FULL)) {
- pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET) - vpe_ctrl->out_w;
- } else
- CDBG("%s: Invalid packing = %d\n", __func__,
- vpe_ctrl->frame_pack);
-
- pcbcraddr = vpe_ctrl->pcbcr_before_dis;
- } else {
- src_y = msm_io_r(vpe_device->vpebase +
- VPE_SRCP0_ADDR_OFFSET);
- src_cbcr = msm_io_r(vpe_device->vpebase +
- VPE_SRCP1_ADDR_OFFSET);
- pyaddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- pcbcraddr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- }
-
- if (vpe_ctrl->dis_en)
- pcbcraddr = vpe_ctrl->pcbcr_before_dis;
-
- msm_io_w(src_y,
- vpe_device->vpebase + VPE_OUTP0_ADDR_OFFSET);
- msm_io_w(src_cbcr,
- vpe_device->vpebase + VPE_OUTP1_ADDR_OFFSET);
-
- temp = msm_io_r(vpe_device->vpebase + VPE_OP_MODE_OFFSET) &
- 0xFFFFFFFC;
- msm_io_w(temp, vpe_device->vpebase + VPE_OP_MODE_OFFSET);
-
- /* now pass this frame to msm_camera.c. */
- if (vpe_ctrl->output_type == OUTPUT_TYPE_ST_R) {
- CDBG("vpe send out R msg.\n");
- vpe_send_outmsg(MSG_ID_VPE_OUTPUT_ST_R, pyaddr,
- pcbcraddr);
- } else if (vpe_ctrl->output_type == OUTPUT_TYPE_V) {
- CDBG("vpe send out V msg.\n");
- vpe_send_outmsg(MSG_ID_VPE_OUTPUT_V, pyaddr, pcbcraddr);
- }
-
- vpe_ctrl->output_type = 0;
- vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */
-
- }
- kfree(qcmd);
}
DECLARE_TASKLET(vpe_tasklet, vpe_do_tasklet, 0);
static irqreturn_t vpe_parse_irq(int irq_num, void *data)
{
- unsigned long flags;
- uint32_t irq_status = 0;
- struct vpe_isr_queue_cmd_type *qcmd;
-
- CDBG("vpe_parse_irq.\n");
- /* read and clear back-to-back. */
- irq_status = msm_io_r_mb(vpe_device->vpebase +
+ vpe_ctrl->irq_status = msm_io_r_mb(vpe_device->vpebase +
VPE_INTR_STATUS_OFFSET);
- msm_io_w_mb(irq_status, vpe_device->vpebase +
+ msm_io_w_mb(vpe_ctrl->irq_status, vpe_device->vpebase +
VPE_INTR_CLEAR_OFFSET);
-
msm_io_w(0, vpe_device->vpebase + VPE_INTR_ENABLE_OFFSET);
-
- if (irq_status == 0) {
- pr_err("%s: irq_status = 0,Something is wrong!\n", __func__);
- return IRQ_HANDLED;
- }
- irq_status &= 0x1;
- /* apply mask. only interested in bit 0. */
- if (irq_status) {
- qcmd = kzalloc(sizeof(struct vpe_isr_queue_cmd_type),
- GFP_ATOMIC);
- if (!qcmd) {
- pr_err("%s: qcmd malloc failed!\n", __func__);
- return IRQ_HANDLED;
- }
- /* must be 0x1 now. so in bottom half we don't really
- need to check. */
- qcmd->irq_status = irq_status & 0x1;
- spin_lock_irqsave(&vpe_ctrl->tasklet_lock, flags);
- list_add_tail(&qcmd->list, &vpe_ctrl->tasklet_q);
- spin_unlock_irqrestore(&vpe_ctrl->tasklet_lock, flags);
- tasklet_schedule(&vpe_tasklet);
- }
+ CDBG("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
+ tasklet_schedule(&vpe_tasklet);
return IRQ_HANDLED;
}
static int vpe_enable_irq(void)
{
- uint32_t rc = 0;
- rc = request_irq(vpe_device->vpeirq,
- vpe_parse_irq,
- IRQF_TRIGGER_HIGH, "vpe", 0);
+ uint32_t rc = 0;
+ enable_irq(vpe_device->vpeirq);
return rc;
}
-int msm_vpe_open(void)
-{
- int rc = 0;
-
- CDBG("%s: In\n", __func__);
-
- vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
- if (!vpe_ctrl) {
- pr_err("%s: no memory!\n", __func__);
- return -ENOMEM;
- }
-
- spin_lock_init(&vpe_ctrl->ops_lock);
- CDBG("%s: Out\n", __func__);
-
- return rc;
-}
-
-int msm_vpe_release(void)
-{
- /* clean up....*/
- int rc = 0;
- CDBG("%s: state %d\n", __func__, vpe_ctrl->state);
- if (vpe_ctrl->state != VPE_STATE_IDLE)
- rc = vpe_disable();
-
- kfree(vpe_ctrl);
- return rc;
-}
-
-
int vpe_enable(uint32_t clk_rate)
{
int rc = 0;
unsigned long flags = 0;
+ CDBG("%s", __func__);
/* don't change the order of clock and irq.*/
- CDBG("%s: enable_clock rate %u\n", __func__, clk_rate);
- spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state != VPE_STATE_IDLE) {
- CDBG("%s: VPE already enabled", __func__);
- spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
+ pr_err("%s: VPE already enabled", __func__);
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return 0;
}
vpe_ctrl->state = VPE_STATE_INIT;
- spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
-
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
rc = msm_camio_vpe_clk_enable(clk_rate);
if (rc < 0) {
pr_err("%s: msm_camio_vpe_clk_enable failed", __func__);
vpe_ctrl->state = VPE_STATE_IDLE;
return rc;
}
-
- CDBG("%s: enable_irq\n", __func__);
vpe_enable_irq();
-
- /* initialize the data structure - lock, queue etc. */
- spin_lock_init(&vpe_ctrl->tasklet_lock);
- INIT_LIST_HEAD(&vpe_ctrl->tasklet_q);
-
return rc;
}
@@ -1308,44 +534,149 @@
{
int rc = 0;
unsigned long flags = 0;
- CDBG("%s: called", __func__);
- spin_lock_irqsave(&vpe_ctrl->ops_lock, flags);
+ CDBG("%s", __func__);
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state == VPE_STATE_IDLE) {
CDBG("%s: VPE already disabled", __func__);
- spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
- return 0;
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ return rc;
}
vpe_ctrl->state = VPE_STATE_IDLE;
- spin_unlock_irqrestore(&vpe_ctrl->ops_lock, flags);
- vpe_ctrl->out_y_addr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP0_ADDR_OFFSET);
- vpe_ctrl->out_cbcr_addr = msm_io_r(vpe_device->vpebase +
- VPE_OUTP1_ADDR_OFFSET);
- free_irq(vpe_device->vpeirq, 0);
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ disable_irq(vpe_device->vpeirq);
tasklet_kill(&vpe_tasklet);
rc = msm_camio_vpe_clk_disable();
return rc;
}
-static int __msm_vpe_probe(struct platform_device *pdev)
+static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
+ struct msm_mctl_pp_frame_info *pp_frame_info)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vpe_ctrl->lock, flags);
+ if (vpe_ctrl->state == VPE_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ pr_err(" =====VPE is busy!!! Wrong!========\n");
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
+ vpe_ctrl->pp_frame_info = pp_frame_info;
+ msm_vpe_cfg_update(
+ &vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
+ rc = msm_send_frame_to_vpe();
+ return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int subdev_cmd, void *arg)
+{
+ struct msm_mctl_pp_params *vpe_params =
+ (struct msm_mctl_pp_params *)arg;
+ struct msm_mctl_pp_cmd *cmd = vpe_params->cmd;
+ int rc = 0;
+ switch (cmd->id) {
+ case VPE_CMD_INIT:
+ case VPE_CMD_DEINIT:
+ break;
+ case VPE_CMD_RESET:
+ rc = vpe_reset();
+ break;
+ case VPE_CMD_OPERATION_MODE_CFG:
+ rc = vpe_operation_config(cmd->value);
+ break;
+ case VPE_CMD_INPUT_PLANE_CFG:
+ vpe_input_plane_config(cmd->value);
+ break;
+ case VPE_CMD_OUTPUT_PLANE_CFG:
+ vpe_output_plane_config(cmd->value);
+ break;
+ case VPE_CMD_SCALE_CFG_TYPE:
+ vpe_update_scale_coef(cmd->value);
+ break;
+ case VPE_CMD_ZOOM: {
+ rc = msm_vpe_do_pp(cmd,
+ (struct msm_mctl_pp_frame_info *)vpe_params->data);
+ break;
+ }
+ case VPE_CMD_ENABLE: {
+ struct msm_vpe_clock_rate *clk_rate = cmd->value;
+ int turbo_mode = (int)clk_rate->rate;
+ rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
+ vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+ break;
+ }
+ case VPE_CMD_DISABLE:
+ rc = vpe_disable();
+ break;
+ case VPE_CMD_INPUT_PLANE_UPDATE:
+ case VPE_CMD_FLUSH:
+ case VPE_CMD_DIS_OFFSET_CFG:
+ default:
+ break;
+ }
+ CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
+ return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+ .ioctl = msm_vpe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+ .core = &msm_vpe_subdev_core_ops,
+};
+
+static int msm_vpe_resource_init(struct platform_device *pdev, void *sdata);
+
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev)
+{
+ int rc = 0;
+ CDBG("%s:begin", __func__);
+ if (atomic_read(&vpe_init_done)) {
+ pr_err("%s: VPE has been initialized", __func__);
+ return -EBUSY;
+ }
+ atomic_set(&vpe_init_done, 1);
+ vpe_syncdata = data;
+ rc = msm_vpe_resource_init(pdev, vpe_syncdata);
+ if (rc < 0) {
+ atomic_set(&vpe_init_done, 0);
+ return rc;
+ }
+ vpe_ctrl->subdev = sd;
+ v4l2_subdev_init(sd, &msm_vpe_subdev_ops);
+ v4l2_set_subdev_hostdata(sd, data);
+ snprintf(sd->name, sizeof(sd->name), "vpe");
+ spin_lock_init(&vpe_ctrl->lock);
+ CDBG("%s:end", __func__);
+ return rc;
+}
+EXPORT_SYMBOL(msm_vpe_subdev_init);
+
+static int msm_vpe_resource_init(struct platform_device *pdev,
+ void *sdata)
{
int rc = 0;
struct resource *vpemem, *vpeirq, *vpeio;
void __iomem *vpebase;
-
/* first allocate */
-
- vpe_device = &vpe_device_data;
- memset(vpe_device, 0, sizeof(struct vpe_device_type));
-
+ vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
+ if (!vpe_ctrl) {
+ rc = -ENOMEM;
+ goto vpe_free_device;
+ }
+ vpe_device = &vpe_ctrl->device_data;
/* does the device exist? */
- vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!vpeirq) {
pr_err("%s: no vpe irq resource.\n", __func__);
rc = -ENODEV;
goto vpe_free_device;
}
- vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!vpemem) {
pr_err("%s: no vpe mem resource!\n", __func__);
rc = -ENODEV;
@@ -1356,9 +687,8 @@
if (!vpeio) {
pr_err("%s: VPE region already claimed.\n", __func__);
rc = -EBUSY;
- goto vpe_free_device;
+ goto vpe_release_mem_region;
}
-
vpebase =
ioremap(vpemem->start,
(vpemem->end - vpemem->start) + 1);
@@ -1373,6 +703,11 @@
vpe_device->vpemem = vpemem;
vpe_device->vpeio = vpeio;
vpe_device->vpebase = vpebase;
+ rc = request_irq(vpe_device->vpeirq,
+ vpe_parse_irq,
+ IRQF_TRIGGER_HIGH, "vpe", 0);
+ disable_irq(vpe_device->vpeirq);
+ CDBG("%s:end: vpebase=0x%p", __func__, vpebase);
return rc; /* this rc should be zero.*/
iounmap(vpe_device->vpebase); /* this path should never occur */
@@ -1381,41 +716,32 @@
vpe_release_mem_region:
release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1);
vpe_free_device:
+ kfree(vpe_ctrl);
return rc; /* this rc should have error code. */
}
-static int __msm_vpe_remove(struct platform_device *pdev)
+void msm_vpe_subdev_release(struct platform_device *pdev)
{
- struct resource *vpemem;
- vpemem = vpe_device->vpemem;
+ struct resource *vpemem, *vpeio;
+ if (!atomic_read(&vpe_init_done)) {
+ /* no VPE object created */
+ pr_err("%s: no VPE object to release", __func__);
+ return;
+ }
+ CDBG("%s, free_irq\n", __func__);
+ free_irq(vpe_ctrl->device_data.vpeirq, 0);
- iounmap(vpe_device->vpebase);
- release_mem_region(vpemem->start,
- (vpemem->end - vpemem->start) + 1);
- return 0;
+ vpemem = vpe_ctrl->device_data.vpemem;
+ vpeio = vpe_ctrl->device_data.vpeio;
+
+ kfree(vpe_ctrl->extdata);
+ iounmap(vpe_ctrl->device_data.vpebase);
+ kfree(vpe_ctrl);
+ vpe_ctrl = NULL;
+ release_mem_region(vpemem->start, (vpemem->end - vpemem->start) + 1);
+ CDBG("%s, end\n", __func__);
+ vpe_syncdata = NULL;
+ atomic_set(&vpe_init_done, 0);
}
+EXPORT_SYMBOL(msm_vpe_subdev_release);
-static struct platform_driver msm_vpe_driver = {
- .probe = __msm_vpe_probe,
- .remove = __msm_vpe_remove,
- .driver = {
- .name = "msm_vpe",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init msm_vpe_init(void)
-{
- return platform_driver_register(&msm_vpe_driver);
-}
-module_init(msm_vpe_init);
-
-static void __exit msm_vpe_exit(void)
-{
- platform_driver_unregister(&msm_vpe_driver);
-}
-module_exit(msm_vpe_exit);
-
-MODULE_DESCRIPTION("msm vpe 1.0 driver");
-MODULE_VERSION("msm vpe driver 1.0");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 39f5781..40df0b0 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -72,67 +72,19 @@
#define VPE_HARDWARE_VERSION 0x00080308
#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/
#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924
-#define VPE_CMD_MODE_VALUE 0x1
+#define VPE_CMD_MODE_VALUE 0x1
#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004
#define VPE_CGC_ENABLE_VALUE 0xffff
#define VPE_DEFAULT_SCALE_CONFIG 0x3c
#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
#define VPE_TURBO_MODE_CLOCK_RATE 200000000
-/**************************************************/
-/*********** Start of command id ******************/
-/**************************************************/
-enum VPE_CMD_ID_ENUM {
- VPE_DUMMY_0 = 0,
- VPE_SET_CLK,
- VPE_RESET,
- VPE_START,
- VPE_ABORT,
- VPE_OPERATION_MODE_CFG, /* 5 */
- VPE_INPUT_PLANE_CFG,
- VPE_OUTPUT_PLANE_CFG,
- VPE_INPUT_PLANE_UPDATE,
- VPE_SCALE_CFG_TYPE,
- VPE_ROTATION_CFG_TYPE, /* 10 */
- VPE_AXI_OUT_CFG,
- VPE_CMD_DIS_OFFSET_CFG,
- VPE_ENABLE,
- VPE_DISABLE,
-};
-/* Length of each command. In bytes. (payload only) */
-#define VPE_OPERATION_MODE_CFG_LEN 8
-#define VPE_INPUT_PLANE_CFG_LEN 24
-#define VPE_OUTPUT_PLANE_CFG_LEN 20
-#define VPE_INPUT_PLANE_UPDATE_LEN 12
-#define VPE_SCALER_CONFIG_LEN 260
-#define VPE_DIS_OFFSET_CFG_LEN 12
+
/**************************************************/
/*********** End of command id ********************/
/**************************************************/
-struct msm_vpe_cmd {
- int32_t id;
- uint16_t length;
- void *value;
-};
-
-struct vpe_cmd_type {
- uint16_t id;
- uint32_t length;
-};
-
-struct vpe_isr_queue_cmd_type {
- struct list_head list;
- uint32_t irq_status;
-};
-
-enum VPE_MESSAGE_ID {
- MSG_ID_VPE_OUTPUT_V = 7, /* To match with that of VFE */
- MSG_ID_VPE_OUTPUT_ST_L,
- MSG_ID_VPE_OUTPUT_ST_R,
-};
-
enum vpe_state {
VPE_STATE_IDLE,
VPE_STATE_INIT,
@@ -155,11 +107,8 @@
};
struct vpe_ctrl_type {
- spinlock_t tasklet_lock;
- spinlock_t state_lock;
- spinlock_t ops_lock;
-
- struct list_head tasklet_q;
+ spinlock_t lock;
+ uint32_t irq_status;
void *syncdata;
uint16_t op_mode;
void *extdata;
@@ -179,6 +128,9 @@
enum vpe_state state;
unsigned long out_y_addr;
unsigned long out_cbcr_addr;
+ struct v4l2_subdev *subdev;
+ struct vpe_device_type device_data;
+ struct msm_mctl_pp_frame_info *pp_frame_info;
};
/*
@@ -238,28 +190,6 @@
int32_t phase_step_y;
};
-extern struct vpe_ctrl_type *vpe_ctrl;
-
-int msm_vpe_open(void);
-int msm_vpe_release(void);
-int msm_vpe_reg(struct msm_vpe_callback *presp);
-void msm_send_frame_to_vpe(uint32_t pyaddr, uint32_t pcbcraddr,
- struct timespec *ts, int output_id);
-int msm_vpe_config(struct msm_vpe_cfg_cmd *cmd, void *data);
-int msm_vpe_cfg_update(void *pinfo);
-void msm_vpe_offset_update(int frame_pack, uint32_t pyaddr,
- uint32_t pcbcraddr,
- struct timespec *ts, int output_id,
- struct msm_st_half st_half,
- int frameid);
-void msm_send_frame_with_crop_and_dis_offset(
- struct msm_vpe_buf_info *src_buf,
- struct msm_vpe_buf_info *dest_buf,
- int output_id,
- struct dis_offset_type *dis_offset);
-
-typedef void (*msm_vpe_buf_cb_t) (struct msm_vpe_buf_info *out_buf,
- uint8_t output_id, void *cookie);
#endif /*_MSM_VPE_H_*/
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index b69ce5d..ad515dd 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -144,6 +144,26 @@
#define MSM_CAM_IOCTL_ACTUATOR_IO_CFG \
_IOW(MSM_CAM_IOCTL_MAGIC, 43, struct msm_actuator_cfg_data *)
+#define MSM_CAM_IOCTL_MCTL_POST_PROC \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 44, struct msm_mctl_post_proc_cmd *)
+
+#define MSM_CAM_IOCTL_RESERVE_FREE_FRAME \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 45, struct msm_cam_evt_divert_frame *)
+
+#define MSM_CAM_IOCTL_RELEASE_FREE_FRAME \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 46, struct msm_cam_evt_divert_frame *)
+
+struct msm_mctl_pp_cmd {
+ int32_t id;
+ uint16_t length;
+ void *value;
+};
+
+struct msm_mctl_post_proc_cmd {
+ int32_t type;
+ struct msm_mctl_pp_cmd cmd;
+};
+
#define MSM_CAMERA_LED_OFF 0
#define MSM_CAMERA_LED_LOW 1
#define MSM_CAMERA_LED_HIGH 2
@@ -208,12 +228,15 @@
unsigned short node_idx;
unsigned long phy_addr;
uint32_t phy_offset;
- uint32_t offset;
+ uint32_t y_off;
+ uint32_t cbcr_off;
int32_t fd;
uint32_t frame_id;
int path;
uint32_t length;
struct timeval timestamp;
+ int do_pp;
+ uint32_t vb;
};
struct msm_isp_stats_event_ctrl {
@@ -224,17 +247,20 @@
} isp_data;
};
-#define MSM_CAM_RESP_CTRL 0
-#define MSM_CAM_RESP_STAT_EVT_MSG 1
-#define MSM_CAM_RESP_STEREO_OP_1 2
-#define MSM_CAM_RESP_STEREO_OP_2 3
-#define MSM_CAM_RESP_V4L2 4
+#define MSM_CAM_RESP_CTRL 0
+#define MSM_CAM_RESP_STAT_EVT_MSG 1
+#define MSM_CAM_RESP_STEREO_OP_1 2
+#define MSM_CAM_RESP_STEREO_OP_2 3
+#define MSM_CAM_RESP_V4L2 4
#define MSM_CAM_RESP_DIV_FRAME_EVT_MSG 5
-#define MSM_CAM_RESP_DONE_EVENT 6
-#define MSM_CAM_RESP_MAX 7
+#define MSM_CAM_RESP_DONE_EVENT 6
+#define MSM_CAM_RESP_MCTL_PP_EVENT 7
+#define MSM_CAM_RESP_MAX 8
#define MSM_CAM_APP_NOTIFY_EVENT 0
+
/* this one is used to send ctrl/status up to config thread */
+
struct msm_stats_event_ctrl {
/* 0 - ctrl_cmd from control thread,
* 1 - stats/event kernel,
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index b60216f..fd46692 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -172,4 +172,148 @@
void *value;
};
-#endif /* __MSM_ISP_H__ */
+
+#define VPE_CMD_DUMMY_0 0
+#define VPE_CMD_INIT 1
+#define VPE_CMD_DEINIT 2
+#define VPE_CMD_ENABLE 3
+#define VPE_CMD_DISABLE 4
+#define VPE_CMD_RESET 5
+#define VPE_CMD_FLUSH 6
+#define VPE_CMD_OPERATION_MODE_CFG 7
+#define VPE_CMD_INPUT_PLANE_CFG 8
+#define VPE_CMD_OUTPUT_PLANE_CFG 9
+#define VPE_CMD_INPUT_PLANE_UPDATE 10
+#define VPE_CMD_SCALE_CFG_TYPE 11
+#define VPE_CMD_DIS_OFFSET_CFG 12
+#define VPE_CMD_ZOOM 13
+
+#define MSM_PP_CMD_TYPE_NOT_USED 0 /* not used */
+#define MSM_PP_CMD_TYPE_VPE 1 /* VPE cmd */
+#define MSM_PP_CMD_TYPE_MCTL 2 /* MCTL cmd */
+
+#define MCTL_CMD_DUMMY_0 0 /* not used */
+#define MCTL_CMD_GET_FRAME_BUFFER 1 /* reserve a free frame buffer */
+#define MCTL_CMD_PUT_FRAME_BUFFER 2 /* return the free frame buffer */
+#define MCTL_CMD_DIVERT_FRAME_PP_PATH 3 /* divert frame for pp */
+#define MCTL_CMD_DIVERT_FRAME_PP_DONE 4 /* pp done. buf send to app */
+
+/* event typese sending to MCTL PP module */
+#define MCTL_PP_EVENT_NOTUSED 0
+#define MCTL_PP_EVENT_CMD_ACK 1
+
+#define VPE_OPERATION_MODE_CFG_LEN 8
+#define VPE_INPUT_PLANE_CFG_LEN 24
+#define VPE_OUTPUT_PLANE_CFG_LEN 24
+#define VPE_INPUT_PLANE_UPDATE_LEN 12
+#define VPE_SCALER_CONFIG_LEN 260
+#define VPE_DIS_OFFSET_CFG_LEN 12
+
+struct msm_vpe_op_mode_cfg {
+ uint8_t op_mode_cfg[VPE_OPERATION_MODE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_cfg {
+ uint8_t input_plane_cfg[VPE_INPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_output_plane_cfg {
+ uint8_t output_plane_cfg[VPE_OUTPUT_PLANE_CFG_LEN];
+};
+
+struct msm_vpe_input_plane_update_cfg {
+ uint8_t input_plane_update_cfg[VPE_INPUT_PLANE_UPDATE_LEN];
+};
+
+struct msm_vpe_scaler_cfg {
+ uint8_t scaler_cfg[VPE_SCALER_CONFIG_LEN];
+};
+
+struct msm_vpe_dis_offset_cfg {
+ uint8_t dis_offset_cfg[VPE_DIS_OFFSET_CFG_LEN];
+};
+
+struct msm_vpe_flush_frame_buffer {
+ uint32_t src_buf_handle;
+ uint32_t dest_buf_handle;
+ int path;
+};
+
+struct msm_mctl_pp_frame_buffer {
+ uint32_t buf_handle;
+ int path;
+};
+struct msm_mctl_pp_divert_pp {
+ int path;
+};
+struct msm_vpe_clock_rate {
+ uint32_t rate;
+};
+struct msm_pp_crop {
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t dst_x;
+ uint32_t dst_y;
+ uint32_t dst_w;
+ uint32_t dst_h;
+ uint8_t update_flag;
+};
+#define MSM_MCTL_PP_VPE_FRAME_ACK (1<<0)
+#define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1)
+
+struct msm_mctl_pp_frame_cmd {
+ uint32_t cookie;
+ uint8_t vpe_output_action;
+ uint32_t src_buf_handle;
+ uint32_t dest_buf_handle;
+ struct msm_pp_crop crop;
+ int path;
+ /* TBD: 3D related */
+};
+
+struct msm_mctl_pp_cmd_ack_event {
+ uint32_t cmd; /* VPE_CMD_ZOOM? */
+ int status; /* 0 done, < 0 err */
+ uint32_t cookie; /* daemon's cookie */
+};
+
+struct msm_pp_frame_sp {
+ unsigned long phy_addr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ uint32_t length;
+ int32_t fd;
+ uint32_t addr_offset;
+};
+
+struct msm_pp_frame_mp {
+ unsigned long phy_addr;
+ uint32_t data_offset;
+ uint32_t length;
+ int32_t fd;
+ uint32_t addr_offset;
+};
+
+struct msm_pp_frame {
+ uint32_t handle;
+ uint32_t frame_id;
+ unsigned short image_type;
+ unsigned short num_planes; /* 1 for sp */
+ struct timeval timestamp;
+ union {
+ struct msm_pp_frame_sp sp;
+ };
+};
+
+struct msm_mctl_pp_event_info {
+ int32_t event;
+ union {
+ struct msm_mctl_pp_cmd_ack_event ack;
+ };
+};
+
+
+#endif /*__MSM_ISP_H__*/
+