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