From a3ca4db7ad56a4dbe6db346250efddca2d8e89fe Mon Sep 17 00:00:00 2001 From: Kevin Chan Date: Sun, 22 Jul 2012 02:23:43 -0700 Subject: [PATCH] msm: camera: Initial commit for VFE 4.0 Add Image Signal Processor support for 8974 chipset. Change-Id: Id1f425e59d48e490d5e426f5d056bca7c54b54a2 Signed-off-by: Kevin Chan --- drivers/media/video/msm/vfe/Makefile | 1 + drivers/media/video/msm/vfe/msm_vfe40.c | 3699 +++++++++++++++++++ drivers/media/video/msm/vfe/msm_vfe40.h | 1202 ++++++ drivers/media/video/msm/vfe/msm_vfe40_axi.c | 812 ++++ include/media/msm_isp.h | 13 + 5 files changed, 5727 insertions(+) create mode 100644 drivers/media/video/msm/vfe/msm_vfe40.c create mode 100644 drivers/media/video/msm/vfe/msm_vfe40.h create mode 100644 drivers/media/video/msm/vfe/msm_vfe40_axi.c diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile index 8068e4faf16..91f0e7f9c7d 100644 --- a/drivers/media/video/msm/vfe/Makefile +++ b/drivers/media/video/msm/vfe/Makefile @@ -16,4 +16,5 @@ endif obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o obj-$(CONFIG_ARCH_MSM8960) += msm_vfe32.o +obj-$(CONFIG_ARCH_MSM8974) += msm_vfe40.o msm_vfe40_axi.o obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_vfe_stats_buf.o diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c new file mode 100644 index 00000000000..5a1d488607c --- /dev/null +++ b/drivers/media/video/msm/vfe/msm_vfe40.c @@ -0,0 +1,3699 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm.h" +#include "msm_vfe40.h" + +struct vfe40_isr_queue_cmd { + struct list_head list; + uint32_t vfeInterruptStatus0; + uint32_t vfeInterruptStatus1; +}; + +static const char * const vfe40_general_cmd[] = { + "DUMMY_0", /* 0 */ + "SET_CLK", + "RESET", + "START", + "TEST_GEN_START", + "OPERATION_CFG", /* 5 */ + "AXI_OUT_CFG", + "CAMIF_CFG", + "AXI_INPUT_CFG", + "BLACK_LEVEL_CFG", + "ROLL_OFF_CFG", /* 10 */ + "DEMUX_CFG", + "FOV_CFG", + "MAIN_SCALER_CFG", + "WB_CFG", + "COLOR_COR_CFG", /* 15 */ + "RGB_G_CFG", + "LA_CFG", + "CHROMA_EN_CFG", + "CHROMA_SUP_CFG", + "MCE_CFG", /* 20 */ + "SK_ENHAN_CFG", + "ASF_CFG", + "S2Y_CFG", + "S2CbCr_CFG", + "CHROMA_SUBS_CFG", /* 25 */ + "OUT_CLAMP_CFG", + "FRAME_SKIP_CFG", + "DUMMY_1", + "DUMMY_2", + "DUMMY_3", /* 30 */ + "UPDATE", + "BL_LVL_UPDATE", + "DEMUX_UPDATE", + "FOV_UPDATE", + "MAIN_SCALER_UPDATE", /* 35 */ + "WB_UPDATE", + "COLOR_COR_UPDATE", + "RGB_G_UPDATE", + "LA_UPDATE", + "CHROMA_EN_UPDATE", /* 40 */ + "CHROMA_SUP_UPDATE", + "MCE_UPDATE", + "SK_ENHAN_UPDATE", + "S2CbCr_UPDATE", + "S2Y_UPDATE", /* 45 */ + "ASF_UPDATE", + "FRAME_SKIP_UPDATE", + "CAMIF_FRAME_UPDATE", + "STATS_AF_UPDATE", + "STATS_AE_UPDATE", /* 50 */ + "STATS_AWB_UPDATE", + "STATS_RS_UPDATE", + "STATS_CS_UPDATE", + "STATS_SKIN_UPDATE", + "STATS_IHIST_UPDATE", /* 55 */ + "DUMMY_4", + "EPOCH1_ACK", + "EPOCH2_ACK", + "START_RECORDING", + "STOP_RECORDING", /* 60 */ + "DUMMY_5", + "DUMMY_6", + "CAPTURE", + "DUMMY_7", + "STOP", /* 65 */ + "GET_HW_VERSION", + "GET_FRAME_SKIP_COUNTS", + "OUTPUT1_BUFFER_ENQ", + "OUTPUT2_BUFFER_ENQ", + "OUTPUT3_BUFFER_ENQ", /* 70 */ + "JPEG_OUT_BUF_ENQ", + "RAW_OUT_BUF_ENQ", + "RAW_IN_BUF_ENQ", + "STATS_AF_ENQ", + "STATS_AE_ENQ", /* 75 */ + "STATS_AWB_ENQ", + "STATS_RS_ENQ", + "STATS_CS_ENQ", + "STATS_SKIN_ENQ", + "STATS_IHIST_ENQ", /* 80 */ + "DUMMY_8", + "JPEG_ENC_CFG", + "DUMMY_9", + "STATS_AF_START", + "STATS_AF_STOP", /* 85 */ + "STATS_AE_START", + "STATS_AE_STOP", + "STATS_AWB_START", + "STATS_AWB_STOP", + "STATS_RS_START", /* 90 */ + "STATS_RS_STOP", + "STATS_CS_START", + "STATS_CS_STOP", + "STATS_SKIN_START", + "STATS_SKIN_STOP", /* 95 */ + "STATS_IHIST_START", + "STATS_IHIST_STOP", + "DUMMY_10", + "SYNC_TIMER_SETTING", + "ASYNC_TIMER_SETTING", /* 100 */ + "LIVESHOT", + "LA_SETUP", + "LINEARIZATION_CFG", + "DEMOSAICV3", + "DEMOSAICV3_ABCC_CFG", /* 105 */ + "DEMOSAICV3_DBCC_CFG", + "DEMOSAICV3_DBPC_CFG", + "DEMOSAICV3_ABF_CFG", + "DEMOSAICV3_ABCC_UPDATE", + "DEMOSAICV3_DBCC_UPDATE", /* 110 */ + "DEMOSAICV3_DBPC_UPDATE", + "XBAR_CFG", + "EZTUNE_CFG", + "V40_ZSL", + "LINEARIZATION_UPDATE", /*115*/ + "DEMOSAICV3_ABF_UPDATE", + "CLF_CFG", + "CLF_LUMA_UPDATE", + "CLF_CHROMA_UPDATE", + "PCA_ROLL_OFF_CFG", /*120*/ + "PCA_ROLL_OFF_UPDATE", + "GET_REG_DUMP", + "GET_LINEARIZATON_TABLE", + "GET_MESH_ROLLOFF_TABLE", + "GET_PCA_ROLLOFF_TABLE", /*125*/ + "GET_RGB_G_TABLE", + "GET_LA_TABLE", + "DEMOSAICV3_UPDATE", + "ACTIVE_REGION_CONFIG", + "COLOR_PROCESSING_CONFIG", /*130*/ + "STATS_WB_AEC_CONFIG", + "STATS_WB_AEC_UPDATE", + "Y_GAMMA_CONFIG", + "SCALE_OUTPUT1_CONFIG", + "SCALE_OUTPUT2_CONFIG", /*135*/ + "CAPTURE_RAW", + "STOP_LIVESHOT", + "RECONFIG_VFE", + "STATS_REQBUF_CFG", + "STATS_ENQUEUEBUF_CFG",/*140*/ + "STATS_FLUSH_BUFQ_CFG", + "FOV_ENC_CFG", + "FOV_VIEW_CFG", + "FOV_ENC_UPDATE", + "FOV_VIEW_UPDATE",/*145*/ + "SCALER_ENC_CFG", + "SCALER_VIEW_CFG", + "SCALER_ENC_UPDATE", + "SCALER_VIEW_UPDATE", + "COLORXFORM_ENC_CFG",/*150*/ + "COLORXFORM_VIEW_CFG", + "COLORXFORM_ENC_UPDATE", + "COLORXFORM_VIEW_UPDATE", +}; + +static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + + atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0); + + /* for reset hw modules, and send msg when reset_irq comes.*/ + spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + vfe40_ctrl->share_ctrl->stop_ack_pending = TRUE; + spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + + /* disable all interrupts. */ + msm_camera_io_w(VFE_DISABLE_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_camera_io_w(VFE_DISABLE_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts*/ + msm_camera_io_w(VFE_CLEAR_ALL_IRQ0, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_camera_io_w(VFE_CLEAR_ALL_IRQ1, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD); + + /* in either continuous or snapshot mode, stop command can be issued + * at any time. stop camif immediately. */ + msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY, + vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND); +} + +void vfe40_subdev_notify(int id, int path, int image_mode, + struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl) +{ + struct msm_vfe_resp rp; + struct msm_frame_info frame_info; + unsigned long flags = 0; + spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags); + CDBG("%s: msgId = %d\n", __func__, id); + memset(&rp, 0, sizeof(struct msm_vfe_resp)); + rp.evt_msg.type = MSM_CAMERA_MSG; + frame_info.image_mode = image_mode; + frame_info.path = path; + rp.evt_msg.data = &frame_info; + rp.type = id; + v4l2_subdev_notify(sd, NOTIFY_VFE_BUF_EVT, &rp); + spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags); +} + +static void vfe40_reset_internal_variables( + struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + vfe40_ctrl->vfeImaskCompositePacked = 0; + /* state control variables */ + vfe40_ctrl->start_ack_pending = FALSE; + atomic_set(&vfe40_ctrl->share_ctrl->irq_cnt, 0); + + spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + + vfe40_ctrl->reset_ack_pending = FALSE; + + spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags); + vfe40_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags); + + vfe40_ctrl->recording_state = VFE_STATE_IDLE; + vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE; + + atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0); + + /* 0 for continuous mode, 1 for snapshot mode */ + vfe40_ctrl->share_ctrl->operation_mode = 0; + vfe40_ctrl->share_ctrl->outpath.output_mode = 0; + vfe40_ctrl->share_ctrl->vfe_capture_count = 0; + + /* this is unsigned 32 bit integer. */ + vfe40_ctrl->share_ctrl->vfeFrameId = 0; + /* Stats control variables. */ + memset(&(vfe40_ctrl->afStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe40_ctrl->awbStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe40_ctrl->aecStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe40_ctrl->ihistStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe40_ctrl->rsStatsControl), 0, + sizeof(struct vfe_stats_control)); + + memset(&(vfe40_ctrl->csStatsControl), 0, + sizeof(struct vfe_stats_control)); + + vfe40_ctrl->frame_skip_cnt = 31; + vfe40_ctrl->frame_skip_pattern = 0xffffffff; + vfe40_ctrl->snapshot_frame_cnt = 0; +} + +static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl) +{ + vfe40_reset_internal_variables(vfe40_ctrl); + /* disable all interrupts. vfeImaskLocal is also reset to 0 + * to begin with. */ + msm_camera_io_w(VFE_DISABLE_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0); + + msm_camera_io_w(VFE_DISABLE_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* clear all pending interrupts*/ + msm_camera_io_w(VFE_CLEAR_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_camera_io_w(VFE_CLEAR_ALL_IRQS, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD); + + /* enable reset_ack interrupt. */ + msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset + * is done, hardware interrupt will be generated. VFE ist processes + * the interrupt to complete the function call. Note that the reset + * function is synchronous. */ + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD, + vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET); + + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_0); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_1); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_2); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_3); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_4); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_5); + msm_camera_io_w(0xAAAAAAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_6); + msm_camera_io_w(0x0002AAAA, + vfe40_ctrl->share_ctrl->vfebase + VFE_0_BUS_BDG_QOS_CFG_7); +} + +static int vfe40_operation_config(uint32_t *cmd, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t *p = cmd; + + vfe40_ctrl->share_ctrl->operation_mode = *p; + vfe40_ctrl->share_ctrl->stats_comp = *(++p); + vfe40_ctrl->hfr_mode = *(++p); + + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_CFG); + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG); + if (msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + V40_GET_HW_VERSION_OFF) == + VFE40_HW_NUMBER) { + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG); + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG); + } else { + ++p; + ++p; + } + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF); + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP); + msm_camera_io_w(*(++p), + vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG); + return 0; +} + +static unsigned long vfe40_stats_dqbuf(struct vfe40_ctrl_type *vfe40_ctrl, + enum msm_stats_enum_type stats_type) +{ + struct msm_stats_meta_buf *buf = NULL; + int rc = 0; + rc = vfe40_ctrl->stats_ops.dqbuf( + vfe40_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 vfe40_stats_flush_enqueue( + struct vfe40_ctrl_type *vfe40_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 = vfe40_ctrl->stats_ops.bufq_flush( + vfe40_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 = vfe40_ctrl->stats_ctrl.bufq[stats_type]; + for (i = 0; i < bufq->num_bufs; i++) { + stats_buf = &bufq->bufs[i]; + rc = vfe40_ctrl->stats_ops.enqueue_buf( + vfe40_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 vfe40_ctrl_type *vfe40_ctrl, + struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AWB_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AWB_WR_PONG_ADDR); + return 0; +} + +static int vfe_stats_aec_buf_init( + struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AEC_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AEC_WR_PONG_ADDR); + return 0; +} + +static int vfe_stats_af_buf_init( + struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF); + if (rc < 0) { + pr_err("%s: dq stats buf err = %d", + __func__, rc); + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + return -EINVAL; + } + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AF_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_AF_WR_PONG_ADDR); + + return 0; +} + +static int vfe_stats_ihist_buf_init( + struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_HIST_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_HIST_WR_PONG_ADDR); + + return 0; +} + +static int vfe_stats_rs_buf_init( + struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_RS_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_RS_WR_PONG_ADDR); + return 0; +} + +static int vfe_stats_cs_buf_init( + struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in) +{ + uint32_t addr; + unsigned long flags; + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_CS_WR_PING_ADDR); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS); + spin_unlock_irqrestore(&vfe40_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, + vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_CS_WR_PONG_ADDR); + return 0; +} + +static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t irq_mask = 0x1E000011; + vfe40_ctrl->start_ack_pending = TRUE; + CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n", + vfe40_ctrl->share_ctrl->operation_mode, + vfe40_ctrl->share_ctrl->outpath.output_mode); + + msm_camera_io_w(irq_mask, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND); + + msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase, + vfe40_ctrl->share_ctrl->register_total*4); + + atomic_set(&vfe40_ctrl->share_ctrl->vstate, 1); +} + +static int vfe40_start_recording( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO); + vfe40_ctrl->recording_state = VFE_STATE_START_REQUESTED; + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + return 0; +} + +static int vfe40_stop_recording( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED; + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW); + return 0; +} + +static void vfe40_start_liveshot( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + /* Hardcode 1 live snapshot for now. */ + vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = 1; + vfe40_ctrl->share_ctrl->vfe_capture_count = + vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt; + + vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED; + msm_camera_io_w_mb(1, vfe40_ctrl-> + share_ctrl->vfebase + VFE_REG_UPDATE_CMD); +} + +static int vfe40_zsl( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t irq_comp_mask = 0; + /* capture command is valid for both idle and active state. */ + irq_comp_mask = + msm_camera_io_r(vfe40_ctrl-> + share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + CDBG("%s:op mode %d O/P Mode %d\n", __func__, + vfe40_ctrl->share_ctrl->operation_mode, + vfe40_ctrl->share_ctrl->outpath.output_mode); + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + irq_comp_mask |= ( + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) | + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1))); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) { + irq_comp_mask |= ( + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)) | + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch1)) | + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch2))); + } + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + irq_comp_mask |= ((0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch0 + 8)) | + (0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch1 + 8))); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) { + irq_comp_mask |= ( + (0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch0 + 8)) | + (0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch1 + 8)) | + (0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch2 + 8))); + } + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch2]); + } + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch2]); + } + + msm_camera_io_w(irq_comp_mask, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + vfe40_start_common(vfe40_ctrl); + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL); + + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188); + return 0; +} +static int vfe40_capture_raw( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl, + uint32_t num_frames_capture) +{ + uint32_t irq_comp_mask = 0; + + vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture; + vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture; + + irq_comp_mask = + msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + irq_comp_mask |= + (0x1 << (vfe40_ctrl->share_ctrl->outpath.out0.ch0)); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + } + + msm_camera_io_w(irq_comp_mask, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE); + vfe40_start_common(vfe40_ctrl); + return 0; +} + +static int vfe40_capture( + struct msm_cam_media_controller *pmctl, + uint32_t num_frames_capture, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t irq_comp_mask = 0; + + /* capture command is valid for both idle and active state. */ + vfe40_ctrl->share_ctrl->outpath.out1.capture_cnt = num_frames_capture; + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG) { + vfe40_ctrl->share_ctrl->outpath.out0.capture_cnt = + num_frames_capture; + } + + vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture; + irq_comp_mask = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN) { + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + irq_comp_mask |= (0x1 << vfe40_ctrl-> + share_ctrl->outpath.out0.ch0 | + 0x1 << vfe40_ctrl-> + share_ctrl->outpath.out0.ch1); + } + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + irq_comp_mask |= + (0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch0 + 8) | + 0x1 << (vfe40_ctrl-> + share_ctrl->outpath.out1.ch1 + 8)); + } + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + } + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + } + } + + vfe40_ctrl->share_ctrl->vfe_capture_count = num_frames_capture; + + msm_camera_io_w(irq_comp_mask, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE); + + vfe40_start_common(vfe40_ctrl); + /* for debug */ + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x18C); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + 0x188); + return 0; +} + +static int vfe40_start( + struct msm_cam_media_controller *pmctl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t irq_comp_mask = 0; + irq_comp_mask = + msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + VFE_IRQ_COMP_MASK); + + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + irq_comp_mask |= ( + 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 | + 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) { + irq_comp_mask |= ( + 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch0 | + 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch1 | + 0x1 << vfe40_ctrl->share_ctrl->outpath.out0.ch2); + } + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + irq_comp_mask |= ( + 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) | + 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8)); + } else if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) { + irq_comp_mask |= ( + 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch0 + 8) | + 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch1 + 8) | + 0x1 << (vfe40_ctrl->share_ctrl->outpath.out1.ch2 + 8)); + } + msm_camera_io_w(irq_comp_mask, + vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK); + + /* + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);*/ + vfe40_start_common(vfe40_ctrl); + return 0; +} + +static void vfe40_update(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + uint32_t value = 0; + if (vfe40_ctrl->update_linear) { + if (!msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1)) + msm_camera_io_w(1, + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1); + else + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1); + vfe40_ctrl->update_linear = false; + } + + if (vfe40_ctrl->update_la) { + if (!msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF)) + msm_camera_io_w(1, + vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF); + else + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF); + vfe40_ctrl->update_la = false; + } + + if (vfe40_ctrl->update_gamma) { + value = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF); + value ^= V40_GAMMA_LUT_BANK_SEL_MASK; + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF); + vfe40_ctrl->update_gamma = false; + } + + spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags); + vfe40_ctrl->update_ack_pending = TRUE; + spin_unlock_irqrestore(&vfe40_ctrl->update_ack_lock, flags); + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + return; +} + +static void vfe40_sync_timer_stop(struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t value = 0; + vfe40_ctrl->sync_timer_state = 0; + if (vfe40_ctrl->sync_timer_number == 0) + value = 0x10000; + else if (vfe40_ctrl->sync_timer_number == 1) + value = 0x20000; + else if (vfe40_ctrl->sync_timer_number == 2) + value = 0x40000; + + /* Timer Stop */ + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF); +} + +static void vfe40_sync_timer_start( + const uint32_t *tbl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + /* set bit 8 for auto increment. */ + uint32_t value = 1; + uint32_t val; + + vfe40_ctrl->sync_timer_state = *tbl++; + vfe40_ctrl->sync_timer_repeat_count = *tbl++; + vfe40_ctrl->sync_timer_number = *tbl++; + CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n", + __func__, vfe40_ctrl->sync_timer_state, + vfe40_ctrl->sync_timer_repeat_count, + vfe40_ctrl->sync_timer_number); + + if (vfe40_ctrl->sync_timer_state) { /* Start Timer */ + value = value << vfe40_ctrl->sync_timer_number; + } else { /* Stop Timer */ + CDBG("Failed to Start timer\n"); + return; + } + + /* Timer Start */ + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF); + /* Sync Timer Line Start */ + value = *tbl++; + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF + + 4 + ((vfe40_ctrl->sync_timer_number) * 12)); + /* Sync Timer Pixel Start */ + value = *tbl++; + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF + + 8 + ((vfe40_ctrl->sync_timer_number) * 12)); + /* Sync Timer Pixel Duration */ + value = *tbl++; + val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000; + val = 10000000 / val; + val = value * 10000 / val; + CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val); + msm_camera_io_w(val, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_OFF + + 12 + ((vfe40_ctrl->sync_timer_number) * 12)); + /* Timer0 Active High/LOW */ + value = *tbl++; + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_SYNC_TIMER_POLARITY_OFF); + /* Selects sync timer 0 output to drive onto timer1 port */ + value = 0; + msm_camera_io_w(value, + vfe40_ctrl->share_ctrl->vfebase + V40_TIMER_SELECT_OFF); +} + +static void vfe40_program_dmi_cfg( + enum VFE40_DMI_RAM_SEL bankSel, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + /* set bit 8 for auto increment. */ + uint32_t value = VFE_DMI_CFG_DEFAULT; + value += (uint32_t)bankSel; + CDBG("%s: banksel = %d\n", __func__, bankSel); + + msm_camera_io_w(value, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_CFG); + /* by default, always starts with offset 0.*/ + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR); +} +static void vfe40_write_gamma_cfg( + enum VFE40_DMI_RAM_SEL channel_sel, + const uint32_t *tbl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + int i; + uint32_t value, value1, value2; + vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl); + for (i = 0 ; i < (VFE40_GAMMA_NUM_ENTRIES/2) ; i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000)>>16; + msm_camera_io_w((value1), + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_camera_io_w((value2), + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); +} + +static void vfe40_read_gamma_cfg( + enum VFE40_DMI_RAM_SEL channel_sel, + uint32_t *tbl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + int i; + vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl); + CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel); + for (i = 0 ; i < VFE40_GAMMA_NUM_ENTRIES ; i++) { + *tbl = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *tbl); + tbl++; + } + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); +} + +static void vfe40_write_la_cfg( + enum VFE40_DMI_RAM_SEL channel_sel, + const uint32_t *tbl, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t i; + uint32_t value, value1, value2; + + vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl); + for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH/2) ; i++) { + value = *tbl++; + value1 = value & 0x0000FFFF; + value2 = (value & 0xFFFF0000)>>16; + msm_camera_io_w((value1), + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + msm_camera_io_w((value2), + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + } + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); +} + +struct vfe40_output_ch *vfe40_get_ch( + int path, struct vfe_share_ctrl_t *share_ctrl) +{ + struct vfe40_output_ch *ch = NULL; + + if (path == VFE_MSG_OUTPUT_PRIMARY) + ch = &share_ctrl->outpath.out0; + else if (path == VFE_MSG_OUTPUT_SECONDARY) + ch = &share_ctrl->outpath.out1; + else + pr_err("%s: Invalid path %d\n", __func__, + path); + + BUG_ON(ch == NULL); + return ch; +} + +static int vfe40_configure_pingpong_buffers( + int id, int path, struct vfe40_ctrl_type *vfe40_ctrl) +{ + struct vfe40_output_ch *outch = NULL; + int rc = 0; + uint32_t image_mode = 0; + if (path == VFE_MSG_OUTPUT_PRIMARY) + image_mode = vfe40_ctrl->share_ctrl->outpath.out0.image_mode; + else + image_mode = vfe40_ctrl->share_ctrl->outpath.out1.image_mode; + + vfe40_subdev_notify(id, path, image_mode, + &vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl); + outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl); + if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) { + /* Configure Preview Ping Pong */ + CDBG("%s Configure ping/pong address for %d", + __func__, path); + vfe40_put_ch_ping_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch0, + outch->ping.ch_paddr[0]); + vfe40_put_ch_pong_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch0, + outch->pong.ch_paddr[0]); + + if (vfe40_ctrl->share_ctrl->operation_mode != + VFE_OUTPUTS_RAW) { + vfe40_put_ch_ping_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch1, + outch->ping.ch_paddr[1]); + vfe40_put_ch_pong_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch1, + outch->pong.ch_paddr[1]); + } + + if (outch->ping.num_planes > 2) + vfe40_put_ch_ping_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch2, + outch->ping.ch_paddr[2]); + if (outch->pong.num_planes > 2) + vfe40_put_ch_pong_addr( + vfe40_ctrl->share_ctrl->vfebase, outch->ch2, + outch->pong.ch_paddr[2]); + + /* avoid stale info */ + memset(&outch->ping, 0, sizeof(struct msm_free_buf)); + memset(&outch->pong, 0, sizeof(struct msm_free_buf)); + } else { + pr_err("%s ping/pong addr is null!!", __func__); + rc = -EINVAL; + } + return rc; +} + +static void vfe40_write_linear_cfg( + enum VFE40_DMI_RAM_SEL channel_sel, + const uint32_t *tbl, struct vfe40_ctrl_type *vfe40_ctrl) +{ + uint32_t i; + + vfe40_program_dmi_cfg(channel_sel, vfe40_ctrl); + /* for loop for configuring LUT. */ + for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) { + msm_camera_io_w(*tbl, + vfe40_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO); + tbl++; + } + CDBG("done writing to linearization table\n"); + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); +} + +void vfe40_send_isp_msg( + struct v4l2_subdev *sd, + uint32_t vfeFrameId, + uint32_t isp_msg_id) +{ + struct isp_msg_event isp_msg_evt; + + isp_msg_evt.msg_id = isp_msg_id; + isp_msg_evt.sof_count = vfeFrameId; + v4l2_subdev_notify(sd, + NOTIFY_ISP_MSG_EVT, + (void *)&isp_msg_evt); +} + +static int vfe40_proc_general( + struct msm_cam_media_controller *pmctl, + struct msm_isp_cmd *cmd, + struct vfe40_ctrl_type *vfe40_ctrl) +{ + int i , rc = 0; + uint32_t old_val = 0 , new_val = 0; + uint32_t *cmdp = NULL; + uint32_t *cmdp_local = NULL; + uint32_t snapshot_cnt = 0; + uint32_t temp1 = 0, temp2 = 0; + + CDBG("vfe40_proc_general: cmdID = %s, length = %d\n", + vfe40_general_cmd[cmd->id], cmd->length); + switch (cmd->id) { + case VFE_CMD_RESET: + CDBG("vfe40_proc_general: cmdID = %s\n", + vfe40_general_cmd[cmd->id]); + vfe40_reset(vfe40_ctrl); + break; + case VFE_CMD_START: + CDBG("vfe40_proc_general: cmdID = %s\n", + vfe40_general_cmd[cmd->id]); + if ((vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_PREVIEW_AND_VIDEO) || + (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_PREVIEW)) + /* Configure primary channel */ + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_START, VFE_MSG_OUTPUT_PRIMARY, + vfe40_ctrl); + else + /* Configure secondary channel */ + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_START, VFE_MSG_OUTPUT_SECONDARY, + vfe40_ctrl); + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for preview", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + + rc = vfe40_start(pmctl, vfe40_ctrl); + break; + case VFE_CMD_UPDATE: + vfe40_update(vfe40_ctrl); + break; + case VFE_CMD_CAPTURE_RAW: + CDBG("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__); + if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value), + sizeof(uint32_t))) { + rc = -EFAULT; + goto proc_general_done; + } + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_PRIMARY, + vfe40_ctrl); + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for snapshot", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe40_capture_raw(pmctl, vfe40_ctrl, snapshot_cnt); + break; + case VFE_CMD_CAPTURE: + if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value), + sizeof(uint32_t))) { + rc = -EFAULT; + goto proc_general_done; + } + + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG) { + if (snapshot_cnt != 1) { + pr_err("only support 1 inline snapshot\n"); + rc = -EINVAL; + goto proc_general_done; + } + /* Configure primary channel for JPEG */ + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_JPEG_CAPTURE, + VFE_MSG_OUTPUT_PRIMARY, + vfe40_ctrl); + } else { + /* Configure primary channel */ + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_CAPTURE, + VFE_MSG_OUTPUT_PRIMARY, + vfe40_ctrl); + } + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for primary output", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + /* Configure secondary channel */ + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_CAPTURE, VFE_MSG_OUTPUT_SECONDARY, + vfe40_ctrl); + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for secondary output", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl); + break; + case VFE_CMD_START_RECORDING: + CDBG("vfe40_proc_general: cmdID = %s\n", + vfe40_general_cmd[cmd->id]); + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_PREVIEW_AND_VIDEO) + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_START_RECORDING, + VFE_MSG_OUTPUT_SECONDARY, + vfe40_ctrl); + else if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_VIDEO_AND_PREVIEW) + rc = vfe40_configure_pingpong_buffers( + VFE_MSG_START_RECORDING, + VFE_MSG_OUTPUT_PRIMARY, + vfe40_ctrl); + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for video\n", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + rc = vfe40_start_recording(pmctl, vfe40_ctrl); + break; + case VFE_CMD_STOP_RECORDING: + CDBG("vfe40_proc_general: cmdID = %s\n", + vfe40_general_cmd[cmd->id]); + rc = vfe40_stop_recording(pmctl, vfe40_ctrl); + break; + case VFE_CMD_OPERATION_CFG: { + if (cmd->length != V40_OPERATION_CFG_LEN) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(V40_OPERATION_CFG_LEN, GFP_ATOMIC); + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + V40_OPERATION_CFG_LEN)) { + rc = -EFAULT; + goto proc_general_done; + } + rc = vfe40_operation_config(cmdp, vfe40_ctrl); + } + break; + + case VFE_CMD_STATS_AE_START: { + rc = vfe_stats_aec_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= BG_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + case VFE_CMD_STATS_AF_START: { + rc = vfe_stats_af_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + VFE_MODULE_CFG); + old_val |= BF_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_AWB_START: { + rc = vfe_stats_awb_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= AWB_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_IHIST_START: { + rc = vfe_stats_ihist_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val |= IHIST_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + + case VFE_CMD_STATS_RS_START: { + rc = vfe_stats_rs_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_STATS_CS_START: { + rc = vfe_stats_cs_buf_init(vfe40_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; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_MCE_UPDATE: + case VFE_CMD_MCE_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + /* Incrementing with 4 so as to point to the 2nd Register as + the 2nd register has the mce_enable bit */ + old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 4); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + old_val &= MCE_EN_MASK; + new_val = new_val | old_val; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 4, &new_val, 4); + cmdp_local += 1; + + old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 8); + new_val = *cmdp_local; + old_val &= MCE_Q_K_MASK; + new_val = new_val | old_val; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 8, &new_val, 4); + cmdp_local += 1; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp_local, (vfe40_cmd[cmd->id].length)); + } + break; + case VFE_CMD_CHROMA_SUP_UPDATE: + case VFE_CMD_CHROMA_SUP_CFG:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF, cmdp_local, 4); + + cmdp_local += 1; + new_val = *cmdp_local; + /* Incrementing with 4 so as to point to the 2nd Register as + * the 2nd register has the mce_enable bit + */ + old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 4); + old_val &= ~MCE_EN_MASK; + new_val = new_val | old_val; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 4, &new_val, 4); + cmdp_local += 1; + + old_val = msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 8); + new_val = *cmdp_local; + old_val &= ~MCE_Q_K_MASK; + new_val = new_val | old_val; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_CHROMA_SUP_OFF + 8, &new_val, 4); + } + break; + case VFE_CMD_BLACK_LEVEL_CFG: + rc = -EFAULT; + goto proc_general_done; + + case VFE_CMD_LA_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp_local, (vfe40_cmd[cmd->id].length)); + + cmdp_local += 1; + vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, + cmdp_local, vfe40_ctrl); + break; + + case VFE_CMD_LA_UPDATE: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + + rc = -EFAULT; + goto proc_general_done; + } + + cmdp_local = cmdp + 1; + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_LA_OFF); + if (old_val != 0x0) + vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, + cmdp_local, vfe40_ctrl); + else + vfe40_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1, + cmdp_local, vfe40_ctrl); + } + vfe40_ctrl->update_la = true; + break; + + case VFE_CMD_GET_LA_TABLE: + temp1 = sizeof(uint32_t) * VFE40_LA_TABLE_LENGTH / 2; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + if (msm_camera_io_r(vfe40_ctrl-> + share_ctrl->vfebase + V40_LA_OFF)) + vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1, + vfe40_ctrl); + else + vfe40_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0, + vfe40_ctrl); + for (i = 0 ; i < (VFE40_LA_TABLE_LENGTH / 2) ; i++) { + *cmdp_local = + msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + VFE_DMI_DATA_LO); + *cmdp_local |= (msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + VFE_DMI_DATA_LO)) << 16; + cmdp_local++; + } + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); + if (copy_to_user((void __user *)(cmd->value), cmdp, + temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_SK_ENHAN_CFG: + case VFE_CMD_SK_ENHAN_UPDATE:{ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_SCE_OFF, + cmdp, V40_SCE_LEN); + } + break; + + case VFE_CMD_LIVESHOT: + /* Configure primary channel */ + rc = vfe40_configure_pingpong_buffers(VFE_MSG_CAPTURE, + VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl); + if (rc < 0) { + pr_err( + "%s error configuring pingpong buffers for primary output\n", + __func__); + rc = -EINVAL; + goto proc_general_done; + } + vfe40_start_liveshot(pmctl, vfe40_ctrl); + break; + + case VFE_CMD_LINEARIZATION_CFG: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1, + cmdp_local, V40_LINEARIZATION_LEN1); + + cmdp_local = cmdp + 17; + vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0, + cmdp_local, vfe40_ctrl); + break; + + case VFE_CMD_LINEARIZATION_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + cmdp_local++; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1 + 4, + cmdp_local, (V40_LINEARIZATION_LEN1 - 4)); + cmdp_local = cmdp + 17; + /*extracting the bank select*/ + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1); + + if (old_val != 0x0) + vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK0, + cmdp_local, vfe40_ctrl); + else + vfe40_write_linear_cfg(BLACK_LUT_RAM_BANK1, + cmdp_local, vfe40_ctrl); + vfe40_ctrl->update_linear = true; + break; + + case VFE_CMD_GET_LINEARIZATON_TABLE: + temp1 = sizeof(uint32_t) * VFE40_LINEARIZATON_TABLE_LENGTH; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + if (msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + V40_LINEARIZATION_OFF1)) + vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK1, vfe40_ctrl); + else + vfe40_program_dmi_cfg(BLACK_LUT_RAM_BANK0, vfe40_ctrl); + CDBG("%s: Linearization Table\n", __func__); + for (i = 0 ; i < VFE40_LINEARIZATON_TABLE_LENGTH ; i++) { + *cmdp_local = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + + VFE_DMI_DATA_LO); + CDBG("%s: %08x\n", __func__, *cmdp_local); + cmdp_local++; + } + vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl); + if (copy_to_user((void __user *)(cmd->value), cmdp, + temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_DEMOSAICV3: + if (cmd->length != + V40_DEMOSAICV3_0_LEN+V40_DEMOSAICV3_1_LEN) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF); + old_val &= DEMOSAIC_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF, + cmdp_local, V40_DEMOSAICV3_0_LEN); + cmdp_local += 1; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF, + cmdp_local, V40_DEMOSAICV3_1_LEN); + break; + + case VFE_CMD_DEMOSAICV3_UPDATE: + if (cmd->length != + V40_DEMOSAICV3_0_LEN * V40_DEMOSAICV3_UP_REG_CNT) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF); + old_val &= DEMOSAIC_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF, + cmdp_local, V40_DEMOSAICV3_0_LEN); + /* As the address space is not contiguous increment by 2 + * before copying to next address space */ + cmdp_local += 1; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_1_OFF, + cmdp_local, 2 * V40_DEMOSAICV3_0_LEN); + /* As the address space is not contiguous increment by 2 + * before copying to next address space */ + cmdp_local += 2; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_2_OFF, + cmdp_local, 2 * V40_DEMOSAICV3_0_LEN); + break; + + case VFE_CMD_DEMOSAICV3_ABCC_CFG: + rc = -EFAULT; + break; + + case VFE_CMD_DEMOSAICV3_ABF_UPDATE:/* 116 ABF update */ + case VFE_CMD_DEMOSAICV3_ABF_CFG: { /* 108 ABF config */ + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF); + old_val &= ABF_MASK; + new_val = new_val | old_val; + *cmdp_local = new_val; + + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF, + cmdp_local, 4); + + cmdp_local += 1; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp_local, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_DEMOSAICV3_DBCC_CFG: + case VFE_CMD_DEMOSAICV3_DBCC_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF); + old_val &= DBCC_MASK; + + new_val = new_val | old_val; + *cmdp_local = new_val; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF, + cmdp_local, 4); + cmdp_local += 1; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp_local, (vfe40_cmd[cmd->id].length)); + break; + + case VFE_CMD_DEMOSAICV3_DBPC_CFG: + case VFE_CMD_DEMOSAICV3_DBPC_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + cmdp_local = cmdp; + new_val = *cmdp_local; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_DEMOSAICV3_0_OFF); + old_val &= DBPC_MASK; + + new_val = new_val | old_val; + *cmdp_local = new_val; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_DEMOSAICV3_0_OFF, + cmdp_local, V40_DEMOSAICV3_0_LEN); + cmdp_local += 1; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_DEMOSAICV3_DBPC_CFG_OFF, + cmdp_local, V40_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_DEMOSAICV3_DBPC_CFG_OFF0, + cmdp_local, V40_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_DEMOSAICV3_DBPC_CFG_OFF1, + cmdp_local, V40_DEMOSAICV3_DBPC_LEN); + cmdp_local += 1; + msm_camera_io_memcpy(vfe40_ctrl->share_ctrl->vfebase + + V40_DEMOSAICV3_DBPC_CFG_OFF2, + cmdp_local, V40_DEMOSAICV3_DBPC_LEN); + break; + + case VFE_CMD_RGB_G_CFG: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF, + cmdp, 4); + cmdp += 1; + + vfe40_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl); + } + cmdp -= 1; + break; + + case VFE_CMD_RGB_G_UPDATE: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF); + cmdp += 1; + if (old_val != 0x0) { + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH0_BANK0, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH1_BANK0, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH2_BANK0, cmdp, vfe40_ctrl); + } else { + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH0_BANK1, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH1_BANK1, cmdp, vfe40_ctrl); + vfe40_write_gamma_cfg( + RGBLUT_RAM_CH2_BANK1, cmdp, vfe40_ctrl); + } + } + vfe40_ctrl->update_gamma = TRUE; + cmdp -= 1; + break; + + case VFE_CMD_GET_RGB_G_TABLE: + temp1 = sizeof(uint32_t) * VFE40_GAMMA_NUM_ENTRIES * 3; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kzalloc(temp1, GFP_KERNEL); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + cmdp_local = cmdp; + + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + V40_RGB_G_OFF); + temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 : + RGBLUT_RAM_CH0_BANK0; + for (i = 0; i < 3; i++) { + vfe40_read_gamma_cfg(temp2, + cmdp_local + (VFE40_GAMMA_NUM_ENTRIES * i), + vfe40_ctrl); + temp2 += 2; + } + if (copy_to_user((void __user *)(cmd->value), cmdp, + temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + + case VFE_CMD_STATS_AWB_STOP: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~AWB_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_AE_STOP: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~BG_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case VFE_CMD_STATS_AF_STOP: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~BF_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + rc = vfe40_stats_flush_enqueue(vfe40_ctrl, 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: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~IHIST_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_RS_STOP: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~RS_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + + case VFE_CMD_STATS_CS_STOP: { + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= ~CS_ENABLE_MASK; + msm_camera_io_w(old_val, + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + } + break; + case VFE_CMD_STOP: + CDBG("vfe40_proc_general: cmdID = %s\n", + vfe40_general_cmd[cmd->id]); + vfe40_stop(vfe40_ctrl); + break; + + case VFE_CMD_SYNC_TIMER_SETTING: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + vfe40_sync_timer_start(cmdp, vfe40_ctrl); + break; + + case VFE_CMD_MODULE_CFG: { + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, + (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + *cmdp &= ~STATS_ENABLE_MASK; + old_val = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG); + old_val &= STATS_ENABLE_MASK; + *cmdp |= old_val; + + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + } + break; + + case VFE_CMD_ZSL: + rc = vfe40_configure_pingpong_buffers(VFE_MSG_START, + VFE_MSG_OUTPUT_PRIMARY, vfe40_ctrl); + if (rc < 0) + goto proc_general_done; + rc = vfe40_configure_pingpong_buffers(VFE_MSG_START, + VFE_MSG_OUTPUT_SECONDARY, vfe40_ctrl); + if (rc < 0) + goto proc_general_done; + + rc = vfe40_zsl(pmctl, vfe40_ctrl); + break; + + case VFE_CMD_ASF_CFG: + case VFE_CMD_ASF_UPDATE: + cmdp = kmalloc(cmd->length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + if (copy_from_user(cmdp, (void __user *)(cmd->value), + cmd->length)) { + rc = -EFAULT; + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + cmdp_local = cmdp + V40_ASF_LEN/4; + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + V40_ASF_SPECIAL_EFX_CFG_OFF, + cmdp_local, V40_ASF_SPECIAL_EFX_CFG_LEN); + break; + + case VFE_CMD_GET_HW_VERSION: + if (cmd->length != V40_GET_HW_VERSION_LEN) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(V40_GET_HW_VERSION_LEN, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + *cmdp = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase+V40_GET_HW_VERSION_OFF); + if (copy_to_user((void __user *)(cmd->value), cmdp, + V40_GET_HW_VERSION_LEN)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_GET_REG_DUMP: + temp1 = sizeof(uint32_t) * + vfe40_ctrl->share_ctrl->register_total; + if (cmd->length != temp1) { + rc = -EINVAL; + goto proc_general_done; + } + cmdp = kmalloc(temp1, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase, + vfe40_ctrl->share_ctrl->register_total*4); + CDBG("%s: %p %p %d\n", __func__, (void *)cmdp, + vfe40_ctrl->share_ctrl->vfebase, temp1); + memcpy_fromio((void *)cmdp, + vfe40_ctrl->share_ctrl->vfebase, temp1); + if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) { + rc = -EFAULT; + goto proc_general_done; + } + break; + case VFE_CMD_FRAME_SKIP_CFG: + if (cmd->length != vfe40_cmd[cmd->id].length) + return -EINVAL; + + cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + + if (copy_from_user((cmdp), (void __user *)cmd->value, + cmd->length)) { + rc = -EFAULT; + pr_err("%s copy from user failed for cmd %d", + __func__, cmd->id); + break; + } + + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + vfe40_ctrl->frame_skip_cnt = ((uint32_t) + *cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1; + vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2)); + break; + default: + if (cmd->length != vfe40_cmd[cmd->id].length) + return -EINVAL; + + cmdp = kmalloc(vfe40_cmd[cmd->id].length, GFP_ATOMIC); + if (!cmdp) { + rc = -ENOMEM; + goto proc_general_done; + } + + if (copy_from_user((cmdp), (void __user *)cmd->value, + cmd->length)) { + rc = -EFAULT; + pr_err("%s copy from user failed for cmd %d", + __func__, cmd->id); + goto proc_general_done; + } + msm_camera_io_memcpy( + vfe40_ctrl->share_ctrl->vfebase + + vfe40_cmd[cmd->id].offset, + cmdp, (vfe40_cmd[cmd->id].length)); + break; + + } + +proc_general_done: + kfree(cmdp); + + return rc; +} + +static inline void vfe40_read_irq_status( + struct axi_ctrl_t *axi_ctrl, struct vfe40_irq_status *out) +{ + uint32_t *temp; + memset(out, 0, sizeof(struct vfe40_irq_status)); + temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_0); + out->vfeIrqStatus0 = msm_camera_io_r(temp); + + temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_1); + out->vfeIrqStatus1 = msm_camera_io_r(temp); + + temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS); + out->camifStatus = msm_camera_io_r(temp); + CDBG("camifStatus = 0x%x\n", out->camifStatus); + + /* clear the pending interrupt of the same kind.*/ + msm_camera_io_w(out->vfeIrqStatus0, + axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0); + msm_camera_io_w(out->vfeIrqStatus1, + axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD); + +} + +static void vfe40_process_reg_update_irq( + struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + + if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) { + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_VIDEO_AND_PREVIEW) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + } else if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_PREVIEW_AND_VIDEO) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + } + vfe40_ctrl->recording_state = VFE_STATE_STARTED; + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + CDBG("start video triggered .\n"); + } else if (vfe40_ctrl->recording_state == + VFE_STATE_STOP_REQUESTED) { + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_VIDEO_AND_PREVIEW) { + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + } else if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_PREVIEW_AND_VIDEO) { + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + } + CDBG("stop video triggered .\n"); + } + + if (vfe40_ctrl->start_ack_pending == TRUE) { + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK); + vfe40_ctrl->start_ack_pending = FALSE; + } else { + if (vfe40_ctrl->recording_state == + VFE_STATE_STOP_REQUESTED) { + vfe40_ctrl->recording_state = VFE_STATE_STOPPED; + /* request a reg update and send STOP_REC_ACK + * when we process the next reg update irq. + */ + msm_camera_io_w_mb(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + } else if (vfe40_ctrl->recording_state == + VFE_STATE_STOPPED) { + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_STOP_REC_ACK); + vfe40_ctrl->recording_state = VFE_STATE_IDLE; + } + spin_lock_irqsave(&vfe40_ctrl->update_ack_lock, flags); + if (vfe40_ctrl->update_ack_pending == TRUE) { + vfe40_ctrl->update_ack_pending = FALSE; + spin_unlock_irqrestore( + &vfe40_ctrl->update_ack_lock, flags); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_UPDATE_ACK); + } else { + spin_unlock_irqrestore( + &vfe40_ctrl->update_ack_lock, flags); + } + } + + if (vfe40_ctrl->share_ctrl->liveshot_state == + VFE_STATE_START_REQUESTED) { + CDBG("%s enabling liveshot output\n", __func__); + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + vfe40_ctrl->share_ctrl->liveshot_state = + VFE_STATE_STARTED; + } + } + + if (vfe40_ctrl->share_ctrl->liveshot_state == VFE_STATE_STARTED) { + vfe40_ctrl->share_ctrl->vfe_capture_count--; + if (!vfe40_ctrl->share_ctrl->vfe_capture_count) + vfe40_ctrl->share_ctrl->liveshot_state = + VFE_STATE_STOP_REQUESTED; + msm_camera_io_w_mb(1, vfe40_ctrl-> + share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + } else if (vfe40_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STOP_REQUESTED) { + CDBG("%s: disabling liveshot output\n", __func__); + if (vfe40_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + vfe40_ctrl->share_ctrl->liveshot_state = + VFE_STATE_STOPPED; + msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase + + VFE_REG_UPDATE_CMD); + } + } else if (vfe40_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STOPPED) { + vfe40_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE; + } + + if ((vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN) || + (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB) || + (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG) || + (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB)) { + /* in snapshot mode */ + /* later we need to add check for live snapshot mode. */ + if (vfe40_ctrl->frame_skip_pattern & (0x1 << + (vfe40_ctrl->snapshot_frame_cnt % + vfe40_ctrl->frame_skip_cnt))) { + vfe40_ctrl->share_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) { + /* stop the bus output:write master enable = 0*/ + if (vfe40_ctrl->share_ctrl->outpath.output_mode + & VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase+ + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase+ + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out0.ch1]); + } + if (vfe40_ctrl->share_ctrl->outpath.output_mode& + VFE40_OUTPUT_MODE_SECONDARY) { + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase+ + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase+ + vfe40_AXI_WM_CFG[vfe40_ctrl-> + share_ctrl->outpath.out1.ch1]); + } + msm_camera_io_w_mb + (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe40_ctrl->share_ctrl->vfebase + + VFE_CAMIF_COMMAND); + vfe40_ctrl->snapshot_frame_cnt = -1; + vfe40_ctrl->frame_skip_cnt = 31; + vfe40_ctrl->frame_skip_pattern = 0xffffffff; + } /*if snapshot count is 0*/ + } /*if frame is not being dropped*/ + vfe40_ctrl->snapshot_frame_cnt++; + /* then do reg_update. */ + msm_camera_io_w(1, + vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD); + } /* if snapshot mode. */ +} + +static void vfe40_set_default_reg_values( + struct vfe40_ctrl_type *vfe40_ctrl) +{ + msm_camera_io_w(0x800080, + vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0); + msm_camera_io_w(0x800080, + vfe40_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1); + /* What value should we program CGC_OVERRIDE to? */ + msm_camera_io_w(0xFFFFF, + vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE); + + /* default frame drop period and pattern */ + msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MIN); + msm_camera_io_w(0xFFFFFF, + vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_ENC_MAX); + msm_camera_io_w(0, + vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MIN); + msm_camera_io_w(0xFFFFFF, + vfe40_ctrl->share_ctrl->vfebase + VFE_CLAMP_VIEW_MAX); + + /* stats UB config */ + msm_camera_io_w(0x3980007, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG); + msm_camera_io_w(0x3A00007, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG); + msm_camera_io_w(0x3A8000F, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG); + msm_camera_io_w(0x3B80007, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG); + msm_camera_io_w(0x3C0001F, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG); + msm_camera_io_w(0x3E0001F, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG); +} + +static void vfe40_process_reset_irq( + struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + + atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0); + + spin_lock_irqsave(&vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + if (vfe40_ctrl->share_ctrl->stop_ack_pending) { + vfe40_ctrl->share_ctrl->stop_ack_pending = FALSE; + spin_unlock_irqrestore( + &vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK); + } else { + spin_unlock_irqrestore( + &vfe40_ctrl->share_ctrl->stop_flag_lock, flags); + /* this is from reset command. */ + vfe40_set_default_reg_values(vfe40_ctrl); + + /* reload all write masters. (frame & line)*/ + msm_camera_io_w(0x7FFF, + vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK); + } +} + +static void vfe40_process_camif_sof_irq( + struct vfe40_ctrl_type *vfe40_ctrl) +{ + if (vfe40_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW) { + if (vfe40_ctrl->start_ack_pending) { + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_START_ACK); + vfe40_ctrl->start_ack_pending = FALSE; + } + vfe40_ctrl->share_ctrl->vfe_capture_count--; + /* if last frame to be captured: */ + if (vfe40_ctrl->share_ctrl->vfe_capture_count == 0) { + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY, + vfe40_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND); + } + } /* if raw snapshot mode. */ + if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) && + (vfe40_ctrl->share_ctrl->operation_mode == + VFE_MODE_OF_OPERATION_VIDEO) && + (vfe40_ctrl->share_ctrl->vfeFrameId % + vfe40_ctrl->hfr_mode != 0)) { + vfe40_ctrl->share_ctrl->vfeFrameId++; + CDBG("Skip the SOF notification when HFR enabled\n"); + return; + } + vfe40_ctrl->share_ctrl->vfeFrameId++; + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK); + CDBG("camif_sof_irq, frameId = %d\n", + vfe40_ctrl->share_ctrl->vfeFrameId); + + if (vfe40_ctrl->sync_timer_state) { + if (vfe40_ctrl->sync_timer_repeat_count == 0) + vfe40_sync_timer_stop(vfe40_ctrl); + else + vfe40_ctrl->sync_timer_repeat_count--; + } +} + +static void vfe40_process_error_irq( + struct axi_ctrl_t *axi_ctrl, uint32_t errStatus) +{ + uint32_t reg_value; + + if (errStatus & VFE40_IMASK_CAMIF_ERROR) { + pr_err("vfe40_irq: camif errors\n"); + reg_value = msm_camera_io_r( + axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS); + pr_err("camifStatus = 0x%x\n", reg_value); + vfe40_send_isp_msg(&axi_ctrl->subdev, + axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR); + } + + if (errStatus & VFE40_IMASK_BHIST_OVWR) + pr_err("vfe40_irq: stats bhist overwrite\n"); + + if (errStatus & VFE40_IMASK_STATS_CS_OVWR) + pr_err("vfe40_irq: stats cs overwrite\n"); + + if (errStatus & VFE40_IMASK_STATS_IHIST_OVWR) + pr_err("vfe40_irq: stats ihist overwrite\n"); + + if (errStatus & VFE40_IMASK_REALIGN_BUF_Y_OVFL) + pr_err("vfe40_irq: realign bug Y overflow\n"); + + if (errStatus & VFE40_IMASK_REALIGN_BUF_CB_OVFL) + pr_err("vfe40_irq: realign bug CB overflow\n"); + + if (errStatus & VFE40_IMASK_REALIGN_BUF_CR_OVFL) + pr_err("vfe40_irq: realign bug CR overflow\n"); + + if (errStatus & VFE40_IMASK_VIOLATION) { + pr_err("vfe40_irq: violation interrupt\n"); + reg_value = msm_camera_io_r( + axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS); + pr_err("%s: violationStatus = 0x%x\n", __func__, reg_value); + } + + if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL) + pr_err("vfe40_irq: image master 0 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_1_BUS_OVFL) + pr_err("vfe40_irq: image master 1 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_2_BUS_OVFL) + pr_err("vfe40_irq: image master 2 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_3_BUS_OVFL) + pr_err("vfe40_irq: image master 3 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_4_BUS_OVFL) + pr_err("vfe40_irq: image master 4 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_5_BUS_OVFL) + pr_err("vfe40_irq: image master 5 bus overflow\n"); + + if (errStatus & VFE40_IMASK_IMG_MAST_6_BUS_OVFL) + pr_err("vfe40_irq: image master 6 bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_AE_BG_BUS_OVFL) + pr_err("vfe40_irq: ae/bg stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_AF_BF_BUS_OVFL) + pr_err("vfe40_irq: af/bf stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL) + pr_err("vfe40_irq: awb stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL) + pr_err("vfe40_irq: rs stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL) + pr_err("vfe40_irq: cs stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL) + pr_err("vfe40_irq: ihist stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL) + pr_err("vfe40_irq: skin/bhist stats bus overflow\n"); + + if (errStatus & VFE40_IMASK_AXI_ERROR) + pr_err("vfe40_irq: axi error\n"); +} + +static uint32_t vfe40_process_stats_irq_common( + struct vfe40_ctrl_type *vfe40_ctrl, + uint32_t statsNum, uint32_t newAddr) +{ + uint32_t pingpongStatus; + uint32_t returnAddr; + uint32_t pingpongAddr; + + /* must be 0=ping, 1=pong */ + pingpongStatus = + ((msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS)) + & ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7); + /* stats bits starts at 7 */ + CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus); + pingpongAddr = + ((uint32_t)(vfe40_ctrl->share_ctrl->vfebase + + VFE_BUS_STATS_PING_PONG_BASE)) + + (3*statsNum)*4 + (1-pingpongStatus)*4; + returnAddr = msm_camera_io_r((uint32_t *)pingpongAddr); + msm_camera_io_w(newAddr, (uint32_t *)pingpongAddr); + return returnAddr; +} + +static void +vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl, + uint32_t bufAddress, uint32_t statsNum) +{ + 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 = vfe40_ctrl->share_ctrl->vfeFrameId; + msgStats.buffer = bufAddress; + + switch (statsNum) { + case statsAeNum:{ + msgStats.id = MSG_ID_STATS_AEC; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_AEC, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + case statsAfNum:{ + msgStats.id = MSG_ID_STATS_AF; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_AF, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + case statsAwbNum: { + msgStats.id = MSG_ID_STATS_AWB; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_AWB, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + + case statsIhistNum: { + msgStats.id = MSG_ID_STATS_IHIST; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_IHIST, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + case statsRsNum: { + msgStats.id = MSG_ID_STATS_RS; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_RS, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + case statsCsNum: { + msgStats.id = MSG_ID_STATS_CS; + rc = vfe40_ctrl->stats_ops.dispatch( + vfe40_ctrl->stats_ops.stats_ctrl, + MSM_STATS_TYPE_CS, bufAddress, + &msgStats.buf_idx, &vaddr, &msgStats.fd, + vfe40_ctrl->stats_ops.client); + } + break; + + default: + goto stats_done; + } + if (rc == 0) { + msgStats.buffer = (uint32_t)vaddr; + v4l2_subdev_notify(&vfe40_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; +} + +static void vfe_send_comp_stats_msg( + struct vfe40_ctrl_type *vfe40_ctrl, uint32_t status_bits) +{ + struct msm_stats_buf msgStats; + uint32_t temp; + + msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId; + msgStats.status_bits = status_bits; + + msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender; + msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender; + msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender; + + msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender; + msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender; + msgStats.cs.buff = vfe40_ctrl->csStatsControl.bufToRender; + + temp = msm_camera_io_r( + vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG); + msgStats.awb_ymin = (0xFF00 & temp) >> 8; + + v4l2_subdev_notify(&vfe40_ctrl->subdev, + NOTIFY_VFE_MSG_COMP_STATS, + &msgStats); +} + +static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + uint32_t addr; + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB); + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + if (addr) { + vfe40_ctrl->awbStatsControl.bufToRender = + vfe40_process_stats_irq_common(vfe40_ctrl, statsAwbNum, + addr); + + vfe_send_stats_msg(vfe40_ctrl, + vfe40_ctrl->awbStatsControl.bufToRender, statsAwbNum); + } else{ + vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++; + CDBG("%s: droppedStatsFrameCount = %d", __func__, + vfe40_ctrl->awbStatsControl.droppedStatsFrameCount); + } +} + +static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + uint32_t addr; + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_IHIST); + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + if (addr) { + vfe40_ctrl->ihistStatsControl.bufToRender = + vfe40_process_stats_irq_common( + vfe40_ctrl, statsIhistNum, addr); + + vfe_send_stats_msg(vfe40_ctrl, + vfe40_ctrl->ihistStatsControl.bufToRender, + statsIhistNum); + } else { + vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++; + CDBG("%s: droppedStatsFrameCount = %d", __func__, + vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount); + } +} + +static void vfe40_process_stats_rs_irq(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + uint32_t addr; + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_RS); + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + if (addr) { + vfe40_ctrl->rsStatsControl.bufToRender = + vfe40_process_stats_irq_common(vfe40_ctrl, statsRsNum, + addr); + + vfe_send_stats_msg(vfe40_ctrl, + vfe40_ctrl->rsStatsControl.bufToRender, statsRsNum); + } else { + vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++; + CDBG("%s: droppedStatsFrameCount = %d", __func__, + vfe40_ctrl->rsStatsControl.droppedStatsFrameCount); + } +} + +static void vfe40_process_stats_cs_irq(struct vfe40_ctrl_type *vfe40_ctrl) +{ + unsigned long flags; + uint32_t addr; + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_CS); + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + if (addr) { + vfe40_ctrl->csStatsControl.bufToRender = + vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum, + addr); + + vfe_send_stats_msg(vfe40_ctrl, + vfe40_ctrl->csStatsControl.bufToRender, statsCsNum); + } else { + vfe40_ctrl->csStatsControl.droppedStatsFrameCount++; + CDBG("%s: droppedStatsFrameCount = %d", __func__, + vfe40_ctrl->csStatsControl.droppedStatsFrameCount); + } +} + +static void vfe40_process_stats(struct vfe40_ctrl_type *vfe40_ctrl, + uint32_t status_bits) +{ + unsigned long flags; + int32_t process_stats = false; + uint32_t addr; + + CDBG("%s, stats = 0x%x\n", __func__, status_bits); + spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags); + if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) { + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, + MSM_STATS_TYPE_AWB); + if (addr) { + vfe40_ctrl->awbStatsControl.bufToRender = + vfe40_process_stats_irq_common( + vfe40_ctrl, statsAwbNum, + addr); + process_stats = true; + } else{ + vfe40_ctrl->awbStatsControl.droppedStatsFrameCount++; + vfe40_ctrl->awbStatsControl.bufToRender = 0; + } + } else { + vfe40_ctrl->awbStatsControl.bufToRender = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) { + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, + MSM_STATS_TYPE_IHIST); + if (addr) { + vfe40_ctrl->ihistStatsControl.bufToRender = + vfe40_process_stats_irq_common( + vfe40_ctrl, statsIhistNum, + addr); + process_stats = true; + } else { + vfe40_ctrl->ihistStatsControl.droppedStatsFrameCount++; + vfe40_ctrl->ihistStatsControl.bufToRender = 0; + } + } else { + vfe40_ctrl->ihistStatsControl.bufToRender = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_RS) { + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, + MSM_STATS_TYPE_RS); + if (addr) { + vfe40_ctrl->rsStatsControl.bufToRender = + vfe40_process_stats_irq_common( + vfe40_ctrl, statsRsNum, + addr); + process_stats = true; + } else { + vfe40_ctrl->rsStatsControl.droppedStatsFrameCount++; + vfe40_ctrl->rsStatsControl.bufToRender = 0; + } + } else { + vfe40_ctrl->rsStatsControl.bufToRender = 0; + } + + if (status_bits & VFE_IRQ_STATUS0_STATS_CS) { + addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, + MSM_STATS_TYPE_CS); + if (addr) { + vfe40_ctrl->csStatsControl.bufToRender = + vfe40_process_stats_irq_common( + vfe40_ctrl, statsCsNum, + addr); + process_stats = true; + } else { + vfe40_ctrl->csStatsControl.droppedStatsFrameCount++; + vfe40_ctrl->csStatsControl.bufToRender = 0; + } + } else { + vfe40_ctrl->csStatsControl.bufToRender = 0; + } + spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags); + if (process_stats) + vfe_send_comp_stats_msg(vfe40_ctrl, status_bits); + + return; +} + +static void vfe40_process_stats_irq( + struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus) +{ + uint32_t status_bits = VFE_COM_STATUS & irqstatus; + + if ((vfe40_ctrl->hfr_mode != HFR_MODE_OFF) && + (vfe40_ctrl->share_ctrl->vfeFrameId % + vfe40_ctrl->hfr_mode != 0)) { + CDBG("Skip the stats when HFR enabled\n"); + return; + } + + vfe40_process_stats(vfe40_ctrl, status_bits); + return; +} + +static void vfe40_process_irq( + struct vfe40_ctrl_type *vfe40_ctrl, uint32_t irqstatus) +{ + if (irqstatus & + VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) { + vfe40_process_stats_irq(vfe40_ctrl, irqstatus); + return; + } + + switch (irqstatus) { + case VFE_IRQ_STATUS0_CAMIF_SOF_MASK: + CDBG("irq camifSofIrq\n"); + vfe40_process_camif_sof_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS0_REG_UPDATE_MASK: + CDBG("irq regUpdateIrq\n"); + vfe40_process_reg_update_irq(vfe40_ctrl); + break; + case VFE_IMASK_WHILE_STOPPING_0: + CDBG("irq resetAckIrq\n"); + vfe40_process_reset_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS0_STATS_AWB: + CDBG("Stats AWB irq occured.\n"); + vfe40_process_stats_awb_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS0_STATS_IHIST: + CDBG("Stats IHIST irq occured.\n"); + vfe40_process_stats_ihist_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS0_STATS_RS: + CDBG("Stats RS irq occured.\n"); + vfe40_process_stats_rs_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS0_STATS_CS: + CDBG("Stats CS irq occured.\n"); + vfe40_process_stats_cs_irq(vfe40_ctrl); + break; + case VFE_IRQ_STATUS1_SYNC_TIMER0: + CDBG("SYNC_TIMER 0 irq occured.\n"); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_SYNC_TIMER0_DONE); + break; + case VFE_IRQ_STATUS1_SYNC_TIMER1: + CDBG("SYNC_TIMER 1 irq occured.\n"); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_SYNC_TIMER1_DONE); + break; + case VFE_IRQ_STATUS1_SYNC_TIMER2: + CDBG("SYNC_TIMER 2 irq occured.\n"); + vfe40_send_isp_msg(&vfe40_ctrl->subdev, + vfe40_ctrl->share_ctrl->vfeFrameId, + MSG_ID_SYNC_TIMER2_DONE); + break; + default: + pr_err("Invalid IRQ status\n"); + } +} + +static void axi40_do_tasklet(unsigned long data) +{ + unsigned long flags; + struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data; + struct vfe40_isr_queue_cmd *qcmd = NULL; + + CDBG("=== axi40_do_tasklet start ===\n"); + + while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) { + spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags); + qcmd = list_first_entry(&axi_ctrl->tasklet_q, + struct vfe40_isr_queue_cmd, list); + atomic_sub(1, &axi_ctrl->share_ctrl->irq_cnt); + + if (!qcmd) { + spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, + flags); + return; + } + + list_del(&qcmd->list); + spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, + flags); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_CAMIF_SOF_MASK) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK); + + /* interrupt to be processed, *qcmd has the payload. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_REG_UPDATE_MASK) { + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK); + } + + if (qcmd->vfeInterruptStatus0 & + VFE_IMASK_WHILE_STOPPING_0) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IMASK_WHILE_STOPPING_0); + + if (atomic_read(&axi_ctrl->share_ctrl->vstate)) { + if (qcmd->vfeInterruptStatus1 & + VFE40_IMASK_ERROR_ONLY_1) { + pr_err("irq errorIrq\n"); + vfe40_process_error_irq( + axi_ctrl, + qcmd->vfeInterruptStatus1 & + VFE40_IMASK_ERROR_ONLY_1); + } + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_AXI_IRQ, + (void *)qcmd->vfeInterruptStatus0); + + /* then process stats irq. */ + if (axi_ctrl->share_ctrl->stats_comp) { + /* process stats comb interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) { + CDBG("Stats composite irq occured.\n"); + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)qcmd->vfeInterruptStatus0); + } + } else { + /* process individual stats interrupt. */ + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_AWB) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_STATS_AWB); + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_IHIST) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_STATS_IHIST); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_RS) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_STATS_RS); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS0_STATS_CS) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS0_STATS_CS); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS1_SYNC_TIMER0) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS1_SYNC_TIMER0); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS1_SYNC_TIMER1) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS1_SYNC_TIMER1); + + if (qcmd->vfeInterruptStatus0 & + VFE_IRQ_STATUS1_SYNC_TIMER2) + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_IRQ, + (void *)VFE_IRQ_STATUS1_SYNC_TIMER2); + } + } + kfree(qcmd); + } + CDBG("=== axi40_do_tasklet end ===\n"); +} + +static irqreturn_t vfe40_parse_irq(int irq_num, void *data) +{ + unsigned long flags; + struct vfe40_irq_status irq; + struct vfe40_isr_queue_cmd *qcmd; + struct axi_ctrl_t *axi_ctrl = data; + + CDBG("vfe_parse_irq\n"); + + vfe40_read_irq_status(axi_ctrl, &irq); + + if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) { + CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n"); + return IRQ_HANDLED; + } + + qcmd = kzalloc(sizeof(struct vfe40_isr_queue_cmd), + GFP_ATOMIC); + if (!qcmd) { + pr_err("vfe_parse_irq: qcmd malloc failed!\n"); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags); + if (axi_ctrl->share_ctrl->stop_ack_pending) { + irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0; + irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1; + } + spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags); + + CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n", + irq.vfeIrqStatus0, irq.vfeIrqStatus1); + + qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0; + qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1; + + spin_lock_irqsave(&axi_ctrl->tasklet_lock, flags); + list_add_tail(&qcmd->list, &axi_ctrl->tasklet_q); + + atomic_add(1, &axi_ctrl->share_ctrl->irq_cnt); + spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags); + tasklet_schedule(&axi_ctrl->vfe40_tasklet); + return IRQ_HANDLED; +} + + +static long vfe_stats_bufq_sub_ioctl( + struct vfe40_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) +{ + struct msm_cam_media_controller *pmctl = + (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd); + struct vfe40_ctrl_type *vfe40_ctrl = + (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd); + struct msm_isp_cmd vfecmd; + struct msm_camvfe_params *vfe_params = + (struct msm_camvfe_params *)arg; + struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg; + void *data = vfe_params->data; + + long rc = 0; + struct vfe_cmd_stats_buf *scfg = NULL; + struct vfe_cmd_stats_ack *sack = NULL; + + if (!vfe40_ctrl->share_ctrl->vfebase) { + pr_err("%s: base address unmapped\n", __func__); + return -EFAULT; + } + + switch (cmd->cmd_type) { + case CMD_VFE_PROCESS_IRQ: + vfe40_process_irq(vfe40_ctrl, (uint32_t) data); + return rc; + 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(vfe40_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 && + 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) { + 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); + + 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 vfe40_config_done; + } + switch (cmd->cmd_type) { + case CMD_GENERAL: + rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl); + break; + case CMD_CONFIG_PING_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, vfe40_ctrl->share_ctrl); + outch->ping = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_PONG_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, vfe40_ctrl->share_ctrl); + outch->pong = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_FREE_BUF_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, vfe40_ctrl->share_ctrl); + outch->free_buf = *((struct msm_free_buf *)data); + } + break; + case CMD_SNAP_BUF_RELEASE: + break; + default: + pr_err("%s Unsupported AXI configuration %x ", __func__, + cmd->cmd_type); + break; + } + } +vfe40_config_done: + kfree(scfg); + kfree(sack); + CDBG("%s done: rc = %d\n", __func__, (int) rc); + return rc; +} + +static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = { + .ioctl = msm_vfe_subdev_ioctl, +}; + +static const struct v4l2_subdev_ops msm_vfe_subdev_ops = { + .core = &msm_vfe_subdev_core_ops, +}; + +int msm_vfe_subdev_init(struct v4l2_subdev *sd, + struct msm_cam_media_controller *mctl) +{ + int rc = 0; + struct vfe40_ctrl_type *vfe40_ctrl = + (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd); + v4l2_set_subdev_hostdata(sd, mctl); + + spin_lock_init(&vfe40_ctrl->share_ctrl->stop_flag_lock); + spin_lock_init(&vfe40_ctrl->state_lock); + spin_lock_init(&vfe40_ctrl->io_lock); + spin_lock_init(&vfe40_ctrl->update_ack_lock); + spin_lock_init(&vfe40_ctrl->stats_bufq_lock); + + + vfe40_ctrl->update_linear = false; + vfe40_ctrl->update_rolloff = false; + vfe40_ctrl->update_la = false; + vfe40_ctrl->update_gamma = false; + vfe40_ctrl->hfr_mode = HFR_MODE_OFF; + + return rc; +} + +void msm_vfe_subdev_release(struct v4l2_subdev *sd) +{ + struct vfe40_ctrl_type *vfe40_ctrl = + (struct vfe40_ctrl_type *)v4l2_get_subdevdata(sd); + if (!vfe40_ctrl->share_ctrl->vfebase) + vfe40_ctrl->share_ctrl->vfebase = NULL; +} + +static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops; + +static int __devinit vfe40_probe(struct platform_device *pdev) +{ + int rc = 0; + struct axi_ctrl_t *axi_ctrl; + struct vfe40_ctrl_type *vfe40_ctrl; + struct vfe_share_ctrl_t *share_ctrl; + struct msm_cam_subdev_info sd_info; + CDBG("%s: device id = %d\n", __func__, pdev->id); + + share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL); + if (!share_ctrl) { + pr_err("%s: no enough memory\n", __func__); + return -ENOMEM; + } + + axi_ctrl = kzalloc(sizeof(struct axi_ctrl_t), GFP_KERNEL); + if (!axi_ctrl) { + pr_err("%s: no enough memory\n", __func__); + kfree(share_ctrl); + return -ENOMEM; + } + + vfe40_ctrl = kzalloc(sizeof(struct vfe40_ctrl_type), GFP_KERNEL); + if (!vfe40_ctrl) { + pr_err("%s: no enough memory\n", __func__); + kfree(share_ctrl); + kfree(axi_ctrl); + return -ENOMEM; + } + + if (pdev->dev.of_node) + of_property_read_u32((&pdev->dev)->of_node, + "cell-index", &pdev->id); + + share_ctrl->axi_ctrl = axi_ctrl; + share_ctrl->vfe40_ctrl = vfe40_ctrl; + axi_ctrl->share_ctrl = share_ctrl; + vfe40_ctrl->share_ctrl = share_ctrl; + axi_ctrl->pdev = pdev; + vfe40_axi_probe(axi_ctrl); + + v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops); + vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops; + vfe40_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(vfe40_ctrl->subdev.name, + sizeof(vfe40_ctrl->subdev.name), "vfe4.0"); + v4l2_set_subdevdata(&vfe40_ctrl->subdev, vfe40_ctrl); + platform_set_drvdata(pdev, &vfe40_ctrl->subdev); + + axi_ctrl->vfemem = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "vfe"); + if (!axi_ctrl->vfemem) { + pr_err("%s: no mem resource?\n", __func__); + rc = -ENODEV; + goto vfe40_no_resource; + } + axi_ctrl->vfeirq = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "vfe"); + if (!axi_ctrl->vfeirq) { + pr_err("%s: no irq resource?\n", __func__); + rc = -ENODEV; + goto vfe40_no_resource; + } + + axi_ctrl->vfeio = request_mem_region(axi_ctrl->vfemem->start, + resource_size(axi_ctrl->vfemem), pdev->name); + if (!axi_ctrl->vfeio) { + pr_err("%s: no valid mem region\n", __func__); + rc = -EBUSY; + goto vfe40_no_resource; + } + + rc = request_irq(axi_ctrl->vfeirq->start, vfe40_parse_irq, + IRQF_TRIGGER_RISING, "vfe", axi_ctrl); + if (rc < 0) { + release_mem_region(axi_ctrl->vfemem->start, + resource_size(axi_ctrl->vfemem)); + pr_err("%s: irq request fail\n", __func__); + rc = -EBUSY; + goto vfe40_no_resource; + } + + disable_irq(axi_ctrl->vfeirq->start); + + tasklet_init(&axi_ctrl->vfe40_tasklet, + axi40_do_tasklet, (unsigned long)axi_ctrl); + + vfe40_ctrl->pdev = pdev; + sd_info.sdev_type = VFE_DEV; + sd_info.sd_index = pdev->id; + sd_info.irq_num = axi_ctrl->vfeirq->start; + msm_cam_register_subdev_node(&vfe40_ctrl->subdev, &sd_info); + return 0; + +vfe40_no_resource: + kfree(vfe40_ctrl); + kfree(axi_ctrl); + return 0; +} + +static const struct of_device_id msm_vfe_dt_match[] = { + {.compatible = "qcom,vfe40"}, +}; + +MODULE_DEVICE_TABLE(of, msm_vfe_dt_match); + +static struct platform_driver vfe40_driver = { + .probe = vfe40_probe, + .driver = { + .name = MSM_VFE_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = msm_vfe_dt_match, + }, +}; + +static int __init msm_vfe40_init_module(void) +{ + return platform_driver_register(&vfe40_driver); +} + +static void __exit msm_vfe40_exit_module(void) +{ + platform_driver_unregister(&vfe40_driver); +} + +module_init(msm_vfe40_init_module); +module_exit(msm_vfe40_exit_module); +MODULE_DESCRIPTION("VFE 4.0 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h new file mode 100644 index 00000000000..c8b0cb8be84 --- /dev/null +++ b/drivers/media/video/msm/vfe/msm_vfe40.h @@ -0,0 +1,1202 @@ +/* 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_VFE40_H__ +#define __MSM_VFE40_H__ + +#include +#include "msm_vfe_stats_buf.h" + +#define TRUE 1 +#define FALSE 0 + +#define VFE40_HW_NUMBER 0x10000015 + +/* This defines total number registers in VFE. + * Each register is 4 bytes so to get the range, + * multiply this number with 4. */ +#define VFE40_REGISTER_TOTAL 0x00000320 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x10: + * disable image data capture immediately. */ +#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002 + +/* at stop of vfe pipeline, for now it is assumed + * that camif will stop at any time. Bit 1:0 = 0x00: + * disable image data capture at frame boundary */ +#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000 + +/* to halt axi bridge */ +#define AXI_HALT 0x00000001 + +/* clear the halt bit. */ +#define AXI_HALT_CLEAR 0x00000000 + +/* reset the pipeline when stop command is issued. + * (without reset the register.) bit 26-32 = 0, + * domain reset, bit 0-9 = 1 for module reset, except + * register module. */ +#define VFE_RESET_UPON_STOP_CMD 0x000003ef + +/* reset the pipeline when reset command. + * bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */ +#define VFE_RESET_UPON_RESET_CMD 0x000001ff + +/* constants for irq registers */ +#define VFE_DISABLE_ALL_IRQS 0 +/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */ +#define VFE_CLEAR_ALL_IRQ0 0xffff7fff +#define VFE_CLEAR_ALL_IRQ1 0xffffffff + +#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK (0x00000001<<0) +#define VFE_IRQ_STATUS0_REG_UPDATE_MASK (0x00000001<<4) +#define VFE_IRQ_STATUS0_STATS_BE (0x00000001<<16) +#define VFE_IRQ_STATUS0_STATS_BG (0x00000001<<17) +#define VFE_IRQ_STATUS0_STATS_BF (0x00000001<<18) +#define VFE_IRQ_STATUS0_STATS_AWB (0x00000001<<19) +#define VFE_IRQ_STATUS0_STATS_RS (0x00000001<<20) +#define VFE_IRQ_STATUS0_STATS_CS (0x00000001<<21) +#define VFE_IRQ_STATUS0_STATS_IHIST (0x00000001<<22) +#define VFE_IRQ_STATUS0_STATS_SKIN_BHIST (0x00000001<<23) +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK (0x00000001<<25) +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK (0x00000001<<26) +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK (0x00000001<<27) +#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE3_MASK (0x00000001<<28) +#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0 (0x00000001<<29) +#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_1 (0x00000001<<30) +#define VFE_IRQ_STATUS0_RESET_AXI_HALT_ACK_MASK (0x00000001<<31) + +#define VFE_IRQ_STATUS1_SYNC_TIMER0 (0x00000001<<25) +#define VFE_IRQ_STATUS1_SYNC_TIMER1 (0x00000001<<26) +#define VFE_IRQ_STATUS1_SYNC_TIMER2 (0x00000001<<27) +#define VFE_IRQ_STATUS1_ASYNC_TIMER0 (0x00000001<<28) +#define VFE_IRQ_STATUS1_ASYNC_TIMER1 (0x00000001<<29) +#define VFE_IRQ_STATUS1_ASYNC_TIMER2 (0x00000001<<30) +#define VFE_IRQ_STATUS1_ASYNC_TIMER3 (0x00000001<<31) + +/* imask for while waiting for stop ack, driver has already + * requested stop, waiting for reset irq, and async timer irq. + * For irq_status_0, bit 28-32 are for async timer. For + * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack + irq */ +#define VFE_IMASK_WHILE_STOPPING_0 0x80000000 +#define VFE_IMASK_WHILE_STOPPING_1 0x00000100 + +/* For ABF bit 4 is set to zero and other's 1 */ +#define ABF_MASK 0xFFFFFFF7 + +/* For DBPC bit 0 is set to zero and other's 1 */ +#define DBPC_MASK 0xFFFFFFFE + +/* For DBPC bit 1 is set to zero and other's 1 */ +#define DBCC_MASK 0xFFFFFFFD + +/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */ +#define DEMOSAIC_MASK 0xF + +/* For MCE enable bit 28 set to zero and other's 1 */ +#define MCE_EN_MASK 0xEFFFFFFF + +/* For MCE Q_K bit 28 to 32 set to zero and other's 1 */ +#define MCE_Q_K_MASK 0x0FFFFFFF + +#define BE_ENABLE_MASK (0x00000001<<5) +#define BG_ENABLE_MASK (0x00000001<<6) +#define BF_ENABLE_MASK (0x00000001<<7) +#define AWB_ENABLE_MASK (0x00000001<<8) +#define RS_ENABLE_MASK (0x00000001<<9) +#define CS_ENABLE_MASK (0x00000001<<10) +#define CLF_ENABLE_MASK (0x00000001<<12) +#define IHIST_ENABLE_MASK (0x00000001<<15) +#define RS_CS_ENABLE_MASK (RS_ENABLE_MASK|CS_ENABLE_MASK) +#define STATS_ENABLE_MASK 0x000487E0 /* bit 18,15,10,9,8,7,6,5*/ + +#define VFE_DMI_CFG_DEFAULT 0x00000100 + +#define HFR_MODE_OFF 1 +#define VFE_FRAME_SKIP_PERIOD_MASK 0x0000001F /*bits 0 -4*/ + +enum VFE40_DMI_RAM_SEL { + NO_MEM_SELECTED = 0, + BLACK_LUT_RAM_BANK0 = 0x1, + BLACK_LUT_RAM_BANK1 = 0x2, + ROLLOFF_RAM0_BANK0 = 0x3, + ROLLOFF_RAM0_BANK1 = 0x4, + DEMOSAIC_LUT_RAM_BANK0 = 0x5, + DEMOSAIC_LUT_RAM_BANK1 = 0x6, + STATS_BHIST_RAM0 = 0x7, + STATS_BHIST_RAM1 = 0x8, + RGBLUT_RAM_CH0_BANK0 = 0x9, + RGBLUT_RAM_CH0_BANK1 = 0xa, + RGBLUT_RAM_CH1_BANK0 = 0xb, + RGBLUT_RAM_CH1_BANK1 = 0xc, + RGBLUT_RAM_CH2_BANK0 = 0xd, + RGBLUT_RAM_CH2_BANK1 = 0xe, + RGBLUT_CHX_BANK0 = 0xf, + RGBLUT_CHX_BANK1 = 0x10, + STATS_IHIST_RAM = 0x11, + LUMA_ADAPT_LUT_RAM_BANK0 = 0x12, + LUMA_ADAPT_LUT_RAM_BANK1 = 0x13, +}; + +enum vfe_output_state { + VFE_STATE_IDLE, + VFE_STATE_START_REQUESTED, + VFE_STATE_STARTED, + VFE_STATE_STOP_REQUESTED, + VFE_STATE_STOPPED, +}; + +#define V40_CAMIF_OFF 0x000002F8 +#define V40_CAMIF_LEN 36 + +#define V40_DEMUX_OFF 0x00000424 +#define V40_DEMUX_LEN 28 + +#define V40_DEMOSAICV3_0_OFF 0x00000440 +#define V40_DEMOSAICV3_0_LEN 4 +#define V40_DEMOSAICV3_1_OFF 0x00000518 +#define V40_DEMOSAICV3_1_LEN 88 +#define V40_DEMOSAICV3_2_OFF 0x00000568 +#define V40_DEMOSAICV3_UP_REG_CNT 5 + +#define V40_OUT_CLAMP_OFF 0x00000874 +#define V40_OUT_CLAMP_LEN 16 + +#define V40_OPERATION_CFG_LEN 44 + +#define V40_AXI_OUT_OFF 0x0000004C +#define V40_AXI_OUT_LEN 412 +#define V40_AXI_CH_INF_LEN 32 +#define V40_AXI_CFG_LEN 71 + +#define V40_FOV_ENC_OFF 0x00000854 +#define V40_FOV_ENC_LEN 16 +#define V40_FOV_VIEW_OFF 0x00000864 +#define V40_FOV_VIEW_LEN 16 + +#define V40_SCALER_ENC_OFF 0x0000075C +#define V40_SCALER_ENC_LEN 72 + +#define V40_SCALER_VIEW_OFF 0x000007A4 +#define V40_SCALER_VIEW_LEN 72 + +#define V40_COLORXFORM_ENC_CFG_OFF 0x0000071C +#define V40_COLORXFORM_ENC_CFG_LEN 32 + +#define V40_COLORXFORM_VIEW_CFG_OFF 0x0000073C +#define V40_COLORXFORM_VIEW_CFG_LEN 32 + +#define V40_CHROMA_EN_OFF 0x00000640 +#define V40_CHROMA_EN_LEN 36 + +#define V40_SYNC_TIMER_OFF 0x00000324 +#define V40_SYNC_TIMER_POLARITY_OFF 0x0000034C +#define V40_TIMER_SELECT_OFF 0x00000374 +#define V40_SYNC_TIMER_LEN 28 + +#define V40_ASYNC_TIMER_OFF 0x00000350 +#define V40_ASYNC_TIMER_LEN 28 + +/* use 10x13 mesh table in vfe40*/ +#define V40_MESH_ROLL_OFF_CFG_OFF 0x00000400 +#define V40_MESH_ROLL_OFF_CFG_LEN 36 +#define V40_MESH_ROLL_OFF_TABLE_SIZE 130 + + +#define V40_COLOR_COR_OFF 0x000005D0 +#define V40_COLOR_COR_LEN 52 + +#define V40_WB_OFF 0x00000580 +#define V40_WB_LEN 4 + +#define V40_RGB_G_OFF 0x00000638 +#define V40_RGB_G_LEN 4 +#define V40_GAMMA_LUT_BANK_SEL_MASK 0x00000007 + +#define V40_LA_OFF 0x0000063C +#define V40_LA_LEN 4 + +#define V40_SCE_OFF 0x00000694 +#define V40_SCE_LEN 136 + +#define V40_CHROMA_SUP_OFF 0x00000664 +#define V40_CHROMA_SUP_LEN 12 + +#define V40_MCE_OFF 0x00000670 +#define V40_MCE_LEN 36 + +#define V40_STATS_BE_OFF 0x0000088C +#define V40_STATS_BE_LEN 12 + +#define V40_STATS_BG_OFF 0x00000898 +#define V40_STATS_BG_LEN 12 + +#define V40_STATS_BF_OFF 0x000008A4 +#define V40_STATS_BF_LEN 24 + +#define V40_STATS_BHIST_OFF 0x000008BC +#define V40_STATS_BHIST_LEN 8 + +#define V40_STATS_AWB_OFF 0x000008C4 +#define V40_STATS_AWB_LEN 32 + +#define V40_STATS_RS_OFF 0x000008E4 +#define V40_STATS_RS_LEN 8 + +#define V40_STATS_CS_OFF 0x000008EC +#define V40_STATS_CS_LEN 8 + +#define V40_STATS_IHIST_OFF 0x000008F4 +#define V40_STATS_IHIST_LEN 8 + +#define V40_STATS_SKIN_OFF 0x000008FC +#define V40_STATS_SKIN_LEN 20 + +#define V40_ASF_OFF 0x000007EC +#define V40_ASF_LEN 48 +#define V40_ASF_UPDATE_LEN 36 + +#define V40_CAPTURE_LEN 4 + +#define V40_GET_HW_VERSION_OFF 0 +#define V40_GET_HW_VERSION_LEN 4 + +#define V40_LINEARIZATION_OFF1 0x0000037C +#define V40_LINEARIZATION_LEN1 68 + +#define V40_DEMOSAICV3_DBPC_CFG_OFF 0x00000444 +#define V40_DEMOSAICV3_DBPC_LEN 4 + +#define V40_DEMOSAICV3_DBPC_CFG_OFF0 0x00000448 +#define V40_DEMOSAICV3_DBPC_CFG_OFF1 0x0000044C +#define V40_DEMOSAICV3_DBPC_CFG_OFF2 0x00000450 + +#define V40_DEMOSAICV3_DBCC_OFF 0x00000454 +#define V40_DEMOSAICV3_DBCC_LEN 16 + +#define V40_DEMOSAICV3_ABF_OFF 0x00000464 +#define V40_DEMOSAICV3_ABF_LEN 180 + +#define V40_MODULE_CFG_OFF 0x00000018 +#define V40_MODULE_CFG_LEN 4 + +#define V40_ASF_SPECIAL_EFX_CFG_OFF 0x0000081C +#define V40_ASF_SPECIAL_EFX_CFG_LEN 4 + +#define V40_CLF_CFG_OFF 0x00000588 +#define V40_CLF_CFG_LEN 72 + +#define V40_CLF_LUMA_UPDATE_OFF 0x0000058C +#define V40_CLF_LUMA_UPDATE_LEN 60 + +#define V40_CLF_CHROMA_UPDATE_OFF 0x000005C8 +#define V40_CLF_CHROMA_UPDATE_LEN 8 + +#define VFE40_GAMMA_NUM_ENTRIES 64 + +#define VFE40_LA_TABLE_LENGTH 64 + +#define VFE40_LINEARIZATON_TABLE_LENGTH 36 + +#define VFE_WM_CFG_BASE 0x0070 +#define VFE_WM_CFG_LEN 0x0024 + +#define vfe40_get_ch_ping_addr(base, chn) \ + (msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn))) +#define vfe40_get_ch_pong_addr(base, chn) \ + (msm_camera_io_r((base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4)) +#define vfe40_get_ch_addr(ping_pong, base, chn) \ + ((((ping_pong) & (1 << (chn))) == 0) ? \ + (vfe40_get_ch_pong_addr((base), chn)) : \ + (vfe40_get_ch_ping_addr((base), chn))) + +#define vfe40_put_ch_ping_addr(base, chn, addr) \ + (msm_camera_io_w((addr), \ + (base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn))) +#define vfe40_put_ch_pong_addr(base, chn, addr) \ + (msm_camera_io_w((addr), \ + (base) + VFE_WM_CFG_BASE + VFE_WM_CFG_LEN * (chn) + 4)) +#define vfe40_put_ch_addr(ping_pong, base, chn, addr) \ + (((ping_pong) & (1 << (chn))) == 0 ? \ + vfe40_put_ch_pong_addr((base), (chn), (addr)) : \ + vfe40_put_ch_ping_addr((base), (chn), (addr))) + +struct vfe_cmd_hw_version { + uint32_t minorVersion; + uint32_t majorVersion; + uint32_t coreVersion; +}; + +enum VFE_AXI_OUTPUT_MODE { + VFE_AXI_OUTPUT_MODE_Output1, + VFE_AXI_OUTPUT_MODE_Output2, + VFE_AXI_OUTPUT_MODE_Output1AndOutput2, + VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2, + VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1, + VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2, + VFE_AXI_LAST_OUTPUT_MODE_ENUM +}; + +enum VFE_RAW_WR_PATH_SEL { + VFE_RAW_OUTPUT_DISABLED, + VFE_RAW_OUTPUT_ENC_CBCR_PATH, + VFE_RAW_OUTPUT_VIEW_CBCR_PATH, + VFE_RAW_OUTPUT_PATH_INVALID +}; + + +#define VFE_AXI_OUTPUT_BURST_LENGTH 4 +#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4 +#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3 + +struct vfe_cmds_per_write_master { + uint16_t imageWidth; + uint16_t imageHeight; + uint16_t outRowCount; + uint16_t outRowIncrement; + uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT] + [VFE_MAX_NUM_FRAGMENTS_PER_FRAME]; +}; + +struct vfe_cmds_axi_per_output_path { + uint8_t fragmentCount; + struct vfe_cmds_per_write_master firstWM; + struct vfe_cmds_per_write_master secondWM; +}; + +enum VFE_AXI_BURST_LENGTH { + VFE_AXI_BURST_LENGTH_IS_2 = 2, + VFE_AXI_BURST_LENGTH_IS_4 = 4, + VFE_AXI_BURST_LENGTH_IS_8 = 8, + VFE_AXI_BURST_LENGTH_IS_16 = 16 +}; + + +struct vfe_cmd_fov_crop_config { + uint8_t enable; + uint16_t firstPixel; + uint16_t lastPixel; + uint16_t firstLine; + uint16_t lastLine; +}; + +struct vfe_cmds_main_scaler_stripe_init { + uint16_t MNCounterInit; + uint16_t phaseInit; +}; + +struct vfe_cmds_scaler_one_dimension { + uint8_t enable; + uint16_t inputSize; + uint16_t outputSize; + uint32_t phaseMultiplicationFactor; + uint8_t interpolationResolution; +}; + +struct vfe_cmd_main_scaler_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; + struct vfe_cmds_main_scaler_stripe_init MNInitH; + struct vfe_cmds_main_scaler_stripe_init MNInitV; +}; + +struct vfe_cmd_scaler2_config { + uint8_t enable; + struct vfe_cmds_scaler_one_dimension hconfig; + struct vfe_cmds_scaler_one_dimension vconfig; +}; + + +struct vfe_cmd_frame_skip_update { + uint32_t output1Pattern; + uint32_t output2Pattern; +}; + +struct vfe_cmd_output_clamp_config { + uint8_t minCh0; + uint8_t minCh1; + uint8_t minCh2; + uint8_t maxCh0; + uint8_t maxCh1; + uint8_t maxCh2; +}; + +struct vfe_cmd_chroma_subsample_config { + uint8_t enable; + uint8_t cropEnable; + uint8_t vsubSampleEnable; + uint8_t hsubSampleEnable; + uint8_t vCosited; + uint8_t hCosited; + uint8_t vCositedPhase; + uint8_t hCositedPhase; + uint16_t cropWidthFirstPixel; + uint16_t cropWidthLastPixel; + uint16_t cropHeightFirstLine; + uint16_t cropHeightLastLine; +}; + +enum VFE_START_PIXEL_PATTERN { + VFE_BAYER_RGRGRG, + VFE_BAYER_GRGRGR, + VFE_BAYER_BGBGBG, + VFE_BAYER_GBGBGB, + VFE_YUV_YCbYCr, + VFE_YUV_YCrYCb, + VFE_YUV_CbYCrY, + VFE_YUV_CrYCbY +}; + +enum VFE_BUS_RD_INPUT_PIXEL_PATTERN { + VFE_BAYER_RAW, + VFE_YUV_INTERLEAVED, + VFE_YUV_PSEUDO_PLANAR_Y, + VFE_YUV_PSEUDO_PLANAR_CBCR +}; + +enum VFE_YUV_INPUT_COSITING_MODE { + VFE_YUV_COSITED, + VFE_YUV_INTERPOLATED +}; + +struct vfe_cmds_demosaic_abf { + uint8_t enable; + uint8_t forceOn; + uint8_t shift; + uint16_t lpThreshold; + uint16_t max; + uint16_t min; + uint8_t ratio; +}; + +struct vfe_cmds_demosaic_bpc { + uint8_t enable; + uint16_t fmaxThreshold; + uint16_t fminThreshold; + uint16_t redDiffThreshold; + uint16_t blueDiffThreshold; + uint16_t greenDiffThreshold; +}; + +struct vfe_cmd_demosaic_config { + uint8_t enable; + uint8_t slopeShift; + struct vfe_cmds_demosaic_abf abfConfig; + struct vfe_cmds_demosaic_bpc bpcConfig; +}; + +struct vfe_cmd_demosaic_bpc_update { + struct vfe_cmds_demosaic_bpc bpcUpdate; +}; + +struct vfe_cmd_demosaic_abf_update { + struct vfe_cmds_demosaic_abf abfUpdate; +}; + +struct vfe_cmd_white_balance_config { + uint8_t enable; + uint16_t ch2Gain; + uint16_t ch1Gain; + uint16_t ch0Gain; +}; + +enum VFE_COLOR_CORRECTION_COEF_QFACTOR { + COEF_IS_Q7_SIGNED, + COEF_IS_Q8_SIGNED, + COEF_IS_Q9_SIGNED, + COEF_IS_Q10_SIGNED +}; + +struct vfe_cmd_color_correction_config { + uint8_t enable; + enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor; + int16_t C0; + int16_t C1; + int16_t C2; + int16_t C3; + int16_t C4; + int16_t C5; + int16_t C6; + int16_t C7; + int16_t C8; + int16_t K0; + int16_t K1; + int16_t K2; +}; + +#define VFE_LA_TABLE_LENGTH 64 + +struct vfe_cmd_la_config { + uint8_t enable; + int16_t table[VFE_LA_TABLE_LENGTH]; +}; + +#define VFE_GAMMA_TABLE_LENGTH 256 +enum VFE_RGB_GAMMA_TABLE_SELECT { + RGB_GAMMA_CH0_SELECTED, + RGB_GAMMA_CH1_SELECTED, + RGB_GAMMA_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_SELECTED, + RGB_GAMMA_CH0_CH2_SELECTED, + RGB_GAMMA_CH1_CH2_SELECTED, + RGB_GAMMA_CH0_CH1_CH2_SELECTED +}; + +struct vfe_cmd_rgb_gamma_config { + uint8_t enable; + enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect; + int16_t table[VFE_GAMMA_TABLE_LENGTH]; +}; + +struct vfe_cmd_chroma_enhan_config { + uint8_t enable; + int16_t am; + int16_t ap; + int16_t bm; + int16_t bp; + int16_t cm; + int16_t cp; + int16_t dm; + int16_t dp; + int16_t kcr; + int16_t kcb; + int16_t RGBtoYConversionV0; + int16_t RGBtoYConversionV1; + int16_t RGBtoYConversionV2; + uint8_t RGBtoYConversionOffset; +}; + +struct vfe_cmd_chroma_suppression_config { + uint8_t enable; + uint8_t m1; + uint8_t m3; + uint8_t n1; + uint8_t n3; + uint8_t nn1; + uint8_t mm1; +}; + +struct vfe_cmd_asf_config { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; + uint16_t cropFirstPixel; + uint16_t cropLastPixel; + uint16_t cropFirstLine; + uint16_t cropLastLine; +}; + +struct vfe_cmd_asf_update { + uint8_t enable; + uint8_t smoothFilterEnabled; + uint8_t sharpMode; + uint8_t smoothCoefCenter; + uint8_t smoothCoefSurr; + uint8_t normalizeFactor; + uint8_t sharpK1; + uint8_t sharpK2; + uint8_t sharpThreshE1; + int8_t sharpThreshE2; + int8_t sharpThreshE3; + int8_t sharpThreshE4; + int8_t sharpThreshE5; + int8_t filter1Coefficients[9]; + int8_t filter2Coefficients[9]; + uint8_t cropEnable; +}; + +enum VFE_TEST_GEN_SYNC_EDGE { + VFE_TEST_GEN_SYNC_EDGE_ActiveHigh, + VFE_TEST_GEN_SYNC_EDGE_ActiveLow +}; + + +struct vfe_cmd_bus_pm_start { + uint8_t output2YWrPmEnable; + uint8_t output2CbcrWrPmEnable; + uint8_t output1YWrPmEnable; + uint8_t output1CbcrWrPmEnable; +}; + +struct vfe_frame_skip_counts { + uint32_t totalFrameCount; + uint32_t output1Count; + uint32_t output2Count; +}; + +enum VFE_AXI_RD_UNPACK_HBI_SEL { + VFE_AXI_RD_HBI_32_CLOCK_CYCLES, + VFE_AXI_RD_HBI_64_CLOCK_CYCLES, + VFE_AXI_RD_HBI_128_CLOCK_CYCLES, + VFE_AXI_RD_HBI_256_CLOCK_CYCLES, + VFE_AXI_RD_HBI_512_CLOCK_CYCLES, + VFE_AXI_RD_HBI_1024_CLOCK_CYCLES, + VFE_AXI_RD_HBI_2048_CLOCK_CYCLES, + VFE_AXI_RD_HBI_4096_CLOCK_CYCLES +}; + +struct vfe_frame_bpc_info { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; +}; + +struct vfe_frame_asf_info { + uint32_t asfMaxEdge; + uint32_t asfHbiCount; +}; + +struct vfe_msg_camif_status { + uint8_t camifState; + uint32_t pixelCount; + uint32_t lineCount; +}; + +struct vfe40_irq_status { + uint32_t vfeIrqStatus0; + uint32_t vfeIrqStatus1; + uint32_t camifStatus; + uint32_t demosaicStatus; + uint32_t asfMaxEdge; +}; + +#define V40_PREVIEW_AXI_FLAG 0x00000001 +#define V40_SNAPSHOT_AXI_FLAG (0x00000001<<1) + +struct vfe40_cmd_type { + uint16_t id; + uint32_t length; + uint32_t offset; + uint32_t flag; +}; + +struct vfe40_free_buf { + struct list_head node; + uint32_t paddr; + uint32_t y_off; + uint32_t cbcr_off; +}; + +struct vfe40_output_ch { + struct list_head free_buf_queue; + spinlock_t free_buf_lock; + uint16_t image_mode; + int8_t ch0; + int8_t ch1; + int8_t ch2; + uint32_t capture_cnt; + uint32_t frame_drop_cnt; + struct msm_free_buf ping; + struct msm_free_buf pong; + struct msm_free_buf free_buf; +}; + +/* no error irq in mask 0 */ +#define VFE40_IMASK_ERROR_ONLY_0 0x0 +/* when normal case, don't want to block error status. */ +/* bit 0-21 are error irq bits */ +#define VFE40_IMASK_ERROR_ONLY_1 0x005FFFFF +#define VFE40_IMASK_CAMIF_ERROR (0x00000001<<0) +#define VFE40_IMASK_BHIST_OVWR (0x00000001<<1) +#define VFE40_IMASK_STATS_CS_OVWR (0x00000001<<2) +#define VFE40_IMASK_STATS_IHIST_OVWR (0x00000001<<3) +#define VFE40_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<4) +#define VFE40_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<5) +#define VFE40_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<6) +#define VFE40_IMASK_VIOLATION (0x00000001<<7) +#define VFE40_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<8) +#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<9) +#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<10) +#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<11) +#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<12) +#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<13) +#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<14) +#define VFE40_IMASK_STATS_AE_BG_BUS_OVFL (0x00000001<<15) +#define VFE40_IMASK_STATS_AF_BF_BUS_OVFL (0x00000001<<16) +#define VFE40_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<17) +#define VFE40_IMASK_STATS_RS_BUS_OVFL (0x00000001<<18) +#define VFE40_IMASK_STATS_CS_BUS_OVFL (0x00000001<<19) +#define VFE40_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<20) +#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<21) +#define VFE40_IMASK_AXI_ERROR (0x00000001<<22) + +#define VFE_COM_STATUS 0x000FE000 + +struct vfe40_output_path { + uint16_t output_mode; /* bitmask */ + + struct vfe40_output_ch out0; /* preview and thumbnail */ + struct vfe40_output_ch out1; /* snapshot */ + struct vfe40_output_ch out2; /* video */ +}; + +struct vfe40_frame_extra { + uint32_t greenDefectPixelCount; + uint32_t redBlueDefectPixelCount; + + uint32_t asfMaxEdge; + uint32_t asfHbiCount; + + uint32_t yWrPmStats0; + uint32_t yWrPmStats1; + uint32_t cbcrWrPmStats0; + uint32_t cbcrWrPmStats1; + + uint32_t frameCounter; +}; + +#define VFE_CLEAR_ALL_IRQS 0xffffffff + +#define VFE_HW_VERSION 0x00000000 +#define VFE_GLOBAL_RESET 0x0000000C +#define VFE_MODULE_RESET 0x00000010 +#define VFE_CGC_OVERRIDE 0x00000014 +#define VFE_MODULE_CFG 0x00000018 +#define VFE_CFG 0x0000001C +#define VFE_IRQ_CMD 0x00000024 +#define VFE_IRQ_MASK_0 0x00000028 +#define VFE_IRQ_MASK_1 0x0000002C +#define VFE_IRQ_CLEAR_0 0x00000030 +#define VFE_IRQ_CLEAR_1 0x00000034 +#define VFE_IRQ_STATUS_0 0x00000038 +#define VFE_IRQ_STATUS_1 0x0000003C +#define VFE_IRQ_COMP_MASK 0x00000040 +#define VFE_BUS_CMD 0x0000004C +#define VFE_BUS_PING_PONG_STATUS 0x00000180 +#define VFE_AXI_CMD 0x000001D8 +#define VFE_AXI_STATUS 0x000002C0 +#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4 + +#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4 +#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8 +#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC +#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100 +#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104 +#define VFE_BUS_STATS_AF_UB_CFG 0x00000108 +#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C +#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110 +#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114 +#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118 +#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C +#define VFE_BUS_STATS_RS_UB_CFG 0x00000120 +#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124 +#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128 +#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C +#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130 +#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134 +#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138 +#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C +#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140 +#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144 + +#define VFE_0_BUS_BDG_QOS_CFG_0 0x000002C4 +#define VFE_0_BUS_BDG_QOS_CFG_1 0x000002C8 +#define VFE_0_BUS_BDG_QOS_CFG_2 0x000002CC +#define VFE_0_BUS_BDG_QOS_CFG_3 0x000002D0 +#define VFE_0_BUS_BDG_QOS_CFG_4 0x000002D4 +#define VFE_0_BUS_BDG_QOS_CFG_5 0x000002D8 +#define VFE_0_BUS_BDG_QOS_CFG_6 0x000002DC +#define VFE_0_BUS_BDG_QOS_CFG_7 0x000002E0 + +#define VFE_CAMIF_COMMAND 0x000002F4 +#define VFE_CAMIF_STATUS 0x0000031C +#define VFE_REG_UPDATE_CMD 0x00000378 +#define VFE_DEMUX_GAIN_0 0x00000428 +#define VFE_DEMUX_GAIN_1 0x0000042C +#define VFE_CHROMA_UP 0x0000057C + +#define VFE_CLAMP_ENC_MAX 0x00000874 +#define VFE_CLAMP_ENC_MIN 0x00000878 +#define VFE_CLAMP_VIEW_MAX 0x0000087C +#define VFE_CLAMP_VIEW_MIN 0x00000880 + +#define VFE_REALIGN_BUF 0x00000884 +#define VFE_STATS_CFG 0x00000888 +#define VFE_STATS_AWB_SGW_CFG 0x000008CC +#define VFE_DMI_CFG 0x00000910 +#define VFE_DMI_ADDR 0x00000914 +#define VFE_DMI_DATA_LO 0x0000091C +#define VFE_BUS_IO_FORMAT_CFG 0x00000054 +#define VFE_RDI0_CFG 0x000002E8 +#define VFE_RDI1_CFG 0x000002EC +#define VFE_RDI2_CFG 0x000002F0 + +#define VFE_VIOLATION_STATUS 0x000007B4 + +#define VFE40_DMI_DATA_HI 0x00000918 +#define VFE40_DMI_DATA_LO 0x0000091C + +#define VFE40_OUTPUT_MODE_PT BIT(0) +#define VFE40_OUTPUT_MODE_S BIT(1) +#define VFE40_OUTPUT_MODE_V BIT(2) +#define VFE40_OUTPUT_MODE_P BIT(3) +#define VFE40_OUTPUT_MODE_T BIT(4) +#define VFE40_OUTPUT_MODE_P_ALL_CHNLS BIT(5) +#define VFE40_OUTPUT_MODE_PRIMARY BIT(6) +#define VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS BIT(7) +#define VFE40_OUTPUT_MODE_SECONDARY BIT(8) +#define VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS BIT(9) + +struct vfe_stats_control { + uint32_t droppedStatsFrameCount; + uint32_t bufToRender; +}; +struct axi_ctrl_t; +struct vfe40_ctrl_type; + +struct vfe_share_ctrl_t { + void __iomem *vfebase; + uint32_t register_total; + + atomic_t vstate; + uint32_t vfeFrameId; + uint32_t stats_comp; + spinlock_t stop_flag_lock; + int8_t stop_ack_pending; + enum vfe_output_state liveshot_state; + uint32_t vfe_capture_count; + + uint16_t operation_mode; /* streaming or snapshot */ + struct vfe40_output_path outpath; + + uint32_t ref_count; + spinlock_t sd_notify_lock; + uint32_t vfe_clk_rate; + + atomic_t irq_cnt; + struct axi_ctrl_t *axi_ctrl; + struct vfe40_ctrl_type *vfe40_ctrl; +}; + +struct axi_ctrl_t { + struct v4l2_subdev subdev; + struct platform_device *pdev; + struct resource *vfeirq; + spinlock_t tasklet_lock; + struct list_head tasklet_q; + + void *syncdata; + + struct resource *vfemem; + struct resource *vfeio; + struct regulator *fs_vfe; + struct clk *vfe_clk[3]; + struct tasklet_struct vfe40_tasklet; + struct vfe_share_ctrl_t *share_ctrl; +}; + +struct vfe40_ctrl_type { + uint32_t vfeImaskCompositePacked; + + spinlock_t update_ack_lock; + spinlock_t state_lock; + spinlock_t io_lock; + spinlock_t stats_bufq_lock; + uint32_t extlen; + void *extdata; + + int8_t start_ack_pending; + int8_t reset_ack_pending; + int8_t update_ack_pending; + enum vfe_output_state recording_state; + int8_t update_linear; + int8_t update_rolloff; + int8_t update_la; + int8_t update_gamma; + + struct vfe_share_ctrl_t *share_ctrl; + + uint32_t sync_timer_repeat_count; + uint32_t sync_timer_state; + uint32_t sync_timer_number; + + uint32_t output1Pattern; + uint32_t output1Period; + uint32_t output2Pattern; + uint32_t output2Period; + uint32_t vfeFrameSkipCount; + uint32_t vfeFrameSkipPeriod; + struct vfe_stats_control afStatsControl; + struct vfe_stats_control awbStatsControl; + struct vfe_stats_control aecStatsControl; + struct vfe_stats_control ihistStatsControl; + struct vfe_stats_control rsStatsControl; + struct vfe_stats_control csStatsControl; + + /* v4l2 subdev */ + struct v4l2_subdev subdev; + struct platform_device *pdev; + uint32_t hfr_mode; + 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 +#define statsAfNum 1 +#define statsAwbNum 2 +#define statsRsNum 3 +#define statsCsNum 4 +#define statsIhistNum 5 +#define statsSkinNum 6 + +struct vfe_cmd_stats_ack { + uint32_t nextStatsBuf; +}; + +#define VFE_STATS_BUFFER_COUNT 3 + +struct vfe_cmd_stats_buf { + uint32_t statsBuf[VFE_STATS_BUFFER_COUNT]; +}; + +void vfe40_subdev_notify(int id, int path, int image_mode, + struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl); +struct vfe40_output_ch *vfe40_get_ch( + int path, struct vfe_share_ctrl_t *share_ctrl); +void vfe40_send_isp_msg(struct v4l2_subdev *sd, + uint32_t vfeFrameId, uint32_t isp_msg_id); +void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl); + +static const uint32_t vfe40_AXI_WM_CFG[] = { + 0x0000006C, + 0x00000090, + 0x000000B4, + 0x000000D8, + 0x000000FC, + 0x00000120, + 0x00000144, +}; + +static struct vfe40_cmd_type vfe40_cmd[] = { +/*0*/ + {VFE_CMD_DUMMY_0}, + {VFE_CMD_SET_CLK}, + {VFE_CMD_RESET}, + {VFE_CMD_START}, + {VFE_CMD_TEST_GEN_START}, +/*5*/ + {VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN}, + {VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_OUT_OFF, 0xFF}, + {VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF}, + {VFE_CMD_AXI_INPUT_CFG}, + {VFE_CMD_BLACK_LEVEL_CFG}, +/*10*/ + {VFE_CMD_MESH_ROLL_OFF_CFG}, + {VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF}, + {VFE_CMD_FOV_CFG}, + {VFE_CMD_MAIN_SCALER_CFG}, + {VFE_CMD_WB_CFG, V40_WB_LEN, V40_WB_OFF, 0xFF}, +/*15*/ + {VFE_CMD_COLOR_COR_CFG, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF}, + {VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF}, + {VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF }, + {VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF}, + {VFE_CMD_CHROMA_SUP_CFG, V40_CHROMA_SUP_LEN, V40_CHROMA_SUP_OFF, 0xFF}, +/*20*/ + {VFE_CMD_MCE_CFG, V40_MCE_LEN, V40_MCE_OFF, 0xFF}, + {VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF}, + {VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF}, + {VFE_CMD_S2Y_CFG}, + {VFE_CMD_S2CbCr_CFG}, +/*25*/ + {VFE_CMD_CHROMA_SUBS_CFG}, + {VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF, 0xFF}, + {VFE_CMD_FRAME_SKIP_CFG}, + {VFE_CMD_DUMMY_1}, + {VFE_CMD_DUMMY_2}, +/*30*/ + {VFE_CMD_DUMMY_3}, + {VFE_CMD_UPDATE}, + {VFE_CMD_BL_LVL_UPDATE}, + {VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF}, + {VFE_CMD_FOV_UPDATE}, +/*35*/ + {VFE_CMD_MAIN_SCALER_UPDATE}, + {VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF}, + {VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN, V40_COLOR_COR_OFF, 0xFF}, + {VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF}, + {VFE_CMD_LA_UPDATE, V40_LA_LEN, V40_LA_OFF, 0xFF }, +/*40*/ + {VFE_CMD_CHROMA_EN_UPDATE, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF, 0xFF}, + {VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN, + V40_CHROMA_SUP_OFF, 0xFF}, + {VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF}, + {VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF}, + {VFE_CMD_S2CbCr_UPDATE}, +/*45*/ + {VFE_CMD_S2Y_UPDATE}, + {VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF}, + {VFE_CMD_FRAME_SKIP_UPDATE}, + {VFE_CMD_CAMIF_FRAME_UPDATE}, + {VFE_CMD_STATS_AF_UPDATE}, +/*50*/ + {VFE_CMD_STATS_AE_UPDATE}, + {VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF}, + {VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF}, + {VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF}, + {VFE_CMD_STATS_SKIN_UPDATE}, +/*55*/ + {VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF}, + {VFE_CMD_DUMMY_4}, + {VFE_CMD_EPOCH1_ACK}, + {VFE_CMD_EPOCH2_ACK}, + {VFE_CMD_START_RECORDING}, +/*60*/ + {VFE_CMD_STOP_RECORDING}, + {VFE_CMD_DUMMY_5}, + {VFE_CMD_DUMMY_6}, + {VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF}, + {VFE_CMD_DUMMY_7}, +/*65*/ + {VFE_CMD_STOP}, + {VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN, + V40_GET_HW_VERSION_OFF}, + {VFE_CMD_GET_FRAME_SKIP_COUNTS}, + {VFE_CMD_OUTPUT1_BUFFER_ENQ}, + {VFE_CMD_OUTPUT2_BUFFER_ENQ}, +/*70*/ + {VFE_CMD_OUTPUT3_BUFFER_ENQ}, + {VFE_CMD_JPEG_OUT_BUF_ENQ}, + {VFE_CMD_RAW_OUT_BUF_ENQ}, + {VFE_CMD_RAW_IN_BUF_ENQ}, + {VFE_CMD_STATS_AF_ENQ}, +/*75*/ + {VFE_CMD_STATS_AE_ENQ}, + {VFE_CMD_STATS_AWB_ENQ}, + {VFE_CMD_STATS_RS_ENQ}, + {VFE_CMD_STATS_CS_ENQ}, + {VFE_CMD_STATS_SKIN_ENQ}, +/*80*/ + {VFE_CMD_STATS_IHIST_ENQ}, + {VFE_CMD_DUMMY_8}, + {VFE_CMD_JPEG_ENC_CFG}, + {VFE_CMD_DUMMY_9}, + {VFE_CMD_STATS_AF_START}, +/*85*/ + {VFE_CMD_STATS_AF_STOP}, + {VFE_CMD_STATS_AE_START}, + {VFE_CMD_STATS_AE_STOP}, + {VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF}, + {VFE_CMD_STATS_AWB_STOP}, +/*90*/ + {VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF}, + {VFE_CMD_STATS_RS_STOP}, + {VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF}, + {VFE_CMD_STATS_CS_STOP}, + {VFE_CMD_STATS_SKIN_START}, +/*95*/ + {VFE_CMD_STATS_SKIN_STOP}, + {VFE_CMD_STATS_IHIST_START, V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF}, + {VFE_CMD_STATS_IHIST_STOP}, + {VFE_CMD_DUMMY_10}, + {VFE_CMD_SYNC_TIMER_SETTING, V40_SYNC_TIMER_LEN, V40_SYNC_TIMER_OFF}, +/*100*/ + {VFE_CMD_ASYNC_TIMER_SETTING, V40_ASYNC_TIMER_LEN, V40_ASYNC_TIMER_OFF}, + {VFE_CMD_LIVESHOT}, + {VFE_CMD_LA_SETUP}, + {VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1, + V40_LINEARIZATION_OFF1}, + {VFE_CMD_DEMOSAICV3}, +/*105*/ + {VFE_CMD_DEMOSAICV3_ABCC_CFG}, + {VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN, + V40_DEMOSAICV3_DBCC_OFF}, + {VFE_CMD_DEMOSAICV3_DBPC_CFG}, + {VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN, + V40_DEMOSAICV3_ABF_OFF}, + {VFE_CMD_DEMOSAICV3_ABCC_UPDATE}, +/*110*/ + {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN, + V40_DEMOSAICV3_DBCC_OFF}, + {VFE_CMD_DEMOSAICV3_DBPC_UPDATE}, + {VFE_CMD_XBAR_CFG}, + {VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF}, + {VFE_CMD_ZSL}, +/*115*/ + {VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1, + V40_LINEARIZATION_OFF1}, + {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN, + V40_DEMOSAICV3_ABF_OFF}, + {VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF}, + {VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN, + V40_CLF_LUMA_UPDATE_OFF}, + {VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN, + V40_CLF_CHROMA_UPDATE_OFF}, +/*120*/ + {VFE_CMD_PCA_ROLL_OFF_CFG}, + {VFE_CMD_PCA_ROLL_OFF_UPDATE}, + {VFE_CMD_GET_REG_DUMP}, + {VFE_CMD_GET_LINEARIZATON_TABLE}, + {VFE_CMD_GET_MESH_ROLLOFF_TABLE}, +/*125*/ + {VFE_CMD_GET_PCA_ROLLOFF_TABLE}, + {VFE_CMD_GET_RGB_G_TABLE}, + {VFE_CMD_GET_LA_TABLE}, + {VFE_CMD_DEMOSAICV3_UPDATE}, + {VFE_CMD_ACTIVE_REGION_CFG}, +/*130*/ + {VFE_CMD_COLOR_PROCESSING_CONFIG}, + {VFE_CMD_STATS_WB_AEC_CONFIG}, + {VFE_CMD_STATS_WB_AEC_UPDATE}, + {VFE_CMD_Y_GAMMA_CONFIG}, + {VFE_CMD_SCALE_OUTPUT1_CONFIG}, +/*135*/ + {VFE_CMD_SCALE_OUTPUT2_CONFIG}, + {VFE_CMD_CAPTURE_RAW}, + {VFE_CMD_STOP_LIVESHOT}, + {VFE_CMD_RECONFIG_VFE}, + {VFE_CMD_STATS_REQBUF}, +/*140*/ + {VFE_CMD_STATS_ENQUEUEBUF}, + {VFE_CMD_STATS_FLUSH_BUFQ}, + {VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF}, + {VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF}, + {VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN, V40_FOV_ENC_OFF, 0xFF}, +/*145*/ + {VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN, V40_FOV_VIEW_OFF, 0xFF}, + {VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN, V40_SCALER_ENC_OFF, 0xFF}, + {VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN, + V40_SCALER_VIEW_OFF, 0xFF}, + {VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN, + V40_SCALER_ENC_OFF, 0xFF}, + {VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN, + V40_SCALER_VIEW_OFF, 0xFF}, +/*150*/ + {VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN, + V40_COLORXFORM_ENC_CFG_OFF, 0xFF}, + {VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN, + V40_COLORXFORM_VIEW_CFG_OFF}, + {VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN, + V40_COLORXFORM_ENC_CFG_OFF, 0xFF}, + {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN, + V40_COLORXFORM_VIEW_CFG_OFF, 0xFF}, +}; + +#endif /* __MSM_VFE40_H__ */ diff --git a/drivers/media/video/msm/vfe/msm_vfe40_axi.c b/drivers/media/video/msm/vfe/msm_vfe40_axi.c new file mode 100644 index 00000000000..35d5207895e --- /dev/null +++ b/drivers/media/video/msm/vfe/msm_vfe40_axi.c @@ -0,0 +1,812 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm.h" +#include "msm_vfe40.h" + +static int msm_axi_subdev_s_crystal_freq(struct v4l2_subdev *sd, + u32 freq, u32 flags) +{ + int rc = 0; + int round_rate; + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + + round_rate = clk_round_rate(axi_ctrl->vfe_clk[0], freq); + if (rc < 0) { + pr_err("%s: clk_round_rate failed %d\n", + __func__, rc); + return rc; + } + + axi_ctrl->share_ctrl->vfe_clk_rate = round_rate; + rc = clk_set_rate(axi_ctrl->vfe_clk[0], round_rate); + if (rc < 0) + pr_err("%s: clk_set_rate failed %d\n", + __func__, rc); + + return rc; +} + +void axi_start(struct axi_ctrl_t *axi_ctrl) +{ + switch (axi_ctrl->share_ctrl->operation_mode) { + case VFE_OUTPUTS_PREVIEW: + case VFE_OUTPUTS_PREVIEW_AND_VIDEO: + if (axi_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY) { + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out0.ch1]); + } else if (axi_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) { + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out0.ch0]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out0.ch1]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out0.ch2]); + } + break; + default: + if (axi_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY) { + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out1.ch1]); + } else if (axi_ctrl->share_ctrl->outpath.output_mode & + VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) { + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out1.ch0]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out1.ch1]); + msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase + + vfe40_AXI_WM_CFG[axi_ctrl-> + share_ctrl->outpath.out1.ch2]); + } + break; + } +} + +void axi_stop(struct axi_ctrl_t *axi_ctrl) +{ + uint8_t axiBusyFlag = true; + /* axi halt command. */ + msm_camera_io_w(AXI_HALT, + axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD); + wmb(); + while (axiBusyFlag) { + if (msm_camera_io_r( + axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1) + axiBusyFlag = false; + } + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(AXI_HALT_CLEAR, + axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD); + + /* after axi halt, then ok to apply global reset. */ + /* enable reset_ack and async timer interrupt only while + stopping the pipeline.*/ + msm_camera_io_w(0xf0000000, + axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0); + msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1, + axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1); + + /* Ensure the write order while writing + to the command register using the barrier */ + msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD, + axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET); +} + +static int vfe40_config_axi( + struct axi_ctrl_t *axi_ctrl, int mode, uint32_t *ao) +{ + uint32_t *ch_info; + uint32_t *axi_cfg = ao; + + /* Update the corresponding write masters for each output*/ + ch_info = axi_cfg + V40_AXI_CFG_LEN; + axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info; + axi_ctrl->share_ctrl->outpath.out0.ch1 = + 0x0000FFFF & (*ch_info++ >> 16); + axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info; + axi_ctrl->share_ctrl->outpath.out0.image_mode = + 0x0000FFFF & (*ch_info++ >> 16); + axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info; + axi_ctrl->share_ctrl->outpath.out1.ch1 = + 0x0000FFFF & (*ch_info++ >> 16); + axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info; + axi_ctrl->share_ctrl->outpath.out1.image_mode = + 0x0000FFFF & (*ch_info++ >> 16); + axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info; + axi_ctrl->share_ctrl->outpath.out2.ch1 = + 0x0000FFFF & (*ch_info++ >> 16); + axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++; + + switch (mode) { + case OUTPUT_PRIM: + axi_ctrl->share_ctrl->outpath.output_mode = + VFE40_OUTPUT_MODE_PRIMARY; + break; + case OUTPUT_PRIM_ALL_CHNLS: + axi_ctrl->share_ctrl->outpath.output_mode = + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS; + break; + case OUTPUT_PRIM|OUTPUT_SEC: + axi_ctrl->share_ctrl->outpath.output_mode = + VFE40_OUTPUT_MODE_PRIMARY; + axi_ctrl->share_ctrl->outpath.output_mode |= + VFE40_OUTPUT_MODE_SECONDARY; + break; + case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS: + axi_ctrl->share_ctrl->outpath.output_mode = + VFE40_OUTPUT_MODE_PRIMARY; + axi_ctrl->share_ctrl->outpath.output_mode |= + VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS; + break; + case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC: + axi_ctrl->share_ctrl->outpath.output_mode = + VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS; + axi_ctrl->share_ctrl->outpath.output_mode |= + VFE40_OUTPUT_MODE_SECONDARY; + break; + default: + pr_err("%s Invalid AXI mode %d ", __func__, mode); + return -EINVAL; + } + msm_camera_io_w(*ao, axi_ctrl->share_ctrl->vfebase + + VFE_BUS_IO_FORMAT_CFG); + msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase + + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg, + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length - V40_AXI_CH_INF_LEN); + return 0; +} + +static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg) +{ + struct msm_vfe_cfg_cmd cfgcmd; + struct msm_isp_cmd vfecmd; + int rc = 0; + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + + if (!axi_ctrl->share_ctrl->vfebase) { + pr_err("%s: base address unmapped\n", __func__); + return -EFAULT; + } + if (NULL != arg) { + if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) { + ERR_COPY_FROM_USER(); + return -EFAULT; + } + } + if (NULL != cfgcmd.value) { + if (copy_from_user(&vfecmd, + (void __user *)(cfgcmd.value), + sizeof(vfecmd))) { + pr_err("%s %d: copy_from_user failed\n", __func__, + __LINE__); + return -EFAULT; + } + } + + switch (cfgcmd.cmd_type) { + case CMD_AXI_CFG_PRIM: { + uint32_t *axio = NULL; + axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe40_config_axi(axi_ctrl, OUTPUT_PRIM, axio); + kfree(axio); + } + break; + case CMD_AXI_CFG_PRIM_ALL_CHNLS: { + uint32_t *axio = NULL; + axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe40_config_axi(axi_ctrl, OUTPUT_PRIM_ALL_CHNLS, axio); + kfree(axio); + } + break; + case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: { + uint32_t *axio = NULL; + axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe40_config_axi(axi_ctrl, OUTPUT_PRIM|OUTPUT_SEC, axio); + kfree(axio); + } + break; + case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: { + uint32_t *axio = NULL; + axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe40_config_axi(axi_ctrl, + OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio); + kfree(axio); + } + break; + case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: { + uint32_t *axio = NULL; + axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length, + GFP_ATOMIC); + if (!axio) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(axio, (void __user *)(vfecmd.value), + vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) { + kfree(axio); + rc = -EFAULT; + break; + } + vfe40_config_axi(axi_ctrl, + OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio); + kfree(axio); + } + break; + case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS: + pr_err("%s Invalid/Unsupported AXI configuration %x", + __func__, cfgcmd.cmd_type); + break; + case CMD_AXI_START: + axi_start(axi_ctrl); + break; + case CMD_AXI_STOP: + axi_stop(axi_ctrl); + break; + default: + pr_err("%s Unsupported AXI configuration %x ", __func__, + cfgcmd.cmd_type); + break; + } + return rc; +} + +static struct msm_free_buf *vfe40_check_free_buffer( + int id, int path, struct axi_ctrl_t *axi_ctrl) +{ + struct vfe40_output_ch *outch = NULL; + struct msm_free_buf *b = NULL; + uint32_t image_mode = 0; + + if (path == VFE_MSG_OUTPUT_PRIMARY) + image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode; + else + image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode; + + vfe40_subdev_notify(id, path, image_mode, + &axi_ctrl->subdev, axi_ctrl->share_ctrl); + outch = vfe40_get_ch(path, axi_ctrl->share_ctrl); + if (outch->free_buf.ch_paddr[0]) + b = &outch->free_buf; + return b; +} + +static void vfe_send_outmsg( + struct axi_ctrl_t *axi_ctrl, uint8_t msgid, + uint32_t ch0_paddr, uint32_t ch1_paddr, + uint32_t ch2_paddr, uint32_t image_mode) +{ + struct isp_msg_output msg; + + msg.output_id = msgid; + msg.buf.image_mode = image_mode; + msg.buf.ch_paddr[0] = ch0_paddr; + msg.buf.ch_paddr[1] = ch1_paddr; + msg.buf.ch_paddr[2] = ch2_paddr; + msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId; + + v4l2_subdev_notify(&axi_ctrl->subdev, + NOTIFY_VFE_MSG_OUT, + &msg); + return; +} + +static void vfe40_process_output_path_irq_0( + struct axi_ctrl_t *axi_ctrl) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + uint8_t out_bool = 0; + struct msm_free_buf *free_buf = NULL; + + free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_PRIMARY, axi_ctrl); + + /* we render frames in the following conditions: + 1. Continuous mode and the free buffer is avaialable. + 2. In snapshot shot mode, free buffer is not always available. + when pending snapshot count is <=1, then no need to use + free buffer. + */ + out_bool = ( + (axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW || + axi_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STARTED || + axi_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STOP_REQUESTED || + axi_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STOPPED) && + (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) || + free_buf; + + if (out_bool) { + ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + + /* Channel 0*/ + ch0_paddr = vfe40_get_ch_addr( + ping_pong, axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch0); + /* Channel 1*/ + ch1_paddr = vfe40_get_ch_addr( + ping_pong, axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch1); + /* Channel 2*/ + ch2_paddr = vfe40_get_ch_addr( + ping_pong, axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch2); + + CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n", + ch0_paddr, ch1_paddr, ch2_paddr); + if (free_buf) { + /* Y channel */ + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch0, + free_buf->ch_paddr[0]); + /* Chroma channel */ + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch1, + free_buf->ch_paddr[1]); + if (free_buf->num_planes > 2) + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out0.ch2, + free_buf->ch_paddr[2]); + } + if (axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW || + axi_ctrl->share_ctrl->liveshot_state == + VFE_STATE_STOPPED) + axi_ctrl->share_ctrl->outpath.out0.capture_cnt--; + + vfe_send_outmsg(axi_ctrl, + MSG_ID_OUTPUT_PRIMARY, ch0_paddr, + ch1_paddr, ch2_paddr, + axi_ctrl->share_ctrl->outpath.out0.image_mode); + + if (axi_ctrl->share_ctrl->liveshot_state == VFE_STATE_STOPPED) + axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE; + + } else { + axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++; + CDBG("path_irq_0 - no free buffer!\n"); + } +} + +static void vfe40_process_output_path_irq_1( + struct axi_ctrl_t *axi_ctrl) +{ + uint32_t ping_pong; + uint32_t ch0_paddr, ch1_paddr, ch2_paddr; + /* this must be snapshot main image output. */ + uint8_t out_bool = 0; + struct msm_free_buf *free_buf = NULL; + + free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ, + VFE_MSG_OUTPUT_SECONDARY, axi_ctrl); + out_bool = ((axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB) && + (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) || + free_buf; + + if (out_bool) { + ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase + + VFE_BUS_PING_PONG_STATUS); + + /* Y channel */ + ch0_paddr = vfe40_get_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch0); + /* Chroma channel */ + ch1_paddr = vfe40_get_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch1); + ch2_paddr = vfe40_get_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch2); + + CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n", + __func__, ch0_paddr, ch1_paddr, ch2_paddr); + if (free_buf) { + /* Y channel */ + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch0, + free_buf->ch_paddr[0]); + /* Chroma channel */ + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch1, + free_buf->ch_paddr[1]); + if (free_buf->num_planes > 2) + vfe40_put_ch_addr(ping_pong, + axi_ctrl->share_ctrl->vfebase, + axi_ctrl->share_ctrl->outpath.out1.ch2, + free_buf->ch_paddr[2]); + } + if (axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB) + axi_ctrl->share_ctrl->outpath.out1.capture_cnt--; + + vfe_send_outmsg(axi_ctrl, + MSG_ID_OUTPUT_SECONDARY, ch0_paddr, + ch1_paddr, ch2_paddr, + axi_ctrl->share_ctrl->outpath.out1.image_mode); + + } else { + axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++; + CDBG("path_irq_1 - no free buffer!\n"); + } +} + +static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg) +{ + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + uint32_t irqstatus = (uint32_t) arg; + + if (!axi_ctrl->share_ctrl->vfebase) { + pr_err("%s: base address unmapped\n", __func__); + return; + } + /* next, check output path related interrupts. */ + if (irqstatus & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) { + CDBG("Image composite done 0 irq occured.\n"); + vfe40_process_output_path_irq_0(axi_ctrl); + } + if (irqstatus & + VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) { + CDBG("Image composite done 1 irq occured.\n"); + vfe40_process_output_path_irq_1(axi_ctrl); + } + /* in snapshot mode if done then send + snapshot done message */ + if (axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_MAIN || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_MAIN_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_THUMB_AND_JPEG || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_JPEG_AND_THUMB || + axi_ctrl->share_ctrl->operation_mode == + VFE_OUTPUTS_RAW) { + if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0) + && (axi_ctrl->share_ctrl->outpath.out1. + capture_cnt == 0)) { + msm_camera_io_w_mb( + CAMIF_COMMAND_STOP_IMMEDIATELY, + axi_ctrl->share_ctrl->vfebase + + VFE_CAMIF_COMMAND); + vfe40_send_isp_msg(&axi_ctrl->subdev, + axi_ctrl->share_ctrl->vfeFrameId, + MSG_ID_SNAPSHOT_DONE); + } + } +} + +static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg) +{ + struct msm_camvfe_params *vfe_params = + (struct msm_camvfe_params *)arg; + struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg; + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + void *data = vfe_params->data; + int rc = 0; + + if (!axi_ctrl->share_ctrl->vfebase) { + pr_err("%s: base address unmapped\n", __func__); + return -EFAULT; + } + + switch (cmd->cmd_type) { + case CMD_CONFIG_PING_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, axi_ctrl->share_ctrl); + outch->ping = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_PONG_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, axi_ctrl->share_ctrl); + outch->pong = *((struct msm_free_buf *)data); + } + break; + + case CMD_CONFIG_FREE_BUF_ADDR: { + int path = *((int *)cmd->value); + struct vfe40_output_ch *outch = + vfe40_get_ch(path, axi_ctrl->share_ctrl); + outch->free_buf = *((struct msm_free_buf *)data); + } + break; + default: + pr_err("%s Unsupported AXI Buf config %x ", __func__, + cmd->cmd_type); + } + return rc; +}; + +static struct msm_cam_clk_info vfe40_clk_info[] = { + {"vfe_clk_src", 266670000}, + {"camss_vfe_vfe_clk", -1}, + {"camss_csi_vfe_clk", -1}, + {"top_clk", -1}, + {"iface_clk", -1}, + {"bus_clk", -1}, +}; + +int msm_axi_subdev_init(struct v4l2_subdev *sd, + struct msm_cam_media_controller *mctl) +{ + int rc = 0; + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + v4l2_set_subdev_hostdata(sd, mctl); + spin_lock_init(&axi_ctrl->tasklet_lock); + INIT_LIST_HEAD(&axi_ctrl->tasklet_q); + spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock); + + axi_ctrl->share_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start, + resource_size(axi_ctrl->vfemem)); + if (!axi_ctrl->share_ctrl->vfebase) { + rc = -ENOMEM; + pr_err("%s: vfe ioremap failed\n", __func__); + goto remap_failed; + } + + if (axi_ctrl->fs_vfe == NULL) { + axi_ctrl->fs_vfe = + regulator_get(&axi_ctrl->pdev->dev, "vdd"); + if (IS_ERR(axi_ctrl->fs_vfe)) { + pr_err("%s: Regulator FS_VFE get failed %ld\n", + __func__, PTR_ERR(axi_ctrl->fs_vfe)); + axi_ctrl->fs_vfe = NULL; + goto fs_failed; + } else if (regulator_enable(axi_ctrl->fs_vfe)) { + pr_err("%s: Regulator FS_VFE enable failed\n", + __func__); + regulator_put(axi_ctrl->fs_vfe); + axi_ctrl->fs_vfe = NULL; + goto fs_failed; + } + } + rc = msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info, + axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 1); + if (rc < 0) + goto clk_enable_failed; + + msm_camio_bus_scale_cfg( + mctl->sdata->pdata->cam_bus_scale_table, S_INIT); + msm_camio_bus_scale_cfg( + mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW); + + axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL; + + enable_irq(axi_ctrl->vfeirq->start); + + return rc; +clk_enable_failed: + regulator_disable(axi_ctrl->fs_vfe); + regulator_put(axi_ctrl->fs_vfe); + axi_ctrl->fs_vfe = NULL; +fs_failed: + iounmap(axi_ctrl->share_ctrl->vfebase); + axi_ctrl->share_ctrl->vfebase = NULL; +remap_failed: + disable_irq(axi_ctrl->vfeirq->start); + return rc; +} + +void msm_axi_subdev_release(struct v4l2_subdev *sd) +{ + struct msm_cam_media_controller *pmctl = + (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd); + struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd); + if (!axi_ctrl->share_ctrl->vfebase) { + pr_err("%s: base address unmapped\n", __func__); + return; + } + + CDBG("%s, free_irq\n", __func__); + disable_irq(axi_ctrl->vfeirq->start); + tasklet_kill(&axi_ctrl->vfe40_tasklet); + msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info, + axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0); + + if (axi_ctrl->fs_vfe) { + regulator_disable(axi_ctrl->fs_vfe); + regulator_put(axi_ctrl->fs_vfe); + axi_ctrl->fs_vfe = NULL; + } + iounmap(axi_ctrl->share_ctrl->vfebase); + axi_ctrl->share_ctrl->vfebase = NULL; + + if (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) + pr_warning("%s, Warning IRQ Count not ZERO\n", __func__); + + msm_camio_bus_scale_cfg( + pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT); +} + +static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = -ENOIOCTLCMD; + switch (cmd) { + case VIDIOC_MSM_AXI_INIT: + rc = msm_axi_subdev_init(sd, + (struct msm_cam_media_controller *)arg); + break; + case VIDIOC_MSM_AXI_CFG: + rc = msm_axi_config(sd, arg); + break; + case VIDIOC_MSM_AXI_IRQ: + msm_axi_process_irq(sd, arg); + rc = 0; + break; + case VIDIOC_MSM_AXI_BUF_CFG: + msm_axi_buf_cfg(sd, arg); + rc = 0; + break; + case VIDIOC_MSM_AXI_RELEASE: + msm_axi_subdev_release(sd); + rc = 0; + break; + default: + pr_err("%s: command not found\n", __func__); + } + return rc; +} + +static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = { + .ioctl = msm_axi_subdev_ioctl, +}; + +static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = { + .s_crystal_freq = msm_axi_subdev_s_crystal_freq, +}; + +static const struct v4l2_subdev_ops msm_axi_subdev_ops = { + .core = &msm_axi_subdev_core_ops, + .video = &msm_axi_subdev_video_ops, +}; + +static const struct v4l2_subdev_internal_ops msm_axi_internal_ops; + +void vfe40_axi_probe(struct axi_ctrl_t *axi_ctrl) +{ + struct msm_cam_subdev_info sd_info; + v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops); + axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops; + axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(axi_ctrl->subdev.name, + sizeof(axi_ctrl->subdev.name), "axi"); + v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl); + + sd_info.sdev_type = AXI_DEV; + sd_info.sd_index = axi_ctrl->pdev->id; + sd_info.irq_num = 0; + msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info); +} diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h index f8dbed98417..9fa59329cb3 100644 --- a/include/media/msm_isp.h +++ b/include/media/msm_isp.h @@ -220,6 +220,19 @@ #define VFE_CMD_STATS_BHIST_START 147 #define VFE_CMD_STATS_BHIST_STOP 148 #define VFE_CMD_RESET_2 149 +#define VFE_CMD_FOV_ENC_CFG 150 +#define VFE_CMD_FOV_VIEW_CFG 151 +#define VFE_CMD_FOV_ENC_UPDATE 152 +#define VFE_CMD_FOV_VIEW_UPDATE 153 +#define VFE_CMD_SCALER_ENC_CFG 154 +#define VFE_CMD_SCALER_VIEW_CFG 155 +#define VFE_CMD_SCALER_ENC_UPDATE 156 +#define VFE_CMD_SCALER_VIEW_UPDATE 157 +#define VFE_CMD_COLORXFORM_ENC_CFG 158 +#define VFE_CMD_COLORXFORM_VIEW_CFG 159 +#define VFE_CMD_COLORXFORM_ENC_UPDATE 160 +#define VFE_CMD_COLORXFORM_VIEW_UPDATE 161 +#define VFE_CMD_TEST_GEN_CFG 162 struct msm_isp_cmd { int32_t id;