[v5,09/22] media: camss: Refactor CSID HW version support

Message ID 20210217112122.424236-10-robert.foss@linaro.org
State New
Headers show
Series
  • Add support for the SDM845 Camera Subsystem
Related show

Commit Message

Robert Foss Feb. 17, 2021, 11:21 a.m.
In order to support Qualcomm ISP hardware architectures that diverge
from older architectures, the CSID subdevice drivers needs to be refactored
to better abstract the different ISP hardware architectures.

Signed-off-by: Robert Foss <robert.foss@linaro.org>

---

Changes since v1
 - kernel test robot: Add missing include, interrupt.h

Changes since v4
 - Andrey: Removed whitespace from some includes
 - Andrey: Removed unused enum


 drivers/media/platform/qcom/camss/Makefile    |   2 +
 .../platform/qcom/camss/camss-csid-4-1.c      | 330 ++++++++++
 .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++
 .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------
 .../media/platform/qcom/camss/camss-csid.h    | 126 +++-
 5 files changed, 890 insertions(+), 590 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

-- 
2.27.0

Comments

Andrey Konovalov Feb. 21, 2021, 3:15 p.m. | #1
Hi Robert,

Thank you for your patch!

Reviewed-by: Andrey Konovalov <andrey.konovalov@linaro.org>


Thanks,
Andrey

On 17.02.2021 14:21, Robert Foss wrote:
> In order to support Qualcomm ISP hardware architectures that diverge

> from older architectures, the CSID subdevice drivers needs to be refactored

> to better abstract the different ISP hardware architectures.

> 

> Signed-off-by: Robert Foss <robert.foss@linaro.org>

> ---

> 

> Changes since v1

>   - kernel test robot: Add missing include, interrupt.h

> 

> Changes since v4

>   - Andrey: Removed whitespace from some includes

>   - Andrey: Removed unused enum

> 

> 

>   drivers/media/platform/qcom/camss/Makefile    |   2 +

>   .../platform/qcom/camss/camss-csid-4-1.c      | 330 ++++++++++

>   .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++

>   .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------

>   .../media/platform/qcom/camss/camss-csid.h    | 126 +++-

>   5 files changed, 890 insertions(+), 590 deletions(-)

>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c

>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

> 

> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile

> index 052c4f405fa3..cff388b653ba 100644

> --- a/drivers/media/platform/qcom/camss/Makefile

> +++ b/drivers/media/platform/qcom/camss/Makefile

> @@ -4,6 +4,8 @@

>   qcom-camss-objs += \

>   		camss.o \

>   		camss-csid.o \

> +		camss-csid-4-1.o \

> +		camss-csid-4-7.o \

>   		camss-csiphy-2ph-1-0.o \

>   		camss-csiphy-3ph-1-0.o \

>   		camss-csiphy.o \

> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

> new file mode 100644

> index 000000000000..c92077a7f758

> --- /dev/null

> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

> @@ -0,0 +1,330 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * camss-csid-4-1.c

> + *

> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

> + *

> + * Copyright (C) 2020 Linaro Ltd.

> + */

> +

> +#include <linux/completion.h>

> +#include <linux/interrupt.h>

> +#include <linux/io.h>

> +#include <linux/kernel.h>

> +#include <linux/of.h>

> +

> +#include "camss-csid.h"

> +#include "camss.h"

> +

> +#define CAMSS_CSID_HW_VERSION		0x0

> +#define CAMSS_CSID_CORE_CTRL_0		0x004

> +#define CAMSS_CSID_CORE_CTRL_1		0x008

> +#define CAMSS_CSID_RST_CMD		0x00c

> +#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x010 + 0x4 * (n))

> +#define CAMSS_CSID_CID_n_CFG(n)		(0x020 + 0x4 * (n))

> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)

> +#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)

> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)

> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)

> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)

> +#define CAMSS_CSID_IRQ_CLEAR_CMD	0x060

> +#define CAMSS_CSID_IRQ_MASK		0x064

> +#define CAMSS_CSID_IRQ_STATUS		0x068

> +#define CAMSS_CSID_TG_CTRL		0x0a0

> +#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436

> +#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437

> +#define CAMSS_CSID_TG_VC_CFG		0x0a4

> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff

> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f

> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0ac + 0xc * (n))

> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b0 + 0xc * (n))

> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0b4 + 0xc * (n))

> +

> +

> +static const struct csid_format csid_formats[] = {

> +	{

> +		MEDIA_BUS_FMT_UYVY8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_VYUY8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_YUYV8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_YVYU8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_Y10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +};

> +

> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

> +{

> +	struct csid_testgen_config *tg = &csid->testgen;

> +	u32 val;

> +

> +	if (enable) {

> +		struct v4l2_mbus_framefmt *input_format;

> +		const struct csid_format *format;

> +		u8 vc = 0; /* Virtual Channel 0 */

> +		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> +		u8 dt_shift;

> +

> +		if (tg->enabled) {

> +			/* Config Test Generator */

> +			u32 num_lines, num_bytes_per_line;

> +

> +			input_format = &csid->fmt[MSM_CSID_PAD_SRC];

> +			format = csid_get_fmt_entry(csid->formats, csid->nformats,

> +						    input_format->code);

> +			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

> +			num_lines = input_format->height;

> +

> +			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> +			/* 1:0 VC */

> +			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> +				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

> +

> +			/* 28:16 bytes per lines, 12:0 num of lines */

> +			val = ((num_bytes_per_line & 0x1fff) << 16) |

> +				  (num_lines & 0x1fff);

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

> +

> +			/* 5:0 data type */

> +			val = format->data_type;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

> +

> +			/* 2:0 output test pattern */

> +			val = tg->mode;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

> +		} else {

> +			struct csid_phy_config *phy = &csid->phy;

> +

> +			input_format = &csid->fmt[MSM_CSID_PAD_SINK];

> +			format = csid_get_fmt_entry(csid->formats, csid->nformats,

> +						    input_format->code);

> +

> +			val = phy->lane_cnt - 1;

> +			val |= phy->lane_assign << 4;

> +

> +			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

> +

> +			val = phy->csiphy_id << 17;

> +			val |= 0x9;

> +

> +			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

> +		}

> +

> +		/* Config LUT */

> +

> +		dt_shift = (cid % 4) * 8;

> +		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> +		val &= ~(0xff << dt_shift);

> +		val |= format->data_type << dt_shift;

> +		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> +

> +		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> +		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> +		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> +		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> +		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

> +

> +		if (tg->enabled) {

> +			val = CAMSS_CSID_TG_CTRL_ENABLE;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> +		}

> +	} else {

> +		if (tg->enabled) {

> +			val = CAMSS_CSID_TG_CTRL_DISABLE;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> +		}

> +	}

> +}

> +

> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

> +{

> +	s32 regval = val - 1;

> +

> +	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)

> +		csid->testgen.mode = regval;

> +

> +	return 0;

> +}

> +

> +static u32 csid_hw_version(struct csid_device *csid)

> +{

> +	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> +

> +	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

> +

> +	return hw_version;

> +}

> +

> +static irqreturn_t csid_isr(int irq, void *dev)

> +{

> +	struct csid_device *csid = dev;

> +	u32 value;

> +

> +	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

> +	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

> +

> +	if ((value >> 11) & 0x1)

> +		complete(&csid->reset_complete);

> +

> +	return IRQ_HANDLED;

> +}

> +

> +static int csid_reset(struct csid_device *csid)

> +{

> +	unsigned long time;

> +

> +	reinit_completion(&csid->reset_complete);

> +

> +	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

> +

> +	time = wait_for_completion_timeout(&csid->reset_complete,

> +		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> +	if (!time) {

> +		dev_err(csid->camss->dev, "CSID reset timeout\n");

> +		return -EIO;

> +	}

> +

> +	return 0;

> +}

> +

> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> +			     unsigned int match_format_idx, u32 match_code)

> +{

> +	if (match_format_idx > 0)

> +		return 0;

> +

> +	return sink_code;

> +}

> +

> +static void csid_subdev_init(struct csid_device *csid)

> +{

> +	csid->formats = csid_formats;

> +	csid->nformats = ARRAY_SIZE(csid_formats);

> +	csid->testgen.modes = csid_testgen_modes;

> +	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;

> +}

> +

> +const struct csid_hw_ops csid_ops_4_1 = {

> +	.configure_stream = csid_configure_stream,

> +	.configure_testgen_pattern = csid_configure_testgen_pattern,

> +	.hw_version = csid_hw_version,

> +	.isr = csid_isr,

> +	.reset = csid_reset,

> +	.src_pad_code = csid_src_pad_code,

> +	.subdev_init = csid_subdev_init,

> +};

> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

> new file mode 100644

> index 000000000000..16a69b140f4e

> --- /dev/null

> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

> @@ -0,0 +1,406 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * camss-csid-4-7.c

> + *

> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

> + *

> + * Copyright (C) 2020 Linaro Ltd.

> + */

> +#include <linux/completion.h>

> +#include <linux/interrupt.h>

> +#include <linux/io.h>

> +#include <linux/kernel.h>

> +#include <linux/of.h>

> +

> +#include "camss-csid.h"

> +#include "camss.h"

> +

> +#define CAMSS_CSID_HW_VERSION		0x0

> +#define CAMSS_CSID_CORE_CTRL_0		0x004

> +#define CAMSS_CSID_CORE_CTRL_1		0x008

> +#define CAMSS_CSID_RST_CMD		0x010

> +#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x014 + 0x4 * (n))

> +#define CAMSS_CSID_CID_n_CFG(n)		(0x024 + 0x4 * (n))

> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)

> +#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)

> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)

> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)

> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)

> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)

> +#define CAMSS_CSID_IRQ_CLEAR_CMD	0x064

> +#define CAMSS_CSID_IRQ_MASK		0x068

> +#define CAMSS_CSID_IRQ_STATUS		0x06c

> +#define CAMSS_CSID_TG_CTRL		0x0a8

> +#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436

> +#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437

> +#define CAMSS_CSID_TG_VC_CFG		0x0ac

> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff

> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f

> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0b4 + 0xc * (n))

> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b8 + 0xc * (n))

> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0bc + 0xc * (n))

> +

> +

> +static const struct csid_format csid_formats[] = {

> +	{

> +		MEDIA_BUS_FMT_UYVY8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_VYUY8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_YUYV8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_YVYU8_2X8,

> +		DATA_TYPE_YUV422_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		2,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB8_1X8,

> +		DATA_TYPE_RAW_8BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> +		8,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB12_1X12,

> +		DATA_TYPE_RAW_12BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> +		12,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SBGGR14_1X14,

> +		DATA_TYPE_RAW_14BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> +		14,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGBRG14_1X14,

> +		DATA_TYPE_RAW_14BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> +		14,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SGRBG14_1X14,

> +		DATA_TYPE_RAW_14BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> +		14,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_SRGGB14_1X14,

> +		DATA_TYPE_RAW_14BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> +		14,

> +		1,

> +	},

> +	{

> +		MEDIA_BUS_FMT_Y10_1X10,

> +		DATA_TYPE_RAW_10BIT,

> +		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> +		10,

> +		1,

> +	},

> +};

> +

> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

> +{

> +	struct csid_testgen_config *tg = &csid->testgen;

> +	u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

> +	u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

> +	u32 val;

> +

> +	if (enable) {

> +		struct v4l2_mbus_framefmt *input_format;

> +		const struct csid_format *format;

> +		u8 vc = 0; /* Virtual Channel 0 */

> +		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> +		u8 dt_shift;

> +

> +		if (tg->enabled) {

> +			/* Config Test Generator */

> +			u32 num_bytes_per_line, num_lines;

> +

> +			input_format = &csid->fmt[MSM_CSID_PAD_SRC];

> +			format = csid_get_fmt_entry(csid->formats, csid->nformats,

> +						    input_format->code);

> +			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

> +			num_lines = input_format->height;

> +

> +			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> +			/* 1:0 VC */

> +			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> +				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

> +

> +			/* 28:16 bytes per lines, 12:0 num of lines */

> +			val = ((num_bytes_per_line & 0x1fff) << 16) |

> +				  (num_lines & 0x1fff);

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

> +

> +			/* 5:0 data type */

> +			val = format->data_type;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

> +

> +			/* 2:0 output test pattern */

> +			val = tg->mode;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

> +		} else {

> +			struct csid_phy_config *phy = &csid->phy;

> +

> +			input_format = &csid->fmt[MSM_CSID_PAD_SINK];

> +			format = csid_get_fmt_entry(csid->formats, csid->nformats,

> +						    input_format->code);

> +

> +			val = phy->lane_cnt - 1;

> +			val |= phy->lane_assign << 4;

> +

> +			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

> +

> +			val = phy->csiphy_id << 17;

> +			val |= 0x9;

> +

> +			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

> +		}

> +

> +		/* Config LUT */

> +

> +		dt_shift = (cid % 4) * 8;

> +

> +		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> +		val &= ~(0xff << dt_shift);

> +		val |= format->data_type << dt_shift;

> +		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> +

> +		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> +		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> +		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> +		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> +

> +		if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

> +		     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

> +		    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

> +		     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

> +			val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

> +			val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

> +			val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

> +		}

> +

> +		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

> +

> +		if (tg->enabled) {

> +			val = CAMSS_CSID_TG_CTRL_ENABLE;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> +		}

> +	} else {

> +		if (tg->enabled) {

> +			val = CAMSS_CSID_TG_CTRL_DISABLE;

> +			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> +		}

> +	}

> +}

> +

> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

> +{

> +	s32 regval = val - 1;

> +

> +	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)

> +		csid->testgen.mode = regval;

> +

> +	return 0;

> +}

> +

> +static u32 csid_hw_version(struct csid_device *csid)

> +{

> +	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> +

> +	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

> +

> +	return hw_version;

> +}

> +

> +/*

> + * isr - CSID module interrupt service routine

> + * @irq: Interrupt line

> + * @dev: CSID device

> + *

> + * Return IRQ_HANDLED on success

> + */

> +static irqreturn_t csid_isr(int irq, void *dev)

> +{

> +	struct csid_device *csid = dev;

> +	u32 value;

> +

> +	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

> +	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

> +

> +	if ((value >> 11) & 0x1)

> +		complete(&csid->reset_complete);

> +

> +	return IRQ_HANDLED;

> +}

> +

> +/*

> + * csid_reset - Trigger reset on CSID module and wait to complete

> + * @csid: CSID device

> + *

> + * Return 0 on success or a negative error code otherwise

> + */

> +static int csid_reset(struct csid_device *csid)

> +{

> +	unsigned long time;

> +

> +	reinit_completion(&csid->reset_complete);

> +

> +	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

> +

> +	time = wait_for_completion_timeout(&csid->reset_complete,

> +		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> +	if (!time) {

> +		dev_err(csid->camss->dev, "CSID reset timeout\n");

> +		return -EIO;

> +	}

> +

> +	return 0;

> +}

> +

> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> +			     unsigned int match_format_idx, u32 match_code)

> +{

> +	switch (sink_code) {

> +	case MEDIA_BUS_FMT_SBGGR10_1X10:

> +	{

> +		u32 src_code[] = {

> +			MEDIA_BUS_FMT_SBGGR10_1X10,

> +			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

> +		};

> +

> +		return csid_find_code(src_code, ARRAY_SIZE(src_code),

> +				      match_format_idx, match_code);

> +	}

> +	case MEDIA_BUS_FMT_Y10_1X10:

> +	{

> +		u32 src_code[] = {

> +			MEDIA_BUS_FMT_Y10_1X10,

> +			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

> +		};

> +

> +		return csid_find_code(src_code, ARRAY_SIZE(src_code),

> +				      match_format_idx, match_code);

> +	}

> +	default:

> +		if (match_format_idx > 0)

> +			return 0;

> +

> +		return sink_code;

> +	}

> +}

> +

> +static void csid_subdev_init(struct csid_device *csid)

> +{

> +	csid->formats = csid_formats;

> +	csid->nformats = ARRAY_SIZE(csid_formats);

> +	csid->testgen.modes = csid_testgen_modes;

> +	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;

> +}

> +

> +const struct csid_hw_ops csid_ops_4_7 = {

> +	.configure_stream = csid_configure_stream,

> +	.configure_testgen_pattern = csid_configure_testgen_pattern,

> +	.hw_version = csid_hw_version,

> +	.isr = csid_isr,

> +	.reset = csid_reset,

> +	.src_pad_code = csid_src_pad_code,

> +	.subdev_init = csid_subdev_init,

> +};

> diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c

> index be3fe76f3dc3..601bd810f2b0 100644

> --- a/drivers/media/platform/qcom/camss/camss-csid.c

> +++ b/drivers/media/platform/qcom/camss/camss-csid.c

> @@ -26,405 +26,35 @@

>   

>   #define MSM_CSID_NAME "msm_csid"

>   

> -#define CAMSS_CSID_HW_VERSION		0x0

> -#define CAMSS_CSID_CORE_CTRL_0		0x004

> -#define CAMSS_CSID_CORE_CTRL_1		0x008

> -#define CAMSS_CSID_RST_CMD(v)		((v) == CAMSS_8x16 ? 0x00c : 0x010)

> -#define CAMSS_CSID_CID_LUT_VC_n(v, n)	\

> -			(((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))

> -#define CAMSS_CSID_CID_n_CFG(v, n)	\

> -			(((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))

> -#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)

> -#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)

> -#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4

> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)

> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)

> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)

> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)

> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)

> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)

> -#define CAMSS_CSID_IRQ_CLEAR_CMD(v)	((v) == CAMSS_8x16 ? 0x060 : 0x064)

> -#define CAMSS_CSID_IRQ_MASK(v)		((v) == CAMSS_8x16 ? 0x064 : 0x068)

> -#define CAMSS_CSID_IRQ_STATUS(v)	((v) == CAMSS_8x16 ? 0x068 : 0x06c)

> -#define CAMSS_CSID_TG_CTRL(v)		((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)

> -#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436

> -#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437

> -#define CAMSS_CSID_TG_VC_CFG(v)		((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)

> -#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff

> -#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f

> -#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)	\

> -			(((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))

> -#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)	\

> -			(((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))

> -#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)	\

> -			(((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))

> -

> -#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12

> -#define DATA_TYPE_YUV422_8BIT		0x1e

> -#define DATA_TYPE_RAW_6BIT		0x28

> -#define DATA_TYPE_RAW_8BIT		0x2a

> -#define DATA_TYPE_RAW_10BIT		0x2b

> -#define DATA_TYPE_RAW_12BIT		0x2c

> -#define DATA_TYPE_RAW_14BIT		0x2d

> -

> -#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0

> -#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1

> -#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2

> -#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3

> -#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x8

> -

> -#define CSID_RESET_TIMEOUT_MS 500

> -

> -struct csid_format {

> -	u32 code;

> -	u8 data_type;

> -	u8 decode_format;

> -	u8 bpp;

> -	u8 spp; /* bus samples per pixel */

> -};

> -

> -static const struct csid_format csid_formats_8x16[] = {

> -	{

> -		MEDIA_BUS_FMT_UYVY8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_VYUY8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_YUYV8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_YVYU8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_Y10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -};

> -

> -static const struct csid_format csid_formats_8x96[] = {

> -	{

> -		MEDIA_BUS_FMT_UYVY8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_VYUY8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_YUYV8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_YVYU8_2X8,

> -		DATA_TYPE_YUV422_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		2,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB8_1X8,

> -		DATA_TYPE_RAW_8BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> -		8,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB12_1X12,

> -		DATA_TYPE_RAW_12BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> -		12,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SBGGR14_1X14,

> -		DATA_TYPE_RAW_14BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> -		14,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGBRG14_1X14,

> -		DATA_TYPE_RAW_14BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> -		14,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SGRBG14_1X14,

> -		DATA_TYPE_RAW_14BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> -		14,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_SRGGB14_1X14,

> -		DATA_TYPE_RAW_14BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> -		14,

> -		1,

> -	},

> -	{

> -		MEDIA_BUS_FMT_Y10_1X10,

> -		DATA_TYPE_RAW_10BIT,

> -		DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> -		10,

> -		1,

> -	},

> -};

>   

> -static u32 csid_find_code(u32 *code, unsigned int n_code,

> -			  unsigned int index, u32 req_code)

> +u32 csid_find_code(u32 *codes, unsigned int ncodes,

> +		   unsigned int match_format_idx, u32 match_code)

>   {

>   	int i;

>   

> -	if (!req_code && (index >= n_code))

> +	if (!match_code && (match_format_idx >= ncodes))

>   		return 0;

>   

> -	for (i = 0; i < n_code; i++)

> -		if (req_code) {

> -			if (req_code == code[i])

> -				return req_code;

> +	for (i = 0; i < ncodes; i++)

> +		if (match_code) {

> +			if (codes[i] == match_code)

> +				return match_code;

>   		} else {

> -			if (i == index)

> -				return code[i];

> -		}

> -

> -	return code[0];

> -}

> -

> -static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> -			     unsigned int index, u32 src_req_code)

> -{

> -	if (csid->camss->version == CAMSS_8x16) {

> -		if (index > 0)

> -			return 0;

> -

> -		return sink_code;

> -	} else if (csid->camss->version == CAMSS_8x96 ||

> -		   csid->camss->version == CAMSS_660) {

> -		switch (sink_code) {

> -		case MEDIA_BUS_FMT_SBGGR10_1X10:

> -		{

> -			u32 src_code[] = {

> -				MEDIA_BUS_FMT_SBGGR10_1X10,

> -				MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

> -			};

> -

> -			return csid_find_code(src_code, ARRAY_SIZE(src_code),

> -					      index, src_req_code);

> -		}

> -		case MEDIA_BUS_FMT_Y10_1X10:

> -		{

> -			u32 src_code[] = {

> -				MEDIA_BUS_FMT_Y10_1X10,

> -				MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

> -			};

> -

> -			return csid_find_code(src_code, ARRAY_SIZE(src_code),

> -					      index, src_req_code);

> +			if (i == match_format_idx)

> +				return codes[i];

>   		}

> -		default:

> -			if (index > 0)

> -				return 0;

>   

> -			return sink_code;

> -		}

> -	} else {

> -		return 0;

> -	}

> +	return codes[0];

>   }

>   

> -static const struct csid_format *csid_get_fmt_entry(

> +const struct csid_format *csid_get_fmt_entry(

>   					const struct csid_format *formats,

> -					unsigned int nformat,

> +					unsigned int nformats,

>   					u32 code)

>   {

>   	unsigned int i;

>   

> -	for (i = 0; i < nformat; i++)

> +	for (i = 0; i < nformats; i++)

>   		if (code == formats[i].code)

>   			return &formats[i];

>   

> @@ -433,28 +63,6 @@ static const struct csid_format *csid_get_fmt_entry(

>   	return &formats[0];

>   }

>   

> -/*

> - * csid_isr - CSID module interrupt handler

> - * @irq: Interrupt line

> - * @dev: CSID device

> - *

> - * Return IRQ_HANDLED on success

> - */

> -static irqreturn_t csid_isr(int irq, void *dev)

> -{

> -	struct csid_device *csid = dev;

> -	enum camss_version ver = csid->camss->version;

> -	u32 value;

> -

> -	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));

> -	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));

> -

> -	if ((value >> 11) & 0x1)

> -		complete(&csid->reset_complete);

> -

> -	return IRQ_HANDLED;

> -}

> -

>   /*

>    * csid_set_clock_rates - Calculate and set clock rates on CSID module

>    * @csiphy: CSID device

> @@ -521,31 +129,6 @@ static int csid_set_clock_rates(struct csid_device *csid)

>   	return 0;

>   }

>   

> -/*

> - * csid_reset - Trigger reset on CSID module and wait to complete

> - * @csid: CSID device

> - *

> - * Return 0 on success or a negative error code otherwise

> - */

> -static int csid_reset(struct csid_device *csid)

> -{

> -	unsigned long time;

> -

> -	reinit_completion(&csid->reset_complete);

> -

> -	writel_relaxed(0x7fff, csid->base +

> -		       CAMSS_CSID_RST_CMD(csid->camss->version));

> -

> -	time = wait_for_completion_timeout(&csid->reset_complete,

> -		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> -	if (!time) {

> -		dev_err(csid->camss->dev, "CSID reset timeout\n");

> -		return -EIO;

> -	}

> -

> -	return 0;

> -}

> -

>   /*

>    * csid_set_power - Power on/off CSID module

>    * @sd: CSID V4L2 subdevice

> @@ -560,8 +143,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>   	int ret;

>   

>   	if (on) {

> -		u32 hw_version;

> -

>   		ret = pm_runtime_get_sync(dev);

>   		if (ret < 0) {

>   			pm_runtime_put_sync(dev);

> @@ -590,7 +171,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>   

>   		enable_irq(csid->irq);

>   

> -		ret = csid_reset(csid);

> +		ret = csid->ops->reset(csid);

>   		if (ret < 0) {

>   			disable_irq(csid->irq);

>   			camss_disable_clocks(csid->nclocks, csid->clock);

> @@ -599,8 +180,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>   			return ret;

>   		}

>   

> -		hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> -		dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);

> +		csid->ops->hw_version(csid);

>   	} else {

>   		disable_irq(csid->irq);

>   		camss_disable_clocks(csid->nclocks, csid->clock);

> @@ -623,16 +203,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>   static int csid_set_stream(struct v4l2_subdev *sd, int enable)

>   {

>   	struct csid_device *csid = v4l2_get_subdevdata(sd);

> -	struct csid_testgen_config *tg = &csid->testgen;

> -	enum camss_version ver = csid->camss->version;

> -	u32 val;

> +	int ret;

>   

>   	if (enable) {

> -		u8 vc = 0; /* Virtual Channel 0 */

> -		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> -		u8 dt, dt_shift, df;

> -		int ret;

> -

>   		ret = v4l2_ctrl_handler_setup(&csid->ctrls);

>   		if (ret < 0) {

>   			dev_err(csid->camss->dev,

> @@ -640,116 +213,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)

>   			return ret;

>   		}

>   

> -		if (!tg->enabled &&

> +		if (!csid->testgen.enabled &&

>   		    !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))

>   			return -ENOLINK;

> -

> -		if (tg->enabled) {

> -			/* Config Test Generator */

> -			struct v4l2_mbus_framefmt *f =

> -					&csid->fmt[MSM_CSID_PAD_SRC];

> -			const struct csid_format *format = csid_get_fmt_entry(

> -					csid->formats, csid->nformats, f->code);

> -			u32 num_bytes_per_line =

> -				f->width * format->bpp * format->spp / 8;

> -			u32 num_lines = f->height;

> -

> -			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> -			/* 1:0 VC */

> -			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> -			      ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_VC_CFG(ver));

> -

> -			/* 28:16 bytes per lines, 12:0 num of lines */

> -			val = ((num_bytes_per_line & 0x1fff) << 16) |

> -			      (num_lines & 0x1fff);

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));

> -

> -			dt = format->data_type;

> -

> -			/* 5:0 data type */

> -			val = dt;

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));

> -

> -			/* 2:0 output test pattern */

> -			val = tg->payload_mode;

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));

> -

> -			df = format->decode_format;

> -		} else {

> -			struct v4l2_mbus_framefmt *f =

> -					&csid->fmt[MSM_CSID_PAD_SINK];

> -			const struct csid_format *format = csid_get_fmt_entry(

> -					csid->formats, csid->nformats, f->code);

> -			struct csid_phy_config *phy = &csid->phy;

> -

> -			val = phy->lane_cnt - 1;

> -			val |= phy->lane_assign << 4;

> -

> -			writel_relaxed(val,

> -				       csid->base + CAMSS_CSID_CORE_CTRL_0);

> -

> -			val = phy->csiphy_id << 17;

> -			val |= 0x9;

> -

> -			writel_relaxed(val,

> -				       csid->base + CAMSS_CSID_CORE_CTRL_1);

> -

> -			dt = format->data_type;

> -			df = format->decode_format;

> -		}

> -

> -		/* Config LUT */

> -

> -		dt_shift = (cid % 4) * 8;

> -

> -		val = readl_relaxed(csid->base +

> -				    CAMSS_CSID_CID_LUT_VC_n(ver, vc));

> -		val &= ~(0xff << dt_shift);

> -		val |= dt << dt_shift;

> -		writel_relaxed(val, csid->base +

> -			       CAMSS_CSID_CID_LUT_VC_n(ver, vc));

> -

> -		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> -		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> -		val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> -		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> -

> -		if (csid->camss->version == CAMSS_8x96 ||

> -		    csid->camss->version == CAMSS_660) {

> -			u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

> -			u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

> -

> -			if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

> -			     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

> -			    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

> -			     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

> -				val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

> -				val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

> -				val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

> -			}

> -		}

> -

> -		writel_relaxed(val, csid->base +

> -			       CAMSS_CSID_CID_n_CFG(ver, cid));

> -

> -		if (tg->enabled) {

> -			val = CAMSS_CSID_TG_CTRL_ENABLE;

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_CTRL(ver));

> -		}

> -	} else {

> -		if (tg->enabled) {

> -			val = CAMSS_CSID_TG_CTRL_DISABLE;

> -			writel_relaxed(val, csid->base +

> -				       CAMSS_CSID_TG_CTRL(ver));

> -		}

>   	}

>   

> +	csid->ops->configure_stream(csid, enable);

> +

>   	return 0;

>   }

>   

> @@ -818,7 +288,7 @@ static void csid_try_format(struct csid_device *csid,

>   

>   			*fmt = *__csid_get_format(csid, cfg,

>   						      MSM_CSID_PAD_SINK, which);

> -			fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);

> +			fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);

>   		} else {

>   			/* Test generator is enabled, set format on source */

>   			/* pad to allow test generator usage */

> @@ -868,7 +338,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,

>   						     MSM_CSID_PAD_SINK,

>   						     code->which);

>   

> -			code->code = csid_src_pad_code(csid, sink_fmt->code,

> +			code->code = csid->ops->src_pad_code(csid, sink_fmt->code,

>   						       code->index, 0);

>   			if (!code->code)

>   				return -EINVAL;

> @@ -1004,15 +474,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)

>   	return csid_set_format(sd, fh ? fh->pad : NULL, &format);

>   }

>   

> -static const char * const csid_test_pattern_menu[] = {

> -	"Disabled",

> -	"Incrementing",

> -	"Alternating 0x55/0xAA",

> -	"All Zeros 0x00",

> -	"All Ones 0xFF",

> -	"Pseudo-random Data",

> -};

> -

>   /*

>    * csid_set_test_pattern - Set test generator's pattern mode

>    * @csid: CSID device

> @@ -1030,25 +491,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)

>   

>   	tg->enabled = !!value;

>   

> -	switch (value) {

> -	case 1:

> -		tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;

> -		break;

> -	case 2:

> -		tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;

> -		break;

> -	case 3:

> -		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;

> -		break;

> -	case 4:

> -		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;

> -		break;

> -	case 5:

> -		tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;

> -		break;

> -	}

> -

> -	return 0;

> +	return csid->ops->configure_testgen_pattern(csid, value);

>   }

>   

>   /*

> @@ -1097,17 +540,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>   	csid->id = id;

>   

>   	if (camss->version == CAMSS_8x16) {

> -		csid->formats = csid_formats_8x16;

> -		csid->nformats =

> -				ARRAY_SIZE(csid_formats_8x16);

> +		csid->ops = &csid_ops_4_1;

>   	} else if (camss->version == CAMSS_8x96 ||

>   		   camss->version == CAMSS_660) {

> -		csid->formats = csid_formats_8x96;

> -		csid->nformats =

> -				ARRAY_SIZE(csid_formats_8x96);

> +		csid->ops = &csid_ops_4_7;

>   	} else {

>   		return -EINVAL;

>   	}

> +	csid->ops->subdev_init(csid);

>   

>   	/* Memory */

>   

> @@ -1130,7 +570,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>   	csid->irq = r->start;

>   	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",

>   		 dev_name(dev), MSM_CSID_NAME, csid->id);

> -	ret = devm_request_irq(dev, csid->irq, csid_isr,

> +	ret = devm_request_irq(dev, csid->irq, csid->ops->isr,

>   		IRQF_TRIGGER_RISING, csid->irq_name, csid);

>   	if (ret < 0) {

>   		dev_err(dev, "request_irq failed: %d\n", ret);

> @@ -1341,8 +781,8 @@ int msm_csid_register_entity(struct csid_device *csid,

>   

>   	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,

>   				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,

> -				ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,

> -				csid_test_pattern_menu);

> +				csid->testgen.nmodes, 0, 0,

> +				csid->testgen.modes);

>   

>   	if (csid->ctrls.error) {

>   		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);

> diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h

> index 02fc34ee8a41..d40194e2bed3 100644

> --- a/drivers/media/platform/qcom/camss/camss-csid.h

> +++ b/drivers/media/platform/qcom/camss/camss-csid.h

> @@ -11,6 +11,7 @@

>   #define QC_MSM_CAMSS_CSID_H

>   

>   #include <linux/clk.h>

> +#include <linux/interrupt.h>

>   #include <media/media-entity.h>

>   #include <media/v4l2-ctrls.h>

>   #include <media/v4l2-device.h>

> @@ -70,19 +71,50 @@

>   #define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */

>   #define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */

>   

> +#define CSID_RESET_TIMEOUT_MS 500

>   

> -enum csid_payload_mode {

> +

> +enum csid_testgen_mode {

>   	CSID_PAYLOAD_MODE_INCREMENTING = 0,

>   	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,

>   	CSID_PAYLOAD_MODE_ALL_ZEROES = 2,

>   	CSID_PAYLOAD_MODE_ALL_ONES = 3,

>   	CSID_PAYLOAD_MODE_RANDOM = 4,

>   	CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,

> +	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,

> +	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,

> +	CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,

> +	CSID_PAYLOAD_MODE_COLOR_BOX = 7,

> +	CSID_PAYLOAD_MODE_COLOR_BARS = 8,

> +	CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,

> +};

> +

> +static const char * const csid_testgen_modes[] = {

> +	"Disabled",

> +	"Incrementing",

> +	"Alternating 0x55/0xAA",

> +	"All Zeros 0x00",

> +	"All Ones 0xFF",

> +	"Pseudo-random Data",

> +	"User Specified",

> +	"Complex pattern",

> +	"Color box",

> +	"Color bars",

> +};

> +

> +struct csid_format {

> +	u32 code;

> +	u8 data_type;

> +	u8 decode_format;

> +	u8 bpp;

> +	u8 spp; /* bus samples per pixel */

>   };

>   

>   struct csid_testgen_config {

> +	enum csid_testgen_mode mode;

> +	const char * const*modes;

> +	u8 nmodes;

>   	u8 enabled;

> -	enum csid_payload_mode payload_mode;

>   };

>   

>   struct csid_phy_config {

> @@ -91,6 +123,65 @@ struct csid_phy_config {

>   	u32 lane_assign;

>   };

>   

> +struct csid_device;

> +

> +struct csid_hw_ops {

> +	/*

> +	 * configure_stream - Configures and starts CSID input stream

> +	 * @csid: CSID device

> +	 */

> +	void (*configure_stream)(struct csid_device *csid, u8 enable);

> +

> +	/*

> +	 * configure_testgen_pattern - Validates and configures output pattern mode

> +	 * of test pattern generator

> +	 * @csid: CSID device

> +	 */

> +	int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);

> +

> +	/*

> +	 * hw_version - Read hardware version register from hardware

> +	 * @csid: CSID device

> +	 */

> +	u32 (*hw_version)(struct csid_device *csid);

> +

> +	/*

> +	 * isr - CSID module interrupt service routine

> +	 * @irq: Interrupt line

> +	 * @dev: CSID device

> +	 *

> +	 * Return IRQ_HANDLED on success

> +	 */

> +	irqreturn_t (*isr)(int irq, void *dev);

> +

> +	/*

> +	 * reset - Trigger reset on CSID module and wait to complete

> +	 * @csid: CSID device

> +	 *

> +	 * Return 0 on success or a negative error code otherwise

> +	 */

> +	int (*reset)(struct csid_device *csid);

> +

> +	/*

> +	 * src_pad_code - Pick an output/src format based on the input/sink format

> +	 * @csid: CSID device

> +	 * @sink_code: The sink format of the input

> +	 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.

> +	 *	Set @match_code to 0 if used.

> +	 * @match_code: Request preferred code, set @match_format_idx to 0 if used

> +	 *

> +	 * Return 0 on failure or src format code otherwise

> +	 */

> +	u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,

> +			    unsigned int match_format_idx, u32 match_code);

> +

> +	/*

> +	 * subdev_init - Initialize CSID device according for hardware revision

> +	 * @csid: CSID device

> +	 */

> +	void (*subdev_init)(struct csid_device *csid);

> +};

> +

>   struct csid_device {

>   	struct camss *camss;

>   	u8 id;

> @@ -110,10 +201,37 @@ struct csid_device {

>   	struct v4l2_ctrl *testgen_mode;

>   	const struct csid_format *formats;

>   	unsigned int nformats;

> +	const struct csid_hw_ops *ops;

>   };

>   

>   struct resources;

>   

> +

> +/*

> + * csid_find_code - Find a format code in an array using array index or format code

> + * @codes: Array of format codes

> + * @ncodes: Length of @code array

> + * @req_format_idx: Request preferred index, as defined by subdevice csid_format.

> + *	Set @match_code to 0 if used.

> + * @match_code: Request preferred code, set @req_format_idx to 0 if used

> + *

> + * Return 0 on failure or format code otherwise

> + */

> +u32 csid_find_code(u32 *codes, unsigned int ncode,

> +		   unsigned int match_format_idx, u32 match_code);

> +

> +/*

> + * csid_get_fmt_entry - Find csid_format entry with matching format code

> + * @formats: Array of format csid_format entries

> + * @nformats: Length of @nformats array

> + * @code: Desired format code

> + *

> + * Return formats[0] on failure to find code

> + */

> +const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,

> +					     unsigned int nformats,

> +					     u32 code);

> +

>   int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>   			 const struct resources *res, u8 id);

>   

> @@ -124,4 +242,8 @@ void msm_csid_unregister_entity(struct csid_device *csid);

>   

>   void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);

>   

> +

> +extern const struct csid_hw_ops csid_ops_4_1;

> +extern const struct csid_hw_ops csid_ops_4_7;

> +

>   #endif /* QC_MSM_CAMSS_CSID_H */

>
Andrey Konovalov Feb. 21, 2021, 5:50 p.m. | #2
Hi Robert,

After reviewing the [PATCH v5 10/22], I noticed that this patch also
has a problematic test_pattern control implementation.

See below.

On 21.02.2021 18:15, Andrey Konovalov wrote:
> Hi Robert,

> 

> Thank you for your patch!

> 

> Reviewed-by: Andrey Konovalov <andrey.konovalov@linaro.org>

> 

> Thanks,

> Andrey

> 

> On 17.02.2021 14:21, Robert Foss wrote:

>> In order to support Qualcomm ISP hardware architectures that diverge

>> from older architectures, the CSID subdevice drivers needs to be refactored

>> to better abstract the different ISP hardware architectures.

>>

>> Signed-off-by: Robert Foss <robert.foss@linaro.org>

>> ---

>>

>> Changes since v1

>>   - kernel test robot: Add missing include, interrupt.h

>>

>> Changes since v4

>>   - Andrey: Removed whitespace from some includes

>>   - Andrey: Removed unused enum

>>

>>

>>   drivers/media/platform/qcom/camss/Makefile    |   2 +

>>   .../platform/qcom/camss/camss-csid-4-1.c      | 330 ++++++++++

>>   .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++

>>   .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------

>>   .../media/platform/qcom/camss/camss-csid.h    | 126 +++-

>>   5 files changed, 890 insertions(+), 590 deletions(-)

>>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c

>>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

>>

>> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile

>> index 052c4f405fa3..cff388b653ba 100644

>> --- a/drivers/media/platform/qcom/camss/Makefile

>> +++ b/drivers/media/platform/qcom/camss/Makefile

>> @@ -4,6 +4,8 @@

>>   qcom-camss-objs += \

>>           camss.o \

>>           camss-csid.o \

>> +        camss-csid-4-1.o \

>> +        camss-csid-4-7.o \

>>           camss-csiphy-2ph-1-0.o \

>>           camss-csiphy-3ph-1-0.o \

>>           camss-csiphy.o \

>> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

>> new file mode 100644

>> index 000000000000..c92077a7f758

>> --- /dev/null

>> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

>> @@ -0,0 +1,330 @@

>> +// SPDX-License-Identifier: GPL-2.0

>> +/*

>> + * camss-csid-4-1.c

>> + *

>> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

>> + *

>> + * Copyright (C) 2020 Linaro Ltd.

>> + */

>> +

>> +#include <linux/completion.h>

>> +#include <linux/interrupt.h>

>> +#include <linux/io.h>

>> +#include <linux/kernel.h>

>> +#include <linux/of.h>

>> +

>> +#include "camss-csid.h"

>> +#include "camss.h"

>> +

>> +#define CAMSS_CSID_HW_VERSION        0x0

>> +#define CAMSS_CSID_CORE_CTRL_0        0x004

>> +#define CAMSS_CSID_CORE_CTRL_1        0x008

>> +#define CAMSS_CSID_RST_CMD        0x00c

>> +#define CAMSS_CSID_CID_LUT_VC_n(n)    (0x010 + 0x4 * (n))

>> +#define CAMSS_CSID_CID_n_CFG(n)        (0x020 + 0x4 * (n))

>> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

>> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

>> +#define CAMSS_CSID_IRQ_CLEAR_CMD    0x060

>> +#define CAMSS_CSID_IRQ_MASK        0x064

>> +#define CAMSS_CSID_IRQ_STATUS        0x068

>> +#define CAMSS_CSID_TG_CTRL        0x0a0

>> +#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

>> +#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

>> +#define CAMSS_CSID_TG_VC_CFG        0x0a4

>> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

>> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

>> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)    (0x0ac + 0xc * (n))

>> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)    (0x0b0 + 0xc * (n))

>> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)    (0x0b4 + 0xc * (n))

>> +

>> +

>> +static const struct csid_format csid_formats[] = {

>> +    {

>> +        MEDIA_BUS_FMT_UYVY8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_VYUY8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_YUYV8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_YVYU8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_Y10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +};

>> +

>> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

>> +{

>> +    struct csid_testgen_config *tg = &csid->testgen;

>> +    u32 val;

>> +

>> +    if (enable) {

>> +        struct v4l2_mbus_framefmt *input_format;

>> +        const struct csid_format *format;

>> +        u8 vc = 0; /* Virtual Channel 0 */

>> +        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

>> +        u8 dt_shift;

>> +

>> +        if (tg->enabled) {

>> +            /* Config Test Generator */

>> +            u32 num_lines, num_bytes_per_line;

>> +

>> +            input_format = &csid->fmt[MSM_CSID_PAD_SRC];

>> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

>> +                            input_format->code);

>> +            num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

>> +            num_lines = input_format->height;

>> +

>> +            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

>> +            /* 1:0 VC */

>> +            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

>> +                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

>> +

>> +            /* 28:16 bytes per lines, 12:0 num of lines */

>> +            val = ((num_bytes_per_line & 0x1fff) << 16) |

>> +                  (num_lines & 0x1fff);

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

>> +

>> +            /* 5:0 data type */

>> +            val = format->data_type;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

>> +

>> +            /* 2:0 output test pattern */

>> +            val = tg->mode;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

>> +        } else {

>> +            struct csid_phy_config *phy = &csid->phy;

>> +

>> +            input_format = &csid->fmt[MSM_CSID_PAD_SINK];

>> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

>> +                            input_format->code);

>> +

>> +            val = phy->lane_cnt - 1;

>> +            val |= phy->lane_assign << 4;

>> +

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

>> +

>> +            val = phy->csiphy_id << 17;

>> +            val |= 0x9;

>> +

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

>> +        }

>> +

>> +        /* Config LUT */

>> +

>> +        dt_shift = (cid % 4) * 8;

>> +        val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

>> +        val &= ~(0xff << dt_shift);

>> +        val |= format->data_type << dt_shift;

>> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

>> +

>> +        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

>> +        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

>> +        val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

>> +        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

>> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

>> +

>> +        if (tg->enabled) {

>> +            val = CAMSS_CSID_TG_CTRL_ENABLE;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

>> +        }

>> +    } else {

>> +        if (tg->enabled) {

>> +            val = CAMSS_CSID_TG_CTRL_DISABLE;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

>> +        }

>> +    }

>> +}

>> +

>> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

>> +{

>> +    s32 regval = val - 1;

>> +

>> +    if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)

>> +        csid->testgen.mode = regval;


regval of 0 is the valid "Incrementing" test pattern. The condition above
should be "regval >= 0", not "regval > 0".

>> +

>> +    return 0;

>> +}

>> +

>> +static u32 csid_hw_version(struct csid_device *csid)

>> +{

>> +    u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

>> +

>> +    dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

>> +

>> +    return hw_version;

>> +}

>> +

>> +static irqreturn_t csid_isr(int irq, void *dev)

>> +{

>> +    struct csid_device *csid = dev;

>> +    u32 value;

>> +

>> +    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

>> +    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

>> +

>> +    if ((value >> 11) & 0x1)

>> +        complete(&csid->reset_complete);

>> +

>> +    return IRQ_HANDLED;

>> +}

>> +

>> +static int csid_reset(struct csid_device *csid)

>> +{

>> +    unsigned long time;

>> +

>> +    reinit_completion(&csid->reset_complete);

>> +

>> +    writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

>> +

>> +    time = wait_for_completion_timeout(&csid->reset_complete,

>> +        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

>> +    if (!time) {

>> +        dev_err(csid->camss->dev, "CSID reset timeout\n");

>> +        return -EIO;

>> +    }

>> +

>> +    return 0;

>> +}

>> +

>> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

>> +                 unsigned int match_format_idx, u32 match_code)

>> +{

>> +    if (match_format_idx > 0)

>> +        return 0;

>> +

>> +    return sink_code;

>> +}

>> +

>> +static void csid_subdev_init(struct csid_device *csid)

>> +{

>> +    csid->formats = csid_formats;

>> +    csid->nformats = ARRAY_SIZE(csid_formats);

>> +    csid->testgen.modes = csid_testgen_modes;

>> +    csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;

>> +}

>> +

>> +const struct csid_hw_ops csid_ops_4_1 = {

>> +    .configure_stream = csid_configure_stream,

>> +    .configure_testgen_pattern = csid_configure_testgen_pattern,

>> +    .hw_version = csid_hw_version,

>> +    .isr = csid_isr,

>> +    .reset = csid_reset,

>> +    .src_pad_code = csid_src_pad_code,

>> +    .subdev_init = csid_subdev_init,

>> +};

>> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

>> new file mode 100644

>> index 000000000000..16a69b140f4e

>> --- /dev/null

>> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

>> @@ -0,0 +1,406 @@

>> +// SPDX-License-Identifier: GPL-2.0

>> +/*

>> + * camss-csid-4-7.c

>> + *

>> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

>> + *

>> + * Copyright (C) 2020 Linaro Ltd.

>> + */

>> +#include <linux/completion.h>

>> +#include <linux/interrupt.h>

>> +#include <linux/io.h>

>> +#include <linux/kernel.h>

>> +#include <linux/of.h>

>> +

>> +#include "camss-csid.h"

>> +#include "camss.h"

>> +

>> +#define CAMSS_CSID_HW_VERSION        0x0

>> +#define CAMSS_CSID_CORE_CTRL_0        0x004

>> +#define CAMSS_CSID_CORE_CTRL_1        0x008

>> +#define CAMSS_CSID_RST_CMD        0x010

>> +#define CAMSS_CSID_CID_LUT_VC_n(n)    (0x014 + 0x4 * (n))

>> +#define CAMSS_CSID_CID_n_CFG(n)        (0x024 + 0x4 * (n))

>> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

>> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

>> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

>> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

>> +#define CAMSS_CSID_IRQ_CLEAR_CMD    0x064

>> +#define CAMSS_CSID_IRQ_MASK        0x068

>> +#define CAMSS_CSID_IRQ_STATUS        0x06c

>> +#define CAMSS_CSID_TG_CTRL        0x0a8

>> +#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

>> +#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

>> +#define CAMSS_CSID_TG_VC_CFG        0x0ac

>> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

>> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

>> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)    (0x0b4 + 0xc * (n))

>> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)    (0x0b8 + 0xc * (n))

>> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)    (0x0bc + 0xc * (n))

>> +

>> +

>> +static const struct csid_format csid_formats[] = {

>> +    {

>> +        MEDIA_BUS_FMT_UYVY8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_VYUY8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_YUYV8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_YVYU8_2X8,

>> +        DATA_TYPE_YUV422_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        2,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB8_1X8,

>> +        DATA_TYPE_RAW_8BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> +        8,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB12_1X12,

>> +        DATA_TYPE_RAW_12BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> +        12,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SBGGR14_1X14,

>> +        DATA_TYPE_RAW_14BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> +        14,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGBRG14_1X14,

>> +        DATA_TYPE_RAW_14BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> +        14,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SGRBG14_1X14,

>> +        DATA_TYPE_RAW_14BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> +        14,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_SRGGB14_1X14,

>> +        DATA_TYPE_RAW_14BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> +        14,

>> +        1,

>> +    },

>> +    {

>> +        MEDIA_BUS_FMT_Y10_1X10,

>> +        DATA_TYPE_RAW_10BIT,

>> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> +        10,

>> +        1,

>> +    },

>> +};

>> +

>> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

>> +{

>> +    struct csid_testgen_config *tg = &csid->testgen;

>> +    u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

>> +    u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

>> +    u32 val;

>> +

>> +    if (enable) {

>> +        struct v4l2_mbus_framefmt *input_format;

>> +        const struct csid_format *format;

>> +        u8 vc = 0; /* Virtual Channel 0 */

>> +        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

>> +        u8 dt_shift;

>> +

>> +        if (tg->enabled) {

>> +            /* Config Test Generator */

>> +            u32 num_bytes_per_line, num_lines;

>> +

>> +            input_format = &csid->fmt[MSM_CSID_PAD_SRC];

>> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

>> +                            input_format->code);

>> +            num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

>> +            num_lines = input_format->height;

>> +

>> +            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

>> +            /* 1:0 VC */

>> +            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

>> +                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

>> +

>> +            /* 28:16 bytes per lines, 12:0 num of lines */

>> +            val = ((num_bytes_per_line & 0x1fff) << 16) |

>> +                  (num_lines & 0x1fff);

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

>> +

>> +            /* 5:0 data type */

>> +            val = format->data_type;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

>> +

>> +            /* 2:0 output test pattern */

>> +            val = tg->mode;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

>> +        } else {

>> +            struct csid_phy_config *phy = &csid->phy;

>> +

>> +            input_format = &csid->fmt[MSM_CSID_PAD_SINK];

>> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

>> +                            input_format->code);

>> +

>> +            val = phy->lane_cnt - 1;

>> +            val |= phy->lane_assign << 4;

>> +

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

>> +

>> +            val = phy->csiphy_id << 17;

>> +            val |= 0x9;

>> +

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

>> +        }

>> +

>> +        /* Config LUT */

>> +

>> +        dt_shift = (cid % 4) * 8;

>> +

>> +        val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

>> +        val &= ~(0xff << dt_shift);

>> +        val |= format->data_type << dt_shift;

>> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

>> +

>> +        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

>> +        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

>> +        val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

>> +        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

>> +

>> +        if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

>> +             src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

>> +            (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

>> +             src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

>> +            val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

>> +            val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

>> +            val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

>> +        }

>> +

>> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

>> +

>> +        if (tg->enabled) {

>> +            val = CAMSS_CSID_TG_CTRL_ENABLE;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

>> +        }

>> +    } else {

>> +        if (tg->enabled) {

>> +            val = CAMSS_CSID_TG_CTRL_DISABLE;

>> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

>> +        }

>> +    }

>> +}

>> +

>> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

>> +{

>> +    s32 regval = val - 1;

>> +

>> +    if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)

>> +        csid->testgen.mode = regval;


regval of 0 is the valid "Incrementing" test pattern. The condition above
should be "regval >= 0", not "regval > 0".

>> +    return 0;

>> +}

>> +

>> +static u32 csid_hw_version(struct csid_device *csid)

>> +{

>> +    u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

>> +

>> +    dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

>> +

>> +    return hw_version;

>> +}

>> +

>> +/*

>> + * isr - CSID module interrupt service routine

>> + * @irq: Interrupt line

>> + * @dev: CSID device

>> + *

>> + * Return IRQ_HANDLED on success

>> + */

>> +static irqreturn_t csid_isr(int irq, void *dev)

>> +{

>> +    struct csid_device *csid = dev;

>> +    u32 value;

>> +

>> +    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

>> +    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

>> +

>> +    if ((value >> 11) & 0x1)

>> +        complete(&csid->reset_complete);

>> +

>> +    return IRQ_HANDLED;

>> +}

>> +

>> +/*

>> + * csid_reset - Trigger reset on CSID module and wait to complete

>> + * @csid: CSID device

>> + *

>> + * Return 0 on success or a negative error code otherwise

>> + */

>> +static int csid_reset(struct csid_device *csid)

>> +{

>> +    unsigned long time;

>> +

>> +    reinit_completion(&csid->reset_complete);

>> +

>> +    writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

>> +

>> +    time = wait_for_completion_timeout(&csid->reset_complete,

>> +        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

>> +    if (!time) {

>> +        dev_err(csid->camss->dev, "CSID reset timeout\n");

>> +        return -EIO;

>> +    }

>> +

>> +    return 0;

>> +}

>> +

>> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

>> +                 unsigned int match_format_idx, u32 match_code)

>> +{

>> +    switch (sink_code) {

>> +    case MEDIA_BUS_FMT_SBGGR10_1X10:

>> +    {

>> +        u32 src_code[] = {

>> +            MEDIA_BUS_FMT_SBGGR10_1X10,

>> +            MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

>> +        };

>> +

>> +        return csid_find_code(src_code, ARRAY_SIZE(src_code),

>> +                      match_format_idx, match_code);

>> +    }

>> +    case MEDIA_BUS_FMT_Y10_1X10:

>> +    {

>> +        u32 src_code[] = {

>> +            MEDIA_BUS_FMT_Y10_1X10,

>> +            MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

>> +        };

>> +

>> +        return csid_find_code(src_code, ARRAY_SIZE(src_code),

>> +                      match_format_idx, match_code);

>> +    }

>> +    default:

>> +        if (match_format_idx > 0)

>> +            return 0;

>> +

>> +        return sink_code;

>> +    }

>> +}

>> +

>> +static void csid_subdev_init(struct csid_device *csid)

>> +{

>> +    csid->formats = csid_formats;

>> +    csid->nformats = ARRAY_SIZE(csid_formats);

>> +    csid->testgen.modes = csid_testgen_modes;

>> +    csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;

>> +}

>> +

>> +const struct csid_hw_ops csid_ops_4_7 = {

>> +    .configure_stream = csid_configure_stream,

>> +    .configure_testgen_pattern = csid_configure_testgen_pattern,

>> +    .hw_version = csid_hw_version,

>> +    .isr = csid_isr,

>> +    .reset = csid_reset,

>> +    .src_pad_code = csid_src_pad_code,

>> +    .subdev_init = csid_subdev_init,

>> +};

>> diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c

>> index be3fe76f3dc3..601bd810f2b0 100644

>> --- a/drivers/media/platform/qcom/camss/camss-csid.c

>> +++ b/drivers/media/platform/qcom/camss/camss-csid.c

>> @@ -26,405 +26,35 @@

>>   #define MSM_CSID_NAME "msm_csid"

>> -#define CAMSS_CSID_HW_VERSION        0x0

>> -#define CAMSS_CSID_CORE_CTRL_0        0x004

>> -#define CAMSS_CSID_CORE_CTRL_1        0x008

>> -#define CAMSS_CSID_RST_CMD(v)        ((v) == CAMSS_8x16 ? 0x00c : 0x010)

>> -#define CAMSS_CSID_CID_LUT_VC_n(v, n)    \

>> -            (((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))

>> -#define CAMSS_CSID_CID_n_CFG(v, n)    \

>> -            (((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))

>> -#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

>> -#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

>> -#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

>> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

>> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

>> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

>> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

>> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

>> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

>> -#define CAMSS_CSID_IRQ_CLEAR_CMD(v)    ((v) == CAMSS_8x16 ? 0x060 : 0x064)

>> -#define CAMSS_CSID_IRQ_MASK(v)        ((v) == CAMSS_8x16 ? 0x064 : 0x068)

>> -#define CAMSS_CSID_IRQ_STATUS(v)    ((v) == CAMSS_8x16 ? 0x068 : 0x06c)

>> -#define CAMSS_CSID_TG_CTRL(v)        ((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)

>> -#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

>> -#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

>> -#define CAMSS_CSID_TG_VC_CFG(v)        ((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)

>> -#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

>> -#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

>> -#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)    \

>> -            (((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))

>> -#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)    \

>> -            (((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))

>> -#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)    \

>> -            (((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))

>> -

>> -#define DATA_TYPE_EMBEDDED_DATA_8BIT    0x12

>> -#define DATA_TYPE_YUV422_8BIT        0x1e

>> -#define DATA_TYPE_RAW_6BIT        0x28

>> -#define DATA_TYPE_RAW_8BIT        0x2a

>> -#define DATA_TYPE_RAW_10BIT        0x2b

>> -#define DATA_TYPE_RAW_12BIT        0x2c

>> -#define DATA_TYPE_RAW_14BIT        0x2d

>> -

>> -#define DECODE_FORMAT_UNCOMPRESSED_6_BIT    0x0

>> -#define DECODE_FORMAT_UNCOMPRESSED_8_BIT    0x1

>> -#define DECODE_FORMAT_UNCOMPRESSED_10_BIT    0x2

>> -#define DECODE_FORMAT_UNCOMPRESSED_12_BIT    0x3

>> -#define DECODE_FORMAT_UNCOMPRESSED_14_BIT    0x8

>> -

>> -#define CSID_RESET_TIMEOUT_MS 500

>> -

>> -struct csid_format {

>> -    u32 code;

>> -    u8 data_type;

>> -    u8 decode_format;

>> -    u8 bpp;

>> -    u8 spp; /* bus samples per pixel */

>> -};

>> -

>> -static const struct csid_format csid_formats_8x16[] = {

>> -    {

>> -        MEDIA_BUS_FMT_UYVY8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_VYUY8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_YUYV8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_YVYU8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_Y10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -};

>> -

>> -static const struct csid_format csid_formats_8x96[] = {

>> -    {

>> -        MEDIA_BUS_FMT_UYVY8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_VYUY8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_YUYV8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_YVYU8_2X8,

>> -        DATA_TYPE_YUV422_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        2,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB8_1X8,

>> -        DATA_TYPE_RAW_8BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

>> -        8,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB12_1X12,

>> -        DATA_TYPE_RAW_12BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

>> -        12,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SBGGR14_1X14,

>> -        DATA_TYPE_RAW_14BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> -        14,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGBRG14_1X14,

>> -        DATA_TYPE_RAW_14BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> -        14,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SGRBG14_1X14,

>> -        DATA_TYPE_RAW_14BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> -        14,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_SRGGB14_1X14,

>> -        DATA_TYPE_RAW_14BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

>> -        14,

>> -        1,

>> -    },

>> -    {

>> -        MEDIA_BUS_FMT_Y10_1X10,

>> -        DATA_TYPE_RAW_10BIT,

>> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

>> -        10,

>> -        1,

>> -    },

>> -};

>> -static u32 csid_find_code(u32 *code, unsigned int n_code,

>> -              unsigned int index, u32 req_code)

>> +u32 csid_find_code(u32 *codes, unsigned int ncodes,

>> +           unsigned int match_format_idx, u32 match_code)

>>   {

>>       int i;

>> -    if (!req_code && (index >= n_code))

>> +    if (!match_code && (match_format_idx >= ncodes))

>>           return 0;

>> -    for (i = 0; i < n_code; i++)

>> -        if (req_code) {

>> -            if (req_code == code[i])

>> -                return req_code;

>> +    for (i = 0; i < ncodes; i++)

>> +        if (match_code) {

>> +            if (codes[i] == match_code)

>> +                return match_code;

>>           } else {

>> -            if (i == index)

>> -                return code[i];

>> -        }

>> -

>> -    return code[0];

>> -}

>> -

>> -static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

>> -                 unsigned int index, u32 src_req_code)

>> -{

>> -    if (csid->camss->version == CAMSS_8x16) {

>> -        if (index > 0)

>> -            return 0;

>> -

>> -        return sink_code;

>> -    } else if (csid->camss->version == CAMSS_8x96 ||

>> -           csid->camss->version == CAMSS_660) {

>> -        switch (sink_code) {

>> -        case MEDIA_BUS_FMT_SBGGR10_1X10:

>> -        {

>> -            u32 src_code[] = {

>> -                MEDIA_BUS_FMT_SBGGR10_1X10,

>> -                MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

>> -            };

>> -

>> -            return csid_find_code(src_code, ARRAY_SIZE(src_code),

>> -                          index, src_req_code);

>> -        }

>> -        case MEDIA_BUS_FMT_Y10_1X10:

>> -        {

>> -            u32 src_code[] = {

>> -                MEDIA_BUS_FMT_Y10_1X10,

>> -                MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

>> -            };

>> -

>> -            return csid_find_code(src_code, ARRAY_SIZE(src_code),

>> -                          index, src_req_code);

>> +            if (i == match_format_idx)

>> +                return codes[i];

>>           }

>> -        default:

>> -            if (index > 0)

>> -                return 0;

>> -            return sink_code;

>> -        }

>> -    } else {

>> -        return 0;

>> -    }

>> +    return codes[0];

>>   }

>> -static const struct csid_format *csid_get_fmt_entry(

>> +const struct csid_format *csid_get_fmt_entry(

>>                       const struct csid_format *formats,

>> -                    unsigned int nformat,

>> +                    unsigned int nformats,

>>                       u32 code)

>>   {

>>       unsigned int i;

>> -    for (i = 0; i < nformat; i++)

>> +    for (i = 0; i < nformats; i++)

>>           if (code == formats[i].code)

>>               return &formats[i];

>> @@ -433,28 +63,6 @@ static const struct csid_format *csid_get_fmt_entry(

>>       return &formats[0];

>>   }

>> -/*

>> - * csid_isr - CSID module interrupt handler

>> - * @irq: Interrupt line

>> - * @dev: CSID device

>> - *

>> - * Return IRQ_HANDLED on success

>> - */

>> -static irqreturn_t csid_isr(int irq, void *dev)

>> -{

>> -    struct csid_device *csid = dev;

>> -    enum camss_version ver = csid->camss->version;

>> -    u32 value;

>> -

>> -    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));

>> -    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));

>> -

>> -    if ((value >> 11) & 0x1)

>> -        complete(&csid->reset_complete);

>> -

>> -    return IRQ_HANDLED;

>> -}

>> -

>>   /*

>>    * csid_set_clock_rates - Calculate and set clock rates on CSID module

>>    * @csiphy: CSID device

>> @@ -521,31 +129,6 @@ static int csid_set_clock_rates(struct csid_device *csid)

>>       return 0;

>>   }

>> -/*

>> - * csid_reset - Trigger reset on CSID module and wait to complete

>> - * @csid: CSID device

>> - *

>> - * Return 0 on success or a negative error code otherwise

>> - */

>> -static int csid_reset(struct csid_device *csid)

>> -{

>> -    unsigned long time;

>> -

>> -    reinit_completion(&csid->reset_complete);

>> -

>> -    writel_relaxed(0x7fff, csid->base +

>> -               CAMSS_CSID_RST_CMD(csid->camss->version));

>> -

>> -    time = wait_for_completion_timeout(&csid->reset_complete,

>> -        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

>> -    if (!time) {

>> -        dev_err(csid->camss->dev, "CSID reset timeout\n");

>> -        return -EIO;

>> -    }

>> -

>> -    return 0;

>> -}

>> -

>>   /*

>>    * csid_set_power - Power on/off CSID module

>>    * @sd: CSID V4L2 subdevice

>> @@ -560,8 +143,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>>       int ret;

>>       if (on) {

>> -        u32 hw_version;

>> -

>>           ret = pm_runtime_get_sync(dev);

>>           if (ret < 0) {

>>               pm_runtime_put_sync(dev);

>> @@ -590,7 +171,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>>           enable_irq(csid->irq);

>> -        ret = csid_reset(csid);

>> +        ret = csid->ops->reset(csid);

>>           if (ret < 0) {

>>               disable_irq(csid->irq);

>>               camss_disable_clocks(csid->nclocks, csid->clock);

>> @@ -599,8 +180,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>>               return ret;

>>           }

>> -        hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

>> -        dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);

>> +        csid->ops->hw_version(csid);

>>       } else {

>>           disable_irq(csid->irq);

>>           camss_disable_clocks(csid->nclocks, csid->clock);

>> @@ -623,16 +203,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

>>   static int csid_set_stream(struct v4l2_subdev *sd, int enable)

>>   {

>>       struct csid_device *csid = v4l2_get_subdevdata(sd);

>> -    struct csid_testgen_config *tg = &csid->testgen;

>> -    enum camss_version ver = csid->camss->version;

>> -    u32 val;

>> +    int ret;

>>       if (enable) {

>> -        u8 vc = 0; /* Virtual Channel 0 */

>> -        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

>> -        u8 dt, dt_shift, df;

>> -        int ret;

>> -

>>           ret = v4l2_ctrl_handler_setup(&csid->ctrls);

>>           if (ret < 0) {

>>               dev_err(csid->camss->dev,

>> @@ -640,116 +213,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)

>>               return ret;

>>           }

>> -        if (!tg->enabled &&

>> +        if (!csid->testgen.enabled &&

>>               !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))

>>               return -ENOLINK;

>> -

>> -        if (tg->enabled) {

>> -            /* Config Test Generator */

>> -            struct v4l2_mbus_framefmt *f =

>> -                    &csid->fmt[MSM_CSID_PAD_SRC];

>> -            const struct csid_format *format = csid_get_fmt_entry(

>> -                    csid->formats, csid->nformats, f->code);

>> -            u32 num_bytes_per_line =

>> -                f->width * format->bpp * format->spp / 8;

>> -            u32 num_lines = f->height;

>> -

>> -            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

>> -            /* 1:0 VC */

>> -            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

>> -                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_VC_CFG(ver));

>> -

>> -            /* 28:16 bytes per lines, 12:0 num of lines */

>> -            val = ((num_bytes_per_line & 0x1fff) << 16) |

>> -                  (num_lines & 0x1fff);

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));

>> -

>> -            dt = format->data_type;

>> -

>> -            /* 5:0 data type */

>> -            val = dt;

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));

>> -

>> -            /* 2:0 output test pattern */

>> -            val = tg->payload_mode;

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));

>> -

>> -            df = format->decode_format;

>> -        } else {

>> -            struct v4l2_mbus_framefmt *f =

>> -                    &csid->fmt[MSM_CSID_PAD_SINK];

>> -            const struct csid_format *format = csid_get_fmt_entry(

>> -                    csid->formats, csid->nformats, f->code);

>> -            struct csid_phy_config *phy = &csid->phy;

>> -

>> -            val = phy->lane_cnt - 1;

>> -            val |= phy->lane_assign << 4;

>> -

>> -            writel_relaxed(val,

>> -                       csid->base + CAMSS_CSID_CORE_CTRL_0);

>> -

>> -            val = phy->csiphy_id << 17;

>> -            val |= 0x9;

>> -

>> -            writel_relaxed(val,

>> -                       csid->base + CAMSS_CSID_CORE_CTRL_1);

>> -

>> -            dt = format->data_type;

>> -            df = format->decode_format;

>> -        }

>> -

>> -        /* Config LUT */

>> -

>> -        dt_shift = (cid % 4) * 8;

>> -

>> -        val = readl_relaxed(csid->base +

>> -                    CAMSS_CSID_CID_LUT_VC_n(ver, vc));

>> -        val &= ~(0xff << dt_shift);

>> -        val |= dt << dt_shift;

>> -        writel_relaxed(val, csid->base +

>> -                   CAMSS_CSID_CID_LUT_VC_n(ver, vc));

>> -

>> -        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

>> -        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

>> -        val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

>> -        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

>> -

>> -        if (csid->camss->version == CAMSS_8x96 ||

>> -            csid->camss->version == CAMSS_660) {

>> -            u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

>> -            u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

>> -

>> -            if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

>> -                 src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

>> -                (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

>> -                 src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

>> -                val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

>> -                val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

>> -                val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

>> -            }

>> -        }

>> -

>> -        writel_relaxed(val, csid->base +

>> -                   CAMSS_CSID_CID_n_CFG(ver, cid));

>> -

>> -        if (tg->enabled) {

>> -            val = CAMSS_CSID_TG_CTRL_ENABLE;

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_CTRL(ver));

>> -        }

>> -    } else {

>> -        if (tg->enabled) {

>> -            val = CAMSS_CSID_TG_CTRL_DISABLE;

>> -            writel_relaxed(val, csid->base +

>> -                       CAMSS_CSID_TG_CTRL(ver));

>> -        }

>>       }

>> +    csid->ops->configure_stream(csid, enable);

>> +

>>       return 0;

>>   }

>> @@ -818,7 +288,7 @@ static void csid_try_format(struct csid_device *csid,

>>               *fmt = *__csid_get_format(csid, cfg,

>>                                 MSM_CSID_PAD_SINK, which);

>> -            fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);

>> +            fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);

>>           } else {

>>               /* Test generator is enabled, set format on source */

>>               /* pad to allow test generator usage */

>> @@ -868,7 +338,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,

>>                                MSM_CSID_PAD_SINK,

>>                                code->which);

>> -            code->code = csid_src_pad_code(csid, sink_fmt->code,

>> +            code->code = csid->ops->src_pad_code(csid, sink_fmt->code,

>>                                  code->index, 0);

>>               if (!code->code)

>>                   return -EINVAL;

>> @@ -1004,15 +474,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)

>>       return csid_set_format(sd, fh ? fh->pad : NULL, &format);

>>   }

>> -static const char * const csid_test_pattern_menu[] = {

>> -    "Disabled",

>> -    "Incrementing",

>> -    "Alternating 0x55/0xAA",

>> -    "All Zeros 0x00",

>> -    "All Ones 0xFF",

>> -    "Pseudo-random Data",

>> -};

>> -

>>   /*

>>    * csid_set_test_pattern - Set test generator's pattern mode

>>    * @csid: CSID device

>> @@ -1030,25 +491,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)

>>       tg->enabled = !!value;

>> -    switch (value) {

>> -    case 1:

>> -        tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;

>> -        break;

>> -    case 2:

>> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;

>> -        break;

>> -    case 3:

>> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;

>> -        break;

>> -    case 4:

>> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;

>> -        break;

>> -    case 5:

>> -        tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;

>> -        break;

>> -    }

>> -

>> -    return 0;

>> +    return csid->ops->configure_testgen_pattern(csid, value);

>>   }

>>   /*

>> @@ -1097,17 +540,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>>       csid->id = id;

>>       if (camss->version == CAMSS_8x16) {

>> -        csid->formats = csid_formats_8x16;

>> -        csid->nformats =

>> -                ARRAY_SIZE(csid_formats_8x16);

>> +        csid->ops = &csid_ops_4_1;

>>       } else if (camss->version == CAMSS_8x96 ||

>>              camss->version == CAMSS_660) {

>> -        csid->formats = csid_formats_8x96;

>> -        csid->nformats =

>> -                ARRAY_SIZE(csid_formats_8x96);

>> +        csid->ops = &csid_ops_4_7;

>>       } else {

>>           return -EINVAL;

>>       }

>> +    csid->ops->subdev_init(csid);

>>       /* Memory */

>> @@ -1130,7 +570,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>>       csid->irq = r->start;

>>       snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",

>>            dev_name(dev), MSM_CSID_NAME, csid->id);

>> -    ret = devm_request_irq(dev, csid->irq, csid_isr,

>> +    ret = devm_request_irq(dev, csid->irq, csid->ops->isr,

>>           IRQF_TRIGGER_RISING, csid->irq_name, csid);

>>       if (ret < 0) {

>>           dev_err(dev, "request_irq failed: %d\n", ret);

>> @@ -1341,8 +781,8 @@ int msm_csid_register_entity(struct csid_device *csid,

>>       csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,

>>                   &csid_ctrl_ops, V4L2_CID_TEST_PATTERN,

>> -                ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,

>> -                csid_test_pattern_menu);

>> +                csid->testgen.nmodes, 0, 0,


enum csid_testgen_mode has the test patterns id's numbered from 0 to MAX_SUPPORTED.
So the MAX_SUPPORTED is the number of test patterns *minus one*.
csid->testgen.nmodes points to the csid_testgen_modes[] array which contains the
test patterns name *plus* "Disabled" as the first element.
Thus the old (ARRAY_SIZE(csid_test_pattern_menu) - 1) is greater by one than
csid->testgen.nmodes.
By passing csid->testgen.nmodes as the max value to v4l2_ctrl_new_std_menu_items()
you exclude the last test pattern from the menu - you can check the output of
"v4l2-ctl -L -d <csid subdevice>".
IMHO the logic would be simpler, if the test patterns were numbered starting from 1, not 0,
leaving the value of 0 to "TG disabled".


Thanks,
Andrey

>> +                csid->testgen.modes);

>>       if (csid->ctrls.error) {

>>           dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);

>> diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h

>> index 02fc34ee8a41..d40194e2bed3 100644

>> --- a/drivers/media/platform/qcom/camss/camss-csid.h

>> +++ b/drivers/media/platform/qcom/camss/camss-csid.h

>> @@ -11,6 +11,7 @@

>>   #define QC_MSM_CAMSS_CSID_H

>>   #include <linux/clk.h>

>> +#include <linux/interrupt.h>

>>   #include <media/media-entity.h>

>>   #include <media/v4l2-ctrls.h>

>>   #include <media/v4l2-device.h>

>> @@ -70,19 +71,50 @@

>>   #define PLAIN_FORMAT_PLAIN16    0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */

>>   #define PLAIN_FORMAT_PLAIN32    0x2 /* supports UNCOMPRESSED_20_BIT */

>> +#define CSID_RESET_TIMEOUT_MS 500

>> -enum csid_payload_mode {

>> +

>> +enum csid_testgen_mode {

>>       CSID_PAYLOAD_MODE_INCREMENTING = 0,

>>       CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,

>>       CSID_PAYLOAD_MODE_ALL_ZEROES = 2,

>>       CSID_PAYLOAD_MODE_ALL_ONES = 3,

>>       CSID_PAYLOAD_MODE_RANDOM = 4,

>>       CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,

>> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,

>> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,

>> +    CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,

>> +    CSID_PAYLOAD_MODE_COLOR_BOX = 7,

>> +    CSID_PAYLOAD_MODE_COLOR_BARS = 8,

>> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,

>> +};

>> +

>> +static const char * const csid_testgen_modes[] = {

>> +    "Disabled",

>> +    "Incrementing",

>> +    "Alternating 0x55/0xAA",

>> +    "All Zeros 0x00",

>> +    "All Ones 0xFF",

>> +    "Pseudo-random Data",

>> +    "User Specified",

>> +    "Complex pattern",

>> +    "Color box",

>> +    "Color bars",

>> +};

>> +

>> +struct csid_format {

>> +    u32 code;

>> +    u8 data_type;

>> +    u8 decode_format;

>> +    u8 bpp;

>> +    u8 spp; /* bus samples per pixel */

>>   };

>>   struct csid_testgen_config {

>> +    enum csid_testgen_mode mode;

>> +    const char * const*modes;

>> +    u8 nmodes;

>>       u8 enabled;

>> -    enum csid_payload_mode payload_mode;

>>   };

>>   struct csid_phy_config {

>> @@ -91,6 +123,65 @@ struct csid_phy_config {

>>       u32 lane_assign;

>>   };

>> +struct csid_device;

>> +

>> +struct csid_hw_ops {

>> +    /*

>> +     * configure_stream - Configures and starts CSID input stream

>> +     * @csid: CSID device

>> +     */

>> +    void (*configure_stream)(struct csid_device *csid, u8 enable);

>> +

>> +    /*

>> +     * configure_testgen_pattern - Validates and configures output pattern mode

>> +     * of test pattern generator

>> +     * @csid: CSID device

>> +     */

>> +    int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);

>> +

>> +    /*

>> +     * hw_version - Read hardware version register from hardware

>> +     * @csid: CSID device

>> +     */

>> +    u32 (*hw_version)(struct csid_device *csid);

>> +

>> +    /*

>> +     * isr - CSID module interrupt service routine

>> +     * @irq: Interrupt line

>> +     * @dev: CSID device

>> +     *

>> +     * Return IRQ_HANDLED on success

>> +     */

>> +    irqreturn_t (*isr)(int irq, void *dev);

>> +

>> +    /*

>> +     * reset - Trigger reset on CSID module and wait to complete

>> +     * @csid: CSID device

>> +     *

>> +     * Return 0 on success or a negative error code otherwise

>> +     */

>> +    int (*reset)(struct csid_device *csid);

>> +

>> +    /*

>> +     * src_pad_code - Pick an output/src format based on the input/sink format

>> +     * @csid: CSID device

>> +     * @sink_code: The sink format of the input

>> +     * @match_format_idx: Request preferred index, as defined by subdevice csid_format.

>> +     *    Set @match_code to 0 if used.

>> +     * @match_code: Request preferred code, set @match_format_idx to 0 if used

>> +     *

>> +     * Return 0 on failure or src format code otherwise

>> +     */

>> +    u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,

>> +                unsigned int match_format_idx, u32 match_code);

>> +

>> +    /*

>> +     * subdev_init - Initialize CSID device according for hardware revision

>> +     * @csid: CSID device

>> +     */

>> +    void (*subdev_init)(struct csid_device *csid);

>> +};

>> +

>>   struct csid_device {

>>       struct camss *camss;

>>       u8 id;

>> @@ -110,10 +201,37 @@ struct csid_device {

>>       struct v4l2_ctrl *testgen_mode;

>>       const struct csid_format *formats;

>>       unsigned int nformats;

>> +    const struct csid_hw_ops *ops;

>>   };

>>   struct resources;

>> +

>> +/*

>> + * csid_find_code - Find a format code in an array using array index or format code

>> + * @codes: Array of format codes

>> + * @ncodes: Length of @code array

>> + * @req_format_idx: Request preferred index, as defined by subdevice csid_format.

>> + *    Set @match_code to 0 if used.

>> + * @match_code: Request preferred code, set @req_format_idx to 0 if used

>> + *

>> + * Return 0 on failure or format code otherwise

>> + */

>> +u32 csid_find_code(u32 *codes, unsigned int ncode,

>> +           unsigned int match_format_idx, u32 match_code);

>> +

>> +/*

>> + * csid_get_fmt_entry - Find csid_format entry with matching format code

>> + * @formats: Array of format csid_format entries

>> + * @nformats: Length of @nformats array

>> + * @code: Desired format code

>> + *

>> + * Return formats[0] on failure to find code

>> + */

>> +const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,

>> +                         unsigned int nformats,

>> +                         u32 code);

>> +

>>   int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

>>                const struct resources *res, u8 id);

>> @@ -124,4 +242,8 @@ void msm_csid_unregister_entity(struct csid_device *csid);

>>   void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);

>> +

>> +extern const struct csid_hw_ops csid_ops_4_1;

>> +extern const struct csid_hw_ops csid_ops_4_7;

>> +

>>   #endif /* QC_MSM_CAMSS_CSID_H */

>>
Robert Foss Feb. 22, 2021, 6:13 p.m. | #3
On Sun, 21 Feb 2021 at 18:50, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>

> Hi Robert,

>

> After reviewing the [PATCH v5 10/22], I noticed that this patch also

> has a problematic test_pattern control implementation.

>

> See below.

>

> On 21.02.2021 18:15, Andrey Konovalov wrote:

> > Hi Robert,

> >

> > Thank you for your patch!

> >

> > Reviewed-by: Andrey Konovalov <andrey.konovalov@linaro.org>

> >

> > Thanks,

> > Andrey

> >

> > On 17.02.2021 14:21, Robert Foss wrote:

> >> In order to support Qualcomm ISP hardware architectures that diverge

> >> from older architectures, the CSID subdevice drivers needs to be refactored

> >> to better abstract the different ISP hardware architectures.

> >>

> >> Signed-off-by: Robert Foss <robert.foss@linaro.org>

> >> ---

> >>

> >> Changes since v1

> >>   - kernel test robot: Add missing include, interrupt.h

> >>

> >> Changes since v4

> >>   - Andrey: Removed whitespace from some includes

> >>   - Andrey: Removed unused enum

> >>

> >>

> >>   drivers/media/platform/qcom/camss/Makefile    |   2 +

> >>   .../platform/qcom/camss/camss-csid-4-1.c      | 330 ++++++++++

> >>   .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++

> >>   .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------

> >>   .../media/platform/qcom/camss/camss-csid.h    | 126 +++-

> >>   5 files changed, 890 insertions(+), 590 deletions(-)

> >>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c

> >>   create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

> >>

> >> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile

> >> index 052c4f405fa3..cff388b653ba 100644

> >> --- a/drivers/media/platform/qcom/camss/Makefile

> >> +++ b/drivers/media/platform/qcom/camss/Makefile

> >> @@ -4,6 +4,8 @@

> >>   qcom-camss-objs += \

> >>           camss.o \

> >>           camss-csid.o \

> >> +        camss-csid-4-1.o \

> >> +        camss-csid-4-7.o \

> >>           camss-csiphy-2ph-1-0.o \

> >>           camss-csiphy-3ph-1-0.o \

> >>           camss-csiphy.o \

> >> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

> >> new file mode 100644

> >> index 000000000000..c92077a7f758

> >> --- /dev/null

> >> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c

> >> @@ -0,0 +1,330 @@

> >> +// SPDX-License-Identifier: GPL-2.0

> >> +/*

> >> + * camss-csid-4-1.c

> >> + *

> >> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

> >> + *

> >> + * Copyright (C) 2020 Linaro Ltd.

> >> + */

> >> +

> >> +#include <linux/completion.h>

> >> +#include <linux/interrupt.h>

> >> +#include <linux/io.h>

> >> +#include <linux/kernel.h>

> >> +#include <linux/of.h>

> >> +

> >> +#include "camss-csid.h"

> >> +#include "camss.h"

> >> +

> >> +#define CAMSS_CSID_HW_VERSION        0x0

> >> +#define CAMSS_CSID_CORE_CTRL_0        0x004

> >> +#define CAMSS_CSID_CORE_CTRL_1        0x008

> >> +#define CAMSS_CSID_RST_CMD        0x00c

> >> +#define CAMSS_CSID_CID_LUT_VC_n(n)    (0x010 + 0x4 * (n))

> >> +#define CAMSS_CSID_CID_n_CFG(n)        (0x020 + 0x4 * (n))

> >> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

> >> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

> >> +#define CAMSS_CSID_IRQ_CLEAR_CMD    0x060

> >> +#define CAMSS_CSID_IRQ_MASK        0x064

> >> +#define CAMSS_CSID_IRQ_STATUS        0x068

> >> +#define CAMSS_CSID_TG_CTRL        0x0a0

> >> +#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

> >> +#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

> >> +#define CAMSS_CSID_TG_VC_CFG        0x0a4

> >> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

> >> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

> >> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)    (0x0ac + 0xc * (n))

> >> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)    (0x0b0 + 0xc * (n))

> >> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)    (0x0b4 + 0xc * (n))

> >> +

> >> +

> >> +static const struct csid_format csid_formats[] = {

> >> +    {

> >> +        MEDIA_BUS_FMT_UYVY8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_VYUY8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_YUYV8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_YVYU8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_Y10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +};

> >> +

> >> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

> >> +{

> >> +    struct csid_testgen_config *tg = &csid->testgen;

> >> +    u32 val;

> >> +

> >> +    if (enable) {

> >> +        struct v4l2_mbus_framefmt *input_format;

> >> +        const struct csid_format *format;

> >> +        u8 vc = 0; /* Virtual Channel 0 */

> >> +        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> >> +        u8 dt_shift;

> >> +

> >> +        if (tg->enabled) {

> >> +            /* Config Test Generator */

> >> +            u32 num_lines, num_bytes_per_line;

> >> +

> >> +            input_format = &csid->fmt[MSM_CSID_PAD_SRC];

> >> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

> >> +                            input_format->code);

> >> +            num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

> >> +            num_lines = input_format->height;

> >> +

> >> +            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> >> +            /* 1:0 VC */

> >> +            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> >> +                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

> >> +

> >> +            /* 28:16 bytes per lines, 12:0 num of lines */

> >> +            val = ((num_bytes_per_line & 0x1fff) << 16) |

> >> +                  (num_lines & 0x1fff);

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

> >> +

> >> +            /* 5:0 data type */

> >> +            val = format->data_type;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

> >> +

> >> +            /* 2:0 output test pattern */

> >> +            val = tg->mode;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

> >> +        } else {

> >> +            struct csid_phy_config *phy = &csid->phy;

> >> +

> >> +            input_format = &csid->fmt[MSM_CSID_PAD_SINK];

> >> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

> >> +                            input_format->code);

> >> +

> >> +            val = phy->lane_cnt - 1;

> >> +            val |= phy->lane_assign << 4;

> >> +

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

> >> +

> >> +            val = phy->csiphy_id << 17;

> >> +            val |= 0x9;

> >> +

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

> >> +        }

> >> +

> >> +        /* Config LUT */

> >> +

> >> +        dt_shift = (cid % 4) * 8;

> >> +        val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> >> +        val &= ~(0xff << dt_shift);

> >> +        val |= format->data_type << dt_shift;

> >> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> >> +

> >> +        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> >> +        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> >> +        val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> >> +        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> >> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

> >> +

> >> +        if (tg->enabled) {

> >> +            val = CAMSS_CSID_TG_CTRL_ENABLE;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> >> +        }

> >> +    } else {

> >> +        if (tg->enabled) {

> >> +            val = CAMSS_CSID_TG_CTRL_DISABLE;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> >> +        }

> >> +    }

> >> +}

> >> +

> >> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

> >> +{

> >> +    s32 regval = val - 1;

> >> +

> >> +    if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)

> >> +        csid->testgen.mode = regval;

>

> regval of 0 is the valid "Incrementing" test pattern. The condition above

> should be "regval >= 0", not "regval > 0".


Ack

>

> >> +

> >> +    return 0;

> >> +}

> >> +

> >> +static u32 csid_hw_version(struct csid_device *csid)

> >> +{

> >> +    u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> >> +

> >> +    dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

> >> +

> >> +    return hw_version;

> >> +}

> >> +

> >> +static irqreturn_t csid_isr(int irq, void *dev)

> >> +{

> >> +    struct csid_device *csid = dev;

> >> +    u32 value;

> >> +

> >> +    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

> >> +    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

> >> +

> >> +    if ((value >> 11) & 0x1)

> >> +        complete(&csid->reset_complete);

> >> +

> >> +    return IRQ_HANDLED;

> >> +}

> >> +

> >> +static int csid_reset(struct csid_device *csid)

> >> +{

> >> +    unsigned long time;

> >> +

> >> +    reinit_completion(&csid->reset_complete);

> >> +

> >> +    writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

> >> +

> >> +    time = wait_for_completion_timeout(&csid->reset_complete,

> >> +        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> >> +    if (!time) {

> >> +        dev_err(csid->camss->dev, "CSID reset timeout\n");

> >> +        return -EIO;

> >> +    }

> >> +

> >> +    return 0;

> >> +}

> >> +

> >> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> >> +                 unsigned int match_format_idx, u32 match_code)

> >> +{

> >> +    if (match_format_idx > 0)

> >> +        return 0;

> >> +

> >> +    return sink_code;

> >> +}

> >> +

> >> +static void csid_subdev_init(struct csid_device *csid)

> >> +{

> >> +    csid->formats = csid_formats;

> >> +    csid->nformats = ARRAY_SIZE(csid_formats);

> >> +    csid->testgen.modes = csid_testgen_modes;

> >> +    csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;

> >> +}

> >> +

> >> +const struct csid_hw_ops csid_ops_4_1 = {

> >> +    .configure_stream = csid_configure_stream,

> >> +    .configure_testgen_pattern = csid_configure_testgen_pattern,

> >> +    .hw_version = csid_hw_version,

> >> +    .isr = csid_isr,

> >> +    .reset = csid_reset,

> >> +    .src_pad_code = csid_src_pad_code,

> >> +    .subdev_init = csid_subdev_init,

> >> +};

> >> diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

> >> new file mode 100644

> >> index 000000000000..16a69b140f4e

> >> --- /dev/null

> >> +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c

> >> @@ -0,0 +1,406 @@

> >> +// SPDX-License-Identifier: GPL-2.0

> >> +/*

> >> + * camss-csid-4-7.c

> >> + *

> >> + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module

> >> + *

> >> + * Copyright (C) 2020 Linaro Ltd.

> >> + */

> >> +#include <linux/completion.h>

> >> +#include <linux/interrupt.h>

> >> +#include <linux/io.h>

> >> +#include <linux/kernel.h>

> >> +#include <linux/of.h>

> >> +

> >> +#include "camss-csid.h"

> >> +#include "camss.h"

> >> +

> >> +#define CAMSS_CSID_HW_VERSION        0x0

> >> +#define CAMSS_CSID_CORE_CTRL_0        0x004

> >> +#define CAMSS_CSID_CORE_CTRL_1        0x008

> >> +#define CAMSS_CSID_RST_CMD        0x010

> >> +#define CAMSS_CSID_CID_LUT_VC_n(n)    (0x014 + 0x4 * (n))

> >> +#define CAMSS_CSID_CID_n_CFG(n)        (0x024 + 0x4 * (n))

> >> +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

> >> +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

> >> +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

> >> +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

> >> +#define CAMSS_CSID_IRQ_CLEAR_CMD    0x064

> >> +#define CAMSS_CSID_IRQ_MASK        0x068

> >> +#define CAMSS_CSID_IRQ_STATUS        0x06c

> >> +#define CAMSS_CSID_TG_CTRL        0x0a8

> >> +#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

> >> +#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

> >> +#define CAMSS_CSID_TG_VC_CFG        0x0ac

> >> +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

> >> +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

> >> +#define CAMSS_CSID_TG_DT_n_CGG_0(n)    (0x0b4 + 0xc * (n))

> >> +#define CAMSS_CSID_TG_DT_n_CGG_1(n)    (0x0b8 + 0xc * (n))

> >> +#define CAMSS_CSID_TG_DT_n_CGG_2(n)    (0x0bc + 0xc * (n))

> >> +

> >> +

> >> +static const struct csid_format csid_formats[] = {

> >> +    {

> >> +        MEDIA_BUS_FMT_UYVY8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_VYUY8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_YUYV8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_YVYU8_2X8,

> >> +        DATA_TYPE_YUV422_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        2,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB8_1X8,

> >> +        DATA_TYPE_RAW_8BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> +        8,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB12_1X12,

> >> +        DATA_TYPE_RAW_12BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> +        12,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SBGGR14_1X14,

> >> +        DATA_TYPE_RAW_14BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> +        14,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGBRG14_1X14,

> >> +        DATA_TYPE_RAW_14BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> +        14,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SGRBG14_1X14,

> >> +        DATA_TYPE_RAW_14BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> +        14,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_SRGGB14_1X14,

> >> +        DATA_TYPE_RAW_14BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> +        14,

> >> +        1,

> >> +    },

> >> +    {

> >> +        MEDIA_BUS_FMT_Y10_1X10,

> >> +        DATA_TYPE_RAW_10BIT,

> >> +        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> +        10,

> >> +        1,

> >> +    },

> >> +};

> >> +

> >> +static void csid_configure_stream(struct csid_device *csid, u8 enable)

> >> +{

> >> +    struct csid_testgen_config *tg = &csid->testgen;

> >> +    u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

> >> +    u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

> >> +    u32 val;

> >> +

> >> +    if (enable) {

> >> +        struct v4l2_mbus_framefmt *input_format;

> >> +        const struct csid_format *format;

> >> +        u8 vc = 0; /* Virtual Channel 0 */

> >> +        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> >> +        u8 dt_shift;

> >> +

> >> +        if (tg->enabled) {

> >> +            /* Config Test Generator */

> >> +            u32 num_bytes_per_line, num_lines;

> >> +

> >> +            input_format = &csid->fmt[MSM_CSID_PAD_SRC];

> >> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

> >> +                            input_format->code);

> >> +            num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;

> >> +            num_lines = input_format->height;

> >> +

> >> +            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> >> +            /* 1:0 VC */

> >> +            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> >> +                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);

> >> +

> >> +            /* 28:16 bytes per lines, 12:0 num of lines */

> >> +            val = ((num_bytes_per_line & 0x1fff) << 16) |

> >> +                  (num_lines & 0x1fff);

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));

> >> +

> >> +            /* 5:0 data type */

> >> +            val = format->data_type;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));

> >> +

> >> +            /* 2:0 output test pattern */

> >> +            val = tg->mode;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));

> >> +        } else {

> >> +            struct csid_phy_config *phy = &csid->phy;

> >> +

> >> +            input_format = &csid->fmt[MSM_CSID_PAD_SINK];

> >> +            format = csid_get_fmt_entry(csid->formats, csid->nformats,

> >> +                            input_format->code);

> >> +

> >> +            val = phy->lane_cnt - 1;

> >> +            val |= phy->lane_assign << 4;

> >> +

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);

> >> +

> >> +            val = phy->csiphy_id << 17;

> >> +            val |= 0x9;

> >> +

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);

> >> +        }

> >> +

> >> +        /* Config LUT */

> >> +

> >> +        dt_shift = (cid % 4) * 8;

> >> +

> >> +        val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> >> +        val &= ~(0xff << dt_shift);

> >> +        val |= format->data_type << dt_shift;

> >> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));

> >> +

> >> +        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> >> +        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> >> +        val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> >> +        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> >> +

> >> +        if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

> >> +             src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

> >> +            (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

> >> +             src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

> >> +            val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

> >> +            val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

> >> +            val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

> >> +        }

> >> +

> >> +        writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));

> >> +

> >> +        if (tg->enabled) {

> >> +            val = CAMSS_CSID_TG_CTRL_ENABLE;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> >> +        }

> >> +    } else {

> >> +        if (tg->enabled) {

> >> +            val = CAMSS_CSID_TG_CTRL_DISABLE;

> >> +            writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);

> >> +        }

> >> +    }

> >> +}

> >> +

> >> +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)

> >> +{

> >> +    s32 regval = val - 1;

> >> +

> >> +    if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)

> >> +        csid->testgen.mode = regval;

>

> regval of 0 is the valid "Incrementing" test pattern. The condition above

> should be "regval >= 0", not "regval > 0".


Ack

>

> >> +    return 0;

> >> +}

> >> +

> >> +static u32 csid_hw_version(struct csid_device *csid)

> >> +{

> >> +    u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> >> +

> >> +    dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);

> >> +

> >> +    return hw_version;

> >> +}

> >> +

> >> +/*

> >> + * isr - CSID module interrupt service routine

> >> + * @irq: Interrupt line

> >> + * @dev: CSID device

> >> + *

> >> + * Return IRQ_HANDLED on success

> >> + */

> >> +static irqreturn_t csid_isr(int irq, void *dev)

> >> +{

> >> +    struct csid_device *csid = dev;

> >> +    u32 value;

> >> +

> >> +    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);

> >> +    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);

> >> +

> >> +    if ((value >> 11) & 0x1)

> >> +        complete(&csid->reset_complete);

> >> +

> >> +    return IRQ_HANDLED;

> >> +}

> >> +

> >> +/*

> >> + * csid_reset - Trigger reset on CSID module and wait to complete

> >> + * @csid: CSID device

> >> + *

> >> + * Return 0 on success or a negative error code otherwise

> >> + */

> >> +static int csid_reset(struct csid_device *csid)

> >> +{

> >> +    unsigned long time;

> >> +

> >> +    reinit_completion(&csid->reset_complete);

> >> +

> >> +    writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);

> >> +

> >> +    time = wait_for_completion_timeout(&csid->reset_complete,

> >> +        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> >> +    if (!time) {

> >> +        dev_err(csid->camss->dev, "CSID reset timeout\n");

> >> +        return -EIO;

> >> +    }

> >> +

> >> +    return 0;

> >> +}

> >> +

> >> +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> >> +                 unsigned int match_format_idx, u32 match_code)

> >> +{

> >> +    switch (sink_code) {

> >> +    case MEDIA_BUS_FMT_SBGGR10_1X10:

> >> +    {

> >> +        u32 src_code[] = {

> >> +            MEDIA_BUS_FMT_SBGGR10_1X10,

> >> +            MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

> >> +        };

> >> +

> >> +        return csid_find_code(src_code, ARRAY_SIZE(src_code),

> >> +                      match_format_idx, match_code);

> >> +    }

> >> +    case MEDIA_BUS_FMT_Y10_1X10:

> >> +    {

> >> +        u32 src_code[] = {

> >> +            MEDIA_BUS_FMT_Y10_1X10,

> >> +            MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

> >> +        };

> >> +

> >> +        return csid_find_code(src_code, ARRAY_SIZE(src_code),

> >> +                      match_format_idx, match_code);

> >> +    }

> >> +    default:

> >> +        if (match_format_idx > 0)

> >> +            return 0;

> >> +

> >> +        return sink_code;

> >> +    }

> >> +}

> >> +

> >> +static void csid_subdev_init(struct csid_device *csid)

> >> +{

> >> +    csid->formats = csid_formats;

> >> +    csid->nformats = ARRAY_SIZE(csid_formats);

> >> +    csid->testgen.modes = csid_testgen_modes;

> >> +    csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;

> >> +}

> >> +

> >> +const struct csid_hw_ops csid_ops_4_7 = {

> >> +    .configure_stream = csid_configure_stream,

> >> +    .configure_testgen_pattern = csid_configure_testgen_pattern,

> >> +    .hw_version = csid_hw_version,

> >> +    .isr = csid_isr,

> >> +    .reset = csid_reset,

> >> +    .src_pad_code = csid_src_pad_code,

> >> +    .subdev_init = csid_subdev_init,

> >> +};

> >> diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c

> >> index be3fe76f3dc3..601bd810f2b0 100644

> >> --- a/drivers/media/platform/qcom/camss/camss-csid.c

> >> +++ b/drivers/media/platform/qcom/camss/camss-csid.c

> >> @@ -26,405 +26,35 @@

> >>   #define MSM_CSID_NAME "msm_csid"

> >> -#define CAMSS_CSID_HW_VERSION        0x0

> >> -#define CAMSS_CSID_CORE_CTRL_0        0x004

> >> -#define CAMSS_CSID_CORE_CTRL_1        0x008

> >> -#define CAMSS_CSID_RST_CMD(v)        ((v) == CAMSS_8x16 ? 0x00c : 0x010)

> >> -#define CAMSS_CSID_CID_LUT_VC_n(v, n)    \

> >> -            (((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))

> >> -#define CAMSS_CSID_CID_n_CFG(v, n)    \

> >> -            (((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))

> >> -#define CAMSS_CSID_CID_n_CFG_ISPIF_EN    BIT(0)

> >> -#define CAMSS_CSID_CID_n_CFG_RDI_EN    BIT(1)

> >> -#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT    4

> >> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8        (0 << 8)

> >> -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16        (1 << 8)

> >> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB    (0 << 9)

> >> -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB    (1 << 9)

> >> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP        (0 << 10)

> >> -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING    (1 << 10)

> >> -#define CAMSS_CSID_IRQ_CLEAR_CMD(v)    ((v) == CAMSS_8x16 ? 0x060 : 0x064)

> >> -#define CAMSS_CSID_IRQ_MASK(v)        ((v) == CAMSS_8x16 ? 0x064 : 0x068)

> >> -#define CAMSS_CSID_IRQ_STATUS(v)    ((v) == CAMSS_8x16 ? 0x068 : 0x06c)

> >> -#define CAMSS_CSID_TG_CTRL(v)        ((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)

> >> -#define CAMSS_CSID_TG_CTRL_DISABLE    0xa06436

> >> -#define CAMSS_CSID_TG_CTRL_ENABLE    0xa06437

> >> -#define CAMSS_CSID_TG_VC_CFG(v)        ((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)

> >> -#define CAMSS_CSID_TG_VC_CFG_H_BLANKING        0x3ff

> >> -#define CAMSS_CSID_TG_VC_CFG_V_BLANKING        0x7f

> >> -#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)    \

> >> -            (((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))

> >> -#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)    \

> >> -            (((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))

> >> -#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)    \

> >> -            (((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))

> >> -

> >> -#define DATA_TYPE_EMBEDDED_DATA_8BIT    0x12

> >> -#define DATA_TYPE_YUV422_8BIT        0x1e

> >> -#define DATA_TYPE_RAW_6BIT        0x28

> >> -#define DATA_TYPE_RAW_8BIT        0x2a

> >> -#define DATA_TYPE_RAW_10BIT        0x2b

> >> -#define DATA_TYPE_RAW_12BIT        0x2c

> >> -#define DATA_TYPE_RAW_14BIT        0x2d

> >> -

> >> -#define DECODE_FORMAT_UNCOMPRESSED_6_BIT    0x0

> >> -#define DECODE_FORMAT_UNCOMPRESSED_8_BIT    0x1

> >> -#define DECODE_FORMAT_UNCOMPRESSED_10_BIT    0x2

> >> -#define DECODE_FORMAT_UNCOMPRESSED_12_BIT    0x3

> >> -#define DECODE_FORMAT_UNCOMPRESSED_14_BIT    0x8

> >> -

> >> -#define CSID_RESET_TIMEOUT_MS 500

> >> -

> >> -struct csid_format {

> >> -    u32 code;

> >> -    u8 data_type;

> >> -    u8 decode_format;

> >> -    u8 bpp;

> >> -    u8 spp; /* bus samples per pixel */

> >> -};

> >> -

> >> -static const struct csid_format csid_formats_8x16[] = {

> >> -    {

> >> -        MEDIA_BUS_FMT_UYVY8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_VYUY8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_YUYV8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_YVYU8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_Y10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -};

> >> -

> >> -static const struct csid_format csid_formats_8x96[] = {

> >> -    {

> >> -        MEDIA_BUS_FMT_UYVY8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_VYUY8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_YUYV8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_YVYU8_2X8,

> >> -        DATA_TYPE_YUV422_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        2,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB8_1X8,

> >> -        DATA_TYPE_RAW_8BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_8_BIT,

> >> -        8,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB12_1X12,

> >> -        DATA_TYPE_RAW_12BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_12_BIT,

> >> -        12,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SBGGR14_1X14,

> >> -        DATA_TYPE_RAW_14BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> -        14,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGBRG14_1X14,

> >> -        DATA_TYPE_RAW_14BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> -        14,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SGRBG14_1X14,

> >> -        DATA_TYPE_RAW_14BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> -        14,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_SRGGB14_1X14,

> >> -        DATA_TYPE_RAW_14BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_14_BIT,

> >> -        14,

> >> -        1,

> >> -    },

> >> -    {

> >> -        MEDIA_BUS_FMT_Y10_1X10,

> >> -        DATA_TYPE_RAW_10BIT,

> >> -        DECODE_FORMAT_UNCOMPRESSED_10_BIT,

> >> -        10,

> >> -        1,

> >> -    },

> >> -};

> >> -static u32 csid_find_code(u32 *code, unsigned int n_code,

> >> -              unsigned int index, u32 req_code)

> >> +u32 csid_find_code(u32 *codes, unsigned int ncodes,

> >> +           unsigned int match_format_idx, u32 match_code)

> >>   {

> >>       int i;

> >> -    if (!req_code && (index >= n_code))

> >> +    if (!match_code && (match_format_idx >= ncodes))

> >>           return 0;

> >> -    for (i = 0; i < n_code; i++)

> >> -        if (req_code) {

> >> -            if (req_code == code[i])

> >> -                return req_code;

> >> +    for (i = 0; i < ncodes; i++)

> >> +        if (match_code) {

> >> +            if (codes[i] == match_code)

> >> +                return match_code;

> >>           } else {

> >> -            if (i == index)

> >> -                return code[i];

> >> -        }

> >> -

> >> -    return code[0];

> >> -}

> >> -

> >> -static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,

> >> -                 unsigned int index, u32 src_req_code)

> >> -{

> >> -    if (csid->camss->version == CAMSS_8x16) {

> >> -        if (index > 0)

> >> -            return 0;

> >> -

> >> -        return sink_code;

> >> -    } else if (csid->camss->version == CAMSS_8x96 ||

> >> -           csid->camss->version == CAMSS_660) {

> >> -        switch (sink_code) {

> >> -        case MEDIA_BUS_FMT_SBGGR10_1X10:

> >> -        {

> >> -            u32 src_code[] = {

> >> -                MEDIA_BUS_FMT_SBGGR10_1X10,

> >> -                MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,

> >> -            };

> >> -

> >> -            return csid_find_code(src_code, ARRAY_SIZE(src_code),

> >> -                          index, src_req_code);

> >> -        }

> >> -        case MEDIA_BUS_FMT_Y10_1X10:

> >> -        {

> >> -            u32 src_code[] = {

> >> -                MEDIA_BUS_FMT_Y10_1X10,

> >> -                MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,

> >> -            };

> >> -

> >> -            return csid_find_code(src_code, ARRAY_SIZE(src_code),

> >> -                          index, src_req_code);

> >> +            if (i == match_format_idx)

> >> +                return codes[i];

> >>           }

> >> -        default:

> >> -            if (index > 0)

> >> -                return 0;

> >> -            return sink_code;

> >> -        }

> >> -    } else {

> >> -        return 0;

> >> -    }

> >> +    return codes[0];

> >>   }

> >> -static const struct csid_format *csid_get_fmt_entry(

> >> +const struct csid_format *csid_get_fmt_entry(

> >>                       const struct csid_format *formats,

> >> -                    unsigned int nformat,

> >> +                    unsigned int nformats,

> >>                       u32 code)

> >>   {

> >>       unsigned int i;

> >> -    for (i = 0; i < nformat; i++)

> >> +    for (i = 0; i < nformats; i++)

> >>           if (code == formats[i].code)

> >>               return &formats[i];

> >> @@ -433,28 +63,6 @@ static const struct csid_format *csid_get_fmt_entry(

> >>       return &formats[0];

> >>   }

> >> -/*

> >> - * csid_isr - CSID module interrupt handler

> >> - * @irq: Interrupt line

> >> - * @dev: CSID device

> >> - *

> >> - * Return IRQ_HANDLED on success

> >> - */

> >> -static irqreturn_t csid_isr(int irq, void *dev)

> >> -{

> >> -    struct csid_device *csid = dev;

> >> -    enum camss_version ver = csid->camss->version;

> >> -    u32 value;

> >> -

> >> -    value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));

> >> -    writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));

> >> -

> >> -    if ((value >> 11) & 0x1)

> >> -        complete(&csid->reset_complete);

> >> -

> >> -    return IRQ_HANDLED;

> >> -}

> >> -

> >>   /*

> >>    * csid_set_clock_rates - Calculate and set clock rates on CSID module

> >>    * @csiphy: CSID device

> >> @@ -521,31 +129,6 @@ static int csid_set_clock_rates(struct csid_device *csid)

> >>       return 0;

> >>   }

> >> -/*

> >> - * csid_reset - Trigger reset on CSID module and wait to complete

> >> - * @csid: CSID device

> >> - *

> >> - * Return 0 on success or a negative error code otherwise

> >> - */

> >> -static int csid_reset(struct csid_device *csid)

> >> -{

> >> -    unsigned long time;

> >> -

> >> -    reinit_completion(&csid->reset_complete);

> >> -

> >> -    writel_relaxed(0x7fff, csid->base +

> >> -               CAMSS_CSID_RST_CMD(csid->camss->version));

> >> -

> >> -    time = wait_for_completion_timeout(&csid->reset_complete,

> >> -        msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));

> >> -    if (!time) {

> >> -        dev_err(csid->camss->dev, "CSID reset timeout\n");

> >> -        return -EIO;

> >> -    }

> >> -

> >> -    return 0;

> >> -}

> >> -

> >>   /*

> >>    * csid_set_power - Power on/off CSID module

> >>    * @sd: CSID V4L2 subdevice

> >> @@ -560,8 +143,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

> >>       int ret;

> >>       if (on) {

> >> -        u32 hw_version;

> >> -

> >>           ret = pm_runtime_get_sync(dev);

> >>           if (ret < 0) {

> >>               pm_runtime_put_sync(dev);

> >> @@ -590,7 +171,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

> >>           enable_irq(csid->irq);

> >> -        ret = csid_reset(csid);

> >> +        ret = csid->ops->reset(csid);

> >>           if (ret < 0) {

> >>               disable_irq(csid->irq);

> >>               camss_disable_clocks(csid->nclocks, csid->clock);

> >> @@ -599,8 +180,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

> >>               return ret;

> >>           }

> >> -        hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);

> >> -        dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);

> >> +        csid->ops->hw_version(csid);

> >>       } else {

> >>           disable_irq(csid->irq);

> >>           camss_disable_clocks(csid->nclocks, csid->clock);

> >> @@ -623,16 +203,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)

> >>   static int csid_set_stream(struct v4l2_subdev *sd, int enable)

> >>   {

> >>       struct csid_device *csid = v4l2_get_subdevdata(sd);

> >> -    struct csid_testgen_config *tg = &csid->testgen;

> >> -    enum camss_version ver = csid->camss->version;

> >> -    u32 val;

> >> +    int ret;

> >>       if (enable) {

> >> -        u8 vc = 0; /* Virtual Channel 0 */

> >> -        u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */

> >> -        u8 dt, dt_shift, df;

> >> -        int ret;

> >> -

> >>           ret = v4l2_ctrl_handler_setup(&csid->ctrls);

> >>           if (ret < 0) {

> >>               dev_err(csid->camss->dev,

> >> @@ -640,116 +213,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)

> >>               return ret;

> >>           }

> >> -        if (!tg->enabled &&

> >> +        if (!csid->testgen.enabled &&

> >>               !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))

> >>               return -ENOLINK;

> >> -

> >> -        if (tg->enabled) {

> >> -            /* Config Test Generator */

> >> -            struct v4l2_mbus_framefmt *f =

> >> -                    &csid->fmt[MSM_CSID_PAD_SRC];

> >> -            const struct csid_format *format = csid_get_fmt_entry(

> >> -                    csid->formats, csid->nformats, f->code);

> >> -            u32 num_bytes_per_line =

> >> -                f->width * format->bpp * format->spp / 8;

> >> -            u32 num_lines = f->height;

> >> -

> >> -            /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */

> >> -            /* 1:0 VC */

> >> -            val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |

> >> -                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_VC_CFG(ver));

> >> -

> >> -            /* 28:16 bytes per lines, 12:0 num of lines */

> >> -            val = ((num_bytes_per_line & 0x1fff) << 16) |

> >> -                  (num_lines & 0x1fff);

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));

> >> -

> >> -            dt = format->data_type;

> >> -

> >> -            /* 5:0 data type */

> >> -            val = dt;

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));

> >> -

> >> -            /* 2:0 output test pattern */

> >> -            val = tg->payload_mode;

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));

> >> -

> >> -            df = format->decode_format;

> >> -        } else {

> >> -            struct v4l2_mbus_framefmt *f =

> >> -                    &csid->fmt[MSM_CSID_PAD_SINK];

> >> -            const struct csid_format *format = csid_get_fmt_entry(

> >> -                    csid->formats, csid->nformats, f->code);

> >> -            struct csid_phy_config *phy = &csid->phy;

> >> -

> >> -            val = phy->lane_cnt - 1;

> >> -            val |= phy->lane_assign << 4;

> >> -

> >> -            writel_relaxed(val,

> >> -                       csid->base + CAMSS_CSID_CORE_CTRL_0);

> >> -

> >> -            val = phy->csiphy_id << 17;

> >> -            val |= 0x9;

> >> -

> >> -            writel_relaxed(val,

> >> -                       csid->base + CAMSS_CSID_CORE_CTRL_1);

> >> -

> >> -            dt = format->data_type;

> >> -            df = format->decode_format;

> >> -        }

> >> -

> >> -        /* Config LUT */

> >> -

> >> -        dt_shift = (cid % 4) * 8;

> >> -

> >> -        val = readl_relaxed(csid->base +

> >> -                    CAMSS_CSID_CID_LUT_VC_n(ver, vc));

> >> -        val &= ~(0xff << dt_shift);

> >> -        val |= dt << dt_shift;

> >> -        writel_relaxed(val, csid->base +

> >> -                   CAMSS_CSID_CID_LUT_VC_n(ver, vc));

> >> -

> >> -        val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;

> >> -        val |= CAMSS_CSID_CID_n_CFG_RDI_EN;

> >> -        val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;

> >> -        val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;

> >> -

> >> -        if (csid->camss->version == CAMSS_8x96 ||

> >> -            csid->camss->version == CAMSS_660) {

> >> -            u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;

> >> -            u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;

> >> -

> >> -            if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&

> >> -                 src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||

> >> -                (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&

> >> -                 src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {

> >> -                val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;

> >> -                val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;

> >> -                val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;

> >> -            }

> >> -        }

> >> -

> >> -        writel_relaxed(val, csid->base +

> >> -                   CAMSS_CSID_CID_n_CFG(ver, cid));

> >> -

> >> -        if (tg->enabled) {

> >> -            val = CAMSS_CSID_TG_CTRL_ENABLE;

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_CTRL(ver));

> >> -        }

> >> -    } else {

> >> -        if (tg->enabled) {

> >> -            val = CAMSS_CSID_TG_CTRL_DISABLE;

> >> -            writel_relaxed(val, csid->base +

> >> -                       CAMSS_CSID_TG_CTRL(ver));

> >> -        }

> >>       }

> >> +    csid->ops->configure_stream(csid, enable);

> >> +

> >>       return 0;

> >>   }

> >> @@ -818,7 +288,7 @@ static void csid_try_format(struct csid_device *csid,

> >>               *fmt = *__csid_get_format(csid, cfg,

> >>                                 MSM_CSID_PAD_SINK, which);

> >> -            fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);

> >> +            fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);

> >>           } else {

> >>               /* Test generator is enabled, set format on source */

> >>               /* pad to allow test generator usage */

> >> @@ -868,7 +338,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,

> >>                                MSM_CSID_PAD_SINK,

> >>                                code->which);

> >> -            code->code = csid_src_pad_code(csid, sink_fmt->code,

> >> +            code->code = csid->ops->src_pad_code(csid, sink_fmt->code,

> >>                                  code->index, 0);

> >>               if (!code->code)

> >>                   return -EINVAL;

> >> @@ -1004,15 +474,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)

> >>       return csid_set_format(sd, fh ? fh->pad : NULL, &format);

> >>   }

> >> -static const char * const csid_test_pattern_menu[] = {

> >> -    "Disabled",

> >> -    "Incrementing",

> >> -    "Alternating 0x55/0xAA",

> >> -    "All Zeros 0x00",

> >> -    "All Ones 0xFF",

> >> -    "Pseudo-random Data",

> >> -};

> >> -

> >>   /*

> >>    * csid_set_test_pattern - Set test generator's pattern mode

> >>    * @csid: CSID device

> >> @@ -1030,25 +491,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)

> >>       tg->enabled = !!value;

> >> -    switch (value) {

> >> -    case 1:

> >> -        tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;

> >> -        break;

> >> -    case 2:

> >> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;

> >> -        break;

> >> -    case 3:

> >> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;

> >> -        break;

> >> -    case 4:

> >> -        tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;

> >> -        break;

> >> -    case 5:

> >> -        tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;

> >> -        break;

> >> -    }

> >> -

> >> -    return 0;

> >> +    return csid->ops->configure_testgen_pattern(csid, value);

> >>   }

> >>   /*

> >> @@ -1097,17 +540,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

> >>       csid->id = id;

> >>       if (camss->version == CAMSS_8x16) {

> >> -        csid->formats = csid_formats_8x16;

> >> -        csid->nformats =

> >> -                ARRAY_SIZE(csid_formats_8x16);

> >> +        csid->ops = &csid_ops_4_1;

> >>       } else if (camss->version == CAMSS_8x96 ||

> >>              camss->version == CAMSS_660) {

> >> -        csid->formats = csid_formats_8x96;

> >> -        csid->nformats =

> >> -                ARRAY_SIZE(csid_formats_8x96);

> >> +        csid->ops = &csid_ops_4_7;

> >>       } else {

> >>           return -EINVAL;

> >>       }

> >> +    csid->ops->subdev_init(csid);

> >>       /* Memory */

> >> @@ -1130,7 +570,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

> >>       csid->irq = r->start;

> >>       snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",

> >>            dev_name(dev), MSM_CSID_NAME, csid->id);

> >> -    ret = devm_request_irq(dev, csid->irq, csid_isr,

> >> +    ret = devm_request_irq(dev, csid->irq, csid->ops->isr,

> >>           IRQF_TRIGGER_RISING, csid->irq_name, csid);

> >>       if (ret < 0) {

> >>           dev_err(dev, "request_irq failed: %d\n", ret);

> >> @@ -1341,8 +781,8 @@ int msm_csid_register_entity(struct csid_device *csid,

> >>       csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,

> >>                   &csid_ctrl_ops, V4L2_CID_TEST_PATTERN,

> >> -                ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,

> >> -                csid_test_pattern_menu);

> >> +                csid->testgen.nmodes, 0, 0,

>

> enum csid_testgen_mode has the test patterns id's numbered from 0 to MAX_SUPPORTED.

> So the MAX_SUPPORTED is the number of test patterns *minus one*.

> csid->testgen.nmodes points to the csid_testgen_modes[] array which contains the

> test patterns name *plus* "Disabled" as the first element.

> Thus the old (ARRAY_SIZE(csid_test_pattern_menu) - 1) is greater by one than

> csid->testgen.nmodes.

> By passing csid->testgen.nmodes as the max value to v4l2_ctrl_new_std_menu_items()

> you exclude the last test pattern from the menu - you can check the output of

> "v4l2-ctl -L -d <csid subdevice>".

> IMHO the logic would be simpler, if the test patterns were numbered starting from 1, not 0,

> leaving the value of 0 to "TG disabled".


Ack. I agree. The reason for the current enum numbering is because it
aligns with register values. But adding a '-1' to the register write
is cleaner than having this pile of exceptions throughout the code.

I think I'll rework enum, the related code chunks, and switch out the
MAX_SUPPORTED value for NUM_SUPPORTED == MAX_SUPPORTED + 1, to get rid
of offsets everywhere.

>

>

> Thanks,

> Andrey

>

> >> +                csid->testgen.modes);

> >>       if (csid->ctrls.error) {

> >>           dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);

> >> diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h

> >> index 02fc34ee8a41..d40194e2bed3 100644

> >> --- a/drivers/media/platform/qcom/camss/camss-csid.h

> >> +++ b/drivers/media/platform/qcom/camss/camss-csid.h

> >> @@ -11,6 +11,7 @@

> >>   #define QC_MSM_CAMSS_CSID_H

> >>   #include <linux/clk.h>

> >> +#include <linux/interrupt.h>

> >>   #include <media/media-entity.h>

> >>   #include <media/v4l2-ctrls.h>

> >>   #include <media/v4l2-device.h>

> >> @@ -70,19 +71,50 @@

> >>   #define PLAIN_FORMAT_PLAIN16    0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */

> >>   #define PLAIN_FORMAT_PLAIN32    0x2 /* supports UNCOMPRESSED_20_BIT */

> >> +#define CSID_RESET_TIMEOUT_MS 500

> >> -enum csid_payload_mode {

> >> +

> >> +enum csid_testgen_mode {

> >>       CSID_PAYLOAD_MODE_INCREMENTING = 0,

> >>       CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,

> >>       CSID_PAYLOAD_MODE_ALL_ZEROES = 2,

> >>       CSID_PAYLOAD_MODE_ALL_ONES = 3,

> >>       CSID_PAYLOAD_MODE_RANDOM = 4,

> >>       CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,

> >> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,

> >> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,

> >> +    CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,

> >> +    CSID_PAYLOAD_MODE_COLOR_BOX = 7,

> >> +    CSID_PAYLOAD_MODE_COLOR_BARS = 8,

> >> +    CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,

> >> +};

> >> +

> >> +static const char * const csid_testgen_modes[] = {

> >> +    "Disabled",

> >> +    "Incrementing",

> >> +    "Alternating 0x55/0xAA",

> >> +    "All Zeros 0x00",

> >> +    "All Ones 0xFF",

> >> +    "Pseudo-random Data",

> >> +    "User Specified",

> >> +    "Complex pattern",

> >> +    "Color box",

> >> +    "Color bars",

> >> +};

> >> +

> >> +struct csid_format {

> >> +    u32 code;

> >> +    u8 data_type;

> >> +    u8 decode_format;

> >> +    u8 bpp;

> >> +    u8 spp; /* bus samples per pixel */

> >>   };

> >>   struct csid_testgen_config {

> >> +    enum csid_testgen_mode mode;

> >> +    const char * const*modes;

> >> +    u8 nmodes;

> >>       u8 enabled;

> >> -    enum csid_payload_mode payload_mode;

> >>   };

> >>   struct csid_phy_config {

> >> @@ -91,6 +123,65 @@ struct csid_phy_config {

> >>       u32 lane_assign;

> >>   };

> >> +struct csid_device;

> >> +

> >> +struct csid_hw_ops {

> >> +    /*

> >> +     * configure_stream - Configures and starts CSID input stream

> >> +     * @csid: CSID device

> >> +     */

> >> +    void (*configure_stream)(struct csid_device *csid, u8 enable);

> >> +

> >> +    /*

> >> +     * configure_testgen_pattern - Validates and configures output pattern mode

> >> +     * of test pattern generator

> >> +     * @csid: CSID device

> >> +     */

> >> +    int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);

> >> +

> >> +    /*

> >> +     * hw_version - Read hardware version register from hardware

> >> +     * @csid: CSID device

> >> +     */

> >> +    u32 (*hw_version)(struct csid_device *csid);

> >> +

> >> +    /*

> >> +     * isr - CSID module interrupt service routine

> >> +     * @irq: Interrupt line

> >> +     * @dev: CSID device

> >> +     *

> >> +     * Return IRQ_HANDLED on success

> >> +     */

> >> +    irqreturn_t (*isr)(int irq, void *dev);

> >> +

> >> +    /*

> >> +     * reset - Trigger reset on CSID module and wait to complete

> >> +     * @csid: CSID device

> >> +     *

> >> +     * Return 0 on success or a negative error code otherwise

> >> +     */

> >> +    int (*reset)(struct csid_device *csid);

> >> +

> >> +    /*

> >> +     * src_pad_code - Pick an output/src format based on the input/sink format

> >> +     * @csid: CSID device

> >> +     * @sink_code: The sink format of the input

> >> +     * @match_format_idx: Request preferred index, as defined by subdevice csid_format.

> >> +     *    Set @match_code to 0 if used.

> >> +     * @match_code: Request preferred code, set @match_format_idx to 0 if used

> >> +     *

> >> +     * Return 0 on failure or src format code otherwise

> >> +     */

> >> +    u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,

> >> +                unsigned int match_format_idx, u32 match_code);

> >> +

> >> +    /*

> >> +     * subdev_init - Initialize CSID device according for hardware revision

> >> +     * @csid: CSID device

> >> +     */

> >> +    void (*subdev_init)(struct csid_device *csid);

> >> +};

> >> +

> >>   struct csid_device {

> >>       struct camss *camss;

> >>       u8 id;

> >> @@ -110,10 +201,37 @@ struct csid_device {

> >>       struct v4l2_ctrl *testgen_mode;

> >>       const struct csid_format *formats;

> >>       unsigned int nformats;

> >> +    const struct csid_hw_ops *ops;

> >>   };

> >>   struct resources;

> >> +

> >> +/*

> >> + * csid_find_code - Find a format code in an array using array index or format code

> >> + * @codes: Array of format codes

> >> + * @ncodes: Length of @code array

> >> + * @req_format_idx: Request preferred index, as defined by subdevice csid_format.

> >> + *    Set @match_code to 0 if used.

> >> + * @match_code: Request preferred code, set @req_format_idx to 0 if used

> >> + *

> >> + * Return 0 on failure or format code otherwise

> >> + */

> >> +u32 csid_find_code(u32 *codes, unsigned int ncode,

> >> +           unsigned int match_format_idx, u32 match_code);

> >> +

> >> +/*

> >> + * csid_get_fmt_entry - Find csid_format entry with matching format code

> >> + * @formats: Array of format csid_format entries

> >> + * @nformats: Length of @nformats array

> >> + * @code: Desired format code

> >> + *

> >> + * Return formats[0] on failure to find code

> >> + */

> >> +const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,

> >> +                         unsigned int nformats,

> >> +                         u32 code);

> >> +

> >>   int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,

> >>                const struct resources *res, u8 id);

> >> @@ -124,4 +242,8 @@ void msm_csid_unregister_entity(struct csid_device *csid);

> >>   void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);

> >> +

> >> +extern const struct csid_hw_ops csid_ops_4_1;

> >> +extern const struct csid_hw_ops csid_ops_4_7;

> >> +

> >>   #endif /* QC_MSM_CAMSS_CSID_H */

> >>

Patch

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 052c4f405fa3..cff388b653ba 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -4,6 +4,8 @@ 
 qcom-camss-objs += \
 		camss.o \
 		camss-csid.o \
+		camss-csid-4-1.o \
+		camss-csid-4-7.o \
 		camss-csiphy-2ph-1-0.o \
 		camss-csiphy-3ph-1-0.o \
 		camss-csiphy.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
new file mode 100644
index 000000000000..c92077a7f758
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
@@ -0,0 +1,330 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-1.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x00c
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x010 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x020 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x060
+#define CAMSS_CSID_IRQ_MASK		0x064
+#define CAMSS_CSID_IRQ_STATUS		0x068
+#define CAMSS_CSID_TG_CTRL		0x0a0
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0a4
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0ac + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b0 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0b4 + 0xc * (n))
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_lines, num_bytes_per_line;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	if (match_format_idx > 0)
+		return 0;
+
+	return sink_code;
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;
+}
+
+const struct csid_hw_ops csid_ops_4_1 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
new file mode 100644
index 000000000000..16a69b140f4e
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
@@ -0,0 +1,406 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x010
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x014 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x024 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x064
+#define CAMSS_CSID_IRQ_MASK		0x068
+#define CAMSS_CSID_IRQ_STATUS		0x06c
+#define CAMSS_CSID_TG_CTRL		0x0a8
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0ac
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0b4 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b8 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0bc + 0xc * (n))
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
+	u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_bytes_per_line, num_lines;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+
+		if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
+		    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
+			val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
+		}
+
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+/*
+ * isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	switch (sink_code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_SBGGR10_1X10,
+			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	case MEDIA_BUS_FMT_Y10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_Y10_1X10,
+			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	default:
+		if (match_format_idx > 0)
+			return 0;
+
+		return sink_code;
+	}
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;
+}
+
+const struct csid_hw_ops csid_ops_4_7 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index be3fe76f3dc3..601bd810f2b0 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -26,405 +26,35 @@ 
 
 #define MSM_CSID_NAME "msm_csid"
 
-#define CAMSS_CSID_HW_VERSION		0x0
-#define CAMSS_CSID_CORE_CTRL_0		0x004
-#define CAMSS_CSID_CORE_CTRL_1		0x008
-#define CAMSS_CSID_RST_CMD(v)		((v) == CAMSS_8x16 ? 0x00c : 0x010)
-#define CAMSS_CSID_CID_LUT_VC_n(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
-#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
-#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
-#define CAMSS_CSID_IRQ_CLEAR_CMD(v)	((v) == CAMSS_8x16 ? 0x060 : 0x064)
-#define CAMSS_CSID_IRQ_MASK(v)		((v) == CAMSS_8x16 ? 0x064 : 0x068)
-#define CAMSS_CSID_IRQ_STATUS(v)	((v) == CAMSS_8x16 ? 0x068 : 0x06c)
-#define CAMSS_CSID_TG_CTRL(v)		((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)
-#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
-#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
-#define CAMSS_CSID_TG_VC_CFG(v)		((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)
-#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
-#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
-#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))
-
-#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
-#define DATA_TYPE_YUV422_8BIT		0x1e
-#define DATA_TYPE_RAW_6BIT		0x28
-#define DATA_TYPE_RAW_8BIT		0x2a
-#define DATA_TYPE_RAW_10BIT		0x2b
-#define DATA_TYPE_RAW_12BIT		0x2c
-#define DATA_TYPE_RAW_14BIT		0x2d
-
-#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
-#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
-#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
-#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
-#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x8
-
-#define CSID_RESET_TIMEOUT_MS 500
-
-struct csid_format {
-	u32 code;
-	u8 data_type;
-	u8 decode_format;
-	u8 bpp;
-	u8 spp; /* bus samples per pixel */
-};
-
-static const struct csid_format csid_formats_8x16[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
-
-static const struct csid_format csid_formats_8x96[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
 
-static u32 csid_find_code(u32 *code, unsigned int n_code,
-			  unsigned int index, u32 req_code)
+u32 csid_find_code(u32 *codes, unsigned int ncodes,
+		   unsigned int match_format_idx, u32 match_code)
 {
 	int i;
 
-	if (!req_code && (index >= n_code))
+	if (!match_code && (match_format_idx >= ncodes))
 		return 0;
 
-	for (i = 0; i < n_code; i++)
-		if (req_code) {
-			if (req_code == code[i])
-				return req_code;
+	for (i = 0; i < ncodes; i++)
+		if (match_code) {
+			if (codes[i] == match_code)
+				return match_code;
 		} else {
-			if (i == index)
-				return code[i];
-		}
-
-	return code[0];
-}
-
-static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
-			     unsigned int index, u32 src_req_code)
-{
-	if (csid->camss->version == CAMSS_8x16) {
-		if (index > 0)
-			return 0;
-
-		return sink_code;
-	} else if (csid->camss->version == CAMSS_8x96 ||
-		   csid->camss->version == CAMSS_660) {
-		switch (sink_code) {
-		case MEDIA_BUS_FMT_SBGGR10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_SBGGR10_1X10,
-				MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
-		}
-		case MEDIA_BUS_FMT_Y10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_Y10_1X10,
-				MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
+			if (i == match_format_idx)
+				return codes[i];
 		}
-		default:
-			if (index > 0)
-				return 0;
 
-			return sink_code;
-		}
-	} else {
-		return 0;
-	}
+	return codes[0];
 }
 
-static const struct csid_format *csid_get_fmt_entry(
+const struct csid_format *csid_get_fmt_entry(
 					const struct csid_format *formats,
-					unsigned int nformat,
+					unsigned int nformats,
 					u32 code)
 {
 	unsigned int i;
 
-	for (i = 0; i < nformat; i++)
+	for (i = 0; i < nformats; i++)
 		if (code == formats[i].code)
 			return &formats[i];
 
@@ -433,28 +63,6 @@  static const struct csid_format *csid_get_fmt_entry(
 	return &formats[0];
 }
 
-/*
- * csid_isr - CSID module interrupt handler
- * @irq: Interrupt line
- * @dev: CSID device
- *
- * Return IRQ_HANDLED on success
- */
-static irqreturn_t csid_isr(int irq, void *dev)
-{
-	struct csid_device *csid = dev;
-	enum camss_version ver = csid->camss->version;
-	u32 value;
-
-	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));
-	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));
-
-	if ((value >> 11) & 0x1)
-		complete(&csid->reset_complete);
-
-	return IRQ_HANDLED;
-}
-
 /*
  * csid_set_clock_rates - Calculate and set clock rates on CSID module
  * @csiphy: CSID device
@@ -521,31 +129,6 @@  static int csid_set_clock_rates(struct csid_device *csid)
 	return 0;
 }
 
-/*
- * csid_reset - Trigger reset on CSID module and wait to complete
- * @csid: CSID device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int csid_reset(struct csid_device *csid)
-{
-	unsigned long time;
-
-	reinit_completion(&csid->reset_complete);
-
-	writel_relaxed(0x7fff, csid->base +
-		       CAMSS_CSID_RST_CMD(csid->camss->version));
-
-	time = wait_for_completion_timeout(&csid->reset_complete,
-		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
-	if (!time) {
-		dev_err(csid->camss->dev, "CSID reset timeout\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
 /*
  * csid_set_power - Power on/off CSID module
  * @sd: CSID V4L2 subdevice
@@ -560,8 +143,6 @@  static int csid_set_power(struct v4l2_subdev *sd, int on)
 	int ret;
 
 	if (on) {
-		u32 hw_version;
-
 		ret = pm_runtime_get_sync(dev);
 		if (ret < 0) {
 			pm_runtime_put_sync(dev);
@@ -590,7 +171,7 @@  static int csid_set_power(struct v4l2_subdev *sd, int on)
 
 		enable_irq(csid->irq);
 
-		ret = csid_reset(csid);
+		ret = csid->ops->reset(csid);
 		if (ret < 0) {
 			disable_irq(csid->irq);
 			camss_disable_clocks(csid->nclocks, csid->clock);
@@ -599,8 +180,7 @@  static int csid_set_power(struct v4l2_subdev *sd, int on)
 			return ret;
 		}
 
-		hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
-		dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);
+		csid->ops->hw_version(csid);
 	} else {
 		disable_irq(csid->irq);
 		camss_disable_clocks(csid->nclocks, csid->clock);
@@ -623,16 +203,9 @@  static int csid_set_power(struct v4l2_subdev *sd, int on)
 static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct csid_device *csid = v4l2_get_subdevdata(sd);
-	struct csid_testgen_config *tg = &csid->testgen;
-	enum camss_version ver = csid->camss->version;
-	u32 val;
+	int ret;
 
 	if (enable) {
-		u8 vc = 0; /* Virtual Channel 0 */
-		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
-		u8 dt, dt_shift, df;
-		int ret;
-
 		ret = v4l2_ctrl_handler_setup(&csid->ctrls);
 		if (ret < 0) {
 			dev_err(csid->camss->dev,
@@ -640,116 +213,13 @@  static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 			return ret;
 		}
 
-		if (!tg->enabled &&
+		if (!csid->testgen.enabled &&
 		    !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
 			return -ENOLINK;
-
-		if (tg->enabled) {
-			/* Config Test Generator */
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SRC];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			u32 num_bytes_per_line =
-				f->width * format->bpp * format->spp / 8;
-			u32 num_lines = f->height;
-
-			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
-			/* 1:0 VC */
-			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
-			      ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_VC_CFG(ver));
-
-			/* 28:16 bytes per lines, 12:0 num of lines */
-			val = ((num_bytes_per_line & 0x1fff) << 16) |
-			      (num_lines & 0x1fff);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));
-
-			dt = format->data_type;
-
-			/* 5:0 data type */
-			val = dt;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));
-
-			/* 2:0 output test pattern */
-			val = tg->payload_mode;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));
-
-			df = format->decode_format;
-		} else {
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SINK];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			struct csid_phy_config *phy = &csid->phy;
-
-			val = phy->lane_cnt - 1;
-			val |= phy->lane_assign << 4;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_0);
-
-			val = phy->csiphy_id << 17;
-			val |= 0x9;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_1);
-
-			dt = format->data_type;
-			df = format->decode_format;
-		}
-
-		/* Config LUT */
-
-		dt_shift = (cid % 4) * 8;
-
-		val = readl_relaxed(csid->base +
-				    CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-		val &= ~(0xff << dt_shift);
-		val |= dt << dt_shift;
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-
-		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
-		val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
-
-		if (csid->camss->version == CAMSS_8x96 ||
-		    csid->camss->version == CAMSS_660) {
-			u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
-			u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
-
-			if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
-			    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
-				val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
-			}
-		}
-
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_n_CFG(ver, cid));
-
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_ENABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
-	} else {
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_DISABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
 	}
 
+	csid->ops->configure_stream(csid, enable);
+
 	return 0;
 }
 
@@ -818,7 +288,7 @@  static void csid_try_format(struct csid_device *csid,
 
 			*fmt = *__csid_get_format(csid, cfg,
 						      MSM_CSID_PAD_SINK, which);
-			fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);
+			fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
 		} else {
 			/* Test generator is enabled, set format on source */
 			/* pad to allow test generator usage */
@@ -868,7 +338,7 @@  static int csid_enum_mbus_code(struct v4l2_subdev *sd,
 						     MSM_CSID_PAD_SINK,
 						     code->which);
 
-			code->code = csid_src_pad_code(csid, sink_fmt->code,
+			code->code = csid->ops->src_pad_code(csid, sink_fmt->code,
 						       code->index, 0);
 			if (!code->code)
 				return -EINVAL;
@@ -1004,15 +474,6 @@  static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	return csid_set_format(sd, fh ? fh->pad : NULL, &format);
 }
 
-static const char * const csid_test_pattern_menu[] = {
-	"Disabled",
-	"Incrementing",
-	"Alternating 0x55/0xAA",
-	"All Zeros 0x00",
-	"All Ones 0xFF",
-	"Pseudo-random Data",
-};
-
 /*
  * csid_set_test_pattern - Set test generator's pattern mode
  * @csid: CSID device
@@ -1030,25 +491,7 @@  static int csid_set_test_pattern(struct csid_device *csid, s32 value)
 
 	tg->enabled = !!value;
 
-	switch (value) {
-	case 1:
-		tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;
-		break;
-	case 2:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;
-		break;
-	case 3:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;
-		break;
-	case 4:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;
-		break;
-	case 5:
-		tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;
-		break;
-	}
-
-	return 0;
+	return csid->ops->configure_testgen_pattern(csid, value);
 }
 
 /*
@@ -1097,17 +540,14 @@  int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->id = id;
 
 	if (camss->version == CAMSS_8x16) {
-		csid->formats = csid_formats_8x16;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x16);
+		csid->ops = &csid_ops_4_1;
 	} else if (camss->version == CAMSS_8x96 ||
 		   camss->version == CAMSS_660) {
-		csid->formats = csid_formats_8x96;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x96);
+		csid->ops = &csid_ops_4_7;
 	} else {
 		return -EINVAL;
 	}
+	csid->ops->subdev_init(csid);
 
 	/* Memory */
 
@@ -1130,7 +570,7 @@  int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->irq = r->start;
 	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
 		 dev_name(dev), MSM_CSID_NAME, csid->id);
-	ret = devm_request_irq(dev, csid->irq, csid_isr,
+	ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
 		IRQF_TRIGGER_RISING, csid->irq_name, csid);
 	if (ret < 0) {
 		dev_err(dev, "request_irq failed: %d\n", ret);
@@ -1341,8 +781,8 @@  int msm_csid_register_entity(struct csid_device *csid,
 
 	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
 				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
-				ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,
-				csid_test_pattern_menu);
+				csid->testgen.nmodes, 0, 0,
+				csid->testgen.modes);
 
 	if (csid->ctrls.error) {
 		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 02fc34ee8a41..d40194e2bed3 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -11,6 +11,7 @@ 
 #define QC_MSM_CAMSS_CSID_H
 
 #include <linux/clk.h>
+#include <linux/interrupt.h>
 #include <media/media-entity.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -70,19 +71,50 @@ 
 #define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
 #define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
 
+#define CSID_RESET_TIMEOUT_MS 500
 
-enum csid_payload_mode {
+
+enum csid_testgen_mode {
 	CSID_PAYLOAD_MODE_INCREMENTING = 0,
 	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
 	CSID_PAYLOAD_MODE_ALL_ZEROES = 2,
 	CSID_PAYLOAD_MODE_ALL_ONES = 3,
 	CSID_PAYLOAD_MODE_RANDOM = 4,
 	CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,
+	CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,
+	CSID_PAYLOAD_MODE_COLOR_BOX = 7,
+	CSID_PAYLOAD_MODE_COLOR_BARS = 8,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,
+};
+
+static const char * const csid_testgen_modes[] = {
+	"Disabled",
+	"Incrementing",
+	"Alternating 0x55/0xAA",
+	"All Zeros 0x00",
+	"All Ones 0xFF",
+	"Pseudo-random Data",
+	"User Specified",
+	"Complex pattern",
+	"Color box",
+	"Color bars",
+};
+
+struct csid_format {
+	u32 code;
+	u8 data_type;
+	u8 decode_format;
+	u8 bpp;
+	u8 spp; /* bus samples per pixel */
 };
 
 struct csid_testgen_config {
+	enum csid_testgen_mode mode;
+	const char * const*modes;
+	u8 nmodes;
 	u8 enabled;
-	enum csid_payload_mode payload_mode;
 };
 
 struct csid_phy_config {
@@ -91,6 +123,65 @@  struct csid_phy_config {
 	u32 lane_assign;
 };
 
+struct csid_device;
+
+struct csid_hw_ops {
+	/*
+	 * configure_stream - Configures and starts CSID input stream
+	 * @csid: CSID device
+	 */
+	void (*configure_stream)(struct csid_device *csid, u8 enable);
+
+	/*
+	 * configure_testgen_pattern - Validates and configures output pattern mode
+	 * of test pattern generator
+	 * @csid: CSID device
+	 */
+	int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);
+
+	/*
+	 * hw_version - Read hardware version register from hardware
+	 * @csid: CSID device
+	 */
+	u32 (*hw_version)(struct csid_device *csid);
+
+	/*
+	 * isr - CSID module interrupt service routine
+	 * @irq: Interrupt line
+	 * @dev: CSID device
+	 *
+	 * Return IRQ_HANDLED on success
+	 */
+	irqreturn_t (*isr)(int irq, void *dev);
+
+	/*
+	 * reset - Trigger reset on CSID module and wait to complete
+	 * @csid: CSID device
+	 *
+	 * Return 0 on success or a negative error code otherwise
+	 */
+	int (*reset)(struct csid_device *csid);
+
+	/*
+	 * src_pad_code - Pick an output/src format based on the input/sink format
+	 * @csid: CSID device
+	 * @sink_code: The sink format of the input
+	 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.
+	 *	Set @match_code to 0 if used.
+	 * @match_code: Request preferred code, set @match_format_idx to 0 if used
+	 *
+	 * Return 0 on failure or src format code otherwise
+	 */
+	u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
+			    unsigned int match_format_idx, u32 match_code);
+
+	/*
+	 * subdev_init - Initialize CSID device according for hardware revision
+	 * @csid: CSID device
+	 */
+	void (*subdev_init)(struct csid_device *csid);
+};
+
 struct csid_device {
 	struct camss *camss;
 	u8 id;
@@ -110,10 +201,37 @@  struct csid_device {
 	struct v4l2_ctrl *testgen_mode;
 	const struct csid_format *formats;
 	unsigned int nformats;
+	const struct csid_hw_ops *ops;
 };
 
 struct resources;
 
+
+/*
+ * csid_find_code - Find a format code in an array using array index or format code
+ * @codes: Array of format codes
+ * @ncodes: Length of @code array
+ * @req_format_idx: Request preferred index, as defined by subdevice csid_format.
+ *	Set @match_code to 0 if used.
+ * @match_code: Request preferred code, set @req_format_idx to 0 if used
+ *
+ * Return 0 on failure or format code otherwise
+ */
+u32 csid_find_code(u32 *codes, unsigned int ncode,
+		   unsigned int match_format_idx, u32 match_code);
+
+/*
+ * csid_get_fmt_entry - Find csid_format entry with matching format code
+ * @formats: Array of format csid_format entries
+ * @nformats: Length of @nformats array
+ * @code: Desired format code
+ *
+ * Return formats[0] on failure to find code
+ */
+const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
+					     unsigned int nformats,
+					     u32 code);
+
 int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 			 const struct resources *res, u8 id);
 
@@ -124,4 +242,8 @@  void msm_csid_unregister_entity(struct csid_device *csid);
 
 void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
 
+
+extern const struct csid_hw_ops csid_ops_4_1;
+extern const struct csid_hw_ops csid_ops_4_7;
+
 #endif /* QC_MSM_CAMSS_CSID_H */