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

Commit 18dab37e authored by Senthil kumar Rajagopal's avatar Senthil kumar Rajagopal Committed by Matt Wagantall
Browse files

msm: camera: isp: Fix for CAMIF error



While changing resolution, ISPIF and ISP hardware need to be reset
to work properly. In the reset hw logic, Some clocks and registers
are not reset properly, This causes some IRQ interruots triggered
whenever changing resolution.

This change fix the Epoch registers with correct line numbers
during reset and reset clock is called during close node.

Change-Id: Iec3522daa0ad662dd535729f2765c3eed615f053
Signed-off-by: default avatarHarsh Shah <harshs@codeaurora.org>
parent a89036af
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -250,6 +250,8 @@ static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev)
	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x2C);
	msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
	msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);

}

static void msm_vfe44_clear_status_reg(struct vfe_device *vfe_dev)
@@ -368,9 +370,11 @@ static void msm_vfe44_process_violation_status(
static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev)
{
	uint32_t error_status1 = vfe_dev->error_info.error_mask1;
	if (error_status1 & (1 << 0))
	if (error_status1 & (1 << 0)) {
		pr_err("%s: camif error status: 0x%x\n",
			__func__, vfe_dev->error_info.camif_status);
		msm_camera_io_dump_2(vfe_dev->vfe_base + 0x2f4, 0x30);
	}
	if (error_status1 & (1 << 1))
		pr_err("%s: stats bhist overwrite\n", __func__);
	if (error_status1 & (1 << 2))
@@ -456,11 +460,18 @@ static void msm_vfe44_process_error_status(struct vfe_device *vfe_dev)
static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
	uint32_t *irq_status0, uint32_t *irq_status1)
{
	uint32_t irq_mask0 = 0, irq_mask1 = 0;
	irq_mask0 = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
	irq_mask1 = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);

	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);

	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
	*irq_status0 &= irq_mask0;
	*irq_status1 &= irq_mask1;
	if (*irq_status0 & 0x10000000) {
		pr_err_ratelimited("%s: Protection triggered\n", __func__);
		*irq_status0 &= ~(0x10000000);
@@ -1044,9 +1055,14 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev,
		return;

	if (update_state == ENABLE_CAMIF) {
		msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
		msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
		msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);

		val = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
		val |= 0xF5;
		val |= 0xF7;
		msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28);
		msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);

		bus_en =
			((vfe_dev->axi_data.
@@ -1060,7 +1076,7 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev,
		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);
		msm_camera_io_w_mb(0x200, vfe_dev->vfe_base + 0x318);

		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);
@@ -1363,6 +1379,7 @@ static int msm_vfe44_axi_restart(struct vfe_device *vfe_dev,
	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);
	msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);

	/* Start AXI */
	msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0);
+81 −78
Original line number Diff line number Diff line
@@ -52,6 +52,11 @@
#define CDBG(fmt, args...) do { } while (0)
#endif

int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
	struct platform_device *pdev,
	struct msm_cam_clk_info *ahb_clk_info,
	struct msm_cam_clk_info *clk_info);

static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
{
	if (!ispif->enb_dump_reg)
@@ -86,45 +91,29 @@ static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = {
	{"camss_csi_vfe_clk", NO_SET_RATE},
};

static struct msm_cam_clk_info ispif_8974_ahb_clk_info[ISPIF_CLK_INFO_MAX];

static struct msm_cam_clk_info ispif_8974_reset_clk_info[] = {
	{"csi0_src_clk", INIT_RATE},
	{"csi0_clk", NO_SET_RATE},
	{"csi0_pix_clk", NO_SET_RATE},
	{"csi0_rdi_clk", NO_SET_RATE},
	{"csi1_src_clk", INIT_RATE},
	{"csi1_clk", NO_SET_RATE},
	{"csi1_pix_clk", NO_SET_RATE},
	{"csi1_rdi_clk", NO_SET_RATE},
	{"csi2_src_clk", INIT_RATE},
	{"csi2_clk", NO_SET_RATE},
	{"csi2_pix_clk", NO_SET_RATE},
	{"csi2_rdi_clk", NO_SET_RATE},
	{"csi3_src_clk", INIT_RATE},
	{"csi3_clk", NO_SET_RATE},
	{"csi3_pix_clk", NO_SET_RATE},
	{"csi3_rdi_clk", NO_SET_RATE},
	{"vfe0_clk_src", INIT_RATE},
	{"camss_vfe_vfe0_clk", NO_SET_RATE},
	{"camss_csi_vfe0_clk", NO_SET_RATE},
	{"vfe1_clk_src", INIT_RATE},
	{"camss_vfe_vfe1_clk", NO_SET_RATE},
	{"camss_csi_vfe1_clk", NO_SET_RATE},
};
static struct msm_cam_clk_info ispif_ahb_clk_info[ISPIF_CLK_INFO_MAX];
static struct msm_cam_clk_info ispif_clk_info[ISPIF_CLK_INFO_MAX];

static int msm_ispif_reset_hw(struct ispif_device *ispif)
{
	int rc = 0;
	long timeout = 0;
	struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];
	struct clk *reset_clk1[ARRAY_SIZE(ispif_8626_reset_clk_info)];
	ispif->clk_idx = 0;

	rc = msm_ispif_get_clk_info(ispif, ispif->pdev,
		ispif_ahb_clk_info, ispif_clk_info);
	if (rc < 0) {
		pr_err("%s: msm_isp_get_clk_info() failed", __func__);
			return -EFAULT;
	}

	rc = msm_cam_clk_enable(&ispif->pdev->dev,
		ispif_8974_reset_clk_info, reset_clk,
		ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
		ispif_clk_info, ispif->clk,
		ispif->num_clk, 1);
	if (rc < 0) {
		pr_err("%s: cannot enable clock, error = %d\n",
			__func__, rc);
		rc = msm_cam_clk_enable(&ispif->pdev->dev,
			ispif_8626_reset_clk_info, reset_clk1,
			ARRAY_SIZE(ispif_8626_reset_clk_info), 1);
@@ -147,9 +136,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
	/* initiate reset of ISPIF */
	msm_camera_io_w(ISPIF_RST_CMD_MASK,
				ispif->base + ISPIF_RST_CMD_ADDR);
	if (ispif->hw_num_isps > 1)
		msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
					ispif->base + ISPIF_RST_CMD_1_ADDR);


	timeout = wait_for_completion_timeout(
			&ispif->reset_complete[VFE0], msecs_to_jiffies(500));
@@ -158,8 +145,8 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
	if (timeout <= 0) {
		pr_err("%s: VFE0 reset wait timeout\n", __func__);
		rc = msm_cam_clk_enable(&ispif->pdev->dev,
			ispif_8974_reset_clk_info, reset_clk,
			ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
			ispif_clk_info, ispif->clk,
			ispif->num_clk, 0);
		if (rc < 0) {
			rc = msm_cam_clk_enable(&ispif->pdev->dev,
				ispif_8626_reset_clk_info, reset_clk1,
@@ -172,23 +159,25 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
	}

	if (ispif->hw_num_isps > 1) {
		msm_camera_io_w(ISPIF_RST_CMD_1_MASK,
					ispif->base + ISPIF_RST_CMD_1_ADDR);
		timeout = wait_for_completion_timeout(
				&ispif->reset_complete[VFE1],
				msecs_to_jiffies(500));
		CDBG("%s: VFE1 done\n", __func__);
		if (timeout <= 0) {
			pr_err("%s: VFE1 reset wait timeout\n", __func__);
			msm_cam_clk_enable(&ispif->pdev->dev,
				ispif_8974_reset_clk_info, reset_clk,
				ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
		rc = msm_cam_clk_enable(&ispif->pdev->dev,
			ispif_clk_info, ispif->clk,
			ispif->num_clk, 0);
			return -ETIMEDOUT;
		}
	}

	if (ispif->clk_idx == 1) {
		rc = msm_cam_clk_enable(&ispif->pdev->dev,
			ispif_8974_reset_clk_info, reset_clk,
			ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
			ispif_clk_info, ispif->clk,
			ispif->num_clk, 0);
		if (rc < 0) {
			pr_err("%s: cannot disable clock, error = %d",
				__func__, rc);
@@ -208,13 +197,14 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
	return rc;
}

int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev,
int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
	struct platform_device *pdev,
	struct msm_cam_clk_info *ahb_clk_info)
	struct msm_cam_clk_info *ahb_clk_info,
	struct msm_cam_clk_info *clk_info)
{
	uint32_t count, num_ahb_clk = 0;
	const char *rate = NULL;
	int i, rc;
	uint32_t rates[ISPIF_CLK_INFO_MAX];

	struct device_node *of_node;
	of_node = pdev->dev.of_node;
@@ -233,31 +223,47 @@ int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev,
		return -EINVAL;
	}

	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
		rates, count);
	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(clk_info[i].clk_name));
		if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
			pr_err("%s reading clock-name failed index %d\n",
				__func__, i);
			return rc;
		}
	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(ahb_clk_info[num_ahb_clk].clk_name));
		CDBG("clock-names[%d] = %s\n",
			 i, ahb_clk_info[i].clk_name);

		rc = of_property_read_string_index(of_node, "qcom,clock-rates",
			i, &rate);
		CDBG("clock-names[%d] = %s, clk_rate = %s\n",
			i, clk_info[i].clk_name, rate);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			pr_err("%s reading clock-rate failed index %d\n",
				__func__, i);
			return rc;
		}
		if (strnstr(ahb_clk_info[num_ahb_clk].clk_name, "ahb",
			sizeof(ahb_clk_info[num_ahb_clk].clk_name))) {

		if (!strcmp(rate, "-1") || !strcmp(rate, "0"))
			clk_info[i].clk_rate = NO_SET_RATE;
		else if (!strcmp(rate, "-2"))
			clk_info[i].clk_rate = INIT_RATE;
		else
			rc = kstrtol(rate, 10, &clk_info[i].clk_rate);

		if (strnstr(clk_info[i].clk_name, "ahb",
			strlen(clk_info[i].clk_name))) {
			ahb_clk_info[num_ahb_clk].clk_name =
				clk_info[i].clk_name;
			ahb_clk_info[num_ahb_clk].clk_rate =
				(rates[i] == 0) ? (long)-1 : rates[i];
			CDBG("clk_rate[%d] = %ld\n", i,
				ahb_clk_info[i].clk_rate);
				clk_info[i].clk_rate;
			CDBG("clk_name[%d]= %s, clk_rate = %ld\n",
				num_ahb_clk, ahb_clk_info[num_ahb_clk].clk_name,
				ahb_clk_info[num_ahb_clk].clk_rate);
			num_ahb_clk++;
		}
	}
	CDBG("%s: num_ahb_clk %d num_clk %d\n", __func__, num_ahb_clk, count);
	ispif_dev->num_ahb_clk = num_ahb_clk;
	ispif_dev->num_clk = count;
	return 0;
}

@@ -270,15 +276,8 @@ static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable)
		return 0;
	}

	rc = msm_ispif_get_ahb_clk_info(ispif, ispif->pdev,
		ispif_8974_ahb_clk_info);
	if (rc < 0) {
		pr_err("%s: msm_isp_get_clk_info() failed", __func__);
			return -EFAULT;
	}

	rc = msm_cam_clk_enable(&ispif->pdev->dev,
		ispif_8974_ahb_clk_info, ispif->ahb_clk,
		ispif_ahb_clk_info, ispif->ahb_clk,
		ispif->num_ahb_clk, enable);
	if (rc < 0) {
		pr_err("%s: cannot enable clock, error = %d",
@@ -778,7 +777,6 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
		rc = -EINVAL;
		return rc;
	}

	msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);

	return rc;
@@ -794,7 +792,6 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
	enum msm_ispif_vfe_intf vfe_intf;
	uint32_t vfe_mask = 0;
	uint32_t intf_addr;
	struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];

	if (ispif->ispif_state != ISPIF_POWER_UP) {
		pr_err("%s: ispif invalid state %d\n", __func__,
@@ -820,8 +817,8 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
	}

	rc = msm_cam_clk_enable(&ispif->pdev->dev,
		ispif_8974_reset_clk_info, reset_clk,
		ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
		ispif_clk_info, ispif->clk,
		ispif->num_clk, 1);
	if (rc < 0) {
		pr_err("%s: cannot enable clock, error = %d",
			__func__, rc);
@@ -865,8 +862,8 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,

	pr_info("%s: ISPIF reset hw done", __func__);
	rc = msm_cam_clk_enable(&ispif->pdev->dev,
		ispif_8974_reset_clk_info, reset_clk,
		ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
		ispif_clk_info, ispif->clk,
		ispif->num_clk, 0);
	if (rc < 0) {
		pr_err("%s: cannot enable clock, error = %d",
			__func__, rc);
@@ -922,8 +919,8 @@ end:
	return rc;
disable_clk:
	rc = msm_cam_clk_enable(&ispif->pdev->dev,
		ispif_8974_reset_clk_info, reset_clk,
		ARRAY_SIZE(ispif_8974_reset_clk_info), 0);
		ispif_clk_info, ispif->clk,
		ispif->num_clk, 0);
	if (rc < 0) {
		pr_err("%s: cannot enable clock, error = %d",
		__func__, rc);
@@ -1188,14 +1185,14 @@ static int msm_ispif_init(struct ispif_device *ispif,
		goto error_irq;
	}

	msm_ispif_reset_hw(ispif);

	rc = msm_ispif_clk_ahb_enable(ispif, 1);
	if (rc) {
		pr_err("%s: ahb_clk enable failed", __func__);
		goto error_ahb;
	}

	msm_ispif_reset_hw(ispif);

	rc = msm_ispif_reset(ispif);
	if (rc == 0) {
		ispif->ispif_state = ISPIF_POWER_UP;
@@ -1229,7 +1226,7 @@ static void msm_ispif_release(struct ispif_device *ispif)

	/* make sure no streaming going on */
	msm_ispif_reset(ispif);

	msm_ispif_reset_hw(ispif);
	msm_ispif_clk_ahb_enable(ispif, 0);

	free_irq(ispif->irq->start, ispif);
@@ -1239,6 +1236,7 @@ static void msm_ispif_release(struct ispif_device *ispif)
	iounmap(ispif->clk_mux_base);

	ispif->ispif_state = ISPIF_POWER_DOWN;

}

static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
@@ -1334,7 +1332,6 @@ static long msm_ispif_subdev_fops_ioctl(struct file *file, unsigned int cmd,
static int ispif_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct ispif_device *ispif = v4l2_get_subdevdata(sd);

	mutex_lock(&ispif->mutex);
	/* mem remap is done in init when the clock is on */
	ispif->open_cnt++;
@@ -1346,7 +1343,6 @@ static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	int rc = 0;
	struct ispif_device *ispif = v4l2_get_subdevdata(sd);

	if (!ispif) {
		pr_err("%s: invalid input\n", __func__);
		return -EINVAL;
@@ -1402,6 +1398,13 @@ static int ispif_probe(struct platform_device *pdev)
		rc = 0;
	}

	rc = msm_ispif_get_clk_info(ispif, pdev,
		ispif_ahb_clk_info, ispif_clk_info);
	if (rc < 0) {
		pr_err("%s: msm_isp_get_clk_info() failed", __func__);
			return -EFAULT;
	}

	mutex_init(&ispif->mutex);
	ispif->mem = platform_get_resource_byname(pdev,
		IORESOURCE_MEM, "ispif");
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -60,9 +60,11 @@ struct ispif_device {
	enum msm_ispif_state_t ispif_state;
	struct msm_ispif_vfe_info vfe_info;
	struct clk *ahb_clk[ISPIF_CLK_INFO_MAX];
	struct clk *clk[ISPIF_CLK_INFO_MAX];
	struct completion reset_complete[VFE_MAX];
	uint32_t hw_num_isps;
	uint32_t num_ahb_clk;
	uint32_t num_clk;
	uint32_t clk_idx;
};
#endif