Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c2d991e authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: cci: Add check for the cci master initialization" into camera-kernel.lnx.1.0

parents 9546e838 83e46a81
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ static int32_t cam_cci_convert_type_to_num_bytes(
		num_bytes = 4;
		break;
	default:
		CAM_ERR(CAM_CCI, "failed: %d", type);
		CAM_ERR(CAM_CCI, "Wrong Sensor I2c Type: %d", type);
		num_bytes = 0;
		break;
	}
@@ -1648,14 +1648,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;
@@ -1766,7 +1767,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:
+7 −5
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@

#define CCI_TIMEOUT msecs_to_jiffies(1500)

#define NUM_MASTERS 2
#define NUM_QUEUES 2

#define CCI_PINCTRL_STATE_DEFAULT "cci_default"
@@ -122,7 +121,7 @@ struct cam_cci_i2c_queue_info {
};

struct cam_cci_master_info {
	uint32_t status;
	int32_t status;
	atomic_t q_free[NUM_QUEUES];
	uint8_t q_lock[NUM_QUEUES];
	uint8_t reset_pending;
@@ -138,6 +137,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 {
@@ -172,6 +172,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
@@ -204,9 +205,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;
+144 −123
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#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;

	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;
		cci_dev->cci_master_info[master].status = 0;
		if (cci_dev->ref_count == 1) {
			cam_io_w_mb(CCI_RESET_CMD_RMSK,
				base + CCI_RESET_CMD_ADDR);
			cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR);
		} else {
			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;
@@ -20,7 +90,8 @@ int cam_cci_init(struct v4l2_subdev *sd,

	cci_dev = v4l2_get_subdevdata(sd);
	if (!cci_dev || !c_ctrl) {
		CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK",
		CAM_ERR(CAM_CCI,
			"failed: invalid params cci_dev:%pK, c_ctrl:%pK",
			cci_dev, c_ctrl);
		rc = -EINVAL;
		return rc;
@@ -30,144 +101,83 @@ int cam_cci_init(struct v4l2_subdev *sd,
	base = soc_info->reg_map[0].mem_base;

	if (!soc_info || !base) {
		CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK",
		CAM_ERR(CAM_CCI,
			"failed: invalid params soc_info:%pK, base:%pK",
			soc_info, base);
		rc = -EINVAL;
		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", cci_dev->ref_count);
		CAM_DBG(CAM_CCI, "master %d", 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 */
			rc = wait_for_completion_timeout(
			&cci_dev->cci_master_info[master].reset_complete,
				CCI_TIMEOUT);
			if (rc <= 0)
				CAM_ERR(CAM_CCI, "wait failed %d", rc);
			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--;
		}
		return 0;
		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");
	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,
		CAM_LOWSVS_VOTE, true);
	if (rc < 0) {
		CAM_DBG(CAM_CCI, "request platform resources failed");
		CAM_DBG(CAM_CCI, "request platform resources failed, rc: %d",
			rc);
		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;

	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
					= CCI_I2C_QUEUE_0_SIZE;
			else
				cci_dev->cci_i2c_queue_info[i][j].max_queue_size
					= CCI_I2C_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);
	rc = wait_for_completion_timeout(
		&cci_dev->cci_master_info[master].reset_complete,
		CCI_TIMEOUT);
	if (rc <= 0) {
		CAM_ERR(CAM_CCI, "wait_for_completion_timeout");
		if (rc == 0)
			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 */
	cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE,
@@ -181,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);
@@ -201,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);
@@ -382,27 +392,38 @@ 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;
		CAM_DBG(CAM_CCI,
			"All submodules are released for master: %d", master);
	}

	if (--cci_dev->ref_count) {
		CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count);
		CAM_DBG(CAM_CCI, "Submodule release: Ref_count: %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
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-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