Merge "msm: camera: Refactor ISP start stop sequence"
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 ebb73e5..64e2198 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -206,6 +206,7 @@
PAUSE,
START_PENDING,
STOP_PENDING,
+ STARTING,
STOPPING,
PAUSE_PENDING,
};
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 d6b51c1..2a2284e 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
@@ -18,6 +18,8 @@
((src < RDI_INTF_0) ? VFE_PIX_0 : \
(VFE_RAW_0 + src - RDI_INTF_0))
+#define HANDLE_TO_IDX(handle) (handle & 0xFF)
+
int msm_isp_axi_create_stream(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -67,7 +69,7 @@
int rc = -1, i;
struct msm_vfe_axi_stream *stream_info =
&axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
switch (stream_cfg_cmd->output_format) {
case V4L2_PIX_FMT_SBGGR8:
@@ -209,7 +211,7 @@
int i, j;
struct msm_vfe_axi_stream *stream_info =
&axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
for (i = 0; i < stream_info->num_planes; i++) {
for (j = 0; j < axi_data->hw_info->num_wm; j++) {
@@ -245,7 +247,7 @@
uint8_t comp_mask = 0;
struct msm_vfe_axi_stream *stream_info =
&axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
for (i = 0; i < stream_info->num_planes; i++)
comp_mask |= 1 << stream_info->wm[i];
@@ -285,7 +287,7 @@
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info = &axi_data->stream_info[
- (stream_cfg_cmd->stream_handle[i] & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
if (stream_info->state != valid_state) {
pr_err("%s: Invalid stream state\n", __func__);
rc = -EINVAL;
@@ -413,7 +415,7 @@
{
struct msm_vfe_axi_stream *stream_info =
&axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
uint32_t framedrop_period = msm_isp_get_framedrop_period(
stream_cfg_cmd->frame_skip_pattern);
@@ -463,13 +465,12 @@
if (rc) {
pr_err("%s: Request validation failed\n", __func__);
msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
- (stream_cfg_cmd->axi_stream_handle & 0xFF));
+ HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle));
return rc;
}
- stream_info =
- &vfe_dev->axi_data.
- stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ stream_info = &vfe_dev->axi_data.
+ stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
@@ -506,7 +507,7 @@
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_axi_stream *stream_info =
&axi_data->stream_info[
- (stream_release_cmd->stream_handle & 0xFF)];
+ HANDLE_TO_IDX(stream_release_cmd->stream_handle)];
struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
if (stream_info->state == AVALIABLE) {
@@ -540,79 +541,70 @@
msm_isp_axi_free_wm(axi_data, stream_info);
msm_isp_axi_destroy_stream(&vfe_dev->axi_data,
- (stream_release_cmd->stream_handle & 0xFF));
+ HANDLE_TO_IDX(stream_release_cmd->stream_handle));
return rc;
}
-void msm_isp_axi_stream_enable_cfg(
+static void msm_isp_axi_stream_enable_cfg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream *stream_info,
- uint32_t *wm_reload_mask)
+ struct msm_vfe_axi_stream *stream_info)
{
int i;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
if (stream_info->state == INACTIVE)
return;
for (i = 0; i < stream_info->num_planes; i++) {
- /*TD: Frame base command*/
if (stream_info->state == START_PENDING)
vfe_dev->hw_info->vfe_ops.axi_ops.
enable_wm(vfe_dev, stream_info->wm[i], 1);
else
vfe_dev->hw_info->vfe_ops.axi_ops.
enable_wm(vfe_dev, stream_info->wm[i], 0);
-
- *wm_reload_mask |= (1 << stream_info->wm[i]);
}
- if (stream_info->state == START_PENDING) {
+ if (stream_info->state == START_PENDING)
axi_data->num_active_stream++;
- stream_info->state = ACTIVE;
- } else {
+ else
axi_data->num_active_stream--;
- stream_info->state = INACTIVE;
- }
}
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev)
{
int i;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- uint32_t wm_reload_mask = 0x0;
for (i = 0; i < MAX_NUM_STREAM; i++) {
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],
- &wm_reload_mask);
- if (axi_data->stream_info[i].state == STOP_PENDING)
- axi_data->stream_info[i].state = STOPPING;
+ vfe_dev, &axi_data->stream_info[i]);
+ 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;
}
}
- /*Reload AXI*/
- vfe_dev->hw_info->vfe_ops.axi_ops.
- reload_wm(vfe_dev, wm_reload_mask);
- if (vfe_dev->axi_data.stream_update) {
- vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
- ISP_DBG("%s: send update complete\n", __func__);
- vfe_dev->axi_data.stream_update = 0;
+ vfe_dev->axi_data.stream_update--;
+ if (vfe_dev->axi_data.stream_update == 0)
complete(&vfe_dev->stream_config_complete);
- }
}
static void msm_isp_cfg_pong_address(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
int i;
- struct msm_isp_buffer *buf = stream_info->buf[1];
+ struct msm_isp_buffer *buf = stream_info->buf[0];
for (i = 0; i < stream_info->num_planes; i++)
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
- VFE_PING_FLAG, buf->mapped_info[i].paddr +
+ VFE_PONG_FLAG, buf->mapped_info[i].paddr +
stream_info->plane_offset[i]);
- stream_info->buf[0] = buf;
+ stream_info->buf[1] = buf;
}
static void msm_isp_get_done_buf(struct vfe_device *vfe_dev,
@@ -638,7 +630,7 @@
struct msm_isp_buffer *buf = NULL;
uint32_t pingpong_bit = 0;
uint32_t bufq_handle = stream_info->bufq_handle;
- uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+ uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
rc = vfe_dev->buf_mgr->ops->get_buf(vfe_dev->buf_mgr,
vfe_dev->pdev->id, bufq_handle, &buf);
@@ -675,7 +667,7 @@
{
int rc;
struct msm_isp_event_data buf_event;
- uint32_t stream_idx = stream_info->stream_handle & 0xFF;
+ uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
uint32_t frame_id = vfe_dev->axi_data.
src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
@@ -726,7 +718,7 @@
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info =
&axi_data->stream_info[
- (stream_cfg_cmd->stream_handle[i] & 0xFF)];
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
if (stream_info->stream_src < RDI_INTF_0)
pix_stream_cnt++;
if (stream_info->stream_src == PIX_ENCODER ||
@@ -795,16 +787,152 @@
ISP_DBG("%s\n", line_str);
}
-int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
+static int msm_isp_axi_wait_for_cfg_done(struct vfe_device *vfe_dev)
{
- int rc = 0, i;
- struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
+ int rc;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
+ init_completion(&vfe_dev->stream_config_complete);
+ vfe_dev->axi_data.stream_update = 2;
+ spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
+ rc = wait_for_completion_interruptible_timeout(
+ &vfe_dev->stream_config_complete,
+ msecs_to_jiffies(500));
+ if (rc == 0) {
+ pr_err("%s: wait timeout\n", __func__);
+ rc = -1;
+ } 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;
+ /*Set address for both PING & PONG register */
+ rc = msm_isp_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;
+ }
+
+ /* For burst stream of one capture, only one buffer
+ * is allocated. Duplicate ping buffer address to pong
+ * buffer to ensure hardware write to a valid address
+ */
+ if (stream_info->stream_type == BURST_STREAM &&
+ stream_info->runtime_num_burst_capture <= 1) {
+ msm_isp_cfg_pong_address(vfe_dev, stream_info);
+ } else {
+ rc = msm_isp_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;
+ }
+ }
+ return rc;
+}
+
+static void msm_isp_get_stream_wm_mask(
+ struct msm_vfe_axi_stream *stream_info,
+ uint32_t *wm_reload_mask)
+{
+ int i;
+ for (i = 0; i < stream_info->num_planes; i++)
+ *wm_reload_mask |= (1 << stream_info->wm[i]);
+}
+
+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)
+{
+ int i, rc = 0;
+ uint8_t src_state, wait_for_complete = 0;
uint32_t wm_reload_mask = 0x0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- uint8_t src_state;
+ 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])];
+ src_state = axi_data->src_info[
+ SRC_TO_INTF(stream_info->stream_src)].active;
+
+ msm_isp_reset_framedrop(vfe_dev, stream_info);
+ msm_isp_get_stream_wm_mask(stream_info, &wm_reload_mask);
+ 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]));
+ return rc;
+ }
+
+ stream_info->state = START_PENDING;
+ if (src_state) {
+ wait_for_complete = 1;
+ } else {
+ if (vfe_dev->dump_reg)
+ msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);
+
+ /*Configure AXI start bits to start immediately*/
+ msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
+ stream_info->state = ACTIVE;
+ }
+ }
+
+ vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
+
+ if (camif_update == ENABLE_CAMIF)
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ update_camif_state(vfe_dev, camif_update);
+
+ if (wait_for_complete)
+ rc = msm_isp_axi_wait_for_cfg_done(vfe_dev);
+
+ 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 i, rc = 0;
+ struct msm_vfe_axi_stream *stream_info;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ 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 = STOP_PENDING;
+ }
+
+ rc = msm_isp_axi_wait_for_cfg_done(vfe_dev);
+ if (rc < 0) {
+ pr_err("%s: wait for config done failed\n", __func__);
+ return rc;
+ }
+
+ if (camif_update == DISABLE_CAMIF)
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ update_camif_state(vfe_dev, DISABLE_CAMIF);
+ return rc;
+}
+
+
+int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
+{
+ int rc = 0;
+ 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;
- uint8_t wait_for_complete = 0;
+
rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd);
if (rc < 0) {
pr_err("%s: Invalid stream state\n", __func__);
@@ -815,104 +943,18 @@
/*Configure UB*/
vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev);
}
-
camif_update =
msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
- if (camif_update == DISABLE_CAMIF)
- vfe_dev->hw_info->vfe_ops.core_ops.
- update_camif_state(vfe_dev, DISABLE_CAMIF);
+ if (stream_cfg_cmd->cmd == START_STREAM)
+ rc = msm_isp_start_axi_stream(
+ vfe_dev, stream_cfg_cmd, camif_update);
+ else
+ rc = msm_isp_stop_axi_stream(
+ vfe_dev, stream_cfg_cmd, camif_update);
- /*
- * Stream start either immediately or at reg update
- * Depends on whether the stream src is active
- * If source is on, start and stop have to be done during reg update
- * If source is off, start can happen immediately or during reg update
- * stop has to be done immediately.
- */
- for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
- stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->stream_handle[i] & 0xFF)];
-
- if (stream_info->stream_src < RDI_INTF_0)
- src_state = axi_data->src_info[0].active;
- else
- src_state = axi_data->src_info[
- (stream_info->stream_src - RDI_INTF_0)].active;
-
- stream_info->state = (stream_cfg_cmd->cmd == START_STREAM) ?
- START_PENDING : STOP_PENDING;
-
- if (stream_cfg_cmd->cmd == START_STREAM) {
- /*Configure framedrop*/
- msm_isp_reset_framedrop(vfe_dev, stream_info);
-
- /*Set address for both PING & PONG register */
- rc = msm_isp_cfg_ping_pong_address(vfe_dev,
- stream_info, VFE_PONG_FLAG);
- if (rc < 0) {
- pr_err("%s: No buffer for start stream\n",
- __func__);
- return rc;
- }
- /* For burst stream of one capture, only one buffer
- * is allocated. Duplicate ping buffer address to pong
- * buffer to ensure hardware write to a valid address
- */
- if (stream_info->stream_type == BURST_STREAM &&
- stream_info->runtime_num_burst_capture <= 1) {
- msm_isp_cfg_pong_address(vfe_dev, stream_info);
- } else {
- rc = msm_isp_cfg_ping_pong_address(vfe_dev,
- stream_info, VFE_PING_FLAG);
- }
- }
- if (src_state && camif_update != DISABLE_CAMIF) {
- /*On the fly stream start/stop */
- wait_for_complete = 1;
- } else {
- if (vfe_dev->dump_reg &&
- stream_cfg_cmd->cmd == START_STREAM)
- msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);
- /*Configure AXI start bits to start immediately*/
- msm_isp_axi_stream_enable_cfg(
- vfe_dev, stream_info, &wm_reload_mask);
- }
- }
- if (!wait_for_complete) {
- /*Reload AXI*/
- if (stream_cfg_cmd->cmd == START_STREAM)
- vfe_dev->hw_info->vfe_ops.axi_ops.
- reload_wm(vfe_dev, wm_reload_mask);
-
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev);
-
- if (camif_update == ENABLE_CAMIF)
- vfe_dev->hw_info->vfe_ops.core_ops.
- update_camif_state(vfe_dev, camif_update);
- } else {
- unsigned long flags;
- spin_lock_irqsave(&vfe_dev->shared_data_lock, flags);
- init_completion(&vfe_dev->stream_config_complete);
- axi_data->stream_update = 1;
- spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
- /*Reload AXI*/
- if (stream_cfg_cmd->cmd == START_STREAM)
- vfe_dev->hw_info->vfe_ops.axi_ops.
- reload_wm(vfe_dev, wm_reload_mask);
- vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
- rc = wait_for_completion_interruptible_timeout(
- &vfe_dev->stream_config_complete,
- msecs_to_jiffies(500));
- if (rc == 0) {
- pr_err("%s: wait timeout\n", __func__);
- rc = -1;
- } else {
- rc = 0;
- }
- }
+ if (rc < 0)
+ pr_err("%s: start/stop stream failed\n", __func__);
return rc;
}
@@ -923,7 +965,7 @@
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
stream_info = &axi_data->stream_info[
- (update_cmd->stream_handle & 0xFF)];
+ HANDLE_TO_IDX(update_cmd->stream_handle)];
if (stream_info->state != ACTIVE && stream_info->state != INACTIVE) {
pr_err("%s: Invalid stream state\n", __func__);
return -EINVAL;
@@ -986,7 +1028,8 @@
pr_err("%s: Invalid handle for composite irq\n",
__func__);
} else {
- stream_idx = comp_info->stream_handle & 0xFF;
+ stream_idx =
+ HANDLE_TO_IDX(comp_info->stream_handle);
stream_info =
&axi_data->stream_info[stream_idx];
ISP_DBG("%s: stream%d frame id: 0x%x\n",
@@ -1023,7 +1066,7 @@
__func__);
continue;
}
- stream_idx = axi_data->free_wm[i] & 0xFF;
+ stream_idx = HANDLE_TO_IDX(axi_data->free_wm[i]);
stream_info = &axi_data->stream_info[stream_idx];
ISP_DBG("%s: stream%d frame id: 0x%x\n",
__func__,
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 ba845bc..f592a60 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
@@ -46,10 +46,6 @@
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg);
-void msm_isp_axi_stream_enable_cfg(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream *stream_info,
- uint32_t *wm_reload_mask);
-
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);