diff options
| author | Shubhraprakash Das <sadas@codeaurora.org> | 2016-08-16 10:55:11 -0700 |
|---|---|---|
| committer | Shubhraprakash Das <sadas@codeaurora.org> | 2016-08-19 16:51:57 -0700 |
| commit | f6cb7eca5aed4a8810a14d34ccd2a7e4d4d46a64 (patch) | |
| tree | 62fbd8ab7985828d546c952f4912ca63bacb8a4a | |
| parent | 26ea3057fcae3aa5bf9cfcb37d1487a7220c173c (diff) | |
msm: camera: isp: Use single stream for dual vfe
Restructure code to handle dual vfe cases in a more streamline
manner. Instead of using 2 streams in case of dual vfe only
1 stream is used and the vfe devices are added under the
stream. All stream operations that refer to vfe will operate
on all the vfe devices present under stream. It is now not
nessasary to check whether dual vfe is used in multiple places
to decide which hardware needs to be updated, instead just
loop through the list of vfe hardware under the stream
Change-Id: I40ba5c9fe8bf96f81fc5256042b4a70731520e1d
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
16 files changed, 3084 insertions, 2377 deletions
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c index d802e4909322..4200215705d0 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c @@ -654,95 +654,35 @@ static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr, return rc; } -static int msm_isp_update_put_buf_cnt_unsafe( - struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) +static int msm_isp_buf_divert(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id) { - int rc = -1; + unsigned long flags; struct msm_isp_bufq *bufq = NULL; struct msm_isp_buffer *buf_info = NULL; - uint8_t *put_buf_mask = NULL; bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); if (!bufq) { pr_err("Invalid bufq\n"); - return rc; - } - - put_buf_mask = &bufq->put_buf_mask[pingpong_bit]; - - if (buf_index >= 0) { - buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); - if (!buf_info) { - pr_err("%s: buf not found\n", __func__); - return -EFAULT; - } - if (buf_info->state != MSM_ISP_BUFFER_STATE_DEQUEUED) { - pr_err( - "%s: Invalid state, bufq_handle %x stream id %x, state %d\n", - __func__, bufq_handle, - bufq->stream_id, buf_info->state); - return -EFAULT; - } - if (buf_info->pingpong_bit != pingpong_bit) { - pr_err("%s: Pingpong bit mismatch\n", __func__); - return -EFAULT; - } - } - - if (bufq->buf_type != ISP_SHARE_BUF || - (*put_buf_mask == 0)) { - if (buf_info) - buf_info->frame_id = frame_id; - } - - if (bufq->buf_type == ISP_SHARE_BUF && - ((*put_buf_mask & (1 << id)) == 0)) { - *put_buf_mask |= (1 << id); - if (*put_buf_mask != ISP_SHARE_BUF_MASK) { - rc = *put_buf_mask; - return 1; - } - *put_buf_mask = 0; - rc = 0; - } else if (bufq->buf_type == ISP_SHARE_BUF && - (*put_buf_mask & (1 << id)) != 0) { - return -ENOTEMPTY; - } - - if (buf_info && - MSM_ISP_BUFFER_SRC_NATIVE == BUF_SRC(bufq->stream_id)) { - buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; - buf_info->tv = tv; + return -EINVAL; } - return 0; -} -static int msm_isp_update_put_buf_cnt(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit) -{ - int rc = -1; - struct msm_isp_bufq *bufq = NULL; - unsigned long flags; - - bufq = msm_isp_get_bufq(buf_mgr, bufq_handle); - if (!bufq) { - pr_err("Invalid bufq\n"); - return rc; + buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index); + if (!buf_info) { + pr_err("%s: buf not found\n", __func__); + return -EINVAL; } spin_lock_irqsave(&bufq->bufq_lock, flags); - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, id, bufq_handle, - buf_index, tv, frame_id, pingpong_bit); - if (-ENOTEMPTY == rc) { - pr_err("%s: Error! Uncleared put_buf_mask for pingpong(%d) from vfe %d bufq 0x%x buf_idx %d\n", - __func__, pingpong_bit, id, bufq_handle, buf_index); - rc = -EFAULT; + + buf_info->frame_id = frame_id; + if (BUF_SRC(bufq->stream_id) == MSM_ISP_BUFFER_SRC_NATIVE) { + buf_info->state = MSM_ISP_BUFFER_STATE_DIVERTED; + buf_info->tv = tv; } spin_unlock_irqrestore(&bufq->bufq_lock, flags); - return rc; + return 0; } static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr, @@ -800,11 +740,11 @@ done: return rc; } -static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, +static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, struct timeval *tv, uint32_t frame_id) { - int rc = 0, i; + int i; struct msm_isp_bufq *bufq = NULL; struct msm_isp_buffer *buf_info = NULL; unsigned long flags; @@ -822,43 +762,27 @@ static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, pr_err("%s: buf not found\n", __func__); continue; } - if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED && - buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { + switch (flush_type) { + case MSM_ISP_BUFFER_FLUSH_DIVERTED: + if (buf_info->state != + MSM_ISP_BUFFER_STATE_DIVERTED) + continue; buf_info->state = MSM_ISP_BUFFER_STATE_PREPARED; msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - } else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL) { - if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) { - CDBG("%s: no need to queue Diverted buffer\n", - __func__); - } else if (buf_info->state == - MSM_ISP_BUFFER_STATE_DEQUEUED) { - rc = msm_isp_update_put_buf_cnt_unsafe(buf_mgr, - id, bufq_handle, buf_info->buf_idx, tv, - frame_id, buf_info->pingpong_bit); - if (-ENOTEMPTY == rc) { - rc = 0; - continue; - } - - if (rc == 0) { - buf_info->buf_debug.put_state[ - buf_info->buf_debug. - put_state_last] - = MSM_ISP_BUFFER_STATE_FLUSH; - buf_info->buf_debug.put_state_last ^= 1; - buf_info->state = - MSM_ISP_BUFFER_STATE_PREPARED; - rc = msm_isp_put_buf_unsafe(buf_mgr, - bufq_handle, buf_info->buf_idx); - if (rc == -EFAULT) { - spin_unlock_irqrestore( - &bufq->bufq_lock, - flags); - return rc; - } - } - } + bufq_handle, buf_info->buf_idx); + break; + case MSM_ISP_BUFFER_FLUSH_ALL: + if (buf_info->state == + MSM_ISP_BUFFER_STATE_DIVERTED) + continue; + if (buf_info->state != + MSM_ISP_BUFFER_STATE_DEQUEUED) + continue; + msm_isp_put_buf_unsafe(buf_mgr, + bufq_handle, buf_info->buf_idx); + break; + default: + WARN(1, "Invalid flush type %d\n", flush_type); } } @@ -1036,8 +960,6 @@ static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr, bufq->stream_id = buf_request->stream_id; bufq->num_bufs = buf_request->num_buf; bufq->buf_type = buf_request->buf_type; - for (i = 0; i < ISP_NUM_BUF_MASK; i++) - bufq->put_buf_mask[i] = 0; INIT_LIST_HEAD(&bufq->head); for (i = 0; i < buf_request->num_buf; i++) { @@ -1453,7 +1375,7 @@ static struct msm_isp_buf_ops isp_buf_ops = { .buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr, .buf_mgr_debug = msm_isp_buf_mgr_debug, .get_bufq = msm_isp_get_bufq, - .update_put_buf_cnt = msm_isp_update_put_buf_cnt, + .buf_divert = msm_isp_buf_divert, }; int msm_isp_create_isp_buf_mgr( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h index 4dbc5b60c329..43519ee74062 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h @@ -117,7 +117,6 @@ struct msm_isp_bufq { enum msm_isp_buf_type buf_type; struct msm_isp_buffer *bufs; spinlock_t bufq_lock; - uint8_t put_buf_mask[ISP_NUM_BUF_MASK]; /*Native buffer queue*/ struct list_head head; }; @@ -157,7 +156,7 @@ struct msm_isp_buf_ops { int (*put_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, uint32_t buf_index); - int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t id, + int (*flush_buf)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle, enum msm_isp_buffer_flush_t flush_type, struct timeval *tv, uint32_t frame_id); @@ -174,9 +173,9 @@ struct msm_isp_buf_ops { unsigned long fault_addr); struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr, uint32_t bufq_handle); - int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr, - uint32_t id, uint32_t bufq_handle, int32_t buf_index, - struct timeval *tv, uint32_t frame_id, uint32_t pingpong_bit); + int (*buf_divert)(struct msm_isp_buf_mgr *buf_mgr, + uint32_t bufq_handle, uint32_t buf_index, + struct timeval *tv, uint32_t frame_id); }; struct msm_isp_buf_mgr { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index d3c2d77b0107..094996b2d60b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -498,7 +498,12 @@ static int vfe_probe(struct platform_device *pdev) vfe_parent_dev->common_sd->common_data = &vfe_common_data; memset(&vfe_common_data, 0, sizeof(vfe_common_data)); + mutex_init(&vfe_common_data.vfe_common_mutex); spin_lock_init(&vfe_common_data.common_dev_data_lock); + for (i = 0; i < (VFE_AXI_SRC_MAX * MAX_VFE); i++) + spin_lock_init(&(vfe_common_data.streams[i].lock)); + for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++) + spin_lock_init(&(vfe_common_data.stats_streams[i].lock)); of_property_read_u32(pdev->dev.of_node, "num_child", &vfe_parent_dev->num_hw_sd); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index f5be78313024..3b6a2eecb4b6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -169,7 +169,7 @@ struct msm_vfe_axi_ops { int32_t (*cfg_io_format)(struct vfe_device *vfe_dev, enum msm_vfe_axi_stream_src stream_src, uint32_t io_format); - void (*cfg_framedrop)(void __iomem *vfe_base, + void (*cfg_framedrop)(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period); void (*clear_framedrop)(struct vfe_device *vfe_dev, @@ -207,7 +207,7 @@ struct msm_vfe_axi_ops { uint32_t (*get_comp_mask)(uint32_t irq_status0, uint32_t irq_status1); uint32_t (*get_pingpong_status)(struct vfe_device *vfe_dev); int (*halt)(struct vfe_device *vfe_dev, uint32_t blocking); - int (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, + void (*restart)(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif); void (*update_cgc_override)(struct vfe_device *vfe_dev, uint8_t wm_idx, uint8_t cgc_override); @@ -270,7 +270,7 @@ struct msm_vfe_stats_ops { void (*enable_module)(struct vfe_device *vfe_dev, uint32_t stats_mask, uint8_t enable); - void (*update_ping_pong_addr)(void __iomem *vfe_base, + void (*update_ping_pong_addr)(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr); @@ -373,12 +373,6 @@ enum msm_vfe_axi_state { UPDATING, }; -enum msm_vfe_axi_cfg_update_state { - NO_AXI_CFG_UPDATE, - APPLYING_UPDATE_RESUME, - UPDATE_REQUESTED, -}; - #define VFE_NO_DROP 0xFFFFFFFF #define VFE_DROP_EVERY_2FRAME 0x55555555 #define VFE_DROP_EVERY_4FRAME 0x11111111 @@ -398,6 +392,14 @@ struct msm_vfe_frame_request_queue { uint8_t cmd_used; }; +enum msm_isp_comp_irq_types { + MSM_ISP_COMP_IRQ_REG_UPD = 0, + MSM_ISP_COMP_IRQ_EPOCH = 1, + MSM_ISP_COMP_IRQ_PING_BUFDONE = 2, + MSM_ISP_COMP_IRQ_PONG_BUFDONE = 3, + MSM_ISP_COMP_IRQ_MAX = 4 +}; + #define MSM_VFE_REQUESTQ_SIZE 8 struct msm_vfe_axi_stream { @@ -405,10 +407,10 @@ struct msm_vfe_axi_stream { enum msm_vfe_axi_state state; enum msm_vfe_axi_stream_src stream_src; uint8_t num_planes; - uint8_t wm[MAX_PLANES_PER_STREAM]; + uint8_t wm[MAX_VFE][MAX_PLANES_PER_STREAM]; uint32_t output_format;/*Planar/RAW/Misc*/ - struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM]; - uint8_t comp_mask_index; + struct msm_vfe_axi_plane_cfg plane_cfg[MAX_VFE][MAX_PLANES_PER_STREAM]; + uint8_t comp_mask_index[MAX_VFE]; struct msm_isp_buffer *buf[2]; uint32_t session_id; uint32_t stream_id; @@ -420,7 +422,7 @@ struct msm_vfe_axi_stream { struct list_head request_q; struct msm_vfe_frame_request_queue request_queue_cmd[MSM_VFE_REQUESTQ_SIZE]; - uint32_t stream_handle; + uint32_t stream_handle[MAX_VFE]; uint8_t buf_divert; enum msm_vfe_axi_stream_type stream_type; uint32_t frame_based; @@ -433,16 +435,28 @@ struct msm_vfe_axi_stream { spinlock_t lock; /*Bandwidth calculation info*/ - uint32_t max_width; + uint32_t max_width[MAX_VFE]; /*Based on format plane size in Q2. e.g NV12 = 1.5*/ uint32_t format_factor; - uint32_t bandwidth; + uint32_t bandwidth[MAX_VFE]; uint32_t runtime_num_burst_capture; uint32_t runtime_output_format; enum msm_stream_memory_input_t memory_input; struct msm_isp_sw_framskip sw_skip; uint8_t sw_ping_pong_bit; + + struct vfe_device *vfe_dev[MAX_VFE]; + int num_isp; + struct completion active_comp; + struct completion inactive_comp; + uint32_t update_vfe_mask; + /* + * bits in this mask are set that correspond to vfe_id of + * the vfe on which this stream operates + */ + uint32_t vfe_mask; + uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; }; struct msm_vfe_axi_composite_info { @@ -451,17 +465,15 @@ struct msm_vfe_axi_composite_info { }; enum msm_vfe_camif_state { - CAMIF_STOPPED, CAMIF_ENABLE, CAMIF_DISABLE, - CAMIF_STOPPING, }; struct msm_vfe_src_info { uint32_t frame_id; uint32_t reg_update_frame_id; uint8_t active; - uint8_t pix_stream_count; + uint8_t stream_count; uint8_t raw_stream_count; enum msm_vfe_inputmux input_mux; uint32_t width; @@ -492,7 +504,6 @@ enum msm_wm_ub_cfg_type { struct msm_vfe_axi_shared_data { struct msm_vfe_axi_hardware_info *hw_info; - struct msm_vfe_axi_stream stream_info[VFE_AXI_SRC_MAX]; uint32_t free_wm[MAX_NUM_WM]; uint32_t wm_image_size[MAX_NUM_WM]; enum msm_wm_ub_cfg_type wm_ub_cfg_policy; @@ -504,14 +515,11 @@ struct msm_vfe_axi_shared_data { struct msm_vfe_axi_composite_info composite_info[MAX_NUM_COMPOSITE_MASK]; uint8_t num_used_composite_mask; - uint32_t stream_update[VFE_SRC_MAX]; atomic_t axi_cfg_update[VFE_SRC_MAX]; - enum msm_isp_camif_update_state pipeline_update; struct msm_vfe_src_info src_info[VFE_SRC_MAX]; uint16_t stream_handle_cnt; uint32_t event_mask; uint8_t enable_frameid_recovery; - enum msm_vfe_camif_state camif_state; }; struct msm_vfe_stats_hardware_info { @@ -523,7 +531,7 @@ struct msm_vfe_stats_hardware_info { }; enum msm_vfe_stats_state { - STATS_AVALIABLE, + STATS_AVAILABLE, STATS_INACTIVE, STATS_ACTIVE, STATS_START_PENDING, @@ -535,7 +543,7 @@ enum msm_vfe_stats_state { struct msm_vfe_stats_stream { uint32_t session_id; uint32_t stream_id; - uint32_t stream_handle; + uint32_t stream_handle[MAX_VFE]; uint32_t composite_flag; enum msm_isp_stats_type stats_type; enum msm_vfe_stats_state state; @@ -545,17 +553,27 @@ struct msm_vfe_stats_stream { uint32_t init_stats_frame_drop; struct msm_isp_sw_framskip sw_skip; - uint32_t buffer_offset; + uint32_t buffer_offset[MAX_VFE]; struct msm_isp_buffer *buf[2]; uint32_t bufq_handle; + + spinlock_t lock; + struct vfe_device *vfe_dev[MAX_VFE]; + int num_isp; + struct completion active_comp; + struct completion inactive_comp; + /* + * bits in this mask are set that correspond to vfe_id of + * the vfe on which this stream operates + */ + uint32_t vfe_mask; + uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; }; struct msm_vfe_stats_shared_data { - struct msm_vfe_stats_stream stream_info[MSM_ISP_STATS_MAX]; uint8_t num_active_stream; atomic_t stats_comp_mask[MAX_NUM_STATS_COMP_MASK]; uint16_t stream_handle_cnt; - atomic_t stats_update; }; struct msm_vfe_tasklet_queue_cmd { @@ -654,7 +672,6 @@ struct dual_vfe_resource { struct msm_vfe_stats_shared_data *stats_data[MAX_VFE]; struct msm_vfe_axi_shared_data *axi_data[MAX_VFE]; uint32_t wm_reload_mask[MAX_VFE]; - uint32_t epoch_sync_mask; }; struct master_slave_resource_info { @@ -672,6 +689,9 @@ struct msm_vfe_common_dev_data { spinlock_t common_dev_data_lock; struct dual_vfe_resource *dual_vfe_res; struct master_slave_resource_info ms_resource; + struct msm_vfe_axi_stream streams[VFE_AXI_SRC_MAX * MAX_VFE]; + struct msm_vfe_stats_stream stats_streams[MSM_ISP_STATS_MAX * MAX_VFE]; + struct mutex vfe_common_mutex; }; struct msm_vfe_common_subdev { @@ -714,8 +734,6 @@ struct vfe_device { /* Sync variables*/ struct completion reset_complete; struct completion halt_complete; - struct completion stream_config_complete; - struct completion stats_config_complete; struct mutex realtime_mutex; struct mutex core_mutex; spinlock_t shared_data_lock; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c index 9481bede6417..8b5a3d8d508d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c @@ -412,10 +412,9 @@ static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev, ISP_DBG("%s: SOF IRQ\n", __func__); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0, ts); msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); } } @@ -608,15 +607,14 @@ static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev, if ((rdi_status & BIT(7)) && (!(irq_status0 & 0x20))) return; } - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); } for (i = VFE_RAW_0; i <= VFE_RAW_2; i++) { if (irq_status1 & BIT(26 + (i - VFE_RAW_0))) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); + msm_isp_axi_stream_update(vfe_dev, i, ts); msm_isp_update_framedrop_reg(vfe_dev, i); vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, @@ -693,8 +691,9 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + stream_info->comp_mask_index[vfe_idx]; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -711,7 +710,9 @@ static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe32_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index = + stream_info->comp_mask_index[vfe_idx]; uint32_t irq_mask; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x34); @@ -727,8 +728,10 @@ static void msm_vfe32_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(stream_info->wm[0] + 6); + irq_mask |= BIT(stream_info->wm[vfe_idx][0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } @@ -736,15 +739,19 @@ static void msm_vfe32_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t irq_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask &= ~BIT(stream_info->wm[0] + 6); + irq_mask &= ~BIT(stream_info->wm[vfe_idx][0] + 6); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); } -static void msm_vfe32_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe32_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; + if (stream_info->stream_src == PIX_ENCODER) { msm_camera_io_w(framedrop_period - 1, vfe_base + 0x504); msm_camera_io_w(framedrop_period - 1, vfe_base + 0x508); @@ -929,7 +936,7 @@ static void msm_vfe32_update_camif_state( VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data.src_info[ - VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + VFE_PIX_0].stream_count > 0) ? 1 : 0); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4); @@ -971,16 +978,17 @@ static void msm_vfe32_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (!stream_info->frame_based) { /*WR_IMAGE_SIZE*/ val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); @@ -988,9 +996,9 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } else { @@ -998,9 +1006,9 @@ static void msm_vfe32_axi_cfg_wm_reg( val = msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1) << 4 | VFE32_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); } @@ -1012,7 +1020,8 @@ static void msm_vfe32_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_IMAGE_SIZE*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10); /*WR_BUFFER_CFG*/ @@ -1024,9 +1033,10 @@ static void msm_vfe32_axi_cfg_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + &stream_info->plane_cfg[vfe_idx][plane_idx]; + uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; @@ -1080,7 +1090,8 @@ static void msm_vfe32_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm = stream_info->wm[vfe_idx][plane_idx]; uint32_t xbar_reg_cfg = 0; xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_XBAR_BASE(wm)); @@ -1098,6 +1109,7 @@ static void msm_vfe32_cfg_axi_ub_equal_default(struct vfe_device *vfe_dev) uint32_t prop_size = 0; uint32_t wm_ub_size; uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (axi_data->free_wm[i] > 0) { num_used_wms++; @@ -1243,9 +1255,11 @@ static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t irq_mask; irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C); - irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13); + irq_mask |= BIT(STATS_IDX(stream_info->stream_handle[vfe_idx]) + 13); msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C); return; } @@ -1342,12 +1356,15 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev, msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10); } -static void msm_vfe32_stats_update_ping_pong_addr(void __iomem *vfe_base, +static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index d42ada769380..a2aa2983b056 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -599,7 +599,6 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, return; /* Shift status bits so that PIX REG UPDATE is 1st bit */ shift_irq = ((irq_status0 & 0xF0) >> 4); - for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { if (shift_irq & BIT(i)) { reg_updated |= BIT(i); @@ -607,15 +606,17 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, (uint32_t)BIT(i)); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i]. + raw_stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -624,29 +625,22 @@ static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is also epoch for RDI */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -695,7 +689,9 @@ static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x378); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378); @@ -713,16 +709,18 @@ static void msm_vfe40_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { ISP_DBG("%s: SOF IRQ\n", __func__); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -791,8 +789,10 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -807,8 +807,11 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; - vfe_dev->irq0_mask &= ~BIT(27); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; + vfe_dev->irq0_mask &= ~BIT(27); comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -821,32 +824,38 @@ static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[vfe_idx][0] + 8)); + msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe40_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe40_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE40_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } msm_camera_io_w_mb(0x1, vfe_base + 0x378); @@ -856,9 +865,11 @@ static void msm_vfe40_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE40_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE40_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe40_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1374,7 +1385,7 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1443,7 +1454,10 @@ static void msm_vfe40_axi_cfg_wm_reg( { uint32_t val; uint32_t burst_len, wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION || vfe_dev->vfe_hw_version == VFE40_8939_VERSION) { @@ -1468,18 +1482,18 @@ static void msm_vfe40_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /*WR_BUFFER_CFG*/ val = msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_stride) << 16 | - (stream_info->plane_cfg[ + (stream_info->plane_cfg[vfe_idx][ plane_idx].output_height - 1) << wm_bit_shift | burst_len; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1487,9 +1501,9 @@ static void msm_vfe40_axi_cfg_wm_reg( msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); val = msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_width) << 16 | - (stream_info->plane_cfg[ + (stream_info->plane_cfg[vfe_idx][ plane_idx].output_height - 1) << 4 | burst_len; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1507,7 +1521,10 @@ static void msm_vfe40_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE40_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); /*WR_IMAGE_SIZE*/ @@ -1524,12 +1541,15 @@ static void msm_vfe40_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_ENCODER: case PIX_VIEWFINDER: { @@ -1584,9 +1604,12 @@ static void msm_vfe40_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE40_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE40_XBAR_SHIFT(wm)); @@ -1714,6 +1737,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe40_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1722,30 +1746,16 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24); + + msm_isp_get_timestamp(&ts); /* if any stream is waiting for update, signal complete */ for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); if (blocking) { init_completion(&vfe_dev->halt_complete); @@ -1764,7 +1774,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, return rc; } -static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe40_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1786,8 +1796,6 @@ static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe40_get_wm_mask( @@ -1903,27 +1911,37 @@ static void msm_vfe40_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe40_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 16), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe40_config_irq(vfe_dev, - (1 << (STATS_IDX(stream_info->stream_handle) + 16)), 0, - MSM_ISP_IRQ_DISABLE); + (1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 16)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe40_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE40_STATS_BASE(stats_idx); /*WR_ADDR_CFG*/ msm_camera_io_w(stream_info->framedrop_period << 2, vfe_dev->vfe_base + stats_base + 0x8); @@ -1939,9 +1957,14 @@ static void msm_vfe40_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE40_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE40_STATS_BASE(stats_idx); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x8); @@ -2095,11 +2118,16 @@ static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev, } static void msm_vfe40_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE40_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index 388656b9ca30..c77eff66ccca 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -437,15 +437,17 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, (uint32_t)BIT(i)); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i]. + raw_stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -454,29 +456,22 @@ static void msm_vfe44_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is epoch for rdi */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -498,17 +493,19 @@ static void msm_vfe44_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { ISP_DBG("%s: SOF IRQ\n", __func__); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update( + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } } @@ -550,7 +547,9 @@ static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x378); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378); @@ -628,8 +627,10 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -644,7 +645,10 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -657,31 +661,38 @@ static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe44_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe44_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE44_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } } @@ -689,9 +700,11 @@ static void msm_vfe44_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE44_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE44_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe44_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1039,7 +1052,7 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x2F8); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1101,7 +1114,10 @@ static void msm_vfe44_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); if (!stream_info->frame_based) { msm_camera_io_w(0x0, vfe_dev->vfe_base + wm_base); @@ -1109,28 +1125,30 @@ static void msm_vfe44_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+1)/2 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /*WR_BUFFER_CFG*/ - val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1); val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); val = val << 2 | msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_stride) << 16 | VFE44_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); } else { msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base); - val = (stream_info->plane_cfg[plane_idx].output_height - 1); + val = (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1); val = (((val & 0xfff) << 2) | ((val >> 12) & 0x3)); val = val << 2 | msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[ + stream_info->plane_cfg[vfe_idx][ plane_idx].output_width) << 16 | VFE44_BURST_LEN; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); @@ -1147,8 +1165,10 @@ static void msm_vfe44_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE44_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE44_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /*WR_ADDR_CFG*/ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); /*WR_IMAGE_SIZE*/ @@ -1164,12 +1184,15 @@ static void msm_vfe44_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_ENCODER: case PIX_VIEWFINDER: { @@ -1223,9 +1246,12 @@ static void msm_vfe44_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE44_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE44_XBAR_SHIFT(wm)); @@ -1245,6 +1271,7 @@ static void msm_vfe44_cfg_axi_ub_equal_default( uint32_t prop_size = 0; uint32_t wm_ub_size; uint64_t delta; + for (i = 0; i < axi_data->hw_info->num_wm; i++) { if (axi_data->free_wm[i] > 0) { num_used_wms++; @@ -1316,6 +1343,7 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe44_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1349,34 +1377,20 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe44_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1397,8 +1411,6 @@ static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe44_get_wm_mask( @@ -1450,15 +1462,15 @@ static int msm_vfe44_stats_check_streams( struct msm_vfe_stats_stream *stream_info) { if (stream_info[STATS_IDX_BF].state == - STATS_AVALIABLE && + STATS_AVAILABLE && stream_info[STATS_IDX_BF_SCALE].state != - STATS_AVALIABLE) { + STATS_AVAILABLE) { pr_err("%s: does not support BF_SCALE while BF is disabled\n", __func__); return -EINVAL; } - if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE && stream_info[STATS_IDX_BF].composite_flag != stream_info[STATS_IDX_BF_SCALE].composite_flag) { pr_err("%s: Different composite flag for BF and BF_SCALE\n", @@ -1541,27 +1553,37 @@ static void msm_vfe44_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe44_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe44_config_irq(vfe_dev, - (1 << (STATS_IDX(stream_info->stream_handle) + 15)), 0, - MSM_ISP_IRQ_DISABLE); + (1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe44_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE44_STATS_BASE(stats_idx); /* BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; * it's using the same from BF */ @@ -1582,9 +1604,14 @@ static void msm_vfe44_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE44_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE44_STATS_BASE(stats_idx); /* BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; * it's using the same from BF */ @@ -1742,12 +1769,16 @@ static void msm_vfe44_stats_update_cgc_override(struct vfe_device *vfe_dev, } static void msm_vfe44_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE44_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 40bb044fde47..6336892b1b4e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -376,46 +376,40 @@ static void msm_vfe46_process_reg_update(struct vfe_device *vfe_dev, switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + msm_isp_stats_stream_update(vfe_dev); + if (vfe_dev->axi_data.src_info[i].stream_count + == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. - reg_update(vfe_dev, i); + reg_update(vfe_dev, i); break; case VFE_RAW_0: case VFE_RAW_1: case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, i); + /* reg upd is also epoch for rdi */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -437,14 +431,16 @@ static void msm_vfe46_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + stream_count == 0) { + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -488,7 +484,9 @@ static void msm_vfe46_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x3D8); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x3D8); @@ -567,8 +565,10 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -583,7 +583,10 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); @@ -596,31 +599,37 @@ static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, static void msm_vfe46_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -static void msm_vfe46_cfg_framedrop(void __iomem *vfe_base, +static void msm_vfe46_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { uint32_t i, temp; + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); temp = msm_camera_io_r(vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0xC); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE46_WM_BASE(stream_info->wm[i]) + 0xC); + vfe_base + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0xC); } } @@ -628,10 +637,11 @@ static void msm_vfe46_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE46_WM_BASE(stream_info->wm[i]) + 0x1C); + VFE46_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x1C); } static int32_t msm_vfe46_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1114,7 +1124,7 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x3AC); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1178,7 +1188,10 @@ static void msm_vfe46_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE46_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0xC); val &= ~0x2; @@ -1190,17 +1203,18 @@ static void msm_vfe46_axi_cfg_wm_reg( val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+3)/4 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /* WR_BUFFER_CFG */ val = VFE46_BURST_LEN | - (stream_info->plane_cfg[plane_idx].output_height - 1) << + (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1) << 2 | ((msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride)+1)/2) << 16; msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18); } @@ -1215,7 +1229,10 @@ static void msm_vfe46_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE46_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + + wm_base = VFE46_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0xC); @@ -1232,12 +1249,15 @@ static void msm_vfe46_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; + switch (stream_info->stream_src) { case PIX_VIDEO: case PIX_ENCODER: @@ -1295,9 +1315,12 @@ static void msm_vfe46_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; + xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE46_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE46_XBAR_SHIFT(wm)); @@ -1407,6 +1430,7 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + struct msm_isp_timestamp ts; /* Keep only halt and restart mask */ msm_vfe46_config_irq(vfe_dev, (1 << 31), (1 << 8), @@ -1440,34 +1464,19 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x374); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -static int msm_vfe46_axi_restart(struct vfe_device *vfe_dev, +static void msm_vfe46_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1488,8 +1497,6 @@ static int msm_vfe46_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } static uint32_t msm_vfe46_get_wm_mask( @@ -1541,15 +1548,15 @@ static int msm_vfe46_stats_check_streams( struct msm_vfe_stats_stream *stream_info) { if (stream_info[STATS_IDX_BF].state == - STATS_AVALIABLE && + STATS_AVAILABLE && stream_info[STATS_IDX_BF_SCALE].state != - STATS_AVALIABLE) { + STATS_AVAILABLE) { pr_err("%s: does not support BF_SCALE while BF is disabled\n", __func__); return -EINVAL; } - if (stream_info[STATS_IDX_BF].state != STATS_AVALIABLE && - stream_info[STATS_IDX_BF_SCALE].state != STATS_AVALIABLE && + if (stream_info[STATS_IDX_BF].state != STATS_AVAILABLE && + stream_info[STATS_IDX_BF_SCALE].state != STATS_AVAILABLE && stream_info[STATS_IDX_BF].composite_flag != stream_info[STATS_IDX_BF_SCALE].composite_flag) { pr_err("%s: Different composite flag for BF and BF_SCALE\n", @@ -1632,26 +1639,37 @@ static void msm_vfe46_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe46_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_ENABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + msm_vfe46_config_irq(vfe_dev, - 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, - MSM_ISP_IRQ_DISABLE); + 1 << (STATS_IDX(stream_info->stream_handle[vfe_idx]) + 15), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe46_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE46_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE46_STATS_BASE(stats_idx); /* * BF_SCALE does not have its own WR_ADDR_CFG, @@ -1676,10 +1694,14 @@ static void msm_vfe46_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE46_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE46_STATS_BASE(stats_idx); /* * BF_SCALE does not have its own WR_ADDR_CFG, * IRQ_FRAMEDROP_PATTERN and IRQ_SUBSAMPLE_PATTERN; @@ -1845,12 +1867,16 @@ static void msm_vfe46_stats_enable_module(struct vfe_device *vfe_dev, } static void msm_vfe46_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE46_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 290f100ffeba..b434161f5599 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -562,19 +562,20 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { if (shift_irq & BIT(i)) { reg_updated |= BIT(i); - ISP_DBG("%s REG_UPDATE IRQ %x\n", __func__, - (uint32_t)BIT(i)); + ISP_DBG("%s REG_UPDATE IRQ %x vfe %d\n", __func__, + (uint32_t)BIT(i), vfe_dev->pdev->id); switch (i) { case VFE_PIX_0: - msm_isp_save_framedrop_values(vfe_dev, - VFE_PIX_0); msm_isp_notify(vfe_dev, ISP_EVENT_REG_UPDATE, VFE_PIX_0, ts); - if (atomic_read( - &vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - if (vfe_dev->axi_data.camif_state == - CAMIF_STOPPING) + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_REG_UPD); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); + /* if 0 streams then force reg update */ + if (vfe_dev->axi_data.src_info + [i].stream_count == 0 && + vfe_dev->axi_data.src_info[i].active) vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); break; @@ -582,31 +583,23 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev, case VFE_RAW_1: case VFE_RAW_2: msm_isp_increment_frame_id(vfe_dev, i, ts); - msm_isp_save_framedrop_values(vfe_dev, i); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, i, ts); - msm_isp_update_framedrop_reg(vfe_dev, i); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_REG_UPD, ts); /* * Reg Update is pseudo SOF for RDI, * so request every frame */ vfe_dev->hw_info->vfe_ops.core_ops. reg_update(vfe_dev, i); + /* reg upd is also epoch for RDI */ + msm_isp_process_reg_upd_epoch_irq(vfe_dev, i, + MSM_ISP_COMP_IRQ_EPOCH, ts); break; default: pr_err("%s: Error case\n", __func__); return; } - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read( - &vfe_dev->axi_data.axi_cfg_update[i]) == - 0) - msm_isp_notify(vfe_dev, - ISP_EVENT_STREAM_UPDATE_DONE, - i, ts); - } } } @@ -627,15 +620,17 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev, if (irq_status0 & BIT(2)) { ISP_DBG("%s: EPOCH0 IRQ\n", __func__); - msm_isp_update_framedrop_reg(vfe_dev, VFE_PIX_0); - msm_isp_update_stats_framedrop_reg(vfe_dev); + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_EPOCH, ts); + msm_isp_process_stats_reg_upd_epoch_irq(vfe_dev, + MSM_ISP_COMP_IRQ_EPOCH); msm_isp_update_error_frame_count(vfe_dev); msm_isp_notify(vfe_dev, ISP_EVENT_SOF, VFE_PIX_0, ts); if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { - if (vfe_dev->axi_data.stream_update[VFE_PIX_0]) - msm_isp_axi_stream_update(vfe_dev, VFE_PIX_0); + stream_count == 0) { + msm_isp_process_reg_upd_epoch_irq(vfe_dev, VFE_PIX_0, + MSM_ISP_COMP_IRQ_REG_UPD, ts); vfe_dev->hw_info->vfe_ops.core_ops.reg_update( vfe_dev, VFE_PIX_0); } @@ -679,7 +674,9 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->vfe_base + 0x4AC); } else if (!vfe_dev->is_split || ((frame_src == VFE_PIX_0) && - (vfe_dev->axi_data.camif_state == CAMIF_STOPPING)) || + (vfe_dev->axi_data.src_info[VFE_PIX_0].stream_count == 0) && + (vfe_dev->axi_data.src_info[VFE_PIX_0]. + raw_stream_count == 0)) || (frame_src >= VFE_RAW_0 && frame_src <= VFE_SRC_MAX)) { msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x4AC); @@ -768,9 +765,10 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t comp_mask, comp_mask_index = - stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); comp_mask |= (axi_data->composite_info[comp_mask_index]. @@ -784,8 +782,10 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t comp_mask, comp_mask_index; + comp_mask_index = stream_info->comp_mask_index[vfe_idx]; comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x74); comp_mask &= ~(0x7F << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); @@ -797,31 +797,37 @@ void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[vfe_idx][0] + 8), 0, MSM_ISP_IRQ_ENABLE); } void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, - MSM_ISP_IRQ_DISABLE); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[vfe_idx][0] + 8)), + 0, MSM_ISP_IRQ_DISABLE); } -void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, +void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period) { + void __iomem *vfe_base = vfe_dev->vfe_base; uint32_t i, temp; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { msm_camera_io_w(framedrop_pattern, vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x24); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24); temp = msm_camera_io_r(vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x14); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14); temp &= 0xFFFFFF83; msm_camera_io_w(temp | (framedrop_period - 1) << 2, - vfe_base + VFE47_WM_BASE(stream_info->wm[i]) + 0x14); + vfe_base + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x14); } } @@ -829,10 +835,11 @@ void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { uint32_t i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) msm_camera_io_w(0, vfe_dev->vfe_base + - VFE47_WM_BASE(stream_info->wm[i]) + 0x24); + VFE47_WM_BASE(stream_info->wm[vfe_idx][i]) + 0x24); } static int32_t msm_vfe47_convert_bpp_to_reg(int32_t bpp, uint32_t *bpp_reg) @@ -1395,7 +1402,7 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, src_info[VFE_PIX_0].raw_stream_count > 0) ? 1 : 0); vfe_en = ((vfe_dev->axi_data. - src_info[VFE_PIX_0].pix_stream_count > 0) ? 1 : 0); + src_info[VFE_PIX_0].stream_count > 0) ? 1 : 0); val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C); val &= 0xFFFFFF3F; val = val | bus_en << 7 | vfe_en << 6; @@ -1404,7 +1411,6 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x478); /* configure EPOCH0 for 20 lines */ msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x4A0); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1; /* testgen GO*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1, vfe_dev->vfe_base + 0xC58); @@ -1427,7 +1433,6 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, poll_val, poll_val & 0x80000000, 1000, 2000000)) pr_err("%s: camif disable failed %x\n", __func__, poll_val); - vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0; /* testgen OFF*/ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) msm_camera_io_w(1 << 1, vfe_dev->vfe_base + 0xC58); @@ -1469,8 +1474,10 @@ void msm_vfe47_axi_cfg_wm_reg( uint8_t plane_idx) { uint32_t val; - uint32_t wm_base = VFE47_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); val = msm_camera_io_r(vfe_dev->vfe_base + wm_base + 0x14); val &= ~0x2; if (stream_info->frame_based) @@ -1480,17 +1487,18 @@ void msm_vfe47_axi_cfg_wm_reg( /* WR_IMAGE_SIZE */ val = ((msm_isp_cal_word_per_line( stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_width)+3)/4 - 1) << 16 | - (stream_info->plane_cfg[plane_idx]. + (stream_info->plane_cfg[vfe_idx][plane_idx]. output_height - 1); msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x1C); /* WR_BUFFER_CFG */ val = VFE47_BURST_LEN | - (stream_info->plane_cfg[plane_idx].output_height - 1) << + (stream_info->plane_cfg[vfe_idx][plane_idx]. + output_height - 1) << 2 | ((msm_isp_cal_word_per_line(stream_info->output_format, - stream_info->plane_cfg[plane_idx]. + stream_info->plane_cfg[vfe_idx][plane_idx]. output_stride)+1)/2) << 16; } msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x20); @@ -1504,8 +1512,10 @@ void msm_vfe47_axi_clear_wm_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { uint32_t val = 0; - uint32_t wm_base = VFE47_WM_BASE(stream_info->wm[plane_idx]); + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint32_t wm_base; + wm_base = VFE47_WM_BASE(stream_info->wm[vfe_idx][plane_idx]); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14); /* WR_IMAGE_SIZE */ @@ -1521,12 +1531,14 @@ void msm_vfe47_axi_cfg_wm_xbar_reg( struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - struct msm_vfe_axi_plane_cfg *plane_cfg = - &stream_info->plane_cfg[plane_idx]; - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + struct msm_vfe_axi_plane_cfg *plane_cfg; + uint8_t wm; uint32_t xbar_cfg = 0; uint32_t xbar_reg_cfg = 0; + plane_cfg = &stream_info->plane_cfg[vfe_idx][plane_idx]; + wm = stream_info->wm[vfe_idx][plane_idx]; switch (stream_info->stream_src) { case PIX_VIDEO: case PIX_ENCODER: @@ -1585,9 +1597,11 @@ void msm_vfe47_axi_clear_wm_xbar_reg( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx) { - uint8_t wm = stream_info->wm[plane_idx]; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + uint8_t wm; uint32_t xbar_reg_cfg = 0; + wm = stream_info->wm[vfe_idx][plane_idx]; xbar_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE47_XBAR_BASE(wm)); xbar_reg_cfg &= ~(0xFFFF << VFE47_XBAR_SHIFT(wm)); @@ -1707,6 +1721,7 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, int rc = 0; enum msm_vfe_input_src i; uint32_t val = 0; + struct msm_isp_timestamp ts; val = msm_camera_io_r(vfe_dev->vfe_vbif_base + VFE47_VBIF_CLK_OFFSET); val |= 0x1; @@ -1746,34 +1761,20 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400); } + msm_isp_get_timestamp(&ts); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { - /* if any stream is waiting for update, signal complete */ - if (vfe_dev->axi_data.stream_update[i]) { - ISP_DBG("%s: complete stream update\n", __func__); - msm_isp_axi_stream_update(vfe_dev, i); - if (vfe_dev->axi_data.stream_update[i]) - msm_isp_axi_stream_update(vfe_dev, i); - } - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) { - ISP_DBG("%s: complete on axi config update\n", - __func__); - msm_isp_axi_cfg_update(vfe_dev, i); - if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[i])) - msm_isp_axi_cfg_update(vfe_dev, i); - } + /* if any stream is waiting for update, signal fake completes */ + msm_isp_axi_stream_update(vfe_dev, i, &ts); + msm_isp_axi_stream_update(vfe_dev, i, &ts); } - if (atomic_read(&vfe_dev->stats_data.stats_update)) { - ISP_DBG("%s: complete on stats update\n", __func__); - msm_isp_stats_stream_update(vfe_dev); - if (atomic_read(&vfe_dev->stats_data.stats_update)) - msm_isp_stats_stream_update(vfe_dev); - } + msm_isp_stats_stream_update(vfe_dev); + msm_isp_stats_stream_update(vfe_dev); return rc; } -int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, +void msm_vfe47_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif) { msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, @@ -1793,8 +1794,6 @@ int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, ENABLE_CAMIF); } - - return 0; } uint32_t msm_vfe47_get_wm_mask( @@ -1912,7 +1911,10 @@ void msm_vfe47_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - switch (STATS_IDX(stream_info->stream_handle)) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + + switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) { case STATS_COMP_IDX_AEC_BG: msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_ENABLE); break; @@ -1943,7 +1945,7 @@ void msm_vfe47_stats_cfg_wm_irq_mask( break; default: pr_err("%s: Invalid stats idx %d\n", __func__, - STATS_IDX(stream_info->stream_handle)); + STATS_IDX(stream_info->stream_handle[vfe_idx])); } } @@ -1951,12 +1953,10 @@ void msm_vfe47_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - uint32_t irq_mask, irq_mask_1; - - irq_mask = vfe_dev->irq0_mask; - irq_mask_1 = vfe_dev->irq1_mask; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); - switch (STATS_IDX(stream_info->stream_handle)) { + switch (STATS_IDX(stream_info->stream_handle[vfe_idx])) { case STATS_COMP_IDX_AEC_BG: msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_DISABLE); break; @@ -1987,7 +1987,7 @@ void msm_vfe47_stats_clear_wm_irq_mask( break; default: pr_err("%s: Invalid stats idx %d\n", __func__, - STATS_IDX(stream_info->stream_handle)); + STATS_IDX(stream_info->stream_handle[vfe_idx])); } } @@ -1995,8 +1995,13 @@ void msm_vfe47_stats_cfg_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE47_STATS_BASE(stats_idx); + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE47_STATS_BASE(stats_idx); /* WR_ADDR_CFG */ msm_camera_io_w(stream_info->framedrop_period << 2, @@ -2013,9 +2018,14 @@ void msm_vfe47_stats_clear_wm_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t val = 0; - int stats_idx = STATS_IDX(stream_info->stream_handle); - uint32_t stats_base = VFE47_STATS_BASE(stats_idx); + int stats_idx; + uint32_t stats_base; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); + stats_base = VFE47_STATS_BASE(stats_idx); /* WR_ADDR_CFG */ msm_camera_io_w(val, vfe_dev->vfe_base + stats_base + 0x10); @@ -2171,11 +2181,16 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, } void msm_vfe47_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr) { + void __iomem *vfe_base = vfe_dev->vfe_base; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); uint32_t paddr32 = (paddr & 0xFFFFFFFF); - int stats_idx = STATS_IDX(stream_info->stream_handle); + int stats_idx; + + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); msm_camera_io_w(paddr32, vfe_base + VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status)); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h index 737f845c7272..8581373b3b71 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h @@ -56,7 +56,7 @@ void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); -void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, +void msm_vfe47_cfg_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t framedrop_pattern, uint32_t framedrop_period); void msm_vfe47_clear_framedrop(struct vfe_device *vfe_dev, @@ -107,7 +107,7 @@ void msm_vfe47_update_ping_pong_addr( int32_t buf_size); int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking); -int msm_vfe47_axi_restart(struct vfe_device *vfe_dev, +void msm_vfe47_axi_restart(struct vfe_device *vfe_dev, uint32_t blocking, uint32_t enable_camif); uint32_t msm_vfe47_get_wm_mask( uint32_t irq_status0, uint32_t irq_status1); @@ -141,7 +141,7 @@ bool msm_vfe47_is_module_cfg_lock_needed( void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev, uint32_t stats_mask, uint8_t enable); void msm_vfe47_stats_update_ping_pong_addr( - void __iomem *vfe_base, struct msm_vfe_stats_stream *stream_info, + struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status, dma_addr_t paddr); uint32_t msm_vfe47_stats_get_wm_mask( uint32_t irq_status0, uint32_t irq_status1); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index cf5fc72a932c..572e3c637c7b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -22,9 +22,12 @@ static int msm_isp_update_dual_HW_ms_info_at_start( struct vfe_device *vfe_dev, enum msm_vfe_input_src stream_src); -static int msm_isp_update_dual_HW_axi( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info); +static void msm_isp_reload_ping_pong_offset( + struct msm_vfe_axi_stream *stream_info); + +static void __msm_isp_axi_stream_update( + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts); #define DUAL_VFE_AND_VFE1(s, v) ((s->stream_src < RDI_INTF_0) && \ v->is_split && vfe_dev->pdev->id == ISP_VFE1) @@ -33,105 +36,151 @@ static int msm_isp_update_dual_HW_axi( ((s->stream_src >= RDI_INTF_0) && \ (stream_info->stream_src <= RDI_INTF_2))) -static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( - struct dual_vfe_resource *dual_vfe_res, - int vfe_id, uint32_t index) -{ - struct msm_vfe_axi_shared_data *axi_data = - dual_vfe_res->axi_data[vfe_id]; - return &axi_data->stream_info[index]; -} - -static inline struct msm_vfe_axi_stream *msm_isp_get_controllable_stream( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) -{ - if (vfe_dev->is_split && stream_info->stream_src < RDI_INTF_0 && - stream_info->controllable_output) - return msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ISP_VFE1, - HANDLE_TO_IDX( - stream_info->stream_handle)); - return stream_info; -} - -int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, +static int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) + struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, + struct msm_vfe_axi_stream *stream_info) { - uint32_t i = stream_cfg_cmd->stream_src; - - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; - } + uint32_t i; + int rc = 0; - if (axi_data->stream_info[i].state != AVAILABLE) { + if (stream_info->state != AVAILABLE) { pr_err("%s:%d invalid state %d expected %d for src %d\n", - __func__, __LINE__, axi_data->stream_info[i].state, + __func__, __LINE__, stream_info->state, AVAILABLE, i); return -EINVAL; } + if (stream_info->num_isp == 0) { + stream_info->session_id = stream_cfg_cmd->session_id; + stream_info->stream_id = stream_cfg_cmd->stream_id; + stream_info->buf_divert = stream_cfg_cmd->buf_divert; + stream_info->stream_src = stream_cfg_cmd->stream_src; + stream_info->controllable_output = + stream_cfg_cmd->controllable_output; + stream_info->activated_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + if (stream_cfg_cmd->controllable_output) + stream_cfg_cmd->frame_skip_pattern = SKIP_ALL; + INIT_LIST_HEAD(&stream_info->request_q); + } else { + /* check if the stream has been added for the vfe-device */ + if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) { + pr_err("%s: stream %p/%x is already added for vfe dev %d vfe_mask %x\n", + __func__, stream_info, stream_info->stream_id, + vfe_dev->pdev->id, stream_info->vfe_mask); + return -EINVAL; + } + if (stream_info->session_id != stream_cfg_cmd->session_id) { + pr_err("%s: dual stream session id mismatch %d/%d\n", + __func__, stream_info->session_id, + stream_cfg_cmd->session_id); + rc = -EINVAL; + } + if (stream_info->stream_id != stream_cfg_cmd->stream_id) { + pr_err("%s: dual stream stream id mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_cfg_cmd->stream_id); + rc = -EINVAL; + } + if (stream_info->controllable_output != + stream_cfg_cmd->controllable_output) { + pr_err("%s: dual stream controllable_op mismatch %d/%d\n", + __func__, stream_info->controllable_output, + stream_cfg_cmd->controllable_output); + rc = -EINVAL; + } + if (stream_info->buf_divert != stream_cfg_cmd->buf_divert) { + pr_err("%s: dual stream buf_divert mismatch %d/%d\n", + __func__, stream_info->buf_divert, + stream_cfg_cmd->buf_divert); + rc = -EINVAL; + } + if (rc) + return rc; + } + stream_info->vfe_dev[stream_info->num_isp] = vfe_dev; + stream_info->num_isp++; + if ((axi_data->stream_handle_cnt << 8) == 0) axi_data->stream_handle_cnt++; stream_cfg_cmd->axi_stream_handle = - (++axi_data->stream_handle_cnt) << 8 | i; + (++axi_data->stream_handle_cnt) << 8 | stream_info->stream_src; ISP_DBG("%s: vfe %d handle %x\n", __func__, vfe_dev->pdev->id, stream_cfg_cmd->axi_stream_handle); - memset(&axi_data->stream_info[i], 0, - sizeof(struct msm_vfe_axi_stream)); - spin_lock_init(&axi_data->stream_info[i].lock); - axi_data->stream_info[i].session_id = stream_cfg_cmd->session_id; - axi_data->stream_info[i].stream_id = stream_cfg_cmd->stream_id; - axi_data->stream_info[i].buf_divert = stream_cfg_cmd->buf_divert; - axi_data->stream_info[i].state = INACTIVE; - axi_data->stream_info[i].stream_handle = + stream_info->stream_handle[stream_info->num_isp - 1] = stream_cfg_cmd->axi_stream_handle; - axi_data->stream_info[i].controllable_output = - stream_cfg_cmd->controllable_output; - axi_data->stream_info[i].activated_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - if (stream_cfg_cmd->controllable_output) - stream_cfg_cmd->frame_skip_pattern = SKIP_ALL; - INIT_LIST_HEAD(&axi_data->stream_info[i].request_q); + stream_info->vfe_mask |= (1 << vfe_dev->pdev->id); + + if (!vfe_dev->is_split || stream_cfg_cmd->stream_src >= RDI_INTF_0 || + stream_info->num_isp == MAX_VFE) { + stream_info->state = INACTIVE; + + for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++) + stream_info->composite_irq[i] = 0; + } return 0; } -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx) +static void msm_isp_axi_destroy_stream( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - if (axi_data->stream_info[stream_idx].state != AVAILABLE) { - axi_data->stream_info[stream_idx].state = AVAILABLE; - axi_data->stream_info[stream_idx].stream_handle = 0; - } else { - pr_err("%s: stream does not exist\n", __func__); + int k; + int j; + int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + /* + * For the index being removed, shift everything to it's right by 1 + * so that the index being removed becomes the last index + */ + for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) { + stream_info->vfe_dev[i] = stream_info->vfe_dev[k]; + stream_info->stream_handle[i] = stream_info->stream_handle[k]; + stream_info->bandwidth[i] = stream_info->bandwidth[k]; + stream_info->max_width[i] = stream_info->max_width[k]; + stream_info->comp_mask_index[i] = + stream_info->comp_mask_index[k]; + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->plane_cfg[i][j] = + stream_info->plane_cfg[k][j]; + stream_info->wm[i][j] = stream_info->wm[k][j]; + } + } + + stream_info->num_isp--; + stream_info->vfe_dev[stream_info->num_isp] = NULL; + stream_info->stream_handle[stream_info->num_isp] = 0; + stream_info->bandwidth[stream_info->num_isp] = 0; + stream_info->max_width[stream_info->num_isp] = 0; + stream_info->comp_mask_index[stream_info->num_isp] = -1; + stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id); + for (j = 0; j < stream_info->num_planes; j++) { + stream_info->wm[stream_info->num_isp][j] = -1; + memset(&stream_info->plane_cfg[stream_info->num_isp][j], + 0, sizeof( + stream_info->plane_cfg[stream_info->num_isp][j])); + } + + if (stream_info->num_isp == 0) { + /* release the bufq */ + for (k = 0; k < VFE_BUF_QUEUE_MAX; k++) + stream_info->bufq_handle[k] = 0; + stream_info->vfe_mask = 0; + stream_info->state = AVAILABLE; } } -int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, +static int msm_isp_validate_axi_request(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) { int rc = -1, i; - struct msm_vfe_axi_stream *stream_info = NULL; - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) - < VFE_AXI_SRC_MAX) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - } else { - pr_err("%s: Invalid axi_stream_handle\n", __func__); - return rc; - } - - if (!stream_info) { - pr_err("%s: Stream info is NULL\n", __func__); - return -EINVAL; - } + int vfe_idx; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; switch (stream_cfg_cmd->output_format) { case V4L2_PIX_FMT_YUYV: @@ -236,9 +285,13 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, return rc; } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) { - stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i]; - stream_info->max_width = max(stream_info->max_width, + stream_info->plane_cfg[vfe_idx][i] = + stream_cfg_cmd->plane_cfg[i]; + stream_info->max_width[vfe_idx] = + max(stream_info->max_width[vfe_idx], stream_cfg_cmd->plane_cfg[i].output_width); } @@ -250,10 +303,11 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, } static uint32_t msm_isp_axi_get_plane_size( - struct msm_vfe_axi_stream *stream_info, int plane_idx) + struct msm_vfe_axi_stream *stream_info, int vfe_idx, int plane_idx) { uint32_t size = 0; - struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg; + struct msm_vfe_axi_plane_cfg *plane_cfg = + stream_info->plane_cfg[vfe_idx]; switch (stream_info->output_format) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: @@ -355,37 +409,41 @@ static uint32_t msm_isp_axi_get_plane_size( return size; } -void msm_isp_axi_reserve_wm(struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_reserve_wm(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i, j; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) { for (j = 0; j < axi_data->hw_info->num_wm; j++) { if (!axi_data->free_wm[j]) { axi_data->free_wm[j] = - stream_info->stream_handle; + stream_info->stream_handle[vfe_idx]; axi_data->wm_image_size[j] = msm_isp_axi_get_plane_size( - stream_info, i); + stream_info, vfe_idx, i); axi_data->num_used_wm++; break; } } ISP_DBG("%s vfe %d stream_handle %x wm %d\n", __func__, vfe_dev->pdev->id, - stream_info->stream_handle, j); - stream_info->wm[i] = j; + stream_info->stream_handle[vfe_idx], j); + stream_info->wm[vfe_idx][i] = j; } } -void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, +void msm_isp_axi_free_wm(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { - axi_data->free_wm[stream_info->wm[i]] = 0; + axi_data->free_wm[stream_info->wm[vfe_idx][i]] = 0; axi_data->num_used_wm--; } if (stream_info->stream_src <= IDEAL_RAW) @@ -394,88 +452,47 @@ void msm_isp_axi_free_wm(struct msm_vfe_axi_shared_data *axi_data, axi_data->num_rdi_stream++; } -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_reserve_comp_mask( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { int i; uint8_t comp_mask = 0; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) - comp_mask |= 1 << stream_info->wm[i]; + comp_mask |= 1 << stream_info->wm[vfe_idx][i]; for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) { if (!axi_data->composite_info[i].stream_handle) { axi_data->composite_info[i].stream_handle = - stream_info->stream_handle; + stream_info->stream_handle[vfe_idx]; axi_data->composite_info[i]. stream_composite_mask = comp_mask; axi_data->num_used_composite_mask++; break; } } - stream_info->comp_mask_index = i; + stream_info->comp_mask_index[vfe_idx] = i; return; } -void msm_isp_axi_free_comp_mask(struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_axi_free_comp_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - axi_data->composite_info[stream_info->comp_mask_index]. + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]]. stream_composite_mask = 0; - axi_data->composite_info[stream_info->comp_mask_index]. + axi_data->composite_info[stream_info->comp_mask_index[vfe_idx]]. stream_handle = 0; axi_data->num_used_composite_mask--; } -int msm_isp_axi_check_stream_state( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) -{ - int rc = 0, i; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - enum msm_vfe_axi_state valid_state = - (stream_cfg_cmd->cmd == START_STREAM) ? INACTIVE : ACTIVE; - - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return -EINVAL; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state != valid_state) { - if ((stream_info->state == PAUSING || - stream_info->state == PAUSED || - stream_info->state == RESUME_PENDING || - stream_info->state == RESUMING || - stream_info->state == UPDATING) && - (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { - stream_info->state = ACTIVE; - } else { - pr_err("%s: Invalid stream state: %d\n", - __func__, stream_info->state); - spin_unlock_irqrestore( - &stream_info->lock, flags); - if (stream_cfg_cmd->cmd == START_STREAM) - rc = -EINVAL; - break; - } - } - spin_unlock_irqrestore(&stream_info->lock, flags); - } - return rc; -} - /** * msm_isp_cfg_framedrop_reg() - Program the period and pattern - * @vfe_dev: The device for which the period and pattern is programmed * @stream_info: The stream for which programming is done * * This function calculates the period and pattern to be configured @@ -484,15 +501,15 @@ int msm_isp_axi_check_stream_state( * * Returns void. */ -static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev, +static void msm_isp_cfg_framedrop_reg( struct msm_vfe_axi_stream *stream_info) { - struct msm_vfe_axi_stream *vfe0_stream_info = NULL; + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; uint32_t runtime_init_frame_drop; - uint32_t framedrop_pattern = 0; uint32_t framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; enum msm_vfe_input_src frame_src = SRC_TO_INTF(stream_info->stream_src); + int i; if (vfe_dev->axi_data.src_info[frame_src].frame_id >= stream_info->init_frame_drop) @@ -507,127 +524,45 @@ static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev, if (MSM_VFE_STREAM_STOP_PERIOD != framedrop_period) framedrop_pattern = 0x1; - ISP_DBG("%s: stream %x framedrop pattern %x period %u\n", __func__, - stream_info->stream_handle, framedrop_pattern, - framedrop_period); - BUG_ON(0 == framedrop_period); - if (DUAL_VFE_AND_VFE1(stream_info, vfe_dev)) { - vfe0_stream_info = msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ISP_VFE0, - HANDLE_TO_IDX( - stream_info->stream_handle)); + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->common_data->dual_vfe_res-> - vfe_base[ISP_VFE0], - vfe0_stream_info, framedrop_pattern, - framedrop_period); - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->vfe_base, stream_info, - framedrop_pattern, - framedrop_period); + vfe_dev, stream_info, framedrop_pattern, + framedrop_period); + } - stream_info->requested_framedrop_period = - framedrop_period; - vfe0_stream_info->requested_framedrop_period = - framedrop_period; + ISP_DBG("%s: stream %x src %x framedrop pattern %x period %u\n", + __func__, + stream_info->stream_handle[0], stream_info->stream_src, + framedrop_pattern, framedrop_period); - } else if (RDI_OR_NOT_DUAL_VFE(vfe_dev, stream_info)) { - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop( - vfe_dev->vfe_base, stream_info, framedrop_pattern, - framedrop_period); - stream_info->requested_framedrop_period = framedrop_period; - } + stream_info->requested_framedrop_period = framedrop_period; } -/** - * msm_isp_check_epoch_status() - check the epock signal for framedrop - * - * @vfe_dev: The h/w on which the epoch signel is reveived - * @frame_src: The source of the epoch signal for this frame - * - * For dual vfe case and pixel stream, if both vfe's epoch signal is - * received, this function will return success. - * It will also return the vfe1 for further process - * For none dual VFE stream or none pixl source, this - * funciton will just return success. - * - * Returns 1 - epoch received is complete. - * 0 - epoch reveived is not complete. - */ -static int msm_isp_check_epoch_status(struct vfe_device **vfe_dev, - enum msm_vfe_input_src frame_src) +static int msm_isp_composite_irq(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + enum msm_isp_comp_irq_types irq) { - struct vfe_device *vfe_dev_cur = *vfe_dev; - struct vfe_device *vfe_dev_other = NULL; - uint32_t vfe_id_other = 0; - uint32_t vfe_id_cur = 0; - uint32_t epoch_mask = 0; - unsigned long flags; - int completed = 0; - - spin_lock_irqsave( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); - - if (vfe_dev_cur->is_split && - frame_src == VFE_PIX_0) { - if (vfe_dev_cur->pdev->id == ISP_VFE0) { - vfe_id_cur = ISP_VFE0; - vfe_id_other = ISP_VFE1; - } else { - vfe_id_cur = ISP_VFE1; - vfe_id_other = ISP_VFE0; - } - vfe_dev_other = vfe_dev_cur->common_data->dual_vfe_res-> - vfe_dev[vfe_id_other]; - - if (vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask & (1 << vfe_id_cur)) { - /* serious scheduling delay */ - pr_err("Missing epoch: vfe %d, epoch mask 0x%x\n", - vfe_dev_cur->pdev->id, - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask); - goto fatal; - } - - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask |= (1 << vfe_id_cur); - - epoch_mask = (1 << vfe_id_cur) | (1 << vfe_id_other); - if ((vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask & epoch_mask) == epoch_mask) { - - if (vfe_id_other == ISP_VFE0) - *vfe_dev = vfe_dev_cur; - else - *vfe_dev = vfe_dev_other; + /* interrupt recv on same vfe w/o recv on other vfe */ + if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) { + pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n", + __func__, irq, vfe_dev->pdev->id); + return -EINVAL; + } - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask &= ~epoch_mask; - completed = 1; - } - } else - completed = 1; + stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id); + if (stream_info->composite_irq[irq] != stream_info->vfe_mask) + return 1; - spin_unlock_irqrestore( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); + stream_info->composite_irq[irq] = 0; - return completed; -fatal: - spin_unlock_irqrestore( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); - /* new error event code will be added later */ - msm_isp_halt_send_error(vfe_dev_cur, ISP_EVENT_PING_PONG_MISMATCH); return 0; } - /** * msm_isp_update_framedrop_reg() - Update frame period pattern on h/w - * @vfe_dev: The h/w on which the perion pattern is updated. - * @frame_src: Input source. + * @stream_info: Stream for which update is to be performed * * If the period and pattern needs to be updated for a stream then it is * updated here. Updates happen if initial frame drop reaches 0 or burst @@ -635,47 +570,75 @@ fatal: * * Returns void */ -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) +static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info) +{ + if (stream_info->stream_type == BURST_STREAM) { + if (stream_info->runtime_num_burst_capture == 0 || + (stream_info->runtime_num_burst_capture == 1 && + stream_info->activated_framedrop_period == 1)) + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + } + + if (stream_info->undelivered_request_cnt > 0) + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + + /* + * re-configure the period pattern, only if it's not already + * set to what we want + */ + if (stream_info->current_framedrop_period != + stream_info->requested_framedrop_period) { + msm_isp_cfg_framedrop_reg(stream_info); + } +} + +void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, + enum msm_isp_comp_irq_types irq, + struct msm_isp_timestamp *ts) { int i; - struct msm_vfe_axi_shared_data *axi_data = NULL; struct msm_vfe_axi_stream *stream_info; unsigned long flags; - - if (msm_isp_check_epoch_status(&vfe_dev, frame_src) != 1) - return; - - axi_data = &vfe_dev->axi_data; + int ret; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + if (SRC_TO_INTF(stream_info->stream_src) != frame_src) { continue; } - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) continue; spin_lock_irqsave(&stream_info->lock, flags); - if (BURST_STREAM == stream_info->stream_type) { - if (0 == stream_info->runtime_num_burst_capture) - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; + ret = msm_isp_composite_irq(vfe_dev, stream_info, irq); + if (ret) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (ret < 0) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + continue; } - if (stream_info->undelivered_request_cnt > 0) - stream_info->current_framedrop_period = - MSM_VFE_STREAM_STOP_PERIOD; - - /* - * re-configure the period pattern, only if it's not already - * set to what we want - */ - if (stream_info->current_framedrop_period != - stream_info->requested_framedrop_period) { - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + switch (irq) { + case MSM_ISP_COMP_IRQ_REG_UPD: + stream_info->activated_framedrop_period = + stream_info->requested_framedrop_period; + __msm_isp_axi_stream_update(stream_info, ts); + break; + case MSM_ISP_COMP_IRQ_EPOCH: + if (stream_info->state == ACTIVE) + msm_isp_update_framedrop_reg(stream_info); + break; + default: + WARN(1, "Invalid irq %d\n", irq); } spin_unlock_irqrestore(&stream_info->lock, flags); } @@ -708,7 +671,7 @@ void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, stream_info->frame_skip_pattern); } - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); ISP_DBG("%s: init frame drop: %d\n", __func__, stream_info->init_frame_drop); ISP_DBG("%s: num_burst_capture: %d\n", __func__, @@ -741,10 +704,9 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; } for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - struct msm_vfe_axi_stream *temp_stream_info; - - stream_info = &axi_data->stream_info[i]; - stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + stream_info = msm_isp_get_stream_common_data(vfe_dev, + i); + stream_idx = HANDLE_TO_IDX(stream_info->stream_handle[0]); /* * Process drop only if controllable ACTIVE PIX stream && @@ -761,10 +723,8 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev, if (stream_info->controllable_output && !vfe_dev->reg_updated) { - temp_stream_info = - msm_isp_get_controllable_stream(vfe_dev, - stream_info); - if (temp_stream_info->undelivered_request_cnt) { + if (stream_info->undelivered_request_cnt) { + pr_err("Drop frame no reg update\n"); if (msm_isp_drop_frame(vfe_dev, stream_info, ts, sof_info)) { pr_err("drop frame failed\n"); @@ -1010,7 +970,7 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, /** * msm_isp_calculate_framedrop() - Setup frame period and pattern - * @axi_data: Structure describing the h/w streams. + * @vfe_dev: vfe device. * @stream_cfg_cmd: User space input parameter for perion/pattern. * * Initialize the h/w stream framedrop period and pattern sent @@ -1018,16 +978,16 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, * * Returns 0 on success else error code. */ -int msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, +static int msm_isp_calculate_framedrop( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd) { uint32_t framedrop_period = 0; struct msm_vfe_axi_stream *stream_info = NULL; if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < VFE_AXI_SRC_MAX) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); } else { pr_err("%s: Invalid stream handle", __func__); return -EINVAL; @@ -1059,26 +1019,36 @@ int msm_isp_calculate_framedrop( return 0; } -void msm_isp_calculate_bandwidth( - struct msm_vfe_axi_shared_data *axi_data, +static void msm_isp_calculate_bandwidth( struct msm_vfe_axi_stream *stream_info) { int bpp = 0; + struct msm_vfe_axi_shared_data *axi_data; + int i; + if (stream_info->stream_src < RDI_INTF_0) { - stream_info->bandwidth = - (axi_data->src_info[VFE_PIX_0].pixel_clock / - axi_data->src_info[VFE_PIX_0].width) * - stream_info->max_width; - stream_info->bandwidth = (unsigned long)stream_info->bandwidth * - stream_info->format_factor / ISP_Q2; + for (i = 0; i < stream_info->num_isp; i++) { + axi_data = &stream_info->vfe_dev[i]->axi_data; + stream_info->bandwidth[i] = + (axi_data->src_info[VFE_PIX_0].pixel_clock / + axi_data->src_info[VFE_PIX_0].width) * + stream_info->max_width[i]; + stream_info->bandwidth[i] = + (unsigned long)stream_info->bandwidth[i] * + stream_info->format_factor / ISP_Q2; + } } else { int rdi = SRC_TO_INTF(stream_info->stream_src); bpp = msm_isp_get_bit_per_pixel(stream_info->output_format); - if (rdi < VFE_SRC_MAX) - stream_info->bandwidth = + if (rdi < VFE_SRC_MAX) { + for (i = 0; i < stream_info->num_isp; i++) { + axi_data = &stream_info->vfe_dev[i]->axi_data; + stream_info->bandwidth[i] = (axi_data->src_info[rdi].pixel_clock / 8) * bpp; - else + } + } else { pr_err("%s: Invalid rdi interface\n", __func__); + } } } @@ -1133,37 +1103,40 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) uint32_t io_format = 0; struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg; struct msm_vfe_axi_stream *stream_info; + unsigned long flags; + + if (stream_cfg_cmd->stream_src >= VFE_AXI_SRC_MAX) { + pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, + stream_cfg_cmd->stream_src); + return -EINVAL; + } + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_cfg_cmd->stream_src); + + spin_lock_irqsave(&stream_info->lock, flags); rc = msm_isp_axi_create_stream(vfe_dev, - &vfe_dev->axi_data, stream_cfg_cmd); + &vfe_dev->axi_data, stream_cfg_cmd, stream_info); if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: create stream failed\n", __func__); return rc; } rc = msm_isp_validate_axi_request( - &vfe_dev->axi_data, stream_cfg_cmd); + vfe_dev, stream_info, stream_cfg_cmd); if (rc) { + msm_isp_axi_destroy_stream(vfe_dev, stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: Request validation failed\n", __func__); - if (HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle) < - VFE_AXI_SRC_MAX) - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); return rc; } - stream_info = &vfe_dev->axi_data. - stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)]; - if (!stream_info) { - pr_err("%s: can not find stream handle %x\n", __func__, - stream_cfg_cmd->axi_stream_handle); - return -EINVAL; - } stream_info->memory_input = stream_cfg_cmd->memory_input; vfe_dev->reg_update_requested &= ~(BIT(SRC_TO_INTF(stream_info->stream_src))); - msm_isp_axi_reserve_wm(vfe_dev, &vfe_dev->axi_data, stream_info); + msm_isp_axi_reserve_wm(vfe_dev, stream_info); if (stream_info->stream_src < RDI_INTF_0) { io_format = vfe_dev->axi_data.src_info[VFE_PIX_0].input_format; @@ -1183,16 +1156,67 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) goto done; } } - rc = msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd); - if (rc) - goto done; + + if (!stream_info->controllable_output) { + /* + * check that the parameters passed from second vfe is same + * as first vfe, do this only for non controllable stream + * right now because user driver has bug where it sends + * mismatch info for controllable streams + */ + if (stream_info->num_isp > 1) { + if (stream_cfg_cmd->init_frame_drop != + stream_info->init_frame_drop) { + pr_err("%s: stream %d init drop mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->init_frame_drop, + stream_cfg_cmd->init_frame_drop); + rc = -EINVAL; + } + if (stream_cfg_cmd->frame_skip_pattern != + stream_info->frame_skip_pattern) { + pr_err("%s: stream %d skip pattern mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->frame_skip_pattern, + stream_cfg_cmd->frame_skip_pattern); + rc = -EINVAL; + } + if (stream_info->stream_type == CONTINUOUS_STREAM && + stream_cfg_cmd->burst_count > 0) { + pr_err("%s: stream %d stream type mismatch\n", + __func__, stream_info->stream_id); + rc = -EINVAL; + } + if (stream_info->stream_type == BURST_STREAM && + stream_info->num_burst_capture != + stream_cfg_cmd->burst_count) { + pr_err("%s: stream %d stream burst count mismatch %d/%d\n", + __func__, stream_info->stream_id, + stream_info->num_burst_capture, + stream_cfg_cmd->burst_count); + rc = -EINVAL; + } + } else { + rc = msm_isp_calculate_framedrop(vfe_dev, + stream_cfg_cmd); + } + if (rc) + goto done; + } else { + stream_info->stream_type = BURST_STREAM; + stream_info->num_burst_capture = 0; + stream_info->frame_skip_pattern = NO_SKIP; + stream_info->init_frame_drop = stream_cfg_cmd->init_frame_drop; + stream_info->current_framedrop_period = + MSM_VFE_STREAM_STOP_PERIOD; + } if (stream_cfg_cmd->vt_enable && !vfe_dev->vt_enable) { vfe_dev->vt_enable = stream_cfg_cmd->vt_enable; msm_isp_start_avtimer(); } + if (stream_info->num_planes > 1) - msm_isp_axi_reserve_comp_mask( - &vfe_dev->axi_data, stream_info); + msm_isp_axi_reserve_comp_mask(vfe_dev, stream_info); for (i = 0; i < stream_info->num_planes; i++) { vfe_dev->hw_info->vfe_ops.axi_ops. @@ -1201,16 +1225,17 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) vfe_dev->hw_info->vfe_ops.axi_ops. cfg_wm_xbar_reg(vfe_dev, stream_info, i); } - /* initialize the WM ping pong with scratch buffer */ - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PONG_FLAG); - + if (stream_info->state == INACTIVE) { + /* initialize the WM ping pong with scratch buffer */ + msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + } done: if (rc) { - msm_isp_axi_free_wm(&vfe_dev->axi_data, stream_info); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)); + msm_isp_axi_free_wm(vfe_dev, stream_info); + msm_isp_axi_destroy_stream(vfe_dev, stream_info); } + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } @@ -1218,26 +1243,42 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, i; struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_stream_cfg_cmd stream_cfg; - + int vfe_idx; + unsigned long flags; if (HANDLE_TO_IDX(stream_release_cmd->stream_handle) >= VFE_AXI_SRC_MAX) { pr_err("%s: Invalid stream handle\n", __func__); return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_release_cmd->stream_handle)]; - if (stream_info->state == AVAILABLE) { - pr_err("%s: Stream already released\n", __func__); + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + + spin_lock_irqsave(&stream_info->lock, flags); + + vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info); + if (vfe_idx == -ENOTTY || + stream_release_cmd->stream_handle != + stream_info->stream_handle[vfe_idx]) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Invalid stream %p handle %x/%x vfe_idx %d vfe_dev %d num_isp %d\n", + __func__, stream_info, + stream_release_cmd->stream_handle, + vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0, vfe_idx, + vfe_dev->pdev->id, stream_info->num_isp); return -EINVAL; - } else if (stream_info->state != INACTIVE) { + } + + if (stream_info->state != INACTIVE && stream_info->state != AVAILABLE) { stream_cfg.cmd = STOP_STREAM; stream_cfg.num_streams = 1; stream_cfg.stream_handle[0] = stream_release_cmd->stream_handle; + spin_unlock_irqrestore(&stream_info->lock, flags); msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg); + spin_lock_irqsave(&stream_info->lock, flags); } for (i = 0; i < stream_info->num_planes; i++) { @@ -1249,33 +1290,75 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) } if (stream_info->num_planes > 1) - msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); + msm_isp_axi_free_comp_mask(vfe_dev, stream_info); vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); - msm_isp_axi_free_wm(axi_data, stream_info); + msm_isp_axi_free_wm(vfe_dev, stream_info); - msm_isp_axi_destroy_stream(&vfe_dev->axi_data, - HANDLE_TO_IDX(stream_release_cmd->stream_handle)); + msm_isp_axi_destroy_stream(vfe_dev, stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } -static int msm_isp_axi_stream_enable_cfg( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, int32_t dual_vfe_sync) +void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev) { - int i, vfe_id = 0, enable_wm = 0; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; + struct msm_vfe_axi_stream_release_cmd + stream_release_cmd[VFE_AXI_SRC_MAX]; + struct msm_vfe_axi_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_axi_stream *stream_info; + int i; + int vfe_idx; + int num_stream = 0; + unsigned long flags; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream_idx", __func__); - goto error; + stream_cfg_cmd.cmd = STOP_STREAM; + stream_cfg_cmd.num_streams = 0; + + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + spin_lock_irqsave(&stream_info->lock, flags); + vfe_idx = msm_isp_get_vfe_idx_for_stream_user( + vfe_dev, stream_info); + if (-ENOTTY == vfe_idx) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_release_cmd[num_stream++].stream_handle = + stream_info->stream_handle[vfe_idx]; + if (stream_info->state == INACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_cfg_cmd.stream_handle[ + stream_cfg_cmd.num_streams] = + stream_info->stream_handle[vfe_idx]; + stream_cfg_cmd.num_streams++; + spin_unlock_irqrestore(&stream_info->lock, flags); } + if (stream_cfg_cmd.num_streams) + msm_isp_cfg_axi_stream(vfe_dev, (void *) &stream_cfg_cmd); - if (stream_info->state == INACTIVE) - goto error; + for (i = 0; i < num_stream; i++) + msm_isp_release_axi_stream(vfe_dev, &stream_release_cmd[i]); +} + +static void msm_isp_axi_stream_enable_cfg( + struct msm_vfe_axi_stream *stream_info) +{ + int enable_wm = 0; + struct vfe_device *vfe_dev; + struct msm_vfe_axi_shared_data *axi_data; + uint32_t stream_idx = stream_info->stream_src; + int k; + int i; + + WARN_ON(stream_idx >= VFE_AXI_SRC_MAX); + + WARN_ON(stream_info->state != START_PENDING && + stream_info->state != RESUME_PENDING && + stream_info->state != STOP_PENDING && + stream_info->state != PAUSE_PENDING); if (stream_info->state == START_PENDING || stream_info->state == RESUME_PENDING) { @@ -1283,50 +1366,24 @@ static int msm_isp_axi_stream_enable_cfg( } else { enable_wm = 0; } - for (i = 0; i < stream_info->num_planes; i++) { - /* - * In case when sensor is streaming, use dual vfe sync mode - * to enable wm together and avoid split. - */ - if ((stream_info->stream_src < RDI_INTF_0) && - vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1 && - dual_vfe_sync) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s:%d failed vfe0 %pK %pK vfe %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->axi_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->axi_data[ISP_VFE1]); - goto error; - } - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(dual_vfe_res->vfe_base[vfe_id], - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].wm[i], - enable_wm); - } - } else if (!vfe_dev->is_split || - (stream_info->stream_src >= RDI_INTF_0 && - stream_info->stream_src <= RDI_INTF_2) || - !dual_vfe_sync) { - vfe_dev->hw_info->vfe_ops.axi_ops. - enable_wm(vfe_dev->vfe_base, stream_info->wm[i], - enable_wm); - } - if (!enable_wm) { - /* Issue a reg update for Raw Snapshot Case + + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + axi_data = &vfe_dev->axi_data; + for (i = 0; i < stream_info->num_planes; i++) { + vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm( + vfe_dev->vfe_base, + stream_info->wm[k][i], enable_wm); + if (enable_wm) + continue; + /* + * Issue a reg update for Raw Snapshot Case * since we dont have reg update ack - */ + */ if (vfe_dev->axi_data.src_info[VFE_PIX_0]. raw_stream_count > 0 && vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count == 0) { + stream_count == 0) { if (stream_info->stream_src == CAMIF_RAW || stream_info->stream_src == IDEAL_RAW) { vfe_dev->hw_info->vfe_ops.core_ops. @@ -1335,70 +1392,103 @@ static int msm_isp_axi_stream_enable_cfg( } } } + if (stream_info->state == START_PENDING) + axi_data->num_active_stream++; + else if (stream_info->state == STOP_PENDING) + axi_data->num_active_stream--; + } +} + +static void __msm_isp_axi_stream_update( + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts) +{ + int j; + int intf = SRC_TO_INTF(stream_info->stream_src); + struct vfe_device *vfe_dev; + int k; + + switch (stream_info->state) { + case UPDATING: + stream_info->state = ACTIVE; + break; + case STOP_PENDING: + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = STOPPING; + break; + case START_PENDING: + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = STARTING; + break; + case STOPPING: + stream_info->state = INACTIVE; + for (k = 0; k < MSM_ISP_COMP_IRQ_MAX; k++) + stream_info->composite_irq[k] = 0; + complete_all(&stream_info->inactive_comp); + break; + case STARTING: + stream_info->state = ACTIVE; + complete_all(&stream_info->active_comp); + break; + case PAUSING: + stream_info->state = PAUSED; + msm_isp_reload_ping_pong_offset(stream_info); + for (j = 0; j < stream_info->num_planes; j++) { + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + } + } + stream_info->state = RESUME_PENDING; + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = RESUMING; + break; + case RESUMING: + stream_info->runtime_output_format = stream_info->output_format; + stream_info->state = ACTIVE; + complete_all(&stream_info->active_comp); + for (j = 0; j < stream_info->num_isp; j++) { + /* notify that all streams have been updated */ + msm_isp_notify(stream_info->vfe_dev[j], + ISP_EVENT_STREAM_UPDATE_DONE, intf, ts); + atomic_set(&stream_info->vfe_dev[j]-> + axi_data.axi_cfg_update[intf], 0); + } + stream_info->update_vfe_mask = 0; + break; + default: + break; } - if (stream_info->state == START_PENDING) - axi_data->num_active_stream++; - else if (stream_info->state == STOP_PENDING) - axi_data->num_active_stream--; - return 0; -error: - return -EINVAL; } void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) + enum msm_vfe_input_src frame_src, + struct msm_isp_timestamp *ts) { int i; unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_stream *stream_info; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); + if (SRC_TO_INTF(stream_info->stream_src) != frame_src) { ISP_DBG("%s stream_src %d frame_src %d\n", __func__, SRC_TO_INTF( - axi_data->stream_info[i].stream_src), + stream_info->stream_src), frame_src); continue; } - if (axi_data->stream_info[i].state == UPDATING) - axi_data->stream_info[i].state = ACTIVE; - else if (axi_data->stream_info[i].state == START_PENDING || - axi_data->stream_info[i].state == STOP_PENDING) { - msm_isp_axi_stream_enable_cfg( - vfe_dev, &axi_data->stream_info[i], - axi_data->stream_info[i].state == - START_PENDING ? 1 : 0); - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == - START_PENDING ? STARTING : STOPPING; - } else if (axi_data->stream_info[i].state == STARTING || - axi_data->stream_info[i].state == STOPPING) { - axi_data->stream_info[i].state = - axi_data->stream_info[i].state == STARTING ? - ACTIVE : INACTIVE; - } - } - - spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); - if (vfe_dev->axi_data.stream_update[frame_src]) { - vfe_dev->axi_data.stream_update[frame_src]--; - } - spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); - - if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF || - (vfe_dev->axi_data.pipeline_update == - DISABLE_CAMIF_IMMEDIATELY)) { - vfe_dev->hw_info->vfe_ops.stats_ops. - enable_module(vfe_dev, 0xFF, 0); - vfe_dev->axi_data.pipeline_update = NO_UPDATE; + if (stream_info->state == AVAILABLE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_axi_stream_update(stream_info, ts); + spin_unlock_irqrestore(&stream_info->lock, flags); } - - if (vfe_dev->axi_data.stream_update[frame_src] == 0) - complete(&vfe_dev->stream_config_complete); } -static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, +static void msm_isp_reload_ping_pong_offset( struct msm_vfe_axi_stream *stream_info) { int i, j; @@ -1406,120 +1496,70 @@ static void msm_isp_reload_ping_pong_offset(struct vfe_device *vfe_dev, struct msm_isp_buffer *buf; int32_t buf_size_byte = 0; int32_t word_per_line = 0; + int k; + struct vfe_device *vfe_dev; + + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + for (i = 0; i < 2; i++) { + buf = stream_info->buf[i]; + if (!buf) + continue; - for (i = 0; i < 2; i++) { - buf = stream_info->buf[i]; - if (!buf) - continue; - - bit = i ? 0 : 1; + bit = i ? 0 : 1; - for (j = 0; j < stream_info->num_planes; j++) { - word_per_line = msm_isp_cal_word_per_line( + for (j = 0; j < stream_info->num_planes; j++) { + word_per_line = msm_isp_cal_word_per_line( stream_info->output_format, stream_info-> - plane_cfg[j].output_stride); - if (word_per_line < 0) { - /* 0 means no prefetch*/ - word_per_line = 0; - buf_size_byte = 0; - } else { - buf_size_byte = (word_per_line * 8 * - stream_info->plane_cfg[j]. + plane_cfg[k][j].output_stride); + if (word_per_line < 0) { + /* 0 means no prefetch*/ + word_per_line = 0; + buf_size_byte = 0; + } else { + buf_size_byte = (word_per_line * 8 * + stream_info->plane_cfg[k][j]. output_scan_lines) - stream_info-> - plane_cfg[j].plane_addr_offset; - } - - vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr( - vfe_dev->vfe_base, stream_info->wm[j], bit, - buf->mapped_info[j].paddr + - stream_info->plane_cfg[j].plane_addr_offset, - buf_size_byte); - } - } -} - -void msm_isp_axi_cfg_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) -{ - int i, j; - uint32_t update_state; - unsigned long flags; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - struct msm_vfe_axi_stream *stream_info; - int num_stream = 0; + plane_cfg[k][j].plane_addr_offset; + } - spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags); - for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != - frame_src) { - continue; - } - num_stream++; - stream_info = &axi_data->stream_info[i]; - if ((stream_info->stream_type == BURST_STREAM && - !stream_info->controllable_output) || - stream_info->state == AVAILABLE) - continue; - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state == PAUSING) { - /*AXI Stopped, apply update*/ - stream_info->state = PAUSED; - msm_isp_reload_ping_pong_offset(vfe_dev, stream_info); - for (j = 0; j < stream_info->num_planes; j++) vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - /*Resume AXI*/ - stream_info->state = RESUME_PENDING; - if (vfe_dev->is_split) { - msm_isp_update_dual_HW_axi(vfe_dev, - stream_info); - } else { - msm_isp_axi_stream_enable_cfg( - vfe_dev, - &axi_data->stream_info[i], 1); - stream_info->state = RESUMING; + update_ping_pong_addr( + vfe_dev->vfe_base, + stream_info->wm[k][j], + bit, + buf->mapped_info[j].paddr + + stream_info->plane_cfg[k][j]. + plane_addr_offset, + buf_size_byte); } - } else if (stream_info->state == RESUMING) { - stream_info->runtime_output_format = - stream_info->output_format; - stream_info->state = ACTIVE; } - spin_unlock_irqrestore(&stream_info->lock, flags); } - spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock, - flags); - if (num_stream) - update_state = atomic_dec_return( - &axi_data->axi_cfg_update[frame_src]); } static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit) { - struct msm_vfe_axi_stream *temp_stream_info; int rc = 0; if (!stream_info->controllable_output) goto done; - temp_stream_info = - msm_isp_get_controllable_stream(vfe_dev, stream_info); - - if (!temp_stream_info->undelivered_request_cnt) { + if (!stream_info->undelivered_request_cnt) { pr_err_ratelimited("%s:%d error undelivered_request_cnt 0\n", __func__, __LINE__); rc = -EINVAL; goto done; } else { - temp_stream_info->undelivered_request_cnt--; - if (pingpong_bit != temp_stream_info->sw_ping_pong_bit) { + stream_info->undelivered_request_cnt--; + if (pingpong_bit != stream_info->sw_ping_pong_bit) { pr_err("%s:%d ping pong bit actual %d sw %d\n", __func__, __LINE__, pingpong_bit, - temp_stream_info->sw_ping_pong_bit); + stream_info->sw_ping_pong_bit); rc = -EINVAL; goto done; } - temp_stream_info->sw_ping_pong_bit ^= 1; + stream_info->sw_ping_pong_bit ^= 1; } done: return rc; @@ -1527,7 +1567,6 @@ done: void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) { - uint32_t i = 0; struct msm_isp_event_data error_event; struct msm_vfe_axi_halt_cmd halt_cmd; @@ -1545,10 +1584,6 @@ void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) /* heavy spin lock in axi halt, avoid spin lock outside. */ msm_isp_axi_halt(vfe_dev, &halt_cmd); - for (i = 0; i < VFE_AXI_SRC_MAX; i++) - vfe_dev->axi_data.stream_info[i].state = - INACTIVE; - error_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; @@ -1562,31 +1597,49 @@ int msm_isp_print_ping_pong_address(struct vfe_device *vfe_dev, struct msm_isp_buffer *buf = NULL; uint32_t pingpong_bit; struct msm_vfe_axi_stream *stream_info = NULL; + int k; for (j = 0; j < VFE_AXI_SRC_MAX; j++) { - stream_info = &vfe_dev->axi_data.stream_info[j]; - if (stream_info->state == INACTIVE) + stream_info = msm_isp_get_stream_common_data(vfe_dev, j); + if (stream_info->state == INACTIVE || + stream_info->state == AVAILABLE) continue; for (pingpong_bit = 0; pingpong_bit < 2; pingpong_bit++) { + dma_addr_t temp; + + buf = stream_info->buf[pingpong_bit]; + if (buf == NULL) { + pr_err("%s: buf NULL for stream %x num_isp %d\n", + __func__, + stream_info->stream_src, + stream_info->num_isp); + continue; + } + temp = buf->mapped_info[0].paddr + + buf->mapped_info[0].len; + pr_err("%s: stream %x ping bit %d uses buffer %pa-%pa, num_isp %d\n", + __func__, stream_info->stream_src, + pingpong_bit, + &buf->mapped_info[0].paddr, &temp, + stream_info->num_isp); + for (i = 0; i < stream_info->num_planes; i++) { - buf = stream_info->buf[pingpong_bit]; - if (buf == NULL) { - pr_err("%s: buf NULL\n", __func__); - continue; - } - pr_debug("%s: stream_id %x ping-pong %d plane %d start_addr %lu addr_offset %x len %zx stride %d scanline %d\n" + for (k = 0; k < stream_info->num_isp; k++) { + pr_debug( + "%s: stream_id %x ping-pong %d plane %d start_addr %lu addr_offset %x len %zx stride %d scanline %d\n" , __func__, stream_info->stream_id, pingpong_bit, i, (unsigned long) buf->mapped_info[i].paddr, stream_info-> - plane_cfg[i].plane_addr_offset, + plane_cfg[k][i].plane_addr_offset, buf->mapped_info[i].len, stream_info-> - plane_cfg[i].output_stride, + plane_cfg[k][i].output_stride, stream_info-> - plane_cfg[i].output_scan_lines + plane_cfg[k][i].output_scan_lines ); + } } } } @@ -1601,7 +1654,6 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( int rc = 0; uint32_t bufq_handle = 0; struct msm_isp_buffer *buf = NULL; - struct msm_vfe_axi_stream *temp_stream_info = NULL; struct msm_vfe_frame_request_queue *queue_req; uint32_t buf_index = MSM_ISP_INVALID_BUF_INDEX; @@ -1609,19 +1661,17 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( bufq_handle = stream_info->bufq_handle [VFE_BUF_QUEUE_DEFAULT]; } else { - temp_stream_info = msm_isp_get_controllable_stream( - vfe_dev, stream_info); queue_req = list_first_entry_or_null( - &temp_stream_info->request_q, + &stream_info->request_q, struct msm_vfe_frame_request_queue, list); if (!queue_req) return buf; - bufq_handle = temp_stream_info-> + bufq_handle = stream_info-> bufq_handle[queue_req->buff_queue_id]; if (!bufq_handle || - temp_stream_info->request_q_cnt <= 0) { + stream_info->request_q_cnt <= 0) { pr_err_ratelimited("%s: Drop request. Shared stream is stopped.\n", __func__); return buf; @@ -1629,7 +1679,7 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( buf_index = queue_req->buf_index; queue_req->cmd_used = 0; list_del(&queue_req->list); - temp_stream_info->request_q_cnt--; + stream_info->request_q_cnt--; } rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, vfe_dev->pdev->id, bufq_handle, buf_index, &buf); @@ -1651,144 +1701,74 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer( return buf; } -static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status, - int scratch) +static int msm_isp_cfg_ping_pong_address( + struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) { int i; - struct msm_isp_buffer *buf = NULL; + int j; uint32_t pingpong_bit; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; uint32_t buffer_size_byte = 0; int32_t word_per_line = 0; dma_addr_t paddr; - struct dual_vfe_resource *dual_vfe_res = NULL; - uint32_t vfe_id = 0; - unsigned long flags; + struct msm_isp_buffer *buf = NULL; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream_idx", __func__); - return -EINVAL; - } - /* make sure that streams are in right state */ - if ((stream_info->stream_src < RDI_INTF_0) && - vfe_dev->is_split) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s:%d failed vfe0 %pK %pK vfe %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->axi_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->axi_data[ISP_VFE1]); - return -EINVAL; - } - } else if (!vfe_dev->is_split || - (stream_info->stream_src >= RDI_INTF_0 && - stream_info->stream_src <= RDI_INTF_2)) { - dual_vfe_res = NULL; - } else { - pr_err("%s: Error! Should not reach this case is_split %d stream_src %d\n", - __func__, vfe_dev->is_split, stream_info->stream_src); - msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); + /* Isolate pingpong_bit from pingpong_status */ + pingpong_bit = ((pingpong_status >> + stream_info->wm[0][0]) & 0x1); + + /* return if buffer already present */ + if (stream_info->buf[!pingpong_bit]) { + pr_err("stream %x buffer already set for pingpong %d\n", + stream_info->stream_src, pingpong_bit); return 0; } - if (!scratch) - buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); + buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); - /* Isolate pingpong_bit from pingpong_status */ - pingpong_bit = ((pingpong_status >> - stream_info->wm[0]) & 0x1); + if (!buf) { + msm_isp_cfg_stream_scratch(stream_info, pingpong_status); + return 0; + } for (i = 0; i < stream_info->num_planes; i++) { - if (buf) { - word_per_line = msm_isp_cal_word_per_line( - stream_info->output_format, stream_info-> - plane_cfg[i].output_stride); + paddr = buf->mapped_info[i].paddr; + ISP_DBG( + "%s: vfe %d config buf %d to pingpong %d stream %x\n", + __func__, vfe_dev->pdev->id, + buf->buf_idx, !pingpong_bit, + stream_info->stream_id); + for (j = 0; j < stream_info->num_isp; j++) { + vfe_dev = stream_info->vfe_dev[j]; + word_per_line = + msm_isp_cal_word_per_line( + stream_info->output_format, + stream_info->plane_cfg[j][i].output_stride); if (word_per_line < 0) { /* 0 means no prefetch*/ word_per_line = 0; buffer_size_byte = 0; } else { - buffer_size_byte = (word_per_line * 8 * - stream_info->plane_cfg[i]. - output_scan_lines) - stream_info-> - plane_cfg[i].plane_addr_offset; + buffer_size_byte = + (word_per_line * 8 * + stream_info->plane_cfg[j][i]. + output_scan_lines) - + stream_info->plane_cfg[j][i]. + plane_addr_offset; } - - paddr = buf->mapped_info[i].paddr; - ISP_DBG( - "%s: vfe %d config buf %d to pingpong %d stream %x\n", - __func__, vfe_dev->pdev->id, - buf->buf_idx, !pingpong_bit, - stream_info->stream_id); - } - - if (dual_vfe_res) { - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - if (vfe_id != vfe_dev->pdev->id) - spin_lock_irqsave( - &dual_vfe_res-> - axi_data[vfe_id]-> - stream_info[stream_idx]. - lock, flags); - - if (buf) - vfe_dev->hw_info->vfe_ops.axi_ops. - update_ping_pong_addr( - dual_vfe_res->vfe_base[vfe_id], - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].wm[i], - pingpong_bit, paddr + - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx]. - plane_cfg[i].plane_addr_offset, - buffer_size_byte); - else - msm_isp_cfg_stream_scratch( - dual_vfe_res->vfe_dev[vfe_id], - &(dual_vfe_res->axi_data - [vfe_id]-> - stream_info[stream_idx]), - pingpong_status); - - if (i == 0) { - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx]. - buf[!pingpong_bit] = - buf; - } - if (vfe_id != vfe_dev->pdev->id) - spin_unlock_irqrestore( - &dual_vfe_res-> - axi_data[vfe_id]-> - stream_info[stream_idx]. - lock, flags); - } - } else { - if (buf) - vfe_dev->hw_info->vfe_ops.axi_ops. + vfe_dev->hw_info->vfe_ops.axi_ops. update_ping_pong_addr( - vfe_dev->vfe_base, stream_info->wm[i], + vfe_dev->vfe_base, + stream_info->wm[j][i], pingpong_bit, paddr + - stream_info->plane_cfg[i]. - plane_addr_offset, + stream_info->plane_cfg[j][i]. + plane_addr_offset, buffer_size_byte); - else - msm_isp_cfg_stream_scratch(vfe_dev, - stream_info, pingpong_status); - if (0 == i) - stream_info->buf[!pingpong_bit] = buf; } - if (0 == i && buf) - buf->pingpong_bit = !pingpong_bit; } - + stream_info->buf[!pingpong_bit] = buf; + buf->pingpong_bit = !pingpong_bit; return 0; } @@ -1805,10 +1785,14 @@ static void msm_isp_handle_done_buf_frame_id_mismatch( vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; error_event.u.error_info.err_type = ISP_ERROR_FRAME_ID_MISMATCH; - ret = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, time_stamp, - frame_id, - stream_info->runtime_output_format); + if (stream_info->buf_divert) + vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + else + ret = vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, time_stamp, + frame_id, + stream_info->runtime_output_format); if (ret == -EFAULT) { msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); return; @@ -1827,7 +1811,7 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, int rc; unsigned long flags; struct msm_isp_event_data buf_event; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + uint32_t stream_idx = stream_info->stream_src; uint32_t buf_src; uint8_t drop_frame = 0; struct msm_isp_bufq *bufq = NULL; @@ -1877,11 +1861,16 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, buf->buf_debug.put_state_last] = MSM_ISP_BUFFER_STATE_DROP_SKIP; buf->buf_debug.put_state_last ^= 1; - rc = vfe_dev->buf_mgr->ops->buf_done( - vfe_dev->buf_mgr, - buf->bufq_handle, buf->buf_idx, - time_stamp, frame_id, - stream_info->runtime_output_format); + if (stream_info->buf_divert) + vfe_dev->buf_mgr->ops->put_buf( + vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx); + else + rc = vfe_dev->buf_mgr->ops->buf_done( + vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, + time_stamp, frame_id, + stream_info->runtime_output_format); if (rc == -EFAULT) { msm_isp_halt_send_error(vfe_dev, @@ -1920,6 +1909,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, return -EINVAL; } + /* divert native buffers */ + vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + buf->bufq_handle, buf->buf_idx, time_stamp, + frame_id); + if ((bufq != NULL) && bufq->buf_type == ISP_SHARE_BUF) msm_isp_send_event(vfe_dev->common_data-> dual_vfe_res->vfe_dev[ISP_VFE1], @@ -1959,6 +1953,7 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, unsigned long flags; struct msm_isp_bufq *bufq = NULL; uint32_t pingpong_bit; + int vfe_idx; if (!vfe_dev || !stream_info || !ts || !sof_info) { pr_err("%s %d vfe_dev %pK stream_info %pK ts %pK op_info %pK\n", @@ -1966,11 +1961,14 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, sof_info); return -EINVAL; } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + pingpong_status = ~vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(vfe_dev); spin_lock_irqsave(&stream_info->lock, flags); - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + pingpong_bit = + (~(pingpong_status >> stream_info->wm[vfe_idx][0]) & 0x1); done_buf = stream_info->buf[pingpong_bit]; if (done_buf) { bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr, @@ -1996,93 +1994,149 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev, return 0; } -static void msm_isp_get_camif_update_state_and_halt( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state *camif_update, - int *halt) +/** + * msm_isp_input_disable() - Disable the input for given vfe + * @vfe_dev: The vfe device whose input is to be disabled + * + * Returns - void + * + * If stream count on an input line is 0 then disable the input + */ +static void msm_isp_input_disable(struct vfe_device *vfe_dev) { - int i; - struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt; - cur_pix_stream_cnt = - axi_data->src_info[VFE_PIX_0].pix_stream_count + - axi_data->src_info[VFE_PIX_0].raw_stream_count; - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src < RDI_INTF_0) - pix_stream_cnt++; - } + int ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + int stream_count; + int total_stream_count = 0; + int i; - if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams - && (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) - *halt = 1; - else - *halt = 0; - - if ((pix_stream_cnt) && - (axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) { - if (cur_pix_stream_cnt == 0 && pix_stream_cnt && - stream_cfg_cmd->cmd == START_STREAM) - *camif_update = ENABLE_CAMIF; - else if (cur_pix_stream_cnt && - (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { - if (*halt) - *camif_update = DISABLE_CAMIF_IMMEDIATELY; - else - *camif_update = DISABLE_CAMIF; - } + for (i = 0; i < VFE_SRC_MAX; i++) + total_stream_count += axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + + for (i = 0; i < VFE_SRC_MAX; i++) { + stream_count = axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (stream_count) + continue; + if (axi_data->src_info[i].active == 0) + continue; + /* deactivate the input line */ + axi_data->src_info[i].active = 0; + + if (i != VFE_PIX_0 || ext_read) + continue; + /* halt camif */ + if (total_stream_count == 0) + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, + DISABLE_CAMIF_IMMEDIATELY); else - *camif_update = NO_UPDATE; - } else - *camif_update = NO_UPDATE; + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); + } + + /* halt and reset hardware if all streams are disabled */ + if (total_stream_count == 0) { + vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); + vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1); + vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); + + } } -static void msm_isp_update_camif_output_count( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +/** + * msm_isp_input_enable() - Enable the input for given vfe + * @vfe_dev: The vfe device whose input is to be enabled + * + * Returns - void + * + * Enable inout line if it is not enabled + */ +static void msm_isp_input_enable(struct vfe_device *vfe_dev, + int sync_frame_id_src) { - int i; - struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + int stream_count; + int i; - if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) - return; - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return; + for (i = 0; i < VFE_SRC_MAX; i++) { + stream_count = axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (stream_count == 0) + continue; + if (axi_data->src_info[i].active) + continue; + /* activate the input since it is deactivated */ + axi_data->src_info[i].frame_id = 0; + axi_data->src_info[i].active = 1; + if (i >= VFE_RAW_0 && sync_frame_id_src) { + /* + * Incase PIX and RDI streams are part + * of same session, this will ensure + * RDI stream will have same frame id + * as of PIX stream + */ + axi_data->src_info[i].frame_id = + axi_data->src_info[VFE_PIX_0].frame_id; } - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src >= RDI_INTF_0) + if (i != VFE_PIX_0 || ext_read) continue; - if (stream_info->stream_src == PIX_ENCODER || - stream_info->stream_src == PIX_VIEWFINDER || - stream_info->stream_src == PIX_VIDEO || - stream_info->stream_src == IDEAL_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count++; + /* for camif input the camif needs enabling */ + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, ENABLE_CAMIF); + } +} + +/** + * msm_isp_update_intf_stream_cnt() - Update the stream count in axi interface + * @stream_info: The stream that is either being enabled/disabled + * @enable: 0 means stream is being disabled, else enabled + * + * Returns - void + */ +static void msm_isp_update_intf_stream_cnt( + struct msm_vfe_axi_stream *stream_info, + int enable) +{ + int i; + + switch (stream_info->stream_src) { + case PIX_ENCODER: + case PIX_VIEWFINDER: + case PIX_VIDEO: + case IDEAL_RAW: + case RDI_INTF_0: + case RDI_INTF_1: + case RDI_INTF_2: + for (i = 0; i < stream_info->num_isp; i++) { + if (enable) + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. + stream_count++; else - vfe_dev->axi_data.src_info[VFE_PIX_0]. - pix_stream_count--; - } else if (stream_info->stream_src == CAMIF_RAW) { - if (stream_cfg_cmd->cmd == START_STREAM) - vfe_dev->axi_data.src_info[VFE_PIX_0]. + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. + stream_count--; + } + break; + case CAMIF_RAW: + for (i = 0; i < stream_info->num_isp; i++) { + if (enable) + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. raw_stream_count++; else - vfe_dev->axi_data.src_info[VFE_PIX_0]. + stream_info->vfe_dev[i]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)]. raw_stream_count--; } + break; + default: + WARN(1, "Invalid steam src %d\n", stream_info->stream_src); } } @@ -2093,20 +2147,24 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) { int i, rc = 0; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint64_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0; uint32_t num_pix_streams = 0; uint64_t total_bandwidth = 0; + int vfe_idx; for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = &axi_data->stream_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); if (stream_info->state == ACTIVE || stream_info->state == START_PENDING) { + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); if (stream_info->stream_src < RDI_INTF_0) { - total_pix_bandwidth += stream_info->bandwidth; + total_pix_bandwidth += + stream_info->bandwidth[vfe_idx]; num_pix_streams++; } else { - total_rdi_bandwidth += stream_info->bandwidth; + total_rdi_bandwidth += + stream_info->bandwidth[vfe_idx]; } } } @@ -2121,121 +2179,88 @@ static int msm_isp_update_stream_bandwidth(struct vfe_device *vfe_dev) return rc; } -static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev, - enum msm_isp_camif_update_state camif_update, - uint32_t src_mask, int regUpdateCnt) -{ - int rc; - unsigned long flags; - enum msm_vfe_input_src i = 0; - spin_lock_irqsave(&vfe_dev->shared_data_lock, flags); - - for (i = 0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - if (vfe_dev->axi_data.stream_update[i] > 0) { - pr_err("%s:Stream Update in progress. cnt %d\n", - __func__, - vfe_dev->axi_data.stream_update[i]); - spin_unlock_irqrestore( - &vfe_dev->shared_data_lock, flags); - return -EINVAL; - } - vfe_dev->axi_data.stream_update[i] = regUpdateCnt; - } - } - if (src_mask) { - init_completion(&vfe_dev->stream_config_complete); - vfe_dev->axi_data.pipeline_update = camif_update; - } - spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags); - rc = wait_for_completion_timeout( - &vfe_dev->stream_config_complete, - msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - for (i = 0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - spin_lock_irqsave(&vfe_dev->shared_data_lock, - flags); - vfe_dev->axi_data.stream_update[i] = 0; - spin_unlock_irqrestore(&vfe_dev-> - shared_data_lock, flags); - } - } - pr_err("%s: wait timeout\n", __func__); - rc = -EBUSY; - } else { - rc = 0; - } - return rc; -} - static int msm_isp_init_stream_ping_pong_reg( - struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { int rc = 0; - if ((vfe_dev->is_split && vfe_dev->pdev->id == 1 && - stream_info->stream_src < RDI_INTF_0) || - !vfe_dev->is_split || stream_info->stream_src >= RDI_INTF_0) { - /* Set address for both PING & PONG register */ - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG, 0); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", - __func__); - return rc; - } - - if (stream_info->stream_type != BURST_STREAM || - stream_info->runtime_num_burst_capture > 1) - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG, 0); + /* Set address for both PING & PO NG register */ + rc = msm_isp_cfg_ping_pong_address( + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", + __func__); + return rc; + } + if (stream_info->stream_type != BURST_STREAM || + stream_info->runtime_num_burst_capture > 1) + rc = msm_isp_cfg_ping_pong_address( + stream_info, VFE_PONG_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", - __func__); - return rc; - } + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", + __func__); + return rc; } return rc; } static void msm_isp_get_stream_wm_mask( + struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info, uint32_t *wm_reload_mask) { int i; + int vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + for (i = 0; i < stream_info->num_planes; i++) - *wm_reload_mask |= (1 << stream_info->wm[i]); + *wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]); } int msm_isp_axi_halt(struct vfe_device *vfe_dev, struct msm_vfe_axi_halt_cmd *halt_cmd) { int rc = 0; + int i; + struct vfe_device *halt_vfes[MAX_VFE] = { NULL, NULL }; - if (atomic_read(&vfe_dev->error_info.overflow_state) == - OVERFLOW_DETECTED) { - ISP_DBG("%s: VFE%d already halted, direct return\n", - __func__, vfe_dev->pdev->id); - return rc; - } + if (vfe_dev->is_split) + for (i = 0; i < MAX_VFE; i++) + halt_vfes[i] = vfe_dev->common_data-> + dual_vfe_res->vfe_dev[i]; + else + halt_vfes[vfe_dev->pdev->id] = vfe_dev; - if (halt_cmd->overflow_detected) { - atomic_cmpxchg(&vfe_dev->error_info.overflow_state, - NO_OVERFLOW, OVERFLOW_DETECTED); - pr_err("%s: VFE%d Bus overflow detected: start recovery!\n", - __func__, vfe_dev->pdev->id); - } + for (i = 0; i < MAX_VFE; i++) { + vfe_dev = halt_vfes[i]; + if (!vfe_dev) + continue; + if (atomic_read(&vfe_dev->error_info.overflow_state) == + OVERFLOW_DETECTED) { + ISP_DBG("%s: VFE%d already halted, direct return\n", + __func__, vfe_dev->pdev->id); + continue; + } - if (halt_cmd->stop_camif) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY); + if (halt_cmd->overflow_detected) { + atomic_cmpxchg(&vfe_dev->error_info.overflow_state, + NO_OVERFLOW, OVERFLOW_DETECTED); + pr_err("%s: VFE%d Bus overflow detected: start recovery!\n", + __func__, vfe_dev->pdev->id); + } + + if (halt_cmd->stop_camif) { + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, + DISABLE_CAMIF_IMMEDIATELY); + } + rc |= vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, + halt_cmd->blocking_halt); + + /* take care of pending items in tasklet after halt */ + msm_isp_flush_tasklet(vfe_dev); } - rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, - halt_cmd->blocking_halt); return rc; } @@ -2243,12 +2268,13 @@ int msm_isp_axi_halt(struct vfe_device *vfe_dev, int msm_isp_axi_reset(struct vfe_device *vfe_dev, struct msm_vfe_axi_reset_cmd *reset_cmd) { - int rc = 0, i, j; + int rc = 0, i, k; struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t bufq_handle = 0, bufq_id = 0; struct msm_isp_timestamp timestamp; unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; if (!reset_cmd) { pr_err("%s: NULL pointer reset cmd %pK\n", __func__, reset_cmd); @@ -2258,49 +2284,74 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, reset_cmd->blocking); + if (vfe_dev->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev->common_data->dual_vfe_res-> + vfe_dev[i]; + } else { + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } msm_isp_get_timestamp(×tamp); - for (i = 0, j = 0; j < axi_data->num_active_stream && - i < VFE_AXI_SRC_MAX; i++, j++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { - rc = -1; - pr_err("%s invalid stream src = %d\n", __func__, - stream_info->stream_src); - break; - } - if (stream_info->state != ACTIVE) { - j--; + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; - } + rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, + 0, reset_cmd->blocking); - for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { - bufq_handle = stream_info->bufq_handle[bufq_id]; - if (!bufq_handle) - continue; - /* set ping pong address to scratch before flush */ - spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PONG_FLAG); - spin_unlock_irqrestore(&stream_info->lock, flags); - rc = vfe_dev->buf_mgr->ops->flush_buf( - vfe_dev->buf_mgr, vfe_dev->pdev->id, - bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, - ×tamp.buf_time, reset_cmd->frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data( + vfe_dev, i); + if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { + rc = -1; + pr_err("%s invalid stream src = %d\n", + __func__, + stream_info->stream_src); + break; } + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) + continue; - axi_data->src_info[SRC_TO_INTF(stream_info-> - stream_src)].frame_id = reset_cmd->frame_id; - msm_isp_reset_burst_count_and_frame_drop(vfe_dev, - stream_info); + /* handle dual stream on ISP_VFE1 turn */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + + for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; + bufq_id++) { + bufq_handle = stream_info->bufq_handle[bufq_id]; + if (!bufq_handle) + continue; + + /* set ping pong to scratch before flush */ + spin_lock_irqsave(&stream_info->lock, flags); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, + VFE_PONG_FLAG); + spin_unlock_irqrestore(&stream_info->lock, + flags); + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, + ×tamp.buf_time, + reset_cmd->frame_id); + if (rc == -EFAULT) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return rc; + } + + axi_data->src_info[SRC_TO_INTF(stream_info-> + stream_src)].frame_id = + reset_cmd->frame_id; + msm_isp_reset_burst_count_and_frame_drop( + vfe_dev, stream_info); + } } } @@ -2310,46 +2361,67 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, return rc; } -int msm_isp_axi_restart(struct vfe_device *vfe_dev, +int msm_isp_axi_restart(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_axi_restart_cmd *restart_cmd) { - int rc = 0, i, j; + int rc = 0, i, k, j; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - uint32_t wm_reload_mask = 0x0; + uint32_t wm_reload_mask = 0; unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; - vfe_dev->buf_mgr->frameId_mismatch_recovery = 0; - for (i = 0, j = 0; j < axi_data->num_active_stream && - i < VFE_AXI_SRC_MAX; i++, j++) { - stream_info = &axi_data->stream_info[i]; - if (stream_info->state != ACTIVE) { - j--; + if (vfe_dev_ioctl->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev_ioctl->common_data-> + dual_vfe_res->vfe_dev[i]; + } else { + update_vfes[vfe_dev_ioctl->pdev->id] = vfe_dev_ioctl; + } + + vfe_dev_ioctl->buf_mgr->frameId_mismatch_recovery = 0; + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; + vfe_dev->buf_mgr->frameId_mismatch_recovery = 0; + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { + stream_info = msm_isp_get_stream_common_data( + vfe_dev, i); + if (stream_info->state == AVAILABLE || + stream_info->state == INACTIVE) + continue; + msm_isp_get_stream_wm_mask(vfe_dev, stream_info, + &wm_reload_mask); + /* handle dual stream on ISP_VFE1 turn */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++) + stream_info->composite_irq[j] = 0; + msm_isp_init_stream_ping_pong_reg(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } - msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); - spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); - spin_unlock_irqrestore(&stream_info->lock, flags); - } - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, wm_reload_mask); - rc = vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0, - restart_cmd->enable_camif); - if (rc < 0) - pr_err("%s Error restarting HW\n", __func__); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + vfe_dev->vfe_base, wm_reload_mask); + vfe_dev->hw_info->vfe_ops.axi_ops.restart(vfe_dev, 0, + restart_cmd->enable_camif); + } return rc; } -static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev, +static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, uint8_t cgc_override) { int i = 0, j = 0; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + int k; + struct vfe_device *vfe_dev; + int vfe_idx; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) return -EINVAL; @@ -2359,14 +2431,21 @@ static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev, VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); for (j = 0; j < stream_info->num_planes; j++) { - if (vfe_dev->hw_info->vfe_ops.axi_ops. - update_cgc_override) + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (!vfe_dev->hw_info->vfe_ops.axi_ops. + update_cgc_override) + continue; + vfe_idx = msm_isp_get_vfe_idx_for_stream( + vfe_dev, stream_info); vfe_dev->hw_info->vfe_ops.axi_ops. update_cgc_override(vfe_dev, - stream_info->wm[j], cgc_override); + stream_info->wm[vfe_idx][j], + cgc_override); + } } } return 0; @@ -2458,8 +2537,7 @@ static int msm_isp_update_dual_HW_ms_info_at_start( static int msm_isp_update_dual_HW_ms_info_at_stop( struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; uint8_t slave_id; @@ -2478,13 +2556,13 @@ static int msm_isp_update_dual_HW_ms_info_at_stop( VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); stream_src = SRC_TO_INTF(stream_info->stream_src); /* Remove PIX if DISABLE CAMIF */ - if (stream_src == VFE_PIX_0 && !((camif_update == DISABLE_CAMIF) - || (camif_update == DISABLE_CAMIF_IMMEDIATELY))) + if (stream_src == VFE_PIX_0 && + axi_data->src_info[VFE_PIX_0].active) continue; src_info = &axi_data->src_info[stream_src]; @@ -2519,404 +2597,489 @@ static int msm_isp_update_dual_HW_ms_info_at_stop( return rc; } -static int msm_isp_update_dual_HW_axi(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream *stream_info) +/** + * msm_isp_axi_wait_for_stream_cfg_done() - Wait for a stream completion + * @stream_info: The stream to wait on + * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE + * + * Returns - 0 on success else error code + */ +static int msm_isp_axi_wait_for_stream_cfg_done( + struct msm_vfe_axi_stream *stream_info, int active) { + int rc = -1; + unsigned long flags; + + /* No need to wait if stream is already in required state */ + spin_lock_irqsave(&stream_info->lock, flags); + if (active && ACTIVE == stream_info->state) + rc = 0; + if (!active && INACTIVE == stream_info->state) + rc = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc == 0) + return rc; + + rc = wait_for_completion_timeout( + active ? &stream_info->active_comp : + &stream_info->inactive_comp, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); + + if (rc <= 0) { + rc = rc ? rc : -ETIMEDOUT; + pr_err("%s: wait for stream %x/%x state %d config failed %d\n", + __func__, + stream_info->stream_id, + stream_info->stream_src, + stream_info->state, + rc); + rc = -EINVAL; + } else { + rc = 0; + } + return rc; +} + +/** + * msm_isp_axi_wait_for_streams() - Wait for completion of a number of streams + * @streams: The streams to wait on + * @num_stream: Number of streams to wait on + * @active: Reset means wait for stream to be INACTIVE else wait for ACTIVE + * + * Returns - 0 on success else error code + */ +static int msm_isp_axi_wait_for_streams(struct msm_vfe_axi_stream **streams, + int num_stream, int active) +{ + int i; int rc = 0; - int vfe_id; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; + struct msm_vfe_axi_stream *stream_info; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream idx %d\n", __func__, stream_idx); + for (i = 0; i < num_stream; i++) { + stream_info = streams[i]; + rc |= msm_isp_axi_wait_for_stream_cfg_done(stream_info, active); + } + return rc; +} + +static int __msm_isp_check_stream_state(struct msm_vfe_axi_stream *stream_info, + int cmd) +{ + switch (stream_info->state) { + case AVAILABLE: return -EINVAL; + case PAUSING: + case RESUMING: + case RESUME_PENDING: + case ACTIVE: + if (cmd != 0) + return -EALREADY; + break; + case INACTIVE: + if (cmd == 0) + return -EALREADY; + break; + /* + * stream cannot be in following states since we always + * wait in ioctl for stream to be active or inactive + */ + case UPDATING: + case START_PENDING: + case STARTING: + case STOPPING: + case STOP_PENDING: + case PAUSE_PENDING: + default: + WARN(1, "Invalid state %d\n", stream_info->state); } + return 0; +} - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_dev[ISP_VFE0] || - !dual_vfe_res->vfe_dev[ISP_VFE1] || - !dual_vfe_res->axi_data[ISP_VFE0] || - !dual_vfe_res->axi_data[ISP_VFE1]) { - pr_err("%s: Error in dual vfe resource\n", __func__); - rc = -EINVAL; - } else { - if (stream_info->state == RESUME_PENDING && - (dual_vfe_res->axi_data[!vfe_dev->pdev->id]-> - stream_info[stream_idx].state == RESUME_PENDING)) { - /* Update the AXI only after both ISPs receiving the - Reg update interrupt*/ - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - rc = msm_isp_axi_stream_enable_cfg( - dual_vfe_res->vfe_dev[vfe_id], - &dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx], 1); - dual_vfe_res->axi_data[vfe_id]-> - stream_info[stream_idx].state = - RESUMING; +static void __msm_isp_stop_axi_streams(struct msm_vfe_axi_stream **streams, + int num_streams, int cmd_type) +{ + int i; + struct msm_vfe_axi_shared_data *axi_data; + struct msm_isp_timestamp timestamp; + int total_stream_count = 0; + uint32_t bufq_id = 0, bufq_handle = 0; + struct msm_vfe_axi_stream *stream_info; + unsigned long flags; + uint32_t intf; + int rc; + struct vfe_device *vfe_dev; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + int k; + + msm_isp_get_timestamp(×tamp); + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + spin_lock_irqsave(&stream_info->lock, flags); + /* + * since we can get here from start axi stream error path due + * to which the stream may be intermittent state like + * STARTING/START_PENDING, force the stream to move out of + * intermittent state so it can be made INACTIVE. The + * intermittent states update variables so better to go through + * those state transitions instead of directly forcing stream to + * be INACTIVE + */ + while (stream_info->state != ACTIVE) + __msm_isp_axi_stream_update(stream_info, + ×tamp); + msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); + msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (stream_info->num_planes > 1) + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + else + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } + init_completion(&stream_info->inactive_comp); + stream_info->state = STOP_PENDING; + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_update_intf_stream_cnt(stream_info, 0); + } + + for (k = 0; k < MAX_VFE; k++) { + int ext_read; + + if (!update_vfes[k]) + continue; + vfe_dev = update_vfes[k]; + axi_data = &vfe_dev->axi_data; + ext_read = + (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); + for (i = 0; i < VFE_SRC_MAX; i++) { + total_stream_count += + axi_data->src_info[i].stream_count + + axi_data->src_info[i].raw_stream_count; + if (i != VFE_PIX_0) + continue; + if (axi_data->src_info[i].stream_count == 0) { + vfe_dev->hw_info->vfe_ops.stats_ops. + enable_module(vfe_dev, 0xFF, 0); + /* reg update for PIX with 0 streams active */ + if (ext_read == 0) + vfe_dev->hw_info->vfe_ops.core_ops. + reg_update(vfe_dev, VFE_PIX_0); } } + + } + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + intf = SRC_TO_INTF(stream_info->stream_src); + if (total_stream_count == 0 || + ((stream_info->stream_type == BURST_STREAM) && + stream_info->runtime_num_burst_capture == 0)) { + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + } + + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0); + if (rc) { + pr_err("%s: wait for stream comp failed, retry...\n", __func__); + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_axi_stream_update(stream_info, + ×tamp); + spin_unlock_irqrestore(&stream_info->lock, flags); + } + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 0); + if (rc) { + pr_err("%s: wait for stream comp failed, force streams to inactive\n", + __func__); + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != INACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); + spin_unlock_irqrestore(&stream_info->lock, + flags); + } + } + } + /* clear buffers that are dequeued */ + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { + bufq_handle = stream_info->bufq_handle[bufq_id]; + if (!bufq_handle) + continue; + vfe_dev = stream_info->vfe_dev[0]; + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, + ×tamp.buf_time, 0); + if (rc == -EFAULT) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + } + } + + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k]) + continue; + msm_isp_update_stream_bandwidth(update_vfes[k]); + msm_isp_input_disable(update_vfes[k]); + } + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + intf = SRC_TO_INTF(stream_info->stream_src); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + axi_data = &vfe_dev->axi_data; + if (axi_data->src_info[intf].stream_count == 0) + vfe_dev->reg_update_requested &= + ~(BIT(intf)); + } } - return rc; } -static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update) +static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; - uint8_t src_state, wait_for_complete = 0; - uint32_t wm_reload_mask = 0x0; + uint8_t src_state; + uint32_t wm_reload_mask[MAX_VFE] = {0, 0}; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; uint32_t src_mask = 0; unsigned long flags; + struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM]; + int num_streams = 0; + struct msm_isp_timestamp timestamp; + struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; + int k; + uint32_t num_active_streams[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; + struct msm_vfe_axi_shared_data *axi_data = &vfe_dev_ioctl->axi_data; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) return -EINVAL; - if (camif_update == ENABLE_CAMIF) { - ISP_DBG("%s: vfe %d camif enable\n", __func__, - vfe_dev->pdev->id); - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0; - } + msm_isp_get_timestamp(×tamp); for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); if (SRC_TO_INTF(stream_info->stream_src) < VFE_SRC_MAX) src_state = axi_data->src_info[ SRC_TO_INTF(stream_info->stream_src)].active; + else { ISP_DBG("%s: invalid src info index\n", __func__); - return -EINVAL; + rc = -EINVAL; + goto error; } - - msm_isp_calculate_bandwidth(axi_data, stream_info); - msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask); spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_reset_framedrop(vfe_dev, stream_info); - rc = msm_isp_init_stream_ping_pong_reg(vfe_dev, stream_info); + rc = __msm_isp_check_stream_state(stream_info, 1); + if (-EALREADY == rc) { + rc = 0; + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + goto error; + } + + msm_isp_calculate_bandwidth(stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], + stream_info, &wm_reload_mask[ + stream_info->vfe_dev[k]->pdev->id]); + src_state = stream_info->vfe_dev[k]->axi_data.src_info[ + SRC_TO_INTF(stream_info->stream_src)].active; + if (update_vfes[stream_info->vfe_dev[k]->pdev->id]) + continue; + update_vfes[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]; + num_active_streams[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]->axi_data. + num_active_stream; + } + msm_isp_reset_framedrop(vfe_dev_ioctl, stream_info); + rc = msm_isp_init_stream_ping_pong_reg(stream_info); if (rc < 0) { pr_err("%s: No buffer for stream%d\n", __func__, HANDLE_TO_IDX( stream_cfg_cmd->stream_handle[i])); spin_unlock_irqrestore(&stream_info->lock, flags); - return rc; + goto error; } - spin_unlock_irqrestore(&stream_info->lock, flags); - if (stream_info->num_planes > 1) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_comp_mask(vfe_dev, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } } + init_completion(&stream_info->active_comp); stream_info->state = START_PENDING; + msm_isp_update_intf_stream_cnt(stream_info, 1); - ISP_DBG("%s, Stream 0x%x src %d src_state %d on vfe %d\n", - __func__, stream_info->stream_id, - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]), - src_state, vfe_dev->pdev->id); - + ISP_DBG("%s, Stream 0x%x src_state %d on vfe %d\n", __func__, + stream_info->stream_src, src_state, + vfe_dev_ioctl->pdev->id); if (src_state) { src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src)); - wait_for_complete = 1; } else { - if (vfe_dev->dump_reg) - msm_camera_io_dump(vfe_dev->vfe_base, - 0x1000, 1); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; - /*Configure AXI start bits to start immediately*/ - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info, 0); - stream_info->state = ACTIVE; - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); + if (vfe_dev->dump_reg) + msm_camera_io_dump(vfe_dev->vfe_base, + 0x1000, 1); + } - /* - * Active bit is set in enable_camif for PIX. - * For RDI, set it here - */ - if (SRC_TO_INTF(stream_info->stream_src) >= VFE_RAW_0 && - SRC_TO_INTF(stream_info->stream_src) < - VFE_SRC_MAX) { - /* Incase PIX and RDI streams are part of same - * session, this will ensure RDI stream will - * have same frame id as of PIX stream - */ - if (stream_cfg_cmd->sync_frame_id_src) - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].frame_id = - vfe_dev->axi_data.src_info[VFE_PIX_0] - .frame_id; - else - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].frame_id = 0; - vfe_dev->axi_data.src_info[SRC_TO_INTF( - stream_info->stream_src)].active = 1; + /* Configure AXI start bits to start immediately */ + while (stream_info->state != ACTIVE) + __msm_isp_axi_stream_update( + stream_info, ×tamp); + + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.core_ops.reg_update( + vfe_dev, + SRC_TO_INTF(stream_info->stream_src)); } } + spin_unlock_irqrestore(&stream_info->lock, flags); + streams[num_streams++] = stream_info; } - msm_isp_update_stream_bandwidth(vfe_dev); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, wm_reload_mask); - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - if (camif_update == ENABLE_CAMIF) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, camif_update); - vfe_dev->axi_data.camif_state = CAMIF_ENABLE; - vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; + for (i = 0; i < MAX_VFE; i++) { + vfe_dev = update_vfes[i]; + if (!vfe_dev) + continue; + if (num_active_streams[i] == 0) { + /* Configure UB */ + vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); + /* when start reset overflow state */ + atomic_set(&vfe_dev->error_info.overflow_state, + NO_OVERFLOW); + } + msm_isp_update_stream_bandwidth(vfe_dev); + vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, + vfe_dev->vfe_base, wm_reload_mask[i]); + + msm_isp_input_enable(vfe_dev, + stream_cfg_cmd->sync_frame_id_src); } - if (wait_for_complete) { - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update, - src_mask, 2); - if (rc < 0) { - pr_err("%s: wait for config done failed\n", __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOPPING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 0); - stream_cfg_cmd->cmd = STOP_IMMEDIATELY; - msm_isp_update_camif_output_count(vfe_dev, - stream_cfg_cmd); - } - } + rc = msm_isp_axi_wait_for_streams(streams, num_streams, 1); + if (rc < 0) { + pr_err("%s: wait for config done failed\n", __func__); + goto error; } + return 0; +error: + __msm_isp_stop_axi_streams(streams, num_streams, + STOP_STREAM); + return rc; } -static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd, - enum msm_isp_camif_update_state camif_update, - int halt) +static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev_ioctl, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; - uint8_t wait_for_complete_for_this_stream = 0; struct msm_vfe_axi_stream *stream_info = NULL; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - int ext_read = - (axi_data->src_info[VFE_PIX_0].input_mux == EXTERNAL_READ); - uint32_t src_mask = 0, intf, bufq_id = 0, bufq_handle = 0; + struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM]; + int num_streams = 0; unsigned long flags; - struct msm_isp_timestamp timestamp; if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || stream_cfg_cmd->num_streams == 0) return -EINVAL; - msm_isp_get_timestamp(×tamp); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= - VFE_AXI_SRC_MAX) { - return -EINVAL; - } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); - /* set ping pong address to scratch before stream stop */ spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PONG_FLAG); + rc = __msm_isp_check_stream_state(stream_info, 0); spin_unlock_irqrestore(&stream_info->lock, flags); - wait_for_complete_for_this_stream = 0; - - if (stream_info->num_planes > 1) - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_comp_mask(vfe_dev, stream_info); - else - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - - stream_info->state = STOP_PENDING; - - if (!halt && !ext_read && - !(stream_info->stream_type == BURST_STREAM && - stream_info->runtime_num_burst_capture == 0)) - wait_for_complete_for_this_stream = 1; - - ISP_DBG("%s: stream 0x%x, vfe %d camif %d halt %d wait %d\n", - __func__, - stream_info->stream_id, - vfe_dev->pdev->id, - camif_update, - halt, - wait_for_complete_for_this_stream); - - intf = SRC_TO_INTF(stream_info->stream_src); - if (!wait_for_complete_for_this_stream || - stream_info->state == INACTIVE || - !vfe_dev->axi_data.src_info[intf].active) { - msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info, 0); - stream_info->state = INACTIVE; - vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); - + if (rc) { /* - * Active bit is reset in disble_camif for PIX. - * For RDI, reset it here for not wait_for_complete - * This is assuming there is only 1 stream mapped to - * each RDI. + * continue stopping other streams as error here means + * stream is already not active */ - if (intf >= VFE_RAW_0 && - intf < VFE_SRC_MAX) { - vfe_dev->axi_data.src_info[intf].active = 0; - } - } else - src_mask |= (1 << intf); - - } - - if (src_mask) { - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update, - src_mask, 2); - if (rc < 0) { - pr_err("%s: wait for config done failed, retry...\n", - __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX( - stream_cfg_cmd->stream_handle[i])]; - stream_info->state = STOPPING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 0); - vfe_dev->hw_info->vfe_ops.core_ops.reg_update( - vfe_dev, - SRC_TO_INTF(stream_info->stream_src)); - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, - camif_update, src_mask, 1); - if (rc < 0) { - pr_err("%s: vfe%d cfg done failed\n", - __func__, vfe_dev->pdev->id); - stream_info->state = INACTIVE; - } else - pr_err("%s: vfe%d retry success! report err!\n", - __func__, vfe_dev->pdev->id); - - rc = -EBUSY; - } - } - - /* - * Active bit is reset in disble_camif for PIX. - * For RDI, reset it here after wait_for_complete - * This is assuming there is only 1 stream mapped to each RDI - */ - for (i = VFE_RAW_0; i < VFE_SRC_MAX; i++) { - if (src_mask & (1 << i)) { - vfe_dev->axi_data.src_info[i].active = 0; - } - } - } - - if (camif_update == DISABLE_CAMIF) { - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, DISABLE_CAMIF); - vfe_dev->axi_data.camif_state = CAMIF_DISABLE; - } else if ((camif_update == DISABLE_CAMIF_IMMEDIATELY) || - (ext_read)) { - if (!ext_read) - vfe_dev->hw_info->vfe_ops.core_ops. - update_camif_state(vfe_dev, - DISABLE_CAMIF_IMMEDIATELY); - vfe_dev->axi_data.camif_state = CAMIF_STOPPED; - } - if (halt) { - /*during stop immediately, stop output then stop input*/ - vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1); - vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1); - vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev); - } - - msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd); - msm_isp_update_stream_bandwidth(vfe_dev); - - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - for (bufq_id = 0; bufq_id < VFE_BUF_QUEUE_MAX; bufq_id++) { - bufq_handle = stream_info->bufq_handle[bufq_id]; - if (!bufq_handle) - continue; - - rc = vfe_dev->buf_mgr->ops->flush_buf( - vfe_dev->buf_mgr, vfe_dev->pdev->id, - bufq_handle, MSM_ISP_BUFFER_FLUSH_ALL, - ×tamp.buf_time, 0); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; - } + rc = 0; + continue; } - vfe_dev->reg_update_requested &= - ~(BIT(SRC_TO_INTF(stream_info->stream_src))); + streams[num_streams++] = stream_info; } + __msm_isp_stop_axi_streams(streams, num_streams, + stream_cfg_cmd->cmd); return rc; } - int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, ret; struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - enum msm_isp_camif_update_state camif_update; - int halt = 0; - - rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd); - if (rc < 0) { - pr_err("%s: Invalid stream state\n", __func__); - return rc; - } + int i; - if (axi_data->num_active_stream == 0) { - /*Configure UB*/ - vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev); - /*when start reset overflow state*/ - atomic_set(&vfe_dev->error_info.overflow_state, - NO_OVERFLOW); + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >= + VFE_AXI_SRC_MAX) + return -EINVAL; } - msm_isp_get_camif_update_state_and_halt(vfe_dev, stream_cfg_cmd, - &camif_update, &halt); - if (camif_update == DISABLE_CAMIF) - vfe_dev->axi_data.camif_state = CAMIF_STOPPING; if (stream_cfg_cmd->cmd == START_STREAM) { msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 1); rc = msm_isp_start_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update); + vfe_dev, stream_cfg_cmd); } else { rc = msm_isp_stop_axi_stream( - vfe_dev, stream_cfg_cmd, camif_update, halt); + vfe_dev, stream_cfg_cmd); msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 0); - if (axi_data->num_active_stream == 0) { - /* Reset hvx state */ - vfe_dev->hvx_cmd = HVX_DISABLE; - } /* * Use different ret value to not overwrite the error from * msm_isp_stop_axi_stream */ ret = msm_isp_update_dual_HW_ms_info_at_stop( - vfe_dev, stream_cfg_cmd, camif_update); + vfe_dev, stream_cfg_cmd); if (ret < 0) pr_warn("%s: Warning! Update dual_cam failed\n", __func__); + if (vfe_dev->axi_data.num_active_stream == 0) + vfe_dev->hvx_cmd = HVX_DISABLE; + if (vfe_dev->is_split) { + struct vfe_device *vfe_temp = + vfe_dev->common_data-> + dual_vfe_res->vfe_dev[ISP_VFE0]; + if (vfe_temp->axi_data.num_active_stream == 0) + vfe_temp->hvx_cmd = HVX_DISABLE; + } } if (rc < 0) @@ -2943,7 +3106,7 @@ static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, return -EINVAL; } - stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); + stream_idx = stream_info->stream_src; if (!stream_info->controllable_output) return -EINVAL; @@ -3010,10 +3173,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, unsigned long flags; int rc = 0; enum msm_vfe_input_src frame_src = 0; - struct dual_vfe_resource *dual_vfe_res = - vfe_dev->common_data->dual_vfe_res; - uint32_t vfe_id = 0; - bool dual_vfe = false; + int k; + uint32_t wm_mask = 0; + int vfe_idx; if (!vfe_dev || !stream_info) { pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__, @@ -3021,16 +3183,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return -EINVAL; } - if (vfe_dev->is_split) { - if (stream_info->stream_src < RDI_INTF_0) { - if (vfe_dev->pdev->id == ISP_VFE1) { - dual_vfe = true; - } else { - /* return early for dual vfe0 */ - return 0; - } - } - } + /* return early for dual vfe0 */ + if (stream_info->num_isp > 1 && vfe_dev->pdev->id == ISP_VFE0) + return 0; if (stream_info->stream_src >= VFE_AXI_SRC_MAX) { pr_err("%s:%d invalid stream src %d\n", __func__, __LINE__, @@ -3076,7 +3231,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, __func__, __LINE__, frame_src); stream_info->current_framedrop_period = MSM_VFE_STREAM_STOP_PERIOD; - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); return 0; } @@ -3096,7 +3251,8 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, if (!stream_info->bufq_handle[queue_req->buff_queue_id]) { spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s:%d request frame failed on hw stream 0x%x, request stream %d due to no bufq idx: %d\n", - __func__, __LINE__, stream_info->stream_handle, + __func__, __LINE__, + stream_info->stream_handle[0], user_stream_id, queue_req->buff_queue_id); return 0; } @@ -3109,14 +3265,15 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, stream_info->request_q_cnt++; stream_info->undelivered_request_cnt++; - stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle[vfe_idx]; stream_cfg_cmd.frame_skip_pattern = NO_SKIP; stream_cfg_cmd.init_frame_drop = 0; stream_cfg_cmd.burst_count = stream_info->request_q_cnt; if (stream_info->undelivered_request_cnt == 1) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info, - VFE_PING_FLAG, 0); + rc = msm_isp_cfg_ping_pong_address(stream_info, + VFE_PING_FLAG); if (rc) { spin_unlock_irqrestore(&stream_info->lock, flags); stream_info->undelivered_request_cnt--; @@ -3125,41 +3282,23 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return rc; } - vfe_id = vfe_dev->pdev->id; - if (dual_vfe) { - struct msm_vfe_axi_stream *temp_stream_info; - - temp_stream_info = msm_isp_vfe_get_stream(dual_vfe_res, - ISP_VFE0, - HANDLE_TO_IDX( - stream_info->stream_handle)); - msm_isp_get_stream_wm_mask(temp_stream_info, - &dual_vfe_res->wm_reload_mask[ISP_VFE0]); - msm_isp_get_stream_wm_mask(stream_info, - &dual_vfe_res->wm_reload_mask[ISP_VFE1]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->wm_reload_mask[ISP_VFE0]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->wm_reload_mask[ISP_VFE1]); - dual_vfe_res->wm_reload_mask[ISP_VFE0] = 0; - dual_vfe_res->wm_reload_mask[ISP_VFE1] = 0; - } else { - msm_isp_get_stream_wm_mask(stream_info, - &dual_vfe_res->wm_reload_mask[vfe_id]); - vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, - vfe_dev->vfe_base, - dual_vfe_res->wm_reload_mask[vfe_id]); - dual_vfe_res->wm_reload_mask[vfe_id] = 0; + for (k = 0; k < stream_info->num_isp; k++) { + wm_mask = 0; + msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], + stream_info, &wm_mask); + stream_info->vfe_dev[k]-> + hw_info->vfe_ops.axi_ops.reload_wm( + stream_info->vfe_dev[k], + stream_info->vfe_dev[k]->vfe_base, wm_mask); + } stream_info->sw_ping_pong_bit = 0; } else if (stream_info->undelivered_request_cnt == 2) { pingpong_status = vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status( vfe_dev); - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 0); + rc = msm_isp_cfg_ping_pong_address( + stream_info, pingpong_status); if (rc) { stream_info->undelivered_request_cnt--; spin_unlock_irqrestore(&stream_info->lock, @@ -3176,7 +3315,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, return -EINVAL; } - rc = msm_isp_calculate_framedrop(&vfe_dev->axi_data, &stream_cfg_cmd); + rc = msm_isp_calculate_framedrop(vfe_dev, &stream_cfg_cmd); if (0 == rc) msm_isp_reset_framedrop(vfe_dev, stream_info); @@ -3190,25 +3329,45 @@ static int msm_isp_add_buf_queue(struct vfe_device *vfe_dev, { int rc = 0; uint32_t bufq_id = 0; + unsigned long flags; if (stream_id == stream_info->stream_id) bufq_id = VFE_BUF_QUEUE_DEFAULT; else bufq_id = VFE_BUF_QUEUE_SHARED; + spin_lock_irqsave(&stream_info->lock, flags); - stream_info->bufq_handle[bufq_id] = - vfe_dev->buf_mgr->ops->get_bufq_handle(vfe_dev->buf_mgr, - stream_info->session_id, stream_id); if (stream_info->bufq_handle[bufq_id] == 0) { - pr_err("%s: failed: No valid buffer queue for stream: 0x%x\n", - __func__, stream_id); - rc = -EINVAL; + stream_info->bufq_handle[bufq_id] = + vfe_dev->buf_mgr->ops->get_bufq_handle(vfe_dev->buf_mgr, + stream_info->session_id, stream_id); + if (stream_info->bufq_handle[bufq_id] == 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: failed: No valid buffer queue for stream: 0x%x\n", + __func__, stream_id); + return -EINVAL; + } + } else { + uint32_t bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle( + vfe_dev->buf_mgr, + stream_info->session_id, + stream_id); + if (bufq_handle != stream_info->bufq_handle[bufq_id]) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Stream %x already has buffer q %x cannot add handle %x\n", + __func__, stream_id, + stream_info->bufq_handle[bufq_id], bufq_handle); + return -EINVAL; + } } + spin_unlock_irqrestore(&stream_info->lock, flags); + ISP_DBG("%d: Add bufq handle:0x%x, idx:%d, for stream %d on VFE %d\n", __LINE__, stream_info->bufq_handle[bufq_id], - bufq_id, stream_info->stream_handle, vfe_dev->pdev->id); + bufq_id, stream_info->stream_handle[0], + vfe_dev->pdev->id); return rc; } @@ -3225,16 +3384,100 @@ static void msm_isp_remove_buf_queue(struct vfe_device *vfe_dev, bufq_id = VFE_BUF_QUEUE_SHARED; spin_lock_irqsave(&stream_info->lock, flags); - stream_info->bufq_handle[bufq_id] = 0; + + if (stream_info->bufq_handle[bufq_id]) { + stream_info->bufq_handle[bufq_id] = 0; + if (stream_info->state == ACTIVE) + stream_info->state = UPDATING; + } spin_unlock_irqrestore(&stream_info->lock, flags); + if (stream_info->state == UPDATING) + msm_isp_axi_wait_for_stream_cfg_done(stream_info, 1); } +/** + * msm_isp_stream_axi_cfg_update() - Apply axi config update to a stream + * @vfe_dev: The vfe device on which the update is to be applied + * @stream_info: Stream for which update is to be applied + * @update_info: Parameters of the update + * + * Returns - 0 on success else error code + * + * For dual vfe stream apply the update once update for both vfe is + * received. + */ +static int msm_isp_stream_axi_cfg_update(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_vfe_axi_stream_cfg_update_info *update_info) +{ + int j; + int k; + unsigned long flags; + int vfe_idx; + + if (atomic_read(&vfe_dev->axi_data.axi_cfg_update[ + SRC_TO_INTF(stream_info->stream_src)])) { + pr_err("%s: Update in progress for vfe %d intf %d\n", + __func__, vfe_dev->pdev->id, + SRC_TO_INTF(stream_info->stream_src)); + return -EINVAL; + } + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state != ACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("Invalid stream state for axi update %d\n", + stream_info->state); + return -EINVAL; + } + if (stream_info->update_vfe_mask) { + if (stream_info->update_vfe_mask & (1 << vfe_dev->pdev->id)) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Stream %p/%x Update already in progress for vfe %d\n", + __func__, stream_info, stream_info->stream_src, + vfe_dev->pdev->id); + return -EINVAL; + } + } + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + + for (j = 0; j < stream_info->num_planes; j++) + stream_info->plane_cfg[vfe_idx][j] = update_info->plane_cfg[j]; + + stream_info->update_vfe_mask |= (1 << vfe_dev->pdev->id); + /* wait for update from all vfe's under stream before applying */ + if (stream_info->update_vfe_mask != stream_info->vfe_mask) { + spin_unlock_irqrestore(&stream_info->lock, flags); + return 0; + } + + atomic_set(&vfe_dev->axi_data.axi_cfg_update[ + SRC_TO_INTF(stream_info->stream_src)], 1); + stream_info->output_format = update_info->output_format; + init_completion(&stream_info->active_comp); + if (((vfe_dev->hw_info->runtime_axi_update == 0) || + (vfe_dev->dual_vfe_enable == 1))) { + stream_info->state = PAUSE_PENDING; + msm_isp_axi_stream_enable_cfg(stream_info); + stream_info->state = PAUSING; + } else { + for (j = 0; j < stream_info->num_planes; j++) { + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_reg(vfe_dev, stream_info, j); + } + } + stream_info->state = RESUMING; + } + spin_unlock_irqrestore(&stream_info->lock, flags); + return 0; +} + int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) { - int rc = 0, i, j; + int rc = 0, i; struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; struct msm_isp_sw_framskip *sw_skip_info = NULL; @@ -3254,8 +3497,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) VFE_AXI_SRC_MAX) { return -EINVAL; } - stream_info = &axi_data->stream_info[ - HANDLE_TO_IDX(update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); if (SRC_TO_INTF(stream_info->stream_src) >= VFE_SRC_MAX) continue; if (stream_info->state != ACTIVE && @@ -3272,8 +3515,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) return -EINVAL; } if (update_cmd->update_type == UPDATE_STREAM_AXI_CONFIG && - atomic_read(&axi_data->axi_cfg_update[ - SRC_TO_INTF(stream_info->stream_src)])) { + stream_info->state != ACTIVE) { pr_err("%s: AXI stream config updating\n", __func__); return -EBUSY; } @@ -3285,8 +3527,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); stream_info->buf_divert = 1; } break; @@ -3295,22 +3537,23 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); stream_info->buf_divert = 0; msm_isp_get_timestamp(×tamp); frame_id = vfe_dev->axi_data.src_info[ SRC_TO_INTF(stream_info->stream_src)].frame_id; /* set ping pong address to scratch before flush */ spin_lock_irqsave(&stream_info->lock, flags); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, + msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, + msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); spin_unlock_irqrestore(&stream_info->lock, flags); - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, - stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT], + rc = vfe_dev->buf_mgr->ops->flush_buf( + vfe_dev->buf_mgr, + stream_info->bufq_handle + [VFE_BUF_QUEUE_DEFAULT], MSM_ISP_BUFFER_FLUSH_DIVERTED, ×tamp.buf_time, frame_id); if (rc == -EFAULT) { @@ -3328,8 +3571,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); spin_lock_irqsave(&stream_info->lock, flags); /* no change then break early */ if (stream_info->current_framedrop_period == @@ -3351,7 +3594,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) stream_info->current_framedrop_period = framedrop_period; if (stream_info->stream_type != BURST_STREAM) - msm_isp_cfg_framedrop_reg(vfe_dev, stream_info); + msm_isp_cfg_framedrop_reg(stream_info); spin_unlock_irqrestore(&stream_info->lock, flags); } break; @@ -3361,8 +3604,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); sw_skip_info = &update_info->sw_skip_info; if (sw_skip_info->stream_src_mask != 0) { /* SW image buffer drop */ @@ -3385,48 +3628,12 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; - for (j = 0; j < stream_info->num_planes; j++) { - stream_info->plane_cfg[j] = - update_info->plane_cfg[j]; - } - stream_info->output_format = - update_info->output_format; - if ((stream_info->state == ACTIVE) && - ((vfe_dev->hw_info->runtime_axi_update == 0) || - (vfe_dev->dual_vfe_enable == 1))) { - spin_lock_irqsave(&stream_info->lock, flags); - stream_info->state = PAUSE_PENDING; - msm_isp_axi_stream_enable_cfg( - vfe_dev, stream_info, 1); - stream_info->state = PAUSING; - atomic_set(&axi_data-> - axi_cfg_update[SRC_TO_INTF( - stream_info->stream_src)], - UPDATE_REQUESTED); - spin_unlock_irqrestore(&stream_info->lock, - flags); - } else { - for (j = 0; j < stream_info->num_planes; j++) { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_reg(vfe_dev, stream_info, j); - } - - spin_lock_irqsave(&stream_info->lock, flags); - if (stream_info->state != ACTIVE) { - stream_info->runtime_output_format = - stream_info->output_format; - } else { - stream_info->state = RESUMING; - atomic_set(&axi_data-> - axi_cfg_update[SRC_TO_INTF( - stream_info->stream_src)], - APPLYING_UPDATE_RESUME); - } - spin_unlock_irqrestore(&stream_info->lock, - flags); - } + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); + rc = msm_isp_stream_axi_cfg_update(vfe_dev, stream_info, + update_info); + if (rc) + return rc; } break; } @@ -3435,8 +3642,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); rc = msm_isp_request_frame(vfe_dev, stream_info, update_info->user_stream_id, update_info->frame_id, @@ -3452,8 +3659,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); rc = msm_isp_add_buf_queue(vfe_dev, stream_info, update_info->user_stream_id); if (rc) @@ -3466,29 +3673,20 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - update_info->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(update_info->stream_handle)); msm_isp_remove_buf_queue(vfe_dev, stream_info, update_info->user_stream_id); pr_debug("%s, Remove bufq for Stream 0x%x\n", __func__, stream_info->stream_id); - if (stream_info->state == ACTIVE) { - stream_info->state = UPDATING; - rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, - NO_UPDATE, (1 << SRC_TO_INTF( - stream_info->stream_src)), 2); - if (rc < 0) - pr_err("%s: wait for update failed\n", - __func__); - } } break; } case UPDATE_STREAM_REQUEST_FRAMES_VER2: { struct msm_vfe_axi_stream_cfg_update_info_req_frm *req_frm = &update_cmd->req_frm_ver2; - stream_info = &axi_data->stream_info[HANDLE_TO_IDX( - req_frm->stream_handle)]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + HANDLE_TO_IDX(req_frm->stream_handle)); rc = msm_isp_request_frame(vfe_dev, stream_info, req_frm->user_stream_id, req_frm->frame_id, @@ -3518,7 +3716,7 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, unsigned long flags; struct timeval *time_stamp; uint32_t frame_id, buf_index = -1; - struct msm_vfe_axi_stream *temp_stream; + int vfe_idx; if (!ts) { pr_err("%s: Error! Invalid argument\n", __func__); @@ -3536,10 +3734,13 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id; spin_lock_irqsave(&stream_info->lock, flags); - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info); + pingpong_bit = (~(pingpong_status >> + stream_info->wm[vfe_idx][0]) & 0x1); for (i = 0; i < stream_info->num_planes; i++) { if (pingpong_bit != - (~(pingpong_status >> stream_info->wm[i]) & 0x1)) { + (~(pingpong_status >> + stream_info->wm[vfe_idx][i]) & 0x1)) { spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: Write master ping pong mismatch. Status: 0x%x\n", __func__, pingpong_status); @@ -3548,15 +3749,23 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } } - if (stream_info->state == INACTIVE) { - msm_isp_cfg_stream_scratch(vfe_dev, stream_info, - pingpong_status); + WARN_ON(stream_info->buf[pingpong_bit] != NULL); spin_unlock_irqrestore(&stream_info->lock, flags); - pr_err_ratelimited("%s: Warning! Stream already inactive. Drop irq handling\n", - __func__); return; } + + /* composite the irq for dual vfe */ + rc = msm_isp_composite_irq(vfe_dev, stream_info, + MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc < 0) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + done_buf = stream_info->buf[pingpong_bit]; if (vfe_dev->buf_mgr->frameId_mismatch_recovery == 1) { @@ -3566,46 +3775,28 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } - stream_info->frame_id++; if (done_buf) buf_index = done_buf->buf_idx; - rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt(vfe_dev->buf_mgr, + ISP_DBG("%s: vfe %d: stream 0x%x, frame id %d, pingpong bit %d\n", + __func__, vfe_dev->pdev->id, - done_buf ? done_buf->bufq_handle : - stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT], buf_index, - time_stamp, frame_id, pingpong_bit); + stream_info->stream_id, + frame_id, + pingpong_bit); - if (rc < 0) { - spin_unlock_irqrestore(&stream_info->lock, flags); - /* this usually means a serious scheduling error */ - msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); - return; - } - /* - * Buf divert return value represent whether the buf - * can be diverted. A positive return value means - * other ISP hardware is still processing the frame. - * A negative value is error. Return in both cases. - */ - if (rc != 0) { - spin_unlock_irqrestore(&stream_info->lock, flags); - return; - } + stream_info->frame_id++; + stream_info->buf[pingpong_bit] = NULL; if (stream_info->stream_type == CONTINUOUS_STREAM || stream_info->runtime_num_burst_capture > 1) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 0); + rc = msm_isp_cfg_ping_pong_address( + stream_info, pingpong_status); if (rc < 0) ISP_DBG("%s: Error configuring ping_pong\n", __func__); } else if (done_buf) { - rc = msm_isp_cfg_ping_pong_address(vfe_dev, - stream_info, pingpong_status, 1); - if (rc < 0) - ISP_DBG("%s: Error configuring ping_pong\n", - __func__); + msm_isp_cfg_stream_scratch(stream_info, pingpong_status); } if (!done_buf) { @@ -3619,28 +3810,12 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, return; } - temp_stream = msm_isp_get_controllable_stream(vfe_dev, - stream_info); - if (temp_stream->stream_type == BURST_STREAM && - temp_stream->runtime_num_burst_capture) { + if (stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture) { ISP_DBG("%s: burst_frame_count: %d\n", __func__, - temp_stream->runtime_num_burst_capture); - temp_stream->runtime_num_burst_capture--; - /* - * For non controllable stream decrement the burst count for - * dual stream as well here - */ - if (!stream_info->controllable_output && vfe_dev->is_split && - RDI_INTF_0 > stream_info->stream_src) { - temp_stream = msm_isp_vfe_get_stream( - vfe_dev->common_data->dual_vfe_res, - ((vfe_dev->pdev->id == ISP_VFE0) ? - ISP_VFE1 : ISP_VFE0), - HANDLE_TO_IDX( - stream_info->stream_handle)); - temp_stream->runtime_num_burst_capture--; - } + stream_info->runtime_num_burst_capture); + stream_info->runtime_num_burst_capture--; } rc = msm_isp_update_deliver_count(vfe_dev, stream_info, @@ -3709,7 +3884,8 @@ void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, continue; } stream_idx = HANDLE_TO_IDX(comp_info->stream_handle); - stream_info = &axi_data->stream_info[stream_idx]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_idx); msm_isp_process_axi_irq_stream(vfe_dev, stream_info, pingpong_status, ts); @@ -3728,7 +3904,8 @@ void msm_isp_process_axi_irq(struct vfe_device *vfe_dev, pingpong_status); continue; } - stream_info = &axi_data->stream_info[stream_idx]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, + stream_idx); msm_isp_process_axi_irq_stream(vfe_dev, stream_info, pingpong_status, ts); @@ -3742,6 +3919,7 @@ void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev) struct msm_vfe_axi_stream *stream_info; struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; int i, j; + int vfe_idx; if (!vfe_dev || !axi_data) { pr_err("%s: error %pK %pK\n", __func__, vfe_dev, axi_data); @@ -3749,14 +3927,16 @@ void msm_isp_axi_disable_all_wm(struct vfe_device *vfe_dev) } for (i = 0; i < VFE_AXI_SRC_MAX; i++) { - stream_info = &axi_data->stream_info[i]; + stream_info = msm_isp_get_stream_common_data(vfe_dev, i); if (stream_info->state != ACTIVE) continue; + vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, + stream_info); for (j = 0; j < stream_info->num_planes; j++) vfe_dev->hw_info->vfe_ops.axi_ops.enable_wm( vfe_dev->vfe_base, - stream_info->wm[j], 0); + stream_info->wm[vfe_idx][j], 0); } } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index 08053aa410e7..84720f3d8625 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -14,37 +14,15 @@ #include "msm_isp.h" +#define HANDLE_TO_IDX(handle) (handle & 0xFF) #define SRC_TO_INTF(src) \ ((src < RDI_INTF_0 || src == VFE_AXI_SRC_MAX) ? VFE_PIX_0 : \ (VFE_RAW_0 + src - RDI_INTF_0)) -int msm_isp_axi_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_destroy_stream( - struct msm_vfe_axi_shared_data *axi_data, int stream_idx); - -int msm_isp_validate_axi_request( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); - -void msm_isp_axi_reserve_wm( - struct vfe_device *vfe_dev, - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - -void msm_isp_axi_reserve_comp_mask( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream *stream_info); - int msm_isp_axi_check_stream_state( struct vfe_device *vfe_dev, struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd); -int msm_isp_calculate_framedrop( - struct msm_vfe_axi_shared_data *axi_data, - struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd); void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); @@ -62,10 +40,13 @@ int msm_isp_axi_restart(struct vfe_device *vfe_dev, struct msm_vfe_axi_restart_cmd *restart_cmd); void msm_isp_axi_stream_update(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); + enum msm_vfe_input_src frame_src, + struct msm_isp_timestamp *ts); -void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); +void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_vfe_input_src frame_src, + enum msm_isp_comp_irq_types irq, + struct msm_isp_timestamp *ts); void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts); @@ -94,6 +75,34 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, uint32_t pingpong_status, struct msm_isp_timestamp *ts); +void msm_isp_release_all_axi_stream(struct vfe_device *vfe_dev); + +static inline int msm_isp_get_vfe_idx_for_stream_user( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int vfe_idx; + + for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++) { + if (stream_info->vfe_dev[vfe_idx] == vfe_dev) + return vfe_idx; + } + return -ENOTTY; +} + +static inline int msm_isp_get_vfe_idx_for_stream(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info) +{ + int vfe_idx = msm_isp_get_vfe_idx_for_stream_user(vfe_dev, stream_info); + + if (vfe_idx < 0) { + WARN(1, "%s vfe index misssing for stream %d, vfe %d\n", + __func__, stream_info->stream_src, vfe_dev->pdev->id); + vfe_idx = 0; + } + return vfe_idx; +} + static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev, int wm, uint32_t pingpong_bit) @@ -103,18 +112,48 @@ static inline void msm_isp_cfg_wm_scratch(struct vfe_device *vfe_dev, pingpong_bit, vfe_dev->buf_mgr->scratch_buf_addr, 0); } -static inline void msm_isp_cfg_stream_scratch(struct vfe_device *vfe_dev, +static inline void msm_isp_cfg_stream_scratch( struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status) { int i; + int j; uint32_t pingpong_bit; - - pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1); - for (i = 0; i < stream_info->num_planes; i++) - msm_isp_cfg_wm_scratch(vfe_dev, stream_info->wm[i], + int vfe_idx; + + pingpong_bit = (~(pingpong_status >> stream_info->wm[0][0]) & 0x1); + for (i = 0; i < stream_info->num_planes; i++) { + for (j = 0; j < stream_info->num_isp; j++) { + vfe_idx = msm_isp_get_vfe_idx_for_stream( + stream_info->vfe_dev[j], stream_info); + msm_isp_cfg_wm_scratch(stream_info->vfe_dev[j], + stream_info->wm[vfe_idx][i], ~pingpong_bit); + } + } stream_info->buf[pingpong_bit] = NULL; } +static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data( + struct vfe_device *vfe_dev, int stream_idx) +{ + struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data; + struct msm_vfe_axi_stream *stream_info; + + if (vfe_dev->is_split && stream_idx < RDI_INTF_0) + stream_info = &common_data->streams[stream_idx]; + else + stream_info = &common_data->streams[VFE_AXI_SRC_MAX * + vfe_dev->pdev->id + stream_idx]; + return stream_info; +} + +static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream( + struct dual_vfe_resource *dual_vfe_res, + int vfe_id, uint32_t index) +{ + return msm_isp_get_stream_common_data(dual_vfe_res->vfe_dev[vfe_id], + index); +} + #endif /* __MSM_ISP_AXI_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index 7c914694e49c..f851e8c9289e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -22,50 +22,76 @@ static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev, uint32_t pingpong_status) { vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( - vfe_dev->vfe_base, stream_info, + vfe_dev, stream_info, pingpong_status, vfe_dev->buf_mgr->scratch_buf_addr); } -static inline void msm_isp_stats_cfg_stream_scratch(struct vfe_device *vfe_dev, +static inline void msm_isp_stats_cfg_stream_scratch( struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status) { - uint32_t stats_idx = STATS_IDX(stream_info->stream_handle); + uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]); uint32_t pingpong_bit; - uint32_t stats_pingpong_offset = - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ - stats_idx]; + uint32_t stats_pingpong_offset; + struct vfe_device *vfe_dev; + int i; + stats_pingpong_offset = stream_info->vfe_dev[0]->hw_info-> + stats_hw_info->stats_ping_pong_offset[stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); - msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info, - pingpong_status); + for (i = 0; i < stream_info->num_isp; i++) { + vfe_dev = stream_info->vfe_dev[i]; + msm_isp_stats_cfg_wm_scratch(vfe_dev, stream_info, + pingpong_status); + } + stream_info->buf[pingpong_bit] = NULL; } -static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, +static int msm_isp_composite_stats_irq(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info, + enum msm_isp_comp_irq_types irq) +{ + /* interrupt recv on same vfe w/o recv on other vfe */ + if (stream_info->composite_irq[irq] & (1 << vfe_dev->pdev->id)) { + pr_err("%s: irq %d out of sync for dual vfe on vfe %d\n", + __func__, irq, vfe_dev->pdev->id); + return -EFAULT; + } + + stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id); + if (stream_info->composite_irq[irq] != stream_info->vfe_mask) + return 1; + + stream_info->composite_irq[irq] = 0; + + return 0; +} + +static int msm_isp_stats_cfg_ping_pong_address( struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status) { - int rc = -1, vfe_id = 0; - struct msm_isp_buffer *buf; - uint32_t pingpong_bit = 0; - uint32_t stats_pingpong_offset; + int rc = -1; + struct msm_isp_buffer *buf = NULL; uint32_t bufq_handle = stream_info->bufq_handle; - uint32_t stats_idx = STATS_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; - struct msm_vfe_stats_stream *dual_vfe_stream_info = NULL; + uint32_t stats_idx = STATS_IDX(stream_info->stream_handle[0]); + struct vfe_device *vfe_dev = stream_info->vfe_dev[0]; + uint32_t stats_pingpong_offset; + uint32_t pingpong_bit; + int k; if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type || stats_idx >= MSM_ISP_STATS_MAX) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - - stats_pingpong_offset = - vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ - stats_idx]; - + stats_pingpong_offset = vfe_dev->hw_info->stats_hw_info-> + stats_ping_pong_offset[stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); + /* if buffer already exists then no need to replace */ + if (stream_info->buf[pingpong_bit]) + return 0; rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr, vfe_dev->pdev->id, bufq_handle, @@ -74,8 +100,11 @@ static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, msm_isp_halt_send_error(vfe_dev, ISP_EVENT_BUF_FATAL_ERROR); return rc; } - if (rc < 0 || NULL == buf) - vfe_dev->error_info.stats_framedrop_count[stats_idx]++; + if (rc < 0 || NULL == buf) { + for (k = 0; k < stream_info->num_isp; k++) + stream_info->vfe_dev[k]->error_info. + stats_framedrop_count[stats_idx]++; + } if (buf && buf->num_planes != 1) { pr_err("%s: Invalid buffer\n", __func__); @@ -83,58 +112,22 @@ static int msm_isp_stats_cfg_ping_pong_address(struct vfe_device *vfe_dev, rc = -EINVAL; goto buf_error; } - if (vfe_dev->is_split) { - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; - if (!dual_vfe_res->vfe_base[ISP_VFE0] || - !dual_vfe_res->stats_data[ISP_VFE0] || - !dual_vfe_res->vfe_base[ISP_VFE1] || - !dual_vfe_res->stats_data[ISP_VFE1]) { - pr_err("%s:%d error vfe0 %pK %pK vfe1 %pK %pK\n", - __func__, __LINE__, - dual_vfe_res->vfe_base[ISP_VFE0], - dual_vfe_res->stats_data[ISP_VFE0], - dual_vfe_res->vfe_base[ISP_VFE1], - dual_vfe_res->stats_data[ISP_VFE1]); - } else { - for (vfe_id = 0; vfe_id < MAX_VFE; vfe_id++) { - dual_vfe_stream_info = &dual_vfe_res-> - stats_data[vfe_id]-> - stream_info[stats_idx]; - if (buf) - vfe_dev->hw_info->vfe_ops.stats_ops. - update_ping_pong_addr( - dual_vfe_res->vfe_base[vfe_id], - dual_vfe_stream_info, - pingpong_status, - buf->mapped_info[0].paddr + - dual_vfe_stream_info-> - buffer_offset); - else - msm_isp_stats_cfg_stream_scratch( - vfe_dev, - dual_vfe_stream_info, - pingpong_status); - dual_vfe_stream_info->buf[pingpong_bit] - = buf; - } - } - } else { - if (buf) - vfe_dev->hw_info->vfe_ops.stats_ops. - update_ping_pong_addr( - vfe_dev->vfe_base, stream_info, - pingpong_status, buf->mapped_info[0].paddr + - stream_info->buffer_offset); - else - msm_isp_stats_cfg_stream_scratch(vfe_dev, - stream_info, pingpong_status); - - stream_info->buf[pingpong_bit] = buf; + if (!buf) { + msm_isp_stats_cfg_stream_scratch(stream_info, + pingpong_status); + return 0; } + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr( + vfe_dev, stream_info, pingpong_status, + buf->mapped_info[0].paddr + + stream_info->buffer_offset[k]); + } + stream_info->buf[pingpong_bit] = buf; + buf->pingpong_bit = pingpong_bit; - if (buf) - buf->pingpong_bit = pingpong_bit; return 0; buf_error: vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr, @@ -156,6 +149,8 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, struct msm_isp_buffer *done_buf; uint32_t stats_pingpong_offset; uint32_t stats_idx; + int vfe_idx; + unsigned long flags; if (!vfe_dev || !ts || !buf_event || !stream_info) { pr_err("%s:%d failed: invalid params %pK %pK %pK %pK\n", @@ -164,6 +159,9 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, return -EINVAL; } frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id; + + spin_lock_irqsave(&stream_info->lock, flags); + sw_skip = &stream_info->sw_skip; stats_event = &buf_event->u.stats; @@ -183,73 +181,62 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev, (struct msm_isp_sw_framskip)); } } - stats_idx = STATS_IDX(stream_info->stream_handle); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, stream_info); + stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]); stats_pingpong_offset = vfe_dev->hw_info->stats_hw_info->stats_ping_pong_offset[ stats_idx]; pingpong_bit = (~(pingpong_status >> stats_pingpong_offset) & 0x1); - done_buf = stream_info->buf[pingpong_bit]; - - if (done_buf) - buf_index = done_buf->buf_idx; - - rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt( - vfe_dev->buf_mgr, vfe_dev->pdev->id, stream_info->bufq_handle, - buf_index, &ts->buf_time, - frame_id, pingpong_bit); - - if (rc < 0) { - if (rc == -EFAULT) + rc = msm_isp_composite_stats_irq(vfe_dev, stream_info, + MSM_ISP_COMP_IRQ_PING_BUFDONE + pingpong_bit); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc < 0) msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - pr_err("stats_buf_divert: update put buf cnt fail\n"); - return rc; - } - - if (rc > 0) { - ISP_DBG("%s: vfe_id %d buf_id %d bufq %x put_cnt 1\n", __func__, - vfe_dev->pdev->id, buf_index, - stream_info->bufq_handle); + ISP_EVENT_BUF_FATAL_ERROR); return rc; } + done_buf = stream_info->buf[pingpong_bit]; /* Program next buffer */ - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, stream_info, + stream_info->buf[pingpong_bit] = NULL; + rc = msm_isp_stats_cfg_ping_pong_address(stream_info, pingpong_status); - if (rc) + spin_unlock_irqrestore(&stream_info->lock, flags); + + if (!done_buf) return rc; - if (drop_buffer && done_buf) { - rc = vfe_dev->buf_mgr->ops->buf_done( + buf_index = done_buf->buf_idx; + if (drop_buffer) { + vfe_dev->buf_mgr->ops->put_buf( vfe_dev->buf_mgr, done_buf->bufq_handle, - done_buf->buf_idx, &ts->buf_time, frame_id, 0); - if (rc == -EFAULT) - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + done_buf->buf_idx); + } else { + /* divert native buffers */ + vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr, + done_buf->bufq_handle, done_buf->buf_idx, + &ts->buf_time, frame_id); } - - if (done_buf) { - stats_event->stats_buf_idxs - [stream_info->stats_type] = - done_buf->buf_idx; - if (NULL == comp_stats_type_mask) { - stats_event->stats_mask = - 1 << stream_info->stats_type; - ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n", - __func__, buf_event->frame_id, - stream_info->stats_type, done_buf->bufq_handle); - msm_isp_send_event(vfe_dev, - ISP_EVENT_STATS_NOTIFY + - stream_info->stats_type, - buf_event); - } else { - *comp_stats_type_mask |= - 1 << stream_info->stats_type; - } + stats_event->stats_buf_idxs + [stream_info->stats_type] = + done_buf->buf_idx; + if (comp_stats_type_mask == NULL) { + stats_event->stats_mask = + 1 << stream_info->stats_type; + ISP_DBG("%s: stats frameid: 0x%x %d bufq %x\n", + __func__, buf_event->frame_id, + stream_info->stats_type, done_buf->bufq_handle); + msm_isp_send_event(vfe_dev, + ISP_EVENT_STATS_NOTIFY + + stream_info->stats_type, + buf_event); + } else { + *comp_stats_type_mask |= + 1 << stream_info->stats_type; } return rc; @@ -276,8 +263,9 @@ static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev, for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { if (!(stats_irq_mask & (1 << i))) continue; - stream_info = &vfe_dev->stats_data.stream_info[i]; - if (stream_info->state == STATS_INACTIVE) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_INACTIVE || + stream_info->state == STATS_STOPPING) { pr_debug("%s: Warning! Stream already inactive. Drop irq handling\n", __func__); continue; @@ -354,12 +342,17 @@ void msm_isp_process_stats_irq(struct vfe_device *vfe_dev, } int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, - struct msm_vfe_stats_stream_request_cmd *stream_req_cmd) + struct msm_vfe_stats_stream_request_cmd *stream_req_cmd, + struct msm_vfe_stats_stream *stream_info) { - int rc = -1; - struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + int rc = 0; uint32_t stats_idx; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + int i; + + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); if (!(vfe_dev->hw_info->stats_hw_info->stats_capability_mask & (1 << stream_req_cmd->stats_type))) { @@ -367,16 +360,7 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, return rc; } - stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. - get_stats_idx(stream_req_cmd->stats_type); - - if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, stats_idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state != STATS_AVALIABLE) { + if (stream_info->state != STATS_AVAILABLE) { pr_err("%s: Stats already requested\n", __func__); return rc; } @@ -390,17 +374,74 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, pr_err("%s: Invalid irq subsample pattern\n", __func__); return rc; } + if (stream_req_cmd->composite_flag > + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask) { + pr_err("%s: comp grp %d exceed max %d\n", + __func__, stream_req_cmd->composite_flag, + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask); + return -EINVAL; + } - stream_info->session_id = stream_req_cmd->session_id; - stream_info->stream_id = stream_req_cmd->stream_id; - stream_info->composite_flag = stream_req_cmd->composite_flag; - stream_info->stats_type = stream_req_cmd->stats_type; - stream_info->buffer_offset = stream_req_cmd->buffer_offset; - stream_info->framedrop_pattern = stream_req_cmd->framedrop_pattern; - stream_info->init_stats_frame_drop = stream_req_cmd->init_frame_drop; - stream_info->irq_subsample_pattern = - stream_req_cmd->irq_subsample_pattern; - stream_info->state = STATS_INACTIVE; + if (stream_info->num_isp == 0) { + stream_info->session_id = stream_req_cmd->session_id; + stream_info->stream_id = stream_req_cmd->stream_id; + stream_info->composite_flag = stream_req_cmd->composite_flag; + stream_info->stats_type = stream_req_cmd->stats_type; + framedrop_pattern = stream_req_cmd->framedrop_pattern; + if (framedrop_pattern == SKIP_ALL) + framedrop_pattern = 0; + else + framedrop_pattern = 1; + stream_info->framedrop_pattern = framedrop_pattern; + stream_info->init_stats_frame_drop = + stream_req_cmd->init_frame_drop; + stream_info->irq_subsample_pattern = + stream_req_cmd->irq_subsample_pattern; + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + stream_info->framedrop_period = framedrop_period; + } else { + if (stream_info->vfe_mask & (1 << vfe_dev->pdev->id)) { + pr_err("%s: stats %d already requested for vfe %d\n", + __func__, stats_idx, vfe_dev->pdev->id); + return -EINVAL; + } + if (stream_info->session_id != stream_req_cmd->session_id) + rc = -EINVAL; + if (stream_info->session_id != stream_req_cmd->session_id) + rc = -EINVAL; + if (stream_info->composite_flag != + stream_req_cmd->composite_flag) + rc = -EINVAL; + if (stream_info->stats_type != stream_req_cmd->stats_type) + rc = -EINVAL; + framedrop_pattern = stream_req_cmd->framedrop_pattern; + if (framedrop_pattern == SKIP_ALL) + framedrop_pattern = 0; + else + framedrop_pattern = 1; + if (stream_info->framedrop_pattern != framedrop_pattern) + rc = -EINVAL; + framedrop_period = msm_isp_get_framedrop_period( + stream_req_cmd->framedrop_pattern); + if (stream_info->framedrop_period != framedrop_period) + rc = -EINVAL; + if (rc) { + pr_err("%s: Stats stream param mismatch between vfe\n", + __func__); + return rc; + } + } + stream_info->buffer_offset[stream_info->num_isp] = + stream_req_cmd->buffer_offset; + stream_info->vfe_dev[stream_info->num_isp] = vfe_dev; + stream_info->vfe_mask |= (1 << vfe_dev->pdev->id); + stream_info->num_isp++; + if (!vfe_dev->is_split || stream_info->num_isp == MAX_VFE) { + stream_info->state = STATS_INACTIVE; + for (i = 0; i < MSM_ISP_COMP_IRQ_MAX; i++) + stream_info->composite_irq[i] = 0; + } if ((vfe_dev->stats_data.stream_handle_cnt << 8) == 0) vfe_dev->stats_data.stream_handle_cnt++; @@ -408,7 +449,8 @@ int msm_isp_stats_create_stream(struct vfe_device *vfe_dev, stream_req_cmd->stream_handle = (++vfe_dev->stats_data.stream_handle_cnt) << 8 | stats_idx; - stream_info->stream_handle = stream_req_cmd->stream_handle; + stream_info->stream_handle[stream_info->num_isp - 1] = + stream_req_cmd->stream_handle; return 0; } @@ -417,42 +459,39 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) int rc = -1; struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - uint32_t framedrop_period; uint32_t stats_idx; + unsigned long flags; - rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd); - if (rc < 0) { - pr_err("%s: create stream failed\n", __func__); - return rc; - } - - stats_idx = STATS_IDX(stream_req_cmd->stream_handle); + stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops. + get_stats_idx(stream_req_cmd->stats_type); if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - stream_info = &stats_data->stream_info[stats_idx]; + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx); - framedrop_period = msm_isp_get_framedrop_period( - stream_req_cmd->framedrop_pattern); + spin_lock_irqsave(&stream_info->lock, flags); - if (stream_req_cmd->framedrop_pattern == SKIP_ALL) - stream_info->framedrop_pattern = 0x0; - else - stream_info->framedrop_pattern = 0x1; - stream_info->framedrop_period = framedrop_period - 1; + rc = msm_isp_stats_create_stream(vfe_dev, stream_req_cmd, stream_info); + if (rc < 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: create stream failed\n", __func__); + return rc; + } if (stream_info->init_stats_frame_drop == 0) vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, + if (stream_info->state == STATS_INACTIVE) { + msm_isp_stats_cfg_stream_scratch(stream_info, VFE_PING_FLAG); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, + msm_isp_stats_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); + } + spin_unlock_irqrestore(&stream_info->lock, flags); return rc; } @@ -461,32 +500,112 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) int rc = -1; struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; int stats_idx = STATS_IDX(stream_release_cmd->stream_handle); struct msm_vfe_stats_stream *stream_info = NULL; + int vfe_idx; + int i; + int k; + unsigned long flags; if (stats_idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { pr_err("%s Invalid stats index %d", __func__, stats_idx); return -EINVAL; } - stream_info = &stats_data->stream_info[stats_idx]; - if (stream_info->state == STATS_AVALIABLE) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, stats_idx); + spin_lock_irqsave(&stream_info->lock, flags); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user( + vfe_dev, stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != + stream_release_cmd->stream_handle) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: Invalid stream handle %x, expected %x\n", + __func__, stream_release_cmd->stream_handle, + vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0); + return -EINVAL; + } + if (stream_info->state == STATS_AVAILABLE) { + spin_unlock_irqrestore(&stream_info->lock, flags); pr_err("%s: stream already release\n", __func__); return rc; - } else if (stream_info->state != STATS_INACTIVE) { + } + vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); + + if (stream_info->state != STATS_INACTIVE) { stream_cfg_cmd.enable = 0; stream_cfg_cmd.num_streams = 1; stream_cfg_cmd.stream_handle[0] = stream_release_cmd->stream_handle; - rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + spin_lock_irqsave(&stream_info->lock, flags); } - vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); - memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); + for (i = vfe_idx, k = vfe_idx + 1; k < stream_info->num_isp; k++, i++) { + stream_info->vfe_dev[i] = stream_info->vfe_dev[k]; + stream_info->stream_handle[i] = stream_info->stream_handle[k]; + stream_info->buffer_offset[i] = stream_info->buffer_offset[k]; + } + + stream_info->vfe_dev[stream_info->num_isp] = 0; + stream_info->stream_handle[stream_info->num_isp] = 0; + stream_info->buffer_offset[stream_info->num_isp] = 0; + stream_info->num_isp--; + stream_info->vfe_mask &= ~(1 << vfe_dev->pdev->id); + if (stream_info->num_isp == 0) + stream_info->state = STATS_AVAILABLE; + + spin_unlock_irqrestore(&stream_info->lock, flags); return 0; } +void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev) +{ + struct msm_vfe_stats_stream_release_cmd + stream_release_cmd[MSM_ISP_STATS_MAX]; + struct msm_vfe_stats_stream_cfg_cmd stream_cfg_cmd; + struct msm_vfe_stats_stream *stream_info; + int i; + int vfe_idx; + int num_stream = 0; + unsigned long flags; + + stream_cfg_cmd.enable = 0; + stream_cfg_cmd.num_streams = 0; + + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + spin_lock_irqsave(&stream_info->lock, flags); + if (stream_info->state == STATS_AVAILABLE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_release_cmd[num_stream++].stream_handle = + stream_info->stream_handle[vfe_idx]; + if (stream_info->state == STATS_INACTIVE) { + spin_unlock_irqrestore(&stream_info->lock, flags); + continue; + } + stream_cfg_cmd.stream_handle[ + stream_cfg_cmd.num_streams] = + stream_info->stream_handle[vfe_idx]; + stream_cfg_cmd.num_streams++; + spin_unlock_irqrestore(&stream_info->lock, flags); + } + if (stream_cfg_cmd.num_streams) + msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); + + for (i = 0; i < num_stream; i++) + msm_isp_release_stats_stream(vfe_dev, &stream_release_cmd[i]); +} + static int msm_isp_init_stats_ping_pong_reg( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) @@ -498,108 +617,205 @@ static int msm_isp_init_stats_ping_pong_reg( stream_info->stream_id); if (stream_info->bufq_handle == 0) { pr_err("%s: no buf configured for stream: 0x%x\n", - __func__, stream_info->stream_handle); + __func__, stream_info->stream_handle[0]); return -EINVAL; } - if ((vfe_dev->is_split && vfe_dev->pdev->id == 1) || - !vfe_dev->is_split) { - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PING_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for ping\n", __func__); - return rc; - } - rc = msm_isp_stats_cfg_ping_pong_address(vfe_dev, - stream_info, VFE_PONG_FLAG); - if (rc < 0) { - pr_err("%s: No free buffer for pong\n", __func__); - return rc; - } + rc = msm_isp_stats_cfg_ping_pong_address( + stream_info, VFE_PING_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for ping\n", __func__); + return rc; + } + rc = msm_isp_stats_cfg_ping_pong_address( + stream_info, VFE_PONG_FLAG); + if (rc < 0) { + pr_err("%s: No free buffer for pong\n", __func__); + return rc; } return rc; } -void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev) +void __msm_isp_update_stats_framedrop_reg( + struct msm_vfe_stats_stream *stream_info) { - int i; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - struct msm_vfe_stats_stream *stream_info = NULL; + int k; + struct vfe_device *vfe_dev; - for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state != STATS_ACTIVE) - continue; + if (!stream_info->init_stats_frame_drop) + return; + stream_info->init_stats_frame_drop--; + if (stream_info->init_stats_frame_drop) + return; - if (stream_info->init_stats_frame_drop) { - stream_info->init_stats_frame_drop--; - if (stream_info->init_stats_frame_drop == 0) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( - vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, + stream_info); + + } +} + +static void __msm_isp_stats_stream_update( + struct msm_vfe_stats_stream *stream_info) +{ + uint32_t enable = 0; + uint8_t comp_flag = 0; + int k; + struct vfe_device *vfe_dev; + int index = STATS_IDX(stream_info->stream_handle[0]); + + switch (stream_info->state) { + case STATS_INACTIVE: + case STATS_ACTIVE: + case STATS_AVAILABLE: + break; + case STATS_START_PENDING: + enable = 1; + case STATS_STOP_PENDING: + stream_info->state = + (stream_info->state == STATS_START_PENDING ? + STATS_STARTING : STATS_STOPPING); + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( + vfe_dev, BIT(index), enable); + comp_flag = stream_info->composite_flag; + if (comp_flag) { + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_comp_mask(vfe_dev, BIT(index), + (comp_flag - 1), enable); + } else { + if (enable) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, + stream_info); + else + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, + stream_info); } } + break; + case STATS_STARTING: + stream_info->state = STATS_ACTIVE; + complete_all(&stream_info->active_comp); + break; + case STATS_STOPPING: + stream_info->state = STATS_INACTIVE; + complete_all(&stream_info->inactive_comp); + break; } } + void msm_isp_stats_stream_update(struct vfe_device *vfe_dev) { int i; - uint32_t enable = 0; - uint8_t comp_flag = 0; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - struct msm_vfe_stats_ops *stats_ops = - &vfe_dev->hw_info->vfe_ops.stats_ops; + struct msm_vfe_stats_stream *stream_info; + unsigned long flags; for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { - if (stats_data->stream_info[i].state == STATS_START_PENDING || - stats_data->stream_info[i].state == - STATS_STOP_PENDING) { - enable = stats_data->stream_info[i].state == - STATS_START_PENDING ? 1 : 0; - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_START_PENDING ? - STATS_STARTING : STATS_STOPPING; - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, BIT(i), enable); - comp_flag = stats_data->stream_info[i].composite_flag; - if (comp_flag) - stats_ops->cfg_comp_mask(vfe_dev, BIT(i), - (comp_flag - 1), enable); - } else if (stats_data->stream_info[i].state == STATS_STARTING || - stats_data->stream_info[i].state == STATS_STOPPING) { - stats_data->stream_info[i].state = - stats_data->stream_info[i].state == - STATS_STARTING ? STATS_ACTIVE : STATS_INACTIVE; - } + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + __msm_isp_stats_stream_update(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } - atomic_sub(1, &stats_data->stats_update); - if (!atomic_read(&stats_data->stats_update)) - complete(&vfe_dev->stats_config_complete); } -static int msm_isp_stats_wait_for_cfg_done(struct vfe_device *vfe_dev) +void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_isp_comp_irq_types irq) { + int i; + struct msm_vfe_stats_stream *stream_info; + unsigned long flags; int rc; - init_completion(&vfe_dev->stats_config_complete); - atomic_set(&vfe_dev->stats_data.stats_update, 2); - rc = wait_for_completion_timeout( - &vfe_dev->stats_config_complete, + + for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) { + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + + spin_lock_irqsave(&stream_info->lock, flags); + + rc = msm_isp_composite_stats_irq(vfe_dev, stream_info, irq); + + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + if (-EFAULT == rc) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return; + } + continue; + } + + if (irq == MSM_ISP_COMP_IRQ_REG_UPD) + __msm_isp_stats_stream_update(stream_info); + else if (irq == MSM_ISP_COMP_IRQ_EPOCH && + stream_info->state == STATS_ACTIVE) + __msm_isp_update_stats_framedrop_reg(stream_info); + + spin_unlock_irqrestore(&stream_info->lock, flags); + } +} + +static int msm_isp_stats_wait_for_stream_cfg_done( + struct msm_vfe_stats_stream *stream_info, + int active) +{ + int rc = -1; + + if (active && stream_info->state == STATS_ACTIVE) + rc = 0; + if (!active && stream_info->state == STATS_INACTIVE) + rc = 0; + if (rc == 0) + return rc; + + rc = wait_for_completion_timeout(active ? &stream_info->active_comp : + &stream_info->inactive_comp, msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - if (rc == 0) { - pr_err("%s: wait timeout\n", __func__); - rc = -1; + if (rc <= 0) { + rc = rc ? rc : -ETIMEDOUT; + pr_err("%s: wait for stats stream %x idx %d state %d active %d config failed %d\n", + __func__, stream_info->stream_id, + STATS_IDX(stream_info->stream_handle[0]), + stream_info->state, active, rc); } else { rc = 0; } return rc; } +static int msm_isp_stats_wait_for_streams( + struct msm_vfe_stats_stream **streams, + int num_stream, int active) +{ + int rc = 0; + int i; + struct msm_vfe_stats_stream *stream_info; + + for (i = 0; i < num_stream; i++) { + stream_info = streams[i]; + rc |= msm_isp_stats_wait_for_stream_cfg_done(stream_info, + active); + } + return rc; +} + static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { int i; uint32_t stats_mask = 0, idx; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + struct msm_vfe_stats_stream *stream_info; + int k; for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -608,12 +824,33 @@ static int msm_isp_stats_update_cgc_override(struct vfe_device *vfe_dev, pr_err("%s Invalid stats index %d", __func__, idx); return -EINVAL; } - stats_mask |= 1 << idx; + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, + idx); + if (stream_info->state == STATS_AVAILABLE) + continue; + + /* + * we update cgc after making streams inactive or before + * starting streams, so stream should be in inactive state + */ + if (stream_info->state == STATS_INACTIVE) + stats_mask |= 1 << idx; + for (k = 0; k < stream_info->num_isp; k++) { + if (update_vfes[stream_info->vfe_dev[k]->pdev->id]) + continue; + update_vfes[stream_info->vfe_dev[k]->pdev->id] = + stream_info->vfe_dev[k]; + } } - if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) { - vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override( - vfe_dev, stats_mask, stream_cfg_cmd->enable); + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k]) + continue; + vfe_dev = update_vfes[k]; + if (vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override) { + vfe_dev->hw_info->vfe_ops.stats_ops.update_cgc_override( + vfe_dev, stats_mask, stream_cfg_cmd->enable); + } } return 0; } @@ -622,61 +859,108 @@ int msm_isp_stats_reset(struct vfe_device *vfe_dev) { int i = 0, rc = 0; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; struct msm_isp_timestamp timestamp; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + unsigned long flags; + int k; msm_isp_get_timestamp(×tamp); - for (i = 0; i < MSM_ISP_STATS_MAX; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state != STATS_ACTIVE) + if (vfe_dev->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev->common_data->dual_vfe_res-> + vfe_dev[i]; + } else { + update_vfes[vfe_dev->pdev->id] = vfe_dev; + } + + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) continue; - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, stream_info->bufq_handle, - MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + msm_isp_stats_cfg_stream_scratch(stream_info, + VFE_PING_FLAG); + msm_isp_stats_cfg_stream_scratch(stream_info, + VFE_PONG_FLAG); + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + if (rc == -EFAULT) { + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + return rc; + } } } return rc; } -int msm_isp_stats_restart(struct vfe_device *vfe_dev) +int msm_isp_stats_restart(struct vfe_device *vfe_dev_ioctl) { int i = 0; struct msm_vfe_stats_stream *stream_info = NULL; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + unsigned long flags; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + struct vfe_device *vfe_dev; + int k; + int j; + + if (vfe_dev_ioctl->is_split) { + for (i = 0; i < MAX_VFE; i++) + update_vfes[i] = vfe_dev_ioctl->common_data-> + dual_vfe_res->vfe_dev[i]; + } else { + update_vfes[vfe_dev_ioctl->pdev->id] = vfe_dev_ioctl; + } - for (i = 0; i < MSM_ISP_STATS_MAX; i++) { - stream_info = &stats_data->stream_info[i]; - if (stream_info->state < STATS_ACTIVE) + for (k = 0; k < MAX_VFE; k++) { + vfe_dev = update_vfes[k]; + if (!vfe_dev) + continue; + for (i = 0; i < MSM_ISP_STATS_MAX; i++) { + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, i); + if (stream_info->state == STATS_AVAILABLE || + stream_info->state == STATS_INACTIVE) + continue; + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) continue; - msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + spin_lock_irqsave(&stream_info->lock, flags); + for (j = 0; j < MSM_ISP_COMP_IRQ_MAX; j++) + stream_info->composite_irq[j] = 0; + msm_isp_init_stats_ping_pong_reg(vfe_dev_ioctl, + stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); + } } return 0; } -static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, +static int msm_isp_check_stream_cfg_cmd(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { - int i, rc = 0; - uint32_t stats_mask = 0, idx; - uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; - uint32_t num_stats_comp_mask = 0; + int i; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; - num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( - stats_data->stream_info); - if (rc < 0) - return rc; + uint32_t idx; + int vfe_idx; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); @@ -684,63 +968,99 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, pr_err("%s Invalid stats index %d", __func__, idx); return -EINVAL; } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); - continue; + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, idx); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != + stream_cfg_cmd->stream_handle[i]) { + pr_err("%s: Invalid stream handle: 0x%x received expected %x\n", + __func__, stream_cfg_cmd->stream_handle[i], + vfe_idx == -ENOTTY ? 0 : + stream_info->stream_handle[vfe_idx]); + return -EINVAL; } + } + return 0; +} - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; +static void __msm_isp_stop_stats_streams( + struct msm_vfe_stats_stream **streams, + int num_streams, + struct msm_isp_timestamp timestamp) +{ + int i; + int k; + struct msm_vfe_stats_stream *stream_info; + struct vfe_device *vfe_dev; + struct msm_vfe_stats_shared_data *stats_data; + unsigned long flags; + + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + spin_lock_irqsave(&stream_info->lock, flags); + init_completion(&stream_info->inactive_comp); + stream_info->state = STATS_STOP_PENDING; + if (stream_info->vfe_dev[0]-> + axi_data.src_info[VFE_PIX_0].active == 0) { + while (stream_info->state != STATS_INACTIVE) + __msm_isp_stats_stream_update(stream_info); } - rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); - if (rc < 0) { - pr_err("%s: No buffer for stream%d\n", __func__, idx); - return rc; + for (k = 0; k < stream_info->num_isp; k++) { + stats_data = &stream_info->vfe_dev[k]->stats_data; + stats_data->num_active_stream--; } - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_START_PENDING; - else - stream_info->state = STATS_ACTIVE; - - stats_data->num_active_stream++; - stats_mask |= 1 << idx; - - if (stream_info->composite_flag > 0) - comp_stats_mask[stream_info->composite_flag-1] |= - 1 << idx; - - ISP_DBG("%s: stats_mask %x %x active streams %d\n", - __func__, comp_stats_mask[0], - comp_stats_mask[1], - stats_data->num_active_stream); + msm_isp_stats_cfg_stream_scratch( + stream_info, VFE_PING_FLAG); + msm_isp_stats_cfg_stream_scratch( + stream_info, VFE_PONG_FLAG); + vfe_dev = stream_info->vfe_dev[0]; + if (vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, + stream_info->bufq_handle, + MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == + -EFAULT)) + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_BUF_FATAL_ERROR); + spin_unlock_irqrestore(&stream_info->lock, flags); } - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], i, 1); + if (msm_isp_stats_wait_for_streams(streams, num_streams, 0)) { + for (i = 0; i < num_streams; i++) { + stream_info = streams[i]; + if (stream_info->state == STATS_INACTIVE) + continue; + spin_lock_irqsave(&stream_info->lock, flags); + while (stream_info->state != STATS_INACTIVE) + __msm_isp_stats_stream_update(stream_info); + spin_unlock_irqrestore(&stream_info->lock, flags); } } - return rc; } -static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, +static int msm_isp_check_stats_stream_state( + struct msm_vfe_stats_stream *stream_info, + int cmd) +{ + switch (stream_info->state) { + case STATS_AVAILABLE: + return -EINVAL; + case STATS_INACTIVE: + if (cmd == 0) + return -EALREADY; + break; + case STATS_ACTIVE: + if (cmd) + return -EALREADY; + break; + default: + WARN(1, "Invalid stats state %d\n", stream_info->state); + } + return 0; +} + +static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl, struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) { int i, rc = 0; @@ -748,95 +1068,125 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; uint32_t num_stats_comp_mask = 0; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; + struct msm_vfe_stats_shared_data *stats_data; + int num_stream = 0; + struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; struct msm_isp_timestamp timestamp; + unsigned long flags; + int k; + struct vfe_device *update_vfes[MAX_VFE] = {NULL, NULL}; + uint32_t num_active_streams[MAX_VFE] = {0, 0}; + struct vfe_device *vfe_dev; msm_isp_get_timestamp(×tamp); num_stats_comp_mask = - vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; - + vfe_dev_ioctl->hw_info->stats_hw_info->num_stats_comp_mask; for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } - - stream_info = &stats_data->stream_info[idx]; - if (stream_info->stream_handle != - stream_cfg_cmd->stream_handle[i]) { - pr_err("%s: Invalid stream handle: 0x%x received\n", - __func__, stream_cfg_cmd->stream_handle[i]); + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev_ioctl, idx); + spin_lock_irqsave(&stream_info->lock, flags); + rc = msm_isp_check_stats_stream_state(stream_info, 1); + if (rc == -EALREADY) { + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = 0; continue; } - - if (stream_info->composite_flag > num_stats_comp_mask) { - pr_err("%s: comp grp %d exceed max %d\n", - __func__, stream_info->composite_flag, - num_stats_comp_mask); - return -EINVAL; + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + goto error; } + rc = msm_isp_init_stats_ping_pong_reg(vfe_dev_ioctl, + stream_info); + if (rc < 0) { + spin_unlock_irqrestore(&stream_info->lock, flags); + pr_err("%s: No buffer for stream%d\n", __func__, idx); + return rc; + } + init_completion(&stream_info->active_comp); + stream_info->state = STATS_START_PENDING; + if (vfe_dev_ioctl->axi_data.src_info[VFE_PIX_0].active == 0) { + while (stream_info->state != STATS_ACTIVE) + __msm_isp_stats_stream_update(stream_info); + } + spin_unlock_irqrestore(&stream_info->lock, flags); - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) - stream_info->state = STATS_STOP_PENDING; - else - stream_info->state = STATS_INACTIVE; - - stats_data->num_active_stream--; stats_mask |= 1 << idx; + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + if (update_vfes[vfe_dev->pdev->id]) + continue; + update_vfes[vfe_dev->pdev->id] = vfe_dev; + stats_data = &vfe_dev->stats_data; + num_active_streams[vfe_dev->pdev->id] = + stats_data->num_active_stream; + stats_data->num_active_stream++; + } - if (stream_info->composite_flag > 0) + if (stream_info->composite_flag) comp_stats_mask[stream_info->composite_flag-1] |= 1 << idx; - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PING_FLAG); - msm_isp_stats_cfg_stream_scratch(vfe_dev, stream_info, - VFE_PONG_FLAG); - ISP_DBG("%s: stats_mask %x %x active streams %d\n", __func__, comp_stats_mask[0], comp_stats_mask[1], stats_data->num_active_stream); + streams[num_stream++] = stream_info; } - if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) { - rc = msm_isp_stats_wait_for_cfg_done(vfe_dev); - } else { - vfe_dev->hw_info->vfe_ops.stats_ops.enable_module( - vfe_dev, stats_mask, stream_cfg_cmd->enable); - for (i = 0; i < num_stats_comp_mask; i++) { - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask( - vfe_dev, comp_stats_mask[i], i, 0); - } + for (k = 0; k < MAX_VFE; k++) { + if (!update_vfes[k] || num_active_streams[k]) + continue; + vfe_dev = update_vfes[k]; + vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); } + rc = msm_isp_stats_wait_for_streams(streams, num_stream, 1); + if (rc) + goto error; + return 0; +error: + __msm_isp_stop_stats_streams(streams, num_stream, timestamp); + return rc; +} + +static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + uint32_t idx; + uint32_t num_stats_comp_mask = 0; + struct msm_vfe_stats_stream *stream_info; + struct msm_isp_timestamp timestamp; + int num_stream = 0; + struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; + unsigned long flags; + + msm_isp_get_timestamp(×tamp); + + num_stats_comp_mask = + vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - if (idx >= vfe_dev->hw_info->stats_hw_info->num_stats_type) { - pr_err("%s Invalid stats index %d", __func__, idx); - return -EINVAL; - } + idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); - stream_info = &stats_data->stream_info[idx]; - rc = vfe_dev->buf_mgr->ops->flush_buf(vfe_dev->buf_mgr, - vfe_dev->pdev->id, stream_info->bufq_handle, - MSM_ISP_BUFFER_FLUSH_ALL, ×tamp.buf_time, - vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); - if (rc == -EFAULT) { - msm_isp_halt_send_error(vfe_dev, - ISP_EVENT_BUF_FATAL_ERROR); - return rc; + stream_info = msm_isp_get_stats_stream_common_data( + vfe_dev, idx); + spin_lock_irqsave(&stream_info->lock, flags); + rc = msm_isp_check_stats_stream_state(stream_info, 0); + if (rc) { + spin_unlock_irqrestore(&stream_info->lock, flags); + rc = 0; + continue; } + spin_unlock_irqrestore(&stream_info->lock, flags); + streams[num_stream++] = stream_info; } + + __msm_isp_stop_stats_streams(streams, num_stream, timestamp); + return rc; } @@ -844,8 +1194,10 @@ int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0; struct msm_vfe_stats_stream_cfg_cmd *stream_cfg_cmd = arg; - if (vfe_dev->stats_data.num_active_stream == 0) - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_ub(vfe_dev); + + rc = msm_isp_check_stream_cfg_cmd(vfe_dev, stream_cfg_cmd); + if (rc) + return rc; if (stream_cfg_cmd->enable) { msm_isp_stats_update_cgc_override(vfe_dev, stream_cfg_cmd); @@ -864,10 +1216,11 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) { int rc = 0, i; struct msm_vfe_stats_stream *stream_info; - struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data; struct msm_vfe_axi_stream_update_cmd *update_cmd = arg; struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL; struct msm_isp_sw_framskip *sw_skip_info = NULL; + int vfe_idx; + int k; /*validate request*/ for (i = 0; i < update_cmd->num_streams; i++) { @@ -885,13 +1238,15 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) for (i = 0; i < update_cmd->num_streams; i++) { update_info = (struct msm_vfe_axi_stream_cfg_update_info *) &update_cmd->update_info[i]; - stream_info = &stats_data->stream_info[ - STATS_IDX( - update_info->stream_handle)]; - if (stream_info->stream_handle != + stream_info = msm_isp_get_stats_stream_common_data(vfe_dev, + STATS_IDX(update_info->stream_handle)); + vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + if (vfe_idx == -ENOTTY || stream_info->stream_handle[vfe_idx] != update_info->stream_handle) { pr_err("%s: stats stream handle %x %x mismatch!\n", - __func__, stream_info->stream_handle, + __func__, vfe_idx != -ENOTTY ? + stream_info->stream_handle[vfe_idx] : 0, update_info->stream_handle); continue; } @@ -908,8 +1263,10 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg) stream_info->framedrop_pattern = 0x1; stream_info->framedrop_period = framedrop_period - 1; if (stream_info->init_stats_frame_drop == 0) - vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg( - vfe_dev, stream_info); + for (k = 0; k < stream_info->num_isp; k++) + stream_info->vfe_dev[k]->hw_info-> + vfe_ops.stats_ops.cfg_wm_reg( + vfe_dev, stream_info); break; } case UPDATE_STREAM_SW_FRAME_DROP: { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h index 01120b65be92..e9728f33fae1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,8 +23,58 @@ int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg); -void msm_isp_update_stats_framedrop_reg(struct vfe_device *vfe_dev); void msm_isp_stats_disable(struct vfe_device *vfe_dev); int msm_isp_stats_reset(struct vfe_device *vfe_dev); int msm_isp_stats_restart(struct vfe_device *vfe_dev); +void msm_isp_release_all_stats_stream(struct vfe_device *vfe_dev); +void msm_isp_process_stats_reg_upd_epoch_irq(struct vfe_device *vfe_dev, + enum msm_isp_comp_irq_types irq); + +static inline int msm_isp_get_vfe_idx_for_stats_stream_user( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int vfe_idx; + + for (vfe_idx = 0; vfe_idx < stream_info->num_isp; vfe_idx++) + if (stream_info->vfe_dev[vfe_idx] == vfe_dev) + return vfe_idx; + return -ENOTTY; +} + +static inline int msm_isp_get_vfe_idx_for_stats_stream( + struct vfe_device *vfe_dev, + struct msm_vfe_stats_stream *stream_info) +{ + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream_user(vfe_dev, + stream_info); + + if (vfe_idx < 0) { + WARN(1, "%s vfe index missing for stream %d vfe %d\n", + __func__, stream_info->stats_type, vfe_dev->pdev->id); + vfe_idx = 0; + } + return vfe_idx; +} + +static inline struct msm_vfe_stats_stream * + msm_isp_get_stats_stream_common_data( + struct vfe_device *vfe_dev, + enum msm_isp_stats_type idx) +{ + if (vfe_dev->is_split) + return &vfe_dev->common_data->stats_streams[idx]; + else + return &vfe_dev->common_data->stats_streams[idx + + MSM_ISP_STATS_MAX * vfe_dev->pdev->id]; +} + +static inline struct msm_vfe_stats_stream * + msm_isp_get_stats_stream(struct dual_vfe_resource *dual_vfe_res, + int vfe_id, + enum msm_isp_stats_type idx) +{ + return msm_isp_get_stats_stream_common_data( + dual_vfe_res->vfe_dev[vfe_id], idx); +} #endif /* __MSM_ISP_STATS_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index e47a8de30aa9..fdee3cabd097 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -25,6 +25,22 @@ static DEFINE_MUTEX(bandwidth_mgr_mutex); static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr; +#define MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev) { \ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \ + struct vfe_device *vfe1_dev = vfe_dev->common_data-> \ + dual_vfe_res->vfe_dev[ISP_VFE1]; \ + mutex_lock(&vfe1_dev->core_mutex); \ + } \ +} + +#define MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev) { \ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { \ + struct vfe_device *vfe1_dev = vfe_dev->common_data-> \ + dual_vfe_res->vfe_dev[ISP_VFE1]; \ + mutex_unlock(&vfe1_dev->core_mutex); \ + } \ +} + static uint64_t msm_isp_cpp_clk_rate; #define VFE40_8974V2_VERSION 0x1001001A @@ -762,26 +778,39 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, } case VIDIOC_MSM_ISP_REQUEST_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_request_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_RELEASE_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_release_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_cfg_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_AXI_HALT: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_axi_halt(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_AXI_RESET: mutex_lock(&vfe_dev->core_mutex); + /* For dual vfe reset both on vfe1 call */ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { + mutex_unlock(&vfe_dev->core_mutex); + return 0; + } if (atomic_read(&vfe_dev->error_info.overflow_state) != HALT_ENFORCED) { rc = msm_isp_stats_reset(vfe_dev); @@ -796,6 +825,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_AXI_RESTART: mutex_lock(&vfe_dev->core_mutex); + /* For dual vfe restart both on vfe1 call */ + if (vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE0) { + mutex_unlock(&vfe_dev->core_mutex); + return 0; + } if (atomic_read(&vfe_dev->error_info.overflow_state) != HALT_ENFORCED) { rc = msm_isp_stats_restart(vfe_dev); @@ -848,27 +882,37 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_request_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_release_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_cfg_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_update_stats_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STREAM: mutex_lock(&vfe_dev->core_mutex); + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); rc = msm_isp_update_axi_stream(vfe_dev, arg); + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_SMMU_ATTACH: @@ -883,10 +927,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, vfe_dev->isp_raw2_debug = 0; break; case MSM_SD_UNNOTIFY_FREEZE: - break; case MSM_SD_SHUTDOWN: - while (vfe_dev->vfe_open_cnt != 0) - msm_isp_close_node(sd, NULL); break; default: @@ -1631,8 +1672,8 @@ static int msm_isp_process_iommu_page_fault(struct vfe_device *vfe_dev) { int rc = vfe_dev->buf_mgr->pagefault_debug_disable; - pr_err("%s:%d] VFE%d Handle Page fault! vfe_dev %pK\n", __func__, - __LINE__, vfe_dev->pdev->id, vfe_dev); + pr_err("%s:%d] VFE%d Handle Page fault!\n", __func__, + __LINE__, vfe_dev->pdev->id); msm_isp_halt_send_error(vfe_dev, ISP_EVENT_IOMMU_P_FAULT); @@ -1899,6 +1940,7 @@ static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain, if (vfe_dev->vfe_open_cnt > 0) { atomic_set(&vfe_dev->error_info.overflow_state, HALT_ENFORCED); + pr_err("%s: fault address is %lx\n", __func__, iova); msm_isp_process_iommu_page_fault(vfe_dev); } else { pr_err("%s: no handling, vfe open cnt = %d\n", @@ -1928,9 +1970,6 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -EINVAL; } - if (vfe_dev->pdev->id == ISP_VFE0) - vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; - mutex_lock(&vfe_dev->realtime_mutex); mutex_lock(&vfe_dev->core_mutex); @@ -2032,6 +2071,10 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&vfe_dev->realtime_mutex); return 0; } + MSM_ISP_DUAL_VFE_MUTEX_LOCK(vfe_dev); + msm_isp_release_all_axi_stream(vfe_dev); + msm_isp_release_all_stats_stream(vfe_dev); + /* Unregister page fault handler */ cam_smmu_reg_client_page_fault_handler( vfe_dev->buf_mgr->iommu_hdl, @@ -2059,6 +2102,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) msm_isp_end_avtimer(); vfe_dev->vt_enable = 0; } + MSM_ISP_DUAL_VFE_MUTEX_UNLOCK(vfe_dev); vfe_dev->is_split = 0; mutex_unlock(&vfe_dev->core_mutex); @@ -2088,25 +2132,3 @@ void msm_isp_flush_tasklet(struct vfe_device *vfe_dev) return; } -void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src) -{ - struct msm_vfe_axi_stream *stream_info = NULL; - uint32_t j = 0; - unsigned long flags; - - for (j = 0; j < VFE_AXI_SRC_MAX; j++) { - stream_info = &vfe_dev->axi_data.stream_info[j]; - if (stream_info->state != ACTIVE) - continue; - if (frame_src != SRC_TO_INTF(stream_info->stream_src)) - continue; - - stream_info = - &vfe_dev->axi_data.stream_info[j]; - spin_lock_irqsave(&stream_info->lock, flags); - stream_info->activated_framedrop_period = - stream_info->requested_framedrop_period; - spin_unlock_irqrestore(&stream_info->lock, flags); - } -} diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index 9df60c0d7383..16e3198f35b7 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -70,7 +70,5 @@ void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info); void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format); void msm_isp_flush_tasklet(struct vfe_device *vfe_dev); -void msm_isp_save_framedrop_values(struct vfe_device *vfe_dev, - enum msm_vfe_input_src frame_src); void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp); #endif /* __MSM_ISP_UTIL_H__ */ |
