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

Commit cf79a54c authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: add support for bus overflow recovery"

parents 0fbbc140 9d1a75e4
Loading
Loading
Loading
Loading
+75 −7
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)

static struct msm_isp_bufq *msm_isp_get_bufq(
struct msm_isp_bufq *msm_isp_get_bufq(
	struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle)
{
@@ -497,6 +497,11 @@ static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr,
		return rc;
	}


	buf_info->buf_get_count = 0;
	buf_info->buf_put_count = 0;
	memset(buf_info->buf_used, 0, sizeof(buf_info->buf_used));

	spin_lock_irqsave(&bufq->bufq_lock, flags);
	switch (buf_info->state) {
	case MSM_ISP_BUFFER_STATE_PREPARED:
@@ -529,6 +534,53 @@ static int msm_isp_put_buf(struct msm_isp_buf_mgr *buf_mgr,
	return rc;
}

static int msm_isp_put_buf_unsafe(struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle, uint32_t buf_index)
{
	int rc = -1;
	struct msm_isp_bufq *bufq = NULL;
	struct msm_isp_buffer *buf_info = NULL;

	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
	if (!bufq) {
		pr_err("%s: Invalid bufq\n", __func__);
		return rc;
	}

	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
	if (!buf_info) {
		pr_err("%s: buf not found\n", __func__);
		return rc;
	}

	switch (buf_info->state) {
	case MSM_ISP_BUFFER_STATE_PREPARED:
	case MSM_ISP_BUFFER_STATE_DEQUEUED:
	case MSM_ISP_BUFFER_STATE_DIVERTED:
		if (BUF_SRC(bufq->stream_id))
			list_add_tail(&buf_info->list, &bufq->head);
		else
			buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf,
				bufq->session_id, bufq->stream_id);
		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
		rc = 0;
		break;
	case MSM_ISP_BUFFER_STATE_DISPATCHED:
		buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
		rc = 0;
		break;
	case MSM_ISP_BUFFER_STATE_QUEUED:
		rc = 0;
		break;
	default:
		pr_err("%s: incorrect state = %d",
			__func__, buf_info->state);
		break;
	}

	return rc;
}

static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle, uint32_t buf_index,
	struct timeval *tv, uint32_t frame_id, uint32_t output_format)
@@ -607,19 +659,34 @@ static int msm_isp_flush_buf(struct msm_isp_buf_mgr *buf_mgr,
			pr_err("%s: buf not found\n", __func__);
			continue;
		}

		spin_lock_irqsave(&bufq->bufq_lock, flags);
		if (flush_type == MSM_ISP_BUFFER_FLUSH_DIVERTED &&
			buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) {
			buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
		} else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL &&
			(buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
			buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED ||
			buf_info->state == MSM_ISP_BUFFER_STATE_DISPATCHED)) {
			buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
		} else if (flush_type == MSM_ISP_BUFFER_FLUSH_ALL) {
			if (buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED) {
				CDBG("%s: no need to queue Diverted buffer\n",
					__func__);
			} else if (buf_info->state ==
				MSM_ISP_BUFFER_STATE_DEQUEUED) {
				if (buf_info->buf_get_count ==
					ISP_SHARE_BUF_CLIENT) {
					msm_isp_put_buf_unsafe(buf_mgr,
						bufq_handle, buf_info->buf_idx);
				} else {
					buf_info->state =
						MSM_ISP_BUFFER_STATE_DEQUEUED;
					buf_info->buf_get_count = 0;
					buf_info->buf_put_count = 0;
					memset(buf_info->buf_used, 0,
						sizeof(uint8_t) * 2);
				}
			}
		}

		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
	}

	return 0;
}

@@ -1079,6 +1146,7 @@ static struct msm_isp_buf_ops isp_buf_ops = {
	.buf_mgr_init = msm_isp_init_isp_buf_mgr,
	.buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr,
	.buf_mgr_debug = msm_isp_buf_mgr_debug,
	.get_bufq = msm_isp_get_bufq,
};

int msm_isp_create_isp_buf_mgr(
+2 −0
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ struct msm_isp_buf_ops {
		const char *ctx_name, uint16_t num_buf_q);
	int (*buf_mgr_deinit) (struct msm_isp_buf_mgr *buf_mgr);
	int (*buf_mgr_debug) (struct msm_isp_buf_mgr *buf_mgr);
	struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr,
		uint32_t bufq_handle);
};

struct msm_isp_buf_mgr {
+27 −2
Original line number Diff line number Diff line
@@ -154,12 +154,15 @@ struct msm_vfe_axi_ops {
	uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1);
	uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1);
	uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev);
	long (*halt) (struct vfe_device *vfe_dev);
	int (*halt) (struct vfe_device *vfe_dev, uint32_t blocking);
	int (*restart) (struct vfe_device *vfe_dev, uint32_t blocking,
		uint32_t enable_camif);
};

struct msm_vfe_core_ops {
	void (*reg_update) (struct vfe_device *vfe_dev);
	long (*reset_hw) (struct vfe_device *vfe_dev);
	long (*reset_hw) (struct vfe_device *vfe_dev, uint32_t first_start,
		uint32_t blocking_call);
	int (*init_hw) (struct vfe_device *vfe_dev);
	void (*init_hw_reg) (struct vfe_device *vfe_dev);
	void (*release_hw) (struct vfe_device *vfe_dev);
@@ -173,6 +176,14 @@ struct msm_vfe_core_ops {
	int (*get_platform_data) (struct vfe_device *vfe_dev);
	void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1);
	void (*process_error_status) (struct vfe_device *vfe_dev);
	void (*get_overflow_mask) (uint32_t *overflow_mask);
	void (*get_irq_mask) (struct vfe_device *vfe_dev,
		uint32_t *irq0_mask, uint32_t *irq1_mask);
	void (*restore_irq_mask) (struct vfe_device *vfe_dev);
	void (*get_halt_restart_mask) (uint32_t *irq0_mask,
		uint32_t *irq1_mask);
	void (*get_rdi_wm_mask)(struct vfe_device *vfe_dev,
		uint32_t *rdi_wm_mask);
};
struct msm_vfe_stats_ops {
	int (*get_stats_idx) (enum msm_isp_stats_type stats_type);
@@ -290,6 +301,7 @@ struct msm_vfe_axi_stream {
	enum msm_vfe_axi_stream_type stream_type;
	uint32_t vt_enable;
	uint32_t frame_based;
	enum msm_vfe_frame_skip_pattern frame_skip_pattern;
	uint32_t framedrop_period;
	uint32_t framedrop_pattern;
	uint32_t num_burst_capture;/*number of frame to capture*/
@@ -343,6 +355,9 @@ struct msm_vfe_axi_shared_data {
	enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
	uint8_t num_used_wm;
	uint8_t num_active_stream;
	uint8_t num_rdi_stream;
	uint8_t num_pix_stream;
	uint32_t rdi_wm_mask;
	struct msm_vfe_axi_composite_info
		composite_info[MAX_NUM_COMPOSITE_MASK];
	uint8_t num_used_composite_mask;
@@ -406,7 +421,17 @@ struct msm_vfe_tasklet_queue_cmd {

#define MSM_VFE_TASKLETQ_SIZE 200

enum msm_vfe_overflow_state {
	NO_OVERFLOW,
	OVERFLOW_DETECTED,
	HALT_REQUESTED,
	RESTART_REQUESTED,
};

struct msm_vfe_error_info {
	atomic_t overflow_state;
	uint32_t overflow_recover_irq_mask0;
	uint32_t overflow_recover_irq_mask1;
	uint32_t error_mask0;
	uint32_t error_mask1;
	uint32_t violation_status;
+3 −7
Original line number Diff line number Diff line
@@ -410,7 +410,8 @@ static void msm_vfe32_reg_update(
	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
}

static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev)
static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev,
	uint32_t first_start, uint32_t blocking)
{
	init_completion(&vfe_dev->reset_complete);
	msm_camera_io_w_mb(0x3FF, vfe_dev->vfe_base + 0x4);
@@ -676,13 +677,8 @@ static void msm_vfe32_update_camif_state(
		msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
		vfe_dev->ignore_error = 1;
		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0);
		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
		vfe_dev->ignore_error = 0;
	}
}

@@ -907,7 +903,7 @@ static void msm_vfe32_update_ping_pong_addr(struct vfe_device *vfe_dev,
		VFE32_PING_PONG_BASE(wm_idx, pingpong_status));
}

static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev)
static int msm_vfe32_axi_halt(struct vfe_device *vfe_dev, uint32_t blocking)
{
	uint32_t halt_mask;
	uint32_t axi_busy_flag = true;
+113 −17
Original line number Diff line number Diff line
@@ -404,8 +404,10 @@ static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev,
static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev,
	uint32_t irq_status0, uint32_t irq_status1)
{
	if (irq_status1 & (1 << 8))
	if (irq_status1 & (1 << 8)) {
		complete(&vfe_dev->halt_complete);
		msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
	}
}

static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev,
@@ -655,13 +657,30 @@ static void msm_vfe40_reg_update(struct vfe_device *vfe_dev)
	msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378);
}

static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev)
static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev,
	uint32_t first_start, uint32_t blocking_call)
{
	long rc = 0;
	init_completion(&vfe_dev->reset_complete);

	if (first_start) {
		msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0xC);
	return wait_for_completion_timeout(
	} else {
		msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC);
		msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
		msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
		msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
		vfe_dev->hw_info->vfe_ops.axi_ops.
			reload_wm(vfe_dev, 0x0003FFFF);
	}


	if (blocking_call) {
		rc = wait_for_completion_interruptible_timeout(
			&vfe_dev->reset_complete, msecs_to_jiffies(50));
	}
	return rc;
}

static void msm_vfe40_axi_reload_wm(
	struct vfe_device *vfe_dev, uint32_t reload_mask)
@@ -953,19 +972,15 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev,
		val &= 0xFFFFFF3F;
		val = val | bus_en << 7 | vfe_en << 6;
		msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
		msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4);
		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4);
		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
	} else if (update_state == DISABLE_CAMIF) {
		msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4);
		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
		vfe_dev->ignore_error = 1;
		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4);
		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
		vfe_dev->ignore_error = 0;
	}
}

@@ -1219,17 +1234,56 @@ static void msm_vfe40_update_ping_pong_addr(
		VFE40_PING_PONG_BASE(wm_idx, pingpong_status));
}

static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev)
static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev,
	uint32_t blocking)
{
	uint32_t halt_mask;
	halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
	halt_mask |= (1 << 8);
	msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x2C);
	int rc = 0;

	/* Keep only halt and restart mask */
	msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28);
	msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C);
	/*Clear IRQ Status */
	msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
	msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
	msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);
	/* if any stream is waiting for update, signal complete */
	if (vfe_dev->axi_data.stream_update) {
		pr_err("%s: calling complete on stream update\n", __func__);
		complete(&vfe_dev->stream_config_complete);
	}
	/* Halt AXI Bus Bridge */
	init_completion(&vfe_dev->halt_complete);
	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
	return wait_for_completion_interruptible_timeout(
	if (blocking) {
		rc = wait_for_completion_interruptible_timeout(
			&vfe_dev->halt_complete, msecs_to_jiffies(500));
	}
	return rc;
}

static int msm_vfe40_axi_restart(struct vfe_device *vfe_dev,
	uint32_t blocking, uint32_t enable_camif)
{
	vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev);
	/* Clear IRQ Status */
	msm_camera_io_w(0x7FFFFFFF, vfe_dev->vfe_base + 0x30);
	msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34);
	msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24);

	/* Start AXI */
	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);

	vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
	memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
	atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);

	if (enable_camif) {
		vfe_dev->hw_info->vfe_ops.core_ops.
		update_camif_state(vfe_dev, ENABLE_CAMIF);
	}

	return 0;
}

static uint32_t msm_vfe40_get_wm_mask(
	uint32_t irq_status0, uint32_t irq_status1)
@@ -1550,6 +1604,41 @@ static void msm_vfe40_get_error_mask(
	*error_mask1 = 0x00FFFEFF;
}

static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask)
{
	*overflow_mask = 0x00FFFE7E;
}

static void msm_vfe40_get_rdi_wm_mask(struct vfe_device *vfe_dev,
	uint32_t *rdi_wm_mask)
{
	*rdi_wm_mask = vfe_dev->axi_data.rdi_wm_mask;
}

static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev,
	uint32_t *irq0_mask, uint32_t *irq1_mask)
{
	*irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
	*irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
}


static void msm_vfe40_restore_irq_mask(struct vfe_device *vfe_dev)
{
	msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0,
		vfe_dev->vfe_base + 0x28);
	msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1,
		vfe_dev->vfe_base + 0x2C);
}


static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask,
	uint32_t *irq1_mask)
{
	*irq0_mask = BIT(31);
	*irq1_mask = BIT(8);
}

static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
	.num_wm = 7,
	.num_comp_mask = 3,
@@ -1620,6 +1709,7 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
			.get_wm_mask = msm_vfe40_get_wm_mask,
			.get_pingpong_status = msm_vfe40_get_pingpong_status,
			.halt = msm_vfe40_axi_halt,
			.restart = msm_vfe40_axi_restart,
		},
		.core_ops = {
			.reg_update = msm_vfe40_reg_update,
@@ -1632,6 +1722,12 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
			.release_hw = msm_vfe40_release_hardware,
			.get_platform_data = msm_vfe40_get_platform_data,
			.get_error_mask = msm_vfe40_get_error_mask,
			.get_overflow_mask = msm_vfe40_get_overflow_mask,
			.get_rdi_wm_mask = msm_vfe40_get_rdi_wm_mask,
			.get_irq_mask = msm_vfe40_get_irq_mask,
			.restore_irq_mask = msm_vfe40_restore_irq_mask,
			.get_halt_restart_mask =
				msm_vfe40_get_halt_restart_mask,
			.process_error_status = msm_vfe40_process_error_status,
		},
		.stats_ops = {
Loading