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; + return -EINVAL; } - 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 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; + int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev, + stream_info); - irq_mask = vfe_dev->irq0_mask; - irq_mask_1 = vfe_dev->irq1_mask; - - 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; + uint32_t i; + int rc = 0; - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; - } - - 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); - - stream_info->requested_framedrop_period = - framedrop_period; - vfe0_stream_info->requested_framedrop_period = - 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; + vfe_dev, stream_info, framedrop_pattern, + 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); + + 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; + /* 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; + } - spin_lock_irqsave( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); + stream_info->composite_irq[irq] |= (1 << vfe_dev->pdev->id); + if (stream_info->composite_irq[irq] != stream_info->vfe_mask) + return 1; - 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]; + stream_info->composite_irq[irq] = 0; - 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; - - vfe_dev_cur->common_data->dual_vfe_res-> - epoch_sync_mask &= ~epoch_mask; - completed = 1; - } - } else - completed = 1; - - spin_unlock_irqrestore( - &vfe_dev_cur->common_data->common_dev_data_lock, flags); - - 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; - } + 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); } - - 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 (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 (i = 0; i < 2; i++) { - buf = stream_info->buf[i]; - if (!buf) - continue; + 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; - 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; - } + plane_cfg[k][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; - - 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); - return 0; - } - - if (!scratch) - 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); + 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; + } + + buf = msm_isp_get_stream_buffer(vfe_dev, stream_info); + + 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; + + 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 + vfe_dev->hw_info->vfe_ops.core_ops. + update_camif_state(vfe_dev, DISABLE_CAMIF); } - 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; + /* 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); - 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; - } - else - *camif_update = NO_UPDATE; - } else - *camif_update = NO_UPDATE; + } } -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) +{ + 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; + + 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; + } + if (i != VFE_PIX_0 || ext_read) + continue; + /* 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; - struct msm_vfe_axi_stream *stream_info; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; - 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; - } - stream_info = - &axi_data->stream_info[ - HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])]; - if (stream_info->stream_src >= RDI_INTF_0) - 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++; + 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; - } + /* 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 (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); - - 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) + + 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; - /* 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; - } + /* handle dual stream on ISP_VFE1 turn */ + if (stream_info->num_isp > 1 && + vfe_dev->pdev->id == ISP_VFE0) + 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); + 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--; - continue; - } - 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); + 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->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_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); + } + + 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 = 0; - int vfe_id; - uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle); - struct dual_vfe_resource *dual_vfe_res = NULL; + int rc = -1; + unsigned long flags; - if (stream_idx >= VFE_AXI_SRC_MAX) { - pr_err("%s: Invalid stream idx %d\n", __func__, stream_idx); - return -EINVAL; - } + /* 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; - dual_vfe_res = vfe_dev->common_data->dual_vfe_res; + rc = wait_for_completion_timeout( + active ? &stream_info->active_comp : + &stream_info->inactive_comp, + msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT)); - 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__); + 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 { - 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; - } - } + rc = 0; } 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) +/** + * 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; + struct msm_vfe_axi_stream *stream_info; + + 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; +} + + +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)); + } + } +} + +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; - } - - 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])]; - 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; - } - - 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); - 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; - } - 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); - } - - stream_info->state = START_PENDING; - - 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); - - 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); - - /*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)); - - /* - * 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; - } - } - } - 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; - } - - 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); - } - } - } - - 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) -{ - 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; - 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 = 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__); + rc = -EINVAL; + goto error; } - stream_info = &axi_data->stream_info[ - 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); - spin_unlock_irqrestore(&stream_info->lock, flags); - wait_for_complete_for_this_stream = 0; + 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; + } - 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)); - - /* - * 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. - */ - 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); + 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: wait for config done failed, retry...\n", - __func__); - for (i = 0; i < stream_cfg_cmd->num_streams; i++) { - stream_info = &axi_data->stream_info[ + pr_err("%s: No buffer for stream%d\n", __func__, 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->stream_handle[i])); + spin_unlock_irqrestore(&stream_info->lock, flags); + goto error; + } + 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_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)); + } else { + for (k = 0; k < stream_info->num_isp; k++) { + vfe_dev = stream_info->vfe_dev[k]; + + if (vfe_dev->dump_reg) + msm_camera_io_dump(vfe_dev->vfe_base, + 0x1000, 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)); - 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; } } + spin_unlock_irqrestore(&stream_info->lock, flags); + streams[num_streams++] = stream_info; + } - /* - * 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; - } + 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 (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); + 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; } - 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; - } - } - vfe_dev->reg_update_requested &= - ~(BIT(SRC_TO_INTF(stream_info->stream_src))); - } + 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_ioctl, + struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd) +{ + int i, rc = 0; + struct msm_vfe_axi_stream *stream_info = NULL; + struct msm_vfe_axi_stream *streams[MAX_NUM_STREAM]; + int num_streams = 0; + unsigned long flags; + + if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM || + stream_cfg_cmd->num_streams == 0) + return -EINVAL; + + for (i = 0; i < stream_cfg_cmd->num_streams; i++) { + stream_info = msm_isp_get_stream_common_data(vfe_dev_ioctl, + HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])); + + spin_lock_irqsave(&stream_info->lock, flags); + rc = __msm_isp_check_stream_state(stream_info, 0); + spin_unlock_irqrestore(&stream_info->lock, flags); + if (rc) { + /* + * continue stopping other streams as error here means + * stream is already not active + */ + rc = 0; + continue; + } + 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; + int i; - 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; + 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; } - - 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); - } - 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; + 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); - 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; } 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; - spin_unlock_irqrestore(&stream_info->lock, flags); + 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; + int vfe_idx; - 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], + 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; + + 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); - 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); - } - } } } +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; - 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_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 (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; - msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + 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_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,39 +968,163 @@ 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; - } - - 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); + 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; } - rc = msm_isp_init_stats_ping_pong_reg(vfe_dev, stream_info); + } + return 0; +} + +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); + } + for (k = 0; k < stream_info->num_isp; k++) { + stats_data = &stream_info->vfe_dev[k]->stats_data; + 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 (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); + } + } +} + +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; + uint32_t stats_mask = 0, idx; + 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; + 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_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]); + 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 (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; } - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); + 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 (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; + 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; @@ -724,19 +1132,22 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, __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, 1); - } + 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; } @@ -744,12 +1155,13 @@ 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 stats_mask = 0, idx; - uint32_t comp_stats_mask[MAX_NUM_STATS_COMP_MASK] = {0}; + uint32_t idx; 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_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); @@ -760,83 +1172,21 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, 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, 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; } - - 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 (!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; - - if (stream_info->composite_flag > 0) - 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); + spin_unlock_irqrestore(&stream_info->lock, flags); + 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); - } - } + __msm_isp_stop_stats_streams(streams, num_stream, timestamp); - 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]; - 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; - } - } 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__ */