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

This commit is contained in:
Camera Software Integration 2020-06-19 17:29:26 -07:00 • committed by Gerrit - the friendly Code Review server
commit 9ff96e5949
4 changed files with 140 additions and 142 deletions

View file

@ -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:

View file

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

View file

@ -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,79 +106,46 @@ 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;
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);
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;
}
cam_cci_get_clk_rates(cci_dev, c_ctrl);
/* 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]);
/* Enable Regulators and IRQ*/
rc = cam_soc_util_enable_platform_resource(soc_info, true,
CAM_LOWSVS_VOTE, 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) {

View file

@ -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