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

Commit 5da5db28 authored by Karthik Anantha Ram's avatar Karthik Anantha Ram Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: cci: Fix burst read sequence



This change clears the threshold irq after draining the FIFO
buffer as oppose to immediately clearing it. Also added separate
complete events for threshold and read done.

Change-Id: I29f21545bb52a3c08ec1afffdd7d3f610a3055dc
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
parent cc53d333
Loading
Loading
Loading
Loading
+80 −11
Original line number Diff line number Diff line
@@ -870,8 +870,8 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
	struct cam_cci_ctrl *c_ctrl)
{
	int32_t rc = 0;
	uint32_t val = 0, i = 0;
	unsigned long rem_jiffies;
	uint32_t val = 0, i = 0, j = 0;
	unsigned long rem_jiffies, flags;
	int32_t read_words = 0, exp_words = 0;
	int32_t index = 0, first_byte = 0, total_read_words = 0;
	enum cci_i2c_master_t master;
@@ -990,11 +990,13 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,

	val = 1 << ((master * 2) + queue);
	cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR);

	exp_words = ((read_cfg->num_byte / 4) + 1);
	CAM_DBG(CAM_CCI, "waiting for threshold [exp_words %d]", exp_words);

	while (exp_words != total_read_words) {
	while (total_read_words != exp_words) {
		rem_jiffies = wait_for_completion_timeout(
			&cci_dev->cci_master_info[master].reset_complete,
			&cci_dev->cci_master_info[master].th_complete,
			CCI_TIMEOUT);
		if (!rem_jiffies) {
			rc = -ETIMEDOUT;
@@ -1013,6 +1015,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,

		read_words = cam_io_r_mb(base +
			CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
		if (read_words <= 0) {
			CAM_DBG(CAM_CCI, "FIFO Buffer lvl is 0");
			continue;
		}

		j++;
		CAM_DBG(CAM_CCI, "Iteration: %u read_words %d", j, read_words);

		total_read_words += read_words;
		while (read_words > 0) {
			val = cam_io_r_mb(base +
@@ -1034,8 +1044,55 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd,
			}
			read_words--;
		}

		CAM_DBG(CAM_CCI, "Iteraion:%u total_read_words %d",
			j, total_read_words);

		spin_lock_irqsave(&cci_dev->lock_status, flags);
		if (cci_dev->irq_status1) {
			CAM_DBG(CAM_CCI, "clear irq_status1:%x",
				cci_dev->irq_status1);
			cam_io_w_mb(cci_dev->irq_status1,
				base + CCI_IRQ_CLEAR_1_ADDR);
			cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
			cci_dev->irq_status1 = 0;
		}
		spin_unlock_irqrestore(&cci_dev->lock_status, flags);

		if (total_read_words == exp_words) {
		   /*
		    * This wait is for RD_DONE irq, if RD_DONE is
		    * triggered we will call complete on both threshold
		    * & read done waits. As part of the threshold wait
		    * we will be draining the entire buffer out. This
		    * wait is to compensate for the complete invoked for
		    * RD_DONE exclusively.
		    */
			rem_jiffies = wait_for_completion_timeout(
			&cci_dev->cci_master_info[master].reset_complete,
			CCI_TIMEOUT);
			if (!rem_jiffies) {
				rc = -ETIMEDOUT;
				val = cam_io_r_mb(base +
					CCI_I2C_M0_READ_BUF_LEVEL_ADDR +
					master * 0x100);
				CAM_ERR(CAM_CCI,
					"Failed to receive RD_DONE irq rc = %d FIFO buf_lvl:0x%x",
					rc, val);
				#ifdef DUMP_CCI_REGISTERS
					cam_cci_dump_registers(cci_dev,
						master, queue);
				#endif
					cam_cci_flush_queue(cci_dev, master);
				goto rel_mutex;
			}
			break;
		}
	}

	CAM_DBG(CAM_CCI, "Burst read successful words_read %d",
		total_read_words);

rel_mutex:
	mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]);
	return rc;
@@ -1167,7 +1224,8 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd,

	val = 1 << ((master * 2) + queue);
	cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR);
	CAM_DBG(CAM_CCI, "wait_for_completion_timeout");
	CAM_DBG(CAM_CCI,
		"waiting_for_rd_done [exp_words: %d]", exp_words);

	rc = wait_for_completion_timeout(
		&cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT);
@@ -1222,7 +1280,6 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd,
	}
rel_mutex:
	mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]);

	return rc;
}

@@ -1401,23 +1458,34 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd,
	}

	read_bytes = read_cfg->num_byte;

	/*
	 * To avoid any conflicts due to back to back trigger of
	 * THRESHOLD irq's, we reinit the threshold wait before
	 * we load the burst read cmd.
	 */
	reinit_completion(&cci_dev->cci_master_info[master].th_complete);

	CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes);
	do {
		if (read_bytes > CCI_I2C_MAX_BYTE_COUNT)
		if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT)
			read_cfg->num_byte = CCI_I2C_MAX_BYTE_COUNT;
		else
			read_cfg->num_byte = read_bytes;

		if (read_cfg->num_byte > CCI_READ_MAX)
		if (read_cfg->num_byte >= CCI_READ_MAX) {
			cci_dev->is_burst_read = true;
			rc = cam_cci_burst_read(sd, c_ctrl);
		else
		} else {
			cci_dev->is_burst_read = false;
			rc = cam_cci_read(sd, c_ctrl);

		}
		if (rc) {
			CAM_ERR(CAM_CCI, "failed to read rc:%d", rc);
			goto ERROR;
		}

		if (read_bytes > CCI_I2C_MAX_BYTE_COUNT) {
		if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT) {
			read_cfg->addr += (CCI_I2C_MAX_BYTE_COUNT /
				read_cfg->data_type);
			read_cfg->data += CCI_I2C_MAX_BYTE_COUNT;
@@ -1428,6 +1496,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd,
	} while (read_bytes);

ERROR:
	cci_dev->is_burst_read = false;
	return rc;
}

+39 −13
Original line number Diff line number Diff line
@@ -65,15 +65,12 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
		&cci_dev->soc_info;
	void __iomem *base = soc_info->reg_map[0].mem_base;
	unsigned long flags;
	bool burst_read_assert = false;
	bool rd_done_th_assert = false;

	irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR);
	irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR);
	cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR);
	cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR);
	cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);

	CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1);

	if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) {
		if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) {
			cci_dev->cci_master_info[MASTER_0].reset_pending =
@@ -92,18 +89,23 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
	if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) &&
		(irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD)) {
		cci_dev->cci_master_info[MASTER_0].status = 0;
		rd_done_th_assert = true;
		complete(&cci_dev->cci_master_info[MASTER_0].th_complete);
		complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
		burst_read_assert = true;
	}
	if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) &&
		(!burst_read_assert)) {
		(!rd_done_th_assert)) {
		cci_dev->cci_master_info[MASTER_0].status = 0;
		rd_done_th_assert = true;
		if (cci_dev->is_burst_read)
			complete(
			&cci_dev->cci_master_info[MASTER_0].th_complete);
		complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
	}
	if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) &&
		(!burst_read_assert)) {
		(!rd_done_th_assert)) {
		cci_dev->cci_master_info[MASTER_0].status = 0;
		complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
		complete(&cci_dev->cci_master_info[MASTER_0].th_complete);
	}
	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) {
		struct cam_cci_master_info *cci_master_info;
@@ -142,18 +144,23 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
	if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) &&
		(irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)) {
		cci_dev->cci_master_info[MASTER_1].status = 0;
		rd_done_th_assert = true;
		complete(&cci_dev->cci_master_info[MASTER_1].th_complete);
		complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
		burst_read_assert = true;
	}
	if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) &&
		(!burst_read_assert)) {
		(!rd_done_th_assert)) {
		cci_dev->cci_master_info[MASTER_1].status = 0;
		rd_done_th_assert = true;
		if (cci_dev->is_burst_read)
			complete(
			&cci_dev->cci_master_info[MASTER_1].th_complete);
		complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
	}
	if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) &&
		(!burst_read_assert)) {
		(!rd_done_th_assert)) {
		cci_dev->cci_master_info[MASTER_1].status = 0;
		complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
		complete(&cci_dev->cci_master_info[MASTER_1].th_complete);
	}
	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) {
		struct cam_cci_master_info *cci_master_info;
@@ -189,6 +196,12 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
			&cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1],
			flags);
	}
	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE)
		CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_0");

	if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE)
		CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_1");

	if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
		cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
		cam_io_w_mb(CCI_M0_RESET_RMSK,
@@ -211,6 +224,19 @@ irqreturn_t cam_cci_irq(int irq_num, void *data)
			base + CCI_HALT_REQ_ADDR);
		CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq_status0);
	}

	if ((rd_done_th_assert) || (!cci_dev->is_burst_read)) {
		cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR);
		CAM_DBG(CAM_CCI, "clear irq_status0:%x irq_status1:%x",
			irq_status0, irq_status1);
	} else {
		spin_lock_irqsave(&cci_dev->lock_status, flags);
		cci_dev->irq_status1 |= irq_status1;
		spin_unlock_irqrestore(&cci_dev->lock_status, flags);
	}

	cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR);
	cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
	return IRQ_HANDLED;
}

+9 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct cam_cci_master_info {
	uint8_t reset_pending;
	struct mutex mutex;
	struct completion reset_complete;
	struct completion th_complete;
	struct mutex mutex_q[NUM_QUEUES];
	struct completion report_q[NUM_QUEUES];
	atomic_t done_pending[NUM_QUEUES];
@@ -192,6 +193,11 @@ enum cam_cci_state_t {
 * @cci_wait_sync_cfg: CCI sync config
 * @cycles_per_us: Cycles per micro sec
 * @payload_size: CCI packet payload size
 * @irq_status1: Store irq_status1 to be cleared after
 *               draining FIFO buffer for burst read
 * @lock_status: to protect changes to irq_status1
 * @is_burst_read: Flag to determine if we are performing
 *                 a burst read operation or not
 */
struct cci_device {
	struct v4l2_subdev subdev;
@@ -216,6 +222,9 @@ struct cci_device {
	uint8_t payload_size;
	char device_name[20];
	uint32_t cpas_handle;
	uint32_t irq_status1;
	spinlock_t lock_status;
	bool is_burst_read;
};

enum cam_cci_i2c_cmd_type {
+3 −1
Original line number Diff line number Diff line
@@ -56,15 +56,17 @@
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK                         0x10000
#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK                            0x1000
#define CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD                          0x100000
#define CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE                              0x200000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK                           0x100
#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_RD_DONE_BMSK                               0x1
#define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD                           0x10000
#define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE                               0x20000
#define CCI_I2C_M0_RD_THRESHOLD_ADDR                                0x00000120
#define CCI_I2C_M1_RD_THRESHOLD_ADDR                                0x00000220
#define CCI_I2C_RD_THRESHOLD_VALUE                                        0x38
#define CCI_I2C_RD_THRESHOLD_VALUE                                        0x30
#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR                               0x00000c00

#define DEBUG_TOP_REG_START                                                0x0
+3 −0
Original line number Diff line number Diff line
@@ -199,6 +199,8 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev)
		mutex_init(&new_cci_dev->cci_master_info[i].mutex);
		init_completion(
			&new_cci_dev->cci_master_info[i].reset_complete);
		init_completion(
			&new_cci_dev->cci_master_info[i].th_complete);

		for (j = 0; j < NUM_QUEUES; j++) {
			mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
@@ -208,6 +210,7 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev)
				&new_cci_dev->cci_master_info[i].lock_q[j]);
		}
	}
	spin_lock_init(&new_cci_dev->lock_status);
}

static void cam_cci_init_default_clk_params(struct cci_device *cci_dev,