msm: Allow VPE driver to be configured directly.
Currently VPE hardware is being controlled through the config node. Since it is converted into a V4L2 subdevice, we could control it directly from userspace by issuing open, close and ioctl system calls. The ACK from VPE hardware shall be routed directly to userspace by putting the ACK event on the v4l2 event queue. Change-Id: I7f82a750a28732382627349da362dbee8e27b149 Signed-off-by: Kiran Kumar H N <hurlisal@codeaurora.org>
This commit is contained in:
committed by
Stephen Boyd
parent
adc2fa8f07
commit
bd50cd17b0
@@ -39,11 +39,16 @@
|
||||
#define MSM_V4L2_DIMENSION_SIZE 96
|
||||
#define MAX_DEV_NAME_LEN 50
|
||||
|
||||
#define ERR_USER_COPY(to) pr_debug("%s(%d): copy %s user\n", \
|
||||
#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
|
||||
__func__, __LINE__, ((to) ? "to" : "from"))
|
||||
#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
|
||||
#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
|
||||
|
||||
#define COPY_FROM_USER(error, dest, src, size) \
|
||||
(error = (copy_from_user(dest, src, size) ? -EFAULT : 0))
|
||||
#define COPY_TO_USER(error, dest, src, size) \
|
||||
(error = (copy_to_user(dest, src, size) ? -EFAULT : 0))
|
||||
|
||||
#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
|
||||
#define MSM_CSID_DRV_NAME "msm_csid"
|
||||
#define MSM_CSIC_DRV_NAME "msm_csic"
|
||||
@@ -102,6 +107,7 @@ enum msm_cam_subdev_type {
|
||||
qcmd = list_first_entry(&__q->list, \
|
||||
struct msm_queue_cmd, member); \
|
||||
list_del_init(&qcmd->member); \
|
||||
kfree(qcmd->command); \
|
||||
free_qcmd(qcmd); \
|
||||
}; \
|
||||
spin_unlock_irqrestore(&__q->lock, flags); \
|
||||
@@ -147,7 +153,6 @@ enum msm_camera_v4l2_subdev_notify {
|
||||
NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
|
||||
NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
|
||||
NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
|
||||
NOTIFY_VPE_MSG_EVT,
|
||||
NOTIFY_PCLK_CHANGE, /* arg = pclk */
|
||||
NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
|
||||
NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
|
||||
@@ -206,6 +211,7 @@ struct msm_mctl_pp_frame_info {
|
||||
struct msm_pp_frame src_frame;
|
||||
struct msm_pp_frame dest_frame;
|
||||
struct msm_mctl_pp_frame_cmd pp_frame_cmd;
|
||||
struct msm_cam_media_controller *p_mctl;
|
||||
};
|
||||
|
||||
struct msm_mctl_pp_ctrl {
|
||||
@@ -587,6 +593,10 @@ int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
|
||||
int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
|
||||
long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
|
||||
unsigned int cmd, unsigned long evt);
|
||||
int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom);
|
||||
void msm_queue_init(struct msm_device_queue *queue, const char *name);
|
||||
void msm_enqueue(struct msm_device_queue *queue, struct list_head *entry);
|
||||
void msm_drain_eventq(struct msm_device_queue *queue);
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _MSM_H */
|
||||
|
||||
@@ -742,13 +742,6 @@ static int msm_isp_config(struct msm_cam_media_controller *pmctl,
|
||||
|
||||
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
|
||||
switch (cmd) {
|
||||
case MSM_CAM_IOCTL_PICT_PP_DONE:
|
||||
/* Release the preview of snapshot frame
|
||||
* that was grabbed.
|
||||
*/
|
||||
/*rc = msm_pp_release(pmsm->sync, arg);*/
|
||||
break;
|
||||
|
||||
case MSM_CAM_IOCTL_CONFIG_VFE:
|
||||
/* Coming from config thread for update */
|
||||
rc = msm_config_vfe(sd, pmctl, argp);
|
||||
|
||||
@@ -454,7 +454,7 @@ int msm_mctl_buf_done(struct msm_cam_media_controller *p_mctl,
|
||||
image_mode, fbuf,
|
||||
&frame_id, 1);
|
||||
D("%s mctl node buf done %d\n", __func__, 0);
|
||||
return -EINVAL;
|
||||
return rc;
|
||||
} else {
|
||||
pr_err("%s Invalid instance, dropping buffer\n",
|
||||
__func__);
|
||||
|
||||
@@ -36,18 +36,6 @@
|
||||
#define D(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
static int msm_mctl_pp_vpe_ioctl(struct v4l2_subdev *vpe_sd,
|
||||
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(vpe_sd, core, ioctl, VIDIOC_MSM_VPE_CFG, &parm);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_mctl_pp_buf_divert(
|
||||
struct msm_cam_media_controller *pmctl,
|
||||
struct msm_cam_v4l2_dev_inst *pcam_inst,
|
||||
@@ -384,244 +372,6 @@ static int msm_mctl_pp_path_to_inst_index(struct msm_cam_v4l2_device *pcam,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int msm_mctl_pp_proc_vpe_cmd(
|
||||
struct msm_cam_media_controller *p_mctl,
|
||||
struct msm_mctl_pp_cmd *pp_cmd)
|
||||
{
|
||||
int rc = 0, idx;
|
||||
void __user *argp = (void __user *)pp_cmd->value;
|
||||
struct msm_cam_v4l2_dev_inst *pcam_inst;
|
||||
|
||||
switch (pp_cmd->id) {
|
||||
case VPE_CMD_INIT:
|
||||
case VPE_CMD_DEINIT:
|
||||
rc = msm_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, pp_cmd, NULL);
|
||||
break;
|
||||
case VPE_CMD_DISABLE:
|
||||
case VPE_CMD_RESET:
|
||||
rc = msm_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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) {
|
||||
pr_err("%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))) {
|
||||
pr_err("%s:clk_rate copy failed", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
pp_cmd->value = (void *)&clk_rate;
|
||||
rc = msm_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, 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);
|
||||
idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
|
||||
zoom->pp_frame_cmd.path);
|
||||
if (idx < 0) {
|
||||
pr_err("%s Invalid path, returning\n", __func__);
|
||||
kfree(zoom);
|
||||
return idx;
|
||||
}
|
||||
pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
|
||||
if (!pcam_inst) {
|
||||
pr_err("%s Invalid instance, returning\n", __func__);
|
||||
kfree(zoom);
|
||||
return -EINVAL;
|
||||
}
|
||||
zoom->user_cmd = pp_cmd->id;
|
||||
rc = msm_mctl_pp_get_phy_addr(pcam_inst,
|
||||
zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
|
||||
if (rc) {
|
||||
kfree(zoom);
|
||||
break;
|
||||
}
|
||||
rc = msm_mctl_pp_get_phy_addr(pcam_inst,
|
||||
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_mctl_pp_vpe_ioctl(
|
||||
p_mctl->vpe_sdev, pp_cmd, (void *)zoom);
|
||||
if (rc) {
|
||||
kfree(zoom);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_mctl_pp_path_to_img_mode(int path)
|
||||
{
|
||||
switch (path) {
|
||||
@@ -717,9 +467,6 @@ int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
|
||||
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;
|
||||
@@ -739,71 +486,6 @@ int msm_mctl_pp_ioctl(struct msm_cam_media_controller *p_mctl,
|
||||
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 img_mode =
|
||||
msm_mctl_pp_path_to_img_mode(
|
||||
pp_frame_cmd->path);
|
||||
if (img_mode < 0) {
|
||||
pr_err("%s Invalid image mode\n", __func__);
|
||||
return img_mode;
|
||||
}
|
||||
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, img_mode, &done_frame, 0, 0);
|
||||
D("%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;
|
||||
struct msm_isp_event_ctrl *isp_event;
|
||||
isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl),
|
||||
GFP_ATOMIC);
|
||||
if (!isp_event) {
|
||||
pr_err("%s Insufficient memory.", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(&v4l2_evt, 0, sizeof(v4l2_evt));
|
||||
*((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
|
||||
|
||||
/* Get hold of pp event info struct inside event ctrl.*/
|
||||
pp_event_info = &(isp_event->isp_data.pp_event_info);
|
||||
|
||||
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.id = 0;
|
||||
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);
|
||||
D("%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)
|
||||
@@ -1027,3 +709,54 @@ int msm_mctl_pp_mctl_divert_done(
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom)
|
||||
{
|
||||
struct msm_cam_media_controller *p_mctl;
|
||||
struct msm_cam_v4l2_dev_inst *pcam_inst;
|
||||
int rc = 0, idx;
|
||||
|
||||
if (!zoom || !zoom->p_mctl) {
|
||||
pr_err("%s Invalid input, not sending buffer to VPE ",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
p_mctl = zoom->p_mctl;
|
||||
idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
|
||||
zoom->pp_frame_cmd.path);
|
||||
if (idx < 0) {
|
||||
pr_err("%s Invalid path, returning\n", __func__);
|
||||
return idx;
|
||||
}
|
||||
pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
|
||||
if (!pcam_inst) {
|
||||
pr_err("%s Invalid instance, returning\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msm_mctl_pp_get_phy_addr(pcam_inst,
|
||||
zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
|
||||
if (rc) {
|
||||
pr_err("%s Error getting buffer address for src frame\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = msm_mctl_pp_get_phy_addr(pcam_inst,
|
||||
zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
|
||||
if (rc) {
|
||||
pr_err("%s Error getting buffer address for dest frame\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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 < 0) {
|
||||
pr_err("%s Error copying timestamp info\n",
|
||||
__func__);
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -30,14 +30,19 @@
|
||||
#include "msm.h"
|
||||
#include "msm_vpe.h"
|
||||
|
||||
#ifdef CONFIG_MSM_CAMERA_DEBUG
|
||||
#define D(fmt, args...) pr_debug("msm_vpe: " fmt, ##args)
|
||||
#else
|
||||
#define D(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static int vpe_enable(uint32_t);
|
||||
static int vpe_disable(void);
|
||||
static int vpe_update_scaler(struct msm_pp_crop *pcrop);
|
||||
struct vpe_ctrl_type *vpe_ctrl;
|
||||
static atomic_t vpe_init_done = ATOMIC_INIT(0);
|
||||
|
||||
static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
|
||||
struct msm_mctl_pp_frame_info *pp_frame_info);
|
||||
static int msm_vpe_do_pp(struct msm_mctl_pp_frame_info *pp_frame_info);
|
||||
|
||||
static long long vpe_do_div(long long num, long long den)
|
||||
{
|
||||
@@ -57,8 +62,7 @@ static int vpe_start(void)
|
||||
msm_camera_io_dump(vpe_ctrl->vpebase + 0x50400, 0x10);
|
||||
|
||||
/* this triggers the operation. */
|
||||
msm_camera_io_w(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
|
||||
wmb();
|
||||
msm_camera_io_w_mb(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ void vpe_reset_state_variables(void)
|
||||
static void vpe_config_axi_default(void)
|
||||
{
|
||||
msm_camera_io_w(0x25, vpe_ctrl->vpebase + VPE_AXI_ARB_2_OFFSET);
|
||||
CDBG("%s: yaddr %ld cbcraddr %ld", __func__,
|
||||
D("%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;
|
||||
@@ -81,7 +85,6 @@ static void vpe_config_axi_default(void)
|
||||
/* for video CbCr address */
|
||||
msm_camera_io_w(vpe_ctrl->out_cbcr_addr,
|
||||
vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
|
||||
|
||||
}
|
||||
|
||||
static int vpe_reset(void)
|
||||
@@ -92,7 +95,7 @@ static int vpe_reset(void)
|
||||
|
||||
spin_lock_irqsave(&vpe_ctrl->lock, flags);
|
||||
if (vpe_ctrl->state == VPE_STATE_IDLE) {
|
||||
CDBG("%s: VPE already disabled.", __func__);
|
||||
D("%s: VPE already disabled.", __func__);
|
||||
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
|
||||
return rc;
|
||||
}
|
||||
@@ -101,7 +104,7 @@ static int vpe_reset(void)
|
||||
vpe_reset_state_variables();
|
||||
vpe_version = msm_camera_io_r(
|
||||
vpe_ctrl->vpebase + VPE_HW_VERSION_OFFSET);
|
||||
CDBG("vpe_version = 0x%x\n", vpe_version);
|
||||
D("vpe_version = 0x%x\n", vpe_version);
|
||||
/* disable all interrupts.*/
|
||||
msm_camera_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
|
||||
/* clear all pending interrupts*/
|
||||
@@ -139,13 +142,13 @@ static int msm_vpe_cfg_update(void *pinfo)
|
||||
rot_flag = msm_camera_io_r(vpe_ctrl->vpebase +
|
||||
VPE_OP_MODE_OFFSET) & 0xE00;
|
||||
if (pinfo != NULL) {
|
||||
CDBG("%s: Crop info in2_w = %d, in2_h = %d "
|
||||
D("%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);
|
||||
D("return rc = %d rot_flag = %d\n", rc, rot_flag);
|
||||
rc |= rot_flag;
|
||||
|
||||
return rc;
|
||||
@@ -200,7 +203,7 @@ static int vpe_operation_config(uint32_t *p)
|
||||
vpe_ctrl->out_w = w;
|
||||
vpe_ctrl->out_h = h;
|
||||
}
|
||||
CDBG("%s: out_w=%d, out_h=%d", __func__, vpe_ctrl->out_w,
|
||||
D("%s: out_w=%d, out_h=%d", __func__, vpe_ctrl->out_w,
|
||||
vpe_ctrl->out_h);
|
||||
return 0;
|
||||
}
|
||||
@@ -239,7 +242,7 @@ static int vpe_update_scaler(struct msm_pp_crop *pcrop)
|
||||
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",
|
||||
D("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;
|
||||
@@ -249,12 +252,12 @@ static int vpe_update_scaler(struct msm_pp_crop *pcrop)
|
||||
src_x = pcrop->src_x;
|
||||
src_y = pcrop->src_y;
|
||||
|
||||
CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
|
||||
D("src_x = %d, src_y=%d.\n", src_x, src_y);
|
||||
|
||||
src_xy = src_y*(1<<16) + src_x;
|
||||
msm_camera_io_w(src_xy, vpe_ctrl->vpebase +
|
||||
VPE_SRC_XY_OFFSET);
|
||||
CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi);
|
||||
D("src_xy = %d, src_roi=%d.\n", src_xy, src_roi);
|
||||
|
||||
/* decide whether to use FIR or M/N for scaling */
|
||||
if ((out_ROI_width == 1 && src_ROI_width < 4) ||
|
||||
@@ -387,9 +390,9 @@ static int vpe_update_scaler(struct msm_pp_crop *pcrop)
|
||||
} else if (scale_unit_sel_y == 1) /* M over N scalar */
|
||||
phase_init_y = 0;
|
||||
|
||||
CDBG("phase step x = %d, step y = %d.\n",
|
||||
D("phase step x = %d, step y = %d.\n",
|
||||
phase_step_x, phase_step_y);
|
||||
CDBG("phase init x = %d, init y = %d.\n",
|
||||
D("phase init x = %d, init y = %d.\n",
|
||||
phase_init_x, phase_init_y);
|
||||
|
||||
msm_camera_io_w(phase_step_x, vpe_ctrl->vpebase +
|
||||
@@ -416,24 +419,40 @@ int msm_vpe_is_busy(void)
|
||||
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
|
||||
return busy;
|
||||
}
|
||||
|
||||
static int msm_send_frame_to_vpe(void)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
unsigned long srcP0, srcP1, outP0, outP1;
|
||||
struct msm_mctl_pp_frame_info *frame = vpe_ctrl->pp_frame_info;
|
||||
|
||||
spin_lock_irqsave(&vpe_ctrl->lock, flags);
|
||||
msm_camera_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.sp.y_off),
|
||||
vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
|
||||
msm_camera_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off),
|
||||
vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
|
||||
msm_camera_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.sp.y_off),
|
||||
vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
|
||||
msm_camera_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off),
|
||||
vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
|
||||
if (frame->src_frame.num_planes > 1) {
|
||||
srcP0 = vpe_ctrl->pp_frame_info->src_frame.mp[0].phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.mp[0].data_offset;
|
||||
srcP1 = vpe_ctrl->pp_frame_info->src_frame.mp[1].phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.mp[1].data_offset;
|
||||
outP0 = vpe_ctrl->pp_frame_info->dest_frame.mp[0].phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.mp[0].data_offset;
|
||||
outP1 = vpe_ctrl->pp_frame_info->dest_frame.mp[1].phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.mp[1].data_offset;
|
||||
} else {
|
||||
srcP0 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.sp.y_off;
|
||||
srcP1 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off;
|
||||
outP0 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.sp.y_off;
|
||||
outP1 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
|
||||
vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off;
|
||||
}
|
||||
|
||||
msm_camera_io_w(srcP0, vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
|
||||
msm_camera_io_w(srcP1, vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
|
||||
msm_camera_io_w(outP0, vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
|
||||
msm_camera_io_w(outP1, vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
|
||||
|
||||
vpe_ctrl->state = VPE_STATE_ACTIVE;
|
||||
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
|
||||
vpe_start();
|
||||
@@ -443,27 +462,33 @@ static int msm_send_frame_to_vpe(void)
|
||||
static void vpe_send_outmsg(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct msm_vpe_resp rp;
|
||||
memset(&rp, 0, sizeof(rp));
|
||||
struct v4l2_event v4l2_evt;
|
||||
struct msm_queue_cmd *event_qcmd;
|
||||
spin_lock_irqsave(&vpe_ctrl->lock, flags);
|
||||
if (vpe_ctrl->state == VPE_STATE_IDLE) {
|
||||
pr_err("%s VPE is in IDLE state. Ignore the ack msg", __func__);
|
||||
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
|
||||
return;
|
||||
}
|
||||
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. */
|
||||
event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
|
||||
atomic_set(&event_qcmd->on_heap, 1);
|
||||
event_qcmd->command = (void *)vpe_ctrl->pp_frame_info;
|
||||
vpe_ctrl->pp_frame_info = NULL;
|
||||
vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */
|
||||
|
||||
/* Enqueue the event payload. */
|
||||
msm_enqueue(&vpe_ctrl->eventData_q, &event_qcmd->list_eventdata);
|
||||
/* Now queue the event. */
|
||||
v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT;
|
||||
v4l2_evt.id = 0;
|
||||
v4l2_event_queue(vpe_ctrl->subdev.devnode, &v4l2_evt);
|
||||
|
||||
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)
|
||||
{
|
||||
CDBG("%s: irq_status = 0x%x",
|
||||
D("%s: irq_status = 0x%x",
|
||||
__func__, vpe_ctrl->irq_status);
|
||||
if (vpe_ctrl->irq_status & 0x1)
|
||||
vpe_send_outmsg();
|
||||
@@ -478,7 +503,7 @@ static irqreturn_t vpe_parse_irq(int irq_num, void *data)
|
||||
msm_camera_io_w_mb(vpe_ctrl->irq_status, vpe_ctrl->vpebase +
|
||||
VPE_INTR_CLEAR_OFFSET);
|
||||
msm_camera_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
|
||||
CDBG("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
|
||||
D("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
|
||||
tasklet_schedule(&vpe_tasklet);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -492,7 +517,7 @@ int vpe_enable(uint32_t clk_rate)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags = 0;
|
||||
CDBG("%s", __func__);
|
||||
D("%s", __func__);
|
||||
/* don't change the order of clock and irq.*/
|
||||
spin_lock_irqsave(&vpe_ctrl->lock, flags);
|
||||
if (vpe_ctrl->state != VPE_STATE_IDLE) {
|
||||
@@ -536,10 +561,10 @@ int vpe_disable(void)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags = 0;
|
||||
CDBG("%s", __func__);
|
||||
D("%s", __func__);
|
||||
spin_lock_irqsave(&vpe_ctrl->lock, flags);
|
||||
if (vpe_ctrl->state == VPE_STATE_IDLE) {
|
||||
CDBG("%s: VPE already disabled", __func__);
|
||||
D("%s: VPE already disabled", __func__);
|
||||
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
|
||||
return rc;
|
||||
}
|
||||
@@ -559,8 +584,7 @@ int vpe_disable(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
|
||||
struct msm_mctl_pp_frame_info *pp_frame_info)
|
||||
static int msm_vpe_do_pp(struct msm_mctl_pp_frame_info *pp_frame_info)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
@@ -577,7 +601,7 @@ static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
|
||||
vpe_ctrl->pp_frame_info = pp_frame_info;
|
||||
msm_vpe_cfg_update(
|
||||
&vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
|
||||
CDBG("%s Sending frame idx %d id %d to VPE ", __func__,
|
||||
D("%s Sending frame idx %d id %d to VPE ", __func__,
|
||||
pp_frame_info->src_frame.buf_idx,
|
||||
pp_frame_info->src_frame.frame_id);
|
||||
rc = msm_send_frame_to_vpe();
|
||||
@@ -590,7 +614,7 @@ int msm_vpe_subdev_init(struct v4l2_subdev *sd,
|
||||
struct msm_cam_media_controller *mctl)
|
||||
{
|
||||
int rc = 0;
|
||||
CDBG("%s:begin", __func__);
|
||||
D("%s:begin", __func__);
|
||||
if (atomic_read(&vpe_init_done)) {
|
||||
pr_err("%s: VPE has been initialized", __func__);
|
||||
return -EBUSY;
|
||||
@@ -604,7 +628,7 @@ int msm_vpe_subdev_init(struct v4l2_subdev *sd,
|
||||
}
|
||||
v4l2_set_subdev_hostdata(sd, mctl);
|
||||
spin_lock_init(&vpe_ctrl->lock);
|
||||
CDBG("%s:end", __func__);
|
||||
D("%s:end", __func__);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vpe_subdev_init);
|
||||
@@ -646,84 +670,310 @@ void msm_vpe_subdev_release(void)
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vpe_subdev_release);
|
||||
|
||||
static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int subdev_cmd, void *arg)
|
||||
static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd)
|
||||
{
|
||||
struct msm_mctl_pp_params *vpe_params;
|
||||
struct msm_mctl_pp_cmd *cmd;
|
||||
int rc = 0;
|
||||
|
||||
if (subdev_cmd == VIDIOC_MSM_VPE_INIT) {
|
||||
switch (vpe_cmd->cmd_type) {
|
||||
case VPE_CMD_RESET:
|
||||
rc = vpe_reset();
|
||||
break;
|
||||
|
||||
case VPE_CMD_OPERATION_MODE_CFG: {
|
||||
struct msm_vpe_op_mode_cfg op_mode_cfg;
|
||||
if (sizeof(struct msm_vpe_op_mode_cfg) != vpe_cmd->length) {
|
||||
pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(struct msm_vpe_op_mode_cfg));
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
COPY_FROM_USER(rc, &op_mode_cfg, (void __user *)vpe_cmd->value,
|
||||
sizeof(op_mode_cfg));
|
||||
if (rc) {
|
||||
ERR_COPY_FROM_USER();
|
||||
break;
|
||||
}
|
||||
|
||||
vpe_cmd->value = (void *)&op_mode_cfg;
|
||||
rc = vpe_operation_config(vpe_cmd->value);
|
||||
break;
|
||||
}
|
||||
|
||||
case VPE_CMD_INPUT_PLANE_CFG: {
|
||||
struct msm_vpe_input_plane_cfg input_cfg;
|
||||
if (sizeof(struct msm_vpe_input_plane_cfg) != vpe_cmd->length) {
|
||||
pr_err("%s: mismatch cmd = %d, len = %d, expected = %d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(struct msm_vpe_input_plane_cfg));
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
COPY_FROM_USER(rc, &input_cfg, (void __user *)vpe_cmd->value,
|
||||
sizeof(input_cfg));
|
||||
if (rc) {
|
||||
ERR_COPY_FROM_USER();
|
||||
break;
|
||||
}
|
||||
|
||||
vpe_cmd->value = (void *)&input_cfg;
|
||||
vpe_input_plane_config(vpe_cmd->value);
|
||||
break;
|
||||
}
|
||||
|
||||
case VPE_CMD_OUTPUT_PLANE_CFG: {
|
||||
struct msm_vpe_output_plane_cfg output_cfg;
|
||||
if (sizeof(struct msm_vpe_output_plane_cfg) !=
|
||||
vpe_cmd->length) {
|
||||
pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(struct msm_vpe_output_plane_cfg));
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
COPY_FROM_USER(rc, &output_cfg, (void __user *)vpe_cmd->value,
|
||||
sizeof(output_cfg));
|
||||
if (rc) {
|
||||
ERR_COPY_FROM_USER();
|
||||
break;
|
||||
}
|
||||
|
||||
vpe_cmd->value = (void *)&output_cfg;
|
||||
vpe_output_plane_config(vpe_cmd->value);
|
||||
break;
|
||||
}
|
||||
|
||||
case VPE_CMD_SCALE_CFG_TYPE:{
|
||||
struct msm_vpe_scaler_cfg scaler_cfg;
|
||||
if (sizeof(struct msm_vpe_scaler_cfg) != vpe_cmd->length) {
|
||||
pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(struct msm_vpe_scaler_cfg));
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
COPY_FROM_USER(rc, &scaler_cfg, (void __user *)vpe_cmd->value,
|
||||
sizeof(scaler_cfg));
|
||||
if (rc) {
|
||||
ERR_COPY_FROM_USER();
|
||||
break;
|
||||
}
|
||||
|
||||
vpe_cmd->value = (void *)&scaler_cfg;
|
||||
vpe_update_scale_coef(vpe_cmd->value);
|
||||
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) {
|
||||
pr_err("%s Not enough memory ", __func__);
|
||||
rc = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sizeof(zoom->pp_frame_cmd) != vpe_cmd->length) {
|
||||
pr_err("%s: size mismatch id=%d, len=%d, expected=%d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(zoom->pp_frame_cmd));
|
||||
rc = -EINVAL;
|
||||
kfree(zoom);
|
||||
break;
|
||||
}
|
||||
COPY_FROM_USER(rc, &zoom->pp_frame_cmd,
|
||||
(void __user *)vpe_cmd->value,
|
||||
sizeof(zoom->pp_frame_cmd));
|
||||
if (rc) {
|
||||
ERR_COPY_FROM_USER();
|
||||
kfree(zoom);
|
||||
break;
|
||||
}
|
||||
|
||||
zoom->user_cmd = vpe_cmd->cmd_type;
|
||||
zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
|
||||
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);
|
||||
rc = msm_mctl_pp_get_vpe_buf_info(zoom);
|
||||
if (rc < 0) {
|
||||
pr_err("%s Error getting buffer info from mctl rc = %d",
|
||||
__func__, rc);
|
||||
kfree(zoom);
|
||||
break;
|
||||
}
|
||||
rc = msm_vpe_do_pp(zoom);
|
||||
break;
|
||||
}
|
||||
|
||||
case VPE_CMD_ENABLE: {
|
||||
struct msm_vpe_clock_rate clk_rate;
|
||||
int turbo_mode;
|
||||
if (sizeof(struct msm_vpe_clock_rate) != vpe_cmd->length) {
|
||||
pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
|
||||
__func__, vpe_cmd->cmd_type, vpe_cmd->length,
|
||||
sizeof(struct msm_vpe_clock_rate));
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (copy_from_user(&clk_rate, (void __user *)vpe_cmd->value,
|
||||
sizeof(struct msm_vpe_clock_rate))) {
|
||||
pr_err("%s:clk_rate copy failed", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
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;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, void *arg)
|
||||
{
|
||||
struct msm_vpe_cfg_cmd *vpe_cmd;
|
||||
int rc = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case VIDIOC_MSM_VPE_INIT: {
|
||||
struct msm_cam_media_controller *mctl =
|
||||
(struct msm_cam_media_controller *)arg;
|
||||
msm_vpe_subdev_init(sd, mctl);
|
||||
} else if (subdev_cmd == VIDIOC_MSM_VPE_RELEASE) {
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDIOC_MSM_VPE_RELEASE:
|
||||
msm_vpe_subdev_release();
|
||||
} else if (subdev_cmd == VIDIOC_MSM_VPE_CFG) {
|
||||
vpe_params = (struct msm_mctl_pp_params *)arg;
|
||||
cmd = vpe_params->cmd;
|
||||
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 MSM_CAM_V4L2_IOCTL_CFG_VPE: {
|
||||
vpe_cmd = (struct msm_vpe_cfg_cmd *)arg;
|
||||
rc = msm_vpe_process_vpe_cmd(vpe_cmd);
|
||||
if (rc < 0) {
|
||||
pr_err("%s Error processing VPE cmd %d ",
|
||||
__func__, vpe_cmd->cmd_type);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case VPE_CMD_DISABLE:
|
||||
rc = vpe_disable();
|
||||
break;
|
||||
case VPE_CMD_INPUT_PLANE_UPDATE:
|
||||
case VPE_CMD_FLUSH:
|
||||
default:
|
||||
break;
|
||||
|
||||
case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
|
||||
struct msm_device_queue *queue = &vpe_ctrl->eventData_q;
|
||||
struct msm_queue_cmd *event_qcmd;
|
||||
struct msm_mctl_pp_event_info pp_event_info;
|
||||
struct msm_mctl_pp_frame_info *pp_frame_info;
|
||||
struct msm_camera_v4l2_ioctl_t *v4l2_ioctl = arg;
|
||||
|
||||
event_qcmd = msm_dequeue(queue, list_eventdata);
|
||||
if (!event_qcmd) {
|
||||
pr_err("%s No events in the queue", __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
|
||||
pp_frame_info = event_qcmd->command;
|
||||
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_info->pp_frame_cmd.cookie;
|
||||
D("%s Sending payload %d %d %d", __func__,
|
||||
pp_event_info.ack.cmd, pp_event_info.ack.status,
|
||||
pp_event_info.ack.cookie);
|
||||
if (copy_to_user((void __user *)v4l2_ioctl->ioctl_ptr,
|
||||
&pp_event_info,
|
||||
sizeof(struct msm_mctl_pp_event_info)))
|
||||
pr_err("%s EVENTPAYLOAD Copy to user failed ",
|
||||
__func__);
|
||||
kfree(pp_frame_info);
|
||||
kfree(event_qcmd);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vpe_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
|
||||
struct v4l2_event_subscription *sub)
|
||||
{
|
||||
D("%s E\n", __func__);
|
||||
return v4l2_event_subscribe(fh, sub, VPE_SUBDEV_MAX_EVENTS);
|
||||
}
|
||||
|
||||
int msm_vpe_subdev_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
|
||||
struct v4l2_event_subscription *sub)
|
||||
{
|
||||
D("%s E\n", __func__);
|
||||
return v4l2_event_unsubscribe(fh, sub);
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
|
||||
.ioctl = msm_vpe_subdev_ioctl,
|
||||
.subscribe_event = msm_vpe_subdev_subscribe_event,
|
||||
.unsubscribe_event = msm_vpe_subdev_unsubscribe_event,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
|
||||
.core = &msm_vpe_subdev_core_ops,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops;
|
||||
static int msm_vpe_subdev_open(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
|
||||
/* Only one client of VPE allowed. */
|
||||
if (atomic_read(&vpe_ctrl->active) != 0) {
|
||||
pr_err("%s already opened\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __devinit vpe_probe(struct platform_device *pdev)
|
||||
D("%s E ", __func__);
|
||||
atomic_inc(&vpe_ctrl->active);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_vpe_subdev_close(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
|
||||
if (atomic_read(&vpe_ctrl->active) == 0) {
|
||||
pr_err("%s already closed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
D("%s E ", __func__);
|
||||
/* Drain the payload queue. */
|
||||
msm_queue_drain(&vpe_ctrl->eventData_q, list_eventdata);
|
||||
atomic_dec(&vpe_ctrl->active);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
|
||||
.open = msm_vpe_subdev_open,
|
||||
.close = msm_vpe_subdev_close,
|
||||
};
|
||||
|
||||
static int __devinit msm_vpe_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
CDBG("%s: device id = %d\n", __func__, pdev->id);
|
||||
D("%s: device id = %d\n", __func__, pdev->id);
|
||||
vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
|
||||
if (!vpe_ctrl) {
|
||||
pr_err("%s: no enough memory\n", __func__);
|
||||
pr_err("%s: not enough memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -734,6 +984,13 @@ static int __devinit vpe_probe(struct platform_device *pdev)
|
||||
snprintf(vpe_ctrl->subdev.name, sizeof(vpe_ctrl->subdev.name), "vpe");
|
||||
platform_set_drvdata(pdev, &vpe_ctrl->subdev);
|
||||
|
||||
media_entity_init(&vpe_ctrl->subdev.entity, 0, NULL, 0);
|
||||
vpe_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
|
||||
vpe_ctrl->subdev.entity.group_id = VPE_DEV;
|
||||
vpe_ctrl->subdev.entity.name = vpe_ctrl->subdev.name;
|
||||
|
||||
vpe_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
|
||||
vpe_ctrl->vpemem = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "vpe");
|
||||
if (!vpe_ctrl->vpemem) {
|
||||
@@ -769,17 +1026,22 @@ static int __devinit vpe_probe(struct platform_device *pdev)
|
||||
|
||||
disable_irq(vpe_ctrl->vpeirq->start);
|
||||
|
||||
atomic_set(&vpe_ctrl->active, 0);
|
||||
vpe_ctrl->pdev = pdev;
|
||||
msm_cam_register_subdev_node(&vpe_ctrl->subdev, VPE_DEV, pdev->id);
|
||||
vpe_ctrl->subdev.entity.revision = vpe_ctrl->subdev.devnode->num;
|
||||
msm_queue_init(&vpe_ctrl->eventData_q, "ackevents");
|
||||
|
||||
return 0;
|
||||
|
||||
vpe_no_resource:
|
||||
pr_err("%s: VPE Probe failed.\n", __func__);
|
||||
kfree(vpe_ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_driver vpe_driver = {
|
||||
.probe = vpe_probe,
|
||||
struct platform_driver msm_vpe_driver = {
|
||||
.probe = msm_vpe_probe,
|
||||
.driver = {
|
||||
.name = MSM_VPE_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
@@ -788,9 +1050,15 @@ struct platform_driver vpe_driver = {
|
||||
|
||||
static int __init msm_vpe_init_module(void)
|
||||
{
|
||||
return platform_driver_register(&vpe_driver);
|
||||
return platform_driver_register(&msm_vpe_driver);
|
||||
}
|
||||
|
||||
static void __exit msm_vpe_exit_module(void)
|
||||
{
|
||||
platform_driver_unregister(&msm_vpe_driver);
|
||||
}
|
||||
|
||||
module_init(msm_vpe_init_module);
|
||||
module_exit(msm_vpe_exit_module);
|
||||
MODULE_DESCRIPTION("VPE driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -79,8 +79,8 @@
|
||||
#define VPE_DEFAULT_SCALE_CONFIG 0x3c
|
||||
|
||||
#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
|
||||
#define VPE_TURBO_MODE_CLOCK_RATE 200000000
|
||||
|
||||
#define VPE_TURBO_MODE_CLOCK_RATE 200000000
|
||||
#define VPE_SUBDEV_MAX_EVENTS 30
|
||||
|
||||
/**************************************************/
|
||||
/*********** End of command id ********************/
|
||||
@@ -119,6 +119,8 @@ struct vpe_ctrl_type {
|
||||
struct regulator *fs_vpe;
|
||||
struct clk *vpe_clk[2];
|
||||
struct msm_mctl_pp_frame_info *pp_frame_info;
|
||||
atomic_t active;
|
||||
struct msm_device_queue eventData_q; /*V4L2 Event Payload Queue*/
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -34,7 +34,7 @@ static long msm_server_send_v4l2_evt(void *evt);
|
||||
static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
|
||||
unsigned int notification, void *arg);
|
||||
|
||||
static void msm_queue_init(struct msm_device_queue *queue, const char *name)
|
||||
void msm_queue_init(struct msm_device_queue *queue, const char *name)
|
||||
{
|
||||
D("%s\n", __func__);
|
||||
spin_lock_init(&queue->lock);
|
||||
@@ -45,7 +45,7 @@ static void msm_queue_init(struct msm_device_queue *queue, const char *name)
|
||||
init_waitqueue_head(&queue->wait);
|
||||
}
|
||||
|
||||
static void msm_enqueue(struct msm_device_queue *queue,
|
||||
void msm_enqueue(struct msm_device_queue *queue,
|
||||
struct list_head *entry)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -62,7 +62,7 @@ static void msm_enqueue(struct msm_device_queue *queue,
|
||||
spin_unlock_irqrestore(&queue->lock, flags);
|
||||
}
|
||||
|
||||
static void msm_drain_eventq(struct msm_device_queue *queue)
|
||||
void msm_drain_eventq(struct msm_device_queue *queue)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct msm_queue_cmd *qcmd;
|
||||
@@ -1421,16 +1421,6 @@ static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
|
||||
g_server_dev.vfe_device[0], notification, arg);
|
||||
}
|
||||
break;
|
||||
case NOTIFY_VPE_MSG_EVT: {
|
||||
struct msm_cam_media_controller *pmctl =
|
||||
(struct msm_cam_media_controller *)
|
||||
v4l2_get_subdev_hostdata(sd);
|
||||
struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
|
||||
msm_mctl_pp_notify(pmctl,
|
||||
(struct msm_mctl_pp_frame_info *)
|
||||
vdata->extdata);
|
||||
break;
|
||||
}
|
||||
case NOTIFY_VFE_IRQ:{
|
||||
struct msm_vfe_cfg_cmd cfg_cmd;
|
||||
struct msm_camvfe_params vfe_params;
|
||||
|
||||
@@ -1467,6 +1467,9 @@ struct img_plane_info {
|
||||
#define MSM_CAM_IOCTL_SEND_EVENT \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
|
||||
|
||||
#define MSM_CAM_V4L2_IOCTL_CFG_VPE \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_vpe_cfg_cmd)
|
||||
|
||||
struct msm_camera_v4l2_ioctl_t {
|
||||
void __user *ioctl_ptr;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user