Просмотр исходного кода

Merge "msm: camera: cpas: Add mechanism to check camnoc idle status" into camera-kernel.lnx.5.0

Savita Patted 4 лет назад
Родитель
Сommit
1c8d0fb818

+ 26 - 0
drivers/cam_cpas/cam_cpas_hw.c

@@ -1545,6 +1545,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
 	struct cam_cpas_private_soc *soc_private = NULL;
 	int rc = 0;
 	long result;
+	int retry_camnoc_idle = 0;
 
 	if (!hw_priv || !stop_args) {
 		CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -1598,6 +1599,18 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
 			}
 		}
 
+		if (cpas_core->internal_ops.qchannel_handshake) {
+			rc = cpas_core->internal_ops.qchannel_handshake(
+				cpas_hw, false);
+			if (rc) {
+				CAM_ERR(CAM_CPAS,
+					"failed in qchannel_handshake rc=%d",
+					rc);
+				retry_camnoc_idle = 1;
+				/* Do not return error, passthrough */
+			}
+		}
+
 		rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
 		if (rc) {
 			CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
@@ -1613,6 +1626,19 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
 				atomic_read(&cpas_core->irq_count));
 		}
 
+		/* try again incase camnoc is still not idle */
+		if (cpas_core->internal_ops.qchannel_handshake &&
+			retry_camnoc_idle) {
+			rc = cpas_core->internal_ops.qchannel_handshake(
+				cpas_hw, false);
+			if (rc) {
+				CAM_ERR(CAM_CPAS,
+					"failed in qchannel_handshake rc=%d",
+					rc);
+				/* Do not return error, passthrough */
+			}
+		}
+
 		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
 			true, false);
 		if (rc) {

+ 3 - 0
drivers/cam_cpas/cam_cpas_hw.h

@@ -71,6 +71,8 @@ enum cam_cpas_access_type {
  * @power_off: Function pointer for hw core specific power off settings
  * @setup_qos_settings: Function pointer for hw to select a specific qos header
  * @print_poweron_settings: Function pointer for hw to print poweron settings
+ * @qchannel_handshake: Function pointer for hw core specific qchannel
+ *                      handshake settings
  *
  */
 struct cam_cpas_internal_ops {
@@ -86,6 +88,7 @@ struct cam_cpas_internal_ops {
 	int (*setup_qos_settings)(struct cam_hw_info *cpas_hw,
 		uint32_t selection_mask);
 	int (*print_poweron_settings)(struct cam_hw_info *cpas_hw);
+	int (*qchannel_handshake)(struct cam_hw_info *cpas_hw, bool power_on);
 };
 
 /**

+ 2 - 0
drivers/cam_cpas/cam_cpas_hw_intf.h

@@ -19,6 +19,8 @@
 #define CAM_CPAS_POLL_MIN_USECS 200
 /* Maximum usecs to sleep while polling */
 #define CAM_CPAS_POLL_MAX_USECS 250
+/* Number of times to retry while polling */
+#define CAM_CPAS_POLL_QH_RETRY_CNT 50
 
 /**
  * enum cam_cpas_hw_type - Enum for CPAS HW type

+ 1 - 0
drivers/cam_cpas/camss_top/cam_camsstop_hw.c

@@ -79,6 +79,7 @@ int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops)
 	internal_ops->power_off = NULL;
 	internal_ops->setup_qos_settings = NULL;
 	internal_ops->print_poweron_settings = NULL;
+	internal_ops->qchannel_handshake = NULL;
 
 	return 0;
 }

+ 62 - 0
drivers/cam_cpas/cpas_top/cam_cpastop_hw.c

@@ -34,6 +34,8 @@
 #include "cam_req_mgr_workq.h"
 
 struct cam_camnoc_info *camnoc_info;
+struct cam_cpas_camnoc_qchannel *qchannel_info;
+
 
 #define CAMNOC_SLAVE_MAX_ERR_CODE 7
 static const char * const camnoc_salve_err_code[] = {
@@ -818,11 +820,65 @@ static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
 	return rc;
 }
 
+static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
+	bool power_on)
+{
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+	int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
+	uint32_t mask = 0;
+	uint32_t wait_data, qchannel_status, qdeny;
+	int rc = 0;
+
+	if (reg_indx == -1)
+		return -EINVAL;
+
+	if (!qchannel_info)
+		return 0;
+
+	if (power_on) {
+		/* wait for QACCEPTN in QCHANNEL status*/
+		mask = BIT(0);
+		wait_data = 1;
+	} else {
+		/* Clear the quiecience request in QCHANNEL ctrl*/
+		cam_io_w_mb(0, soc_info->reg_map[reg_indx].mem_base +
+			qchannel_info->qchannel_ctrl);
+		/* wait for QACCEPTN and QDENY in QCHANNEL status*/
+		mask = BIT(1) | BIT(0);
+		wait_data = 0;
+	}
+
+	rc = cam_io_poll_value_wmask(
+		soc_info->reg_map[reg_indx].mem_base +
+		qchannel_info->qchannel_status,
+		wait_data, mask, CAM_CPAS_POLL_QH_RETRY_CNT,
+		CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
+	if (rc) {
+		CAM_ERR(CAM_CPAS,
+			"camnoc idle sequence failed, qstat 0x%x",
+			cam_io_r(soc_info->reg_map[reg_indx].mem_base +
+			qchannel_info->qchannel_status));
+		/* Do not return error, passthrough */
+		rc = 0;
+	}
+
+	/* check if deny bit is set */
+	qchannel_status = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base +
+				qchannel_info->qchannel_status);
+	qdeny = (qchannel_status & BIT(1));
+	if (!power_on && qdeny)
+		rc = -EBUSY;
+
+	return rc;
+}
+
 static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 	struct cam_cpas_hw_caps *hw_caps)
 {
 	int rc = 0;
 	struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+	qchannel_info = NULL;
 
 	CAM_DBG(CAM_CPAS,
 		"hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
@@ -864,18 +920,23 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
 		break;
 	case CAM_CPAS_TITAN_580_V100:
 		camnoc_info = &cam580_cpas100_camnoc_info;
+		qchannel_info = &cam580_cpas100_qchannel_info;
 		break;
 	case CAM_CPAS_TITAN_540_V100:
 		camnoc_info = &cam540_cpas100_camnoc_info;
+		qchannel_info = &cam540_cpas100_qchannel_info;
 		break;
 	case CAM_CPAS_TITAN_520_V100:
 		camnoc_info = &cam520_cpas100_camnoc_info;
+		qchannel_info = &cam520_cpas100_qchannel_info;
 		break;
 	case CAM_CPAS_TITAN_545_V100:
 		camnoc_info = &cam545_cpas100_camnoc_info;
+		qchannel_info = &cam545_cpas100_qchannel_info;
 		break;
 	case CAM_CPAS_TITAN_570_V200:
 		camnoc_info = &cam570_cpas200_camnoc_info;
+		qchannel_info = &cam570_cpas200_qchannel_info;
 		break;
 	case CAM_CPAS_TITAN_680_V100:
 		camnoc_info = &cam680_cpas100_camnoc_info;
@@ -961,6 +1022,7 @@ int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops)
 	internal_ops->setup_qos_settings = cam_cpastop_setup_qos_settings;
 	internal_ops->print_poweron_settings =
 		cam_cpastop_print_poweron_settings;
+	internal_ops->qchannel_handshake = cam_cpastop_qchannel_handshake;
 
 	return 0;
 }

+ 12 - 0
drivers/cam_cpas/cpas_top/cam_cpastop_hw.h

@@ -356,4 +356,16 @@ struct cam_cpas_work_payload {
 	struct work_struct work;
 };
 
+/**
+ * struct cam_cpas_camnoc_qchannel : Cpas camnoc qchannel info
+ *
+ * @qchannel_ctrl: offset to configure to control camnoc qchannel interface
+ * @qchannel_status: offset to read camnoc qchannel interface status
+ *
+ */
+struct cam_cpas_camnoc_qchannel {
+	uint32_t qchannel_ctrl;
+	uint32_t qchannel_status;
+};
+
 #endif /* _CAM_CPASTOP_HW_H_ */

+ 4 - 0
drivers/cam_cpas/cpas_top/cpastop_v520_100.h

@@ -237,4 +237,8 @@ static struct cam_camnoc_info cam520_cpas100_camnoc_info = {
 	.errata_wa_list = NULL,
 };
 
+static struct cam_cpas_camnoc_qchannel cam520_cpas100_qchannel_info = {
+	.qchannel_ctrl   = 0x14,
+	.qchannel_status = 0x18,
+};
 #endif /* _CPASTOP_V520_100_H_ */

+ 4 - 0
drivers/cam_cpas/cpas_top/cpastop_v540_100.h

@@ -238,4 +238,8 @@ static struct cam_camnoc_info cam540_cpas100_camnoc_info = {
 	.errata_wa_list = NULL,
 };
 
+static struct cam_cpas_camnoc_qchannel cam540_cpas100_qchannel_info = {
+	.qchannel_ctrl   = 0x14,
+	.qchannel_status = 0x18,
+};
 #endif /* _CPASTOP_V540_100_H_ */

+ 4 - 0
drivers/cam_cpas/cpas_top/cpastop_v545_100.h

@@ -315,4 +315,8 @@ static struct cam_camnoc_info cam545_cpas100_camnoc_info = {
 	.errata_wa_list = NULL,
 };
 
+static struct cam_cpas_camnoc_qchannel cam545_cpas100_qchannel_info = {
+	.qchannel_ctrl   = 0x14,
+	.qchannel_status = 0x18,
+};
 #endif /* _CPASTOP_V545_100_H_ */

+ 4 - 0
drivers/cam_cpas/cpas_top/cpastop_v570_200.h

@@ -881,4 +881,8 @@ static struct cam_camnoc_info cam570_cpas200_camnoc_info = {
 	.errata_wa_list = &cam570_cpas200_errata_wa_list,
 };
 
+static struct cam_cpas_camnoc_qchannel cam570_cpas200_qchannel_info = {
+	.qchannel_ctrl   = 0x5C,
+	.qchannel_status = 0x60,
+};
 #endif /* _CPASTOP_V570_200_H_ */

+ 4 - 0
drivers/cam_cpas/cpas_top/cpastop_v580_100.h

@@ -1043,5 +1043,9 @@ static struct cam_camnoc_info cam580_cpas100_camnoc_info = {
 	.errata_wa_list = &cam580_cpas100_errata_wa_list,
 };
 
+static struct cam_cpas_camnoc_qchannel cam580_cpas100_qchannel_info = {
+	.qchannel_ctrl   = 0x5C,
+	.qchannel_status = 0x60,
+};
 #endif /* _CPASTOP_V580_100_H_ */