瀏覽代碼

msm: camera: isp: Change csid stop sequence during flush

This change takes care of a race which we see when we halt master
csid immediately and slave csid halt to follow. In some scenarios
after master csid halt, slave gives violation errors.
With this change we are first changing the halt mode of slave to
internal so that dependency on master is removed and
then issue halt commands to both master and slave.

CRs-Fixed: 2785781
Change-Id: Ib84a8c416e05a4ac54b6afad5c06017931d67a05
Signed-off-by: Shravya Samala <[email protected]>
Shravya Samala 4 年之前
父節點
當前提交
a3077c7802

+ 53 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -897,6 +897,52 @@ static void cam_ife_hw_mgr_dump_acq_data(
 	}
 }
 
+static int cam_ife_mgr_csid_change_halt_mode(struct cam_ife_hw_mgr_ctx *ctx,
+	enum cam_ife_csid_halt_mode halt_mode)
+{
+	struct cam_isp_hw_mgr_res        *hw_mgr_res;
+	struct cam_isp_resource_node     *isp_res;
+	struct cam_ife_csid_hw_halt_args halt;
+	struct cam_hw_intf               *hw_intf;
+	uint32_t i;
+	int rc = 0;
+
+	if (!ctx->is_dual)
+		return 0;
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (i == CAM_ISP_HW_SPLIT_LEFT)
+				continue;
+
+			if (!hw_mgr_res->hw_res[i] ||
+				(hw_mgr_res->hw_res[i]->res_state !=
+				CAM_ISP_RESOURCE_STATE_STREAMING))
+				continue;
+
+			isp_res = hw_mgr_res->hw_res[i];
+
+			if ((isp_res->res_type == CAM_ISP_RESOURCE_PIX_PATH) &&
+				(isp_res->res_id == CAM_IFE_PIX_PATH_RES_IPP)) {
+				hw_intf         = isp_res->hw_intf;
+				halt.node_res   = isp_res;
+				halt.halt_mode  = halt_mode;
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
+					&halt,
+					sizeof(
+					struct cam_ife_csid_hw_halt_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "Halt update failed");
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static int cam_ife_mgr_csid_stop_hw(
 	struct cam_ife_hw_mgr_ctx *ctx, struct list_head  *stop_list,
 		uint32_t  base_idx, uint32_t stop_cmd)
@@ -4074,6 +4120,13 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
 	 */
 	if (i == ctx->num_base)
 		master_base_idx = ctx->base[0].idx;
+
+	/*Change slave mode*/
+	if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY)
+		cam_ife_mgr_csid_change_halt_mode(ctx,
+			CAM_CSID_HALT_MODE_INTERNAL);
+
+
 	CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);
 
 	/* Stop the master CSID path first */

+ 18 - 20
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -529,26 +529,30 @@ static int cam_tfe_hw_mgr_free_hw_res(
 	return 0;
 }
 
-static int cam_tfe_mgr_csid_change_halt_mode(struct list_head  *halt_list,
-	uint32_t  base_idx, enum cam_tfe_csid_halt_mode halt_mode)
+static int cam_tfe_mgr_csid_change_halt_mode(struct cam_tfe_hw_mgr_ctx *ctx,
+	enum cam_tfe_csid_halt_mode halt_mode)
 {
-	struct cam_isp_hw_mgr_res      *hw_mgr_res;
-	struct cam_isp_resource_node   *isp_res;
-	struct cam_csid_hw_halt_args    halt;
-	struct cam_hw_intf             *hw_intf;
+	struct cam_isp_hw_mgr_res        *hw_mgr_res;
+	struct cam_isp_resource_node     *isp_res;
+	struct cam_tfe_csid_hw_halt_args halt;
+	struct cam_hw_intf               *hw_intf;
 	uint32_t i;
 	int rc = 0;
 
-	list_for_each_entry(hw_mgr_res, halt_list, list) {
+	if (!ctx->is_dual)
+		return 0;
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_tfe_csid, list) {
 		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (i == CAM_ISP_HW_SPLIT_LEFT)
+				continue;
+
 			if (!hw_mgr_res->hw_res[i] ||
 				(hw_mgr_res->hw_res[i]->res_state !=
 				CAM_ISP_RESOURCE_STATE_STREAMING))
 				continue;
 
 			isp_res = hw_mgr_res->hw_res[i];
-			if (isp_res->hw_intf->hw_idx != base_idx)
-				continue;
 
 			if ((isp_res->res_type == CAM_ISP_RESOURCE_PIX_PATH) &&
 				(isp_res->res_id ==
@@ -560,7 +564,8 @@ static int cam_tfe_mgr_csid_change_halt_mode(struct list_head  *halt_list,
 					hw_intf->hw_priv,
 					CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
 					&halt,
-					sizeof(struct cam_csid_hw_halt_args));
+					sizeof(
+					struct cam_tfe_csid_hw_halt_args));
 				if (rc)
 					CAM_ERR(CAM_ISP, "Halt update failed");
 				break;
@@ -2668,16 +2673,9 @@ static int cam_tfe_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
 		master_base_idx = ctx->base[0].idx;
 
 	/*Change slave mode*/
-	if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY) {
-		for (i = 0; i < ctx->num_base; i++) {
-			if (ctx->base[i].idx == master_base_idx)
-				continue;
-			cam_tfe_mgr_csid_change_halt_mode(
-				&ctx->res_list_tfe_csid,
-				ctx->base[i].idx,
-				CAM_TFE_CSID_HALT_MODE_INTERNAL);
-		}
-	}
+	if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY)
+		cam_tfe_mgr_csid_change_halt_mode(ctx,
+			CAM_TFE_CSID_HALT_MODE_INTERNAL);
 
 	CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);
 

+ 90 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c

@@ -2344,6 +2344,52 @@ static int cam_ife_csid_enable_pxl_path(
 	return 0;
 }
 
+
+static int cam_ife_csid_change_pxl_halt_mode(
+	struct cam_ife_csid_hw            *csid_hw,
+	struct cam_ife_csid_hw_halt_args  *csid_halt)
+{
+	uint32_t val = 0;
+	const struct cam_ife_csid_reg_offset       *csid_reg;
+	struct cam_hw_soc_info                     *soc_info;
+	const struct cam_ife_csid_pxl_reg_offset   *pxl_reg;
+	struct cam_isp_resource_node               *res;
+
+	res = csid_halt->node_res;
+
+	csid_reg = csid_hw->csid_info->csid_reg;
+	soc_info = &csid_hw->hw_info->soc_info;
+
+	if (res->res_id != CAM_IFE_PIX_PATH_RES_IPP) {
+		CAM_ERR(CAM_ISP, "CSID:%d Invalid res id %d",
+			csid_hw->hw_intf->hw_idx, res->res_id);
+		return -EINVAL;
+	}
+
+	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
+		CAM_ERR(CAM_ISP, "CSID:%d Res:%d in invalid state:%d",
+			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
+		return -EINVAL;
+	}
+
+	pxl_reg = csid_reg->ipp_reg;
+
+	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
+		pxl_reg->csid_pxl_irq_mask_addr);
+
+	/* configure Halt for slave */
+	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
+		pxl_reg->csid_pxl_ctrl_addr);
+	val &= ~0xC;
+	val |= (csid_halt->halt_mode << 2);
+	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
+		pxl_reg->csid_pxl_ctrl_addr);
+	CAM_DBG(CAM_ISP, "CSID:%d IPP path Res halt mode:%d configured:%x",
+		csid_hw->hw_intf->hw_idx, csid_halt->halt_mode, val);
+
+	return 0;
+}
+
 static int cam_ife_csid_disable_pxl_path(
 	struct cam_ife_csid_hw          *csid_hw,
 	struct cam_isp_resource_node    *res,
@@ -3977,6 +4023,47 @@ end:
 	return rc;
 }
 
+int cam_ife_csid_halt(struct cam_ife_csid_hw *csid_hw,
+		void *halt_args)
+{
+	struct cam_isp_resource_node         *res;
+	struct cam_ife_csid_hw_halt_args     *csid_halt;
+	int rc = 0;
+
+	if (!csid_hw || !halt_args) {
+		CAM_ERR(CAM_ISP, "CSID: Invalid args");
+		return -EINVAL;
+	}
+
+	csid_halt = (struct cam_ife_csid_hw_halt_args *)halt_args;
+
+	/* Change the halt mode */
+	res = csid_halt->node_res;
+	CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d",
+		csid_hw->hw_intf->hw_idx,
+		res->res_type, res->res_id);
+
+	if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) {
+		CAM_ERR(CAM_ISP, "CSID:%d Invalid res type %d",
+			csid_hw->hw_intf->hw_idx,
+			res->res_type);
+		return -EINVAL;
+	}
+
+	switch (res->res_id) {
+	case CAM_IFE_PIX_PATH_RES_IPP:
+		rc = cam_ife_csid_change_pxl_halt_mode(csid_hw, csid_halt);
+		break;
+	default:
+		CAM_DBG(CAM_ISP, "CSID:%d res_id %d",
+			csid_hw->hw_intf->hw_idx,
+			res->res_id);
+		break;
+	}
+
+	return rc;
+}
+
 int cam_ife_csid_stop(void *hw_priv,
 	void *stop_args, uint32_t arg_size)
 {
@@ -4450,6 +4537,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
 	case CAM_IFE_CSID_LOG_ACQUIRE_DATA:
 		rc = cam_ife_csid_log_acquire_data(csid_hw, cmd_args);
 		break;
+	case CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE:
+		rc = cam_ife_csid_halt(csid_hw, cmd_args);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
 			csid_hw->hw_intf->hw_idx, cmd_type);

+ 27 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h

@@ -156,6 +156,33 @@ enum cam_ife_csid_halt_cmd {
 	CAM_CSID_HALT_MAX,
 };
 
+/**
+ *  enum cam_ife_csid_halt_mode - Specify the halt command type
+ */
+enum cam_ife_csid_halt_mode {
+	CAM_CSID_HALT_MODE_INTERNAL,
+	CAM_CSID_HALT_MODE_GLOBAL,
+	CAM_CSID_HALT_MODE_MASTER,
+	CAM_CSID_HALT_MODE_SLAVE,
+	CAM_CSID_HALT_MODE_MAX,
+};
+
+/**
+ * struct cam_ife_csid_hw_halt_args
+ * @halt_mode : Applicable only for PATH resources
+ *              0 Internal : The CSID responds to the HALT_CMD
+ *              1 Global   : The CSID responds to the GLOBAL_HALT_CMD
+ *              2 Master   : The CSID responds to the HALT_CMD
+ *              3 Slave    : The CSID responds to the external halt command
+ *                           and not the HALT_CMD register
+ * @node_res : reource pointer array( ie cid or CSID)
+ *
+ */
+struct cam_ife_csid_hw_halt_args {
+	enum cam_ife_csid_halt_mode     halt_mode;
+	struct cam_isp_resource_node   *node_res;
+};
+
 /**
  * struct cam_csid_hw_stop- stop all resources
  * @stop_cmd : Applicable only for PATH resources

+ 5 - 5
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_tfe_csid_hw_intf.h

@@ -96,7 +96,7 @@ enum cam_tfe_csid_halt_cmd {
 };
 
 /**
- * enum cam_tfe_csid_halt_mode_cmd - Specify the halt command type
+ * enum cam_tfe_csid_halt_mode - Specify the halt command type
  */
 enum cam_tfe_csid_halt_mode {
 	CAM_TFE_CSID_HALT_MODE_INTERNAL,
@@ -107,7 +107,7 @@ enum cam_tfe_csid_halt_mode {
 };
 
 /**
- * struct cam_csid_hw_halt_args
+ * struct cam_tfe_csid_hw_halt_args
  * @halt_mode : Applicable only for PATH resources
  *              0 Internal : The CSID responds to the HALT_CMD
  *              1 Global   : The CSID responds to the GLOBAL_HALT_CMD
@@ -117,9 +117,9 @@ enum cam_tfe_csid_halt_mode {
  * @node_res : reource pointer array( ie cid or CSID)
  *
  */
-struct cam_csid_hw_halt_args {
-	enum cam_tfe_csid_halt_mode   halt_mode;
-	struct cam_isp_resource_node *node_res;
+struct cam_tfe_csid_hw_halt_args {
+	enum cam_tfe_csid_halt_mode     halt_mode;
+	struct cam_isp_resource_node   *node_res;
 };
 
 /**

+ 34 - 40
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_csid_hw/cam_tfe_csid_core.c

@@ -1248,48 +1248,34 @@ static int cam_tfe_csid_enable_pxl_path(
 	return 0;
 }
 
-static void cam_tfe_csid_change_pxl_halt_mode(
-	struct cam_tfe_csid_hw          *csid_hw,
-	struct cam_isp_resource_node    *res,
-	enum cam_tfe_csid_halt_mode      halt_mode)
+static int cam_tfe_csid_change_pxl_halt_mode(
+	struct cam_tfe_csid_hw            *csid_hw,
+	struct cam_tfe_csid_hw_halt_args  *csid_halt)
 {
 	uint32_t val = 0;
 	const struct cam_tfe_csid_reg_offset       *csid_reg;
 	struct cam_hw_soc_info                     *soc_info;
-	struct cam_tfe_csid_path_cfg               *path_data;
 	const struct cam_tfe_csid_pxl_reg_offset   *pxl_reg;
-	bool                                        is_ipp;
+	struct cam_isp_resource_node               *res;
+
+	res = csid_halt->node_res;
 
-	path_data = (struct cam_tfe_csid_path_cfg *) res->res_priv;
 	csid_reg = csid_hw->csid_info->csid_reg;
 	soc_info = &csid_hw->hw_info->soc_info;
 
-	if (res->res_id >= CAM_TFE_CSID_PATH_RES_MAX) {
-		CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d",
+	if (res->res_id != CAM_TFE_CSID_PATH_RES_IPP) {
+		CAM_ERR(CAM_ISP, "CSID:%d Invalid res id %d",
 			csid_hw->hw_intf->hw_idx, res->res_id);
-		goto end;
+		return -EINVAL;
 	}
 
-	if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
-		res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
-		CAM_ERR(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
+	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
+		CAM_ERR(CAM_ISP, "CSID:%d Res:%d in invalid state:%d",
 			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
-		goto end;
-	}
-
-	if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP) {
-		is_ipp = true;
-		pxl_reg = csid_reg->ipp_reg;
-	} else {
-		goto end;
+		return -EINVAL;
 	}
 
-	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
-		CAM_ERR(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d",
-			csid_hw->hw_intf->hw_idx, "IPP",
-			res->res_id, res->res_state);
-		goto end;
-	}
+	pxl_reg = csid_reg->ipp_reg;
 
 	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
 		pxl_reg->csid_pxl_irq_mask_addr);
@@ -1298,11 +1284,13 @@ static void cam_tfe_csid_change_pxl_halt_mode(
 	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
 		pxl_reg->csid_pxl_ctrl_addr);
 	val &= ~0xC;
-	val |= (halt_mode << 2);
+	val |= (csid_halt->halt_mode << 2);
 	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
 		pxl_reg->csid_pxl_ctrl_addr);
-end:
-	return;
+	CAM_DBG(CAM_ISP, "CSID:%d IPP path Res halt mode:%d configured:%x",
+		csid_hw->hw_intf->hw_idx, csid_halt->halt_mode, val);
+
+	return 0;
 }
 
 static int cam_tfe_csid_disable_pxl_path(
@@ -2199,14 +2187,15 @@ int cam_tfe_csid_halt(struct cam_tfe_csid_hw *csid_hw,
 	void *halt_args)
 {
 	struct cam_isp_resource_node         *res;
-	struct cam_csid_hw_halt_args         *csid_halt;
+	struct cam_tfe_csid_hw_halt_args     *csid_halt;
+	int rc = 0;
 
 	if (!csid_hw || !halt_args) {
 		CAM_ERR(CAM_ISP, "CSID: Invalid args");
 		return -EINVAL;
 	}
 
-	csid_halt = (struct cam_csid_hw_halt_args *)halt_args;
+	csid_halt = (struct cam_tfe_csid_hw_halt_args *)halt_args;
 
 	/* Change the halt mode */
 	res = csid_halt->node_res;
@@ -2214,20 +2203,25 @@ int cam_tfe_csid_halt(struct cam_tfe_csid_hw *csid_hw,
 		csid_hw->hw_intf->hw_idx,
 		res->res_type, res->res_id);
 
-	switch (res->res_type) {
-	case CAM_ISP_RESOURCE_PIX_PATH:
-		if (res->res_id == CAM_TFE_CSID_PATH_RES_IPP)
-			cam_tfe_csid_change_pxl_halt_mode(csid_hw, res,
-				csid_halt->halt_mode);
+	if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH) {
+		CAM_ERR(CAM_ISP, "CSID:%d Invalid res type %d",
+			csid_hw->hw_intf->hw_idx,
+			res->res_type);
+		return -EINVAL;
+	}
+
+	switch (res->res_id) {
+	case CAM_TFE_CSID_PATH_RES_IPP:
+		rc = cam_tfe_csid_change_pxl_halt_mode(csid_hw, csid_halt);
 		break;
 	default:
-		CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d",
+		CAM_DBG(CAM_ISP, "CSID:%d res_id %d",
 			csid_hw->hw_intf->hw_idx,
-			res->res_type);
+			res->res_id);
 		break;
 	}
 
-	return 0;
+	return rc;
 }
 
 static int cam_tfe_csid_stop(void *hw_priv,