msm: camera: Add free status buffer queue
Add support for free buffer queues for vfe
statistics
Change-Id: I9a791d5869aa090f661904b41b210cea51f67aa4
Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
Signed-off-by: Lakshmi Narayana Kalavala <lkalaval@codeaurora.org>
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 63120da..5703d88 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -11,7 +11,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
EXTRA_CFLAGS += -Idrivers/media/video/msm/server
- 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) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
obj-$(CONFIG_MSM_CPP) += cpp/
obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c3e8321..08278ff 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -131,6 +131,8 @@
uint32_t id;
uint32_t buffer;
uint32_t frameCounter;
+ int32_t buf_idx;
+ int32_t fd;
};
struct msm_free_buf {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5c61cdb..5fcb62b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -406,12 +406,14 @@
struct msm_stats_buf stats;
struct isp_msg_stats *isp_stats = (struct isp_msg_stats *)arg;
+ memset(&stats, 0, sizeof(stats));
isp_event->isp_data.isp_msg.msg_id = isp_stats->id;
isp_event->isp_data.isp_msg.frame_id =
isp_stats->frameCounter;
- stats.buffer = msm_pmem_stats_ptov_lookup(pmctl,
- isp_stats->buffer,
- &(stats.fd));
+ stats.buffer = isp_stats->buffer;
+ stats.fd = isp_stats->fd;
+ /* buf_idx used for O(0) lookup */
+ stats.buf_idx = isp_stats->buf_idx;
switch (isp_stats->id) {
case MSG_ID_STATS_AEC:
stats.aec.buff = stats.buffer;
@@ -453,8 +455,8 @@
kmalloc(sizeof(struct msm_stats_buf),
GFP_ATOMIC);
if (!stats_buf) {
- pr_err("%s: out of memory.\n",
- __func__);
+ pr_err("%s: out of memory. stats_id = %d\n",
+ __func__, isp_stats->id);
rc = -ENOMEM;
} else {
*stats_buf = stats;
@@ -550,7 +552,6 @@
struct msm_cam_media_controller *mctl, void __user *arg)
{
struct msm_vfe_cfg_cmd cfgcmd;
- struct msm_pmem_region region[8];
struct axidata axi_data;
if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
@@ -562,103 +563,13 @@
CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
switch (cfgcmd.cmd_type) {
case CMD_STATS_AF_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AF, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AEC_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AEC, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AWB_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AWB, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_AEC_AWB_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_AEC_AWB, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_IHIST_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_IHIST, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_RS_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_RS, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
case CMD_STATS_CS_ENABLE:
- axi_data.bufnum1 =
- msm_pmem_region_lookup(
- &mctl->stats_info.pmem_stats_list,
- MSM_PMEM_CS, ®ion[0],
- NUM_STAT_OUTPUT_BUFFERS);
- if (!axi_data.bufnum1) {
- pr_err("%s %d: pmem region lookup error\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- axi_data.region = ®ion[0];
- return msm_isp_subdev_ioctl(sd, &cfgcmd,
- &axi_data);
+ return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
case CMD_GENERAL:
case CMD_STATS_DISABLE:
return msm_isp_subdev_ioctl(sd, &cfgcmd,
@@ -764,6 +675,62 @@
return rc;
}
+static int msm_vfe_stats_buf_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ struct msm_cam_media_controller *mctl,
+ void __user *arg)
+{
+ struct msm_vfe_cfg_cmd cfgcmd;
+ int rc = 0;
+ switch (cmd) {
+ case MSM_CAM_IOCTL_STATS_REQBUF: {
+ struct msm_stats_reqbuf reqbuf;
+ if (copy_from_user(&reqbuf, arg,
+ sizeof(struct msm_stats_reqbuf))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_REQBUF;
+ cfgcmd.value = (void *)&reqbuf;
+ cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+ break;
+ }
+ case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
+ struct msm_stats_buf_info buf_info;
+
+ if (copy_from_user(&buf_info, arg,
+ sizeof(struct msm_stats_buf_info))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_ENQUEUEBUF;
+ cfgcmd.value = (void *)&buf_info;
+ cfgcmd.length = sizeof(struct msm_stats_buf_info);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+ break;
+ }
+ case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq bufq_info;
+
+ if (copy_from_user(&bufq_info, arg,
+ sizeof(struct msm_stats_flush_bufq))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
+ cfgcmd.value = (void *)&bufq_info;
+ cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
+ rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+ break;
+ }
+ default:
+ rc = -1;
+ break;
+ }
+ CDBG("%s\n", __func__);
+ return rc;
+}
/* config function simliar to origanl msm_ioctl_config*/
static int msm_isp_config(struct msm_cam_media_controller *pmctl,
unsigned int cmd, unsigned long arg)
@@ -789,6 +756,12 @@
rc = msm_put_stats_buffer(sd, pmctl, argp);
break;
+ case MSM_CAM_IOCTL_STATS_REQBUF:
+ case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
+ case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+ rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
+ break;
+
default:
break;
}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index fa985ce..2331fcc 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -365,6 +365,229 @@
"DEMOSAICV3_UPDATE",
};
+
+static unsigned long vfe31_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+ rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
+ stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ return buf->paddr;
+}
+
+static unsigned long vfe31_stats_flush_enqueue(
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+
+ rc = vfe31_ctrl->stats_ops.bufq_flush(
+ vfe31_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe31_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe31_ctrl->stats_ops.enqueue_buf(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_af_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ return -EINVAL;
+ }
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+ return 0;
+}
+
+static int vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+ return 0;
+}
+
static void vfe31_stop(void)
{
uint8_t axiBusyFlag = true;
@@ -600,101 +823,6 @@
return 0;
}
-static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
-
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
-
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
-static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
-{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
-
- addr = ptr[0];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
- addr = ptr[1];
- msm_camera_io_w(addr,
- vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
- return 0;
-}
-
static void msm_camera_io_dump2(void __iomem *addr, int size)
{
char line_str[BUFF_SIZE_128], *p_str;
@@ -1388,6 +1516,12 @@
break;
case VFE_CMD_STATS_AE_START:
+ rc = vfe_stats_aec_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AEC",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1408,6 +1542,12 @@
cmdp, (vfe31_cmd[cmd->id].length));
break;
case VFE_CMD_STATS_AF_START:
+ rc = vfe_stats_af_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AF",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1428,6 +1568,12 @@
cmdp, (vfe31_cmd[cmd->id].length));
break;
case VFE_CMD_STATS_AWB_START:
+ rc = vfe_stats_awb_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1449,6 +1595,12 @@
break;
case VFE_CMD_STATS_IHIST_START:
+ rc = vfe_stats_ihist_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of IHIST",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1470,6 +1622,12 @@
break;
case VFE_CMD_STATS_RS_START:
+ rc = vfe_stats_rs_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of RS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1487,6 +1645,12 @@
break;
case VFE_CMD_STATS_CS_START:
+ rc = vfe_stats_cs_buf_init(NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1987,6 +2151,12 @@
old_val &= ~AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
break;
case VFE_CMD_STATS_IHIST_STOP:
@@ -2172,76 +2342,6 @@
return rc;
}
-static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->af_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->afStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->awb_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->awbStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->aec_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->aecStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->ihist_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->rs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->rsStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe31_ctrl->stats_comp ?
- &vfe31_ctrl->comp_stats_ack_lock :
- &vfe31_ctrl->cs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe31_ctrl->csStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
{
uint32_t *temp;
@@ -2810,7 +2910,8 @@
static void
vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
{
- unsigned long flags;
+ int rc = 0;
+ void *vaddr = NULL;
/* fill message with right content. */
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
@@ -2821,55 +2922,72 @@
switch (statsNum) {
case STATS_AE_NUM:{
msgStats.id = MSG_ID_STATS_AEC;
- spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
- vfe31_ctrl->aecStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AEC, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_AF_NUM:{
msgStats.id = MSG_ID_STATS_AF;
- spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
- vfe31_ctrl->afStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_AWB_NUM: {
msgStats.id = MSG_ID_STATS_AWB;
- spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
- vfe31_ctrl->awbStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AWB, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_IHIST_NUM: {
msgStats.id = MSG_ID_STATS_IHIST;
- spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
- vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_IHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_RS_NUM: {
msgStats.id = MSG_ID_STATS_RS;
- spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
- vfe31_ctrl->rsStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_RS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
case STATS_CS_NUM: {
msgStats.id = MSG_ID_STATS_CS;
- spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
- vfe31_ctrl->csStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+ rc = vfe31_ctrl->stats_ops.dispatch(
+ vfe31_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_CS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe31_ctrl->stats_ops.client);
}
break;
default:
goto stats_done;
}
-
- v4l2_subdev_notify(&vfe31_ctrl->subdev,
- NOTIFY_VFE_MSG_STATS,
- &msgStats);
+ if (rc == 0) {
+ msgStats.buffer = (uint32_t)vaddr;
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS, &msgStats);
+ } else {
+ pr_err("%s: paddr to idx mapping error, stats_id = %d,\n"
+ "paddr = 0x%d\n", __func__,
+ msgStats.id, msgStats.buffer);
+ }
stats_done:
/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
return;
@@ -2901,17 +3019,18 @@
static void vfe31_process_stats_ae_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
- if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->aecStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AE_NUM,
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
STATS_AE_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -2921,17 +3040,18 @@
static void vfe31_process_stats_awb_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
- if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->awbStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AWB_NUM,
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
STATS_AWB_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -2941,17 +3061,18 @@
static void vfe31_process_stats_af_irq(void)
{
unsigned long flags;
- spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
- if (!(vfe31_ctrl->afStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->afStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AF_NUM,
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
STATS_AF_NUM);
} else{
- spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -2960,27 +3081,35 @@
static void vfe31_process_stats_ihist_irq(void)
{
- if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->ihistStatsControl.bufToRender =
- vfe31_process_stats_irq_common(STATS_IHIST_NUM,
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
-
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ addr);
vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
- STATS_IHIST_NUM);
+ STATS_IHIST_NUM);
} else {
vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
}
}
static void vfe31_process_stats_rs_irq(void)
{
- if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe31_ctrl->rsStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_RS_NUM,
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
-
+ addr);
vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
STATS_RS_NUM);
} else {
@@ -2992,12 +3121,29 @@
static void vfe31_process_stats_cs_irq(void)
{
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ addr);
+ vfe_send_stats_msg(
+ vfe31_ctrl->csStatsControl.bufToRender,
+ STATS_CS_NUM);
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+ }
if (!(vfe31_ctrl->csStatsControl.ackPending)) {
vfe31_ctrl->csStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_CS_NUM,
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
-
- vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ vfe_send_stats_msg(
+ vfe31_ctrl->csStatsControl.bufToRender,
STATS_CS_NUM);
} else {
vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3010,15 +3156,16 @@
{
unsigned long flags;
int32_t process_stats = false;
+ uint32_t addr;
CDBG("%s, stats = 0x%x\n", __func__, status_bits);
- spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
- if (!vfe31_ctrl->aecStatsControl.ackPending) {
- vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+ if (addr) {
vfe31_ctrl->aecStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AE_NUM,
- vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe31_ctrl->aecStatsControl.bufToRender = 0;
@@ -3029,11 +3176,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
- if (!vfe31_ctrl->awbStatsControl.ackPending) {
- vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+ if (addr) {
vfe31_ctrl->awbStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AWB_NUM,
- vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3045,11 +3192,11 @@
if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
- if (!vfe31_ctrl->afStatsControl.ackPending) {
- vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+ if (addr) {
vfe31_ctrl->afStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_AF_NUM,
- vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->afStatsControl.bufToRender = 0;
@@ -3060,11 +3207,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
- if (!vfe31_ctrl->ihistStatsControl.ackPending) {
- vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+ if (addr) {
vfe31_ctrl->ihistStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_IHIST_NUM,
- vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3075,11 +3222,11 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
- if (!vfe31_ctrl->rsStatsControl.ackPending) {
- vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+ if (!addr) {
vfe31_ctrl->rsStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_RS_NUM,
- vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3091,11 +3238,11 @@
if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
- if (!vfe31_ctrl->csStatsControl.ackPending) {
- vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+ if (addr) {
vfe31_ctrl->csStatsControl.bufToRender =
vfe31_process_stats_irq_common(STATS_CS_NUM,
- vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3105,13 +3252,91 @@
vfe31_ctrl->csStatsControl.bufToRender = 0;
}
- spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
if (process_stats)
vfe_send_comp_stats_msg(status_bits);
return;
}
+static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+ void *ion_client)
+{
+ long rc = 0;
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe31_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(&vfe31_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe31_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.stats_ctrl_init(
+ &vfe31_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops", __func__);
+ memset(&vfe31_ctrl->stats_ops, 0,
+ sizeof(vfe31_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mis match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+ rc = vfe31_ctrl->stats_ops.reqbuf(&vfe31_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe31_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mis match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL ;
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe31_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL ;
+ goto end;
+ }
+ rc = vfe31_ctrl->stats_ops.bufq_flush(&vfe31_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe31_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported", __func__,
+ cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static void vfe31_process_stats_irq(uint32_t *irqstatus)
{
uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
@@ -3334,44 +3559,55 @@
void *data = vfe_params->data;
long rc = 0;
- uint32_t i = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
- struct msm_pmem_region *regptr = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
- if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
- cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
- if (NULL != cmd->value) {
- if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
- pr_err("%s %d: copy_from_user failed\n",
- __func__, __LINE__);
- return -EFAULT;
- }
- }
- } else {
- /* here eith stats release or frame release. */
+
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+ return rc;
+ default:
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
/* then must be stats release. */
- if (!data)
+ if (!data) {
+ pr_err("%s: data = NULL, cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
return -EFAULT;
+ }
sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
GFP_ATOMIC);
- if (!sack)
+ if (!sack) {
+ pr_err("%s: no mem for cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
return -ENOMEM;
+ }
sack->nextStatsBuf = *(uint32_t *)data;
}
- }
+ }
CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
@@ -3381,53 +3617,7 @@
(cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
- struct axidata *axid;
- axid = data;
- if (!axid) {
- rc = -EFAULT;
- goto vfe31_config_done;
- }
-
- scfg =
- kmalloc(sizeof(struct vfe_cmd_stats_buf),
- GFP_ATOMIC);
- if (!scfg) {
- rc = -ENOMEM;
- goto vfe31_config_done;
- }
- regptr = axid->region;
- if (axid->bufnum1 > 0) {
- for (i = 0; i < axid->bufnum1; i++) {
- scfg->statsBuf[i] =
- (uint32_t)(regptr->paddr);
- regptr++;
- }
- }
- /* individual */
- switch (cmd->cmd_type) {
- case CMD_STATS_AEC_ENABLE:
- rc = vfe_stats_aec_buf_init(scfg);
- break;
- case CMD_STATS_AF_ENABLE:
- rc = vfe_stats_af_buf_init(scfg);
- break;
- case CMD_STATS_AWB_ENABLE:
- rc = vfe_stats_awb_buf_init(scfg);
- break;
- case CMD_STATS_IHIST_ENABLE:
- rc = vfe_stats_ihist_buf_init(scfg);
- break;
- case CMD_STATS_RS_ENABLE:
- rc = vfe_stats_rs_buf_init(scfg);
- break;
- case CMD_STATS_CS_ENABLE:
- rc = vfe_stats_cs_buf_init(scfg);
- break;
- default:
- pr_err("%s Unsupported cmd type %d",
- __func__, cmd->cmd_type);
- break;
- }
+ scfg = NULL;
goto vfe31_config_done;
}
switch (cmd->cmd_type) {
@@ -3459,36 +3649,6 @@
case CMD_SNAP_BUF_RELEASE:
break;
- case CMD_STATS_AEC_BUF_RELEASE: {
- vfe31_stats_aec_ack(sack);
- }
- break;
-
- case CMD_STATS_AF_BUF_RELEASE: {
- vfe31_stats_af_ack(sack);
- }
- break;
-
- case CMD_STATS_AWB_BUF_RELEASE: {
- vfe31_stats_awb_ack(sack);
- }
- break;
-
- case CMD_STATS_IHIST_BUF_RELEASE: {
- vfe31_stats_ihist_ack(sack);
- }
- break;
-
- case CMD_STATS_RS_BUF_RELEASE: {
- vfe31_stats_rs_ack(sack);
- }
- break;
-
- case CMD_STATS_CS_BUF_RELEASE: {
- vfe31_stats_cs_ack(sack);
- }
- break;
-
case CMD_AXI_CFG_PRIM: {
uint32_t *axio = NULL;
axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -3607,6 +3767,7 @@
pr_err("%s Unsupported AXI configuration %x ", __func__,
cmd->cmd_type);
break;
+ }
}
vfe31_config_done:
kfree(scfg);
@@ -3714,17 +3875,10 @@
spin_lock_init(&vfe31_ctrl->stop_flag_lock);
spin_lock_init(&vfe31_ctrl->state_lock);
+ spin_lock_init(&vfe31_ctrl->stats_bufq_lock);
spin_lock_init(&vfe31_ctrl->io_lock);
spin_lock_init(&vfe31_ctrl->update_ack_lock);
spin_lock_init(&vfe31_ctrl->tasklet_lock);
-
- spin_lock_init(&vfe31_ctrl->aec_ack_lock);
- spin_lock_init(&vfe31_ctrl->awb_ack_lock);
- spin_lock_init(&vfe31_ctrl->af_ack_lock);
- spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
- spin_lock_init(&vfe31_ctrl->rs_ack_lock);
- spin_lock_init(&vfe31_ctrl->cs_ack_lock);
- spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
spin_lock_init(&vfe31_ctrl->sd_notify_lock);
INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index 739d157..2cba995 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -15,6 +15,7 @@
#define __MSM_VFE31_V4L2_H__
#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
#ifndef TRUE
#define TRUE 1
@@ -862,14 +863,7 @@
spinlock_t update_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
-
- spinlock_t aec_ack_lock;
- spinlock_t awb_ack_lock;
- spinlock_t af_ack_lock;
- spinlock_t ihist_ack_lock;
- spinlock_t rs_ack_lock;
- spinlock_t cs_ack_lock;
- spinlock_t comp_stats_ack_lock;
+ spinlock_t stats_bufq_lock;
uint32_t extlen;
void *extdata;
@@ -930,6 +924,8 @@
uint32_t frame_skip_cnt;
uint32_t frame_skip_pattern;
uint32_t snapshot_frame_cnt;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
};
enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3ac4c6a..621a016 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -624,116 +624,248 @@
return 0;
}
-static uint32_t vfe_stats_awb_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static unsigned long vfe32_stats_dqbuf(struct vfe32_ctrl_type *vfe32_ctrl,
+ enum msm_stats_enum_type stats_type)
{
- uint32_t *ptr = in->statsBuf;
- uint32_t addr;
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+ rc = vfe32_ctrl->stats_ops.dqbuf(
+ vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ return buf->paddr;
+}
- addr = ptr[0];
+static unsigned long vfe32_stats_flush_enqueue(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+
+ rc = vfe32_ctrl->stats_ops.bufq_flush(
+ vfe32_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe32_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe32_ctrl->stats_ops.enqueue_buf(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
+{
+ uint32_t addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq awb ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_PONG_ADDR);
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_aec_buf_init(
+static int vfe_stats_aec_buf_init(
struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AEC_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq aec pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_af_buf_init(
+static int vfe_stats_af_buf_init(
struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
+ int rc = 0;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ return -EINVAL;
+ }
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AF_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq af pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AF_WR_PONG_ADDR);
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_ihist_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_ihist_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist ping buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_HIST_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq ihist pong buf from free buf queue",
+ __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_HIST_WR_PONG_ADDR);
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_rs_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_rs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
+ unsigned long flags;
- addr = ptr[0];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq rs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_cs_buf_init(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_cs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ struct vfe_cmd_stats_buf *in)
{
- uint32_t *ptr = in->statsBuf;
uint32_t addr;
-
- addr = ptr[0];
+ unsigned long flags;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs ping buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_PING_ADDR);
- addr = ptr[1];
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq cs pong buf from free buf queue", __func__);
+ return -ENOMEM;
+ }
msm_camera_io_w(addr,
vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
@@ -1614,6 +1746,12 @@
break;
case VFE_CMD_STATS_AE_START: {
+ rc = vfe_stats_aec_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AEC",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1637,6 +1775,12 @@
}
break;
case VFE_CMD_STATS_AF_START: {
+ rc = vfe_stats_af_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AF",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1660,6 +1804,12 @@
}
break;
case VFE_CMD_STATS_AWB_START: {
+ rc = vfe_stats_awb_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1684,6 +1834,12 @@
break;
case VFE_CMD_STATS_IHIST_START: {
+ rc = vfe_stats_ihist_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of IHIST",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1709,6 +1865,12 @@
case VFE_CMD_STATS_RS_START: {
+ rc = vfe_stats_rs_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of RS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -1728,6 +1890,12 @@
break;
case VFE_CMD_STATS_CS_START: {
+ rc = vfe_stats_cs_buf_init(vfe32_ctrl, NULL);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
rc = -ENOMEM;
@@ -2430,6 +2598,12 @@
old_val &= ~AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
}
break;
@@ -2808,82 +2982,6 @@
return rc;
}
-static void vfe32_stats_af_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->af_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->afStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_awb_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->awb_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->awbStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_aec_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->aec_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->aecStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_ihist_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->ihist_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_rs_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->rs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->rsStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_cs_ack(
- struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
- unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
- &vfe32_ctrl->comp_stats_ack_lock :
- &vfe32_ctrl->cs_ack_lock);
- spin_lock_irqsave(lock, flags);
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
- vfe32_ctrl->csStatsControl.ackPending = FALSE;
- spin_unlock_irqrestore(lock, flags);
-}
-
static inline void vfe32_read_irq_status(
struct axi_ctrl_t *axi_ctrl, struct vfe32_irq_status *out)
{
@@ -3653,70 +3751,87 @@
return returnAddr;
}
-static void
-vfe_send_stats_msg(struct vfe32_ctrl_type *vfe32_ctrl,
+static void vfe_send_stats_msg(
+ struct vfe32_ctrl_type *vfe32_ctrl,
uint32_t bufAddress, uint32_t statsNum)
{
- unsigned long flags;
+ int rc = 0;
+ void *vaddr = NULL;
/* fill message with right content. */
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
struct isp_msg_stats msgStats;
msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
msgStats.buffer = bufAddress;
-
switch (statsNum) {
case statsAeNum:{
msgStats.id = MSG_ID_STATS_AEC;
- spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
- vfe32_ctrl->aecStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AEC, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsAfNum:{
msgStats.id = MSG_ID_STATS_AF;
- spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
- vfe32_ctrl->afStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsAwbNum: {
msgStats.id = MSG_ID_STATS_AWB;
- spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
- vfe32_ctrl->awbStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AWB, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsIhistNum: {
msgStats.id = MSG_ID_STATS_IHIST;
- spin_lock_irqsave(&vfe32_ctrl->ihist_ack_lock, flags);
- vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->ihist_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_IHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsRsNum: {
msgStats.id = MSG_ID_STATS_RS;
- spin_lock_irqsave(&vfe32_ctrl->rs_ack_lock, flags);
- vfe32_ctrl->rsStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->rs_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_RS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
case statsCsNum: {
msgStats.id = MSG_ID_STATS_CS;
- spin_lock_irqsave(&vfe32_ctrl->cs_ack_lock, flags);
- vfe32_ctrl->csStatsControl.ackPending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->cs_ack_lock, flags);
+ rc = vfe32_ctrl->stats_ops.dispatch(
+ vfe32_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_CS, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe32_ctrl->stats_ops.client);
}
break;
default:
goto stats_done;
}
-
- v4l2_subdev_notify(&vfe32_ctrl->subdev,
- NOTIFY_VFE_MSG_STATS,
- &msgStats);
+ if (rc == 0) {
+ msgStats.buffer = (uint32_t)vaddr;
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msgStats);
+ } else {
+ pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+ __func__, msgStats.id, msgStats.buffer);
+ }
stats_done:
/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
return;
@@ -3751,17 +3866,18 @@
static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
- if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->aecStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -3771,17 +3887,18 @@
static void vfe32_process_stats_awb_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
- if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->awbStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAwbNum,
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->awbStatsControl.bufToRender, statsAwbNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -3791,17 +3908,18 @@
static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
- if (!(vfe32_ctrl->afStatsControl.ackPending)) {
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->afStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
} else{
- spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
vfe32_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -3810,11 +3928,15 @@
static void vfe32_process_stats_ihist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->ihistStatsControl.bufToRender =
vfe32_process_stats_irq_common(
- vfe32_ctrl, statsIhistNum,
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ vfe32_ctrl, statsIhistNum, addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->ihistStatsControl.bufToRender,
@@ -3828,10 +3950,15 @@
static void vfe32_process_stats_rs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->rsStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsRsNum,
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
vfe_send_stats_msg(vfe32_ctrl,
vfe32_ctrl->rsStatsControl.bufToRender, statsRsNum);
@@ -3844,13 +3971,19 @@
static void vfe32_process_stats_cs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (!(vfe32_ctrl->csStatsControl.ackPending)) {
+ unsigned long flags;
+ uint32_t addr;
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+ if (addr) {
vfe32_ctrl->csStatsControl.bufToRender =
vfe32_process_stats_irq_common(vfe32_ctrl, statsCsNum,
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
- vfe_send_stats_msg(vfe32_ctrl,
- vfe32_ctrl->csStatsControl.bufToRender, statsCsNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->csStatsControl.bufToRender,
+ statsCsNum);
} else {
vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3863,16 +3996,17 @@
{
unsigned long flags;
int32_t process_stats = false;
- CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+ uint32_t addr;
- spin_lock_irqsave(&vfe32_ctrl->comp_stats_ack_lock, flags);
+ CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+ spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
- if (!vfe32_ctrl->aecStatsControl.ackPending) {
- vfe32_ctrl->aecStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AEC);
+ if (addr) {
vfe32_ctrl->aecStatsControl.bufToRender =
vfe32_process_stats_irq_common(
- vfe32_ctrl, statsAeNum,
- vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+ vfe32_ctrl, statsAeNum, addr);
process_stats = true;
} else{
vfe32_ctrl->aecStatsControl.bufToRender = 0;
@@ -3883,12 +4017,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
- if (!vfe32_ctrl->awbStatsControl.ackPending) {
- vfe32_ctrl->awbStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AWB);
+ if (addr) {
vfe32_ctrl->awbStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsAwbNum,
- vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else{
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3898,14 +4033,14 @@
vfe32_ctrl->awbStatsControl.bufToRender = 0;
}
-
if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
- if (!vfe32_ctrl->afStatsControl.ackPending) {
- vfe32_ctrl->afStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_AF);
+ if (addr) {
vfe32_ctrl->afStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsAfNum,
- vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->afStatsControl.bufToRender = 0;
@@ -3916,12 +4051,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
- if (!vfe32_ctrl->ihistStatsControl.ackPending) {
- vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_IHIST);
+ if (addr) {
vfe32_ctrl->ihistStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsIhistNum,
- vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3932,12 +4068,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
- if (!vfe32_ctrl->rsStatsControl.ackPending) {
- vfe32_ctrl->rsStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_RS);
+ if (addr) {
vfe32_ctrl->rsStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsRsNum,
- vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3948,12 +4085,13 @@
}
if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
- if (!vfe32_ctrl->csStatsControl.ackPending) {
- vfe32_ctrl->csStatsControl.ackPending = TRUE;
+ addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+ MSM_STATS_TYPE_CS);
+ if (addr) {
vfe32_ctrl->csStatsControl.bufToRender =
vfe32_process_stats_irq_common(
vfe32_ctrl, statsCsNum,
- vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+ addr);
process_stats = true;
} else {
vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3962,8 +4100,7 @@
} else {
vfe32_ctrl->csStatsControl.bufToRender = 0;
}
-
- spin_unlock_irqrestore(&vfe32_ctrl->comp_stats_ack_lock, flags);
+ spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
if (process_stats)
vfe_send_comp_stats_msg(vfe32_ctrl, status_bits);
@@ -4259,6 +4396,88 @@
return 0;
}
+static long vfe_stats_bufq_sub_ioctl(
+ struct vfe32_ctrl_type *vfe_ctrl,
+ struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+ long rc = 0;
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops", __func__);
+ memset(&vfe_ctrl->stats_ops, 0,
+ sizeof(vfe_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL ;
+ goto end;
+ }
+ }
+ rc = vfe_ctrl->stats_ops.reqbuf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.enqueue_buf(
+ &vfe_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mitch match\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe_ctrl->stats_ops.bufq_flush(
+ &vfe_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported", __func__,
+ cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int subdev_cmd, void *arg)
{
@@ -4273,9 +4492,7 @@
void *data = vfe_params->data;
long rc = 0;
- uint32_t i = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
- struct msm_pmem_region *regptr = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
if (!vfe32_ctrl->share_ctrl->vfebase) {
@@ -4283,151 +4500,100 @@
return -EFAULT;
}
- if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
+ switch (cmd->cmd_type) {
+ case CMD_VFE_PROCESS_IRQ:
vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
return rc;
- } else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
- cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
- if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
- pr_err("%s %d: copy_from_user failed\n", __func__,
- __LINE__);
- return -EFAULT;
- }
- } else {
- /* here eith stats release or frame release. */
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
+ cmd, vfe_params->data);
+ return rc;
+ default:
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
- cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
- /* then must be stats release. */
- if (!data)
- return -EFAULT;
- sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data) {
+ pr_err("%s: data = NULL, cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -EFAULT;
+ }
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
GFP_ATOMIC);
- if (!sack)
- return -ENOMEM;
-
- sack->nextStatsBuf = *(uint32_t *)data;
- }
- }
-
- CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
-
- if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
- (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
- struct axidata *axid;
- axid = data;
- if (!axid) {
- rc = -EFAULT;
- goto vfe32_config_done;
- }
-
- scfg =
- kmalloc(sizeof(struct vfe_cmd_stats_buf),
- GFP_ATOMIC);
- if (!scfg) {
- rc = -ENOMEM;
- goto vfe32_config_done;
- }
- regptr = axid->region;
- if (axid->bufnum1 > 0) {
- for (i = 0; i < axid->bufnum1; i++) {
- scfg->statsBuf[i] =
- (uint32_t)(regptr->paddr);
- regptr++;
+ if (!sack) {
+ pr_err("%s: no mem for cmd->cmd_type = %d",
+ __func__, cmd->cmd_type);
+ return -ENOMEM;
+ }
+ sack->nextStatsBuf = *(uint32_t *)data;
}
}
- /* individual */
- switch (cmd->cmd_type) {
- case CMD_STATS_AEC_ENABLE:
- rc = vfe_stats_aec_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_AF_ENABLE:
- rc = vfe_stats_af_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_AWB_ENABLE:
- rc = vfe_stats_awb_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_IHIST_ENABLE:
- rc = vfe_stats_ihist_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_RS_ENABLE:
- rc = vfe_stats_rs_buf_init(vfe32_ctrl, scfg);
- break;
- case CMD_STATS_CS_ENABLE:
- rc = vfe_stats_cs_buf_init(vfe32_ctrl, scfg);
- break;
- default:
- pr_err("%s Unsupported cmd type %d",
- __func__, cmd->cmd_type);
- break;
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ scfg = NULL;
+ /* individual */
+ goto vfe32_config_done;
}
- goto vfe32_config_done;
- }
- switch (cmd->cmd_type) {
- case CMD_GENERAL:
- rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL:
+ rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
break;
- case CMD_CONFIG_PING_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->ping = *((struct msm_free_buf *)data);
- }
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
break;
- case CMD_CONFIG_PONG_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->pong = *((struct msm_free_buf *)data);
- }
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
break;
-
- case CMD_CONFIG_FREE_BUF_ADDR: {
- int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch =
- vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
- outch->free_buf = *((struct msm_free_buf *)data);
- }
+ case CMD_SNAP_BUF_RELEASE:
break;
- case CMD_SNAP_BUF_RELEASE:
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
break;
- case CMD_STATS_AEC_BUF_RELEASE:
- vfe32_stats_aec_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_AF_BUF_RELEASE:
- vfe32_stats_af_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_AWB_BUF_RELEASE:
- vfe32_stats_awb_ack(vfe32_ctrl, sack);
- break;
-
- case CMD_STATS_IHIST_BUF_RELEASE:
- vfe32_stats_ihist_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_RS_BUF_RELEASE:
- vfe32_stats_rs_ack(vfe32_ctrl, sack);
- break;
- case CMD_STATS_CS_BUF_RELEASE:
- vfe32_stats_cs_ack(vfe32_ctrl, sack);
- break;
- default:
- pr_err("%s Unsupported AXI configuration %x ", __func__,
- cmd->cmd_type);
- break;
+ }
}
vfe32_config_done:
kfree(scfg);
@@ -4542,14 +4708,7 @@
spin_lock_init(&vfe32_ctrl->io_lock);
spin_lock_init(&vfe32_ctrl->update_ack_lock);
spin_lock_init(&vfe32_ctrl->start_ack_lock);
-
- spin_lock_init(&vfe32_ctrl->aec_ack_lock);
- spin_lock_init(&vfe32_ctrl->awb_ack_lock);
- spin_lock_init(&vfe32_ctrl->af_ack_lock);
- spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
- spin_lock_init(&vfe32_ctrl->rs_ack_lock);
- spin_lock_init(&vfe32_ctrl->cs_ack_lock);
- spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
+ spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
vfe32_ctrl->update_linear = false;
vfe32_ctrl->update_rolloff = false;
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index c41df09..542bbf8 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -14,6 +14,7 @@
#define __MSM_VFE32_H__
#include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
#define TRUE 1
#define FALSE 0
@@ -912,8 +913,6 @@
#define VFE32_OUTPUT_MODE_TERTIARY2 BIT(11)
struct vfe_stats_control {
- uint8_t ackPending;
- uint32_t nextFrameAddrBuf;
uint32_t droppedStatsFrameCount;
uint32_t bufToRender;
};
@@ -966,15 +965,7 @@
spinlock_t start_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
-
- spinlock_t aec_ack_lock;
- spinlock_t awb_ack_lock;
- spinlock_t af_ack_lock;
- spinlock_t ihist_ack_lock;
- spinlock_t rs_ack_lock;
- spinlock_t cs_ack_lock;
- spinlock_t comp_stats_ack_lock;
-
+ spinlock_t stats_bufq_lock;
uint32_t extlen;
void *extdata;
@@ -1013,6 +1004,8 @@
uint32_t frame_skip_cnt;
uint32_t frame_skip_pattern;
uint32_t snapshot_frame_cnt;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
};
#define statsAeNum 0
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 398621f..5fef610 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -351,6 +351,221 @@
static uint32_t raw_mode;
static struct vfe2x_ctrl_type *vfe2x_ctrl;
+static unsigned long vfe2x_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+
+ rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
+ stats_type, &buf);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0;
+ }
+ return buf->paddr;
+}
+
+static unsigned long vfe2x_stats_flush_enqueue(
+ enum msm_stats_enum_type stats_type)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ int rc = 0;
+ int i;
+
+ /*
+ * Passing NULL for ion client as the buffers are already
+ * mapped at this stage, client is not required, flush all
+ * the buffers, and buffers move to PREPARE state
+ */
+ rc = vfe2x_ctrl->stats_ops.bufq_flush(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ stats_type, NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return 0L;
+ }
+
+ /* Queue all the buffers back to QUEUED state */
+ bufq = vfe2x_ctrl->stats_ctrl.bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ &(stats_buf->info), NULL);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf (type = %d) err = %d",
+ __func__, stats_type, rc);
+ return rc;
+ }
+ }
+ return 0L;
+}
+
+static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
+{
+ unsigned long flags;
+ int i = 0, rc = 0;
+ if (type == MSM_STATS_TYPE_AF) {
+ spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+ rc = vfe2x_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock,
+ flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+ }
+ for (i = 0; i < 3; i++) {
+ spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+ if (type == MSM_STATS_TYPE_AE_AW)
+ vfe2x_ctrl->stats_we_buf_ptr[i] =
+ vfe2x_stats_dqbuf(type);
+ else
+ vfe2x_ctrl->stats_af_buf_ptr[i] =
+ vfe2x_stats_dqbuf(type);
+ spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+ if (!vfe2x_ctrl->stats_we_buf_ptr[i]) {
+ pr_err("%s: dq error type %d ", __func__, type);
+ return -ENOMEM;
+ }
+ }
+ return rc;
+}
+
+static unsigned long vfe2x_stats_enqueuebuf(
+ struct msm_stats_buf_info *info, struct vfe_stats_ack *sack)
+{
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ struct msm_stats_meta_buf *buf = NULL;
+ int rc = 0;
+
+ bufq = vfe2x_ctrl->stats_ctrl.bufq[info->type];
+ stats_buf = &bufq->bufs[info->buf_idx];
+
+ CDBG("vfe2x_stats_enqueuebuf: %d\n", stats_buf->state);
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED ||
+ stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ &vfe2x_ctrl->stats_ctrl,
+ info, vfe2x_ctrl->stats_ops.client);
+ if (rc < 0) {
+ pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
+ __func__, info->type, info->buf_idx, rc);
+ return rc;
+ }
+
+ } else {
+ rc = vfe2x_ctrl->stats_ops.querybuf(
+ vfe2x_ctrl->stats_ops.stats_ctrl, info, &buf);
+ if (rc < 0) {
+ pr_err("%s: querybuf (type = %d), index : %d, err = %d",
+ __func__, info->type, info->buf_idx, rc);
+ return rc;
+ }
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+ if (info->type == MSM_STATS_TYPE_AE_AW) {
+ sack->header = VFE_STATS_WB_EXP_ACK;
+ sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+ } else if (info->type == MSM_STATS_TYPE_AF) {
+ sack->header = VFE_STATS_AUTOFOCUS_ACK;
+ sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+ } else
+ pr_err("%s: Invalid stats: should never come here\n", __func__);
+ }
+ return 0L;
+}
+
+static long vfe2x_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+ void *ion_client)
+{
+ long rc = 0;
+
+ switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ if (!vfe2x_ctrl->stats_ops.stats_ctrl) {
+ /* stats_ctrl has not been init yet */
+ rc = msm_stats_buf_ops_init(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct ion_client *)ion_client,
+ &vfe2x_ctrl->stats_ops);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats ops", __func__);
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.stats_ctrl_init(
+ &vfe2x_ctrl->stats_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot init stats_ctrl ops",
+ __func__);
+ memset(&vfe2x_ctrl->stats_ops, 0,
+ sizeof(vfe2x_ctrl->stats_ops));
+ goto end;
+ }
+ if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats reqbuf input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_reqbuf));
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+ rc = vfe2x_ctrl->stats_ops.reqbuf(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct msm_stats_reqbuf *)cmd->value,
+ vfe2x_ctrl->stats_ops.client);
+ break;
+ case VFE_CMD_STATS_ENQUEUEBUF: {
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+ &vfe2x_ctrl->stats_ctrl,
+ (struct msm_stats_buf_info *)cmd->value,
+ vfe2x_ctrl->stats_ops.client);
+ }
+ break;
+ case VFE_CMD_STATS_FLUSH_BUFQ: {
+ struct msm_stats_flush_bufq *flush_req = NULL;
+ flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+ if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats flush queue input size = %d,\n"
+ "struct size = %d, mismatch\n",
+ __func__, cmd->length,
+ sizeof(struct msm_stats_flush_bufq));
+ rc = -EINVAL;
+ goto end;
+ }
+ rc = vfe2x_ctrl->stats_ops.bufq_flush(
+ &vfe2x_ctrl->stats_ctrl,
+ (enum msm_stats_enum_type)flush_req->stats_type,
+ vfe2x_ctrl->stats_ops.client);
+ }
+ break;
+ default:
+ rc = -1;
+ pr_err("%s: cmd_type %d not supported",
+ __func__, cmd->cmd_type);
+ break;
+ }
+end:
+ return rc;
+}
+
static void vfe2x_send_isp_msg(
struct vfe2x_ctrl_type *vctrl,
uint32_t isp_msg_id)
@@ -384,11 +599,26 @@
static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
{
struct isp_msg_stats msg_stats;
+ void *vaddr = NULL;
+ int rc;
msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
msg_stats.buffer = buf_addr;
msg_stats.id = msg_id;
+ if (MSG_ID_STATS_AWB_AEC == msg_id)
+ rc = vfe2x_ctrl->stats_ops.dispatch(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AE_AW, buf_addr,
+ &msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+ vfe2x_ctrl->stats_ops.client);
+ else if (MSG_ID_STATS_AF == msg_id)
+ rc = vfe2x_ctrl->stats_ops.dispatch(
+ vfe2x_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_AF, buf_addr,
+ &msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+ vfe2x_ctrl->stats_ops.client);
+
v4l2_subdev_notify(&vfe2x_ctrl->subdev,
NOTIFY_VFE_MSG_STATS,
&msg_stats);
@@ -979,21 +1209,54 @@
CDBG("msm_vfe_subdev_ioctl is called\n");
if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
- cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
- cmd->cmd_type != CMD_VFE_BUFFER_RELEASE) {
+ cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
+ cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
+ cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+ cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
if (copy_from_user(&vfecmd,
- (void __user *)(cmd->value),
- sizeof(vfecmd))) {
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
return -EFAULT;
}
}
-
switch (cmd->cmd_type) {
+ case VFE_CMD_STATS_REQBUF:
+ case VFE_CMD_STATS_FLUSH_BUFQ:
+ /* for easy porting put in one envelope */
+ rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+ return rc;
+ case VFE_CMD_STATS_ENQUEUEBUF:
+ if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+ /* error. the length not match */
+ pr_err("%s: stats enqueuebuf input size = %d,\n"
+ "struct size = %d, mitch match\n",\
+ __func__, cmd->length,
+ sizeof(struct msm_stats_buf_info));
+ rc = -EINVAL;
+ return rc;
+ }
+ sack.header = 0;
+ sack.bufaddr = NULL;
+ rc = vfe2x_stats_enqueuebuf(cmd->value, &sack);
+ if (rc < 0) {
+ pr_err("%s: error", __func__);
+ rc = -EINVAL;
+ return rc;
+ }
+ if (sack.header != 0 && sack.bufaddr != NULL) {
+ queue = QDSP_CMDQUEUE;
+ vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+ cmd_data = &sack;
+ } else {
+ return 0;
+ }
+ break;
case CMD_VFE_BUFFER_RELEASE: {
if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
return 0;
@@ -1041,7 +1304,6 @@
}
return 0;
- case CMD_STATS_AEC_AWB_ENABLE:
case CMD_STATS_AXI_CFG: {
axid = data;
if (!axid) {
@@ -1096,15 +1358,49 @@
}
}
break;
- case CMD_STATS_AF_ENABLE:
- case CMD_STATS_AF_AXI_CFG: {
- CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
- axid = data;
- if (!axid) {
- rc = -EFAULT;
+ case CMD_STATS_AEC_AWB_ENABLE: {
+ pr_err("CMD_STATS_AEC_AWB_ENABLE\n");
+ scfg =
+ kmalloc(sizeof(struct vfe_stats_we_cfg),
+ GFP_ATOMIC);
+ if (!scfg) {
+ rc = -ENOMEM;
goto config_failure;
}
+ if (copy_from_user((char *)scfg + 4,
+ (void __user *)(vfecmd.value),
+ vfecmd.length)) {
+
+ rc = -EFAULT;
+ goto config_done;
+ }
+
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_failure;
+ }
+ *(uint32_t *)scfg = header;
+ rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AE_AW);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto config_failure;
+ }
+ scfg->wb_expstatoutputbuffer[0] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[0];
+ scfg->wb_expstatoutputbuffer[1] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[1];
+ scfg->wb_expstatoutputbuffer[2] =
+ (void *)vfe2x_ctrl->stats_we_buf_ptr[2];
+ cmd_data = scfg;
+ }
+ break;
+ case CMD_STATS_AF_ENABLE:
+ case CMD_STATS_AF_AXI_CFG: {
+ CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
sfcfg =
kmalloc(sizeof(struct vfe_stats_af_cfg),
GFP_ATOMIC);
@@ -1122,9 +1418,6 @@
goto config_done;
}
- CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
- axid->bufnum1, sfcfg->af_enable);
-
header = cmds_map[vfecmd.id].vfe_id;
queue = cmds_map[vfecmd.id].queue;
if (header == -1 && queue == -1) {
@@ -1132,27 +1425,16 @@
goto config_failure;
}
*(uint32_t *)sfcfg = header;
- CDBG("Number of buffers = %d\n", axid->bufnum1);
- if (axid->bufnum1 > 0) {
- regptr = &axid->region[0];
-
- for (i = 0; i < axid->bufnum1; i++) {
-
- CDBG("STATS_ENABLE, phy = 0x%lx\n",
- regptr->paddr);
-
- sfcfg->af_outbuf[i] =
- (void *)regptr->paddr;
-
- regptr++;
- }
-
- cmd_data = sfcfg;
-
- } else {
- rc = -EINVAL;
- goto config_done;
+ rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AF);
+ sfcfg->af_outbuf[0] = (void *)vfe2x_ctrl->stats_af_buf_ptr[0];
+ sfcfg->af_outbuf[1] = (void *)vfe2x_ctrl->stats_af_buf_ptr[1];
+ sfcfg->af_outbuf[2] = (void *)vfe2x_ctrl->stats_af_buf_ptr[2];
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of AWB",
+ __func__);
+ goto config_failure;
}
+ cmd_data = sfcfg;
}
break;
case CMD_SNAP_BUF_RELEASE:
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2f2d3c6..b7d6806 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -16,6 +16,7 @@
#include <mach/camera.h>
#include <linux/list.h>
#include "msm.h"
+#include "msm_vfe_stats_buf.h"
struct cmd_id_map {
uint32_t isp_id;
@@ -111,6 +112,11 @@
spinlock_t sd_notify_lock;
uint32_t reconfig_vfe;
uint32_t zsl_mode;
+ spinlock_t stats_bufq_lock;
+ struct msm_stats_bufq_ctrl stats_ctrl;
+ struct msm_stats_ops stats_ops;
+ unsigned long stats_we_buf_ptr[3];
+ unsigned long stats_af_buf_ptr[3];
} __packed;
struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c
new file mode 100644
index 0000000..9e8f285
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.c
@@ -0,0 +1,509 @@
+/* Copyright (c) 2012, 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 <media/msm_camera.h>
+#include <media/msm_isp.h>
+#include "msm.h"
+#include "msm_vfe_stats_buf.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+ #define D(fmt, args...) pr_debug("msm_stats: " fmt, ##args)
+#else
+ #define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_stats_init(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+ int rc = 0;
+ /* cannot get spinlock here */
+ if (stats_ctrl->init_done > 0) {
+ pr_err("%s: already initialized stats ctrl. no op", __func__);
+ return 0;
+ }
+ memset(stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
+ spin_lock_init(&stats_ctrl->lock);
+ stats_ctrl->init_done = 1;
+ return rc;
+}
+
+static int msm_stats_reqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_reqbuf *reqbuf,
+ struct ion_client *client)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq;
+ struct msm_stats_meta_buf *bufs;
+ int idx = reqbuf->stats_type;
+ int i;
+
+ D("%s: type : %d, buf num : %d\n", __func__,
+ reqbuf->stats_type, reqbuf->num_buf);
+ if (reqbuf->num_buf > 0) {
+ if (stats_ctrl->bufq[idx]) {
+ /* already in use. Error */
+ pr_err("%s: stats type %d aleady requested",
+ __func__, reqbuf->stats_type);
+ rc = -EEXIST;
+ goto end;
+ } else {
+ /* good case */
+ bufq = (struct msm_stats_bufq *)
+ kzalloc(
+ sizeof(struct msm_stats_bufq),
+ GFP_KERNEL);
+ if (!bufq) {
+ /* no memory */
+ rc = -ENOMEM;
+ pr_err("%s: no mem for stats type %d",
+ __func__, reqbuf->stats_type);
+ goto end;
+ }
+ bufs = (struct msm_stats_meta_buf *)
+ kzalloc((reqbuf->num_buf *
+ sizeof(struct msm_stats_meta_buf)),
+ GFP_KERNEL);
+ if (!bufs) {
+ /* no memory */
+ rc = -ENOMEM;
+ pr_err("%s: no mem for stats buf, stats type = %d",
+ __func__, reqbuf->stats_type);
+ kfree(bufq);
+ goto end;
+ }
+ /* init bufq list head */
+ INIT_LIST_HEAD(&bufq->head);
+ /* set the meta buf state to initialized */
+ bufq->num_bufs = reqbuf->num_buf;
+ for (i = 0; i < reqbuf->num_buf; i++)
+ bufs[i].state =
+ MSM_STATS_BUFFER_STATE_INITIALIZED;
+ bufq->bufs = bufs;
+ bufq->num_bufs = reqbuf->num_buf;
+ bufq->type = reqbuf->stats_type;
+ stats_ctrl->bufq[idx] = bufq;
+ /* done reqbuf (larger than zero case) */
+ goto end;
+ }
+ } else if (reqbuf->num_buf == 0) {
+ if (stats_ctrl->bufq[idx] == NULL) {
+ /* double free case? */
+ pr_err("%s: stats type %d aleady freed",
+ __func__, reqbuf->stats_type);
+ rc = -ENXIO;
+ goto end;
+ } else {
+ /* good case. need to de-reqbuf */
+ kfree(stats_ctrl->bufq[idx]->bufs);
+ kfree(stats_ctrl->bufq[idx]);
+ stats_ctrl->bufq[idx] = NULL;
+ goto end;
+ }
+ } else {
+ /* error case */
+ pr_err("%s: stats type = %d, req_num_buf = %d, error",
+ __func__, reqbuf->stats_type, reqbuf->num_buf);
+ rc = -EPERM;
+ goto end;
+ }
+end:
+ return rc;
+}
+static int msm_stats_deinit(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+ int rc = 0;
+ int i;
+
+ if (stats_ctrl->init_done == 0) {
+ pr_err("%s: not inited yet. no op", __func__);
+ return 0;
+ }
+ /* safe guard in case deallocate memory not done yet. */
+ for (i = 0; i < MSM_STATS_TYPE_MAX; i++) {
+ if (stats_ctrl->bufq[i]) {
+ if (stats_ctrl->bufq[i]->bufs) {
+ rc = -1;
+ pr_err("%s: stats type = %d, buf not freed yet",
+ __func__, i);
+ BUG_ON(stats_ctrl->bufq[i]->bufs);
+ } else {
+ rc = -1;
+ pr_err("%s: stats type = %d, bufq not freed yet",
+ __func__, i);
+ BUG_ON(stats_ctrl->bufq[i]);
+ }
+ }
+ }
+ memset(stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
+ return rc;
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
+{
+ if (info->offset < len &&
+ info->offset + info->len <= len &&
+ info->planar0_off < len && info->planar1_off < len)
+ return 0;
+
+ pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+ __func__,
+ info->offset,
+ info->len,
+ info->planar0_off,
+ info->planar1_off,
+ len);
+ return -EINVAL;
+}
+#endif
+
+static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info, struct ion_client *client)
+{
+ unsigned long paddr;
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+ unsigned long kvstart;
+ struct file *file;
+#endif
+ int rc = 0;
+ unsigned long len;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d, buf num : %d\n", __func__,
+ info->type, info->buf_idx);
+
+ bufq = stats_ctrl->bufq[info->type];
+ stats_buf = &bufq->bufs[info->buf_idx];
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+ pr_err("%s: need reqbuf first, stats type = %d",
+ __func__, info->type);
+ rc = -1;
+ goto out1;
+ }
+ if (stats_buf->state != MSM_STATS_BUFFER_STATE_INITIALIZED) {
+ D("%s: stats already mapped, no op, stats type = %d",
+ __func__, info->type);
+ goto out1;
+ }
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ stats_buf->handle = ion_import_dma_buf(client, info->fd);
+ if (IS_ERR_OR_NULL(stats_buf->handle)) {
+ rc = -EINVAL;
+ pr_err("%s: stats_buf has null/error ION handle %p",
+ __func__, stats_buf->handle);
+ goto out1;
+ }
+ if (ion_map_iommu(client, stats_buf->handle,
+ CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+ 0, &paddr, &len, UNCACHED, 0) < 0) {
+ rc = -EINVAL;
+ pr_err("%s: cannot map address", __func__);
+ goto out2;
+ }
+#elif CONFIG_ANDROID_PMEM
+ rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+ if (rc < 0) {
+ pr_err("%s: get_pmem_file fd %d error %d\n",
+ __func__, info->fd, rc);
+ goto out1;
+ }
+ stats_buf->file = file;
+#else
+ paddr = 0;
+ file = NULL;
+ kvstart = 0;
+#endif
+ if (!info->len)
+ info->len = len;
+ rc = msm_stats_check_pmem_info(info, len);
+ if (rc < 0) {
+ pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
+ goto out3;
+ }
+ paddr += info->offset;
+ len = info->len;
+ stats_buf->paddr = paddr;
+ stats_buf->len = len;
+ memcpy(&stats_buf->info, info, sizeof(stats_buf->info));
+ D("%s Adding buf to list with type %d\n", __func__,
+ stats_buf->info.type);
+ D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ return 0;
+out3:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
+ ion_free(client, stats_buf->handle);
+#elif CONFIG_ANDROID_PMEM
+ put_pmem_file(stats_buf->file);
+#endif
+out1:
+ return rc;
+}
+static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type, int buf_idx,
+ struct ion_client *client)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d, idx : %d\n", __func__, stats_type, buf_idx);
+ bufq = stats_ctrl->bufq[stats_type];
+ stats_buf = &bufq->bufs[buf_idx];
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+ pr_err("%s: need reqbuf first, stats type = %d",
+ __func__, stats_type);
+ rc = -1;
+ goto end;
+ }
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED) {
+ D("%s: stats already mapped, no op, stats type = %d",
+ __func__, stats_type);
+ goto end;
+ }
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, stats_buf->handle,
+ CAMERA_DOMAIN, GEN_POOL);
+ ion_free(client, stats_buf->handle);
+#else
+ put_pmem_file(stats_buf->file);
+#endif
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+ /* buf queued need delete from list */
+ D("%s: delete stats buf, type = %d, idx = %d",
+ __func__, stats_type, buf_idx);
+ list_del_init(&stats_buf->list);
+ }
+end:
+ return rc;
+}
+
+static int msm_stats_bufq_flush(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type, struct ion_client *client)
+{
+ int rc = 0;
+ int i;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d\n", __func__, stats_type);
+ bufq = stats_ctrl->bufq[stats_type];
+
+ for (i = 0; i < bufq->num_bufs; i++) {
+ stats_buf = &bufq->bufs[i];
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_QUEUED:
+ /* buf queued in stats free queue */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ list_del_init(&stats_buf->list);
+ break;
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ /* if stats buf in VFE reset the state */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ break;
+ case MSM_STATS_BUFFER_STATE_DISPATCHED:
+ /* if stats buf in userspace reset the state */
+ stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+ break;
+ default:
+ break;
+ }
+ }
+ return rc;
+}
+
+static int msm_stats_dqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct msm_stats_meta_buf **pp_stats_buf)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+
+ D("%s: type : %d\n", __func__, stats_type);
+ *pp_stats_buf = NULL;
+ bufq = stats_ctrl->bufq[stats_type];
+
+ list_for_each_entry(stats_buf, &bufq->head, list) {
+ if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+ /* found one buf */
+ list_del_init(&stats_buf->list);
+ *pp_stats_buf = stats_buf;
+ break;
+ }
+ }
+ if (!(*pp_stats_buf)) {
+ pr_err("%s: no free stats buf, type = %d",
+ __func__, stats_type);
+ rc = -1;
+ return rc;
+ }
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+ return rc;
+}
+
+
+static int msm_stats_querybuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct msm_stats_meta_buf **pp_stats_buf)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+
+ *pp_stats_buf = NULL;
+ D("%s: stats type : %d, buf_idx : %d", __func__, info->type,
+ info->buf_idx);
+ bufq = stats_ctrl->bufq[info->type];
+ *pp_stats_buf = &bufq->bufs[info->buf_idx];
+
+ return rc;
+}
+
+static int msm_stats_qbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx)
+{
+ int rc = 0;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ D("%s: stats type : %d, buf_idx : %d", __func__, stats_type,
+ buf_idx);
+
+ bufq = stats_ctrl->bufq[stats_type];
+ if (!bufq) {
+ pr_err("%s: null bufq, stats type = %d", __func__, stats_type);
+ rc = -1;
+ goto end;
+ }
+ if (buf_idx >= bufq->num_bufs) {
+ pr_err("%s: stats type = %d, its idx %d larger than buf count %d",
+ __func__, stats_type, buf_idx, bufq->num_bufs);
+ rc = -1;
+ goto end;
+ }
+ stats_buf = &bufq->bufs[buf_idx];
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_PREPARED:
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ case MSM_STATS_BUFFER_STATE_DISPATCHED:
+ stats_buf->state = MSM_STATS_BUFFER_STATE_QUEUED;
+ list_add_tail(&stats_buf->list, &bufq->head);
+ break;
+ default:
+ pr_err("%s: incorrect state = %d, stats type = %d, cannot qbuf",
+ __func__, stats_buf->state, stats_type);
+ rc = -1;
+ break;
+ }
+end:
+ return rc;
+}
+
+static int msm_stats_buf_dispatch(struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ unsigned long phy_addr, int *buf_idx,
+ void **vaddr, int *fd,
+ struct ion_client *client)
+{
+ int rc = 0;
+ int i;
+ struct msm_stats_bufq *bufq = NULL;
+ struct msm_stats_meta_buf *stats_buf = NULL;
+ D("%s: stats type : %d\n", __func__, stats_type);
+
+ *buf_idx = -1;
+ *vaddr = NULL;
+ *fd = 0;
+ bufq = stats_ctrl->bufq[stats_type];
+ for (i = 0; i < bufq->num_bufs; i++) {
+ if (bufq->bufs[i].paddr == phy_addr) {
+ stats_buf = &bufq->bufs[i];
+ *buf_idx = i;
+ *vaddr = stats_buf->info.vaddr;
+ *fd = stats_buf->info.fd;
+ break;
+ }
+ }
+ if (!stats_buf) {
+ pr_err("%s: no match, phy_addr = 0x%ld, stats_type = %d",
+ __func__, phy_addr, stats_type);
+ return -EFAULT;
+ }
+ switch (stats_buf->state) {
+ case MSM_STATS_BUFFER_STATE_DEQUEUED:
+ stats_buf->state = MSM_STATS_BUFFER_STATE_DISPATCHED;
+ break;
+ default:
+ pr_err("%s: type = %d, idx = %d, cur_state = %d,\n"
+ "cannot set state to DISPATCHED\n",
+ __func__, stats_type, *buf_idx, stats_buf->state);
+ rc = -EFAULT;
+ break;
+ }
+ return rc;
+}
+static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info, struct ion_client *client)
+{
+ int rc = 0;
+ rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+ if (rc < 0) {
+ pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
+ return -EINVAL;
+ }
+ rc = msm_stats_qbuf(stats_ctrl, info->type, info->buf_idx);
+ if (rc < 0) {
+ pr_err("%s: msm_stats_qbuf failed, rc = %d", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct ion_client *client, struct msm_stats_ops *ops)
+{
+ ops->stats_ctrl = stats_ctrl;
+ ops->client = client;
+ ops->enqueue_buf = msm_stats_enqueue_buf;
+ ops->qbuf = msm_stats_qbuf;
+ ops->dqbuf = msm_stats_dqbuf;
+ ops->bufq_flush = msm_stats_bufq_flush;
+ ops->buf_unprepare = msm_stats_buf_unprepare;
+ ops->buf_prepare = msm_stats_buf_prepare;
+ ops->reqbuf = msm_stats_reqbuf;
+ ops->querybuf = msm_stats_querybuf;
+ ops->dispatch = msm_stats_buf_dispatch;
+ ops->stats_ctrl_init = msm_stats_init;
+ ops->stats_ctrl_deinit = msm_stats_deinit;
+ return 0;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.h b/drivers/media/video/msm/msm_vfe_stats_buf.h
new file mode 100644
index 0000000..18fd425
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012, 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.
+ *
+ */
+
+#ifndef _MSM_STATS_BUF_H_
+#define _MSM_STATS_BUF_H_
+
+enum msm_stats_buffer_state {
+ MSM_STATS_BUFFER_STATE_UNUSED, /* not used */
+ MSM_STATS_BUFFER_STATE_INITIALIZED, /* REQBUF done */
+ MSM_STATS_BUFFER_STATE_PREPARED, /* BUF mapped */
+ MSM_STATS_BUFFER_STATE_QUEUED, /* buf queued */
+ MSM_STATS_BUFFER_STATE_DEQUEUED, /* in use in VFE */
+ MSM_STATS_BUFFER_STATE_DISPATCHED, /* sent to userspace */
+};
+
+struct msm_stats_meta_buf {
+ struct list_head list;
+ enum msm_stats_buffer_state state;
+ int type;
+ int fd;
+ uint32_t offset;
+ unsigned long paddr;
+ unsigned long len;
+ struct file *file;
+ struct msm_stats_buf_info info;
+ struct ion_handle *handle;
+};
+
+struct msm_stats_bufq {
+ struct list_head head;
+ int num_bufs;
+ int type;
+ struct msm_stats_meta_buf *bufs;
+};
+
+
+struct msm_stats_bufq_ctrl {
+ /* not use spin lock for now. Assume vfe holds spin lock */
+ spinlock_t lock;
+ int init_done;
+ struct msm_stats_bufq *bufq[MSM_STATS_TYPE_MAX];
+};
+
+struct msm_stats_ops {
+ struct msm_stats_bufq_ctrl *stats_ctrl;
+ struct ion_client *client;
+ int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct ion_client *client);
+ int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx);
+ int (*dqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct msm_stats_meta_buf **pp_stats_buf);
+ int (*bufq_flush) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ struct ion_client *client);
+ int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ int buf_idx,
+ struct ion_client *client);
+ int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct ion_client *client);
+ int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_reqbuf *reqbuf,
+ struct ion_client *client);
+ int (*dispatch) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ enum msm_stats_enum_type stats_type,
+ unsigned long phy_addr, int *buf_idx, void **vaddr, int *fd,
+ struct ion_client *client);
+ int (*querybuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct msm_stats_buf_info *info,
+ struct msm_stats_meta_buf **pp_stats_buf);
+ int (*stats_ctrl_init) (struct msm_stats_bufq_ctrl *stats_ctrl);
+ int (*stats_ctrl_deinit) (struct msm_stats_bufq_ctrl *stats_ctrl);
+};
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+ struct ion_client *client, struct msm_stats_ops *ops);
+
+#endif /* _MSM_STATS_BUF_H_ */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 81b6a40..48058e6 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -195,6 +195,24 @@
#define MSM_CAM_IOCTL_ISPIF_IO_CFG \
_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
+#define MSM_CAM_IOCTL_STATS_REQBUF \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *)
+
+#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *)
+
+#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+
+struct msm_stats_reqbuf {
+ int num_buf; /* how many buffers requested */
+ int stats_type; /* stats type */
+};
+
+struct msm_stats_flush_bufq {
+ int stats_type; /* enum msm_stats_enum_type */
+};
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
@@ -515,6 +533,36 @@
#define FRAME_RAW_SNAPSHOT 4
#define FRAME_MAX 5
+enum msm_stats_enum_type {
+ MSM_STATS_TYPE_AEC, /* legacy based AEC */
+ MSM_STATS_TYPE_AF, /* legacy based AF */
+ MSM_STATS_TYPE_AWB, /* legacy based AWB */
+ MSM_STATS_TYPE_RS, /* legacy based RS */
+ MSM_STATS_TYPE_CS, /* legacy based CS */
+ MSM_STATS_TYPE_IHIST, /* legacy based HIST */
+ MSM_STATS_TYPE_SKIN, /* legacy based SKIN */
+ MSM_STATS_TYPE_BG, /* Bayer Grids */
+ MSM_STATS_TYPE_BF, /* Bayer Focus */
+ MSM_STATS_TYPE_BHIST, /* Bayer Hist */
+ MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/
+ MSM_STATS_TYPE_MAX /* MAX */
+};
+
+struct msm_stats_buf_info {
+ int type; /* msm_stats_enum_type */
+ int fd;
+ void *vaddr;
+ uint32_t offset;
+ uint32_t len;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ uint32_t planar0_off;
+ uint32_t planar1_off;
+ uint32_t planar2_off;
+ uint8_t active;
+ int buf_idx;
+};
+
struct msm_pmem_info {
int type;
int fd;
@@ -678,6 +726,7 @@
int length;
struct ion_handle *handle;
uint32_t frame_id;
+ int buf_idx;
};
#define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
/* video capture mode in VIDIOC_S_PARM */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 6547795..1f3527b 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -203,6 +203,9 @@
#define VFE_CMD_CAPTURE_RAW 136
#define VFE_CMD_STOP_LIVESHOT 137
#define VFE_CMD_RECONFIG_VFE 138
+#define VFE_CMD_STATS_REQBUF 139
+#define VFE_CMD_STATS_ENQUEUEBUF 140
+#define VFE_CMD_STATS_FLUSH_BUFQ 141
struct msm_isp_cmd {
int32_t id;