xref: /linux/drivers/media/platform/renesas/rcar-vin/rcar-dma.c (revision fcb3ad4366b9c810cbb9da34c076a9a52d8aa1e0)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for Renesas R-Car VIN
4  *
5  * Copyright (C) 2016 Renesas Electronics Corp.
6  * Copyright (C) 2011-2013 Renesas Solutions Corp.
7  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
8  * Copyright (C) 2008 Magnus Damm
9  *
10  * Based on the soc-camera rcar_vin driver
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/interrupt.h>
15 #include <linux/pm_runtime.h>
16 
17 #include <media/videobuf2-dma-contig.h>
18 
19 #include "rcar-vin.h"
20 
21 /* -----------------------------------------------------------------------------
22  * HW Functions
23  */
24 
25 /* Register offsets for R-Car VIN */
26 #define VNMC_REG	0x00	/* Video n Main Control Register */
27 #define VNMS_REG	0x04	/* Video n Module Status Register */
28 #define VNFC_REG	0x08	/* Video n Frame Capture Register */
29 #define VNSLPRC_REG	0x0C	/* Video n Start Line Pre-Clip Register */
30 #define VNELPRC_REG	0x10	/* Video n End Line Pre-Clip Register */
31 #define VNSPPRC_REG	0x14	/* Video n Start Pixel Pre-Clip Register */
32 #define VNEPPRC_REG	0x18	/* Video n End Pixel Pre-Clip Register */
33 #define VNIS_REG	0x2C	/* Video n Image Stride Register */
34 #define VNMB_REG(m)	(0x30 + ((m) << 2)) /* Video n Memory Base m Register */
35 #define VNIE_REG	0x40	/* Video n Interrupt Enable Register */
36 #define VNINTS_REG	0x44	/* Video n Interrupt Status Register */
37 #define VNSI_REG	0x48	/* Video n Scanline Interrupt Register */
38 #define VNMTC_REG	0x4C	/* Video n Memory Transfer Control Register */
39 #define VNDMR_REG	0x58	/* Video n Data Mode Register */
40 #define VNDMR2_REG	0x5C	/* Video n Data Mode Register 2 */
41 #define VNUVAOF_REG	0x60	/* Video n UV Address Offset Register */
42 
43 /* Register offsets specific for Gen2 */
44 #define VNSLPOC_REG	0x1C	/* Video n Start Line Post-Clip Register */
45 #define VNELPOC_REG	0x20	/* Video n End Line Post-Clip Register */
46 #define VNSPPOC_REG	0x24	/* Video n Start Pixel Post-Clip Register */
47 #define VNEPPOC_REG	0x28	/* Video n End Pixel Post-Clip Register */
48 #define VNYS_REG	0x50	/* Video n Y Scale Register */
49 #define VNXS_REG	0x54	/* Video n X Scale Register */
50 #define VNC1A_REG	0x80	/* Video n Coefficient Set C1A Register */
51 #define VNC1B_REG	0x84	/* Video n Coefficient Set C1B Register */
52 #define VNC1C_REG	0x88	/* Video n Coefficient Set C1C Register */
53 #define VNC2A_REG	0x90	/* Video n Coefficient Set C2A Register */
54 #define VNC2B_REG	0x94	/* Video n Coefficient Set C2B Register */
55 #define VNC2C_REG	0x98	/* Video n Coefficient Set C2C Register */
56 #define VNC3A_REG	0xA0	/* Video n Coefficient Set C3A Register */
57 #define VNC3B_REG	0xA4	/* Video n Coefficient Set C3B Register */
58 #define VNC3C_REG	0xA8	/* Video n Coefficient Set C3C Register */
59 #define VNC4A_REG	0xB0	/* Video n Coefficient Set C4A Register */
60 #define VNC4B_REG	0xB4	/* Video n Coefficient Set C4B Register */
61 #define VNC4C_REG	0xB8	/* Video n Coefficient Set C4C Register */
62 #define VNC5A_REG	0xC0	/* Video n Coefficient Set C5A Register */
63 #define VNC5B_REG	0xC4	/* Video n Coefficient Set C5B Register */
64 #define VNC5C_REG	0xC8	/* Video n Coefficient Set C5C Register */
65 #define VNC6A_REG	0xD0	/* Video n Coefficient Set C6A Register */
66 #define VNC6B_REG	0xD4	/* Video n Coefficient Set C6B Register */
67 #define VNC6C_REG	0xD8	/* Video n Coefficient Set C6C Register */
68 #define VNC7A_REG	0xE0	/* Video n Coefficient Set C7A Register */
69 #define VNC7B_REG	0xE4	/* Video n Coefficient Set C7B Register */
70 #define VNC7C_REG	0xE8	/* Video n Coefficient Set C7C Register */
71 #define VNC8A_REG	0xF0	/* Video n Coefficient Set C8A Register */
72 #define VNC8B_REG	0xF4	/* Video n Coefficient Set C8B Register */
73 #define VNC8C_REG	0xF8	/* Video n Coefficient Set C8C Register */
74 
75 /* Register offsets specific for Gen3 */
76 #define VNCSI_IFMD_REG		0x20 /* Video n CSI2 Interface Mode Register */
77 #define VNUDS_CTRL_REG		0x80 /* Video n scaling control register */
78 #define VNUDS_SCALE_REG		0x84 /* Video n scaling factor register */
79 #define VNUDS_PASS_BWIDTH_REG	0x90 /* Video n passband register */
80 #define VNUDS_CLIP_SIZE_REG	0xa4 /* Video n UDS output size clipping reg */
81 
82 /* Register bit fields for R-Car VIN */
83 /* Video n Main Control Register bits */
84 #define VNMC_INF_MASK		(7 << 16)
85 #define VNMC_DPINE		(1 << 27) /* Gen3 specific */
86 #define VNMC_SCLE		(1 << 26) /* Gen3 specific */
87 #define VNMC_FOC		(1 << 21)
88 #define VNMC_YCAL		(1 << 19)
89 #define VNMC_INF_YUV8_BT656	(0 << 16)
90 #define VNMC_INF_YUV8_BT601	(1 << 16)
91 #define VNMC_INF_YUV10_BT656	(2 << 16)
92 #define VNMC_INF_YUV10_BT601	(3 << 16)
93 #define VNMC_INF_RAW8		(4 << 16)
94 #define VNMC_INF_YUV16		(5 << 16)
95 #define VNMC_INF_RGB888		(6 << 16)
96 #define VNMC_INF_RGB666		(7 << 16)
97 #define VNMC_VUP		(1 << 10)
98 #define VNMC_IM_ODD		(0 << 3)
99 #define VNMC_IM_ODD_EVEN	(1 << 3)
100 #define VNMC_IM_EVEN		(2 << 3)
101 #define VNMC_IM_FULL		(3 << 3)
102 #define VNMC_BPS		(1 << 1)
103 #define VNMC_ME			(1 << 0)
104 
105 /* Video n Module Status Register bits */
106 #define VNMS_FBS_MASK		(3 << 3)
107 #define VNMS_FBS_SHIFT		3
108 #define VNMS_FS			(1 << 2)
109 #define VNMS_AV			(1 << 1)
110 #define VNMS_CA			(1 << 0)
111 
112 /* Video n Frame Capture Register bits */
113 #define VNFC_C_FRAME		(1 << 1)
114 #define VNFC_S_FRAME		(1 << 0)
115 
116 /* Video n Interrupt Enable Register bits */
117 #define VNIE_FIE		(1 << 4)
118 #define VNIE_EFE		(1 << 1)
119 
120 /* Video n Interrupt Status Register bits */
121 #define VNINTS_FIS		(1 << 4)
122 
123 /* Video n Data Mode Register bits */
124 #define VNDMR_A8BIT(n)		(((n) & 0xff) << 24)
125 #define VNDMR_A8BIT_MASK	(0xff << 24)
126 #define VNDMR_RMODE_RAW10	(2 << 19)
127 #define VNDMR_YMODE_Y8		(1 << 12)
128 #define VNDMR_YC_THR		(1 << 11)
129 #define VNDMR_EXRGB		(1 << 8)
130 #define VNDMR_BPSM		(1 << 4)
131 #define VNDMR_ABIT		(1 << 2)
132 #define VNDMR_DTMD_YCSEP	(1 << 1)
133 #define VNDMR_DTMD_ARGB		(1 << 0)
134 #define VNDMR_DTMD_YCSEP_420	(3 << 0)
135 
136 /* Video n Data Mode Register 2 bits */
137 #define VNDMR2_VPS		(1 << 30)
138 #define VNDMR2_HPS		(1 << 29)
139 #define VNDMR2_CES		(1 << 28)
140 #define VNDMR2_YDS		(1 << 22)
141 #define VNDMR2_FTEV		(1 << 17)
142 #define VNDMR2_VLV(n)		((n & 0xf) << 12)
143 
144 /* Video n CSI2 Interface Mode Register (Gen3) */
145 #define VNCSI_IFMD_DES1		(1 << 26)
146 #define VNCSI_IFMD_DES0		(1 << 25)
147 #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0)
148 
149 /* Video n scaling control register (Gen3) */
150 #define VNUDS_CTRL_AMD		(1 << 30)
151 
152 struct rvin_buffer {
153 	struct vb2_v4l2_buffer vb;
154 	struct list_head list;
155 };
156 
157 #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
158 					       struct rvin_buffer, \
159 					       vb)->list)
160 
161 static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
162 {
163 	iowrite32(value, vin->base + offset);
164 }
165 
166 static u32 rvin_read(struct rvin_dev *vin, u32 offset)
167 {
168 	return ioread32(vin->base + offset);
169 }
170 
171 /* -----------------------------------------------------------------------------
172  * Crop and Scaling
173  */
174 
175 static bool rvin_scaler_needed(const struct rvin_dev *vin)
176 {
177 	return !(vin->crop.width == vin->format.width &&
178 		 vin->compose.width == vin->format.width &&
179 		 vin->crop.height == vin->format.height &&
180 		 vin->compose.height == vin->format.height);
181 }
182 
183 struct vin_coeff {
184 	unsigned short xs_value;
185 	u32 coeff_set[24];
186 };
187 
188 static const struct vin_coeff vin_coeff_set[] = {
189 	{ 0x0000, {
190 			  0x00000000, 0x00000000, 0x00000000,
191 			  0x00000000, 0x00000000, 0x00000000,
192 			  0x00000000, 0x00000000, 0x00000000,
193 			  0x00000000, 0x00000000, 0x00000000,
194 			  0x00000000, 0x00000000, 0x00000000,
195 			  0x00000000, 0x00000000, 0x00000000,
196 			  0x00000000, 0x00000000, 0x00000000,
197 			  0x00000000, 0x00000000, 0x00000000 },
198 	},
199 	{ 0x1000, {
200 			  0x000fa400, 0x000fa400, 0x09625902,
201 			  0x000003f8, 0x00000403, 0x3de0d9f0,
202 			  0x001fffed, 0x00000804, 0x3cc1f9c3,
203 			  0x001003de, 0x00000c01, 0x3cb34d7f,
204 			  0x002003d2, 0x00000c00, 0x3d24a92d,
205 			  0x00200bca, 0x00000bff, 0x3df600d2,
206 			  0x002013cc, 0x000007ff, 0x3ed70c7e,
207 			  0x00100fde, 0x00000000, 0x3f87c036 },
208 	},
209 	{ 0x1200, {
210 			  0x002ffff1, 0x002ffff1, 0x02a0a9c8,
211 			  0x002003e7, 0x001ffffa, 0x000185bc,
212 			  0x002007dc, 0x000003ff, 0x3e52859c,
213 			  0x00200bd4, 0x00000002, 0x3d53996b,
214 			  0x00100fd0, 0x00000403, 0x3d04ad2d,
215 			  0x00000bd5, 0x00000403, 0x3d35ace7,
216 			  0x3ff003e4, 0x00000801, 0x3dc674a1,
217 			  0x3fffe800, 0x00000800, 0x3e76f461 },
218 	},
219 	{ 0x1400, {
220 			  0x00100be3, 0x00100be3, 0x04d1359a,
221 			  0x00000fdb, 0x002003ed, 0x0211fd93,
222 			  0x00000fd6, 0x002003f4, 0x0002d97b,
223 			  0x000007d6, 0x002ffffb, 0x3e93b956,
224 			  0x3ff003da, 0x001003ff, 0x3db49926,
225 			  0x3fffefe9, 0x00100001, 0x3d655cee,
226 			  0x3fffd400, 0x00000003, 0x3d65f4b6,
227 			  0x000fb421, 0x00000402, 0x3dc6547e },
228 	},
229 	{ 0x1600, {
230 			  0x00000bdd, 0x00000bdd, 0x06519578,
231 			  0x3ff007da, 0x00000be3, 0x03c24973,
232 			  0x3ff003d9, 0x00000be9, 0x01b30d5f,
233 			  0x3ffff7df, 0x001003f1, 0x0003c542,
234 			  0x000fdfec, 0x001003f7, 0x3ec4711d,
235 			  0x000fc400, 0x002ffffd, 0x3df504f1,
236 			  0x001fa81a, 0x002ffc00, 0x3d957cc2,
237 			  0x002f8c3c, 0x00100000, 0x3db5c891 },
238 	},
239 	{ 0x1800, {
240 			  0x3ff003dc, 0x3ff003dc, 0x0791e558,
241 			  0x000ff7dd, 0x3ff007de, 0x05328554,
242 			  0x000fe7e3, 0x3ff00be2, 0x03232546,
243 			  0x000fd7ee, 0x000007e9, 0x0143bd30,
244 			  0x001fb800, 0x000007ee, 0x00044511,
245 			  0x002fa015, 0x000007f4, 0x3ef4bcee,
246 			  0x002f8832, 0x001003f9, 0x3e4514c7,
247 			  0x001f7853, 0x001003fd, 0x3de54c9f },
248 	},
249 	{ 0x1a00, {
250 			  0x000fefe0, 0x000fefe0, 0x08721d3c,
251 			  0x001fdbe7, 0x000ffbde, 0x0652a139,
252 			  0x001fcbf0, 0x000003df, 0x0463292e,
253 			  0x002fb3ff, 0x3ff007e3, 0x0293a91d,
254 			  0x002f9c12, 0x3ff00be7, 0x01241905,
255 			  0x001f8c29, 0x000007ed, 0x3fe470eb,
256 			  0x000f7c46, 0x000007f2, 0x3f04b8ca,
257 			  0x3fef7865, 0x000007f6, 0x3e74e4a8 },
258 	},
259 	{ 0x1c00, {
260 			  0x001fd3e9, 0x001fd3e9, 0x08f23d26,
261 			  0x002fbff3, 0x001fe3e4, 0x0712ad23,
262 			  0x002fa800, 0x000ff3e0, 0x05631d1b,
263 			  0x001f9810, 0x000ffbe1, 0x03b3890d,
264 			  0x000f8c23, 0x000003e3, 0x0233e8fa,
265 			  0x3fef843b, 0x000003e7, 0x00f430e4,
266 			  0x3fbf8456, 0x3ff00bea, 0x00046cc8,
267 			  0x3f8f8c72, 0x3ff00bef, 0x3f3490ac },
268 	},
269 	{ 0x1e00, {
270 			  0x001fbbf4, 0x001fbbf4, 0x09425112,
271 			  0x001fa800, 0x002fc7ed, 0x0792b110,
272 			  0x000f980e, 0x001fdbe6, 0x0613110a,
273 			  0x3fff8c20, 0x001fe7e3, 0x04a368fd,
274 			  0x3fcf8c33, 0x000ff7e2, 0x0343b8ed,
275 			  0x3f9f8c4a, 0x000fffe3, 0x0203f8da,
276 			  0x3f5f9c61, 0x000003e6, 0x00e428c5,
277 			  0x3f1fb07b, 0x000003eb, 0x3fe440af },
278 	},
279 	{ 0x2000, {
280 			  0x000fa400, 0x000fa400, 0x09625902,
281 			  0x3fff980c, 0x001fb7f5, 0x0812b0ff,
282 			  0x3fdf901c, 0x001fc7ed, 0x06b2fcfa,
283 			  0x3faf902d, 0x001fd3e8, 0x055348f1,
284 			  0x3f7f983f, 0x001fe3e5, 0x04038ce3,
285 			  0x3f3fa454, 0x001fefe3, 0x02e3c8d1,
286 			  0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0,
287 			  0x3ecfd880, 0x000fffe6, 0x00c404ac },
288 	},
289 	{ 0x2200, {
290 			  0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4,
291 			  0x3fbf9818, 0x3fffa400, 0x0842a8f1,
292 			  0x3f8f9827, 0x000fb3f7, 0x0702f0ec,
293 			  0x3f5fa037, 0x000fc3ef, 0x05d330e4,
294 			  0x3f2fac49, 0x001fcfea, 0x04a364d9,
295 			  0x3effc05c, 0x001fdbe7, 0x038394ca,
296 			  0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb,
297 			  0x3ea00083, 0x001fefe6, 0x0183c0a9 },
298 	},
299 	{ 0x2400, {
300 			  0x3f9fa014, 0x3f9fa014, 0x098260e6,
301 			  0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5,
302 			  0x3f4fa431, 0x3fefa400, 0x0742d8e1,
303 			  0x3f1fb440, 0x3fffb3f8, 0x062310d9,
304 			  0x3eefc850, 0x000fbbf2, 0x050340d0,
305 			  0x3ecfe062, 0x000fcbec, 0x041364c2,
306 			  0x3ea00073, 0x001fd3ea, 0x03037cb5,
307 			  0x3e902086, 0x001fdfe8, 0x022388a5 },
308 	},
309 	{ 0x2600, {
310 			  0x3f5fa81e, 0x3f5fa81e, 0x096258da,
311 			  0x3f3fac2b, 0x3f8fa412, 0x088290d8,
312 			  0x3f0fbc38, 0x3fafa408, 0x0772c8d5,
313 			  0x3eefcc47, 0x3fcfa800, 0x0672f4ce,
314 			  0x3ecfe456, 0x3fefaffa, 0x05531cc6,
315 			  0x3eb00066, 0x3fffbbf3, 0x047334bb,
316 			  0x3ea01c77, 0x000fc7ee, 0x039348ae,
317 			  0x3ea04486, 0x000fd3eb, 0x02b350a1 },
318 	},
319 	{ 0x2800, {
320 			  0x3f2fb426, 0x3f2fb426, 0x094250ce,
321 			  0x3f0fc032, 0x3f4fac1b, 0x086284cd,
322 			  0x3eefd040, 0x3f7fa811, 0x0782acc9,
323 			  0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4,
324 			  0x3eb0005b, 0x3fbfac00, 0x05b2f4bc,
325 			  0x3eb0186a, 0x3fdfb3fa, 0x04c308b4,
326 			  0x3eb04077, 0x3fefbbf4, 0x03f31ca8,
327 			  0x3ec06884, 0x000fbff2, 0x03031c9e },
328 	},
329 	{ 0x2a00, {
330 			  0x3f0fc42d, 0x3f0fc42d, 0x090240c4,
331 			  0x3eefd439, 0x3f2fb822, 0x08526cc2,
332 			  0x3edfe845, 0x3f4fb018, 0x078294bf,
333 			  0x3ec00051, 0x3f6fac0f, 0x06b2b4bb,
334 			  0x3ec0185f, 0x3f8fac07, 0x05e2ccb4,
335 			  0x3ec0386b, 0x3fafac00, 0x0502e8ac,
336 			  0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3,
337 			  0x3ef08482, 0x3fdfbbf6, 0x0372f898 },
338 	},
339 	{ 0x2c00, {
340 			  0x3eefdc31, 0x3eefdc31, 0x08e238b8,
341 			  0x3edfec3d, 0x3f0fc828, 0x082258b9,
342 			  0x3ed00049, 0x3f1fc01e, 0x077278b6,
343 			  0x3ed01455, 0x3f3fb815, 0x06c294b2,
344 			  0x3ed03460, 0x3f5fb40d, 0x0602acac,
345 			  0x3ef0506c, 0x3f7fb006, 0x0542c0a4,
346 			  0x3f107476, 0x3f9fb400, 0x0472c89d,
347 			  0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 },
348 	},
349 	{ 0x2e00, {
350 			  0x3eefec37, 0x3eefec37, 0x088220b0,
351 			  0x3ee00041, 0x3effdc2d, 0x07f244ae,
352 			  0x3ee0144c, 0x3f0fd023, 0x07625cad,
353 			  0x3ef02c57, 0x3f1fc81a, 0x06c274a9,
354 			  0x3f004861, 0x3f3fbc13, 0x060288a6,
355 			  0x3f20686b, 0x3f5fb80c, 0x05529c9e,
356 			  0x3f408c74, 0x3f6fb805, 0x04b2ac96,
357 			  0x3f80ac7e, 0x3f8fb800, 0x0402ac8e },
358 	},
359 	{ 0x3000, {
360 			  0x3ef0003a, 0x3ef0003a, 0x084210a6,
361 			  0x3ef01045, 0x3effec32, 0x07b228a7,
362 			  0x3f00284e, 0x3f0fdc29, 0x073244a4,
363 			  0x3f104058, 0x3f0fd420, 0x06a258a2,
364 			  0x3f305c62, 0x3f2fc818, 0x0612689d,
365 			  0x3f508069, 0x3f3fc011, 0x05728496,
366 			  0x3f80a072, 0x3f4fc00a, 0x04d28c90,
367 			  0x3fc0c07b, 0x3f6fbc04, 0x04429088 },
368 	},
369 	{ 0x3200, {
370 			  0x3f00103e, 0x3f00103e, 0x07f1fc9e,
371 			  0x3f102447, 0x3f000035, 0x0782149d,
372 			  0x3f203c4f, 0x3f0ff02c, 0x07122c9c,
373 			  0x3f405458, 0x3f0fe424, 0x06924099,
374 			  0x3f607061, 0x3f1fd41d, 0x06024c97,
375 			  0x3f909068, 0x3f2fcc16, 0x05726490,
376 			  0x3fc0b070, 0x3f3fc80f, 0x04f26c8a,
377 			  0x0000d077, 0x3f4fc409, 0x04627484 },
378 	},
379 	{ 0x3400, {
380 			  0x3f202040, 0x3f202040, 0x07a1e898,
381 			  0x3f303449, 0x3f100c38, 0x0741fc98,
382 			  0x3f504c50, 0x3f10002f, 0x06e21495,
383 			  0x3f706459, 0x3f1ff028, 0x06722492,
384 			  0x3fa08060, 0x3f1fe421, 0x05f2348f,
385 			  0x3fd09c67, 0x3f1fdc19, 0x05824c89,
386 			  0x0000bc6e, 0x3f2fd014, 0x04f25086,
387 			  0x0040dc74, 0x3f3fcc0d, 0x04825c7f },
388 	},
389 	{ 0x3600, {
390 			  0x3f403042, 0x3f403042, 0x0761d890,
391 			  0x3f504848, 0x3f301c3b, 0x0701f090,
392 			  0x3f805c50, 0x3f200c33, 0x06a2008f,
393 			  0x3fa07458, 0x3f10002b, 0x06520c8d,
394 			  0x3fd0905e, 0x3f1ff424, 0x05e22089,
395 			  0x0000ac65, 0x3f1fe81d, 0x05823483,
396 			  0x0030cc6a, 0x3f2fdc18, 0x04f23c81,
397 			  0x0080e871, 0x3f2fd412, 0x0482407c },
398 	},
399 	{ 0x3800, {
400 			  0x3f604043, 0x3f604043, 0x0721c88a,
401 			  0x3f80544a, 0x3f502c3c, 0x06d1d88a,
402 			  0x3fb06851, 0x3f301c35, 0x0681e889,
403 			  0x3fd08456, 0x3f30082f, 0x0611fc88,
404 			  0x00009c5d, 0x3f200027, 0x05d20884,
405 			  0x0030b863, 0x3f2ff421, 0x05621880,
406 			  0x0070d468, 0x3f2fe81b, 0x0502247c,
407 			  0x00c0ec6f, 0x3f2fe015, 0x04a22877 },
408 	},
409 	{ 0x3a00, {
410 			  0x3f904c44, 0x3f904c44, 0x06e1b884,
411 			  0x3fb0604a, 0x3f70383e, 0x0691c885,
412 			  0x3fe07451, 0x3f502c36, 0x0661d483,
413 			  0x00009055, 0x3f401831, 0x0601ec81,
414 			  0x0030a85b, 0x3f300c2a, 0x05b1f480,
415 			  0x0070c061, 0x3f300024, 0x0562047a,
416 			  0x00b0d867, 0x3f3ff41e, 0x05020c77,
417 			  0x00f0f46b, 0x3f2fec19, 0x04a21474 },
418 	},
419 	{ 0x3c00, {
420 			  0x3fb05c43, 0x3fb05c43, 0x06c1b07e,
421 			  0x3fe06c4b, 0x3f902c3f, 0x0681c081,
422 			  0x0000844f, 0x3f703838, 0x0631cc7d,
423 			  0x00309855, 0x3f602433, 0x05d1d47e,
424 			  0x0060b459, 0x3f50142e, 0x0581e47b,
425 			  0x00a0c85f, 0x3f400828, 0x0531f078,
426 			  0x00e0e064, 0x3f300021, 0x0501fc73,
427 			  0x00b0fc6a, 0x3f3ff41d, 0x04a20873 },
428 	},
429 	{ 0x3e00, {
430 			  0x3fe06444, 0x3fe06444, 0x0681a07a,
431 			  0x00007849, 0x3fc0503f, 0x0641b07a,
432 			  0x0020904d, 0x3fa0403a, 0x05f1c07a,
433 			  0x0060a453, 0x3f803034, 0x05c1c878,
434 			  0x0090b858, 0x3f70202f, 0x0571d477,
435 			  0x00d0d05d, 0x3f501829, 0x0531e073,
436 			  0x0110e462, 0x3f500825, 0x04e1e471,
437 			  0x01510065, 0x3f40001f, 0x04a1f06d },
438 	},
439 	{ 0x4000, {
440 			  0x00007044, 0x00007044, 0x06519476,
441 			  0x00208448, 0x3fe05c3f, 0x0621a476,
442 			  0x0050984d, 0x3fc04c3a, 0x05e1b075,
443 			  0x0080ac52, 0x3fa03c35, 0x05a1b875,
444 			  0x00c0c056, 0x3f803030, 0x0561c473,
445 			  0x0100d45b, 0x3f70202b, 0x0521d46f,
446 			  0x0140e860, 0x3f601427, 0x04d1d46e,
447 			  0x01810064, 0x3f500822, 0x0491dc6b },
448 	},
449 	{ 0x5000, {
450 			  0x0110a442, 0x0110a442, 0x0551545e,
451 			  0x0140b045, 0x00e0983f, 0x0531585f,
452 			  0x0160c047, 0x00c08c3c, 0x0511645e,
453 			  0x0190cc4a, 0x00908039, 0x04f1685f,
454 			  0x01c0dc4c, 0x00707436, 0x04d1705e,
455 			  0x0200e850, 0x00506833, 0x04b1785b,
456 			  0x0230f453, 0x00305c30, 0x0491805a,
457 			  0x02710056, 0x0010542d, 0x04718059 },
458 	},
459 	{ 0x6000, {
460 			  0x01c0bc40, 0x01c0bc40, 0x04c13052,
461 			  0x01e0c841, 0x01a0b43d, 0x04c13851,
462 			  0x0210cc44, 0x0180a83c, 0x04a13453,
463 			  0x0230d845, 0x0160a03a, 0x04913c52,
464 			  0x0260e047, 0x01409838, 0x04714052,
465 			  0x0280ec49, 0x01208c37, 0x04514c50,
466 			  0x02b0f44b, 0x01008435, 0x04414c50,
467 			  0x02d1004c, 0x00e07c33, 0x0431544f },
468 	},
469 	{ 0x7000, {
470 			  0x0230c83e, 0x0230c83e, 0x04711c4c,
471 			  0x0250d03f, 0x0210c43c, 0x0471204b,
472 			  0x0270d840, 0x0200b83c, 0x0451244b,
473 			  0x0290dc42, 0x01e0b43a, 0x0441244c,
474 			  0x02b0e443, 0x01c0b038, 0x0441284b,
475 			  0x02d0ec44, 0x01b0a438, 0x0421304a,
476 			  0x02f0f445, 0x0190a036, 0x04213449,
477 			  0x0310f847, 0x01709c34, 0x04213848 },
478 	},
479 	{ 0x8000, {
480 			  0x0280d03d, 0x0280d03d, 0x04310c48,
481 			  0x02a0d43e, 0x0270c83c, 0x04311047,
482 			  0x02b0dc3e, 0x0250c83a, 0x04311447,
483 			  0x02d0e040, 0x0240c03a, 0x04211446,
484 			  0x02e0e840, 0x0220bc39, 0x04111847,
485 			  0x0300e842, 0x0210b438, 0x04012445,
486 			  0x0310f043, 0x0200b037, 0x04012045,
487 			  0x0330f444, 0x01e0ac36, 0x03f12445 },
488 	},
489 	{ 0xefff, {
490 			  0x0340dc3a, 0x0340dc3a, 0x03b0ec40,
491 			  0x0340e03a, 0x0330e039, 0x03c0f03e,
492 			  0x0350e03b, 0x0330dc39, 0x03c0ec3e,
493 			  0x0350e43a, 0x0320dc38, 0x03c0f43e,
494 			  0x0360e43b, 0x0320d839, 0x03b0f03e,
495 			  0x0360e83b, 0x0310d838, 0x03c0fc3b,
496 			  0x0370e83b, 0x0310d439, 0x03a0f83d,
497 			  0x0370e83c, 0x0300d438, 0x03b0fc3c },
498 	}
499 };
500 
501 static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
502 {
503 	int i;
504 	const struct vin_coeff *p_prev_set = NULL;
505 	const struct vin_coeff *p_set = NULL;
506 
507 	/* Look for suitable coefficient values */
508 	for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
509 		p_prev_set = p_set;
510 		p_set = &vin_coeff_set[i];
511 
512 		if (xs < p_set->xs_value)
513 			break;
514 	}
515 
516 	/* Use previous value if its XS value is closer */
517 	if (p_prev_set &&
518 	    xs - p_prev_set->xs_value < p_set->xs_value - xs)
519 		p_set = p_prev_set;
520 
521 	/* Set coefficient registers */
522 	rvin_write(vin, p_set->coeff_set[0], VNC1A_REG);
523 	rvin_write(vin, p_set->coeff_set[1], VNC1B_REG);
524 	rvin_write(vin, p_set->coeff_set[2], VNC1C_REG);
525 
526 	rvin_write(vin, p_set->coeff_set[3], VNC2A_REG);
527 	rvin_write(vin, p_set->coeff_set[4], VNC2B_REG);
528 	rvin_write(vin, p_set->coeff_set[5], VNC2C_REG);
529 
530 	rvin_write(vin, p_set->coeff_set[6], VNC3A_REG);
531 	rvin_write(vin, p_set->coeff_set[7], VNC3B_REG);
532 	rvin_write(vin, p_set->coeff_set[8], VNC3C_REG);
533 
534 	rvin_write(vin, p_set->coeff_set[9], VNC4A_REG);
535 	rvin_write(vin, p_set->coeff_set[10], VNC4B_REG);
536 	rvin_write(vin, p_set->coeff_set[11], VNC4C_REG);
537 
538 	rvin_write(vin, p_set->coeff_set[12], VNC5A_REG);
539 	rvin_write(vin, p_set->coeff_set[13], VNC5B_REG);
540 	rvin_write(vin, p_set->coeff_set[14], VNC5C_REG);
541 
542 	rvin_write(vin, p_set->coeff_set[15], VNC6A_REG);
543 	rvin_write(vin, p_set->coeff_set[16], VNC6B_REG);
544 	rvin_write(vin, p_set->coeff_set[17], VNC6C_REG);
545 
546 	rvin_write(vin, p_set->coeff_set[18], VNC7A_REG);
547 	rvin_write(vin, p_set->coeff_set[19], VNC7B_REG);
548 	rvin_write(vin, p_set->coeff_set[20], VNC7C_REG);
549 
550 	rvin_write(vin, p_set->coeff_set[21], VNC8A_REG);
551 	rvin_write(vin, p_set->coeff_set[22], VNC8B_REG);
552 	rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
553 }
554 
555 void rvin_scaler_gen2(struct rvin_dev *vin)
556 {
557 	unsigned int crop_height;
558 	u32 xs, ys;
559 
560 	/* Set scaling coefficient */
561 	crop_height = vin->crop.height;
562 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
563 		crop_height *= 2;
564 
565 	ys = 0;
566 	if (crop_height != vin->compose.height)
567 		ys = (4096 * crop_height) / vin->compose.height;
568 	rvin_write(vin, ys, VNYS_REG);
569 
570 	xs = 0;
571 	if (vin->crop.width != vin->compose.width)
572 		xs = (4096 * vin->crop.width) / vin->compose.width;
573 
574 	/* Horizontal upscaling is up to double size */
575 	if (xs > 0 && xs < 2048)
576 		xs = 2048;
577 
578 	rvin_write(vin, xs, VNXS_REG);
579 
580 	/* Horizontal upscaling is done out by scaling down from double size */
581 	if (xs < 4096)
582 		xs *= 2;
583 
584 	rvin_set_coeff(vin, xs);
585 
586 	/* Set Start/End Pixel/Line Post-Clip */
587 	rvin_write(vin, 0, VNSPPOC_REG);
588 	rvin_write(vin, 0, VNSLPOC_REG);
589 	rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
590 
591 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
592 		rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
593 	else
594 		rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
595 
596 	vin_dbg(vin,
597 		"Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
598 		vin->crop.width, vin->crop.height, vin->crop.left,
599 		vin->crop.top, ys, xs, vin->format.width, vin->format.height,
600 		0, 0);
601 }
602 
603 static unsigned int rvin_uds_scale_ratio(unsigned int in, unsigned int out)
604 {
605 	unsigned int ratio;
606 
607 	ratio = in * 4096 / out;
608 	return ratio >= 0x10000 ? 0xffff : ratio;
609 }
610 
611 static unsigned int rvin_uds_filter_width(unsigned int ratio)
612 {
613 	if (ratio >= 0x1000)
614 		return 64 * (ratio & 0xf000) / ratio;
615 
616 	return 64;
617 }
618 
619 void rvin_scaler_gen3(struct rvin_dev *vin)
620 {
621 	unsigned int ratio_h, ratio_v;
622 	unsigned int bwidth_h, bwidth_v;
623 	u32 vnmc, clip_size;
624 
625 	vnmc = rvin_read(vin, VNMC_REG);
626 
627 	/* Disable scaler if not needed. */
628 	if (!rvin_scaler_needed(vin)) {
629 		rvin_write(vin, vnmc & ~VNMC_SCLE, VNMC_REG);
630 		return;
631 	}
632 
633 	ratio_h = rvin_uds_scale_ratio(vin->crop.width, vin->compose.width);
634 	bwidth_h = rvin_uds_filter_width(ratio_h);
635 
636 	ratio_v = rvin_uds_scale_ratio(vin->crop.height, vin->compose.height);
637 	bwidth_v = rvin_uds_filter_width(ratio_v);
638 
639 	clip_size = vin->compose.width << 16;
640 
641 	switch (vin->format.field) {
642 	case V4L2_FIELD_INTERLACED_TB:
643 	case V4L2_FIELD_INTERLACED_BT:
644 	case V4L2_FIELD_INTERLACED:
645 	case V4L2_FIELD_SEQ_TB:
646 	case V4L2_FIELD_SEQ_BT:
647 		clip_size |= vin->compose.height / 2;
648 		break;
649 	default:
650 		clip_size |= vin->compose.height;
651 		break;
652 	}
653 
654 	rvin_write(vin, vnmc | VNMC_SCLE, VNMC_REG);
655 	rvin_write(vin, VNUDS_CTRL_AMD, VNUDS_CTRL_REG);
656 	rvin_write(vin, (ratio_h << 16) | ratio_v, VNUDS_SCALE_REG);
657 	rvin_write(vin, (bwidth_h << 16) | bwidth_v, VNUDS_PASS_BWIDTH_REG);
658 	rvin_write(vin, clip_size, VNUDS_CLIP_SIZE_REG);
659 
660 	vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u Post-Clip: %ux%u@%u:%u\n",
661 		vin->crop.width, vin->crop.height, vin->crop.left,
662 		vin->crop.top, vin->compose.width, vin->compose.height,
663 		vin->compose.left, vin->compose.top);
664 }
665 
666 void rvin_crop_scale_comp(struct rvin_dev *vin)
667 {
668 	const struct rvin_video_format *fmt;
669 	u32 stride;
670 
671 	/* Set Start/End Pixel/Line Pre-Clip */
672 	rvin_write(vin, vin->crop.left, VNSPPRC_REG);
673 	rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
674 	rvin_write(vin, vin->crop.top, VNSLPRC_REG);
675 	rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG);
676 
677 	if (vin->scaler)
678 		vin->scaler(vin);
679 
680 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
681 	stride = vin->format.bytesperline / fmt->bpp;
682 
683 	/* For RAW8 format bpp is 1, but the hardware process RAW8
684 	 * format in 2 pixel unit hence configure VNIS_REG as stride / 2.
685 	 */
686 	switch (vin->format.pixelformat) {
687 	case V4L2_PIX_FMT_SBGGR8:
688 	case V4L2_PIX_FMT_SGBRG8:
689 	case V4L2_PIX_FMT_SGRBG8:
690 	case V4L2_PIX_FMT_SRGGB8:
691 	case V4L2_PIX_FMT_GREY:
692 		stride /= 2;
693 		break;
694 	default:
695 		break;
696 	}
697 
698 	rvin_write(vin, stride, VNIS_REG);
699 }
700 
701 /* -----------------------------------------------------------------------------
702  * Hardware setup
703  */
704 
705 static int rvin_setup(struct rvin_dev *vin)
706 {
707 	u32 vnmc, dmr, dmr2, interrupts;
708 	bool progressive = false, output_is_yuv = false, input_is_yuv = false;
709 
710 	switch (vin->format.field) {
711 	case V4L2_FIELD_TOP:
712 		vnmc = VNMC_IM_ODD;
713 		break;
714 	case V4L2_FIELD_BOTTOM:
715 		vnmc = VNMC_IM_EVEN;
716 		break;
717 	case V4L2_FIELD_INTERLACED:
718 		/* Default to TB */
719 		vnmc = VNMC_IM_FULL;
720 		/* Use BT if video standard can be read and is 60 Hz format */
721 		if (!vin->info->use_mc && vin->std & V4L2_STD_525_60)
722 			vnmc = VNMC_IM_FULL | VNMC_FOC;
723 		break;
724 	case V4L2_FIELD_INTERLACED_TB:
725 		vnmc = VNMC_IM_FULL;
726 		break;
727 	case V4L2_FIELD_INTERLACED_BT:
728 		vnmc = VNMC_IM_FULL | VNMC_FOC;
729 		break;
730 	case V4L2_FIELD_SEQ_TB:
731 	case V4L2_FIELD_SEQ_BT:
732 	case V4L2_FIELD_NONE:
733 	case V4L2_FIELD_ALTERNATE:
734 		vnmc = VNMC_IM_ODD_EVEN;
735 		progressive = true;
736 		break;
737 	default:
738 		vnmc = VNMC_IM_ODD;
739 		break;
740 	}
741 
742 	/*
743 	 * Input interface
744 	 */
745 	switch (vin->mbus_code) {
746 	case MEDIA_BUS_FMT_YUYV8_1X16:
747 		if (vin->is_csi)
748 			/* YCbCr422 8-bit */
749 			vnmc |= VNMC_INF_YUV8_BT601;
750 		else
751 			/* BT.601/BT.1358 16bit YCbCr422 */
752 			vnmc |= VNMC_INF_YUV16;
753 		input_is_yuv = true;
754 		break;
755 	case MEDIA_BUS_FMT_UYVY8_1X16:
756 		if (vin->is_csi)
757 			/* YCbCr422 8-bit */
758 			vnmc |= VNMC_INF_YUV8_BT601;
759 		else
760 			/* BT.601/BT.1358 16bit YCbCr422 */
761 			vnmc |= VNMC_INF_YUV16;
762 		vnmc |= VNMC_YCAL;
763 		input_is_yuv = true;
764 		break;
765 	case MEDIA_BUS_FMT_UYVY8_2X8:
766 		/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
767 		if (!vin->is_csi &&
768 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
769 			vnmc |= VNMC_INF_YUV8_BT656;
770 		else
771 			vnmc |= VNMC_INF_YUV8_BT601;
772 
773 		input_is_yuv = true;
774 		break;
775 	case MEDIA_BUS_FMT_RGB888_1X24:
776 		vnmc |= VNMC_INF_RGB888;
777 		break;
778 	case MEDIA_BUS_FMT_UYVY10_2X10:
779 		/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
780 		if (!vin->is_csi &&
781 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
782 			vnmc |= VNMC_INF_YUV10_BT656;
783 		else
784 			vnmc |= VNMC_INF_YUV10_BT601;
785 
786 		input_is_yuv = true;
787 		break;
788 	case MEDIA_BUS_FMT_SBGGR8_1X8:
789 	case MEDIA_BUS_FMT_SGBRG8_1X8:
790 	case MEDIA_BUS_FMT_SGRBG8_1X8:
791 	case MEDIA_BUS_FMT_SRGGB8_1X8:
792 	case MEDIA_BUS_FMT_Y8_1X8:
793 		vnmc |= VNMC_INF_RAW8;
794 		break;
795 	case MEDIA_BUS_FMT_SBGGR10_1X10:
796 	case MEDIA_BUS_FMT_SGBRG10_1X10:
797 	case MEDIA_BUS_FMT_SGRBG10_1X10:
798 	case MEDIA_BUS_FMT_SRGGB10_1X10:
799 		vnmc |= VNMC_INF_RGB666;
800 		break;
801 	default:
802 		break;
803 	}
804 
805 	/* Make sure input interface and input format is valid. */
806 	if (vin->info->model == RCAR_GEN3) {
807 		switch (vnmc & VNMC_INF_MASK) {
808 		case VNMC_INF_YUV8_BT656:
809 		case VNMC_INF_YUV10_BT656:
810 		case VNMC_INF_YUV16:
811 		case VNMC_INF_RGB666:
812 			if (vin->is_csi) {
813 				vin_err(vin, "Invalid setting in MIPI CSI2\n");
814 				return -EINVAL;
815 			}
816 			break;
817 		case VNMC_INF_RAW8:
818 			if (!vin->is_csi) {
819 				vin_err(vin, "Invalid setting in Digital Pins\n");
820 				return -EINVAL;
821 			}
822 			break;
823 		default:
824 			break;
825 		}
826 	}
827 
828 	/* Enable VSYNC Field Toggle mode after one VSYNC input */
829 	if (vin->info->model == RCAR_GEN3)
830 		dmr2 = VNDMR2_FTEV;
831 	else
832 		dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
833 
834 	if (!vin->is_csi) {
835 		/* Hsync Signal Polarity Select */
836 		if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
837 			dmr2 |= VNDMR2_HPS;
838 
839 		/* Vsync Signal Polarity Select */
840 		if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
841 			dmr2 |= VNDMR2_VPS;
842 
843 		/* Data Enable Polarity Select */
844 		if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW)
845 			dmr2 |= VNDMR2_CES;
846 
847 		switch (vin->mbus_code) {
848 		case MEDIA_BUS_FMT_UYVY8_2X8:
849 			if (vin->parallel.bus.bus_width == 8 &&
850 			    vin->parallel.bus.data_shift == 8)
851 				dmr2 |= VNDMR2_YDS;
852 			break;
853 		default:
854 			break;
855 		}
856 	}
857 
858 	/*
859 	 * Output format
860 	 */
861 	switch (vin->format.pixelformat) {
862 	case V4L2_PIX_FMT_NV12:
863 	case V4L2_PIX_FMT_NV16:
864 		rvin_write(vin,
865 			   ALIGN(vin->format.bytesperline * vin->format.height,
866 				 0x80), VNUVAOF_REG);
867 		dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ?
868 			VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP;
869 		output_is_yuv = true;
870 		break;
871 	case V4L2_PIX_FMT_YUYV:
872 		dmr = VNDMR_BPSM;
873 		output_is_yuv = true;
874 		break;
875 	case V4L2_PIX_FMT_UYVY:
876 		dmr = 0;
877 		output_is_yuv = true;
878 		break;
879 	case V4L2_PIX_FMT_XRGB555:
880 		dmr = VNDMR_DTMD_ARGB;
881 		break;
882 	case V4L2_PIX_FMT_RGB565:
883 		dmr = 0;
884 		break;
885 	case V4L2_PIX_FMT_XBGR32:
886 		/* Note: not supported on M1 */
887 		dmr = VNDMR_EXRGB;
888 		break;
889 	case V4L2_PIX_FMT_ARGB555:
890 		dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB;
891 		break;
892 	case V4L2_PIX_FMT_ABGR32:
893 		dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB;
894 		break;
895 	case V4L2_PIX_FMT_SBGGR8:
896 	case V4L2_PIX_FMT_SGBRG8:
897 	case V4L2_PIX_FMT_SGRBG8:
898 	case V4L2_PIX_FMT_SRGGB8:
899 		dmr = 0;
900 		break;
901 	case V4L2_PIX_FMT_GREY:
902 		if (input_is_yuv) {
903 			dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8;
904 			output_is_yuv = true;
905 		} else {
906 			dmr = 0;
907 		}
908 		break;
909 	case V4L2_PIX_FMT_SBGGR10:
910 	case V4L2_PIX_FMT_SGBRG10:
911 	case V4L2_PIX_FMT_SGRBG10:
912 	case V4L2_PIX_FMT_SRGGB10:
913 		dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR;
914 		break;
915 	default:
916 		vin_err(vin, "Invalid pixelformat (0x%x)\n",
917 			vin->format.pixelformat);
918 		return -EINVAL;
919 	}
920 
921 	/* Always update on field change */
922 	vnmc |= VNMC_VUP;
923 
924 	if (!vin->info->use_isp) {
925 		/* If input and output use the same colorspace, use bypass mode */
926 		if (input_is_yuv == output_is_yuv)
927 			vnmc |= VNMC_BPS;
928 
929 		if (vin->info->model == RCAR_GEN3) {
930 			/* Select between CSI-2 and parallel input */
931 			if (vin->is_csi)
932 				vnmc &= ~VNMC_DPINE;
933 			else
934 				vnmc |= VNMC_DPINE;
935 		}
936 	}
937 
938 	/* Progressive or interlaced mode */
939 	interrupts = progressive ? VNIE_FIE : VNIE_EFE;
940 
941 	/* Ack interrupts */
942 	rvin_write(vin, interrupts, VNINTS_REG);
943 	/* Enable interrupts */
944 	rvin_write(vin, interrupts, VNIE_REG);
945 	/* Start capturing */
946 	rvin_write(vin, dmr, VNDMR_REG);
947 	rvin_write(vin, dmr2, VNDMR2_REG);
948 
949 	/* Enable module */
950 	rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
951 
952 	return 0;
953 }
954 
955 static void rvin_disable_interrupts(struct rvin_dev *vin)
956 {
957 	rvin_write(vin, 0, VNIE_REG);
958 }
959 
960 static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
961 {
962 	return rvin_read(vin, VNINTS_REG);
963 }
964 
965 static void rvin_ack_interrupt(struct rvin_dev *vin)
966 {
967 	rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
968 }
969 
970 static bool rvin_capture_active(struct rvin_dev *vin)
971 {
972 	return rvin_read(vin, VNMS_REG) & VNMS_CA;
973 }
974 
975 static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
976 {
977 	if (vin->format.field == V4L2_FIELD_ALTERNATE) {
978 		/* If FS is set it is an Even field. */
979 		if (vnms & VNMS_FS)
980 			return V4L2_FIELD_BOTTOM;
981 		return V4L2_FIELD_TOP;
982 	}
983 
984 	return vin->format.field;
985 }
986 
987 static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
988 {
989 	const struct rvin_video_format *fmt;
990 	int offsetx, offsety;
991 	dma_addr_t offset;
992 
993 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
994 
995 	/*
996 	 * There is no HW support for composition do the beast we can
997 	 * by modifying the buffer offset
998 	 */
999 	offsetx = vin->compose.left * fmt->bpp;
1000 	offsety = vin->compose.top * vin->format.bytesperline;
1001 	offset = addr + offsetx + offsety;
1002 
1003 	/*
1004 	 * The address needs to be 128 bytes aligned. Driver should never accept
1005 	 * settings that do not satisfy this in the first place...
1006 	 */
1007 	if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
1008 		return;
1009 
1010 	rvin_write(vin, offset, VNMB_REG(slot));
1011 }
1012 
1013 /*
1014  * Moves a buffer from the queue to the HW slot. If no buffer is
1015  * available use the scratch buffer. The scratch buffer is never
1016  * returned to userspace, its only function is to enable the capture
1017  * loop to keep running.
1018  */
1019 static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
1020 {
1021 	struct rvin_buffer *buf;
1022 	struct vb2_v4l2_buffer *vbuf;
1023 	dma_addr_t phys_addr;
1024 	int prev;
1025 
1026 	/* A already populated slot shall never be overwritten. */
1027 	if (WARN_ON(vin->buf_hw[slot].buffer))
1028 		return;
1029 
1030 	prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1;
1031 
1032 	if (vin->buf_hw[prev].type == HALF_TOP) {
1033 		vbuf = vin->buf_hw[prev].buffer;
1034 		vin->buf_hw[slot].buffer = vbuf;
1035 		vin->buf_hw[slot].type = HALF_BOTTOM;
1036 		switch (vin->format.pixelformat) {
1037 		case V4L2_PIX_FMT_NV12:
1038 		case V4L2_PIX_FMT_NV16:
1039 			phys_addr = vin->buf_hw[prev].phys +
1040 				vin->format.sizeimage / 4;
1041 			break;
1042 		default:
1043 			phys_addr = vin->buf_hw[prev].phys +
1044 				vin->format.sizeimage / 2;
1045 			break;
1046 		}
1047 	} else if ((vin->state != STOPPED && vin->state != RUNNING) ||
1048 		   list_empty(&vin->buf_list)) {
1049 		vin->buf_hw[slot].buffer = NULL;
1050 		vin->buf_hw[slot].type = FULL;
1051 		phys_addr = vin->scratch_phys;
1052 	} else {
1053 		/* Keep track of buffer we give to HW */
1054 		buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
1055 		vbuf = &buf->vb;
1056 		list_del_init(to_buf_list(vbuf));
1057 		vin->buf_hw[slot].buffer = vbuf;
1058 
1059 		vin->buf_hw[slot].type =
1060 			V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ?
1061 			HALF_TOP : FULL;
1062 
1063 		/* Setup DMA */
1064 		phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
1065 	}
1066 
1067 	vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n",
1068 		slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer);
1069 
1070 	vin->buf_hw[slot].phys = phys_addr;
1071 	rvin_set_slot_addr(vin, slot, phys_addr);
1072 }
1073 
1074 static int rvin_capture_start(struct rvin_dev *vin)
1075 {
1076 	int slot, ret;
1077 
1078 	for (slot = 0; slot < HW_BUFFER_NUM; slot++) {
1079 		vin->buf_hw[slot].buffer = NULL;
1080 		vin->buf_hw[slot].type = FULL;
1081 	}
1082 
1083 	for (slot = 0; slot < HW_BUFFER_NUM; slot++)
1084 		rvin_fill_hw_slot(vin, slot);
1085 
1086 	ret = rvin_setup(vin);
1087 	if (ret)
1088 		return ret;
1089 
1090 	rvin_crop_scale_comp(vin);
1091 
1092 	vin_dbg(vin, "Starting to capture\n");
1093 
1094 	/* Continuous Frame Capture Mode */
1095 	rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
1096 
1097 	vin->state = STARTING;
1098 
1099 	return 0;
1100 }
1101 
1102 static void rvin_capture_stop(struct rvin_dev *vin)
1103 {
1104 	/* Set continuous & single transfer off */
1105 	rvin_write(vin, 0, VNFC_REG);
1106 
1107 	/* Disable module */
1108 	rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
1109 }
1110 
1111 /* -----------------------------------------------------------------------------
1112  * DMA Functions
1113  */
1114 
1115 #define RVIN_TIMEOUT_MS 100
1116 #define RVIN_RETRIES 10
1117 
1118 static irqreturn_t rvin_irq(int irq, void *data)
1119 {
1120 	struct rvin_dev *vin = data;
1121 	u32 int_status, vnms;
1122 	int slot;
1123 	unsigned int handled = 0;
1124 	unsigned long flags;
1125 
1126 	spin_lock_irqsave(&vin->qlock, flags);
1127 
1128 	int_status = rvin_get_interrupt_status(vin);
1129 	if (!int_status)
1130 		goto done;
1131 
1132 	rvin_ack_interrupt(vin);
1133 	handled = 1;
1134 
1135 	/* Nothing to do if nothing was captured. */
1136 	if (!(int_status & VNINTS_FIS))
1137 		goto done;
1138 
1139 	/* Nothing to do if capture status is 'STOPPED' */
1140 	if (vin->state == STOPPED) {
1141 		vin_dbg(vin, "IRQ while state stopped\n");
1142 		goto done;
1143 	}
1144 
1145 	/* Prepare for capture and update state */
1146 	vnms = rvin_read(vin, VNMS_REG);
1147 	slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
1148 
1149 	/*
1150 	 * To hand buffers back in a known order to userspace start
1151 	 * to capture first from slot 0.
1152 	 */
1153 	if (vin->state == STARTING) {
1154 		if (slot != 0) {
1155 			vin_dbg(vin, "Starting sync slot: %d\n", slot);
1156 			goto done;
1157 		}
1158 
1159 		vin_dbg(vin, "Capture start synced!\n");
1160 		vin->state = RUNNING;
1161 	}
1162 
1163 	/* Capture frame */
1164 	if (vin->buf_hw[slot].buffer) {
1165 		/*
1166 		 * Nothing to do but refill the hardware slot if
1167 		 * capture only filled first half of vb2 buffer.
1168 		 */
1169 		if (vin->buf_hw[slot].type == HALF_TOP) {
1170 			vin->buf_hw[slot].buffer = NULL;
1171 			rvin_fill_hw_slot(vin, slot);
1172 			goto done;
1173 		}
1174 
1175 		vin->buf_hw[slot].buffer->field =
1176 			rvin_get_active_field(vin, vnms);
1177 		vin->buf_hw[slot].buffer->sequence = vin->sequence;
1178 		vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns();
1179 		vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf,
1180 				VB2_BUF_STATE_DONE);
1181 		vin->buf_hw[slot].buffer = NULL;
1182 	} else {
1183 		/* Scratch buffer was used, dropping frame. */
1184 		vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
1185 	}
1186 
1187 	vin->sequence++;
1188 
1189 	/* Prepare for next frame */
1190 	rvin_fill_hw_slot(vin, slot);
1191 done:
1192 	spin_unlock_irqrestore(&vin->qlock, flags);
1193 
1194 	return IRQ_RETVAL(handled);
1195 }
1196 
1197 static void return_unused_buffers(struct rvin_dev *vin,
1198 				  enum vb2_buffer_state state)
1199 {
1200 	struct rvin_buffer *buf, *node;
1201 	unsigned long flags;
1202 
1203 	spin_lock_irqsave(&vin->qlock, flags);
1204 
1205 	list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
1206 		vb2_buffer_done(&buf->vb.vb2_buf, state);
1207 		list_del(&buf->list);
1208 	}
1209 
1210 	spin_unlock_irqrestore(&vin->qlock, flags);
1211 }
1212 
1213 static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1214 			    unsigned int *nplanes, unsigned int sizes[],
1215 			    struct device *alloc_devs[])
1216 
1217 {
1218 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
1219 
1220 	/* Make sure the image size is large enough. */
1221 	if (*nplanes)
1222 		return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1223 
1224 	*nplanes = 1;
1225 	sizes[0] = vin->format.sizeimage;
1226 
1227 	return 0;
1228 };
1229 
1230 static int rvin_buffer_prepare(struct vb2_buffer *vb)
1231 {
1232 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1233 	unsigned long size = vin->format.sizeimage;
1234 
1235 	if (vb2_plane_size(vb, 0) < size) {
1236 		vin_err(vin, "buffer too small (%lu < %lu)\n",
1237 			vb2_plane_size(vb, 0), size);
1238 		return -EINVAL;
1239 	}
1240 
1241 	vb2_set_plane_payload(vb, 0, size);
1242 
1243 	return 0;
1244 }
1245 
1246 static void rvin_buffer_queue(struct vb2_buffer *vb)
1247 {
1248 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1249 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1250 	unsigned long flags;
1251 
1252 	spin_lock_irqsave(&vin->qlock, flags);
1253 
1254 	list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1255 
1256 	spin_unlock_irqrestore(&vin->qlock, flags);
1257 }
1258 
1259 static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
1260 				   struct media_pad *pad)
1261 {
1262 	struct v4l2_subdev_format fmt = {
1263 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1264 	};
1265 
1266 	fmt.pad = pad->index;
1267 	if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt))
1268 		return -EPIPE;
1269 
1270 	switch (fmt.format.code) {
1271 	case MEDIA_BUS_FMT_YUYV8_1X16:
1272 	case MEDIA_BUS_FMT_UYVY8_1X16:
1273 	case MEDIA_BUS_FMT_UYVY8_2X8:
1274 	case MEDIA_BUS_FMT_UYVY10_2X10:
1275 	case MEDIA_BUS_FMT_RGB888_1X24:
1276 		break;
1277 	case MEDIA_BUS_FMT_SBGGR8_1X8:
1278 		if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8)
1279 			return -EPIPE;
1280 		break;
1281 	case MEDIA_BUS_FMT_SGBRG8_1X8:
1282 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8)
1283 			return -EPIPE;
1284 		break;
1285 	case MEDIA_BUS_FMT_SGRBG8_1X8:
1286 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8)
1287 			return -EPIPE;
1288 		break;
1289 	case MEDIA_BUS_FMT_SRGGB8_1X8:
1290 		if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8)
1291 			return -EPIPE;
1292 		break;
1293 	case MEDIA_BUS_FMT_Y8_1X8:
1294 		if (vin->format.pixelformat != V4L2_PIX_FMT_GREY)
1295 			return -EPIPE;
1296 		break;
1297 	case MEDIA_BUS_FMT_SBGGR10_1X10:
1298 		if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10)
1299 			return -EPIPE;
1300 		break;
1301 	case MEDIA_BUS_FMT_SGBRG10_1X10:
1302 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10)
1303 			return -EPIPE;
1304 		break;
1305 	case MEDIA_BUS_FMT_SGRBG10_1X10:
1306 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10)
1307 			return -EPIPE;
1308 		break;
1309 	case MEDIA_BUS_FMT_SRGGB10_1X10:
1310 		if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10)
1311 			return -EPIPE;
1312 		break;
1313 	default:
1314 		return -EPIPE;
1315 	}
1316 	vin->mbus_code = fmt.format.code;
1317 
1318 	switch (fmt.format.field) {
1319 	case V4L2_FIELD_TOP:
1320 	case V4L2_FIELD_BOTTOM:
1321 	case V4L2_FIELD_NONE:
1322 	case V4L2_FIELD_INTERLACED_TB:
1323 	case V4L2_FIELD_INTERLACED_BT:
1324 	case V4L2_FIELD_INTERLACED:
1325 	case V4L2_FIELD_SEQ_TB:
1326 	case V4L2_FIELD_SEQ_BT:
1327 		/* Supported natively */
1328 		break;
1329 	case V4L2_FIELD_ALTERNATE:
1330 		switch (vin->format.field) {
1331 		case V4L2_FIELD_TOP:
1332 		case V4L2_FIELD_BOTTOM:
1333 		case V4L2_FIELD_NONE:
1334 		case V4L2_FIELD_ALTERNATE:
1335 			break;
1336 		case V4L2_FIELD_INTERLACED_TB:
1337 		case V4L2_FIELD_INTERLACED_BT:
1338 		case V4L2_FIELD_INTERLACED:
1339 		case V4L2_FIELD_SEQ_TB:
1340 		case V4L2_FIELD_SEQ_BT:
1341 			/* Use VIN hardware to combine the two fields */
1342 			fmt.format.height *= 2;
1343 			break;
1344 		default:
1345 			return -EPIPE;
1346 		}
1347 		break;
1348 	default:
1349 		return -EPIPE;
1350 	}
1351 
1352 	if (rvin_scaler_needed(vin)) {
1353 		/* Gen3 can't scale NV12 */
1354 		if (vin->info->model == RCAR_GEN3 &&
1355 		    vin->format.pixelformat == V4L2_PIX_FMT_NV12)
1356 			return -EPIPE;
1357 
1358 		if (!vin->scaler)
1359 			return -EPIPE;
1360 	} else {
1361 		if (vin->format.pixelformat == V4L2_PIX_FMT_NV12) {
1362 			if (ALIGN(fmt.format.width, 32) != vin->format.width ||
1363 			    ALIGN(fmt.format.height, 32) != vin->format.height)
1364 				return -EPIPE;
1365 		} else {
1366 			if (fmt.format.width != vin->format.width ||
1367 			    fmt.format.height != vin->format.height)
1368 				return -EPIPE;
1369 		}
1370 	}
1371 
1372 	if (fmt.format.code != vin->mbus_code)
1373 		return -EPIPE;
1374 
1375 	return 0;
1376 }
1377 
1378 static int rvin_set_stream(struct rvin_dev *vin, int on)
1379 {
1380 	struct v4l2_subdev *sd;
1381 	struct media_pad *pad;
1382 	int ret;
1383 
1384 	/* No media controller used, simply pass operation to subdevice. */
1385 	if (!vin->info->use_mc) {
1386 		ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream,
1387 				       on);
1388 
1389 		return ret == -ENOIOCTLCMD ? 0 : ret;
1390 	}
1391 
1392 	pad = media_pad_remote_pad_first(&vin->pad);
1393 	if (!pad)
1394 		return -EPIPE;
1395 
1396 	sd = media_entity_to_v4l2_subdev(pad->entity);
1397 
1398 	if (!on) {
1399 		video_device_pipeline_stop(&vin->vdev);
1400 		return v4l2_subdev_call(sd, video, s_stream, 0);
1401 	}
1402 
1403 	ret = rvin_mc_validate_format(vin, sd, pad);
1404 	if (ret)
1405 		return ret;
1406 
1407 	ret = video_device_pipeline_alloc_start(&vin->vdev);
1408 	if (ret)
1409 		return ret;
1410 
1411 	ret = v4l2_subdev_call(sd, video, s_stream, 1);
1412 	if (ret == -ENOIOCTLCMD)
1413 		ret = 0;
1414 	if (ret)
1415 		video_device_pipeline_stop(&vin->vdev);
1416 
1417 	return ret;
1418 }
1419 
1420 int rvin_start_streaming(struct rvin_dev *vin)
1421 {
1422 	unsigned long flags;
1423 	int ret;
1424 
1425 	ret = rvin_set_stream(vin, 1);
1426 	if (ret)
1427 		return ret;
1428 
1429 	spin_lock_irqsave(&vin->qlock, flags);
1430 
1431 	vin->sequence = 0;
1432 
1433 	ret = rvin_capture_start(vin);
1434 	if (ret)
1435 		rvin_set_stream(vin, 0);
1436 
1437 	spin_unlock_irqrestore(&vin->qlock, flags);
1438 
1439 	return ret;
1440 }
1441 
1442 static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
1443 {
1444 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
1445 	int ret = -ENOMEM;
1446 
1447 	/* Allocate scratch buffer. */
1448 	vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage,
1449 					  &vin->scratch_phys, GFP_KERNEL);
1450 	if (!vin->scratch)
1451 		goto err_scratch;
1452 
1453 	ret = rvin_start_streaming(vin);
1454 	if (ret)
1455 		goto err_start;
1456 
1457 	return 0;
1458 err_start:
1459 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
1460 			  vin->scratch_phys);
1461 err_scratch:
1462 	return_unused_buffers(vin, VB2_BUF_STATE_QUEUED);
1463 
1464 	return ret;
1465 }
1466 
1467 void rvin_stop_streaming(struct rvin_dev *vin)
1468 {
1469 	unsigned int i, retries;
1470 	unsigned long flags;
1471 	bool buffersFreed;
1472 
1473 	spin_lock_irqsave(&vin->qlock, flags);
1474 
1475 	if (vin->state == STOPPED) {
1476 		spin_unlock_irqrestore(&vin->qlock, flags);
1477 		return;
1478 	}
1479 
1480 	vin->state = STOPPING;
1481 
1482 	/* Wait until only scratch buffer is used, max 3 interrupts. */
1483 	retries = 0;
1484 	while (retries++ < RVIN_RETRIES) {
1485 		buffersFreed = true;
1486 		for (i = 0; i < HW_BUFFER_NUM; i++)
1487 			if (vin->buf_hw[i].buffer)
1488 				buffersFreed = false;
1489 
1490 		if (buffersFreed)
1491 			break;
1492 
1493 		spin_unlock_irqrestore(&vin->qlock, flags);
1494 		msleep(RVIN_TIMEOUT_MS);
1495 		spin_lock_irqsave(&vin->qlock, flags);
1496 	}
1497 
1498 	/* Wait for streaming to stop */
1499 	retries = 0;
1500 	while (retries++ < RVIN_RETRIES) {
1501 
1502 		rvin_capture_stop(vin);
1503 
1504 		/* Check if HW is stopped */
1505 		if (!rvin_capture_active(vin)) {
1506 			vin->state = STOPPED;
1507 			break;
1508 		}
1509 
1510 		spin_unlock_irqrestore(&vin->qlock, flags);
1511 		msleep(RVIN_TIMEOUT_MS);
1512 		spin_lock_irqsave(&vin->qlock, flags);
1513 	}
1514 
1515 	if (!buffersFreed || vin->state != STOPPED) {
1516 		/*
1517 		 * If this happens something have gone horribly wrong.
1518 		 * Set state to stopped to prevent the interrupt handler
1519 		 * to make things worse...
1520 		 */
1521 		vin_err(vin, "Failed stop HW, something is seriously broken\n");
1522 		vin->state = STOPPED;
1523 	}
1524 
1525 	spin_unlock_irqrestore(&vin->qlock, flags);
1526 
1527 	/* If something went wrong, free buffers with an error. */
1528 	if (!buffersFreed) {
1529 		return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
1530 		for (i = 0; i < HW_BUFFER_NUM; i++) {
1531 			if (vin->buf_hw[i].buffer)
1532 				vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
1533 						VB2_BUF_STATE_ERROR);
1534 		}
1535 	}
1536 
1537 	rvin_set_stream(vin, 0);
1538 
1539 	/* disable interrupts */
1540 	rvin_disable_interrupts(vin);
1541 }
1542 
1543 static void rvin_stop_streaming_vq(struct vb2_queue *vq)
1544 {
1545 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
1546 
1547 	rvin_stop_streaming(vin);
1548 
1549 	/* Free scratch buffer. */
1550 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
1551 			  vin->scratch_phys);
1552 
1553 	return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
1554 }
1555 
1556 static const struct vb2_ops rvin_qops = {
1557 	.queue_setup		= rvin_queue_setup,
1558 	.buf_prepare		= rvin_buffer_prepare,
1559 	.buf_queue		= rvin_buffer_queue,
1560 	.start_streaming	= rvin_start_streaming_vq,
1561 	.stop_streaming		= rvin_stop_streaming_vq,
1562 };
1563 
1564 void rvin_dma_unregister(struct rvin_dev *vin)
1565 {
1566 	mutex_destroy(&vin->lock);
1567 
1568 	v4l2_device_unregister(&vin->v4l2_dev);
1569 }
1570 
1571 int rvin_dma_register(struct rvin_dev *vin, int irq)
1572 {
1573 	struct vb2_queue *q = &vin->queue;
1574 	int i, ret;
1575 
1576 	/* Initialize the top-level structure */
1577 	ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1578 	if (ret)
1579 		return ret;
1580 
1581 	mutex_init(&vin->lock);
1582 	INIT_LIST_HEAD(&vin->buf_list);
1583 
1584 	spin_lock_init(&vin->qlock);
1585 
1586 	vin->state = STOPPED;
1587 
1588 	for (i = 0; i < HW_BUFFER_NUM; i++)
1589 		vin->buf_hw[i].buffer = NULL;
1590 
1591 	/* buffer queue */
1592 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1593 	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
1594 	q->lock = &vin->lock;
1595 	q->drv_priv = vin;
1596 	q->buf_struct_size = sizeof(struct rvin_buffer);
1597 	q->ops = &rvin_qops;
1598 	q->mem_ops = &vb2_dma_contig_memops;
1599 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1600 	q->min_queued_buffers = 4;
1601 	q->dev = vin->dev;
1602 
1603 	ret = vb2_queue_init(q);
1604 	if (ret < 0) {
1605 		vin_err(vin, "failed to initialize VB2 queue\n");
1606 		goto error;
1607 	}
1608 
1609 	/* irq */
1610 	ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED,
1611 			       KBUILD_MODNAME, vin);
1612 	if (ret) {
1613 		vin_err(vin, "failed to request irq\n");
1614 		goto error;
1615 	}
1616 
1617 	return 0;
1618 error:
1619 	rvin_dma_unregister(vin);
1620 
1621 	return ret;
1622 }
1623 
1624 /* -----------------------------------------------------------------------------
1625  * Gen3 CHSEL manipulation
1626  */
1627 
1628 /*
1629  * There is no need to have locking around changing the routing
1630  * as it's only possible to do so when no VIN in the group is
1631  * streaming so nothing can race with the VNMC register.
1632  */
1633 int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
1634 {
1635 	const struct rvin_group_route *route;
1636 	u32 ifmd = 0;
1637 	u32 vnmc;
1638 	int ret;
1639 
1640 	ret = pm_runtime_resume_and_get(vin->dev);
1641 	if (ret < 0)
1642 		return ret;
1643 
1644 	/* Make register writes take effect immediately. */
1645 	vnmc = rvin_read(vin, VNMC_REG);
1646 	rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG);
1647 
1648 	/*
1649 	 * Set data expansion mode to "pad with 0s" by inspecting the routes
1650 	 * table to find out which bit fields are available in the IFMD
1651 	 * register. IFMD_DES1 controls data expansion mode for CSI20/21,
1652 	 * IFMD_DES0 controls data expansion mode for CSI40/41.
1653 	 */
1654 	for (route = vin->info->routes; route->chsel; route++) {
1655 		if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
1656 			ifmd |= VNCSI_IFMD_DES1;
1657 		else
1658 			ifmd |= VNCSI_IFMD_DES0;
1659 
1660 		if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1))
1661 			break;
1662 	}
1663 
1664 	if (ifmd) {
1665 		ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel);
1666 		rvin_write(vin, ifmd, VNCSI_IFMD_REG);
1667 	}
1668 
1669 	vin_dbg(vin, "Set IFMD 0x%x\n", ifmd);
1670 
1671 	vin->chsel = chsel;
1672 
1673 	/* Restore VNMC. */
1674 	rvin_write(vin, vnmc, VNMC_REG);
1675 
1676 	pm_runtime_put(vin->dev);
1677 
1678 	return 0;
1679 }
1680 
1681 void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha)
1682 {
1683 	unsigned long flags;
1684 	u32 dmr;
1685 
1686 	spin_lock_irqsave(&vin->qlock, flags);
1687 
1688 	vin->alpha = alpha;
1689 
1690 	if (vin->state == STOPPED)
1691 		goto out;
1692 
1693 	switch (vin->format.pixelformat) {
1694 	case V4L2_PIX_FMT_ARGB555:
1695 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT;
1696 		if (vin->alpha)
1697 			dmr |= VNDMR_ABIT;
1698 		break;
1699 	case V4L2_PIX_FMT_ABGR32:
1700 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK;
1701 		dmr |= VNDMR_A8BIT(vin->alpha);
1702 		break;
1703 	default:
1704 		goto out;
1705 	}
1706 
1707 	rvin_write(vin, dmr,  VNDMR_REG);
1708 out:
1709 	spin_unlock_irqrestore(&vin->qlock, flags);
1710 }
1711