From fdb9ade9a8e711b162e1054cc14300af25b649a3 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 5 Dec 2019 16:30:26 -0800 Subject: [PATCH] msm: camera: sensor: Notify completion in error case There is no need to wait till timeout in case of NACK or underflow error irq is raised, so notify thread for rd_done completion. Also, correct the error mask to catch the NACK error for Master 1. CRs-Fixed: 2598605 Change-Id: Ib8a16ee119dd81f1384283ac7e9f82d3ac2588bb Signed-off-by: Jigarkumar Zala Signed-off-by: Depeng Shao --- .../cam_sensor_module/cam_cci/cam_cci_core.c | 75 +++++++++++++++++-- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 48 +++++++++--- .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 8 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 3 + 4 files changed, 113 insertions(+), 21 deletions(-) diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index a0d1cbe058d9..4a2a643a7408 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1,6 +1,6 @@ // 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 @@ -42,6 +42,9 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, void __iomem *base = soc_info->reg_map[0].mem_base; cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR); + if (!cci_dev->cci_master_info[master].status) + reinit_completion(&cci_dev->cci_master_info[master] + .reset_complete); rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc < 0) { @@ -51,6 +54,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, /* 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 based on MASTER */ if (master == MASTER_0) @@ -66,6 +70,7 @@ static void cam_cci_flush_queue(struct cci_device *cci_dev, CCI_TIMEOUT); if (rc <= 0) CAM_ERR(CAM_CCI, "wait failed %d", rc); + cci_dev->cci_master_info[master].status = 0; } } @@ -127,8 +132,10 @@ static int32_t cam_cci_validate_queue(struct cci_device *cci_dev, return rc; } rc = cci_dev->cci_master_info[master].status; - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_CCI, "Failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; + } } return rc; @@ -246,14 +253,16 @@ static uint32_t cam_cci_wait(struct cci_device *cci_dev, cam_cci_dump_registers(cci_dev, master, queue); #endif CAM_ERR(CAM_CCI, "wait for queue: %d", queue); - if (rc == 0) + if (rc == 0) { rc = -ETIMEDOUT; - cam_cci_flush_queue(cci_dev, master); - return rc; + cam_cci_flush_queue(cci_dev, master); + return rc; + } } rc = cci_dev->cci_master_info[master].status; if (rc < 0) { CAM_ERR(CAM_CCI, "failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; return rc; } @@ -851,7 +860,8 @@ static int32_t cam_cci_data_queue(struct cci_device *cci_dev, rc = cam_cci_transfer_end(cci_dev, master, queue); if (rc < 0) { - CAM_ERR(CAM_CCI, "failed rc %d", rc); + CAM_ERR(CAM_CCI, "Slave: 0x%x failed rc %d", + (c_ctrl->cci_info->sid << 1), rc); return rc; } @@ -918,6 +928,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1024,6 +1035,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, goto rel_mutex_q; } + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Salve: 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); if (read_words <= 0) { @@ -1104,6 +1123,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, cam_cci_flush_queue(cci_dev, master); goto rel_mutex_q; } + + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Slave 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } break; } } @@ -1183,6 +1210,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, mutex_unlock(&cci_dev->cci_master_info[master].mutex); mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1290,6 +1318,14 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, rc = 0; } + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "ERROR with Slave 0x%x:", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + read_words = cam_io_r_mb(base + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); exp_words = ((read_cfg->num_byte / 4) + 1); @@ -1384,6 +1420,8 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, goto ERROR; } mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + reinit_completion(&cci_dev->cci_master_info[master].report_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_write call. This is to @@ -1546,6 +1584,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, * THRESHOLD irq's, we reinit the threshold wait before * we load the burst read cmd. */ + reinit_completion(&cci_dev->cci_master_info[master].rd_done); reinit_completion(&cci_dev->cci_master_info[master].th_complete); CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); @@ -1687,7 +1726,29 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, { int32_t rc = 0; struct cci_device *cci_dev = v4l2_get_subdevdata(sd); - CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + enum cci_i2c_master_t master = MASTER_MAX; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "CCI_DEV IS NULL"); + return -EINVAL; + } + + if (!cci_ctrl) { + CAM_ERR(CAM_CCI, "CCI_CTRL IS NULL"); + return -EINVAL; + } + + master = cci_ctrl->cci_info->cci_i2c_master; + if (master >= MASTER_MAX) { + CAM_ERR(CAM_CCI, "INVALID MASTER: %d", master); + return -EINVAL; + } + + if (cci_dev->cci_master_info[master].status < 0) { + CAM_WARN(CAM_CCI, "CCI hardware is resetting"); + return -EAGAIN; + } + CAM_DBG(CAM_CCI, "master = %d, cmd = %d", master, cci_ctrl->cmd); switch (cci_ctrl->cmd) { case MSM_CCI_INIT: diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 48552c82239b..4a235c8de287 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,6 +1,6 @@ // 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" @@ -82,7 +82,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); - cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); } if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) { cci_master_info = &cci_dev->cci_master_info[MASTER_1]; @@ -90,7 +92,9 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) false; if (!cci_master_info->status) complete(&cci_master_info->reset_complete); - cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); } } @@ -223,9 +227,18 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_0].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M0 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q0 NACK ERROR: 0x%x", base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q1 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_1]); + } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", @@ -234,22 +247,35 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) CAM_ERR(CAM_CCI, "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", base, irq_status0); - cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + + cci_dev->cci_master_info[MASTER_0].reset_pending = true; + cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { cci_dev->cci_master_info[MASTER_1].status = -EINVAL; - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK) - CAM_ERR(CAM_CCI, "Base:%pK, M1 NACK ERROR: 0x%x", + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q0 NACK ERROR: 0x%x", base, irq_status0); - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q1 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_1]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", base, irq_status0); - if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK) CAM_ERR(CAM_CCI, "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", base, irq_status0); - cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + + cci_dev->cci_master_info[MASTER_1].reset_pending = true; + cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h index f00b854e9533..73756a301f7a 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2015, 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_HWREG_ @@ -54,8 +54,10 @@ #define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 #define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 #define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 -#define CCI_IRQ_STATUS_0_I2C_M0_NACK_ERROR_BMSK 0x18000000 -#define CCI_IRQ_STATUS_0_I2C_M1_NACK_ERROR_BMSK 0x60000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK 0x8000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK 0x10000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK 0x20000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK 0x40000000 #define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 #define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 #define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 diff --git a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c index b21287cd5028..9790055c8a87 100644 --- a/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -55,6 +55,7 @@ int cam_cci_init(struct v4l2_subdev *sd, &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, @@ -68,6 +69,7 @@ int cam_cci_init(struct v4l2_subdev *sd, 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); } return 0; @@ -142,6 +144,7 @@ int cam_cci_init(struct v4l2_subdev *sd, } 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);