1*76005817SRobert Foss // SPDX-License-Identifier: GPL-2.0
2*76005817SRobert Foss /*
3*76005817SRobert Foss  * camss-csid-4-1.c
4*76005817SRobert Foss  *
5*76005817SRobert Foss  * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
6*76005817SRobert Foss  *
7*76005817SRobert Foss  * Copyright (C) 2020 Linaro Ltd.
8*76005817SRobert Foss  */
9*76005817SRobert Foss 
10*76005817SRobert Foss #include <linux/completion.h>
11*76005817SRobert Foss #include <linux/interrupt.h>
12*76005817SRobert Foss #include <linux/io.h>
13*76005817SRobert Foss #include <linux/kernel.h>
14*76005817SRobert Foss #include <linux/of.h>
15*76005817SRobert Foss 
16*76005817SRobert Foss #include "camss-csid.h"
17*76005817SRobert Foss #include "camss-csid-gen1.h"
18*76005817SRobert Foss #include "camss.h"
19*76005817SRobert Foss 
20*76005817SRobert Foss #define CAMSS_CSID_HW_VERSION		0x0
21*76005817SRobert Foss #define CAMSS_CSID_CORE_CTRL_0		0x004
22*76005817SRobert Foss #define CAMSS_CSID_CORE_CTRL_1		0x008
23*76005817SRobert Foss #define CAMSS_CSID_RST_CMD		0x00c
24*76005817SRobert Foss #define CAMSS_CSID_CID_LUT_VC_n(n)	(0x010 + 0x4 * (n))
25*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG(n)		(0x020 + 0x4 * (n))
26*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
27*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
28*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
29*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(PLAIN_FORMAT_PLAIN8 << 8)
30*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(PLAIN_FORMAT_PLAIN16 << 8)
31*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
32*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
33*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
34*76005817SRobert Foss #define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
35*76005817SRobert Foss #define CAMSS_CSID_IRQ_CLEAR_CMD	0x060
36*76005817SRobert Foss #define CAMSS_CSID_IRQ_MASK		0x064
37*76005817SRobert Foss #define CAMSS_CSID_IRQ_STATUS		0x068
38*76005817SRobert Foss #define CAMSS_CSID_TG_CTRL		0x0a0
39*76005817SRobert Foss #define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
40*76005817SRobert Foss #define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
41*76005817SRobert Foss #define CAMSS_CSID_TG_VC_CFG		0x0a4
42*76005817SRobert Foss #define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
43*76005817SRobert Foss #define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
44*76005817SRobert Foss #define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0ac + 0xc * (n))
45*76005817SRobert Foss #define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b0 + 0xc * (n))
46*76005817SRobert Foss #define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0b4 + 0xc * (n))
47*76005817SRobert Foss 
48*76005817SRobert Foss static const struct csid_format csid_formats[] = {
49*76005817SRobert Foss 	{
50*76005817SRobert Foss 		MEDIA_BUS_FMT_UYVY8_2X8,
51*76005817SRobert Foss 		DATA_TYPE_YUV422_8BIT,
52*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
53*76005817SRobert Foss 		8,
54*76005817SRobert Foss 		2,
55*76005817SRobert Foss 	},
56*76005817SRobert Foss 	{
57*76005817SRobert Foss 		MEDIA_BUS_FMT_VYUY8_2X8,
58*76005817SRobert Foss 		DATA_TYPE_YUV422_8BIT,
59*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
60*76005817SRobert Foss 		8,
61*76005817SRobert Foss 		2,
62*76005817SRobert Foss 	},
63*76005817SRobert Foss 	{
64*76005817SRobert Foss 		MEDIA_BUS_FMT_YUYV8_2X8,
65*76005817SRobert Foss 		DATA_TYPE_YUV422_8BIT,
66*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
67*76005817SRobert Foss 		8,
68*76005817SRobert Foss 		2,
69*76005817SRobert Foss 	},
70*76005817SRobert Foss 	{
71*76005817SRobert Foss 		MEDIA_BUS_FMT_YVYU8_2X8,
72*76005817SRobert Foss 		DATA_TYPE_YUV422_8BIT,
73*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
74*76005817SRobert Foss 		8,
75*76005817SRobert Foss 		2,
76*76005817SRobert Foss 	},
77*76005817SRobert Foss 	{
78*76005817SRobert Foss 		MEDIA_BUS_FMT_SBGGR8_1X8,
79*76005817SRobert Foss 		DATA_TYPE_RAW_8BIT,
80*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
81*76005817SRobert Foss 		8,
82*76005817SRobert Foss 		1,
83*76005817SRobert Foss 	},
84*76005817SRobert Foss 	{
85*76005817SRobert Foss 		MEDIA_BUS_FMT_SGBRG8_1X8,
86*76005817SRobert Foss 		DATA_TYPE_RAW_8BIT,
87*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
88*76005817SRobert Foss 		8,
89*76005817SRobert Foss 		1,
90*76005817SRobert Foss 	},
91*76005817SRobert Foss 	{
92*76005817SRobert Foss 		MEDIA_BUS_FMT_SGRBG8_1X8,
93*76005817SRobert Foss 		DATA_TYPE_RAW_8BIT,
94*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
95*76005817SRobert Foss 		8,
96*76005817SRobert Foss 		1,
97*76005817SRobert Foss 	},
98*76005817SRobert Foss 	{
99*76005817SRobert Foss 		MEDIA_BUS_FMT_SRGGB8_1X8,
100*76005817SRobert Foss 		DATA_TYPE_RAW_8BIT,
101*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
102*76005817SRobert Foss 		8,
103*76005817SRobert Foss 		1,
104*76005817SRobert Foss 	},
105*76005817SRobert Foss 	{
106*76005817SRobert Foss 		MEDIA_BUS_FMT_SBGGR10_1X10,
107*76005817SRobert Foss 		DATA_TYPE_RAW_10BIT,
108*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
109*76005817SRobert Foss 		10,
110*76005817SRobert Foss 		1,
111*76005817SRobert Foss 	},
112*76005817SRobert Foss 	{
113*76005817SRobert Foss 		MEDIA_BUS_FMT_SGBRG10_1X10,
114*76005817SRobert Foss 		DATA_TYPE_RAW_10BIT,
115*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
116*76005817SRobert Foss 		10,
117*76005817SRobert Foss 		1,
118*76005817SRobert Foss 	},
119*76005817SRobert Foss 	{
120*76005817SRobert Foss 		MEDIA_BUS_FMT_SGRBG10_1X10,
121*76005817SRobert Foss 		DATA_TYPE_RAW_10BIT,
122*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
123*76005817SRobert Foss 		10,
124*76005817SRobert Foss 		1,
125*76005817SRobert Foss 	},
126*76005817SRobert Foss 	{
127*76005817SRobert Foss 		MEDIA_BUS_FMT_SRGGB10_1X10,
128*76005817SRobert Foss 		DATA_TYPE_RAW_10BIT,
129*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
130*76005817SRobert Foss 		10,
131*76005817SRobert Foss 		1,
132*76005817SRobert Foss 	},
133*76005817SRobert Foss 	{
134*76005817SRobert Foss 		MEDIA_BUS_FMT_SBGGR12_1X12,
135*76005817SRobert Foss 		DATA_TYPE_RAW_12BIT,
136*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
137*76005817SRobert Foss 		12,
138*76005817SRobert Foss 		1,
139*76005817SRobert Foss 	},
140*76005817SRobert Foss 	{
141*76005817SRobert Foss 		MEDIA_BUS_FMT_SGBRG12_1X12,
142*76005817SRobert Foss 		DATA_TYPE_RAW_12BIT,
143*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
144*76005817SRobert Foss 		12,
145*76005817SRobert Foss 		1,
146*76005817SRobert Foss 	},
147*76005817SRobert Foss 	{
148*76005817SRobert Foss 		MEDIA_BUS_FMT_SGRBG12_1X12,
149*76005817SRobert Foss 		DATA_TYPE_RAW_12BIT,
150*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
151*76005817SRobert Foss 		12,
152*76005817SRobert Foss 		1,
153*76005817SRobert Foss 	},
154*76005817SRobert Foss 	{
155*76005817SRobert Foss 		MEDIA_BUS_FMT_SRGGB12_1X12,
156*76005817SRobert Foss 		DATA_TYPE_RAW_12BIT,
157*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
158*76005817SRobert Foss 		12,
159*76005817SRobert Foss 		1,
160*76005817SRobert Foss 	},
161*76005817SRobert Foss 	{
162*76005817SRobert Foss 		MEDIA_BUS_FMT_Y10_1X10,
163*76005817SRobert Foss 		DATA_TYPE_RAW_10BIT,
164*76005817SRobert Foss 		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
165*76005817SRobert Foss 		10,
166*76005817SRobert Foss 		1,
167*76005817SRobert Foss 	},
168*76005817SRobert Foss };
169*76005817SRobert Foss 
csid_configure_stream(struct csid_device * csid,u8 enable)170*76005817SRobert Foss static void csid_configure_stream(struct csid_device *csid, u8 enable)
171*76005817SRobert Foss {
172*76005817SRobert Foss 	struct csid_testgen_config *tg = &csid->testgen;
173*76005817SRobert Foss 	u32 val;
174*76005817SRobert Foss 
175*76005817SRobert Foss 	if (enable) {
176*76005817SRobert Foss 		struct v4l2_mbus_framefmt *input_format;
177*76005817SRobert Foss 		const struct csid_format *format;
178*76005817SRobert Foss 		u8 vc = 0; /* Virtual Channel 0 */
179*76005817SRobert Foss 		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
180*76005817SRobert Foss 		u8 dt_shift;
181*76005817SRobert Foss 
182*76005817SRobert Foss 		if (tg->enabled) {
183*76005817SRobert Foss 			/* Config Test Generator */
184*76005817SRobert Foss 			u32 num_lines, num_bytes_per_line;
185*76005817SRobert Foss 
186*76005817SRobert Foss 			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
187*76005817SRobert Foss 			format = csid_get_fmt_entry(csid->formats, csid->nformats,
188*76005817SRobert Foss 						    input_format->code);
189*76005817SRobert Foss 			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
190*76005817SRobert Foss 			num_lines = input_format->height;
191*76005817SRobert Foss 
192*76005817SRobert Foss 			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
193*76005817SRobert Foss 			/* 1:0 VC */
194*76005817SRobert Foss 			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
195*76005817SRobert Foss 				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
196*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
197*76005817SRobert Foss 
198*76005817SRobert Foss 			/* 28:16 bytes per lines, 12:0 num of lines */
199*76005817SRobert Foss 			val = ((num_bytes_per_line & 0x1fff) << 16) |
200*76005817SRobert Foss 				  (num_lines & 0x1fff);
201*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
202*76005817SRobert Foss 
203*76005817SRobert Foss 			/* 5:0 data type */
204*76005817SRobert Foss 			val = format->data_type;
205*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
206*76005817SRobert Foss 
207*76005817SRobert Foss 			/* 2:0 output test pattern */
208*76005817SRobert Foss 			val = tg->mode - 1;
209*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
210*76005817SRobert Foss 		} else {
211*76005817SRobert Foss 			struct csid_phy_config *phy = &csid->phy;
212*76005817SRobert Foss 
213*76005817SRobert Foss 			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
214*76005817SRobert Foss 			format = csid_get_fmt_entry(csid->formats, csid->nformats,
215*76005817SRobert Foss 						    input_format->code);
216*76005817SRobert Foss 
217*76005817SRobert Foss 			val = phy->lane_cnt - 1;
218*76005817SRobert Foss 			val |= phy->lane_assign << 4;
219*76005817SRobert Foss 
220*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
221*76005817SRobert Foss 
222*76005817SRobert Foss 			val = phy->csiphy_id << 17;
223*76005817SRobert Foss 			val |= 0x9;
224*76005817SRobert Foss 
225*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
226*76005817SRobert Foss 		}
227*76005817SRobert Foss 
228*76005817SRobert Foss 		/* Config LUT */
229*76005817SRobert Foss 
230*76005817SRobert Foss 		dt_shift = (cid % 4) * 8;
231*76005817SRobert Foss 		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
232*76005817SRobert Foss 		val &= ~(0xff << dt_shift);
233*76005817SRobert Foss 		val |= format->data_type << dt_shift;
234*76005817SRobert Foss 		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
235*76005817SRobert Foss 
236*76005817SRobert Foss 		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
237*76005817SRobert Foss 		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
238*76005817SRobert Foss 		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
239*76005817SRobert Foss 		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
240*76005817SRobert Foss 		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
241*76005817SRobert Foss 
242*76005817SRobert Foss 		if (tg->enabled) {
243*76005817SRobert Foss 			val = CAMSS_CSID_TG_CTRL_ENABLE;
244*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
245*76005817SRobert Foss 		}
246*76005817SRobert Foss 	} else {
247*76005817SRobert Foss 		if (tg->enabled) {
248*76005817SRobert Foss 			val = CAMSS_CSID_TG_CTRL_DISABLE;
249*76005817SRobert Foss 			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
250*76005817SRobert Foss 		}
251*76005817SRobert Foss 	}
252*76005817SRobert Foss }
253*76005817SRobert Foss 
csid_configure_testgen_pattern(struct csid_device * csid,s32 val)254*76005817SRobert Foss static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
255*76005817SRobert Foss {
256*76005817SRobert Foss 	if (val > 0 && val <= csid->testgen.nmodes)
257*76005817SRobert Foss 		csid->testgen.mode = val;
258*76005817SRobert Foss 
259*76005817SRobert Foss 	return 0;
260*76005817SRobert Foss }
261*76005817SRobert Foss 
csid_hw_version(struct csid_device * csid)262*76005817SRobert Foss static u32 csid_hw_version(struct csid_device *csid)
263*76005817SRobert Foss {
264*76005817SRobert Foss 	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
265*76005817SRobert Foss 
266*76005817SRobert Foss 	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
267*76005817SRobert Foss 
268*76005817SRobert Foss 	return hw_version;
269*76005817SRobert Foss }
270*76005817SRobert Foss 
csid_isr(int irq,void * dev)271*76005817SRobert Foss static irqreturn_t csid_isr(int irq, void *dev)
272*76005817SRobert Foss {
273*76005817SRobert Foss 	struct csid_device *csid = dev;
274*76005817SRobert Foss 	u32 value;
275*76005817SRobert Foss 
276*76005817SRobert Foss 	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
277*76005817SRobert Foss 	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
278*76005817SRobert Foss 
279*76005817SRobert Foss 	if ((value >> 11) & 0x1)
280*76005817SRobert Foss 		complete(&csid->reset_complete);
281*76005817SRobert Foss 
282*76005817SRobert Foss 	return IRQ_HANDLED;
283*76005817SRobert Foss }
284*76005817SRobert Foss 
csid_reset(struct csid_device * csid)285*76005817SRobert Foss static int csid_reset(struct csid_device *csid)
286*76005817SRobert Foss {
287*76005817SRobert Foss 	unsigned long time;
288*76005817SRobert Foss 
289*76005817SRobert Foss 	reinit_completion(&csid->reset_complete);
290*76005817SRobert Foss 
291*76005817SRobert Foss 	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
292*76005817SRobert Foss 
293*76005817SRobert Foss 	time = wait_for_completion_timeout(&csid->reset_complete,
294*76005817SRobert Foss 					   msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
295*76005817SRobert Foss 	if (!time) {
296*76005817SRobert Foss 		dev_err(csid->camss->dev, "CSID reset timeout\n");
297*76005817SRobert Foss 		return -EIO;
298*76005817SRobert Foss 	}
299*76005817SRobert Foss 
300*76005817SRobert Foss 	return 0;
301*76005817SRobert Foss }
302*76005817SRobert Foss 
csid_src_pad_code(struct csid_device * csid,u32 sink_code,unsigned int match_format_idx,u32 match_code)303*76005817SRobert Foss static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
304*76005817SRobert Foss 			     unsigned int match_format_idx, u32 match_code)
305*76005817SRobert Foss {
306*76005817SRobert Foss 	if (match_format_idx > 0)
307*76005817SRobert Foss 		return 0;
308*76005817SRobert Foss 
309*76005817SRobert Foss 	return sink_code;
310*76005817SRobert Foss }
311*76005817SRobert Foss 
csid_subdev_init(struct csid_device * csid)312*76005817SRobert Foss static void csid_subdev_init(struct csid_device *csid)
313*76005817SRobert Foss {
314*76005817SRobert Foss 	csid->formats = csid_formats;
315*76005817SRobert Foss 	csid->nformats = ARRAY_SIZE(csid_formats);
316*76005817SRobert Foss 	csid->testgen.modes = csid_testgen_modes;
317*76005817SRobert Foss 	csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
318*76005817SRobert Foss }
319*76005817SRobert Foss 
320*76005817SRobert Foss const struct csid_hw_ops csid_ops_4_1 = {
321*76005817SRobert Foss 	.configure_stream = csid_configure_stream,
322*76005817SRobert Foss 	.configure_testgen_pattern = csid_configure_testgen_pattern,
323*76005817SRobert Foss 	.hw_version = csid_hw_version,
324*76005817SRobert Foss 	.isr = csid_isr,
325*76005817SRobert Foss 	.reset = csid_reset,
326*76005817SRobert Foss 	.src_pad_code = csid_src_pad_code,
327*76005817SRobert Foss 	.subdev_init = csid_subdev_init,
328*76005817SRobert Foss };
329