xref: /linux/drivers/media/platform/renesas/rcar-vin/rcar-dma.c (revision 94bf847ae5a61e0ab0b971ed186a443688eb793f)
1aa7b8278SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0+
2f00add96SNiklas Söderlund /*
3f00add96SNiklas Söderlund  * Driver for Renesas R-Car VIN
4f00add96SNiklas Söderlund  *
5f00add96SNiklas Söderlund  * Copyright (C) 2016 Renesas Electronics Corp.
6f00add96SNiklas Söderlund  * Copyright (C) 2011-2013 Renesas Solutions Corp.
7f00add96SNiklas Söderlund  * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
8f00add96SNiklas Söderlund  * Copyright (C) 2008 Magnus Damm
9f00add96SNiklas Söderlund  *
10f00add96SNiklas Söderlund  * Based on the soc-camera rcar_vin driver
11f00add96SNiklas Söderlund  */
12f00add96SNiklas Söderlund 
13f00add96SNiklas Söderlund #include <linux/delay.h>
14f00add96SNiklas Söderlund #include <linux/interrupt.h>
1590dedce9SNiklas Söderlund #include <linux/pm_runtime.h>
16f00add96SNiklas Söderlund 
17f00add96SNiklas Söderlund #include <media/videobuf2-dma-contig.h>
18f00add96SNiklas Söderlund 
19f00add96SNiklas Söderlund #include "rcar-vin.h"
20f00add96SNiklas Söderlund 
21f00add96SNiklas Söderlund /* -----------------------------------------------------------------------------
22f00add96SNiklas Söderlund  * HW Functions
23f00add96SNiklas Söderlund  */
24f00add96SNiklas Söderlund 
25f00add96SNiklas Söderlund /* Register offsets for R-Car VIN */
26f00add96SNiklas Söderlund #define VNMC_REG	0x00	/* Video n Main Control Register */
27f00add96SNiklas Söderlund #define VNMS_REG	0x04	/* Video n Module Status Register */
28f00add96SNiklas Söderlund #define VNFC_REG	0x08	/* Video n Frame Capture Register */
29f00add96SNiklas Söderlund #define VNSLPRC_REG	0x0C	/* Video n Start Line Pre-Clip Register */
30f00add96SNiklas Söderlund #define VNELPRC_REG	0x10	/* Video n End Line Pre-Clip Register */
31f00add96SNiklas Söderlund #define VNSPPRC_REG	0x14	/* Video n Start Pixel Pre-Clip Register */
32f00add96SNiklas Söderlund #define VNEPPRC_REG	0x18	/* Video n End Pixel Pre-Clip Register */
33f00add96SNiklas Söderlund #define VNIS_REG	0x2C	/* Video n Image Stride Register */
34f00add96SNiklas Söderlund #define VNMB_REG(m)	(0x30 + ((m) << 2)) /* Video n Memory Base m Register */
35f00add96SNiklas Söderlund #define VNIE_REG	0x40	/* Video n Interrupt Enable Register */
36f00add96SNiklas Söderlund #define VNINTS_REG	0x44	/* Video n Interrupt Status Register */
37f00add96SNiklas Söderlund #define VNSI_REG	0x48	/* Video n Scanline Interrupt Register */
38f00add96SNiklas Söderlund #define VNMTC_REG	0x4C	/* Video n Memory Transfer Control Register */
39f00add96SNiklas Söderlund #define VNDMR_REG	0x58	/* Video n Data Mode Register */
40f00add96SNiklas Söderlund #define VNDMR2_REG	0x5C	/* Video n Data Mode Register 2 */
41f00add96SNiklas Söderlund #define VNUVAOF_REG	0x60	/* Video n UV Address Offset Register */
424394eb24SNiklas Söderlund 
434394eb24SNiklas Söderlund /* Register offsets specific for Gen2 */
444394eb24SNiklas Söderlund #define VNSLPOC_REG	0x1C	/* Video n Start Line Post-Clip Register */
454394eb24SNiklas Söderlund #define VNELPOC_REG	0x20	/* Video n End Line Post-Clip Register */
464394eb24SNiklas Söderlund #define VNSPPOC_REG	0x24	/* Video n Start Pixel Post-Clip Register */
474394eb24SNiklas Söderlund #define VNEPPOC_REG	0x28	/* Video n End Pixel Post-Clip Register */
484394eb24SNiklas Söderlund #define VNYS_REG	0x50	/* Video n Y Scale Register */
494394eb24SNiklas Söderlund #define VNXS_REG	0x54	/* Video n X Scale Register */
50f00add96SNiklas Söderlund #define VNC1A_REG	0x80	/* Video n Coefficient Set C1A Register */
51f00add96SNiklas Söderlund #define VNC1B_REG	0x84	/* Video n Coefficient Set C1B Register */
52f00add96SNiklas Söderlund #define VNC1C_REG	0x88	/* Video n Coefficient Set C1C Register */
53f00add96SNiklas Söderlund #define VNC2A_REG	0x90	/* Video n Coefficient Set C2A Register */
54f00add96SNiklas Söderlund #define VNC2B_REG	0x94	/* Video n Coefficient Set C2B Register */
55f00add96SNiklas Söderlund #define VNC2C_REG	0x98	/* Video n Coefficient Set C2C Register */
56f00add96SNiklas Söderlund #define VNC3A_REG	0xA0	/* Video n Coefficient Set C3A Register */
57f00add96SNiklas Söderlund #define VNC3B_REG	0xA4	/* Video n Coefficient Set C3B Register */
58f00add96SNiklas Söderlund #define VNC3C_REG	0xA8	/* Video n Coefficient Set C3C Register */
59f00add96SNiklas Söderlund #define VNC4A_REG	0xB0	/* Video n Coefficient Set C4A Register */
60f00add96SNiklas Söderlund #define VNC4B_REG	0xB4	/* Video n Coefficient Set C4B Register */
61f00add96SNiklas Söderlund #define VNC4C_REG	0xB8	/* Video n Coefficient Set C4C Register */
62f00add96SNiklas Söderlund #define VNC5A_REG	0xC0	/* Video n Coefficient Set C5A Register */
63f00add96SNiklas Söderlund #define VNC5B_REG	0xC4	/* Video n Coefficient Set C5B Register */
64f00add96SNiklas Söderlund #define VNC5C_REG	0xC8	/* Video n Coefficient Set C5C Register */
65f00add96SNiklas Söderlund #define VNC6A_REG	0xD0	/* Video n Coefficient Set C6A Register */
66f00add96SNiklas Söderlund #define VNC6B_REG	0xD4	/* Video n Coefficient Set C6B Register */
67f00add96SNiklas Söderlund #define VNC6C_REG	0xD8	/* Video n Coefficient Set C6C Register */
68f00add96SNiklas Söderlund #define VNC7A_REG	0xE0	/* Video n Coefficient Set C7A Register */
69f00add96SNiklas Söderlund #define VNC7B_REG	0xE4	/* Video n Coefficient Set C7B Register */
70f00add96SNiklas Söderlund #define VNC7C_REG	0xE8	/* Video n Coefficient Set C7C Register */
71f00add96SNiklas Söderlund #define VNC8A_REG	0xF0	/* Video n Coefficient Set C8A Register */
72f00add96SNiklas Söderlund #define VNC8B_REG	0xF4	/* Video n Coefficient Set C8B Register */
73f00add96SNiklas Söderlund #define VNC8C_REG	0xF8	/* Video n Coefficient Set C8C Register */
74f00add96SNiklas Söderlund 
754394eb24SNiklas Söderlund /* Register offsets specific for Gen3 */
764394eb24SNiklas Söderlund #define VNCSI_IFMD_REG		0x20 /* Video n CSI2 Interface Mode Register */
77928a6ea4SNiklas Söderlund #define VNUDS_CTRL_REG		0x80 /* Video n scaling control register */
78928a6ea4SNiklas Söderlund #define VNUDS_SCALE_REG		0x84 /* Video n scaling factor register */
79928a6ea4SNiklas Söderlund #define VNUDS_PASS_BWIDTH_REG	0x90 /* Video n passband register */
80928a6ea4SNiklas Söderlund #define VNUDS_CLIP_SIZE_REG	0xa4 /* Video n UDS output size clipping reg */
81f00add96SNiklas Söderlund 
82f00add96SNiklas Söderlund /* Register bit fields for R-Car VIN */
83f00add96SNiklas Söderlund /* Video n Main Control Register bits */
8478b3f9d7SNiklas Söderlund #define VNMC_INF_MASK		(7 << 16)
854394eb24SNiklas Söderlund #define VNMC_DPINE		(1 << 27) /* Gen3 specific */
864394eb24SNiklas Söderlund #define VNMC_SCLE		(1 << 26) /* Gen3 specific */
87f00add96SNiklas Söderlund #define VNMC_FOC		(1 << 21)
88f00add96SNiklas Söderlund #define VNMC_YCAL		(1 << 19)
89f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT656	(0 << 16)
90f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT601	(1 << 16)
91f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT656	(2 << 16)
92f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT601	(3 << 16)
93e87c1a81SLad Prabhakar #define VNMC_INF_RAW8		(4 << 16)
94f00add96SNiklas Söderlund #define VNMC_INF_YUV16		(5 << 16)
95f00add96SNiklas Söderlund #define VNMC_INF_RGB888		(6 << 16)
9678b3f9d7SNiklas Söderlund #define VNMC_INF_RGB666		(7 << 16)
9717b5496cSTomi Valkeinen #define VNMC_EXINF_RAW8		(1 << 12) /* Gen4 specific */
98f00add96SNiklas Söderlund #define VNMC_VUP		(1 << 10)
99f00add96SNiklas Söderlund #define VNMC_IM_ODD		(0 << 3)
100f00add96SNiklas Söderlund #define VNMC_IM_ODD_EVEN	(1 << 3)
101f00add96SNiklas Söderlund #define VNMC_IM_EVEN		(2 << 3)
102f00add96SNiklas Söderlund #define VNMC_IM_FULL		(3 << 3)
103f00add96SNiklas Söderlund #define VNMC_BPS		(1 << 1)
104f00add96SNiklas Söderlund #define VNMC_ME			(1 << 0)
105f00add96SNiklas Söderlund 
106f00add96SNiklas Söderlund /* Video n Module Status Register bits */
107f00add96SNiklas Söderlund #define VNMS_FBS_MASK		(3 << 3)
108f00add96SNiklas Söderlund #define VNMS_FBS_SHIFT		3
109b6f556cbSNiklas Söderlund #define VNMS_FS			(1 << 2)
110f00add96SNiklas Söderlund #define VNMS_AV			(1 << 1)
111f00add96SNiklas Söderlund #define VNMS_CA			(1 << 0)
112f00add96SNiklas Söderlund 
113f00add96SNiklas Söderlund /* Video n Frame Capture Register bits */
114f00add96SNiklas Söderlund #define VNFC_C_FRAME		(1 << 1)
115f00add96SNiklas Söderlund #define VNFC_S_FRAME		(1 << 0)
116f00add96SNiklas Söderlund 
117f00add96SNiklas Söderlund /* Video n Interrupt Enable Register bits */
118f00add96SNiklas Söderlund #define VNIE_FIE		(1 << 4)
119f00add96SNiklas Söderlund #define VNIE_EFE		(1 << 1)
120f00add96SNiklas Söderlund 
12130334d3dSNiklas Söderlund /* Video n Interrupt Status Register bits */
12230334d3dSNiklas Söderlund #define VNINTS_FIS		(1 << 4)
12330334d3dSNiklas Söderlund 
124f00add96SNiklas Söderlund /* Video n Data Mode Register bits */
1251d99e68cSNiklas Söderlund #define VNDMR_A8BIT(n)		(((n) & 0xff) << 24)
1261d99e68cSNiklas Söderlund #define VNDMR_A8BIT_MASK	(0xff << 24)
1271b7e7240SNiklas Söderlund #define VNDMR_RMODE_RAW10	(2 << 19)
128c93beb52SVladimir Barinov #define VNDMR_YMODE_Y8		(1 << 12)
1291b7e7240SNiklas Söderlund #define VNDMR_YC_THR		(1 << 11)
130f00add96SNiklas Söderlund #define VNDMR_EXRGB		(1 << 8)
131f00add96SNiklas Söderlund #define VNDMR_BPSM		(1 << 4)
1321d99e68cSNiklas Söderlund #define VNDMR_ABIT		(1 << 2)
133f00add96SNiklas Söderlund #define VNDMR_DTMD_YCSEP	(1 << 1)
13419ab1f64SNiklas Söderlund #define VNDMR_DTMD_ARGB		(1 << 0)
1359b744a3eSNiklas Söderlund #define VNDMR_DTMD_YCSEP_420	(3 << 0)
136f00add96SNiklas Söderlund 
137f00add96SNiklas Söderlund /* Video n Data Mode Register 2 bits */
138f00add96SNiklas Söderlund #define VNDMR2_VPS		(1 << 30)
139f00add96SNiklas Söderlund #define VNDMR2_HPS		(1 << 29)
14053cf3100SJacopo Mondi #define VNDMR2_CES		(1 << 28)
141e8834943SLad Prabhakar #define VNDMR2_YDS		(1 << 22)
142f00add96SNiklas Söderlund #define VNDMR2_FTEV		(1 << 17)
143f00add96SNiklas Söderlund #define VNDMR2_VLV(n)		((n & 0xf) << 12)
144f00add96SNiklas Söderlund 
1454394eb24SNiklas Söderlund /* Video n CSI2 Interface Mode Register (Gen3) */
1464394eb24SNiklas Söderlund #define VNCSI_IFMD_DES1		(1 << 26)
1474394eb24SNiklas Söderlund #define VNCSI_IFMD_DES0		(1 << 25)
1484394eb24SNiklas Söderlund #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0)
1494394eb24SNiklas Söderlund 
150928a6ea4SNiklas Söderlund /* Video n scaling control register (Gen3) */
151928a6ea4SNiklas Söderlund #define VNUDS_CTRL_AMD		(1 << 30)
152928a6ea4SNiklas Söderlund 
1539e921447SNiklas Söderlund struct rvin_buffer {
1549e921447SNiklas Söderlund 	struct vb2_v4l2_buffer vb;
1559e921447SNiklas Söderlund 	struct list_head list;
1569e921447SNiklas Söderlund };
1579e921447SNiklas Söderlund 
1589e921447SNiklas Söderlund #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
1599e921447SNiklas Söderlund 					       struct rvin_buffer, \
1609e921447SNiklas Söderlund 					       vb)->list)
1619e921447SNiklas Söderlund 
162f00add96SNiklas Söderlund static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
163f00add96SNiklas Söderlund {
164f00add96SNiklas Söderlund 	iowrite32(value, vin->base + offset);
165f00add96SNiklas Söderlund }
166f00add96SNiklas Söderlund 
167f00add96SNiklas Söderlund static u32 rvin_read(struct rvin_dev *vin, u32 offset)
168f00add96SNiklas Söderlund {
169f00add96SNiklas Söderlund 	return ioread32(vin->base + offset);
170f00add96SNiklas Söderlund }
171f00add96SNiklas Söderlund 
172f00add96SNiklas Söderlund /* -----------------------------------------------------------------------------
1733ad69c61SNiklas Söderlund  * Crop and Scaling
174f00add96SNiklas Söderlund  */
175f00add96SNiklas Söderlund 
1763ad69c61SNiklas Söderlund static bool rvin_scaler_needed(const struct rvin_dev *vin)
1773ad69c61SNiklas Söderlund {
1783ad69c61SNiklas Söderlund 	return !(vin->crop.width == vin->format.width &&
1793ad69c61SNiklas Söderlund 		 vin->compose.width == vin->format.width &&
1803ad69c61SNiklas Söderlund 		 vin->crop.height == vin->format.height &&
1813ad69c61SNiklas Söderlund 		 vin->compose.height == vin->format.height);
1823ad69c61SNiklas Söderlund }
1833ad69c61SNiklas Söderlund 
184f00add96SNiklas Söderlund struct vin_coeff {
185f00add96SNiklas Söderlund 	unsigned short xs_value;
186f00add96SNiklas Söderlund 	u32 coeff_set[24];
187f00add96SNiklas Söderlund };
188f00add96SNiklas Söderlund 
189f00add96SNiklas Söderlund static const struct vin_coeff vin_coeff_set[] = {
190f00add96SNiklas Söderlund 	{ 0x0000, {
191f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
192f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
193f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
194f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
195f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
196f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
197f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
198f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000 },
199f00add96SNiklas Söderlund 	},
200f00add96SNiklas Söderlund 	{ 0x1000, {
201f00add96SNiklas Söderlund 			  0x000fa400, 0x000fa400, 0x09625902,
202f00add96SNiklas Söderlund 			  0x000003f8, 0x00000403, 0x3de0d9f0,
203f00add96SNiklas Söderlund 			  0x001fffed, 0x00000804, 0x3cc1f9c3,
204f00add96SNiklas Söderlund 			  0x001003de, 0x00000c01, 0x3cb34d7f,
205f00add96SNiklas Söderlund 			  0x002003d2, 0x00000c00, 0x3d24a92d,
206f00add96SNiklas Söderlund 			  0x00200bca, 0x00000bff, 0x3df600d2,
207f00add96SNiklas Söderlund 			  0x002013cc, 0x000007ff, 0x3ed70c7e,
208f00add96SNiklas Söderlund 			  0x00100fde, 0x00000000, 0x3f87c036 },
209f00add96SNiklas Söderlund 	},
210f00add96SNiklas Söderlund 	{ 0x1200, {
211f00add96SNiklas Söderlund 			  0x002ffff1, 0x002ffff1, 0x02a0a9c8,
212f00add96SNiklas Söderlund 			  0x002003e7, 0x001ffffa, 0x000185bc,
213f00add96SNiklas Söderlund 			  0x002007dc, 0x000003ff, 0x3e52859c,
214f00add96SNiklas Söderlund 			  0x00200bd4, 0x00000002, 0x3d53996b,
215f00add96SNiklas Söderlund 			  0x00100fd0, 0x00000403, 0x3d04ad2d,
216f00add96SNiklas Söderlund 			  0x00000bd5, 0x00000403, 0x3d35ace7,
217f00add96SNiklas Söderlund 			  0x3ff003e4, 0x00000801, 0x3dc674a1,
218f00add96SNiklas Söderlund 			  0x3fffe800, 0x00000800, 0x3e76f461 },
219f00add96SNiklas Söderlund 	},
220f00add96SNiklas Söderlund 	{ 0x1400, {
221f00add96SNiklas Söderlund 			  0x00100be3, 0x00100be3, 0x04d1359a,
222f00add96SNiklas Söderlund 			  0x00000fdb, 0x002003ed, 0x0211fd93,
223f00add96SNiklas Söderlund 			  0x00000fd6, 0x002003f4, 0x0002d97b,
224f00add96SNiklas Söderlund 			  0x000007d6, 0x002ffffb, 0x3e93b956,
225f00add96SNiklas Söderlund 			  0x3ff003da, 0x001003ff, 0x3db49926,
226f00add96SNiklas Söderlund 			  0x3fffefe9, 0x00100001, 0x3d655cee,
227f00add96SNiklas Söderlund 			  0x3fffd400, 0x00000003, 0x3d65f4b6,
228f00add96SNiklas Söderlund 			  0x000fb421, 0x00000402, 0x3dc6547e },
229f00add96SNiklas Söderlund 	},
230f00add96SNiklas Söderlund 	{ 0x1600, {
231f00add96SNiklas Söderlund 			  0x00000bdd, 0x00000bdd, 0x06519578,
232f00add96SNiklas Söderlund 			  0x3ff007da, 0x00000be3, 0x03c24973,
233f00add96SNiklas Söderlund 			  0x3ff003d9, 0x00000be9, 0x01b30d5f,
234f00add96SNiklas Söderlund 			  0x3ffff7df, 0x001003f1, 0x0003c542,
235f00add96SNiklas Söderlund 			  0x000fdfec, 0x001003f7, 0x3ec4711d,
236f00add96SNiklas Söderlund 			  0x000fc400, 0x002ffffd, 0x3df504f1,
237f00add96SNiklas Söderlund 			  0x001fa81a, 0x002ffc00, 0x3d957cc2,
238f00add96SNiklas Söderlund 			  0x002f8c3c, 0x00100000, 0x3db5c891 },
239f00add96SNiklas Söderlund 	},
240f00add96SNiklas Söderlund 	{ 0x1800, {
241f00add96SNiklas Söderlund 			  0x3ff003dc, 0x3ff003dc, 0x0791e558,
242f00add96SNiklas Söderlund 			  0x000ff7dd, 0x3ff007de, 0x05328554,
243f00add96SNiklas Söderlund 			  0x000fe7e3, 0x3ff00be2, 0x03232546,
244f00add96SNiklas Söderlund 			  0x000fd7ee, 0x000007e9, 0x0143bd30,
245f00add96SNiklas Söderlund 			  0x001fb800, 0x000007ee, 0x00044511,
246f00add96SNiklas Söderlund 			  0x002fa015, 0x000007f4, 0x3ef4bcee,
247f00add96SNiklas Söderlund 			  0x002f8832, 0x001003f9, 0x3e4514c7,
248f00add96SNiklas Söderlund 			  0x001f7853, 0x001003fd, 0x3de54c9f },
249f00add96SNiklas Söderlund 	},
250f00add96SNiklas Söderlund 	{ 0x1a00, {
251f00add96SNiklas Söderlund 			  0x000fefe0, 0x000fefe0, 0x08721d3c,
252f00add96SNiklas Söderlund 			  0x001fdbe7, 0x000ffbde, 0x0652a139,
253f00add96SNiklas Söderlund 			  0x001fcbf0, 0x000003df, 0x0463292e,
254f00add96SNiklas Söderlund 			  0x002fb3ff, 0x3ff007e3, 0x0293a91d,
255f00add96SNiklas Söderlund 			  0x002f9c12, 0x3ff00be7, 0x01241905,
256f00add96SNiklas Söderlund 			  0x001f8c29, 0x000007ed, 0x3fe470eb,
257f00add96SNiklas Söderlund 			  0x000f7c46, 0x000007f2, 0x3f04b8ca,
258f00add96SNiklas Söderlund 			  0x3fef7865, 0x000007f6, 0x3e74e4a8 },
259f00add96SNiklas Söderlund 	},
260f00add96SNiklas Söderlund 	{ 0x1c00, {
261f00add96SNiklas Söderlund 			  0x001fd3e9, 0x001fd3e9, 0x08f23d26,
262f00add96SNiklas Söderlund 			  0x002fbff3, 0x001fe3e4, 0x0712ad23,
263f00add96SNiklas Söderlund 			  0x002fa800, 0x000ff3e0, 0x05631d1b,
264f00add96SNiklas Söderlund 			  0x001f9810, 0x000ffbe1, 0x03b3890d,
265f00add96SNiklas Söderlund 			  0x000f8c23, 0x000003e3, 0x0233e8fa,
266f00add96SNiklas Söderlund 			  0x3fef843b, 0x000003e7, 0x00f430e4,
267f00add96SNiklas Söderlund 			  0x3fbf8456, 0x3ff00bea, 0x00046cc8,
268f00add96SNiklas Söderlund 			  0x3f8f8c72, 0x3ff00bef, 0x3f3490ac },
269f00add96SNiklas Söderlund 	},
270f00add96SNiklas Söderlund 	{ 0x1e00, {
271f00add96SNiklas Söderlund 			  0x001fbbf4, 0x001fbbf4, 0x09425112,
272f00add96SNiklas Söderlund 			  0x001fa800, 0x002fc7ed, 0x0792b110,
273f00add96SNiklas Söderlund 			  0x000f980e, 0x001fdbe6, 0x0613110a,
274f00add96SNiklas Söderlund 			  0x3fff8c20, 0x001fe7e3, 0x04a368fd,
275f00add96SNiklas Söderlund 			  0x3fcf8c33, 0x000ff7e2, 0x0343b8ed,
276f00add96SNiklas Söderlund 			  0x3f9f8c4a, 0x000fffe3, 0x0203f8da,
277f00add96SNiklas Söderlund 			  0x3f5f9c61, 0x000003e6, 0x00e428c5,
278f00add96SNiklas Söderlund 			  0x3f1fb07b, 0x000003eb, 0x3fe440af },
279f00add96SNiklas Söderlund 	},
280f00add96SNiklas Söderlund 	{ 0x2000, {
281f00add96SNiklas Söderlund 			  0x000fa400, 0x000fa400, 0x09625902,
282f00add96SNiklas Söderlund 			  0x3fff980c, 0x001fb7f5, 0x0812b0ff,
283f00add96SNiklas Söderlund 			  0x3fdf901c, 0x001fc7ed, 0x06b2fcfa,
284f00add96SNiklas Söderlund 			  0x3faf902d, 0x001fd3e8, 0x055348f1,
285f00add96SNiklas Söderlund 			  0x3f7f983f, 0x001fe3e5, 0x04038ce3,
286f00add96SNiklas Söderlund 			  0x3f3fa454, 0x001fefe3, 0x02e3c8d1,
287f00add96SNiklas Söderlund 			  0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0,
288f00add96SNiklas Söderlund 			  0x3ecfd880, 0x000fffe6, 0x00c404ac },
289f00add96SNiklas Söderlund 	},
290f00add96SNiklas Söderlund 	{ 0x2200, {
291f00add96SNiklas Söderlund 			  0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4,
292f00add96SNiklas Söderlund 			  0x3fbf9818, 0x3fffa400, 0x0842a8f1,
293f00add96SNiklas Söderlund 			  0x3f8f9827, 0x000fb3f7, 0x0702f0ec,
294f00add96SNiklas Söderlund 			  0x3f5fa037, 0x000fc3ef, 0x05d330e4,
295f00add96SNiklas Söderlund 			  0x3f2fac49, 0x001fcfea, 0x04a364d9,
296f00add96SNiklas Söderlund 			  0x3effc05c, 0x001fdbe7, 0x038394ca,
297f00add96SNiklas Söderlund 			  0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb,
298f00add96SNiklas Söderlund 			  0x3ea00083, 0x001fefe6, 0x0183c0a9 },
299f00add96SNiklas Söderlund 	},
300f00add96SNiklas Söderlund 	{ 0x2400, {
301f00add96SNiklas Söderlund 			  0x3f9fa014, 0x3f9fa014, 0x098260e6,
302f00add96SNiklas Söderlund 			  0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5,
303f00add96SNiklas Söderlund 			  0x3f4fa431, 0x3fefa400, 0x0742d8e1,
304f00add96SNiklas Söderlund 			  0x3f1fb440, 0x3fffb3f8, 0x062310d9,
305f00add96SNiklas Söderlund 			  0x3eefc850, 0x000fbbf2, 0x050340d0,
306f00add96SNiklas Söderlund 			  0x3ecfe062, 0x000fcbec, 0x041364c2,
307f00add96SNiklas Söderlund 			  0x3ea00073, 0x001fd3ea, 0x03037cb5,
308f00add96SNiklas Söderlund 			  0x3e902086, 0x001fdfe8, 0x022388a5 },
309f00add96SNiklas Söderlund 	},
310f00add96SNiklas Söderlund 	{ 0x2600, {
311f00add96SNiklas Söderlund 			  0x3f5fa81e, 0x3f5fa81e, 0x096258da,
312f00add96SNiklas Söderlund 			  0x3f3fac2b, 0x3f8fa412, 0x088290d8,
313f00add96SNiklas Söderlund 			  0x3f0fbc38, 0x3fafa408, 0x0772c8d5,
314f00add96SNiklas Söderlund 			  0x3eefcc47, 0x3fcfa800, 0x0672f4ce,
315f00add96SNiklas Söderlund 			  0x3ecfe456, 0x3fefaffa, 0x05531cc6,
316f00add96SNiklas Söderlund 			  0x3eb00066, 0x3fffbbf3, 0x047334bb,
317f00add96SNiklas Söderlund 			  0x3ea01c77, 0x000fc7ee, 0x039348ae,
318f00add96SNiklas Söderlund 			  0x3ea04486, 0x000fd3eb, 0x02b350a1 },
319f00add96SNiklas Söderlund 	},
320f00add96SNiklas Söderlund 	{ 0x2800, {
321f00add96SNiklas Söderlund 			  0x3f2fb426, 0x3f2fb426, 0x094250ce,
322f00add96SNiklas Söderlund 			  0x3f0fc032, 0x3f4fac1b, 0x086284cd,
323f00add96SNiklas Söderlund 			  0x3eefd040, 0x3f7fa811, 0x0782acc9,
324f00add96SNiklas Söderlund 			  0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4,
325f00add96SNiklas Söderlund 			  0x3eb0005b, 0x3fbfac00, 0x05b2f4bc,
326f00add96SNiklas Söderlund 			  0x3eb0186a, 0x3fdfb3fa, 0x04c308b4,
327f00add96SNiklas Söderlund 			  0x3eb04077, 0x3fefbbf4, 0x03f31ca8,
328f00add96SNiklas Söderlund 			  0x3ec06884, 0x000fbff2, 0x03031c9e },
329f00add96SNiklas Söderlund 	},
330f00add96SNiklas Söderlund 	{ 0x2a00, {
331f00add96SNiklas Söderlund 			  0x3f0fc42d, 0x3f0fc42d, 0x090240c4,
332f00add96SNiklas Söderlund 			  0x3eefd439, 0x3f2fb822, 0x08526cc2,
333f00add96SNiklas Söderlund 			  0x3edfe845, 0x3f4fb018, 0x078294bf,
334f00add96SNiklas Söderlund 			  0x3ec00051, 0x3f6fac0f, 0x06b2b4bb,
335f00add96SNiklas Söderlund 			  0x3ec0185f, 0x3f8fac07, 0x05e2ccb4,
336f00add96SNiklas Söderlund 			  0x3ec0386b, 0x3fafac00, 0x0502e8ac,
337f00add96SNiklas Söderlund 			  0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3,
338f00add96SNiklas Söderlund 			  0x3ef08482, 0x3fdfbbf6, 0x0372f898 },
339f00add96SNiklas Söderlund 	},
340f00add96SNiklas Söderlund 	{ 0x2c00, {
341f00add96SNiklas Söderlund 			  0x3eefdc31, 0x3eefdc31, 0x08e238b8,
342f00add96SNiklas Söderlund 			  0x3edfec3d, 0x3f0fc828, 0x082258b9,
343f00add96SNiklas Söderlund 			  0x3ed00049, 0x3f1fc01e, 0x077278b6,
344f00add96SNiklas Söderlund 			  0x3ed01455, 0x3f3fb815, 0x06c294b2,
345f00add96SNiklas Söderlund 			  0x3ed03460, 0x3f5fb40d, 0x0602acac,
346f00add96SNiklas Söderlund 			  0x3ef0506c, 0x3f7fb006, 0x0542c0a4,
347f00add96SNiklas Söderlund 			  0x3f107476, 0x3f9fb400, 0x0472c89d,
348f00add96SNiklas Söderlund 			  0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 },
349f00add96SNiklas Söderlund 	},
350f00add96SNiklas Söderlund 	{ 0x2e00, {
351f00add96SNiklas Söderlund 			  0x3eefec37, 0x3eefec37, 0x088220b0,
352f00add96SNiklas Söderlund 			  0x3ee00041, 0x3effdc2d, 0x07f244ae,
353f00add96SNiklas Söderlund 			  0x3ee0144c, 0x3f0fd023, 0x07625cad,
354f00add96SNiklas Söderlund 			  0x3ef02c57, 0x3f1fc81a, 0x06c274a9,
355f00add96SNiklas Söderlund 			  0x3f004861, 0x3f3fbc13, 0x060288a6,
356f00add96SNiklas Söderlund 			  0x3f20686b, 0x3f5fb80c, 0x05529c9e,
357f00add96SNiklas Söderlund 			  0x3f408c74, 0x3f6fb805, 0x04b2ac96,
358f00add96SNiklas Söderlund 			  0x3f80ac7e, 0x3f8fb800, 0x0402ac8e },
359f00add96SNiklas Söderlund 	},
360f00add96SNiklas Söderlund 	{ 0x3000, {
361f00add96SNiklas Söderlund 			  0x3ef0003a, 0x3ef0003a, 0x084210a6,
362f00add96SNiklas Söderlund 			  0x3ef01045, 0x3effec32, 0x07b228a7,
363f00add96SNiklas Söderlund 			  0x3f00284e, 0x3f0fdc29, 0x073244a4,
364f00add96SNiklas Söderlund 			  0x3f104058, 0x3f0fd420, 0x06a258a2,
365f00add96SNiklas Söderlund 			  0x3f305c62, 0x3f2fc818, 0x0612689d,
366f00add96SNiklas Söderlund 			  0x3f508069, 0x3f3fc011, 0x05728496,
367f00add96SNiklas Söderlund 			  0x3f80a072, 0x3f4fc00a, 0x04d28c90,
368f00add96SNiklas Söderlund 			  0x3fc0c07b, 0x3f6fbc04, 0x04429088 },
369f00add96SNiklas Söderlund 	},
370f00add96SNiklas Söderlund 	{ 0x3200, {
371f00add96SNiklas Söderlund 			  0x3f00103e, 0x3f00103e, 0x07f1fc9e,
372f00add96SNiklas Söderlund 			  0x3f102447, 0x3f000035, 0x0782149d,
373f00add96SNiklas Söderlund 			  0x3f203c4f, 0x3f0ff02c, 0x07122c9c,
374f00add96SNiklas Söderlund 			  0x3f405458, 0x3f0fe424, 0x06924099,
375f00add96SNiklas Söderlund 			  0x3f607061, 0x3f1fd41d, 0x06024c97,
376f00add96SNiklas Söderlund 			  0x3f909068, 0x3f2fcc16, 0x05726490,
377f00add96SNiklas Söderlund 			  0x3fc0b070, 0x3f3fc80f, 0x04f26c8a,
378f00add96SNiklas Söderlund 			  0x0000d077, 0x3f4fc409, 0x04627484 },
379f00add96SNiklas Söderlund 	},
380f00add96SNiklas Söderlund 	{ 0x3400, {
381f00add96SNiklas Söderlund 			  0x3f202040, 0x3f202040, 0x07a1e898,
382f00add96SNiklas Söderlund 			  0x3f303449, 0x3f100c38, 0x0741fc98,
383f00add96SNiklas Söderlund 			  0x3f504c50, 0x3f10002f, 0x06e21495,
384f00add96SNiklas Söderlund 			  0x3f706459, 0x3f1ff028, 0x06722492,
385f00add96SNiklas Söderlund 			  0x3fa08060, 0x3f1fe421, 0x05f2348f,
386f00add96SNiklas Söderlund 			  0x3fd09c67, 0x3f1fdc19, 0x05824c89,
387f00add96SNiklas Söderlund 			  0x0000bc6e, 0x3f2fd014, 0x04f25086,
388f00add96SNiklas Söderlund 			  0x0040dc74, 0x3f3fcc0d, 0x04825c7f },
389f00add96SNiklas Söderlund 	},
390f00add96SNiklas Söderlund 	{ 0x3600, {
391f00add96SNiklas Söderlund 			  0x3f403042, 0x3f403042, 0x0761d890,
392f00add96SNiklas Söderlund 			  0x3f504848, 0x3f301c3b, 0x0701f090,
393f00add96SNiklas Söderlund 			  0x3f805c50, 0x3f200c33, 0x06a2008f,
394f00add96SNiklas Söderlund 			  0x3fa07458, 0x3f10002b, 0x06520c8d,
395f00add96SNiklas Söderlund 			  0x3fd0905e, 0x3f1ff424, 0x05e22089,
396f00add96SNiklas Söderlund 			  0x0000ac65, 0x3f1fe81d, 0x05823483,
397f00add96SNiklas Söderlund 			  0x0030cc6a, 0x3f2fdc18, 0x04f23c81,
398f00add96SNiklas Söderlund 			  0x0080e871, 0x3f2fd412, 0x0482407c },
399f00add96SNiklas Söderlund 	},
400f00add96SNiklas Söderlund 	{ 0x3800, {
401f00add96SNiklas Söderlund 			  0x3f604043, 0x3f604043, 0x0721c88a,
402f00add96SNiklas Söderlund 			  0x3f80544a, 0x3f502c3c, 0x06d1d88a,
403f00add96SNiklas Söderlund 			  0x3fb06851, 0x3f301c35, 0x0681e889,
404f00add96SNiklas Söderlund 			  0x3fd08456, 0x3f30082f, 0x0611fc88,
405f00add96SNiklas Söderlund 			  0x00009c5d, 0x3f200027, 0x05d20884,
406f00add96SNiklas Söderlund 			  0x0030b863, 0x3f2ff421, 0x05621880,
407f00add96SNiklas Söderlund 			  0x0070d468, 0x3f2fe81b, 0x0502247c,
408f00add96SNiklas Söderlund 			  0x00c0ec6f, 0x3f2fe015, 0x04a22877 },
409f00add96SNiklas Söderlund 	},
410f00add96SNiklas Söderlund 	{ 0x3a00, {
411f00add96SNiklas Söderlund 			  0x3f904c44, 0x3f904c44, 0x06e1b884,
412f00add96SNiklas Söderlund 			  0x3fb0604a, 0x3f70383e, 0x0691c885,
413f00add96SNiklas Söderlund 			  0x3fe07451, 0x3f502c36, 0x0661d483,
414f00add96SNiklas Söderlund 			  0x00009055, 0x3f401831, 0x0601ec81,
415f00add96SNiklas Söderlund 			  0x0030a85b, 0x3f300c2a, 0x05b1f480,
416f00add96SNiklas Söderlund 			  0x0070c061, 0x3f300024, 0x0562047a,
417f00add96SNiklas Söderlund 			  0x00b0d867, 0x3f3ff41e, 0x05020c77,
418f00add96SNiklas Söderlund 			  0x00f0f46b, 0x3f2fec19, 0x04a21474 },
419f00add96SNiklas Söderlund 	},
420f00add96SNiklas Söderlund 	{ 0x3c00, {
421f00add96SNiklas Söderlund 			  0x3fb05c43, 0x3fb05c43, 0x06c1b07e,
422f00add96SNiklas Söderlund 			  0x3fe06c4b, 0x3f902c3f, 0x0681c081,
423f00add96SNiklas Söderlund 			  0x0000844f, 0x3f703838, 0x0631cc7d,
424f00add96SNiklas Söderlund 			  0x00309855, 0x3f602433, 0x05d1d47e,
425f00add96SNiklas Söderlund 			  0x0060b459, 0x3f50142e, 0x0581e47b,
426f00add96SNiklas Söderlund 			  0x00a0c85f, 0x3f400828, 0x0531f078,
427f00add96SNiklas Söderlund 			  0x00e0e064, 0x3f300021, 0x0501fc73,
428f00add96SNiklas Söderlund 			  0x00b0fc6a, 0x3f3ff41d, 0x04a20873 },
429f00add96SNiklas Söderlund 	},
430f00add96SNiklas Söderlund 	{ 0x3e00, {
431f00add96SNiklas Söderlund 			  0x3fe06444, 0x3fe06444, 0x0681a07a,
432f00add96SNiklas Söderlund 			  0x00007849, 0x3fc0503f, 0x0641b07a,
433f00add96SNiklas Söderlund 			  0x0020904d, 0x3fa0403a, 0x05f1c07a,
434f00add96SNiklas Söderlund 			  0x0060a453, 0x3f803034, 0x05c1c878,
435f00add96SNiklas Söderlund 			  0x0090b858, 0x3f70202f, 0x0571d477,
436f00add96SNiklas Söderlund 			  0x00d0d05d, 0x3f501829, 0x0531e073,
437f00add96SNiklas Söderlund 			  0x0110e462, 0x3f500825, 0x04e1e471,
438f00add96SNiklas Söderlund 			  0x01510065, 0x3f40001f, 0x04a1f06d },
439f00add96SNiklas Söderlund 	},
440f00add96SNiklas Söderlund 	{ 0x4000, {
441f00add96SNiklas Söderlund 			  0x00007044, 0x00007044, 0x06519476,
442f00add96SNiklas Söderlund 			  0x00208448, 0x3fe05c3f, 0x0621a476,
443f00add96SNiklas Söderlund 			  0x0050984d, 0x3fc04c3a, 0x05e1b075,
444f00add96SNiklas Söderlund 			  0x0080ac52, 0x3fa03c35, 0x05a1b875,
445f00add96SNiklas Söderlund 			  0x00c0c056, 0x3f803030, 0x0561c473,
446f00add96SNiklas Söderlund 			  0x0100d45b, 0x3f70202b, 0x0521d46f,
447f00add96SNiklas Söderlund 			  0x0140e860, 0x3f601427, 0x04d1d46e,
448f00add96SNiklas Söderlund 			  0x01810064, 0x3f500822, 0x0491dc6b },
449f00add96SNiklas Söderlund 	},
450f00add96SNiklas Söderlund 	{ 0x5000, {
451f00add96SNiklas Söderlund 			  0x0110a442, 0x0110a442, 0x0551545e,
452f00add96SNiklas Söderlund 			  0x0140b045, 0x00e0983f, 0x0531585f,
453f00add96SNiklas Söderlund 			  0x0160c047, 0x00c08c3c, 0x0511645e,
454f00add96SNiklas Söderlund 			  0x0190cc4a, 0x00908039, 0x04f1685f,
455f00add96SNiklas Söderlund 			  0x01c0dc4c, 0x00707436, 0x04d1705e,
456f00add96SNiklas Söderlund 			  0x0200e850, 0x00506833, 0x04b1785b,
457f00add96SNiklas Söderlund 			  0x0230f453, 0x00305c30, 0x0491805a,
458f00add96SNiklas Söderlund 			  0x02710056, 0x0010542d, 0x04718059 },
459f00add96SNiklas Söderlund 	},
460f00add96SNiklas Söderlund 	{ 0x6000, {
461f00add96SNiklas Söderlund 			  0x01c0bc40, 0x01c0bc40, 0x04c13052,
462f00add96SNiklas Söderlund 			  0x01e0c841, 0x01a0b43d, 0x04c13851,
463f00add96SNiklas Söderlund 			  0x0210cc44, 0x0180a83c, 0x04a13453,
464f00add96SNiklas Söderlund 			  0x0230d845, 0x0160a03a, 0x04913c52,
465f00add96SNiklas Söderlund 			  0x0260e047, 0x01409838, 0x04714052,
466f00add96SNiklas Söderlund 			  0x0280ec49, 0x01208c37, 0x04514c50,
467f00add96SNiklas Söderlund 			  0x02b0f44b, 0x01008435, 0x04414c50,
468f00add96SNiklas Söderlund 			  0x02d1004c, 0x00e07c33, 0x0431544f },
469f00add96SNiklas Söderlund 	},
470f00add96SNiklas Söderlund 	{ 0x7000, {
471f00add96SNiklas Söderlund 			  0x0230c83e, 0x0230c83e, 0x04711c4c,
472f00add96SNiklas Söderlund 			  0x0250d03f, 0x0210c43c, 0x0471204b,
473f00add96SNiklas Söderlund 			  0x0270d840, 0x0200b83c, 0x0451244b,
474f00add96SNiklas Söderlund 			  0x0290dc42, 0x01e0b43a, 0x0441244c,
475f00add96SNiklas Söderlund 			  0x02b0e443, 0x01c0b038, 0x0441284b,
476f00add96SNiklas Söderlund 			  0x02d0ec44, 0x01b0a438, 0x0421304a,
477f00add96SNiklas Söderlund 			  0x02f0f445, 0x0190a036, 0x04213449,
478f00add96SNiklas Söderlund 			  0x0310f847, 0x01709c34, 0x04213848 },
479f00add96SNiklas Söderlund 	},
480f00add96SNiklas Söderlund 	{ 0x8000, {
481f00add96SNiklas Söderlund 			  0x0280d03d, 0x0280d03d, 0x04310c48,
482f00add96SNiklas Söderlund 			  0x02a0d43e, 0x0270c83c, 0x04311047,
483f00add96SNiklas Söderlund 			  0x02b0dc3e, 0x0250c83a, 0x04311447,
484f00add96SNiklas Söderlund 			  0x02d0e040, 0x0240c03a, 0x04211446,
485f00add96SNiklas Söderlund 			  0x02e0e840, 0x0220bc39, 0x04111847,
486f00add96SNiklas Söderlund 			  0x0300e842, 0x0210b438, 0x04012445,
487f00add96SNiklas Söderlund 			  0x0310f043, 0x0200b037, 0x04012045,
488f00add96SNiklas Söderlund 			  0x0330f444, 0x01e0ac36, 0x03f12445 },
489f00add96SNiklas Söderlund 	},
490f00add96SNiklas Söderlund 	{ 0xefff, {
491f00add96SNiklas Söderlund 			  0x0340dc3a, 0x0340dc3a, 0x03b0ec40,
492f00add96SNiklas Söderlund 			  0x0340e03a, 0x0330e039, 0x03c0f03e,
493f00add96SNiklas Söderlund 			  0x0350e03b, 0x0330dc39, 0x03c0ec3e,
494f00add96SNiklas Söderlund 			  0x0350e43a, 0x0320dc38, 0x03c0f43e,
495f00add96SNiklas Söderlund 			  0x0360e43b, 0x0320d839, 0x03b0f03e,
496f00add96SNiklas Söderlund 			  0x0360e83b, 0x0310d838, 0x03c0fc3b,
497f00add96SNiklas Söderlund 			  0x0370e83b, 0x0310d439, 0x03a0f83d,
498f00add96SNiklas Söderlund 			  0x0370e83c, 0x0300d438, 0x03b0fc3c },
499f00add96SNiklas Söderlund 	}
500f00add96SNiklas Söderlund };
501f00add96SNiklas Söderlund 
502f00add96SNiklas Söderlund static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
503f00add96SNiklas Söderlund {
504f00add96SNiklas Söderlund 	int i;
505f00add96SNiklas Söderlund 	const struct vin_coeff *p_prev_set = NULL;
506f00add96SNiklas Söderlund 	const struct vin_coeff *p_set = NULL;
507f00add96SNiklas Söderlund 
508f00add96SNiklas Söderlund 	/* Look for suitable coefficient values */
509f00add96SNiklas Söderlund 	for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
510f00add96SNiklas Söderlund 		p_prev_set = p_set;
511f00add96SNiklas Söderlund 		p_set = &vin_coeff_set[i];
512f00add96SNiklas Söderlund 
513f00add96SNiklas Söderlund 		if (xs < p_set->xs_value)
514f00add96SNiklas Söderlund 			break;
515f00add96SNiklas Söderlund 	}
516f00add96SNiklas Söderlund 
517f00add96SNiklas Söderlund 	/* Use previous value if its XS value is closer */
518bf78f23aSMauro Carvalho Chehab 	if (p_prev_set &&
519f00add96SNiklas Söderlund 	    xs - p_prev_set->xs_value < p_set->xs_value - xs)
520f00add96SNiklas Söderlund 		p_set = p_prev_set;
521f00add96SNiklas Söderlund 
522f00add96SNiklas Söderlund 	/* Set coefficient registers */
523f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[0], VNC1A_REG);
524f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[1], VNC1B_REG);
525f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[2], VNC1C_REG);
526f00add96SNiklas Söderlund 
527f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[3], VNC2A_REG);
528f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[4], VNC2B_REG);
529f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[5], VNC2C_REG);
530f00add96SNiklas Söderlund 
531f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[6], VNC3A_REG);
532f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[7], VNC3B_REG);
533f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[8], VNC3C_REG);
534f00add96SNiklas Söderlund 
535f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[9], VNC4A_REG);
536f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[10], VNC4B_REG);
537f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[11], VNC4C_REG);
538f00add96SNiklas Söderlund 
539f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[12], VNC5A_REG);
540f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[13], VNC5B_REG);
541f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[14], VNC5C_REG);
542f00add96SNiklas Söderlund 
543f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[15], VNC6A_REG);
544f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[16], VNC6B_REG);
545f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[17], VNC6C_REG);
546f00add96SNiklas Söderlund 
547f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[18], VNC7A_REG);
548f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[19], VNC7B_REG);
549f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[20], VNC7C_REG);
550f00add96SNiklas Söderlund 
551f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[21], VNC8A_REG);
552f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[22], VNC8B_REG);
553f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
554f00add96SNiklas Söderlund }
555f00add96SNiklas Söderlund 
5563ad69c61SNiklas Söderlund void rvin_scaler_gen2(struct rvin_dev *vin)
557f00add96SNiklas Söderlund {
55808369321SNiklas Söderlund 	unsigned int crop_height;
559f00add96SNiklas Söderlund 	u32 xs, ys;
560f00add96SNiklas Söderlund 
561f00add96SNiklas Söderlund 	/* Set scaling coefficient */
56208369321SNiklas Söderlund 	crop_height = vin->crop.height;
5637e0cfdadSNiklas Söderlund 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
56408369321SNiklas Söderlund 		crop_height *= 2;
56508369321SNiklas Söderlund 
566f00add96SNiklas Söderlund 	ys = 0;
56708369321SNiklas Söderlund 	if (crop_height != vin->compose.height)
56808369321SNiklas Söderlund 		ys = (4096 * crop_height) / vin->compose.height;
569f00add96SNiklas Söderlund 	rvin_write(vin, ys, VNYS_REG);
570f00add96SNiklas Söderlund 
571f00add96SNiklas Söderlund 	xs = 0;
572f00add96SNiklas Söderlund 	if (vin->crop.width != vin->compose.width)
573f00add96SNiklas Söderlund 		xs = (4096 * vin->crop.width) / vin->compose.width;
574f00add96SNiklas Söderlund 
575f00add96SNiklas Söderlund 	/* Horizontal upscaling is up to double size */
576f00add96SNiklas Söderlund 	if (xs > 0 && xs < 2048)
577f00add96SNiklas Söderlund 		xs = 2048;
578f00add96SNiklas Söderlund 
579f00add96SNiklas Söderlund 	rvin_write(vin, xs, VNXS_REG);
580f00add96SNiklas Söderlund 
581f00add96SNiklas Söderlund 	/* Horizontal upscaling is done out by scaling down from double size */
582f00add96SNiklas Söderlund 	if (xs < 4096)
583f00add96SNiklas Söderlund 		xs *= 2;
584f00add96SNiklas Söderlund 
585f00add96SNiklas Söderlund 	rvin_set_coeff(vin, xs);
586f00add96SNiklas Söderlund 
587f00add96SNiklas Söderlund 	/* Set Start/End Pixel/Line Post-Clip */
588f00add96SNiklas Söderlund 	rvin_write(vin, 0, VNSPPOC_REG);
589f00add96SNiklas Söderlund 	rvin_write(vin, 0, VNSLPOC_REG);
590f00add96SNiklas Söderlund 	rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
591d23e12dcSNiklas Söderlund 
5927e0cfdadSNiklas Söderlund 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
593f00add96SNiklas Söderlund 		rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
594d23e12dcSNiklas Söderlund 	else
595f00add96SNiklas Söderlund 		rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
596f00add96SNiklas Söderlund 
597f00add96SNiklas Söderlund 	vin_dbg(vin,
598f00add96SNiklas Söderlund 		"Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
599f00add96SNiklas Söderlund 		vin->crop.width, vin->crop.height, vin->crop.left,
600f00add96SNiklas Söderlund 		vin->crop.top, ys, xs, vin->format.width, vin->format.height,
601f00add96SNiklas Söderlund 		0, 0);
602f00add96SNiklas Söderlund }
603f00add96SNiklas Söderlund 
604928a6ea4SNiklas Söderlund static unsigned int rvin_uds_scale_ratio(unsigned int in, unsigned int out)
605928a6ea4SNiklas Söderlund {
606928a6ea4SNiklas Söderlund 	unsigned int ratio;
607928a6ea4SNiklas Söderlund 
608928a6ea4SNiklas Söderlund 	ratio = in * 4096 / out;
609928a6ea4SNiklas Söderlund 	return ratio >= 0x10000 ? 0xffff : ratio;
610928a6ea4SNiklas Söderlund }
611928a6ea4SNiklas Söderlund 
612928a6ea4SNiklas Söderlund static unsigned int rvin_uds_filter_width(unsigned int ratio)
613928a6ea4SNiklas Söderlund {
614928a6ea4SNiklas Söderlund 	if (ratio >= 0x1000)
615928a6ea4SNiklas Söderlund 		return 64 * (ratio & 0xf000) / ratio;
616928a6ea4SNiklas Söderlund 
617928a6ea4SNiklas Söderlund 	return 64;
618928a6ea4SNiklas Söderlund }
619928a6ea4SNiklas Söderlund 
620928a6ea4SNiklas Söderlund void rvin_scaler_gen3(struct rvin_dev *vin)
621928a6ea4SNiklas Söderlund {
622928a6ea4SNiklas Söderlund 	unsigned int ratio_h, ratio_v;
623928a6ea4SNiklas Söderlund 	unsigned int bwidth_h, bwidth_v;
624928a6ea4SNiklas Söderlund 	u32 vnmc, clip_size;
625928a6ea4SNiklas Söderlund 
626928a6ea4SNiklas Söderlund 	vnmc = rvin_read(vin, VNMC_REG);
627928a6ea4SNiklas Söderlund 
628928a6ea4SNiklas Söderlund 	/* Disable scaler if not needed. */
629928a6ea4SNiklas Söderlund 	if (!rvin_scaler_needed(vin)) {
630928a6ea4SNiklas Söderlund 		rvin_write(vin, vnmc & ~VNMC_SCLE, VNMC_REG);
631928a6ea4SNiklas Söderlund 		return;
632928a6ea4SNiklas Söderlund 	}
633928a6ea4SNiklas Söderlund 
634928a6ea4SNiklas Söderlund 	ratio_h = rvin_uds_scale_ratio(vin->crop.width, vin->compose.width);
635928a6ea4SNiklas Söderlund 	bwidth_h = rvin_uds_filter_width(ratio_h);
636928a6ea4SNiklas Söderlund 
637928a6ea4SNiklas Söderlund 	ratio_v = rvin_uds_scale_ratio(vin->crop.height, vin->compose.height);
638928a6ea4SNiklas Söderlund 	bwidth_v = rvin_uds_filter_width(ratio_v);
639928a6ea4SNiklas Söderlund 
640928a6ea4SNiklas Söderlund 	clip_size = vin->compose.width << 16;
641928a6ea4SNiklas Söderlund 
642928a6ea4SNiklas Söderlund 	switch (vin->format.field) {
643928a6ea4SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_TB:
644928a6ea4SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_BT:
645928a6ea4SNiklas Söderlund 	case V4L2_FIELD_INTERLACED:
646928a6ea4SNiklas Söderlund 		clip_size |= vin->compose.height / 2;
647928a6ea4SNiklas Söderlund 		break;
648928a6ea4SNiklas Söderlund 	default:
649928a6ea4SNiklas Söderlund 		clip_size |= vin->compose.height;
650928a6ea4SNiklas Söderlund 		break;
651928a6ea4SNiklas Söderlund 	}
652928a6ea4SNiklas Söderlund 
653928a6ea4SNiklas Söderlund 	rvin_write(vin, vnmc | VNMC_SCLE, VNMC_REG);
654928a6ea4SNiklas Söderlund 	rvin_write(vin, VNUDS_CTRL_AMD, VNUDS_CTRL_REG);
655928a6ea4SNiklas Söderlund 	rvin_write(vin, (ratio_h << 16) | ratio_v, VNUDS_SCALE_REG);
656928a6ea4SNiklas Söderlund 	rvin_write(vin, (bwidth_h << 16) | bwidth_v, VNUDS_PASS_BWIDTH_REG);
657928a6ea4SNiklas Söderlund 	rvin_write(vin, clip_size, VNUDS_CLIP_SIZE_REG);
658928a6ea4SNiklas Söderlund 
659928a6ea4SNiklas Söderlund 	vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u Post-Clip: %ux%u@%u:%u\n",
660928a6ea4SNiklas Söderlund 		vin->crop.width, vin->crop.height, vin->crop.left,
661928a6ea4SNiklas Söderlund 		vin->crop.top, vin->compose.width, vin->compose.height,
662928a6ea4SNiklas Söderlund 		vin->compose.left, vin->compose.top);
663928a6ea4SNiklas Söderlund }
664928a6ea4SNiklas Söderlund 
6654394eb24SNiklas Söderlund void rvin_crop_scale_comp(struct rvin_dev *vin)
6664394eb24SNiklas Söderlund {
66784246ae3SNiklas Söderlund 	const struct rvin_video_format *fmt;
66884246ae3SNiklas Söderlund 	u32 stride;
66984246ae3SNiklas Söderlund 
6704394eb24SNiklas Söderlund 	/* Set Start/End Pixel/Line Pre-Clip */
6714394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.left, VNSPPRC_REG);
6724394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
6734394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.top, VNSLPRC_REG);
67408369321SNiklas Söderlund 	rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG);
67508369321SNiklas Söderlund 
6763ad69c61SNiklas Söderlund 	if (vin->scaler)
6773ad69c61SNiklas Söderlund 		vin->scaler(vin);
6784394eb24SNiklas Söderlund 
67984246ae3SNiklas Söderlund 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
68084246ae3SNiklas Söderlund 	stride = vin->format.bytesperline / fmt->bpp;
68184246ae3SNiklas Söderlund 	rvin_write(vin, stride, VNIS_REG);
6824394eb24SNiklas Söderlund }
6834394eb24SNiklas Söderlund 
684f00add96SNiklas Söderlund /* -----------------------------------------------------------------------------
6850f4b3378SNiklas Söderlund  * Hardware setup
6860f4b3378SNiklas Söderlund  */
6870f4b3378SNiklas Söderlund 
6880f4b3378SNiklas Söderlund static int rvin_setup(struct rvin_dev *vin)
6890f4b3378SNiklas Söderlund {
690d73c3357SNiklas Söderlund 	u32 vnmc, dmr, dmr2, interrupts;
6910f4b3378SNiklas Söderlund 	bool progressive = false, output_is_yuv = false, input_is_yuv = false;
6920f4b3378SNiklas Söderlund 
6930f4b3378SNiklas Söderlund 	switch (vin->format.field) {
6940f4b3378SNiklas Söderlund 	case V4L2_FIELD_TOP:
6950f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_ODD;
6960f4b3378SNiklas Söderlund 		break;
6970f4b3378SNiklas Söderlund 	case V4L2_FIELD_BOTTOM:
6980f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_EVEN;
6990f4b3378SNiklas Söderlund 		break;
7000f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED:
7010f4b3378SNiklas Söderlund 		/* Default to TB */
7020f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL;
7030f4b3378SNiklas Söderlund 		/* Use BT if video standard can be read and is 60 Hz format */
7045e7c6236SNiklas Söderlund 		if (!vin->info->use_mc && vin->std & V4L2_STD_525_60)
7050f4b3378SNiklas Söderlund 			vnmc = VNMC_IM_FULL | VNMC_FOC;
7060f4b3378SNiklas Söderlund 		break;
7070f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_TB:
7080f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL;
7090f4b3378SNiklas Söderlund 		break;
7100f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_BT:
7110f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL | VNMC_FOC;
7120f4b3378SNiklas Söderlund 		break;
7130f4b3378SNiklas Söderlund 	case V4L2_FIELD_NONE:
71408369321SNiklas Söderlund 	case V4L2_FIELD_ALTERNATE:
71508369321SNiklas Söderlund 		vnmc = VNMC_IM_ODD_EVEN;
716e10707d5SNiklas Söderlund 		progressive = true;
71708369321SNiklas Söderlund 		break;
7180f4b3378SNiklas Söderlund 	default:
7190f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_ODD;
7200f4b3378SNiklas Söderlund 		break;
7210f4b3378SNiklas Söderlund 	}
7220f4b3378SNiklas Söderlund 
7230f4b3378SNiklas Söderlund 	/*
7240f4b3378SNiklas Söderlund 	 * Input interface
7250f4b3378SNiklas Söderlund 	 */
726c65c99b4SNiklas Söderlund 	switch (vin->mbus_code) {
7270f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_YUYV8_1X16:
7289caf253eSJacopo Mondi 		if (vin->is_csi)
7299caf253eSJacopo Mondi 			/* YCbCr422 8-bit */
7309caf253eSJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT601;
7319caf253eSJacopo Mondi 		else
7320f4b3378SNiklas Söderlund 			/* BT.601/BT.1358 16bit YCbCr422 */
7330f4b3378SNiklas Söderlund 			vnmc |= VNMC_INF_YUV16;
7340f4b3378SNiklas Söderlund 		input_is_yuv = true;
7350f4b3378SNiklas Söderlund 		break;
73601d72e9dSNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_1X16:
7379caf253eSJacopo Mondi 		if (vin->is_csi)
7389caf253eSJacopo Mondi 			/* YCbCr422 8-bit */
7399caf253eSJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT601;
7409caf253eSJacopo Mondi 		else
7419caf253eSJacopo Mondi 			/* BT.601/BT.1358 16bit YCbCr422 */
7429caf253eSJacopo Mondi 			vnmc |= VNMC_INF_YUV16;
7439caf253eSJacopo Mondi 		vnmc |= VNMC_YCAL;
74401d72e9dSNiklas Söderlund 		input_is_yuv = true;
74501d72e9dSNiklas Söderlund 		break;
7460f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_2X8:
7470f4b3378SNiklas Söderlund 		/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
748158e2a53SJacopo Mondi 		if (!vin->is_csi &&
749d7592b2eSNiklas Söderlund 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
750158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT656;
751158e2a53SJacopo Mondi 		else
752158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT601;
753158e2a53SJacopo Mondi 
7540f4b3378SNiklas Söderlund 		input_is_yuv = true;
7550f4b3378SNiklas Söderlund 		break;
7560f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_RGB888_1X24:
7570f4b3378SNiklas Söderlund 		vnmc |= VNMC_INF_RGB888;
7580f4b3378SNiklas Söderlund 		break;
7590f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY10_2X10:
7600f4b3378SNiklas Söderlund 		/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
761158e2a53SJacopo Mondi 		if (!vin->is_csi &&
762d7592b2eSNiklas Söderlund 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
763158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV10_BT656;
764158e2a53SJacopo Mondi 		else
765158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV10_BT601;
766158e2a53SJacopo Mondi 
7670f4b3378SNiklas Söderlund 		input_is_yuv = true;
7680f4b3378SNiklas Söderlund 		break;
7698c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR8_1X8:
7708c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG8_1X8:
7718c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG8_1X8:
772e87c1a81SLad Prabhakar 	case MEDIA_BUS_FMT_SRGGB8_1X8:
773c93beb52SVladimir Barinov 	case MEDIA_BUS_FMT_Y8_1X8:
774e87c1a81SLad Prabhakar 		vnmc |= VNMC_INF_RAW8;
77517b5496cSTomi Valkeinen 		if (vin->info->model == RCAR_GEN4)
77617b5496cSTomi Valkeinen 			vnmc |= VNMC_EXINF_RAW8;
777e87c1a81SLad Prabhakar 		break;
7781b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR10_1X10:
7791b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG10_1X10:
7801b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG10_1X10:
7811b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SRGGB10_1X10:
7821b7e7240SNiklas Söderlund 		vnmc |= VNMC_INF_RGB666;
7831b7e7240SNiklas Söderlund 		break;
7840f4b3378SNiklas Söderlund 	default:
7850f4b3378SNiklas Söderlund 		break;
7860f4b3378SNiklas Söderlund 	}
7870f4b3378SNiklas Söderlund 
7888b72c18dSMauro Carvalho Chehab 	/* Enable VSYNC Field Toggle mode after one VSYNC input */
789d6a08667STomi Valkeinen 	if (vin->info->model == RCAR_GEN3 || vin->info->model == RCAR_GEN4)
790d73c3357SNiklas Söderlund 		dmr2 = VNDMR2_FTEV;
791d73c3357SNiklas Söderlund 	else
7920f4b3378SNiklas Söderlund 		dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
7930f4b3378SNiklas Söderlund 
794158e2a53SJacopo Mondi 	if (!vin->is_csi) {
7950f4b3378SNiklas Söderlund 		/* Hsync Signal Polarity Select */
796d7592b2eSNiklas Söderlund 		if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
7970f4b3378SNiklas Söderlund 			dmr2 |= VNDMR2_HPS;
7980f4b3378SNiklas Söderlund 
7990f4b3378SNiklas Söderlund 		/* Vsync Signal Polarity Select */
800d7592b2eSNiklas Söderlund 		if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
8010f4b3378SNiklas Söderlund 			dmr2 |= VNDMR2_VPS;
80253cf3100SJacopo Mondi 
80353cf3100SJacopo Mondi 		/* Data Enable Polarity Select */
804d7592b2eSNiklas Söderlund 		if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW)
80553cf3100SJacopo Mondi 			dmr2 |= VNDMR2_CES;
806e8834943SLad Prabhakar 
807e8834943SLad Prabhakar 		switch (vin->mbus_code) {
808e8834943SLad Prabhakar 		case MEDIA_BUS_FMT_UYVY8_2X8:
809d7592b2eSNiklas Söderlund 			if (vin->parallel.bus.bus_width == 8 &&
810d7592b2eSNiklas Söderlund 			    vin->parallel.bus.data_shift == 8)
811e8834943SLad Prabhakar 				dmr2 |= VNDMR2_YDS;
812e8834943SLad Prabhakar 			break;
813e8834943SLad Prabhakar 		default:
814e8834943SLad Prabhakar 			break;
815e8834943SLad Prabhakar 		}
816158e2a53SJacopo Mondi 	}
8170f4b3378SNiklas Söderlund 
8180f4b3378SNiklas Söderlund 	/*
8190f4b3378SNiklas Söderlund 	 * Output format
8200f4b3378SNiklas Söderlund 	 */
8210f4b3378SNiklas Söderlund 	switch (vin->format.pixelformat) {
8229b744a3eSNiklas Söderlund 	case V4L2_PIX_FMT_NV12:
8230f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_NV16:
8240f4b3378SNiklas Söderlund 		rvin_write(vin,
8255c9de1faSNiklas Söderlund 			   ALIGN(vin->format.bytesperline * vin->format.height,
8265c9de1faSNiklas Söderlund 				 0x80), VNUVAOF_REG);
8279b744a3eSNiklas Söderlund 		dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ?
8289b744a3eSNiklas Söderlund 			VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP;
8290f4b3378SNiklas Söderlund 		output_is_yuv = true;
8300f4b3378SNiklas Söderlund 		break;
8310f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_YUYV:
8320f4b3378SNiklas Söderlund 		dmr = VNDMR_BPSM;
8330f4b3378SNiklas Söderlund 		output_is_yuv = true;
8340f4b3378SNiklas Söderlund 		break;
8350f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_UYVY:
8360f4b3378SNiklas Söderlund 		dmr = 0;
8370f4b3378SNiklas Söderlund 		output_is_yuv = true;
8380f4b3378SNiklas Söderlund 		break;
8390f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_XRGB555:
84019ab1f64SNiklas Söderlund 		dmr = VNDMR_DTMD_ARGB;
8410f4b3378SNiklas Söderlund 		break;
8420f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_RGB565:
8430f4b3378SNiklas Söderlund 		dmr = 0;
8440f4b3378SNiklas Söderlund 		break;
8450f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_XBGR32:
8460f4b3378SNiklas Söderlund 		/* Note: not supported on M1 */
8470f4b3378SNiklas Söderlund 		dmr = VNDMR_EXRGB;
8480f4b3378SNiklas Söderlund 		break;
8491d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ARGB555:
8501d99e68cSNiklas Söderlund 		dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB;
8511d99e68cSNiklas Söderlund 		break;
8521d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ABGR32:
8531d99e68cSNiklas Söderlund 		dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB;
8541d99e68cSNiklas Söderlund 		break;
8558c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SBGGR8:
8568c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SGBRG8:
8578c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SGRBG8:
858e87c1a81SLad Prabhakar 	case V4L2_PIX_FMT_SRGGB8:
859e87c1a81SLad Prabhakar 		dmr = 0;
860e87c1a81SLad Prabhakar 		break;
861c93beb52SVladimir Barinov 	case V4L2_PIX_FMT_GREY:
862c93beb52SVladimir Barinov 		if (input_is_yuv) {
863c93beb52SVladimir Barinov 			dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8;
864c93beb52SVladimir Barinov 			output_is_yuv = true;
865c93beb52SVladimir Barinov 		} else {
866c93beb52SVladimir Barinov 			dmr = 0;
867c93beb52SVladimir Barinov 		}
868c93beb52SVladimir Barinov 		break;
8691b7e7240SNiklas Söderlund 	case V4L2_PIX_FMT_SBGGR10:
8701b7e7240SNiklas Söderlund 	case V4L2_PIX_FMT_SGBRG10:
8711b7e7240SNiklas Söderlund 	case V4L2_PIX_FMT_SGRBG10:
8721b7e7240SNiklas Söderlund 	case V4L2_PIX_FMT_SRGGB10:
873*94bf847aSTomi Valkeinen 		dmr = VNDMR_RMODE_RAW10;
8741b7e7240SNiklas Söderlund 		break;
8750f4b3378SNiklas Söderlund 	default:
8760f4b3378SNiklas Söderlund 		vin_err(vin, "Invalid pixelformat (0x%x)\n",
8770f4b3378SNiklas Söderlund 			vin->format.pixelformat);
8780f4b3378SNiklas Söderlund 		return -EINVAL;
8790f4b3378SNiklas Söderlund 	}
8800f4b3378SNiklas Söderlund 
8810f4b3378SNiklas Söderlund 	/* Always update on field change */
8820f4b3378SNiklas Söderlund 	vnmc |= VNMC_VUP;
8830f4b3378SNiklas Söderlund 
884406bb586SNiklas Söderlund 	if (!vin->info->use_isp) {
8850f4b3378SNiklas Söderlund 		/* If input and output use the same colorspace, use bypass mode */
8860f4b3378SNiklas Söderlund 		if (input_is_yuv == output_is_yuv)
8870f4b3378SNiklas Söderlund 			vnmc |= VNMC_BPS;
8880f4b3378SNiklas Söderlund 
889d6a08667STomi Valkeinen 		if (vin->info->model == RCAR_GEN3 || vin->info->model == RCAR_GEN4) {
890d24c029eSJacopo Mondi 			/* Select between CSI-2 and parallel input */
891158e2a53SJacopo Mondi 			if (vin->is_csi)
8924394eb24SNiklas Söderlund 				vnmc &= ~VNMC_DPINE;
8934394eb24SNiklas Söderlund 			else
8944394eb24SNiklas Söderlund 				vnmc |= VNMC_DPINE;
8954394eb24SNiklas Söderlund 		}
896406bb586SNiklas Söderlund 	}
8974394eb24SNiklas Söderlund 
8980f4b3378SNiklas Söderlund 	/* Progressive or interlaced mode */
8990f4b3378SNiklas Söderlund 	interrupts = progressive ? VNIE_FIE : VNIE_EFE;
9000f4b3378SNiklas Söderlund 
9010f4b3378SNiklas Söderlund 	/* Ack interrupts */
9020f4b3378SNiklas Söderlund 	rvin_write(vin, interrupts, VNINTS_REG);
9030f4b3378SNiklas Söderlund 	/* Enable interrupts */
9040f4b3378SNiklas Söderlund 	rvin_write(vin, interrupts, VNIE_REG);
9050f4b3378SNiklas Söderlund 	/* Start capturing */
9060f4b3378SNiklas Söderlund 	rvin_write(vin, dmr, VNDMR_REG);
9070f4b3378SNiklas Söderlund 	rvin_write(vin, dmr2, VNDMR2_REG);
9080f4b3378SNiklas Söderlund 
9090f4b3378SNiklas Söderlund 	/* Enable module */
9100f4b3378SNiklas Söderlund 	rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
9110f4b3378SNiklas Söderlund 
9120f4b3378SNiklas Söderlund 	return 0;
9130f4b3378SNiklas Söderlund }
9140f4b3378SNiklas Söderlund 
9150f4b3378SNiklas Söderlund static void rvin_disable_interrupts(struct rvin_dev *vin)
9160f4b3378SNiklas Söderlund {
9170f4b3378SNiklas Söderlund 	rvin_write(vin, 0, VNIE_REG);
9180f4b3378SNiklas Söderlund }
9190f4b3378SNiklas Söderlund 
9200f4b3378SNiklas Söderlund static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
9210f4b3378SNiklas Söderlund {
9220f4b3378SNiklas Söderlund 	return rvin_read(vin, VNINTS_REG);
9230f4b3378SNiklas Söderlund }
9240f4b3378SNiklas Söderlund 
9250f4b3378SNiklas Söderlund static void rvin_ack_interrupt(struct rvin_dev *vin)
9260f4b3378SNiklas Söderlund {
9270f4b3378SNiklas Söderlund 	rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
9280f4b3378SNiklas Söderlund }
9290f4b3378SNiklas Söderlund 
9300f4b3378SNiklas Söderlund static bool rvin_capture_active(struct rvin_dev *vin)
9310f4b3378SNiklas Söderlund {
9320f4b3378SNiklas Söderlund 	return rvin_read(vin, VNMS_REG) & VNMS_CA;
9330f4b3378SNiklas Söderlund }
9340f4b3378SNiklas Söderlund 
93508369321SNiklas Söderlund static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
93608369321SNiklas Söderlund {
93708369321SNiklas Söderlund 	if (vin->format.field == V4L2_FIELD_ALTERNATE) {
93808369321SNiklas Söderlund 		/* If FS is set it is an Even field. */
93908369321SNiklas Söderlund 		if (vnms & VNMS_FS)
94008369321SNiklas Söderlund 			return V4L2_FIELD_BOTTOM;
94108369321SNiklas Söderlund 		return V4L2_FIELD_TOP;
94208369321SNiklas Söderlund 	}
94308369321SNiklas Söderlund 
94408369321SNiklas Söderlund 	return vin->format.field;
94508369321SNiklas Söderlund }
94608369321SNiklas Söderlund 
9470f4b3378SNiklas Söderlund static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
9480f4b3378SNiklas Söderlund {
9490f4b3378SNiklas Söderlund 	const struct rvin_video_format *fmt;
9500f4b3378SNiklas Söderlund 	int offsetx, offsety;
9510f4b3378SNiklas Söderlund 	dma_addr_t offset;
9520f4b3378SNiklas Söderlund 
95321a816e7SNiklas Söderlund 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
9540f4b3378SNiklas Söderlund 
9550f4b3378SNiklas Söderlund 	/*
9560f4b3378SNiklas Söderlund 	 * There is no HW support for composition do the beast we can
9570f4b3378SNiklas Söderlund 	 * by modifying the buffer offset
9580f4b3378SNiklas Söderlund 	 */
9590f4b3378SNiklas Söderlund 	offsetx = vin->compose.left * fmt->bpp;
9600f4b3378SNiklas Söderlund 	offsety = vin->compose.top * vin->format.bytesperline;
9610f4b3378SNiklas Söderlund 	offset = addr + offsetx + offsety;
9620f4b3378SNiklas Söderlund 
9630f4b3378SNiklas Söderlund 	/*
9640f4b3378SNiklas Söderlund 	 * The address needs to be 128 bytes aligned. Driver should never accept
9650f4b3378SNiklas Söderlund 	 * settings that do not satisfy this in the first place...
9660f4b3378SNiklas Söderlund 	 */
9670f4b3378SNiklas Söderlund 	if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
9680f4b3378SNiklas Söderlund 		return;
9690f4b3378SNiklas Söderlund 
9700f4b3378SNiklas Söderlund 	rvin_write(vin, offset, VNMB_REG(slot));
9710f4b3378SNiklas Söderlund }
9720f4b3378SNiklas Söderlund 
9730f4b3378SNiklas Söderlund /*
9740f4b3378SNiklas Söderlund  * Moves a buffer from the queue to the HW slot. If no buffer is
9750f4b3378SNiklas Söderlund  * available use the scratch buffer. The scratch buffer is never
9760f4b3378SNiklas Söderlund  * returned to userspace, its only function is to enable the capture
9770f4b3378SNiklas Söderlund  * loop to keep running.
9780f4b3378SNiklas Söderlund  */
9790f4b3378SNiklas Söderlund static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
9800f4b3378SNiklas Söderlund {
9810f4b3378SNiklas Söderlund 	struct rvin_buffer *buf;
9820f4b3378SNiklas Söderlund 	struct vb2_v4l2_buffer *vbuf;
9830f4b3378SNiklas Söderlund 	dma_addr_t phys_addr;
9840f4b3378SNiklas Söderlund 
9850f4b3378SNiklas Söderlund 	/* A already populated slot shall never be overwritten. */
986e72b7359SNiklas Söderlund 	if (WARN_ON(vin->buf_hw[slot].buffer))
9870f4b3378SNiklas Söderlund 		return;
9880f4b3378SNiklas Söderlund 
989c1eefe88SNiklas Söderlund 	if (list_empty(&vin->buf_list)) {
990e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
9910f4b3378SNiklas Söderlund 		phys_addr = vin->scratch_phys;
9920f4b3378SNiklas Söderlund 	} else {
9930f4b3378SNiklas Söderlund 		/* Keep track of buffer we give to HW */
9940f4b3378SNiklas Söderlund 		buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
9950f4b3378SNiklas Söderlund 		vbuf = &buf->vb;
9960f4b3378SNiklas Söderlund 		list_del_init(to_buf_list(vbuf));
997e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = vbuf;
9980f4b3378SNiklas Söderlund 
9990f4b3378SNiklas Söderlund 		/* Setup DMA */
10000f4b3378SNiklas Söderlund 		phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
10010f4b3378SNiklas Söderlund 	}
10020f4b3378SNiklas Söderlund 
1003f2f0cd89SNiklas Söderlund 	vin_dbg(vin, "Filling HW slot: %d buffer: %p\n",
1004f2f0cd89SNiklas Söderlund 		slot, vin->buf_hw[slot].buffer);
10057e0cfdadSNiklas Söderlund 
10067e0cfdadSNiklas Söderlund 	vin->buf_hw[slot].phys = phys_addr;
10070f4b3378SNiklas Söderlund 	rvin_set_slot_addr(vin, slot, phys_addr);
10080f4b3378SNiklas Söderlund }
10090f4b3378SNiklas Söderlund 
10100f4b3378SNiklas Söderlund static int rvin_capture_start(struct rvin_dev *vin)
10110f4b3378SNiklas Söderlund {
1012f2f0cd89SNiklas Söderlund 	int ret;
10130f4b3378SNiklas Söderlund 
1014f2f0cd89SNiklas Söderlund 	for (unsigned int slot = 0; slot < HW_BUFFER_NUM; slot++) {
10157e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
10160f4b3378SNiklas Söderlund 		rvin_fill_hw_slot(vin, slot);
1017f2f0cd89SNiklas Söderlund 	}
10180f4b3378SNiklas Söderlund 
10190f4b3378SNiklas Söderlund 	ret = rvin_setup(vin);
10200f4b3378SNiklas Söderlund 	if (ret)
10210f4b3378SNiklas Söderlund 		return ret;
10220f4b3378SNiklas Söderlund 
10233ad69c61SNiklas Söderlund 	rvin_crop_scale_comp(vin);
10243ad69c61SNiklas Söderlund 
10250f4b3378SNiklas Söderlund 	vin_dbg(vin, "Starting to capture\n");
10260f4b3378SNiklas Söderlund 
10270f4b3378SNiklas Söderlund 	/* Continuous Frame Capture Mode */
10280f4b3378SNiklas Söderlund 	rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
10290f4b3378SNiklas Söderlund 
10300f4b3378SNiklas Söderlund 	return 0;
10310f4b3378SNiklas Söderlund }
10320f4b3378SNiklas Söderlund 
10330f4b3378SNiklas Söderlund static void rvin_capture_stop(struct rvin_dev *vin)
10340f4b3378SNiklas Söderlund {
10350f4b3378SNiklas Söderlund 	/* Set continuous & single transfer off */
10360f4b3378SNiklas Söderlund 	rvin_write(vin, 0, VNFC_REG);
10370f4b3378SNiklas Söderlund 
10380f4b3378SNiklas Söderlund 	/* Disable module */
10390f4b3378SNiklas Söderlund 	rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
10400f4b3378SNiklas Söderlund }
10410f4b3378SNiklas Söderlund 
10420f4b3378SNiklas Söderlund /* -----------------------------------------------------------------------------
1043f00add96SNiklas Söderlund  * DMA Functions
1044f00add96SNiklas Söderlund  */
1045f00add96SNiklas Söderlund 
1046f00add96SNiklas Söderlund #define RVIN_TIMEOUT_MS 100
1047f00add96SNiklas Söderlund #define RVIN_RETRIES 10
1048f00add96SNiklas Söderlund 
1049f00add96SNiklas Söderlund static irqreturn_t rvin_irq(int irq, void *data)
1050f00add96SNiklas Söderlund {
1051f00add96SNiklas Söderlund 	struct rvin_dev *vin = data;
1052b6f556cbSNiklas Söderlund 	u32 int_status, vnms;
1053f00add96SNiklas Söderlund 	int slot;
1054dc9aec79SNiklas Söderlund 	unsigned int handled = 0;
1055f00add96SNiklas Söderlund 	unsigned long flags;
1056f00add96SNiklas Söderlund 
1057f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1058f00add96SNiklas Söderlund 
1059f00add96SNiklas Söderlund 	int_status = rvin_get_interrupt_status(vin);
1060f00add96SNiklas Söderlund 	if (!int_status)
1061f00add96SNiklas Söderlund 		goto done;
1062f00add96SNiklas Söderlund 
1063f00add96SNiklas Söderlund 	rvin_ack_interrupt(vin);
1064f00add96SNiklas Söderlund 	handled = 1;
1065f00add96SNiklas Söderlund 
106630334d3dSNiklas Söderlund 	/* Nothing to do if nothing was captured. */
106730334d3dSNiklas Söderlund 	if (!(int_status & VNINTS_FIS))
106830334d3dSNiklas Söderlund 		goto done;
106930334d3dSNiklas Söderlund 
1070c1eefe88SNiklas Söderlund 	/* Nothing to do if not running. */
1071c1eefe88SNiklas Söderlund 	if (!vin->running) {
1072c1eefe88SNiklas Söderlund 		vin_dbg(vin, "IRQ while not running, ignoring\n");
1073f00add96SNiklas Söderlund 		goto done;
1074f00add96SNiklas Söderlund 	}
1075f00add96SNiklas Söderlund 
1076f00add96SNiklas Söderlund 	/* Prepare for capture and update state */
1077b6f556cbSNiklas Söderlund 	vnms = rvin_read(vin, VNMS_REG);
1078dc9aec79SNiklas Söderlund 	slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
1079f00add96SNiklas Söderlund 
108023689ab1SNiklas Söderlund 	/*
108123689ab1SNiklas Söderlund 	 * To hand buffers back in a known order to userspace start
108223689ab1SNiklas Söderlund 	 * to capture first from slot 0.
108323689ab1SNiklas Söderlund 	 */
108425482a98SNiklas Söderlund 	if (!vin->sequence) {
108523689ab1SNiklas Söderlund 		if (slot != 0) {
108623689ab1SNiklas Söderlund 			vin_dbg(vin, "Starting sync slot: %d\n", slot);
108723689ab1SNiklas Söderlund 			goto done;
108823689ab1SNiklas Söderlund 		}
108923689ab1SNiklas Söderlund 
109023689ab1SNiklas Söderlund 		vin_dbg(vin, "Capture start synced!\n");
109123689ab1SNiklas Söderlund 	}
109223689ab1SNiklas Söderlund 
1093f00add96SNiklas Söderlund 	/* Capture frame */
1094e72b7359SNiklas Söderlund 	if (vin->buf_hw[slot].buffer) {
1095e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->field =
1096e72b7359SNiklas Söderlund 			rvin_get_active_field(vin, vnms);
1097e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->sequence = vin->sequence;
1098e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns();
1099e72b7359SNiklas Söderlund 		vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf,
1100dc9aec79SNiklas Söderlund 				VB2_BUF_STATE_DONE);
1101e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
1102dc9aec79SNiklas Söderlund 	} else {
1103dc9aec79SNiklas Söderlund 		/* Scratch buffer was used, dropping frame. */
1104dc9aec79SNiklas Söderlund 		vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
1105dc9aec79SNiklas Söderlund 	}
1106dc9aec79SNiklas Söderlund 
1107dc9aec79SNiklas Söderlund 	vin->sequence++;
1108f00add96SNiklas Söderlund 
1109f00add96SNiklas Söderlund 	/* Prepare for next frame */
1110dc9aec79SNiklas Söderlund 	rvin_fill_hw_slot(vin, slot);
1111f00add96SNiklas Söderlund done:
1112f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1113f00add96SNiklas Söderlund 
1114f00add96SNiklas Söderlund 	return IRQ_RETVAL(handled);
1115f00add96SNiklas Söderlund }
1116f00add96SNiklas Söderlund 
1117b83a18ccSNiklas Söderlund static void return_unused_buffers(struct rvin_dev *vin,
1118f00add96SNiklas Söderlund 				  enum vb2_buffer_state state)
1119f00add96SNiklas Söderlund {
1120f00add96SNiklas Söderlund 	struct rvin_buffer *buf, *node;
112163a71dd8SNiklas Söderlund 	unsigned long flags;
112263a71dd8SNiklas Söderlund 
112363a71dd8SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
11247e0cfdadSNiklas Söderlund 
1125f00add96SNiklas Söderlund 	list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
1126f00add96SNiklas Söderlund 		vb2_buffer_done(&buf->vb.vb2_buf, state);
1127f00add96SNiklas Söderlund 		list_del(&buf->list);
1128f00add96SNiklas Söderlund 	}
112963a71dd8SNiklas Söderlund 
113063a71dd8SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1131f00add96SNiklas Söderlund }
1132f00add96SNiklas Söderlund 
1133f00add96SNiklas Söderlund static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1134f00add96SNiklas Söderlund 			    unsigned int *nplanes, unsigned int sizes[],
113536c0f8b3SHans Verkuil 			    struct device *alloc_devs[])
1136f00add96SNiklas Söderlund 
1137f00add96SNiklas Söderlund {
1138f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
1139f00add96SNiklas Söderlund 
1140f00add96SNiklas Söderlund 	/* Make sure the image size is large enough. */
1141f00add96SNiklas Söderlund 	if (*nplanes)
1142f00add96SNiklas Söderlund 		return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1143f00add96SNiklas Söderlund 
1144f00add96SNiklas Söderlund 	*nplanes = 1;
1145f00add96SNiklas Söderlund 	sizes[0] = vin->format.sizeimage;
1146f00add96SNiklas Söderlund 
1147f00add96SNiklas Söderlund 	return 0;
1148f00add96SNiklas Söderlund };
1149f00add96SNiklas Söderlund 
1150f00add96SNiklas Söderlund static int rvin_buffer_prepare(struct vb2_buffer *vb)
1151f00add96SNiklas Söderlund {
1152f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1153f00add96SNiklas Söderlund 	unsigned long size = vin->format.sizeimage;
1154f00add96SNiklas Söderlund 
1155f00add96SNiklas Söderlund 	if (vb2_plane_size(vb, 0) < size) {
1156f00add96SNiklas Söderlund 		vin_err(vin, "buffer too small (%lu < %lu)\n",
1157f00add96SNiklas Söderlund 			vb2_plane_size(vb, 0), size);
1158f00add96SNiklas Söderlund 		return -EINVAL;
1159f00add96SNiklas Söderlund 	}
1160f00add96SNiklas Söderlund 
1161f00add96SNiklas Söderlund 	vb2_set_plane_payload(vb, 0, size);
1162f00add96SNiklas Söderlund 
1163f00add96SNiklas Söderlund 	return 0;
1164f00add96SNiklas Söderlund }
1165f00add96SNiklas Söderlund 
1166f00add96SNiklas Söderlund static void rvin_buffer_queue(struct vb2_buffer *vb)
1167f00add96SNiklas Söderlund {
1168f00add96SNiklas Söderlund 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1169f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1170f00add96SNiklas Söderlund 	unsigned long flags;
1171f00add96SNiklas Söderlund 
1172f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1173f00add96SNiklas Söderlund 
1174f00add96SNiklas Söderlund 	list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1175f00add96SNiklas Söderlund 
1176f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1177f00add96SNiklas Söderlund }
1178f00add96SNiklas Söderlund 
11797b7eb115SNiklas Söderlund static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
11807b7eb115SNiklas Söderlund 				   struct media_pad *pad)
11817b7eb115SNiklas Söderlund {
11827b7eb115SNiklas Söderlund 	struct v4l2_subdev_format fmt = {
11837b7eb115SNiklas Söderlund 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
11847b7eb115SNiklas Söderlund 	};
11857b7eb115SNiklas Söderlund 
11867b7eb115SNiklas Söderlund 	fmt.pad = pad->index;
11877b7eb115SNiklas Söderlund 	if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt))
11887b7eb115SNiklas Söderlund 		return -EPIPE;
11897b7eb115SNiklas Söderlund 
11907b7eb115SNiklas Söderlund 	switch (fmt.format.code) {
11917b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_YUYV8_1X16:
119201d72e9dSNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_1X16:
11937b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_2X8:
11947b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY10_2X10:
11957b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_RGB888_1X24:
1196fd22e8ebSLad Prabhakar 		break;
11978c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR8_1X8:
11988c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8)
11998c3e0f67SNiklas Söderlund 			return -EPIPE;
12008c3e0f67SNiklas Söderlund 		break;
12018c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG8_1X8:
12028c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8)
12038c3e0f67SNiklas Söderlund 			return -EPIPE;
12048c3e0f67SNiklas Söderlund 		break;
12058c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG8_1X8:
12068c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8)
12078c3e0f67SNiklas Söderlund 			return -EPIPE;
12088c3e0f67SNiklas Söderlund 		break;
1209fd22e8ebSLad Prabhakar 	case MEDIA_BUS_FMT_SRGGB8_1X8:
1210fd22e8ebSLad Prabhakar 		if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8)
1211fd22e8ebSLad Prabhakar 			return -EPIPE;
12127b7eb115SNiklas Söderlund 		break;
1213c93beb52SVladimir Barinov 	case MEDIA_BUS_FMT_Y8_1X8:
1214c93beb52SVladimir Barinov 		if (vin->format.pixelformat != V4L2_PIX_FMT_GREY)
1215c93beb52SVladimir Barinov 			return -EPIPE;
1216c93beb52SVladimir Barinov 		break;
12171b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR10_1X10:
12181b7e7240SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10)
12191b7e7240SNiklas Söderlund 			return -EPIPE;
12201b7e7240SNiklas Söderlund 		break;
12211b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG10_1X10:
12221b7e7240SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10)
12231b7e7240SNiklas Söderlund 			return -EPIPE;
12241b7e7240SNiklas Söderlund 		break;
12251b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG10_1X10:
12261b7e7240SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10)
12271b7e7240SNiklas Söderlund 			return -EPIPE;
12281b7e7240SNiklas Söderlund 		break;
12291b7e7240SNiklas Söderlund 	case MEDIA_BUS_FMT_SRGGB10_1X10:
12301b7e7240SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10)
12311b7e7240SNiklas Söderlund 			return -EPIPE;
12321b7e7240SNiklas Söderlund 		break;
12337b7eb115SNiklas Söderlund 	default:
12347b7eb115SNiklas Söderlund 		return -EPIPE;
12357b7eb115SNiklas Söderlund 	}
1236fd22e8ebSLad Prabhakar 	vin->mbus_code = fmt.format.code;
12377b7eb115SNiklas Söderlund 
12387b7eb115SNiklas Söderlund 	switch (fmt.format.field) {
12397b7eb115SNiklas Söderlund 	case V4L2_FIELD_TOP:
12407b7eb115SNiklas Söderlund 	case V4L2_FIELD_BOTTOM:
12417b7eb115SNiklas Söderlund 	case V4L2_FIELD_NONE:
12427b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_TB:
12437b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_BT:
12447b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED:
12457b7eb115SNiklas Söderlund 		/* Supported natively */
12467b7eb115SNiklas Söderlund 		break;
12477b7eb115SNiklas Söderlund 	case V4L2_FIELD_ALTERNATE:
12487b7eb115SNiklas Söderlund 		switch (vin->format.field) {
12497b7eb115SNiklas Söderlund 		case V4L2_FIELD_TOP:
12507b7eb115SNiklas Söderlund 		case V4L2_FIELD_BOTTOM:
12517b7eb115SNiklas Söderlund 		case V4L2_FIELD_NONE:
125208369321SNiklas Söderlund 		case V4L2_FIELD_ALTERNATE:
12537b7eb115SNiklas Söderlund 			break;
12547b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED_TB:
12557b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED_BT:
12567b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED:
12577b7eb115SNiklas Söderlund 			/* Use VIN hardware to combine the two fields */
12587b7eb115SNiklas Söderlund 			fmt.format.height *= 2;
12597b7eb115SNiklas Söderlund 			break;
12607b7eb115SNiklas Söderlund 		default:
12617b7eb115SNiklas Söderlund 			return -EPIPE;
12627b7eb115SNiklas Söderlund 		}
12637b7eb115SNiklas Söderlund 		break;
12647b7eb115SNiklas Söderlund 	default:
12657b7eb115SNiklas Söderlund 		return -EPIPE;
12667b7eb115SNiklas Söderlund 	}
12677b7eb115SNiklas Söderlund 
12683ad69c61SNiklas Söderlund 	if (rvin_scaler_needed(vin)) {
1269879c5a45SNiklas Söderlund 		/* Gen3 can't scale NV12 */
1270d6a08667STomi Valkeinen 		if ((vin->info->model == RCAR_GEN3 || vin->info->model == RCAR_GEN4) &&
1271879c5a45SNiklas Söderlund 		    vin->format.pixelformat == V4L2_PIX_FMT_NV12)
1272879c5a45SNiklas Söderlund 			return -EPIPE;
1273879c5a45SNiklas Söderlund 
12743ad69c61SNiklas Söderlund 		if (!vin->scaler)
12753ad69c61SNiklas Söderlund 			return -EPIPE;
12763ad69c61SNiklas Söderlund 	} else {
1277cb88d828SNiklas Söderlund 		if (vin->format.pixelformat == V4L2_PIX_FMT_NV12) {
1278cb88d828SNiklas Söderlund 			if (ALIGN(fmt.format.width, 32) != vin->format.width ||
1279cb88d828SNiklas Söderlund 			    ALIGN(fmt.format.height, 32) != vin->format.height)
1280cb88d828SNiklas Söderlund 				return -EPIPE;
1281cb88d828SNiklas Söderlund 		} else {
12827b7eb115SNiklas Söderlund 			if (fmt.format.width != vin->format.width ||
12833ad69c61SNiklas Söderlund 			    fmt.format.height != vin->format.height)
12843ad69c61SNiklas Söderlund 				return -EPIPE;
12853ad69c61SNiklas Söderlund 		}
1286cb88d828SNiklas Söderlund 	}
12873ad69c61SNiklas Söderlund 
12883ad69c61SNiklas Söderlund 	if (fmt.format.code != vin->mbus_code)
12897b7eb115SNiklas Söderlund 		return -EPIPE;
12907b7eb115SNiklas Söderlund 
12917b7eb115SNiklas Söderlund 	return 0;
12927b7eb115SNiklas Söderlund }
12937b7eb115SNiklas Söderlund 
12947b7eb115SNiklas Söderlund static int rvin_set_stream(struct rvin_dev *vin, int on)
12957b7eb115SNiklas Söderlund {
12967b7eb115SNiklas Söderlund 	struct v4l2_subdev *sd;
12977b7eb115SNiklas Söderlund 	struct media_pad *pad;
12987b7eb115SNiklas Söderlund 	int ret;
12997b7eb115SNiklas Söderlund 
13007b7eb115SNiklas Söderlund 	/* No media controller used, simply pass operation to subdevice. */
13017b7eb115SNiklas Söderlund 	if (!vin->info->use_mc) {
1302d7592b2eSNiklas Söderlund 		ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream,
13037b7eb115SNiklas Söderlund 				       on);
13047b7eb115SNiklas Söderlund 
13057b7eb115SNiklas Söderlund 		return ret == -ENOIOCTLCMD ? 0 : ret;
13067b7eb115SNiklas Söderlund 	}
13077b7eb115SNiklas Söderlund 
1308b2e44430SLaurent Pinchart 	pad = media_pad_remote_pad_first(&vin->pad);
13097b7eb115SNiklas Söderlund 	if (!pad)
13107b7eb115SNiklas Söderlund 		return -EPIPE;
13117b7eb115SNiklas Söderlund 
13127b7eb115SNiklas Söderlund 	sd = media_entity_to_v4l2_subdev(pad->entity);
13137b7eb115SNiklas Söderlund 
13147b7eb115SNiklas Söderlund 	if (!on) {
131512cecbf9STomi Valkeinen 		video_device_pipeline_stop(&vin->vdev);
1316178c1be5STomi Valkeinen 		return v4l2_subdev_disable_streams(sd, pad->index, BIT_ULL(0));
13177b7eb115SNiklas Söderlund 	}
13187b7eb115SNiklas Söderlund 
13197b7eb115SNiklas Söderlund 	ret = rvin_mc_validate_format(vin, sd, pad);
13207b7eb115SNiklas Söderlund 	if (ret)
13217b7eb115SNiklas Söderlund 		return ret;
13227b7eb115SNiklas Söderlund 
13236eaff06aSTomi Valkeinen 	ret = video_device_pipeline_alloc_start(&vin->vdev);
13247b7eb115SNiklas Söderlund 	if (ret)
13257b7eb115SNiklas Söderlund 		return ret;
13267b7eb115SNiklas Söderlund 
1327178c1be5STomi Valkeinen 	ret = v4l2_subdev_enable_streams(sd, pad->index, BIT_ULL(0));
13287b7eb115SNiklas Söderlund 	if (ret == -ENOIOCTLCMD)
13297b7eb115SNiklas Söderlund 		ret = 0;
13307b7eb115SNiklas Söderlund 	if (ret)
133112cecbf9STomi Valkeinen 		video_device_pipeline_stop(&vin->vdev);
13327b7eb115SNiklas Söderlund 
13337b7eb115SNiklas Söderlund 	return ret;
13347b7eb115SNiklas Söderlund }
13357b7eb115SNiklas Söderlund 
133663a71dd8SNiklas Söderlund int rvin_start_streaming(struct rvin_dev *vin)
1337f00add96SNiklas Söderlund {
1338f00add96SNiklas Söderlund 	unsigned long flags;
1339f00add96SNiklas Söderlund 	int ret;
1340f00add96SNiklas Söderlund 
13417b7eb115SNiklas Söderlund 	ret = rvin_set_stream(vin, 1);
134263a71dd8SNiklas Söderlund 	if (ret)
134363a71dd8SNiklas Söderlund 		return ret;
1344f00add96SNiklas Söderlund 
1345f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1346f00add96SNiklas Söderlund 
1347f00add96SNiklas Söderlund 	vin->sequence = 0;
1348f00add96SNiklas Söderlund 
1349f00add96SNiklas Söderlund 	ret = rvin_capture_start(vin);
135063a71dd8SNiklas Söderlund 	if (ret)
13517b7eb115SNiklas Söderlund 		rvin_set_stream(vin, 0);
1352f00add96SNiklas Söderlund 
1353c1eefe88SNiklas Söderlund 	vin->running = true;
1354c1eefe88SNiklas Söderlund 
1355f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
13566a8ffa8bSNiklas Söderlund 
1357f00add96SNiklas Söderlund 	return ret;
1358f00add96SNiklas Söderlund }
1359f00add96SNiklas Söderlund 
136063a71dd8SNiklas Söderlund static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
1361f00add96SNiklas Söderlund {
1362f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
136363a71dd8SNiklas Söderlund 	int ret = -ENOMEM;
136463a71dd8SNiklas Söderlund 
136563a71dd8SNiklas Söderlund 	/* Allocate scratch buffer. */
136663a71dd8SNiklas Söderlund 	vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage,
136763a71dd8SNiklas Söderlund 					  &vin->scratch_phys, GFP_KERNEL);
136863a71dd8SNiklas Söderlund 	if (!vin->scratch)
136963a71dd8SNiklas Söderlund 		goto err_scratch;
137063a71dd8SNiklas Söderlund 
137163a71dd8SNiklas Söderlund 	ret = rvin_start_streaming(vin);
137263a71dd8SNiklas Söderlund 	if (ret)
137363a71dd8SNiklas Söderlund 		goto err_start;
137463a71dd8SNiklas Söderlund 
137563a71dd8SNiklas Söderlund 	return 0;
137663a71dd8SNiklas Söderlund err_start:
137763a71dd8SNiklas Söderlund 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
137863a71dd8SNiklas Söderlund 			  vin->scratch_phys);
137963a71dd8SNiklas Söderlund err_scratch:
138063a71dd8SNiklas Söderlund 	return_unused_buffers(vin, VB2_BUF_STATE_QUEUED);
138163a71dd8SNiklas Söderlund 
138263a71dd8SNiklas Söderlund 	return ret;
138363a71dd8SNiklas Söderlund }
138463a71dd8SNiklas Söderlund 
138563a71dd8SNiklas Söderlund void rvin_stop_streaming(struct rvin_dev *vin)
138663a71dd8SNiklas Söderlund {
1387f00add96SNiklas Söderlund 	unsigned long flags;
1388f00add96SNiklas Söderlund 
1389f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1390f00add96SNiklas Söderlund 
1391c1eefe88SNiklas Söderlund 	if (!vin->running) {
1392c4f11535SNiklas Söderlund 		spin_unlock_irqrestore(&vin->qlock, flags);
1393c4f11535SNiklas Söderlund 		return;
1394c4f11535SNiklas Söderlund 	}
1395c4f11535SNiklas Söderlund 
1396f00add96SNiklas Söderlund 	/* Wait for streaming to stop */
1397c1eefe88SNiklas Söderlund 	for (unsigned int i = 0; i < RVIN_RETRIES; i++) {
1398f00add96SNiklas Söderlund 		rvin_capture_stop(vin);
1399f00add96SNiklas Söderlund 
1400f00add96SNiklas Söderlund 		/* Check if HW is stopped */
1401f00add96SNiklas Söderlund 		if (!rvin_capture_active(vin)) {
1402f00add96SNiklas Söderlund 			break;
1403f00add96SNiklas Söderlund 		}
1404f00add96SNiklas Söderlund 
1405f00add96SNiklas Söderlund 		spin_unlock_irqrestore(&vin->qlock, flags);
1406f00add96SNiklas Söderlund 		msleep(RVIN_TIMEOUT_MS);
1407f00add96SNiklas Söderlund 		spin_lock_irqsave(&vin->qlock, flags);
1408f00add96SNiklas Söderlund 	}
1409f00add96SNiklas Söderlund 
1410c1eefe88SNiklas Söderlund 	if (rvin_capture_active(vin))
1411c1eefe88SNiklas Söderlund 		vin_err(vin, "Hardware did not stop\n");
1412c1eefe88SNiklas Söderlund 
1413c1eefe88SNiklas Söderlund 	vin->running = false;
1414f00add96SNiklas Söderlund 
1415f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1416f00add96SNiklas Söderlund 
14177b7eb115SNiklas Söderlund 	rvin_set_stream(vin, 0);
1418f00add96SNiklas Söderlund 
1419f00add96SNiklas Söderlund 	/* disable interrupts */
1420f00add96SNiklas Söderlund 	rvin_disable_interrupts(vin);
1421c1eefe88SNiklas Söderlund 
1422c1eefe88SNiklas Söderlund 	/* Return unprocessed buffers from hardware. */
1423c1eefe88SNiklas Söderlund 	for (unsigned int i = 0; i < HW_BUFFER_NUM; i++) {
1424c1eefe88SNiklas Söderlund 		if (vin->buf_hw[i].buffer)
1425c1eefe88SNiklas Söderlund 			vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
1426c1eefe88SNiklas Söderlund 					VB2_BUF_STATE_ERROR);
1427c1eefe88SNiklas Söderlund 	}
1428c1eefe88SNiklas Söderlund 
142963a71dd8SNiklas Söderlund }
143063a71dd8SNiklas Söderlund 
143163a71dd8SNiklas Söderlund static void rvin_stop_streaming_vq(struct vb2_queue *vq)
143263a71dd8SNiklas Söderlund {
143363a71dd8SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
143463a71dd8SNiklas Söderlund 
143563a71dd8SNiklas Söderlund 	rvin_stop_streaming(vin);
14366a8ffa8bSNiklas Söderlund 
14376a8ffa8bSNiklas Söderlund 	/* Free scratch buffer. */
14386a8ffa8bSNiklas Söderlund 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
14396a8ffa8bSNiklas Söderlund 			  vin->scratch_phys);
144063a71dd8SNiklas Söderlund 
144163a71dd8SNiklas Söderlund 	return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
1442f00add96SNiklas Söderlund }
1443f00add96SNiklas Söderlund 
1444b7b361f0SJulia Lawall static const struct vb2_ops rvin_qops = {
1445f00add96SNiklas Söderlund 	.queue_setup		= rvin_queue_setup,
1446f00add96SNiklas Söderlund 	.buf_prepare		= rvin_buffer_prepare,
1447f00add96SNiklas Söderlund 	.buf_queue		= rvin_buffer_queue,
144863a71dd8SNiklas Söderlund 	.start_streaming	= rvin_start_streaming_vq,
144963a71dd8SNiklas Söderlund 	.stop_streaming		= rvin_stop_streaming_vq,
1450f00add96SNiklas Söderlund };
1451f00add96SNiklas Söderlund 
1452d6ad012eSNiklas Söderlund void rvin_dma_unregister(struct rvin_dev *vin)
1453f00add96SNiklas Söderlund {
1454f00add96SNiklas Söderlund 	mutex_destroy(&vin->lock);
1455f00add96SNiklas Söderlund 
1456f00add96SNiklas Söderlund 	v4l2_device_unregister(&vin->v4l2_dev);
1457f00add96SNiklas Söderlund }
1458f00add96SNiklas Söderlund 
1459d6ad012eSNiklas Söderlund int rvin_dma_register(struct rvin_dev *vin, int irq)
1460f00add96SNiklas Söderlund {
1461f00add96SNiklas Söderlund 	struct vb2_queue *q = &vin->queue;
1462f00add96SNiklas Söderlund 	int i, ret;
1463f00add96SNiklas Söderlund 
1464f00add96SNiklas Söderlund 	/* Initialize the top-level structure */
1465f00add96SNiklas Söderlund 	ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1466f00add96SNiklas Söderlund 	if (ret)
1467f00add96SNiklas Söderlund 		return ret;
1468f00add96SNiklas Söderlund 
1469f00add96SNiklas Söderlund 	mutex_init(&vin->lock);
1470f00add96SNiklas Söderlund 	INIT_LIST_HEAD(&vin->buf_list);
1471f00add96SNiklas Söderlund 
1472f00add96SNiklas Söderlund 	spin_lock_init(&vin->qlock);
1473f00add96SNiklas Söderlund 
1474f00add96SNiklas Söderlund 	for (i = 0; i < HW_BUFFER_NUM; i++)
1475e72b7359SNiklas Söderlund 		vin->buf_hw[i].buffer = NULL;
1476f00add96SNiklas Söderlund 
1477f00add96SNiklas Söderlund 	/* buffer queue */
1478f00add96SNiklas Söderlund 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1479f00add96SNiklas Söderlund 	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
1480f00add96SNiklas Söderlund 	q->lock = &vin->lock;
1481f00add96SNiklas Söderlund 	q->drv_priv = vin;
1482f00add96SNiklas Söderlund 	q->buf_struct_size = sizeof(struct rvin_buffer);
1483f00add96SNiklas Söderlund 	q->ops = &rvin_qops;
1484f00add96SNiklas Söderlund 	q->mem_ops = &vb2_dma_contig_memops;
1485f00add96SNiklas Söderlund 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
148680c2b40aSBenjamin Gaignard 	q->min_queued_buffers = 4;
148753ddcc68SHans Verkuil 	q->dev = vin->dev;
1488f00add96SNiklas Söderlund 
1489f00add96SNiklas Söderlund 	ret = vb2_queue_init(q);
1490f00add96SNiklas Söderlund 	if (ret < 0) {
1491f00add96SNiklas Söderlund 		vin_err(vin, "failed to initialize VB2 queue\n");
1492f00add96SNiklas Söderlund 		goto error;
1493f00add96SNiklas Söderlund 	}
1494f00add96SNiklas Söderlund 
1495f00add96SNiklas Söderlund 	/* irq */
1496f00add96SNiklas Söderlund 	ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED,
1497f00add96SNiklas Söderlund 			       KBUILD_MODNAME, vin);
1498f00add96SNiklas Söderlund 	if (ret) {
1499f00add96SNiklas Söderlund 		vin_err(vin, "failed to request irq\n");
1500f00add96SNiklas Söderlund 		goto error;
1501f00add96SNiklas Söderlund 	}
1502f00add96SNiklas Söderlund 
1503f00add96SNiklas Söderlund 	return 0;
1504f00add96SNiklas Söderlund error:
1505d6ad012eSNiklas Söderlund 	rvin_dma_unregister(vin);
1506f00add96SNiklas Söderlund 
1507f00add96SNiklas Söderlund 	return ret;
1508f00add96SNiklas Söderlund }
150990dedce9SNiklas Söderlund 
151090dedce9SNiklas Söderlund /* -----------------------------------------------------------------------------
151190dedce9SNiklas Söderlund  * Gen3 CHSEL manipulation
151290dedce9SNiklas Söderlund  */
151390dedce9SNiklas Söderlund 
151490dedce9SNiklas Söderlund /*
151590dedce9SNiklas Söderlund  * There is no need to have locking around changing the routing
151690dedce9SNiklas Söderlund  * as it's only possible to do so when no VIN in the group is
151790dedce9SNiklas Söderlund  * streaming so nothing can race with the VNMC register.
151890dedce9SNiklas Söderlund  */
151990dedce9SNiklas Söderlund int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
152090dedce9SNiklas Söderlund {
1521fb25ca37SJacopo Mondi 	const struct rvin_group_route *route;
1522fb25ca37SJacopo Mondi 	u32 ifmd = 0;
1523fb25ca37SJacopo Mondi 	u32 vnmc;
152490dedce9SNiklas Söderlund 	int ret;
152590dedce9SNiklas Söderlund 
1526334fe327SMauro Carvalho Chehab 	ret = pm_runtime_resume_and_get(vin->dev);
1527334fe327SMauro Carvalho Chehab 	if (ret < 0)
152890dedce9SNiklas Söderlund 		return ret;
152990dedce9SNiklas Söderlund 
153090dedce9SNiklas Söderlund 	/* Make register writes take effect immediately. */
153190dedce9SNiklas Söderlund 	vnmc = rvin_read(vin, VNMC_REG);
153290dedce9SNiklas Söderlund 	rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG);
153390dedce9SNiklas Söderlund 
1534fb25ca37SJacopo Mondi 	/*
1535fb25ca37SJacopo Mondi 	 * Set data expansion mode to "pad with 0s" by inspecting the routes
1536fb25ca37SJacopo Mondi 	 * table to find out which bit fields are available in the IFMD
1537fb25ca37SJacopo Mondi 	 * register. IFMD_DES1 controls data expansion mode for CSI20/21,
1538fb25ca37SJacopo Mondi 	 * IFMD_DES0 controls data expansion mode for CSI40/41.
1539fb25ca37SJacopo Mondi 	 */
15403e52419eSNiklas Söderlund 	for (route = vin->info->routes; route->chsel; route++) {
1541fb25ca37SJacopo Mondi 		if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
1542fb25ca37SJacopo Mondi 			ifmd |= VNCSI_IFMD_DES1;
1543fb25ca37SJacopo Mondi 		else
1544fb25ca37SJacopo Mondi 			ifmd |= VNCSI_IFMD_DES0;
154590dedce9SNiklas Söderlund 
1546fb25ca37SJacopo Mondi 		if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1))
1547fb25ca37SJacopo Mondi 			break;
1548fb25ca37SJacopo Mondi 	}
1549fb25ca37SJacopo Mondi 
1550fb25ca37SJacopo Mondi 	if (ifmd) {
1551fb25ca37SJacopo Mondi 		ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel);
155290dedce9SNiklas Söderlund 		rvin_write(vin, ifmd, VNCSI_IFMD_REG);
1553fb25ca37SJacopo Mondi 	}
155490dedce9SNiklas Söderlund 
155590dedce9SNiklas Söderlund 	vin_dbg(vin, "Set IFMD 0x%x\n", ifmd);
155690dedce9SNiklas Söderlund 
155743e36a22SNiklas Söderlund 	vin->chsel = chsel;
155843e36a22SNiklas Söderlund 
155990dedce9SNiklas Söderlund 	/* Restore VNMC. */
156090dedce9SNiklas Söderlund 	rvin_write(vin, vnmc, VNMC_REG);
156190dedce9SNiklas Söderlund 
156290dedce9SNiklas Söderlund 	pm_runtime_put(vin->dev);
156390dedce9SNiklas Söderlund 
15648d19d5d0SNiklas Söderlund 	return 0;
156590dedce9SNiklas Söderlund }
15665720c733SNiklas Söderlund 
15675720c733SNiklas Söderlund void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha)
15685720c733SNiklas Söderlund {
15691d99e68cSNiklas Söderlund 	unsigned long flags;
15701d99e68cSNiklas Söderlund 	u32 dmr;
15711d99e68cSNiklas Söderlund 
15721d99e68cSNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
15731d99e68cSNiklas Söderlund 
15745720c733SNiklas Söderlund 	vin->alpha = alpha;
15751d99e68cSNiklas Söderlund 
1576c1eefe88SNiklas Söderlund 	if (!vin->running)
15771d99e68cSNiklas Söderlund 		goto out;
15781d99e68cSNiklas Söderlund 
15791d99e68cSNiklas Söderlund 	switch (vin->format.pixelformat) {
15801d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ARGB555:
15811d99e68cSNiklas Söderlund 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT;
15821d99e68cSNiklas Söderlund 		if (vin->alpha)
15831d99e68cSNiklas Söderlund 			dmr |= VNDMR_ABIT;
15841d99e68cSNiklas Söderlund 		break;
15851d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ABGR32:
15861d99e68cSNiklas Söderlund 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK;
15871d99e68cSNiklas Söderlund 		dmr |= VNDMR_A8BIT(vin->alpha);
15881d99e68cSNiklas Söderlund 		break;
15891d99e68cSNiklas Söderlund 	default:
15901d99e68cSNiklas Söderlund 		goto out;
15911d99e68cSNiklas Söderlund 	}
15921d99e68cSNiklas Söderlund 
15931d99e68cSNiklas Söderlund 	rvin_write(vin, dmr,  VNDMR_REG);
15941d99e68cSNiklas Söderlund out:
15951d99e68cSNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
15965720c733SNiklas Söderlund }
1597