Browse Source

msm: camera: cci: Add check for the cci master initialization

Multiple Sensor submodules can stream on same CCI master. Currently,
there is not any knowledge, whether requested master is already
initialized by other submodules. This can result in operation slave
in error, while other submodule tries to init the same master.
This change adds the boolean variable to notify cci hardware, whether
master is already initialized, and do the operations accordingly.

CRs-Fixed: 2686487
Change-Id: I8b5d01fc9fd06176e9fbd9a69d56424d4ef79a73
Signed-off-by: Jigarkumar Zala <[email protected]>
Jigarkumar Zala 5 năm trước cách đây
mục cha
commit
becd9f4f11

+ 4 - 3
drivers/cam_sensor_module/cam_cci/cam_cci_core.c

@@ -1776,14 +1776,15 @@ static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd,
 	return rc;
 }
 
-static int32_t cam_cci_release(struct v4l2_subdev *sd)
+static int32_t cam_cci_release(struct v4l2_subdev *sd,
+	enum cci_i2c_master_t master)
 {
 	uint8_t rc = 0;
 	struct cci_device *cci_dev;
 
 	cci_dev = v4l2_get_subdevdata(sd);
 
-	rc = cam_cci_soc_release(cci_dev);
+	rc = cam_cci_soc_release(cci_dev, master);
 	if (rc < 0) {
 		CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc);
 		return rc;
@@ -1896,7 +1897,7 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd,
 		break;
 	case MSM_CCI_RELEASE:
 		mutex_lock(&cci_dev->init_mutex);
-		rc = cam_cci_release(sd);
+		rc = cam_cci_release(sd, master);
 		mutex_unlock(&cci_dev->init_mutex);
 		break;
 	case MSM_CCI_I2C_READ:

+ 6 - 5
drivers/cam_sensor_module/cam_cci/cam_cci_dev.h

@@ -40,8 +40,6 @@
 #define CCI_MAX_DELAY 1000000
 
 #define CCI_TIMEOUT msecs_to_jiffies(1500)
-
-#define NUM_MASTERS 2
 #define NUM_QUEUES 2
 
 #define CCI_PINCTRL_STATE_DEFAULT "cci_default"
@@ -142,6 +140,7 @@ struct cam_cci_master_info {
 	struct semaphore master_sem;
 	bool is_first_req;
 	uint16_t freq_ref_cnt;
+	bool is_initilized;
 };
 
 struct cam_cci_clk_params_t {
@@ -176,6 +175,7 @@ enum cam_cci_state_t {
  * @cci_clk_info:               CCI clock information
  * @cam_cci_i2c_queue_info:     CCI queue information
  * @i2c_freq_mode:              I2C frequency of operations
+ * @master_active_slave:        Number of active/connected slaves for master
  * @cci_clk_params:             CCI hw clk params
  * @cci_gpio_tbl:               CCI GPIO table
  * @cci_gpio_tbl_size:          GPIO table size
@@ -208,9 +208,10 @@ struct cci_device {
 	uint8_t ref_count;
 	enum cam_cci_state_t cci_state;
 	struct cam_cci_i2c_queue_info
-		cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
-	struct cam_cci_master_info cci_master_info[NUM_MASTERS];
-	enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS];
+		cci_i2c_queue_info[MASTER_MAX][NUM_QUEUES];
+	struct cam_cci_master_info cci_master_info[MASTER_MAX];
+	enum i2c_freq_mode i2c_freq_mode[MASTER_MAX];
+	uint8_t master_active_slave[MASTER_MAX];
 	struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES];
 	struct msm_pinctrl_info cci_pinctrl;
 	uint8_t cci_pinctrl_status;

+ 127 - 132
drivers/cam_sensor_module/cam_cci/cam_cci_soc.c

@@ -6,10 +6,78 @@
 #include "cam_cci_dev.h"
 #include "cam_cci_core.h"
 
+static int cam_cci_init_master(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master)
+{
+	int i = 0, rc = 0;
+	void __iomem *base = NULL;
+	struct cam_hw_soc_info *soc_info = NULL;
+	uint32_t max_queue_0_size = 0, max_queue_1_size = 0;
+
+	soc_info = &cci_dev->soc_info;
+	base = soc_info->reg_map[0].mem_base;
+
+	if (cci_dev->hw_version != CCI_VERSION_1_2_9) {
+		max_queue_0_size = CCI_I2C_QUEUE_0_SIZE_V_1_2;
+		max_queue_1_size = CCI_I2C_QUEUE_1_SIZE_V_1_2;
+	} else {
+		max_queue_0_size = CCI_I2C_QUEUE_0_SIZE;
+		max_queue_1_size = CCI_I2C_QUEUE_1_SIZE;
+	}
+
+	cci_dev->master_active_slave[master]++;
+	if (!cci_dev->cci_master_info[master].is_initilized) {
+		/* Re-initialize the completion */
+		reinit_completion(
+		&cci_dev->cci_master_info[master].reset_complete);
+		reinit_completion(&cci_dev->cci_master_info[master].rd_done);
+
+		/* reinit the reports for the queue */
+		for (i = 0; i < NUM_QUEUES; i++)
+			reinit_completion(
+			&cci_dev->cci_master_info[master].report_q[i]);
+
+		/* Set reset pending flag to true */
+		cci_dev->cci_master_info[master].reset_pending = true;
+		cam_io_w_mb((master == MASTER_0) ?
+			CCI_M0_RESET_RMSK : CCI_M1_RESET_RMSK,
+			base + CCI_RESET_CMD_ADDR);
+		if (!wait_for_completion_timeout(
+			&cci_dev->cci_master_info[master].reset_complete,
+			CCI_TIMEOUT)) {
+			CAM_ERR(CAM_CCI,
+				"Failed: reset complete timeout for master: %d",
+				master);
+			rc = -ETIMEDOUT;
+			cci_dev->master_active_slave[master]--;
+			return rc;
+		}
+
+		flush_workqueue(cci_dev->write_wq[master]);
+
+		/* Setting up the queue size for master */
+		cci_dev->cci_i2c_queue_info[master][QUEUE_0].max_queue_size
+					= max_queue_0_size;
+		cci_dev->cci_i2c_queue_info[master][QUEUE_1].max_queue_size
+					= max_queue_1_size;
+
+		CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0: %d Q1: %d", master,
+			cci_dev->cci_i2c_queue_info[master][QUEUE_0]
+				.max_queue_size,
+			cci_dev->cci_i2c_queue_info[master][QUEUE_1]
+				.max_queue_size);
+
+		cci_dev->cci_master_info[master].status = 0;
+		cci_dev->cci_master_info[master].is_initilized = true;
+	}
+
+	return 0;
+}
+
 int cam_cci_init(struct v4l2_subdev *sd,
 	struct cam_cci_ctrl *c_ctrl)
 {
-	uint8_t i = 0, j = 0;
+	uint8_t i = 0;
 	int32_t rc = 0;
 	struct cci_device *cci_dev;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
@@ -17,7 +85,6 @@ int cam_cci_init(struct v4l2_subdev *sd,
 	struct cam_axi_vote axi_vote = {0};
 	struct cam_hw_soc_info *soc_info = NULL;
 	void __iomem *base = NULL;
-	uint32_t max_queue_0_size = 0, max_queue_1_size = 0;
 
 	cci_dev = v4l2_get_subdevdata(sd);
 	if (!cci_dev || !c_ctrl) {
@@ -39,78 +106,45 @@ int cam_cci_init(struct v4l2_subdev *sd,
 		return rc;
 	}
 
-	CAM_DBG(CAM_CCI, "Base address %pK", base);
+	if (master >= MASTER_MAX || master < 0) {
+		CAM_ERR(CAM_CCI, "Incorrect Master: %d", master);
+		return -EINVAL;
+	}
+
+	if (!cci_dev->write_wq[master]) {
+		CAM_ERR(CAM_CCI, "Null memory for write wq[:%d]", master);
+		rc = -ENOMEM;
+		return rc;
+	}
 
 	if (cci_dev->ref_count++) {
-		CAM_DBG(CAM_CCI,
-			"ref_count:%d, master:%d",
-			cci_dev->ref_count, master);
-		if (master < MASTER_MAX && master >= 0) {
-			mutex_lock(&cci_dev->cci_master_info[master].mutex);
-			flush_workqueue(cci_dev->write_wq[master]);
-			/* Re-initialize the completion */
-			reinit_completion(
-			&cci_dev->cci_master_info[master].reset_complete);
-			reinit_completion(
-			&cci_dev->cci_master_info[master].rd_done);
-			for (i = 0; i < NUM_QUEUES; i++)
-				reinit_completion(
-				&cci_dev->cci_master_info[master].report_q[i]);
-			/* Set reset pending flag to true */
-			cci_dev->cci_master_info[master].reset_pending = true;
-			cci_dev->cci_master_info[master].status = 0;
-			/* Set proper mask to RESET CMD address */
-			if (master == MASTER_0)
-				cam_io_w_mb(CCI_M0_RESET_RMSK,
-					base + CCI_RESET_CMD_ADDR);
-			else
-				cam_io_w_mb(CCI_M1_RESET_RMSK,
-					base + CCI_RESET_CMD_ADDR);
-			/* wait for reset done irq */
-			if (!wait_for_completion_timeout(
-			&cci_dev->cci_master_info[master].reset_complete,
-				CCI_TIMEOUT)) {
-				CAM_ERR(CAM_CCI,
-					"wait timeout for reset_complete for master: %d",
-					master);
-				reinit_completion(
-				&cci_dev->cci_master_info[master].reset_complete
-				);
-				rc = -EINVAL;
-			}
-			cci_dev->cci_master_info[master].status = 0;
-			mutex_unlock(&cci_dev->cci_master_info[master].mutex);
+		rc = cam_cci_init_master(cci_dev, master);
+		if (rc) {
+			CAM_ERR(CAM_CCI, "Failed to init: Master: %d: rc: %d",
+				master, rc);
+			cci_dev->ref_count--;
 		}
+		CAM_DBG(CAM_CCI, "ref_count %d, master: %d",
+			cci_dev->ref_count, master);
 		return rc;
 	}
 
 	ahb_vote.type = CAM_VOTE_ABSOLUTE;
 	ahb_vote.vote.level = CAM_LOWSVS_VOTE;
 	axi_vote.num_paths = 1;
-	axi_vote.axi_path[0].path_data_type =
-		CAM_AXI_PATH_DATA_ALL;
-	axi_vote.axi_path[0].transac_type =
-		CAM_AXI_TRANSACTION_WRITE;
-	axi_vote.axi_path[0].camnoc_bw =
-		CAM_CPAS_DEFAULT_AXI_BW;
-	axi_vote.axi_path[0].mnoc_ab_bw =
-		CAM_CPAS_DEFAULT_AXI_BW;
-	axi_vote.axi_path[0].mnoc_ib_bw =
-		CAM_CPAS_DEFAULT_AXI_BW;
-
-	rc = cam_cpas_start(cci_dev->cpas_handle,
-		&ahb_vote, &axi_vote);
-	if (rc != 0)
-		CAM_ERR(CAM_CCI, "CPAS start failed, rc: %d", rc);
+	axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL;
+	axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE;
+	axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW;
 
-	cam_cci_get_clk_rates(cci_dev, c_ctrl);
+	rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote);
+	if (rc) {
+		CAM_ERR(CAM_CCI, "CPAS start failed rc= %d", rc);
+		return rc;
+	}
 
-	/* Re-initialize the completion */
-	reinit_completion(&cci_dev->cci_master_info[master].reset_complete);
-	reinit_completion(&cci_dev->cci_master_info[master].rd_done);
-	for (i = 0; i < NUM_QUEUES; i++)
-		reinit_completion(
-			&cci_dev->cci_master_info[master].report_q[i]);
+	cam_cci_get_clk_rates(cci_dev, c_ctrl);
 
 	/* Enable Regulators and IRQ*/
 	rc = cam_soc_util_enable_platform_resource(soc_info, true,
@@ -121,73 +155,27 @@ int cam_cci_init(struct v4l2_subdev *sd,
 		goto platform_enable_failed;
 	}
 
-	cci_dev->hw_version = cam_io_r_mb(base +
-		CCI_HW_VERSION_ADDR);
+	cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR);
 	CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version);
 
-	cci_dev->payload_size =
-		MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11;
+	cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11;
 	cci_dev->support_seq_write = 1;
 
-	if (cci_dev->hw_version == CCI_VERSION_1_2_9) {
-		max_queue_0_size = CCI_I2C_QUEUE_0_SIZE_V_1_2;
-		max_queue_1_size = CCI_I2C_QUEUE_1_SIZE_V_1_2;
-	} else {
-		max_queue_0_size = CCI_I2C_QUEUE_0_SIZE;
-		max_queue_1_size = CCI_I2C_QUEUE_1_SIZE;
-	}
-
-	for (i = 0; i < NUM_MASTERS; i++) {
-		for (j = 0; j < NUM_QUEUES; j++) {
-			if (j == QUEUE_0)
-				cci_dev->cci_i2c_queue_info[i][j].max_queue_size
-					= max_queue_0_size;
-			else
-				cci_dev->cci_i2c_queue_info[i][j].max_queue_size
-					= max_queue_1_size;
-
-			CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i,
-			cci_dev->cci_i2c_queue_info[i][j].max_queue_size,
-			cci_dev->cci_i2c_queue_info[i][j].max_queue_size);
-		}
-	}
-
-	cci_dev->cci_master_info[master].reset_pending = true;
-	cci_dev->cci_master_info[master].status = 0;
-	cam_io_w_mb(CCI_RESET_CMD_RMSK, base +
-			CCI_RESET_CMD_ADDR);
-	cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR);
-	if (!wait_for_completion_timeout(
-		&cci_dev->cci_master_info[master].reset_complete,
-		CCI_TIMEOUT)) {
-		CAM_ERR(CAM_CCI,
-			"wait timeout for reset_complete for master: %d",
-			master);
-
-		rc = -ETIMEDOUT;
+	rc = cam_cci_init_master(cci_dev, master);
+	if (rc) {
+		CAM_ERR(CAM_CCI, "Failed to init: Master: %d, rc: %d",
+			master, rc);
 		goto reset_complete_failed;
 	}
+
 	for (i = 0; i < MASTER_MAX; i++)
 		cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES;
-	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK,
-		base + CCI_IRQ_MASK_0_ADDR);
-	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK,
-		base + CCI_IRQ_CLEAR_0_ADDR);
-	cam_io_w_mb(CCI_IRQ_MASK_1_RMSK,
-		base + CCI_IRQ_MASK_1_ADDR);
-	cam_io_w_mb(CCI_IRQ_MASK_1_RMSK,
-		base + CCI_IRQ_CLEAR_1_ADDR);
-	cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
-	for (i = 0; i < MASTER_MAX; i++) {
-		if (!cci_dev->write_wq[i]) {
-			CAM_ERR(CAM_CCI, "Failed to flush write wq");
-			rc = -ENOMEM;
-			goto reset_complete_failed;
-		} else {
-			flush_workqueue(cci_dev->write_wq[i]);
-		}
-	}
+	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR);
+	cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR);
+	cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR);
+	cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR);
+	cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
 
 	/* Set RD FIFO threshold for M0 & M1 */
 	if (cci_dev->hw_version != CCI_VERSION_1_2_9) {
@@ -203,7 +191,6 @@ int cam_cci_init(struct v4l2_subdev *sd,
 
 reset_complete_failed:
 	cam_soc_util_disable_platform_resource(soc_info, 1, 1);
-
 platform_enable_failed:
 	cci_dev->ref_count--;
 	cam_cpas_stop(cci_dev->cpas_handle);
@@ -223,9 +210,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev)
 {
 	uint8_t i = 0, j = 0;
 
-	for (i = 0; i < NUM_MASTERS; i++) {
+	for (i = 0; i < MASTER_MAX; i++) {
 		new_cci_dev->cci_master_info[i].status = 0;
 		new_cci_dev->cci_master_info[i].is_first_req = true;
+		new_cci_dev->cci_master_info[i].is_initilized = false;
 		mutex_init(&new_cci_dev->cci_master_info[i].mutex);
 		sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1);
 		spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt);
@@ -400,27 +388,34 @@ int cam_cci_parse_dt_info(struct platform_device *pdev,
 	return 0;
 }
 
-int cam_cci_soc_release(struct cci_device *cci_dev)
+int cam_cci_soc_release(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master)
 {
 	uint8_t i = 0, rc = 0;
-	struct cam_hw_soc_info *soc_info =
-		&cci_dev->soc_info;
+	struct cam_hw_soc_info *soc_info = &cci_dev->soc_info;
 
-	if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) {
-		CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d",
-			cci_dev->ref_count, cci_dev->cci_state);
+	if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED ||
+			!cci_dev->master_active_slave[master]) {
+		CAM_ERR(CAM_CCI,
+			"invalid cci_dev_ref count %u | cci state %d | master_ref_count %u",
+			cci_dev->ref_count, cci_dev->cci_state,
+			cci_dev->master_active_slave[master]);
 		return -EINVAL;
 	}
+
+	if (--cci_dev->master_active_slave[master])
+		cci_dev->cci_master_info[master].is_initilized = false;
+
 	if (--cci_dev->ref_count) {
 		CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count);
 		return 0;
 	}
-	for (i = 0; i < MASTER_MAX; i++)
+
+	for (i = 0; i < MASTER_MAX; i++) {
 		if (cci_dev->write_wq[i])
 			flush_workqueue(cci_dev->write_wq[i]);
-
-	for (i = 0; i < MASTER_MAX; i++)
 		cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES;
+	}
 
 	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
 	if (rc) {

+ 3 - 2
drivers/cam_sensor_module/cam_cci/cam_cci_soc.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_CCI_SOC_H_
@@ -23,7 +23,8 @@ int cam_cci_init(struct v4l2_subdev *sd,
  *
  * This API releases the CCI and its SOC resources
  */
-int cam_cci_soc_release(struct cci_device *cci_dev);
+int cam_cci_soc_release(struct cci_device *cci_dev,
+	enum cci_i2c_master_t master);
 
 /**
  * @pdev: Platform device