xref: /linux/drivers/media/platform/renesas/rcar-vin/rcar-dma.c (revision 3ad69c610ba8a3f7cf76bc856ca62c92d2bd955f)
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 */
77f00add96SNiklas Söderlund 
78f00add96SNiklas Söderlund /* Register bit fields for R-Car VIN */
79f00add96SNiklas Söderlund /* Video n Main Control Register bits */
8078b3f9d7SNiklas Söderlund #define VNMC_INF_MASK		(7 << 16)
814394eb24SNiklas Söderlund #define VNMC_DPINE		(1 << 27) /* Gen3 specific */
824394eb24SNiklas Söderlund #define VNMC_SCLE		(1 << 26) /* Gen3 specific */
83f00add96SNiklas Söderlund #define VNMC_FOC		(1 << 21)
84f00add96SNiklas Söderlund #define VNMC_YCAL		(1 << 19)
85f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT656	(0 << 16)
86f00add96SNiklas Söderlund #define VNMC_INF_YUV8_BT601	(1 << 16)
87f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT656	(2 << 16)
88f00add96SNiklas Söderlund #define VNMC_INF_YUV10_BT601	(3 << 16)
89e87c1a81SLad Prabhakar #define VNMC_INF_RAW8		(4 << 16)
90f00add96SNiklas Söderlund #define VNMC_INF_YUV16		(5 << 16)
91f00add96SNiklas Söderlund #define VNMC_INF_RGB888		(6 << 16)
9278b3f9d7SNiklas Söderlund #define VNMC_INF_RGB666		(7 << 16)
93f00add96SNiklas Söderlund #define VNMC_VUP		(1 << 10)
94f00add96SNiklas Söderlund #define VNMC_IM_ODD		(0 << 3)
95f00add96SNiklas Söderlund #define VNMC_IM_ODD_EVEN	(1 << 3)
96f00add96SNiklas Söderlund #define VNMC_IM_EVEN		(2 << 3)
97f00add96SNiklas Söderlund #define VNMC_IM_FULL		(3 << 3)
98f00add96SNiklas Söderlund #define VNMC_BPS		(1 << 1)
99f00add96SNiklas Söderlund #define VNMC_ME			(1 << 0)
100f00add96SNiklas Söderlund 
101f00add96SNiklas Söderlund /* Video n Module Status Register bits */
102f00add96SNiklas Söderlund #define VNMS_FBS_MASK		(3 << 3)
103f00add96SNiklas Söderlund #define VNMS_FBS_SHIFT		3
104b6f556cbSNiklas Söderlund #define VNMS_FS			(1 << 2)
105f00add96SNiklas Söderlund #define VNMS_AV			(1 << 1)
106f00add96SNiklas Söderlund #define VNMS_CA			(1 << 0)
107f00add96SNiklas Söderlund 
108f00add96SNiklas Söderlund /* Video n Frame Capture Register bits */
109f00add96SNiklas Söderlund #define VNFC_C_FRAME		(1 << 1)
110f00add96SNiklas Söderlund #define VNFC_S_FRAME		(1 << 0)
111f00add96SNiklas Söderlund 
112f00add96SNiklas Söderlund /* Video n Interrupt Enable Register bits */
113f00add96SNiklas Söderlund #define VNIE_FIE		(1 << 4)
114f00add96SNiklas Söderlund #define VNIE_EFE		(1 << 1)
115f00add96SNiklas Söderlund 
11630334d3dSNiklas Söderlund /* Video n Interrupt Status Register bits */
11730334d3dSNiklas Söderlund #define VNINTS_FIS		(1 << 4)
11830334d3dSNiklas Söderlund 
119f00add96SNiklas Söderlund /* Video n Data Mode Register bits */
1201d99e68cSNiklas Söderlund #define VNDMR_A8BIT(n)		(((n) & 0xff) << 24)
1211d99e68cSNiklas Söderlund #define VNDMR_A8BIT_MASK	(0xff << 24)
122c93beb52SVladimir Barinov #define VNDMR_YMODE_Y8		(1 << 12)
123f00add96SNiklas Söderlund #define VNDMR_EXRGB		(1 << 8)
124f00add96SNiklas Söderlund #define VNDMR_BPSM		(1 << 4)
1251d99e68cSNiklas Söderlund #define VNDMR_ABIT		(1 << 2)
126f00add96SNiklas Söderlund #define VNDMR_DTMD_YCSEP	(1 << 1)
12719ab1f64SNiklas Söderlund #define VNDMR_DTMD_ARGB		(1 << 0)
1289b744a3eSNiklas Söderlund #define VNDMR_DTMD_YCSEP_420	(3 << 0)
129f00add96SNiklas Söderlund 
130f00add96SNiklas Söderlund /* Video n Data Mode Register 2 bits */
131f00add96SNiklas Söderlund #define VNDMR2_VPS		(1 << 30)
132f00add96SNiklas Söderlund #define VNDMR2_HPS		(1 << 29)
13353cf3100SJacopo Mondi #define VNDMR2_CES		(1 << 28)
134e8834943SLad Prabhakar #define VNDMR2_YDS		(1 << 22)
135f00add96SNiklas Söderlund #define VNDMR2_FTEV		(1 << 17)
136f00add96SNiklas Söderlund #define VNDMR2_VLV(n)		((n & 0xf) << 12)
137f00add96SNiklas Söderlund 
1384394eb24SNiklas Söderlund /* Video n CSI2 Interface Mode Register (Gen3) */
1394394eb24SNiklas Söderlund #define VNCSI_IFMD_DES1		(1 << 26)
1404394eb24SNiklas Söderlund #define VNCSI_IFMD_DES0		(1 << 25)
1414394eb24SNiklas Söderlund #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0)
1424394eb24SNiklas Söderlund 
1439e921447SNiklas Söderlund struct rvin_buffer {
1449e921447SNiklas Söderlund 	struct vb2_v4l2_buffer vb;
1459e921447SNiklas Söderlund 	struct list_head list;
1469e921447SNiklas Söderlund };
1479e921447SNiklas Söderlund 
1489e921447SNiklas Söderlund #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
1499e921447SNiklas Söderlund 					       struct rvin_buffer, \
1509e921447SNiklas Söderlund 					       vb)->list)
1519e921447SNiklas Söderlund 
152f00add96SNiklas Söderlund static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
153f00add96SNiklas Söderlund {
154f00add96SNiklas Söderlund 	iowrite32(value, vin->base + offset);
155f00add96SNiklas Söderlund }
156f00add96SNiklas Söderlund 
157f00add96SNiklas Söderlund static u32 rvin_read(struct rvin_dev *vin, u32 offset)
158f00add96SNiklas Söderlund {
159f00add96SNiklas Söderlund 	return ioread32(vin->base + offset);
160f00add96SNiklas Söderlund }
161f00add96SNiklas Söderlund 
162f00add96SNiklas Söderlund /* -----------------------------------------------------------------------------
163*3ad69c61SNiklas Söderlund  * Crop and Scaling
164f00add96SNiklas Söderlund  */
165f00add96SNiklas Söderlund 
166*3ad69c61SNiklas Söderlund static bool rvin_scaler_needed(const struct rvin_dev *vin)
167*3ad69c61SNiklas Söderlund {
168*3ad69c61SNiklas Söderlund 	return !(vin->crop.width == vin->format.width &&
169*3ad69c61SNiklas Söderlund 		 vin->compose.width == vin->format.width &&
170*3ad69c61SNiklas Söderlund 		 vin->crop.height == vin->format.height &&
171*3ad69c61SNiklas Söderlund 		 vin->compose.height == vin->format.height);
172*3ad69c61SNiklas Söderlund }
173*3ad69c61SNiklas Söderlund 
174f00add96SNiklas Söderlund struct vin_coeff {
175f00add96SNiklas Söderlund 	unsigned short xs_value;
176f00add96SNiklas Söderlund 	u32 coeff_set[24];
177f00add96SNiklas Söderlund };
178f00add96SNiklas Söderlund 
179f00add96SNiklas Söderlund static const struct vin_coeff vin_coeff_set[] = {
180f00add96SNiklas Söderlund 	{ 0x0000, {
181f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
182f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
183f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
184f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
185f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
186f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
187f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000,
188f00add96SNiklas Söderlund 			  0x00000000, 0x00000000, 0x00000000 },
189f00add96SNiklas Söderlund 	},
190f00add96SNiklas Söderlund 	{ 0x1000, {
191f00add96SNiklas Söderlund 			  0x000fa400, 0x000fa400, 0x09625902,
192f00add96SNiklas Söderlund 			  0x000003f8, 0x00000403, 0x3de0d9f0,
193f00add96SNiklas Söderlund 			  0x001fffed, 0x00000804, 0x3cc1f9c3,
194f00add96SNiklas Söderlund 			  0x001003de, 0x00000c01, 0x3cb34d7f,
195f00add96SNiklas Söderlund 			  0x002003d2, 0x00000c00, 0x3d24a92d,
196f00add96SNiklas Söderlund 			  0x00200bca, 0x00000bff, 0x3df600d2,
197f00add96SNiklas Söderlund 			  0x002013cc, 0x000007ff, 0x3ed70c7e,
198f00add96SNiklas Söderlund 			  0x00100fde, 0x00000000, 0x3f87c036 },
199f00add96SNiklas Söderlund 	},
200f00add96SNiklas Söderlund 	{ 0x1200, {
201f00add96SNiklas Söderlund 			  0x002ffff1, 0x002ffff1, 0x02a0a9c8,
202f00add96SNiklas Söderlund 			  0x002003e7, 0x001ffffa, 0x000185bc,
203f00add96SNiklas Söderlund 			  0x002007dc, 0x000003ff, 0x3e52859c,
204f00add96SNiklas Söderlund 			  0x00200bd4, 0x00000002, 0x3d53996b,
205f00add96SNiklas Söderlund 			  0x00100fd0, 0x00000403, 0x3d04ad2d,
206f00add96SNiklas Söderlund 			  0x00000bd5, 0x00000403, 0x3d35ace7,
207f00add96SNiklas Söderlund 			  0x3ff003e4, 0x00000801, 0x3dc674a1,
208f00add96SNiklas Söderlund 			  0x3fffe800, 0x00000800, 0x3e76f461 },
209f00add96SNiklas Söderlund 	},
210f00add96SNiklas Söderlund 	{ 0x1400, {
211f00add96SNiklas Söderlund 			  0x00100be3, 0x00100be3, 0x04d1359a,
212f00add96SNiklas Söderlund 			  0x00000fdb, 0x002003ed, 0x0211fd93,
213f00add96SNiklas Söderlund 			  0x00000fd6, 0x002003f4, 0x0002d97b,
214f00add96SNiklas Söderlund 			  0x000007d6, 0x002ffffb, 0x3e93b956,
215f00add96SNiklas Söderlund 			  0x3ff003da, 0x001003ff, 0x3db49926,
216f00add96SNiklas Söderlund 			  0x3fffefe9, 0x00100001, 0x3d655cee,
217f00add96SNiklas Söderlund 			  0x3fffd400, 0x00000003, 0x3d65f4b6,
218f00add96SNiklas Söderlund 			  0x000fb421, 0x00000402, 0x3dc6547e },
219f00add96SNiklas Söderlund 	},
220f00add96SNiklas Söderlund 	{ 0x1600, {
221f00add96SNiklas Söderlund 			  0x00000bdd, 0x00000bdd, 0x06519578,
222f00add96SNiklas Söderlund 			  0x3ff007da, 0x00000be3, 0x03c24973,
223f00add96SNiklas Söderlund 			  0x3ff003d9, 0x00000be9, 0x01b30d5f,
224f00add96SNiklas Söderlund 			  0x3ffff7df, 0x001003f1, 0x0003c542,
225f00add96SNiklas Söderlund 			  0x000fdfec, 0x001003f7, 0x3ec4711d,
226f00add96SNiklas Söderlund 			  0x000fc400, 0x002ffffd, 0x3df504f1,
227f00add96SNiklas Söderlund 			  0x001fa81a, 0x002ffc00, 0x3d957cc2,
228f00add96SNiklas Söderlund 			  0x002f8c3c, 0x00100000, 0x3db5c891 },
229f00add96SNiklas Söderlund 	},
230f00add96SNiklas Söderlund 	{ 0x1800, {
231f00add96SNiklas Söderlund 			  0x3ff003dc, 0x3ff003dc, 0x0791e558,
232f00add96SNiklas Söderlund 			  0x000ff7dd, 0x3ff007de, 0x05328554,
233f00add96SNiklas Söderlund 			  0x000fe7e3, 0x3ff00be2, 0x03232546,
234f00add96SNiklas Söderlund 			  0x000fd7ee, 0x000007e9, 0x0143bd30,
235f00add96SNiklas Söderlund 			  0x001fb800, 0x000007ee, 0x00044511,
236f00add96SNiklas Söderlund 			  0x002fa015, 0x000007f4, 0x3ef4bcee,
237f00add96SNiklas Söderlund 			  0x002f8832, 0x001003f9, 0x3e4514c7,
238f00add96SNiklas Söderlund 			  0x001f7853, 0x001003fd, 0x3de54c9f },
239f00add96SNiklas Söderlund 	},
240f00add96SNiklas Söderlund 	{ 0x1a00, {
241f00add96SNiklas Söderlund 			  0x000fefe0, 0x000fefe0, 0x08721d3c,
242f00add96SNiklas Söderlund 			  0x001fdbe7, 0x000ffbde, 0x0652a139,
243f00add96SNiklas Söderlund 			  0x001fcbf0, 0x000003df, 0x0463292e,
244f00add96SNiklas Söderlund 			  0x002fb3ff, 0x3ff007e3, 0x0293a91d,
245f00add96SNiklas Söderlund 			  0x002f9c12, 0x3ff00be7, 0x01241905,
246f00add96SNiklas Söderlund 			  0x001f8c29, 0x000007ed, 0x3fe470eb,
247f00add96SNiklas Söderlund 			  0x000f7c46, 0x000007f2, 0x3f04b8ca,
248f00add96SNiklas Söderlund 			  0x3fef7865, 0x000007f6, 0x3e74e4a8 },
249f00add96SNiklas Söderlund 	},
250f00add96SNiklas Söderlund 	{ 0x1c00, {
251f00add96SNiklas Söderlund 			  0x001fd3e9, 0x001fd3e9, 0x08f23d26,
252f00add96SNiklas Söderlund 			  0x002fbff3, 0x001fe3e4, 0x0712ad23,
253f00add96SNiklas Söderlund 			  0x002fa800, 0x000ff3e0, 0x05631d1b,
254f00add96SNiklas Söderlund 			  0x001f9810, 0x000ffbe1, 0x03b3890d,
255f00add96SNiklas Söderlund 			  0x000f8c23, 0x000003e3, 0x0233e8fa,
256f00add96SNiklas Söderlund 			  0x3fef843b, 0x000003e7, 0x00f430e4,
257f00add96SNiklas Söderlund 			  0x3fbf8456, 0x3ff00bea, 0x00046cc8,
258f00add96SNiklas Söderlund 			  0x3f8f8c72, 0x3ff00bef, 0x3f3490ac },
259f00add96SNiklas Söderlund 	},
260f00add96SNiklas Söderlund 	{ 0x1e00, {
261f00add96SNiklas Söderlund 			  0x001fbbf4, 0x001fbbf4, 0x09425112,
262f00add96SNiklas Söderlund 			  0x001fa800, 0x002fc7ed, 0x0792b110,
263f00add96SNiklas Söderlund 			  0x000f980e, 0x001fdbe6, 0x0613110a,
264f00add96SNiklas Söderlund 			  0x3fff8c20, 0x001fe7e3, 0x04a368fd,
265f00add96SNiklas Söderlund 			  0x3fcf8c33, 0x000ff7e2, 0x0343b8ed,
266f00add96SNiklas Söderlund 			  0x3f9f8c4a, 0x000fffe3, 0x0203f8da,
267f00add96SNiklas Söderlund 			  0x3f5f9c61, 0x000003e6, 0x00e428c5,
268f00add96SNiklas Söderlund 			  0x3f1fb07b, 0x000003eb, 0x3fe440af },
269f00add96SNiklas Söderlund 	},
270f00add96SNiklas Söderlund 	{ 0x2000, {
271f00add96SNiklas Söderlund 			  0x000fa400, 0x000fa400, 0x09625902,
272f00add96SNiklas Söderlund 			  0x3fff980c, 0x001fb7f5, 0x0812b0ff,
273f00add96SNiklas Söderlund 			  0x3fdf901c, 0x001fc7ed, 0x06b2fcfa,
274f00add96SNiklas Söderlund 			  0x3faf902d, 0x001fd3e8, 0x055348f1,
275f00add96SNiklas Söderlund 			  0x3f7f983f, 0x001fe3e5, 0x04038ce3,
276f00add96SNiklas Söderlund 			  0x3f3fa454, 0x001fefe3, 0x02e3c8d1,
277f00add96SNiklas Söderlund 			  0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0,
278f00add96SNiklas Söderlund 			  0x3ecfd880, 0x000fffe6, 0x00c404ac },
279f00add96SNiklas Söderlund 	},
280f00add96SNiklas Söderlund 	{ 0x2200, {
281f00add96SNiklas Söderlund 			  0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4,
282f00add96SNiklas Söderlund 			  0x3fbf9818, 0x3fffa400, 0x0842a8f1,
283f00add96SNiklas Söderlund 			  0x3f8f9827, 0x000fb3f7, 0x0702f0ec,
284f00add96SNiklas Söderlund 			  0x3f5fa037, 0x000fc3ef, 0x05d330e4,
285f00add96SNiklas Söderlund 			  0x3f2fac49, 0x001fcfea, 0x04a364d9,
286f00add96SNiklas Söderlund 			  0x3effc05c, 0x001fdbe7, 0x038394ca,
287f00add96SNiklas Söderlund 			  0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb,
288f00add96SNiklas Söderlund 			  0x3ea00083, 0x001fefe6, 0x0183c0a9 },
289f00add96SNiklas Söderlund 	},
290f00add96SNiklas Söderlund 	{ 0x2400, {
291f00add96SNiklas Söderlund 			  0x3f9fa014, 0x3f9fa014, 0x098260e6,
292f00add96SNiklas Söderlund 			  0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5,
293f00add96SNiklas Söderlund 			  0x3f4fa431, 0x3fefa400, 0x0742d8e1,
294f00add96SNiklas Söderlund 			  0x3f1fb440, 0x3fffb3f8, 0x062310d9,
295f00add96SNiklas Söderlund 			  0x3eefc850, 0x000fbbf2, 0x050340d0,
296f00add96SNiklas Söderlund 			  0x3ecfe062, 0x000fcbec, 0x041364c2,
297f00add96SNiklas Söderlund 			  0x3ea00073, 0x001fd3ea, 0x03037cb5,
298f00add96SNiklas Söderlund 			  0x3e902086, 0x001fdfe8, 0x022388a5 },
299f00add96SNiklas Söderlund 	},
300f00add96SNiklas Söderlund 	{ 0x2600, {
301f00add96SNiklas Söderlund 			  0x3f5fa81e, 0x3f5fa81e, 0x096258da,
302f00add96SNiklas Söderlund 			  0x3f3fac2b, 0x3f8fa412, 0x088290d8,
303f00add96SNiklas Söderlund 			  0x3f0fbc38, 0x3fafa408, 0x0772c8d5,
304f00add96SNiklas Söderlund 			  0x3eefcc47, 0x3fcfa800, 0x0672f4ce,
305f00add96SNiklas Söderlund 			  0x3ecfe456, 0x3fefaffa, 0x05531cc6,
306f00add96SNiklas Söderlund 			  0x3eb00066, 0x3fffbbf3, 0x047334bb,
307f00add96SNiklas Söderlund 			  0x3ea01c77, 0x000fc7ee, 0x039348ae,
308f00add96SNiklas Söderlund 			  0x3ea04486, 0x000fd3eb, 0x02b350a1 },
309f00add96SNiklas Söderlund 	},
310f00add96SNiklas Söderlund 	{ 0x2800, {
311f00add96SNiklas Söderlund 			  0x3f2fb426, 0x3f2fb426, 0x094250ce,
312f00add96SNiklas Söderlund 			  0x3f0fc032, 0x3f4fac1b, 0x086284cd,
313f00add96SNiklas Söderlund 			  0x3eefd040, 0x3f7fa811, 0x0782acc9,
314f00add96SNiklas Söderlund 			  0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4,
315f00add96SNiklas Söderlund 			  0x3eb0005b, 0x3fbfac00, 0x05b2f4bc,
316f00add96SNiklas Söderlund 			  0x3eb0186a, 0x3fdfb3fa, 0x04c308b4,
317f00add96SNiklas Söderlund 			  0x3eb04077, 0x3fefbbf4, 0x03f31ca8,
318f00add96SNiklas Söderlund 			  0x3ec06884, 0x000fbff2, 0x03031c9e },
319f00add96SNiklas Söderlund 	},
320f00add96SNiklas Söderlund 	{ 0x2a00, {
321f00add96SNiklas Söderlund 			  0x3f0fc42d, 0x3f0fc42d, 0x090240c4,
322f00add96SNiklas Söderlund 			  0x3eefd439, 0x3f2fb822, 0x08526cc2,
323f00add96SNiklas Söderlund 			  0x3edfe845, 0x3f4fb018, 0x078294bf,
324f00add96SNiklas Söderlund 			  0x3ec00051, 0x3f6fac0f, 0x06b2b4bb,
325f00add96SNiklas Söderlund 			  0x3ec0185f, 0x3f8fac07, 0x05e2ccb4,
326f00add96SNiklas Söderlund 			  0x3ec0386b, 0x3fafac00, 0x0502e8ac,
327f00add96SNiklas Söderlund 			  0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3,
328f00add96SNiklas Söderlund 			  0x3ef08482, 0x3fdfbbf6, 0x0372f898 },
329f00add96SNiklas Söderlund 	},
330f00add96SNiklas Söderlund 	{ 0x2c00, {
331f00add96SNiklas Söderlund 			  0x3eefdc31, 0x3eefdc31, 0x08e238b8,
332f00add96SNiklas Söderlund 			  0x3edfec3d, 0x3f0fc828, 0x082258b9,
333f00add96SNiklas Söderlund 			  0x3ed00049, 0x3f1fc01e, 0x077278b6,
334f00add96SNiklas Söderlund 			  0x3ed01455, 0x3f3fb815, 0x06c294b2,
335f00add96SNiklas Söderlund 			  0x3ed03460, 0x3f5fb40d, 0x0602acac,
336f00add96SNiklas Söderlund 			  0x3ef0506c, 0x3f7fb006, 0x0542c0a4,
337f00add96SNiklas Söderlund 			  0x3f107476, 0x3f9fb400, 0x0472c89d,
338f00add96SNiklas Söderlund 			  0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 },
339f00add96SNiklas Söderlund 	},
340f00add96SNiklas Söderlund 	{ 0x2e00, {
341f00add96SNiklas Söderlund 			  0x3eefec37, 0x3eefec37, 0x088220b0,
342f00add96SNiklas Söderlund 			  0x3ee00041, 0x3effdc2d, 0x07f244ae,
343f00add96SNiklas Söderlund 			  0x3ee0144c, 0x3f0fd023, 0x07625cad,
344f00add96SNiklas Söderlund 			  0x3ef02c57, 0x3f1fc81a, 0x06c274a9,
345f00add96SNiklas Söderlund 			  0x3f004861, 0x3f3fbc13, 0x060288a6,
346f00add96SNiklas Söderlund 			  0x3f20686b, 0x3f5fb80c, 0x05529c9e,
347f00add96SNiklas Söderlund 			  0x3f408c74, 0x3f6fb805, 0x04b2ac96,
348f00add96SNiklas Söderlund 			  0x3f80ac7e, 0x3f8fb800, 0x0402ac8e },
349f00add96SNiklas Söderlund 	},
350f00add96SNiklas Söderlund 	{ 0x3000, {
351f00add96SNiklas Söderlund 			  0x3ef0003a, 0x3ef0003a, 0x084210a6,
352f00add96SNiklas Söderlund 			  0x3ef01045, 0x3effec32, 0x07b228a7,
353f00add96SNiklas Söderlund 			  0x3f00284e, 0x3f0fdc29, 0x073244a4,
354f00add96SNiklas Söderlund 			  0x3f104058, 0x3f0fd420, 0x06a258a2,
355f00add96SNiklas Söderlund 			  0x3f305c62, 0x3f2fc818, 0x0612689d,
356f00add96SNiklas Söderlund 			  0x3f508069, 0x3f3fc011, 0x05728496,
357f00add96SNiklas Söderlund 			  0x3f80a072, 0x3f4fc00a, 0x04d28c90,
358f00add96SNiklas Söderlund 			  0x3fc0c07b, 0x3f6fbc04, 0x04429088 },
359f00add96SNiklas Söderlund 	},
360f00add96SNiklas Söderlund 	{ 0x3200, {
361f00add96SNiklas Söderlund 			  0x3f00103e, 0x3f00103e, 0x07f1fc9e,
362f00add96SNiklas Söderlund 			  0x3f102447, 0x3f000035, 0x0782149d,
363f00add96SNiklas Söderlund 			  0x3f203c4f, 0x3f0ff02c, 0x07122c9c,
364f00add96SNiklas Söderlund 			  0x3f405458, 0x3f0fe424, 0x06924099,
365f00add96SNiklas Söderlund 			  0x3f607061, 0x3f1fd41d, 0x06024c97,
366f00add96SNiklas Söderlund 			  0x3f909068, 0x3f2fcc16, 0x05726490,
367f00add96SNiklas Söderlund 			  0x3fc0b070, 0x3f3fc80f, 0x04f26c8a,
368f00add96SNiklas Söderlund 			  0x0000d077, 0x3f4fc409, 0x04627484 },
369f00add96SNiklas Söderlund 	},
370f00add96SNiklas Söderlund 	{ 0x3400, {
371f00add96SNiklas Söderlund 			  0x3f202040, 0x3f202040, 0x07a1e898,
372f00add96SNiklas Söderlund 			  0x3f303449, 0x3f100c38, 0x0741fc98,
373f00add96SNiklas Söderlund 			  0x3f504c50, 0x3f10002f, 0x06e21495,
374f00add96SNiklas Söderlund 			  0x3f706459, 0x3f1ff028, 0x06722492,
375f00add96SNiklas Söderlund 			  0x3fa08060, 0x3f1fe421, 0x05f2348f,
376f00add96SNiklas Söderlund 			  0x3fd09c67, 0x3f1fdc19, 0x05824c89,
377f00add96SNiklas Söderlund 			  0x0000bc6e, 0x3f2fd014, 0x04f25086,
378f00add96SNiklas Söderlund 			  0x0040dc74, 0x3f3fcc0d, 0x04825c7f },
379f00add96SNiklas Söderlund 	},
380f00add96SNiklas Söderlund 	{ 0x3600, {
381f00add96SNiklas Söderlund 			  0x3f403042, 0x3f403042, 0x0761d890,
382f00add96SNiklas Söderlund 			  0x3f504848, 0x3f301c3b, 0x0701f090,
383f00add96SNiklas Söderlund 			  0x3f805c50, 0x3f200c33, 0x06a2008f,
384f00add96SNiklas Söderlund 			  0x3fa07458, 0x3f10002b, 0x06520c8d,
385f00add96SNiklas Söderlund 			  0x3fd0905e, 0x3f1ff424, 0x05e22089,
386f00add96SNiklas Söderlund 			  0x0000ac65, 0x3f1fe81d, 0x05823483,
387f00add96SNiklas Söderlund 			  0x0030cc6a, 0x3f2fdc18, 0x04f23c81,
388f00add96SNiklas Söderlund 			  0x0080e871, 0x3f2fd412, 0x0482407c },
389f00add96SNiklas Söderlund 	},
390f00add96SNiklas Söderlund 	{ 0x3800, {
391f00add96SNiklas Söderlund 			  0x3f604043, 0x3f604043, 0x0721c88a,
392f00add96SNiklas Söderlund 			  0x3f80544a, 0x3f502c3c, 0x06d1d88a,
393f00add96SNiklas Söderlund 			  0x3fb06851, 0x3f301c35, 0x0681e889,
394f00add96SNiklas Söderlund 			  0x3fd08456, 0x3f30082f, 0x0611fc88,
395f00add96SNiklas Söderlund 			  0x00009c5d, 0x3f200027, 0x05d20884,
396f00add96SNiklas Söderlund 			  0x0030b863, 0x3f2ff421, 0x05621880,
397f00add96SNiklas Söderlund 			  0x0070d468, 0x3f2fe81b, 0x0502247c,
398f00add96SNiklas Söderlund 			  0x00c0ec6f, 0x3f2fe015, 0x04a22877 },
399f00add96SNiklas Söderlund 	},
400f00add96SNiklas Söderlund 	{ 0x3a00, {
401f00add96SNiklas Söderlund 			  0x3f904c44, 0x3f904c44, 0x06e1b884,
402f00add96SNiklas Söderlund 			  0x3fb0604a, 0x3f70383e, 0x0691c885,
403f00add96SNiklas Söderlund 			  0x3fe07451, 0x3f502c36, 0x0661d483,
404f00add96SNiklas Söderlund 			  0x00009055, 0x3f401831, 0x0601ec81,
405f00add96SNiklas Söderlund 			  0x0030a85b, 0x3f300c2a, 0x05b1f480,
406f00add96SNiklas Söderlund 			  0x0070c061, 0x3f300024, 0x0562047a,
407f00add96SNiklas Söderlund 			  0x00b0d867, 0x3f3ff41e, 0x05020c77,
408f00add96SNiklas Söderlund 			  0x00f0f46b, 0x3f2fec19, 0x04a21474 },
409f00add96SNiklas Söderlund 	},
410f00add96SNiklas Söderlund 	{ 0x3c00, {
411f00add96SNiklas Söderlund 			  0x3fb05c43, 0x3fb05c43, 0x06c1b07e,
412f00add96SNiklas Söderlund 			  0x3fe06c4b, 0x3f902c3f, 0x0681c081,
413f00add96SNiklas Söderlund 			  0x0000844f, 0x3f703838, 0x0631cc7d,
414f00add96SNiklas Söderlund 			  0x00309855, 0x3f602433, 0x05d1d47e,
415f00add96SNiklas Söderlund 			  0x0060b459, 0x3f50142e, 0x0581e47b,
416f00add96SNiklas Söderlund 			  0x00a0c85f, 0x3f400828, 0x0531f078,
417f00add96SNiklas Söderlund 			  0x00e0e064, 0x3f300021, 0x0501fc73,
418f00add96SNiklas Söderlund 			  0x00b0fc6a, 0x3f3ff41d, 0x04a20873 },
419f00add96SNiklas Söderlund 	},
420f00add96SNiklas Söderlund 	{ 0x3e00, {
421f00add96SNiklas Söderlund 			  0x3fe06444, 0x3fe06444, 0x0681a07a,
422f00add96SNiklas Söderlund 			  0x00007849, 0x3fc0503f, 0x0641b07a,
423f00add96SNiklas Söderlund 			  0x0020904d, 0x3fa0403a, 0x05f1c07a,
424f00add96SNiklas Söderlund 			  0x0060a453, 0x3f803034, 0x05c1c878,
425f00add96SNiklas Söderlund 			  0x0090b858, 0x3f70202f, 0x0571d477,
426f00add96SNiklas Söderlund 			  0x00d0d05d, 0x3f501829, 0x0531e073,
427f00add96SNiklas Söderlund 			  0x0110e462, 0x3f500825, 0x04e1e471,
428f00add96SNiklas Söderlund 			  0x01510065, 0x3f40001f, 0x04a1f06d },
429f00add96SNiklas Söderlund 	},
430f00add96SNiklas Söderlund 	{ 0x4000, {
431f00add96SNiklas Söderlund 			  0x00007044, 0x00007044, 0x06519476,
432f00add96SNiklas Söderlund 			  0x00208448, 0x3fe05c3f, 0x0621a476,
433f00add96SNiklas Söderlund 			  0x0050984d, 0x3fc04c3a, 0x05e1b075,
434f00add96SNiklas Söderlund 			  0x0080ac52, 0x3fa03c35, 0x05a1b875,
435f00add96SNiklas Söderlund 			  0x00c0c056, 0x3f803030, 0x0561c473,
436f00add96SNiklas Söderlund 			  0x0100d45b, 0x3f70202b, 0x0521d46f,
437f00add96SNiklas Söderlund 			  0x0140e860, 0x3f601427, 0x04d1d46e,
438f00add96SNiklas Söderlund 			  0x01810064, 0x3f500822, 0x0491dc6b },
439f00add96SNiklas Söderlund 	},
440f00add96SNiklas Söderlund 	{ 0x5000, {
441f00add96SNiklas Söderlund 			  0x0110a442, 0x0110a442, 0x0551545e,
442f00add96SNiklas Söderlund 			  0x0140b045, 0x00e0983f, 0x0531585f,
443f00add96SNiklas Söderlund 			  0x0160c047, 0x00c08c3c, 0x0511645e,
444f00add96SNiklas Söderlund 			  0x0190cc4a, 0x00908039, 0x04f1685f,
445f00add96SNiklas Söderlund 			  0x01c0dc4c, 0x00707436, 0x04d1705e,
446f00add96SNiklas Söderlund 			  0x0200e850, 0x00506833, 0x04b1785b,
447f00add96SNiklas Söderlund 			  0x0230f453, 0x00305c30, 0x0491805a,
448f00add96SNiklas Söderlund 			  0x02710056, 0x0010542d, 0x04718059 },
449f00add96SNiklas Söderlund 	},
450f00add96SNiklas Söderlund 	{ 0x6000, {
451f00add96SNiklas Söderlund 			  0x01c0bc40, 0x01c0bc40, 0x04c13052,
452f00add96SNiklas Söderlund 			  0x01e0c841, 0x01a0b43d, 0x04c13851,
453f00add96SNiklas Söderlund 			  0x0210cc44, 0x0180a83c, 0x04a13453,
454f00add96SNiklas Söderlund 			  0x0230d845, 0x0160a03a, 0x04913c52,
455f00add96SNiklas Söderlund 			  0x0260e047, 0x01409838, 0x04714052,
456f00add96SNiklas Söderlund 			  0x0280ec49, 0x01208c37, 0x04514c50,
457f00add96SNiklas Söderlund 			  0x02b0f44b, 0x01008435, 0x04414c50,
458f00add96SNiklas Söderlund 			  0x02d1004c, 0x00e07c33, 0x0431544f },
459f00add96SNiklas Söderlund 	},
460f00add96SNiklas Söderlund 	{ 0x7000, {
461f00add96SNiklas Söderlund 			  0x0230c83e, 0x0230c83e, 0x04711c4c,
462f00add96SNiklas Söderlund 			  0x0250d03f, 0x0210c43c, 0x0471204b,
463f00add96SNiklas Söderlund 			  0x0270d840, 0x0200b83c, 0x0451244b,
464f00add96SNiklas Söderlund 			  0x0290dc42, 0x01e0b43a, 0x0441244c,
465f00add96SNiklas Söderlund 			  0x02b0e443, 0x01c0b038, 0x0441284b,
466f00add96SNiklas Söderlund 			  0x02d0ec44, 0x01b0a438, 0x0421304a,
467f00add96SNiklas Söderlund 			  0x02f0f445, 0x0190a036, 0x04213449,
468f00add96SNiklas Söderlund 			  0x0310f847, 0x01709c34, 0x04213848 },
469f00add96SNiklas Söderlund 	},
470f00add96SNiklas Söderlund 	{ 0x8000, {
471f00add96SNiklas Söderlund 			  0x0280d03d, 0x0280d03d, 0x04310c48,
472f00add96SNiklas Söderlund 			  0x02a0d43e, 0x0270c83c, 0x04311047,
473f00add96SNiklas Söderlund 			  0x02b0dc3e, 0x0250c83a, 0x04311447,
474f00add96SNiklas Söderlund 			  0x02d0e040, 0x0240c03a, 0x04211446,
475f00add96SNiklas Söderlund 			  0x02e0e840, 0x0220bc39, 0x04111847,
476f00add96SNiklas Söderlund 			  0x0300e842, 0x0210b438, 0x04012445,
477f00add96SNiklas Söderlund 			  0x0310f043, 0x0200b037, 0x04012045,
478f00add96SNiklas Söderlund 			  0x0330f444, 0x01e0ac36, 0x03f12445 },
479f00add96SNiklas Söderlund 	},
480f00add96SNiklas Söderlund 	{ 0xefff, {
481f00add96SNiklas Söderlund 			  0x0340dc3a, 0x0340dc3a, 0x03b0ec40,
482f00add96SNiklas Söderlund 			  0x0340e03a, 0x0330e039, 0x03c0f03e,
483f00add96SNiklas Söderlund 			  0x0350e03b, 0x0330dc39, 0x03c0ec3e,
484f00add96SNiklas Söderlund 			  0x0350e43a, 0x0320dc38, 0x03c0f43e,
485f00add96SNiklas Söderlund 			  0x0360e43b, 0x0320d839, 0x03b0f03e,
486f00add96SNiklas Söderlund 			  0x0360e83b, 0x0310d838, 0x03c0fc3b,
487f00add96SNiklas Söderlund 			  0x0370e83b, 0x0310d439, 0x03a0f83d,
488f00add96SNiklas Söderlund 			  0x0370e83c, 0x0300d438, 0x03b0fc3c },
489f00add96SNiklas Söderlund 	}
490f00add96SNiklas Söderlund };
491f00add96SNiklas Söderlund 
492f00add96SNiklas Söderlund static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
493f00add96SNiklas Söderlund {
494f00add96SNiklas Söderlund 	int i;
495f00add96SNiklas Söderlund 	const struct vin_coeff *p_prev_set = NULL;
496f00add96SNiklas Söderlund 	const struct vin_coeff *p_set = NULL;
497f00add96SNiklas Söderlund 
498f00add96SNiklas Söderlund 	/* Look for suitable coefficient values */
499f00add96SNiklas Söderlund 	for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
500f00add96SNiklas Söderlund 		p_prev_set = p_set;
501f00add96SNiklas Söderlund 		p_set = &vin_coeff_set[i];
502f00add96SNiklas Söderlund 
503f00add96SNiklas Söderlund 		if (xs < p_set->xs_value)
504f00add96SNiklas Söderlund 			break;
505f00add96SNiklas Söderlund 	}
506f00add96SNiklas Söderlund 
507f00add96SNiklas Söderlund 	/* Use previous value if its XS value is closer */
508bf78f23aSMauro Carvalho Chehab 	if (p_prev_set &&
509f00add96SNiklas Söderlund 	    xs - p_prev_set->xs_value < p_set->xs_value - xs)
510f00add96SNiklas Söderlund 		p_set = p_prev_set;
511f00add96SNiklas Söderlund 
512f00add96SNiklas Söderlund 	/* Set coefficient registers */
513f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[0], VNC1A_REG);
514f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[1], VNC1B_REG);
515f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[2], VNC1C_REG);
516f00add96SNiklas Söderlund 
517f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[3], VNC2A_REG);
518f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[4], VNC2B_REG);
519f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[5], VNC2C_REG);
520f00add96SNiklas Söderlund 
521f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[6], VNC3A_REG);
522f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[7], VNC3B_REG);
523f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[8], VNC3C_REG);
524f00add96SNiklas Söderlund 
525f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[9], VNC4A_REG);
526f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[10], VNC4B_REG);
527f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[11], VNC4C_REG);
528f00add96SNiklas Söderlund 
529f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[12], VNC5A_REG);
530f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[13], VNC5B_REG);
531f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[14], VNC5C_REG);
532f00add96SNiklas Söderlund 
533f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[15], VNC6A_REG);
534f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[16], VNC6B_REG);
535f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[17], VNC6C_REG);
536f00add96SNiklas Söderlund 
537f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[18], VNC7A_REG);
538f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[19], VNC7B_REG);
539f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[20], VNC7C_REG);
540f00add96SNiklas Söderlund 
541f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[21], VNC8A_REG);
542f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[22], VNC8B_REG);
543f00add96SNiklas Söderlund 	rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
544f00add96SNiklas Söderlund }
545f00add96SNiklas Söderlund 
546*3ad69c61SNiklas Söderlund void rvin_scaler_gen2(struct rvin_dev *vin)
547f00add96SNiklas Söderlund {
54808369321SNiklas Söderlund 	unsigned int crop_height;
549f00add96SNiklas Söderlund 	u32 xs, ys;
550f00add96SNiklas Söderlund 
551f00add96SNiklas Söderlund 	/* Set scaling coefficient */
55208369321SNiklas Söderlund 	crop_height = vin->crop.height;
5537e0cfdadSNiklas Söderlund 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
55408369321SNiklas Söderlund 		crop_height *= 2;
55508369321SNiklas Söderlund 
556f00add96SNiklas Söderlund 	ys = 0;
55708369321SNiklas Söderlund 	if (crop_height != vin->compose.height)
55808369321SNiklas Söderlund 		ys = (4096 * crop_height) / vin->compose.height;
559f00add96SNiklas Söderlund 	rvin_write(vin, ys, VNYS_REG);
560f00add96SNiklas Söderlund 
561f00add96SNiklas Söderlund 	xs = 0;
562f00add96SNiklas Söderlund 	if (vin->crop.width != vin->compose.width)
563f00add96SNiklas Söderlund 		xs = (4096 * vin->crop.width) / vin->compose.width;
564f00add96SNiklas Söderlund 
565f00add96SNiklas Söderlund 	/* Horizontal upscaling is up to double size */
566f00add96SNiklas Söderlund 	if (xs > 0 && xs < 2048)
567f00add96SNiklas Söderlund 		xs = 2048;
568f00add96SNiklas Söderlund 
569f00add96SNiklas Söderlund 	rvin_write(vin, xs, VNXS_REG);
570f00add96SNiklas Söderlund 
571f00add96SNiklas Söderlund 	/* Horizontal upscaling is done out by scaling down from double size */
572f00add96SNiklas Söderlund 	if (xs < 4096)
573f00add96SNiklas Söderlund 		xs *= 2;
574f00add96SNiklas Söderlund 
575f00add96SNiklas Söderlund 	rvin_set_coeff(vin, xs);
576f00add96SNiklas Söderlund 
577f00add96SNiklas Söderlund 	/* Set Start/End Pixel/Line Post-Clip */
578f00add96SNiklas Söderlund 	rvin_write(vin, 0, VNSPPOC_REG);
579f00add96SNiklas Söderlund 	rvin_write(vin, 0, VNSLPOC_REG);
580f00add96SNiklas Söderlund 	rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
581d23e12dcSNiklas Söderlund 
5827e0cfdadSNiklas Söderlund 	if (V4L2_FIELD_HAS_BOTH(vin->format.field))
583f00add96SNiklas Söderlund 		rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
584d23e12dcSNiklas Söderlund 	else
585f00add96SNiklas Söderlund 		rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
586f00add96SNiklas Söderlund 
587f00add96SNiklas Söderlund 	vin_dbg(vin,
588f00add96SNiklas Söderlund 		"Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
589f00add96SNiklas Söderlund 		vin->crop.width, vin->crop.height, vin->crop.left,
590f00add96SNiklas Söderlund 		vin->crop.top, ys, xs, vin->format.width, vin->format.height,
591f00add96SNiklas Söderlund 		0, 0);
592f00add96SNiklas Söderlund }
593f00add96SNiklas Söderlund 
5944394eb24SNiklas Söderlund void rvin_crop_scale_comp(struct rvin_dev *vin)
5954394eb24SNiklas Söderlund {
59684246ae3SNiklas Söderlund 	const struct rvin_video_format *fmt;
59784246ae3SNiklas Söderlund 	u32 stride;
59884246ae3SNiklas Söderlund 
5994394eb24SNiklas Söderlund 	/* Set Start/End Pixel/Line Pre-Clip */
6004394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.left, VNSPPRC_REG);
6014394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
6024394eb24SNiklas Söderlund 	rvin_write(vin, vin->crop.top, VNSLPRC_REG);
60308369321SNiklas Söderlund 	rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG);
60408369321SNiklas Söderlund 
605*3ad69c61SNiklas Söderlund 	if (vin->scaler)
606*3ad69c61SNiklas Söderlund 		vin->scaler(vin);
6074394eb24SNiklas Söderlund 
60884246ae3SNiklas Söderlund 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
60984246ae3SNiklas Söderlund 	stride = vin->format.bytesperline / fmt->bpp;
610e87c1a81SLad Prabhakar 
611e87c1a81SLad Prabhakar 	/* For RAW8 format bpp is 1, but the hardware process RAW8
612e87c1a81SLad Prabhakar 	 * format in 2 pixel unit hence configure VNIS_REG as stride / 2.
613e87c1a81SLad Prabhakar 	 */
6148c3e0f67SNiklas Söderlund 	switch (vin->format.pixelformat) {
615811b8d66SLad Prabhakar 	case V4L2_PIX_FMT_SBGGR8:
616811b8d66SLad Prabhakar 	case V4L2_PIX_FMT_SGBRG8:
617811b8d66SLad Prabhakar 	case V4L2_PIX_FMT_SGRBG8:
618811b8d66SLad Prabhakar 	case V4L2_PIX_FMT_SRGGB8:
619c93beb52SVladimir Barinov 	case V4L2_PIX_FMT_GREY:
620e87c1a81SLad Prabhakar 		stride /= 2;
6218c3e0f67SNiklas Söderlund 		break;
6228c3e0f67SNiklas Söderlund 	default:
6238c3e0f67SNiklas Söderlund 		break;
6248c3e0f67SNiklas Söderlund 	}
625e87c1a81SLad Prabhakar 
62684246ae3SNiklas Söderlund 	rvin_write(vin, stride, VNIS_REG);
6274394eb24SNiklas Söderlund }
6284394eb24SNiklas Söderlund 
629f00add96SNiklas Söderlund /* -----------------------------------------------------------------------------
6300f4b3378SNiklas Söderlund  * Hardware setup
6310f4b3378SNiklas Söderlund  */
6320f4b3378SNiklas Söderlund 
6330f4b3378SNiklas Söderlund static int rvin_setup(struct rvin_dev *vin)
6340f4b3378SNiklas Söderlund {
635d73c3357SNiklas Söderlund 	u32 vnmc, dmr, dmr2, interrupts;
6360f4b3378SNiklas Söderlund 	bool progressive = false, output_is_yuv = false, input_is_yuv = false;
6370f4b3378SNiklas Söderlund 
6380f4b3378SNiklas Söderlund 	switch (vin->format.field) {
6390f4b3378SNiklas Söderlund 	case V4L2_FIELD_TOP:
6400f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_ODD;
6410f4b3378SNiklas Söderlund 		break;
6420f4b3378SNiklas Söderlund 	case V4L2_FIELD_BOTTOM:
6430f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_EVEN;
6440f4b3378SNiklas Söderlund 		break;
6450f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED:
6460f4b3378SNiklas Söderlund 		/* Default to TB */
6470f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL;
6480f4b3378SNiklas Söderlund 		/* Use BT if video standard can be read and is 60 Hz format */
6495e7c6236SNiklas Söderlund 		if (!vin->info->use_mc && vin->std & V4L2_STD_525_60)
6500f4b3378SNiklas Söderlund 			vnmc = VNMC_IM_FULL | VNMC_FOC;
6510f4b3378SNiklas Söderlund 		break;
6520f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_TB:
6530f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL;
6540f4b3378SNiklas Söderlund 		break;
6550f4b3378SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_BT:
6560f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_FULL | VNMC_FOC;
6570f4b3378SNiklas Söderlund 		break;
6587e0cfdadSNiklas Söderlund 	case V4L2_FIELD_SEQ_TB:
6597e0cfdadSNiklas Söderlund 	case V4L2_FIELD_SEQ_BT:
6600f4b3378SNiklas Söderlund 	case V4L2_FIELD_NONE:
6610f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_ODD_EVEN;
6620f4b3378SNiklas Söderlund 		progressive = true;
6630f4b3378SNiklas Söderlund 		break;
66408369321SNiklas Söderlund 	case V4L2_FIELD_ALTERNATE:
66508369321SNiklas Söderlund 		vnmc = VNMC_IM_ODD_EVEN;
66608369321SNiklas Söderlund 		break;
6670f4b3378SNiklas Söderlund 	default:
6680f4b3378SNiklas Söderlund 		vnmc = VNMC_IM_ODD;
6690f4b3378SNiklas Söderlund 		break;
6700f4b3378SNiklas Söderlund 	}
6710f4b3378SNiklas Söderlund 
6720f4b3378SNiklas Söderlund 	/*
6730f4b3378SNiklas Söderlund 	 * Input interface
6740f4b3378SNiklas Söderlund 	 */
675c65c99b4SNiklas Söderlund 	switch (vin->mbus_code) {
6760f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_YUYV8_1X16:
6770f4b3378SNiklas Söderlund 		/* BT.601/BT.1358 16bit YCbCr422 */
6780f4b3378SNiklas Söderlund 		vnmc |= VNMC_INF_YUV16;
6790f4b3378SNiklas Söderlund 		input_is_yuv = true;
6800f4b3378SNiklas Söderlund 		break;
68101d72e9dSNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_1X16:
68201d72e9dSNiklas Söderlund 		vnmc |= VNMC_INF_YUV16 | VNMC_YCAL;
68301d72e9dSNiklas Söderlund 		input_is_yuv = true;
68401d72e9dSNiklas Söderlund 		break;
6850f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_2X8:
6860f4b3378SNiklas Söderlund 		/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
687158e2a53SJacopo Mondi 		if (!vin->is_csi &&
688d7592b2eSNiklas Söderlund 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
689158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT656;
690158e2a53SJacopo Mondi 		else
691158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV8_BT601;
692158e2a53SJacopo Mondi 
6930f4b3378SNiklas Söderlund 		input_is_yuv = true;
6940f4b3378SNiklas Söderlund 		break;
6950f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_RGB888_1X24:
6960f4b3378SNiklas Söderlund 		vnmc |= VNMC_INF_RGB888;
6970f4b3378SNiklas Söderlund 		break;
6980f4b3378SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY10_2X10:
6990f4b3378SNiklas Söderlund 		/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
700158e2a53SJacopo Mondi 		if (!vin->is_csi &&
701d7592b2eSNiklas Söderlund 		    vin->parallel.mbus_type == V4L2_MBUS_BT656)
702158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV10_BT656;
703158e2a53SJacopo Mondi 		else
704158e2a53SJacopo Mondi 			vnmc |= VNMC_INF_YUV10_BT601;
705158e2a53SJacopo Mondi 
7060f4b3378SNiklas Söderlund 		input_is_yuv = true;
7070f4b3378SNiklas Söderlund 		break;
7088c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR8_1X8:
7098c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG8_1X8:
7108c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG8_1X8:
711e87c1a81SLad Prabhakar 	case MEDIA_BUS_FMT_SRGGB8_1X8:
712c93beb52SVladimir Barinov 	case MEDIA_BUS_FMT_Y8_1X8:
713e87c1a81SLad Prabhakar 		vnmc |= VNMC_INF_RAW8;
714e87c1a81SLad Prabhakar 		break;
7150f4b3378SNiklas Söderlund 	default:
7160f4b3378SNiklas Söderlund 		break;
7170f4b3378SNiklas Söderlund 	}
7180f4b3378SNiklas Söderlund 
71978b3f9d7SNiklas Söderlund 	/* Make sure input interface and input format is valid. */
72078b3f9d7SNiklas Söderlund 	if (vin->info->model == RCAR_GEN3) {
72178b3f9d7SNiklas Söderlund 		switch (vnmc & VNMC_INF_MASK) {
72278b3f9d7SNiklas Söderlund 		case VNMC_INF_YUV8_BT656:
72378b3f9d7SNiklas Söderlund 		case VNMC_INF_YUV10_BT656:
72478b3f9d7SNiklas Söderlund 		case VNMC_INF_YUV16:
72578b3f9d7SNiklas Söderlund 		case VNMC_INF_RGB666:
72678b3f9d7SNiklas Söderlund 			if (vin->is_csi) {
72778b3f9d7SNiklas Söderlund 				vin_err(vin, "Invalid setting in MIPI CSI2\n");
72878b3f9d7SNiklas Söderlund 				return -EINVAL;
72978b3f9d7SNiklas Söderlund 			}
73078b3f9d7SNiklas Söderlund 			break;
73178b3f9d7SNiklas Söderlund 		case VNMC_INF_RAW8:
73278b3f9d7SNiklas Söderlund 			if (!vin->is_csi) {
73378b3f9d7SNiklas Söderlund 				vin_err(vin, "Invalid setting in Digital Pins\n");
73478b3f9d7SNiklas Söderlund 				return -EINVAL;
73578b3f9d7SNiklas Söderlund 			}
73678b3f9d7SNiklas Söderlund 			break;
73778b3f9d7SNiklas Söderlund 		default:
73878b3f9d7SNiklas Söderlund 			break;
73978b3f9d7SNiklas Söderlund 		}
74078b3f9d7SNiklas Söderlund 	}
74178b3f9d7SNiklas Söderlund 
7428b72c18dSMauro Carvalho Chehab 	/* Enable VSYNC Field Toggle mode after one VSYNC input */
743d73c3357SNiklas Söderlund 	if (vin->info->model == RCAR_GEN3)
744d73c3357SNiklas Söderlund 		dmr2 = VNDMR2_FTEV;
745d73c3357SNiklas Söderlund 	else
7460f4b3378SNiklas Söderlund 		dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
7470f4b3378SNiklas Söderlund 
748158e2a53SJacopo Mondi 	if (!vin->is_csi) {
7490f4b3378SNiklas Söderlund 		/* Hsync Signal Polarity Select */
750d7592b2eSNiklas Söderlund 		if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
7510f4b3378SNiklas Söderlund 			dmr2 |= VNDMR2_HPS;
7520f4b3378SNiklas Söderlund 
7530f4b3378SNiklas Söderlund 		/* Vsync Signal Polarity Select */
754d7592b2eSNiklas Söderlund 		if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
7550f4b3378SNiklas Söderlund 			dmr2 |= VNDMR2_VPS;
75653cf3100SJacopo Mondi 
75753cf3100SJacopo Mondi 		/* Data Enable Polarity Select */
758d7592b2eSNiklas Söderlund 		if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW)
75953cf3100SJacopo Mondi 			dmr2 |= VNDMR2_CES;
760e8834943SLad Prabhakar 
761e8834943SLad Prabhakar 		switch (vin->mbus_code) {
762e8834943SLad Prabhakar 		case MEDIA_BUS_FMT_UYVY8_2X8:
763d7592b2eSNiklas Söderlund 			if (vin->parallel.bus.bus_width == 8 &&
764d7592b2eSNiklas Söderlund 			    vin->parallel.bus.data_shift == 8)
765e8834943SLad Prabhakar 				dmr2 |= VNDMR2_YDS;
766e8834943SLad Prabhakar 			break;
767e8834943SLad Prabhakar 		default:
768e8834943SLad Prabhakar 			break;
769e8834943SLad Prabhakar 		}
770158e2a53SJacopo Mondi 	}
7710f4b3378SNiklas Söderlund 
7720f4b3378SNiklas Söderlund 	/*
7730f4b3378SNiklas Söderlund 	 * Output format
7740f4b3378SNiklas Söderlund 	 */
7750f4b3378SNiklas Söderlund 	switch (vin->format.pixelformat) {
7769b744a3eSNiklas Söderlund 	case V4L2_PIX_FMT_NV12:
7770f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_NV16:
7780f4b3378SNiklas Söderlund 		rvin_write(vin,
7795c9de1faSNiklas Söderlund 			   ALIGN(vin->format.bytesperline * vin->format.height,
7805c9de1faSNiklas Söderlund 				 0x80), VNUVAOF_REG);
7819b744a3eSNiklas Söderlund 		dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ?
7829b744a3eSNiklas Söderlund 			VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP;
7830f4b3378SNiklas Söderlund 		output_is_yuv = true;
7840f4b3378SNiklas Söderlund 		break;
7850f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_YUYV:
7860f4b3378SNiklas Söderlund 		dmr = VNDMR_BPSM;
7870f4b3378SNiklas Söderlund 		output_is_yuv = true;
7880f4b3378SNiklas Söderlund 		break;
7890f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_UYVY:
7900f4b3378SNiklas Söderlund 		dmr = 0;
7910f4b3378SNiklas Söderlund 		output_is_yuv = true;
7920f4b3378SNiklas Söderlund 		break;
7930f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_XRGB555:
79419ab1f64SNiklas Söderlund 		dmr = VNDMR_DTMD_ARGB;
7950f4b3378SNiklas Söderlund 		break;
7960f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_RGB565:
7970f4b3378SNiklas Söderlund 		dmr = 0;
7980f4b3378SNiklas Söderlund 		break;
7990f4b3378SNiklas Söderlund 	case V4L2_PIX_FMT_XBGR32:
8000f4b3378SNiklas Söderlund 		/* Note: not supported on M1 */
8010f4b3378SNiklas Söderlund 		dmr = VNDMR_EXRGB;
8020f4b3378SNiklas Söderlund 		break;
8031d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ARGB555:
8041d99e68cSNiklas Söderlund 		dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB;
8051d99e68cSNiklas Söderlund 		break;
8061d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ABGR32:
8071d99e68cSNiklas Söderlund 		dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB;
8081d99e68cSNiklas Söderlund 		break;
8098c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SBGGR8:
8108c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SGBRG8:
8118c3e0f67SNiklas Söderlund 	case V4L2_PIX_FMT_SGRBG8:
812e87c1a81SLad Prabhakar 	case V4L2_PIX_FMT_SRGGB8:
813e87c1a81SLad Prabhakar 		dmr = 0;
814e87c1a81SLad Prabhakar 		break;
815c93beb52SVladimir Barinov 	case V4L2_PIX_FMT_GREY:
816c93beb52SVladimir Barinov 		if (input_is_yuv) {
817c93beb52SVladimir Barinov 			dmr = VNDMR_DTMD_YCSEP | VNDMR_YMODE_Y8;
818c93beb52SVladimir Barinov 			output_is_yuv = true;
819c93beb52SVladimir Barinov 		} else {
820c93beb52SVladimir Barinov 			dmr = 0;
821c93beb52SVladimir Barinov 		}
822c93beb52SVladimir Barinov 		break;
8230f4b3378SNiklas Söderlund 	default:
8240f4b3378SNiklas Söderlund 		vin_err(vin, "Invalid pixelformat (0x%x)\n",
8250f4b3378SNiklas Söderlund 			vin->format.pixelformat);
8260f4b3378SNiklas Söderlund 		return -EINVAL;
8270f4b3378SNiklas Söderlund 	}
8280f4b3378SNiklas Söderlund 
8290f4b3378SNiklas Söderlund 	/* Always update on field change */
8300f4b3378SNiklas Söderlund 	vnmc |= VNMC_VUP;
8310f4b3378SNiklas Söderlund 
832406bb586SNiklas Söderlund 	if (!vin->info->use_isp) {
8330f4b3378SNiklas Söderlund 		/* If input and output use the same colorspace, use bypass mode */
8340f4b3378SNiklas Söderlund 		if (input_is_yuv == output_is_yuv)
8350f4b3378SNiklas Söderlund 			vnmc |= VNMC_BPS;
8360f4b3378SNiklas Söderlund 
8374394eb24SNiklas Söderlund 		if (vin->info->model == RCAR_GEN3) {
838d24c029eSJacopo Mondi 			/* Select between CSI-2 and parallel input */
839158e2a53SJacopo Mondi 			if (vin->is_csi)
8404394eb24SNiklas Söderlund 				vnmc &= ~VNMC_DPINE;
8414394eb24SNiklas Söderlund 			else
8424394eb24SNiklas Söderlund 				vnmc |= VNMC_DPINE;
8434394eb24SNiklas Söderlund 		}
844406bb586SNiklas Söderlund 	}
8454394eb24SNiklas Söderlund 
8460f4b3378SNiklas Söderlund 	/* Progressive or interlaced mode */
8470f4b3378SNiklas Söderlund 	interrupts = progressive ? VNIE_FIE : VNIE_EFE;
8480f4b3378SNiklas Söderlund 
8490f4b3378SNiklas Söderlund 	/* Ack interrupts */
8500f4b3378SNiklas Söderlund 	rvin_write(vin, interrupts, VNINTS_REG);
8510f4b3378SNiklas Söderlund 	/* Enable interrupts */
8520f4b3378SNiklas Söderlund 	rvin_write(vin, interrupts, VNIE_REG);
8530f4b3378SNiklas Söderlund 	/* Start capturing */
8540f4b3378SNiklas Söderlund 	rvin_write(vin, dmr, VNDMR_REG);
8550f4b3378SNiklas Söderlund 	rvin_write(vin, dmr2, VNDMR2_REG);
8560f4b3378SNiklas Söderlund 
8570f4b3378SNiklas Söderlund 	/* Enable module */
8580f4b3378SNiklas Söderlund 	rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
8590f4b3378SNiklas Söderlund 
8600f4b3378SNiklas Söderlund 	return 0;
8610f4b3378SNiklas Söderlund }
8620f4b3378SNiklas Söderlund 
8630f4b3378SNiklas Söderlund static void rvin_disable_interrupts(struct rvin_dev *vin)
8640f4b3378SNiklas Söderlund {
8650f4b3378SNiklas Söderlund 	rvin_write(vin, 0, VNIE_REG);
8660f4b3378SNiklas Söderlund }
8670f4b3378SNiklas Söderlund 
8680f4b3378SNiklas Söderlund static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
8690f4b3378SNiklas Söderlund {
8700f4b3378SNiklas Söderlund 	return rvin_read(vin, VNINTS_REG);
8710f4b3378SNiklas Söderlund }
8720f4b3378SNiklas Söderlund 
8730f4b3378SNiklas Söderlund static void rvin_ack_interrupt(struct rvin_dev *vin)
8740f4b3378SNiklas Söderlund {
8750f4b3378SNiklas Söderlund 	rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
8760f4b3378SNiklas Söderlund }
8770f4b3378SNiklas Söderlund 
8780f4b3378SNiklas Söderlund static bool rvin_capture_active(struct rvin_dev *vin)
8790f4b3378SNiklas Söderlund {
8800f4b3378SNiklas Söderlund 	return rvin_read(vin, VNMS_REG) & VNMS_CA;
8810f4b3378SNiklas Söderlund }
8820f4b3378SNiklas Söderlund 
88308369321SNiklas Söderlund static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
88408369321SNiklas Söderlund {
88508369321SNiklas Söderlund 	if (vin->format.field == V4L2_FIELD_ALTERNATE) {
88608369321SNiklas Söderlund 		/* If FS is set it is an Even field. */
88708369321SNiklas Söderlund 		if (vnms & VNMS_FS)
88808369321SNiklas Söderlund 			return V4L2_FIELD_BOTTOM;
88908369321SNiklas Söderlund 		return V4L2_FIELD_TOP;
89008369321SNiklas Söderlund 	}
89108369321SNiklas Söderlund 
89208369321SNiklas Söderlund 	return vin->format.field;
89308369321SNiklas Söderlund }
89408369321SNiklas Söderlund 
8950f4b3378SNiklas Söderlund static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
8960f4b3378SNiklas Söderlund {
8970f4b3378SNiklas Söderlund 	const struct rvin_video_format *fmt;
8980f4b3378SNiklas Söderlund 	int offsetx, offsety;
8990f4b3378SNiklas Söderlund 	dma_addr_t offset;
9000f4b3378SNiklas Söderlund 
90121a816e7SNiklas Söderlund 	fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
9020f4b3378SNiklas Söderlund 
9030f4b3378SNiklas Söderlund 	/*
9040f4b3378SNiklas Söderlund 	 * There is no HW support for composition do the beast we can
9050f4b3378SNiklas Söderlund 	 * by modifying the buffer offset
9060f4b3378SNiklas Söderlund 	 */
9070f4b3378SNiklas Söderlund 	offsetx = vin->compose.left * fmt->bpp;
9080f4b3378SNiklas Söderlund 	offsety = vin->compose.top * vin->format.bytesperline;
9090f4b3378SNiklas Söderlund 	offset = addr + offsetx + offsety;
9100f4b3378SNiklas Söderlund 
9110f4b3378SNiklas Söderlund 	/*
9120f4b3378SNiklas Söderlund 	 * The address needs to be 128 bytes aligned. Driver should never accept
9130f4b3378SNiklas Söderlund 	 * settings that do not satisfy this in the first place...
9140f4b3378SNiklas Söderlund 	 */
9150f4b3378SNiklas Söderlund 	if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
9160f4b3378SNiklas Söderlund 		return;
9170f4b3378SNiklas Söderlund 
9180f4b3378SNiklas Söderlund 	rvin_write(vin, offset, VNMB_REG(slot));
9190f4b3378SNiklas Söderlund }
9200f4b3378SNiklas Söderlund 
9210f4b3378SNiklas Söderlund /*
9220f4b3378SNiklas Söderlund  * Moves a buffer from the queue to the HW slot. If no buffer is
9230f4b3378SNiklas Söderlund  * available use the scratch buffer. The scratch buffer is never
9240f4b3378SNiklas Söderlund  * returned to userspace, its only function is to enable the capture
9250f4b3378SNiklas Söderlund  * loop to keep running.
9260f4b3378SNiklas Söderlund  */
9270f4b3378SNiklas Söderlund static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
9280f4b3378SNiklas Söderlund {
9290f4b3378SNiklas Söderlund 	struct rvin_buffer *buf;
9300f4b3378SNiklas Söderlund 	struct vb2_v4l2_buffer *vbuf;
9310f4b3378SNiklas Söderlund 	dma_addr_t phys_addr;
9327e0cfdadSNiklas Söderlund 	int prev;
9330f4b3378SNiklas Söderlund 
9340f4b3378SNiklas Söderlund 	/* A already populated slot shall never be overwritten. */
935e72b7359SNiklas Söderlund 	if (WARN_ON(vin->buf_hw[slot].buffer))
9360f4b3378SNiklas Söderlund 		return;
9370f4b3378SNiklas Söderlund 
9387e0cfdadSNiklas Söderlund 	prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1;
9390f4b3378SNiklas Söderlund 
9407e0cfdadSNiklas Söderlund 	if (vin->buf_hw[prev].type == HALF_TOP) {
9417e0cfdadSNiklas Söderlund 		vbuf = vin->buf_hw[prev].buffer;
9427e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].buffer = vbuf;
9437e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].type = HALF_BOTTOM;
9447e0cfdadSNiklas Söderlund 		switch (vin->format.pixelformat) {
9457e0cfdadSNiklas Söderlund 		case V4L2_PIX_FMT_NV12:
9467e0cfdadSNiklas Söderlund 		case V4L2_PIX_FMT_NV16:
9477e0cfdadSNiklas Söderlund 			phys_addr = vin->buf_hw[prev].phys +
9487e0cfdadSNiklas Söderlund 				vin->format.sizeimage / 4;
9497e0cfdadSNiklas Söderlund 			break;
9507e0cfdadSNiklas Söderlund 		default:
9517e0cfdadSNiklas Söderlund 			phys_addr = vin->buf_hw[prev].phys +
9527e0cfdadSNiklas Söderlund 				vin->format.sizeimage / 2;
9537e0cfdadSNiklas Söderlund 			break;
9547e0cfdadSNiklas Söderlund 		}
955a5991c4eSNiklas Söderlund 	} else if ((vin->state != STOPPED && vin->state != RUNNING) ||
956a5991c4eSNiklas Söderlund 		   list_empty(&vin->buf_list)) {
957e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
9587e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].type = FULL;
9590f4b3378SNiklas Söderlund 		phys_addr = vin->scratch_phys;
9600f4b3378SNiklas Söderlund 	} else {
9610f4b3378SNiklas Söderlund 		/* Keep track of buffer we give to HW */
9620f4b3378SNiklas Söderlund 		buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
9630f4b3378SNiklas Söderlund 		vbuf = &buf->vb;
9640f4b3378SNiklas Söderlund 		list_del_init(to_buf_list(vbuf));
965e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = vbuf;
9660f4b3378SNiklas Söderlund 
9677e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].type =
9687e0cfdadSNiklas Söderlund 			V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ?
9697e0cfdadSNiklas Söderlund 			HALF_TOP : FULL;
9707e0cfdadSNiklas Söderlund 
9710f4b3378SNiklas Söderlund 		/* Setup DMA */
9720f4b3378SNiklas Söderlund 		phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
9730f4b3378SNiklas Söderlund 	}
9740f4b3378SNiklas Söderlund 
9757e0cfdadSNiklas Söderlund 	vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n",
9767e0cfdadSNiklas Söderlund 		slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer);
9777e0cfdadSNiklas Söderlund 
9787e0cfdadSNiklas Söderlund 	vin->buf_hw[slot].phys = phys_addr;
9790f4b3378SNiklas Söderlund 	rvin_set_slot_addr(vin, slot, phys_addr);
9800f4b3378SNiklas Söderlund }
9810f4b3378SNiklas Söderlund 
9820f4b3378SNiklas Söderlund static int rvin_capture_start(struct rvin_dev *vin)
9830f4b3378SNiklas Söderlund {
9840f4b3378SNiklas Söderlund 	int slot, ret;
9850f4b3378SNiklas Söderlund 
9867e0cfdadSNiklas Söderlund 	for (slot = 0; slot < HW_BUFFER_NUM; slot++) {
9877e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
9887e0cfdadSNiklas Söderlund 		vin->buf_hw[slot].type = FULL;
9897e0cfdadSNiklas Söderlund 	}
9907e0cfdadSNiklas Söderlund 
9910f4b3378SNiklas Söderlund 	for (slot = 0; slot < HW_BUFFER_NUM; slot++)
9920f4b3378SNiklas Söderlund 		rvin_fill_hw_slot(vin, slot);
9930f4b3378SNiklas Söderlund 
9940f4b3378SNiklas Söderlund 	ret = rvin_setup(vin);
9950f4b3378SNiklas Söderlund 	if (ret)
9960f4b3378SNiklas Söderlund 		return ret;
9970f4b3378SNiklas Söderlund 
998*3ad69c61SNiklas Söderlund 	rvin_crop_scale_comp(vin);
999*3ad69c61SNiklas Söderlund 
10000f4b3378SNiklas Söderlund 	vin_dbg(vin, "Starting to capture\n");
10010f4b3378SNiklas Söderlund 
10020f4b3378SNiklas Söderlund 	/* Continuous Frame Capture Mode */
10030f4b3378SNiklas Söderlund 	rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
10040f4b3378SNiklas Söderlund 
100523689ab1SNiklas Söderlund 	vin->state = STARTING;
10060f4b3378SNiklas Söderlund 
10070f4b3378SNiklas Söderlund 	return 0;
10080f4b3378SNiklas Söderlund }
10090f4b3378SNiklas Söderlund 
10100f4b3378SNiklas Söderlund static void rvin_capture_stop(struct rvin_dev *vin)
10110f4b3378SNiklas Söderlund {
10120f4b3378SNiklas Söderlund 	/* Set continuous & single transfer off */
10130f4b3378SNiklas Söderlund 	rvin_write(vin, 0, VNFC_REG);
10140f4b3378SNiklas Söderlund 
10150f4b3378SNiklas Söderlund 	/* Disable module */
10160f4b3378SNiklas Söderlund 	rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
10170f4b3378SNiklas Söderlund }
10180f4b3378SNiklas Söderlund 
10190f4b3378SNiklas Söderlund /* -----------------------------------------------------------------------------
1020f00add96SNiklas Söderlund  * DMA Functions
1021f00add96SNiklas Söderlund  */
1022f00add96SNiklas Söderlund 
1023f00add96SNiklas Söderlund #define RVIN_TIMEOUT_MS 100
1024f00add96SNiklas Söderlund #define RVIN_RETRIES 10
1025f00add96SNiklas Söderlund 
1026f00add96SNiklas Söderlund static irqreturn_t rvin_irq(int irq, void *data)
1027f00add96SNiklas Söderlund {
1028f00add96SNiklas Söderlund 	struct rvin_dev *vin = data;
1029b6f556cbSNiklas Söderlund 	u32 int_status, vnms;
1030f00add96SNiklas Söderlund 	int slot;
1031dc9aec79SNiklas Söderlund 	unsigned int handled = 0;
1032f00add96SNiklas Söderlund 	unsigned long flags;
1033f00add96SNiklas Söderlund 
1034f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1035f00add96SNiklas Söderlund 
1036f00add96SNiklas Söderlund 	int_status = rvin_get_interrupt_status(vin);
1037f00add96SNiklas Söderlund 	if (!int_status)
1038f00add96SNiklas Söderlund 		goto done;
1039f00add96SNiklas Söderlund 
1040f00add96SNiklas Söderlund 	rvin_ack_interrupt(vin);
1041f00add96SNiklas Söderlund 	handled = 1;
1042f00add96SNiklas Söderlund 
104330334d3dSNiklas Söderlund 	/* Nothing to do if nothing was captured. */
104430334d3dSNiklas Söderlund 	if (!(int_status & VNINTS_FIS))
104530334d3dSNiklas Söderlund 		goto done;
104630334d3dSNiklas Söderlund 
1047f00add96SNiklas Söderlund 	/* Nothing to do if capture status is 'STOPPED' */
1048f00add96SNiklas Söderlund 	if (vin->state == STOPPED) {
1049f00add96SNiklas Söderlund 		vin_dbg(vin, "IRQ while state stopped\n");
1050f00add96SNiklas Söderlund 		goto done;
1051f00add96SNiklas Söderlund 	}
1052f00add96SNiklas Söderlund 
1053f00add96SNiklas Söderlund 	/* Prepare for capture and update state */
1054b6f556cbSNiklas Söderlund 	vnms = rvin_read(vin, VNMS_REG);
1055dc9aec79SNiklas Söderlund 	slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
1056f00add96SNiklas Söderlund 
105723689ab1SNiklas Söderlund 	/*
105823689ab1SNiklas Söderlund 	 * To hand buffers back in a known order to userspace start
105923689ab1SNiklas Söderlund 	 * to capture first from slot 0.
106023689ab1SNiklas Söderlund 	 */
106123689ab1SNiklas Söderlund 	if (vin->state == STARTING) {
106223689ab1SNiklas Söderlund 		if (slot != 0) {
106323689ab1SNiklas Söderlund 			vin_dbg(vin, "Starting sync slot: %d\n", slot);
106423689ab1SNiklas Söderlund 			goto done;
106523689ab1SNiklas Söderlund 		}
106623689ab1SNiklas Söderlund 
106723689ab1SNiklas Söderlund 		vin_dbg(vin, "Capture start synced!\n");
106823689ab1SNiklas Söderlund 		vin->state = RUNNING;
106923689ab1SNiklas Söderlund 	}
107023689ab1SNiklas Söderlund 
1071f00add96SNiklas Söderlund 	/* Capture frame */
1072e72b7359SNiklas Söderlund 	if (vin->buf_hw[slot].buffer) {
10737e0cfdadSNiklas Söderlund 		/*
10747e0cfdadSNiklas Söderlund 		 * Nothing to do but refill the hardware slot if
10757e0cfdadSNiklas Söderlund 		 * capture only filled first half of vb2 buffer.
10767e0cfdadSNiklas Söderlund 		 */
10777e0cfdadSNiklas Söderlund 		if (vin->buf_hw[slot].type == HALF_TOP) {
10787e0cfdadSNiklas Söderlund 			vin->buf_hw[slot].buffer = NULL;
10797e0cfdadSNiklas Söderlund 			rvin_fill_hw_slot(vin, slot);
10807e0cfdadSNiklas Söderlund 			goto done;
10817e0cfdadSNiklas Söderlund 		}
10827e0cfdadSNiklas Söderlund 
1083e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->field =
1084e72b7359SNiklas Söderlund 			rvin_get_active_field(vin, vnms);
1085e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->sequence = vin->sequence;
1086e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns();
1087e72b7359SNiklas Söderlund 		vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf,
1088dc9aec79SNiklas Söderlund 				VB2_BUF_STATE_DONE);
1089e72b7359SNiklas Söderlund 		vin->buf_hw[slot].buffer = NULL;
1090dc9aec79SNiklas Söderlund 	} else {
1091dc9aec79SNiklas Söderlund 		/* Scratch buffer was used, dropping frame. */
1092dc9aec79SNiklas Söderlund 		vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
1093dc9aec79SNiklas Söderlund 	}
1094dc9aec79SNiklas Söderlund 
1095dc9aec79SNiklas Söderlund 	vin->sequence++;
1096f00add96SNiklas Söderlund 
1097f00add96SNiklas Söderlund 	/* Prepare for next frame */
1098dc9aec79SNiklas Söderlund 	rvin_fill_hw_slot(vin, slot);
1099f00add96SNiklas Söderlund done:
1100f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1101f00add96SNiklas Söderlund 
1102f00add96SNiklas Söderlund 	return IRQ_RETVAL(handled);
1103f00add96SNiklas Söderlund }
1104f00add96SNiklas Söderlund 
1105b83a18ccSNiklas Söderlund static void return_unused_buffers(struct rvin_dev *vin,
1106f00add96SNiklas Söderlund 				  enum vb2_buffer_state state)
1107f00add96SNiklas Söderlund {
1108f00add96SNiklas Söderlund 	struct rvin_buffer *buf, *node;
110963a71dd8SNiklas Söderlund 	unsigned long flags;
111063a71dd8SNiklas Söderlund 
111163a71dd8SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
11127e0cfdadSNiklas Söderlund 
1113f00add96SNiklas Söderlund 	list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
1114f00add96SNiklas Söderlund 		vb2_buffer_done(&buf->vb.vb2_buf, state);
1115f00add96SNiklas Söderlund 		list_del(&buf->list);
1116f00add96SNiklas Söderlund 	}
111763a71dd8SNiklas Söderlund 
111863a71dd8SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1119f00add96SNiklas Söderlund }
1120f00add96SNiklas Söderlund 
1121f00add96SNiklas Söderlund static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
1122f00add96SNiklas Söderlund 			    unsigned int *nplanes, unsigned int sizes[],
112336c0f8b3SHans Verkuil 			    struct device *alloc_devs[])
1124f00add96SNiklas Söderlund 
1125f00add96SNiklas Söderlund {
1126f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
1127f00add96SNiklas Söderlund 
1128f00add96SNiklas Söderlund 	/* Make sure the image size is large enough. */
1129f00add96SNiklas Söderlund 	if (*nplanes)
1130f00add96SNiklas Söderlund 		return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1131f00add96SNiklas Söderlund 
1132f00add96SNiklas Söderlund 	*nplanes = 1;
1133f00add96SNiklas Söderlund 	sizes[0] = vin->format.sizeimage;
1134f00add96SNiklas Söderlund 
1135f00add96SNiklas Söderlund 	return 0;
1136f00add96SNiklas Söderlund };
1137f00add96SNiklas Söderlund 
1138f00add96SNiklas Söderlund static int rvin_buffer_prepare(struct vb2_buffer *vb)
1139f00add96SNiklas Söderlund {
1140f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1141f00add96SNiklas Söderlund 	unsigned long size = vin->format.sizeimage;
1142f00add96SNiklas Söderlund 
1143f00add96SNiklas Söderlund 	if (vb2_plane_size(vb, 0) < size) {
1144f00add96SNiklas Söderlund 		vin_err(vin, "buffer too small (%lu < %lu)\n",
1145f00add96SNiklas Söderlund 			vb2_plane_size(vb, 0), size);
1146f00add96SNiklas Söderlund 		return -EINVAL;
1147f00add96SNiklas Söderlund 	}
1148f00add96SNiklas Söderlund 
1149f00add96SNiklas Söderlund 	vb2_set_plane_payload(vb, 0, size);
1150f00add96SNiklas Söderlund 
1151f00add96SNiklas Söderlund 	return 0;
1152f00add96SNiklas Söderlund }
1153f00add96SNiklas Söderlund 
1154f00add96SNiklas Söderlund static void rvin_buffer_queue(struct vb2_buffer *vb)
1155f00add96SNiklas Söderlund {
1156f00add96SNiklas Söderlund 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1157f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1158f00add96SNiklas Söderlund 	unsigned long flags;
1159f00add96SNiklas Söderlund 
1160f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1161f00add96SNiklas Söderlund 
1162f00add96SNiklas Söderlund 	list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1163f00add96SNiklas Söderlund 
1164f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1165f00add96SNiklas Söderlund }
1166f00add96SNiklas Söderlund 
11677b7eb115SNiklas Söderlund static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
11687b7eb115SNiklas Söderlund 				   struct media_pad *pad)
11697b7eb115SNiklas Söderlund {
11707b7eb115SNiklas Söderlund 	struct v4l2_subdev_format fmt = {
11717b7eb115SNiklas Söderlund 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
11727b7eb115SNiklas Söderlund 	};
11737b7eb115SNiklas Söderlund 
11747b7eb115SNiklas Söderlund 	fmt.pad = pad->index;
11757b7eb115SNiklas Söderlund 	if (v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt))
11767b7eb115SNiklas Söderlund 		return -EPIPE;
11777b7eb115SNiklas Söderlund 
11787b7eb115SNiklas Söderlund 	switch (fmt.format.code) {
11797b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_YUYV8_1X16:
118001d72e9dSNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_1X16:
11817b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY8_2X8:
11827b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_UYVY10_2X10:
11837b7eb115SNiklas Söderlund 	case MEDIA_BUS_FMT_RGB888_1X24:
1184fd22e8ebSLad Prabhakar 		break;
11858c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SBGGR8_1X8:
11868c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8)
11878c3e0f67SNiklas Söderlund 			return -EPIPE;
11888c3e0f67SNiklas Söderlund 		break;
11898c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGBRG8_1X8:
11908c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8)
11918c3e0f67SNiklas Söderlund 			return -EPIPE;
11928c3e0f67SNiklas Söderlund 		break;
11938c3e0f67SNiklas Söderlund 	case MEDIA_BUS_FMT_SGRBG8_1X8:
11948c3e0f67SNiklas Söderlund 		if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8)
11958c3e0f67SNiklas Söderlund 			return -EPIPE;
11968c3e0f67SNiklas Söderlund 		break;
1197fd22e8ebSLad Prabhakar 	case MEDIA_BUS_FMT_SRGGB8_1X8:
1198fd22e8ebSLad Prabhakar 		if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8)
1199fd22e8ebSLad Prabhakar 			return -EPIPE;
12007b7eb115SNiklas Söderlund 		break;
1201c93beb52SVladimir Barinov 	case MEDIA_BUS_FMT_Y8_1X8:
1202c93beb52SVladimir Barinov 		if (vin->format.pixelformat != V4L2_PIX_FMT_GREY)
1203c93beb52SVladimir Barinov 			return -EPIPE;
1204c93beb52SVladimir Barinov 		break;
12057b7eb115SNiklas Söderlund 	default:
12067b7eb115SNiklas Söderlund 		return -EPIPE;
12077b7eb115SNiklas Söderlund 	}
1208fd22e8ebSLad Prabhakar 	vin->mbus_code = fmt.format.code;
12097b7eb115SNiklas Söderlund 
12107b7eb115SNiklas Söderlund 	switch (fmt.format.field) {
12117b7eb115SNiklas Söderlund 	case V4L2_FIELD_TOP:
12127b7eb115SNiklas Söderlund 	case V4L2_FIELD_BOTTOM:
12137b7eb115SNiklas Söderlund 	case V4L2_FIELD_NONE:
12147b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_TB:
12157b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED_BT:
12167b7eb115SNiklas Söderlund 	case V4L2_FIELD_INTERLACED:
12177b7eb115SNiklas Söderlund 	case V4L2_FIELD_SEQ_TB:
12187b7eb115SNiklas Söderlund 	case V4L2_FIELD_SEQ_BT:
12197b7eb115SNiklas Söderlund 		/* Supported natively */
12207b7eb115SNiklas Söderlund 		break;
12217b7eb115SNiklas Söderlund 	case V4L2_FIELD_ALTERNATE:
12227b7eb115SNiklas Söderlund 		switch (vin->format.field) {
12237b7eb115SNiklas Söderlund 		case V4L2_FIELD_TOP:
12247b7eb115SNiklas Söderlund 		case V4L2_FIELD_BOTTOM:
12257b7eb115SNiklas Söderlund 		case V4L2_FIELD_NONE:
122608369321SNiklas Söderlund 		case V4L2_FIELD_ALTERNATE:
12277b7eb115SNiklas Söderlund 			break;
12287b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED_TB:
12297b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED_BT:
12307b7eb115SNiklas Söderlund 		case V4L2_FIELD_INTERLACED:
12317b7eb115SNiklas Söderlund 		case V4L2_FIELD_SEQ_TB:
12327b7eb115SNiklas Söderlund 		case V4L2_FIELD_SEQ_BT:
12337b7eb115SNiklas Söderlund 			/* Use VIN hardware to combine the two fields */
12347b7eb115SNiklas Söderlund 			fmt.format.height *= 2;
12357b7eb115SNiklas Söderlund 			break;
12367b7eb115SNiklas Söderlund 		default:
12377b7eb115SNiklas Söderlund 			return -EPIPE;
12387b7eb115SNiklas Söderlund 		}
12397b7eb115SNiklas Söderlund 		break;
12407b7eb115SNiklas Söderlund 	default:
12417b7eb115SNiklas Söderlund 		return -EPIPE;
12427b7eb115SNiklas Söderlund 	}
12437b7eb115SNiklas Söderlund 
1244*3ad69c61SNiklas Söderlund 	if (rvin_scaler_needed(vin)) {
1245*3ad69c61SNiklas Söderlund 		if (!vin->scaler)
1246*3ad69c61SNiklas Söderlund 			return -EPIPE;
1247*3ad69c61SNiklas Söderlund 	} else {
12487b7eb115SNiklas Söderlund 		if (fmt.format.width != vin->format.width ||
1249*3ad69c61SNiklas Söderlund 		    fmt.format.height != vin->format.height)
1250*3ad69c61SNiklas Söderlund 			return -EPIPE;
1251*3ad69c61SNiklas Söderlund 	}
1252*3ad69c61SNiklas Söderlund 
1253*3ad69c61SNiklas Söderlund 	if (fmt.format.code != vin->mbus_code)
12547b7eb115SNiklas Söderlund 		return -EPIPE;
12557b7eb115SNiklas Söderlund 
12567b7eb115SNiklas Söderlund 	return 0;
12577b7eb115SNiklas Söderlund }
12587b7eb115SNiklas Söderlund 
12597b7eb115SNiklas Söderlund static int rvin_set_stream(struct rvin_dev *vin, int on)
12607b7eb115SNiklas Söderlund {
12617b7eb115SNiklas Söderlund 	struct v4l2_subdev *sd;
12627b7eb115SNiklas Söderlund 	struct media_pad *pad;
12637b7eb115SNiklas Söderlund 	int ret;
12647b7eb115SNiklas Söderlund 
12657b7eb115SNiklas Söderlund 	/* No media controller used, simply pass operation to subdevice. */
12667b7eb115SNiklas Söderlund 	if (!vin->info->use_mc) {
1267d7592b2eSNiklas Söderlund 		ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream,
12687b7eb115SNiklas Söderlund 				       on);
12697b7eb115SNiklas Söderlund 
12707b7eb115SNiklas Söderlund 		return ret == -ENOIOCTLCMD ? 0 : ret;
12717b7eb115SNiklas Söderlund 	}
12727b7eb115SNiklas Söderlund 
1273b2e44430SLaurent Pinchart 	pad = media_pad_remote_pad_first(&vin->pad);
12747b7eb115SNiklas Söderlund 	if (!pad)
12757b7eb115SNiklas Söderlund 		return -EPIPE;
12767b7eb115SNiklas Söderlund 
12777b7eb115SNiklas Söderlund 	sd = media_entity_to_v4l2_subdev(pad->entity);
12787b7eb115SNiklas Söderlund 
12797b7eb115SNiklas Söderlund 	if (!on) {
128012cecbf9STomi Valkeinen 		video_device_pipeline_stop(&vin->vdev);
12817b7eb115SNiklas Söderlund 		return v4l2_subdev_call(sd, video, s_stream, 0);
12827b7eb115SNiklas Söderlund 	}
12837b7eb115SNiklas Söderlund 
12847b7eb115SNiklas Söderlund 	ret = rvin_mc_validate_format(vin, sd, pad);
12857b7eb115SNiklas Söderlund 	if (ret)
12867b7eb115SNiklas Söderlund 		return ret;
12877b7eb115SNiklas Söderlund 
12886eaff06aSTomi Valkeinen 	ret = video_device_pipeline_alloc_start(&vin->vdev);
12897b7eb115SNiklas Söderlund 	if (ret)
12907b7eb115SNiklas Söderlund 		return ret;
12917b7eb115SNiklas Söderlund 
12927b7eb115SNiklas Söderlund 	ret = v4l2_subdev_call(sd, video, s_stream, 1);
12937b7eb115SNiklas Söderlund 	if (ret == -ENOIOCTLCMD)
12947b7eb115SNiklas Söderlund 		ret = 0;
12957b7eb115SNiklas Söderlund 	if (ret)
129612cecbf9STomi Valkeinen 		video_device_pipeline_stop(&vin->vdev);
12977b7eb115SNiklas Söderlund 
12987b7eb115SNiklas Söderlund 	return ret;
12997b7eb115SNiklas Söderlund }
13007b7eb115SNiklas Söderlund 
130163a71dd8SNiklas Söderlund int rvin_start_streaming(struct rvin_dev *vin)
1302f00add96SNiklas Söderlund {
1303f00add96SNiklas Söderlund 	unsigned long flags;
1304f00add96SNiklas Söderlund 	int ret;
1305f00add96SNiklas Söderlund 
13067b7eb115SNiklas Söderlund 	ret = rvin_set_stream(vin, 1);
130763a71dd8SNiklas Söderlund 	if (ret)
130863a71dd8SNiklas Söderlund 		return ret;
1309f00add96SNiklas Söderlund 
1310f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1311f00add96SNiklas Söderlund 
1312f00add96SNiklas Söderlund 	vin->sequence = 0;
1313f00add96SNiklas Söderlund 
1314f00add96SNiklas Söderlund 	ret = rvin_capture_start(vin);
131563a71dd8SNiklas Söderlund 	if (ret)
13167b7eb115SNiklas Söderlund 		rvin_set_stream(vin, 0);
1317f00add96SNiklas Söderlund 
1318f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
13196a8ffa8bSNiklas Söderlund 
1320f00add96SNiklas Söderlund 	return ret;
1321f00add96SNiklas Söderlund }
1322f00add96SNiklas Söderlund 
132363a71dd8SNiklas Söderlund static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
1324f00add96SNiklas Söderlund {
1325f00add96SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
132663a71dd8SNiklas Söderlund 	int ret = -ENOMEM;
132763a71dd8SNiklas Söderlund 
132863a71dd8SNiklas Söderlund 	/* Allocate scratch buffer. */
132963a71dd8SNiklas Söderlund 	vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage,
133063a71dd8SNiklas Söderlund 					  &vin->scratch_phys, GFP_KERNEL);
133163a71dd8SNiklas Söderlund 	if (!vin->scratch)
133263a71dd8SNiklas Söderlund 		goto err_scratch;
133363a71dd8SNiklas Söderlund 
133463a71dd8SNiklas Söderlund 	ret = rvin_start_streaming(vin);
133563a71dd8SNiklas Söderlund 	if (ret)
133663a71dd8SNiklas Söderlund 		goto err_start;
133763a71dd8SNiklas Söderlund 
133863a71dd8SNiklas Söderlund 	return 0;
133963a71dd8SNiklas Söderlund err_start:
134063a71dd8SNiklas Söderlund 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
134163a71dd8SNiklas Söderlund 			  vin->scratch_phys);
134263a71dd8SNiklas Söderlund err_scratch:
134363a71dd8SNiklas Söderlund 	return_unused_buffers(vin, VB2_BUF_STATE_QUEUED);
134463a71dd8SNiklas Söderlund 
134563a71dd8SNiklas Söderlund 	return ret;
134663a71dd8SNiklas Söderlund }
134763a71dd8SNiklas Söderlund 
134863a71dd8SNiklas Söderlund void rvin_stop_streaming(struct rvin_dev *vin)
134963a71dd8SNiklas Söderlund {
135090ed5785SNiklas Söderlund 	unsigned int i, retries;
1351f00add96SNiklas Söderlund 	unsigned long flags;
135290ed5785SNiklas Söderlund 	bool buffersFreed;
1353f00add96SNiklas Söderlund 
1354f00add96SNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
1355f00add96SNiklas Söderlund 
1356c4f11535SNiklas Söderlund 	if (vin->state == STOPPED) {
1357c4f11535SNiklas Söderlund 		spin_unlock_irqrestore(&vin->qlock, flags);
1358c4f11535SNiklas Söderlund 		return;
1359c4f11535SNiklas Söderlund 	}
1360c4f11535SNiklas Söderlund 
1361f00add96SNiklas Söderlund 	vin->state = STOPPING;
1362f00add96SNiklas Söderlund 
136390ed5785SNiklas Söderlund 	/* Wait until only scratch buffer is used, max 3 interrupts. */
136490ed5785SNiklas Söderlund 	retries = 0;
136590ed5785SNiklas Söderlund 	while (retries++ < RVIN_RETRIES) {
136690ed5785SNiklas Söderlund 		buffersFreed = true;
136790ed5785SNiklas Söderlund 		for (i = 0; i < HW_BUFFER_NUM; i++)
136890ed5785SNiklas Söderlund 			if (vin->buf_hw[i].buffer)
136990ed5785SNiklas Söderlund 				buffersFreed = false;
137090ed5785SNiklas Söderlund 
137190ed5785SNiklas Söderlund 		if (buffersFreed)
137290ed5785SNiklas Söderlund 			break;
137390ed5785SNiklas Söderlund 
137490ed5785SNiklas Söderlund 		spin_unlock_irqrestore(&vin->qlock, flags);
137590ed5785SNiklas Söderlund 		msleep(RVIN_TIMEOUT_MS);
137690ed5785SNiklas Söderlund 		spin_lock_irqsave(&vin->qlock, flags);
137790ed5785SNiklas Söderlund 	}
137890ed5785SNiklas Söderlund 
1379f00add96SNiklas Söderlund 	/* Wait for streaming to stop */
138090ed5785SNiklas Söderlund 	retries = 0;
1381f00add96SNiklas Söderlund 	while (retries++ < RVIN_RETRIES) {
1382f00add96SNiklas Söderlund 
1383f00add96SNiklas Söderlund 		rvin_capture_stop(vin);
1384f00add96SNiklas Söderlund 
1385f00add96SNiklas Söderlund 		/* Check if HW is stopped */
1386f00add96SNiklas Söderlund 		if (!rvin_capture_active(vin)) {
1387f00add96SNiklas Söderlund 			vin->state = STOPPED;
1388f00add96SNiklas Söderlund 			break;
1389f00add96SNiklas Söderlund 		}
1390f00add96SNiklas Söderlund 
1391f00add96SNiklas Söderlund 		spin_unlock_irqrestore(&vin->qlock, flags);
1392f00add96SNiklas Söderlund 		msleep(RVIN_TIMEOUT_MS);
1393f00add96SNiklas Söderlund 		spin_lock_irqsave(&vin->qlock, flags);
1394f00add96SNiklas Söderlund 	}
1395f00add96SNiklas Söderlund 
139690ed5785SNiklas Söderlund 	if (!buffersFreed || vin->state != STOPPED) {
1397f00add96SNiklas Söderlund 		/*
1398f00add96SNiklas Söderlund 		 * If this happens something have gone horribly wrong.
1399f00add96SNiklas Söderlund 		 * Set state to stopped to prevent the interrupt handler
1400f00add96SNiklas Söderlund 		 * to make things worse...
1401f00add96SNiklas Söderlund 		 */
1402f00add96SNiklas Söderlund 		vin_err(vin, "Failed stop HW, something is seriously broken\n");
1403f00add96SNiklas Söderlund 		vin->state = STOPPED;
1404f00add96SNiklas Söderlund 	}
1405f00add96SNiklas Söderlund 
1406f00add96SNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
1407f00add96SNiklas Söderlund 
1408dca7cc1cSNiklas Söderlund 	/* If something went wrong, free buffers with an error. */
1409dca7cc1cSNiklas Söderlund 	if (!buffersFreed) {
1410dca7cc1cSNiklas Söderlund 		return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
1411dca7cc1cSNiklas Söderlund 		for (i = 0; i < HW_BUFFER_NUM; i++) {
1412dca7cc1cSNiklas Söderlund 			if (vin->buf_hw[i].buffer)
1413dca7cc1cSNiklas Söderlund 				vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf,
1414dca7cc1cSNiklas Söderlund 						VB2_BUF_STATE_ERROR);
1415dca7cc1cSNiklas Söderlund 		}
1416dca7cc1cSNiklas Söderlund 	}
1417dca7cc1cSNiklas Söderlund 
14187b7eb115SNiklas Söderlund 	rvin_set_stream(vin, 0);
1419f00add96SNiklas Söderlund 
1420f00add96SNiklas Söderlund 	/* disable interrupts */
1421f00add96SNiklas Söderlund 	rvin_disable_interrupts(vin);
142263a71dd8SNiklas Söderlund }
142363a71dd8SNiklas Söderlund 
142463a71dd8SNiklas Söderlund static void rvin_stop_streaming_vq(struct vb2_queue *vq)
142563a71dd8SNiklas Söderlund {
142663a71dd8SNiklas Söderlund 	struct rvin_dev *vin = vb2_get_drv_priv(vq);
142763a71dd8SNiklas Söderlund 
142863a71dd8SNiklas Söderlund 	rvin_stop_streaming(vin);
14296a8ffa8bSNiklas Söderlund 
14306a8ffa8bSNiklas Söderlund 	/* Free scratch buffer. */
14316a8ffa8bSNiklas Söderlund 	dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch,
14326a8ffa8bSNiklas Söderlund 			  vin->scratch_phys);
143363a71dd8SNiklas Söderlund 
143463a71dd8SNiklas Söderlund 	return_unused_buffers(vin, VB2_BUF_STATE_ERROR);
1435f00add96SNiklas Söderlund }
1436f00add96SNiklas Söderlund 
1437b7b361f0SJulia Lawall static const struct vb2_ops rvin_qops = {
1438f00add96SNiklas Söderlund 	.queue_setup		= rvin_queue_setup,
1439f00add96SNiklas Söderlund 	.buf_prepare		= rvin_buffer_prepare,
1440f00add96SNiklas Söderlund 	.buf_queue		= rvin_buffer_queue,
144163a71dd8SNiklas Söderlund 	.start_streaming	= rvin_start_streaming_vq,
144263a71dd8SNiklas Söderlund 	.stop_streaming		= rvin_stop_streaming_vq,
1443f00add96SNiklas Söderlund 	.wait_prepare		= vb2_ops_wait_prepare,
1444f00add96SNiklas Söderlund 	.wait_finish		= vb2_ops_wait_finish,
1445f00add96SNiklas Söderlund };
1446f00add96SNiklas Söderlund 
1447d6ad012eSNiklas Söderlund void rvin_dma_unregister(struct rvin_dev *vin)
1448f00add96SNiklas Söderlund {
1449f00add96SNiklas Söderlund 	mutex_destroy(&vin->lock);
1450f00add96SNiklas Söderlund 
1451f00add96SNiklas Söderlund 	v4l2_device_unregister(&vin->v4l2_dev);
1452f00add96SNiklas Söderlund }
1453f00add96SNiklas Söderlund 
1454d6ad012eSNiklas Söderlund int rvin_dma_register(struct rvin_dev *vin, int irq)
1455f00add96SNiklas Söderlund {
1456f00add96SNiklas Söderlund 	struct vb2_queue *q = &vin->queue;
1457f00add96SNiklas Söderlund 	int i, ret;
1458f00add96SNiklas Söderlund 
1459f00add96SNiklas Söderlund 	/* Initialize the top-level structure */
1460f00add96SNiklas Söderlund 	ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1461f00add96SNiklas Söderlund 	if (ret)
1462f00add96SNiklas Söderlund 		return ret;
1463f00add96SNiklas Söderlund 
1464f00add96SNiklas Söderlund 	mutex_init(&vin->lock);
1465f00add96SNiklas Söderlund 	INIT_LIST_HEAD(&vin->buf_list);
1466f00add96SNiklas Söderlund 
1467f00add96SNiklas Söderlund 	spin_lock_init(&vin->qlock);
1468f00add96SNiklas Söderlund 
1469f00add96SNiklas Söderlund 	vin->state = STOPPED;
1470f00add96SNiklas Söderlund 
1471f00add96SNiklas Söderlund 	for (i = 0; i < HW_BUFFER_NUM; i++)
1472e72b7359SNiklas Söderlund 		vin->buf_hw[i].buffer = NULL;
1473f00add96SNiklas Söderlund 
1474f00add96SNiklas Söderlund 	/* buffer queue */
1475f00add96SNiklas Söderlund 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1476f00add96SNiklas Söderlund 	q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
1477f00add96SNiklas Söderlund 	q->lock = &vin->lock;
1478f00add96SNiklas Söderlund 	q->drv_priv = vin;
1479f00add96SNiklas Söderlund 	q->buf_struct_size = sizeof(struct rvin_buffer);
1480f00add96SNiklas Söderlund 	q->ops = &rvin_qops;
1481f00add96SNiklas Söderlund 	q->mem_ops = &vb2_dma_contig_memops;
1482f00add96SNiklas Söderlund 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1483dc9aec79SNiklas Söderlund 	q->min_buffers_needed = 4;
148453ddcc68SHans Verkuil 	q->dev = vin->dev;
1485f00add96SNiklas Söderlund 
1486f00add96SNiklas Söderlund 	ret = vb2_queue_init(q);
1487f00add96SNiklas Söderlund 	if (ret < 0) {
1488f00add96SNiklas Söderlund 		vin_err(vin, "failed to initialize VB2 queue\n");
1489f00add96SNiklas Söderlund 		goto error;
1490f00add96SNiklas Söderlund 	}
1491f00add96SNiklas Söderlund 
1492f00add96SNiklas Söderlund 	/* irq */
1493f00add96SNiklas Söderlund 	ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED,
1494f00add96SNiklas Söderlund 			       KBUILD_MODNAME, vin);
1495f00add96SNiklas Söderlund 	if (ret) {
1496f00add96SNiklas Söderlund 		vin_err(vin, "failed to request irq\n");
1497f00add96SNiklas Söderlund 		goto error;
1498f00add96SNiklas Söderlund 	}
1499f00add96SNiklas Söderlund 
1500f00add96SNiklas Söderlund 	return 0;
1501f00add96SNiklas Söderlund error:
1502d6ad012eSNiklas Söderlund 	rvin_dma_unregister(vin);
1503f00add96SNiklas Söderlund 
1504f00add96SNiklas Söderlund 	return ret;
1505f00add96SNiklas Söderlund }
150690dedce9SNiklas Söderlund 
150790dedce9SNiklas Söderlund /* -----------------------------------------------------------------------------
150890dedce9SNiklas Söderlund  * Gen3 CHSEL manipulation
150990dedce9SNiklas Söderlund  */
151090dedce9SNiklas Söderlund 
151190dedce9SNiklas Söderlund /*
151290dedce9SNiklas Söderlund  * There is no need to have locking around changing the routing
151390dedce9SNiklas Söderlund  * as it's only possible to do so when no VIN in the group is
151490dedce9SNiklas Söderlund  * streaming so nothing can race with the VNMC register.
151590dedce9SNiklas Söderlund  */
151690dedce9SNiklas Söderlund int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
151790dedce9SNiklas Söderlund {
1518fb25ca37SJacopo Mondi 	const struct rvin_group_route *route;
1519fb25ca37SJacopo Mondi 	u32 ifmd = 0;
1520fb25ca37SJacopo Mondi 	u32 vnmc;
152190dedce9SNiklas Söderlund 	int ret;
152290dedce9SNiklas Söderlund 
1523334fe327SMauro Carvalho Chehab 	ret = pm_runtime_resume_and_get(vin->dev);
1524334fe327SMauro Carvalho Chehab 	if (ret < 0)
152590dedce9SNiklas Söderlund 		return ret;
152690dedce9SNiklas Söderlund 
152790dedce9SNiklas Söderlund 	/* Make register writes take effect immediately. */
152890dedce9SNiklas Söderlund 	vnmc = rvin_read(vin, VNMC_REG);
152990dedce9SNiklas Söderlund 	rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG);
153090dedce9SNiklas Söderlund 
1531fb25ca37SJacopo Mondi 	/*
1532fb25ca37SJacopo Mondi 	 * Set data expansion mode to "pad with 0s" by inspecting the routes
1533fb25ca37SJacopo Mondi 	 * table to find out which bit fields are available in the IFMD
1534fb25ca37SJacopo Mondi 	 * register. IFMD_DES1 controls data expansion mode for CSI20/21,
1535fb25ca37SJacopo Mondi 	 * IFMD_DES0 controls data expansion mode for CSI40/41.
1536fb25ca37SJacopo Mondi 	 */
15373e52419eSNiklas Söderlund 	for (route = vin->info->routes; route->chsel; route++) {
1538fb25ca37SJacopo Mondi 		if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21)
1539fb25ca37SJacopo Mondi 			ifmd |= VNCSI_IFMD_DES1;
1540fb25ca37SJacopo Mondi 		else
1541fb25ca37SJacopo Mondi 			ifmd |= VNCSI_IFMD_DES0;
154290dedce9SNiklas Söderlund 
1543fb25ca37SJacopo Mondi 		if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1))
1544fb25ca37SJacopo Mondi 			break;
1545fb25ca37SJacopo Mondi 	}
1546fb25ca37SJacopo Mondi 
1547fb25ca37SJacopo Mondi 	if (ifmd) {
1548fb25ca37SJacopo Mondi 		ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel);
154990dedce9SNiklas Söderlund 		rvin_write(vin, ifmd, VNCSI_IFMD_REG);
1550fb25ca37SJacopo Mondi 	}
155190dedce9SNiklas Söderlund 
155290dedce9SNiklas Söderlund 	vin_dbg(vin, "Set IFMD 0x%x\n", ifmd);
155390dedce9SNiklas Söderlund 
155443e36a22SNiklas Söderlund 	vin->chsel = chsel;
155543e36a22SNiklas Söderlund 
155690dedce9SNiklas Söderlund 	/* Restore VNMC. */
155790dedce9SNiklas Söderlund 	rvin_write(vin, vnmc, VNMC_REG);
155890dedce9SNiklas Söderlund 
155990dedce9SNiklas Söderlund 	pm_runtime_put(vin->dev);
156090dedce9SNiklas Söderlund 
15618d19d5d0SNiklas Söderlund 	return 0;
156290dedce9SNiklas Söderlund }
15635720c733SNiklas Söderlund 
15645720c733SNiklas Söderlund void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha)
15655720c733SNiklas Söderlund {
15661d99e68cSNiklas Söderlund 	unsigned long flags;
15671d99e68cSNiklas Söderlund 	u32 dmr;
15681d99e68cSNiklas Söderlund 
15691d99e68cSNiklas Söderlund 	spin_lock_irqsave(&vin->qlock, flags);
15701d99e68cSNiklas Söderlund 
15715720c733SNiklas Söderlund 	vin->alpha = alpha;
15721d99e68cSNiklas Söderlund 
15731d99e68cSNiklas Söderlund 	if (vin->state == STOPPED)
15741d99e68cSNiklas Söderlund 		goto out;
15751d99e68cSNiklas Söderlund 
15761d99e68cSNiklas Söderlund 	switch (vin->format.pixelformat) {
15771d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ARGB555:
15781d99e68cSNiklas Söderlund 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT;
15791d99e68cSNiklas Söderlund 		if (vin->alpha)
15801d99e68cSNiklas Söderlund 			dmr |= VNDMR_ABIT;
15811d99e68cSNiklas Söderlund 		break;
15821d99e68cSNiklas Söderlund 	case V4L2_PIX_FMT_ABGR32:
15831d99e68cSNiklas Söderlund 		dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK;
15841d99e68cSNiklas Söderlund 		dmr |= VNDMR_A8BIT(vin->alpha);
15851d99e68cSNiklas Söderlund 		break;
15861d99e68cSNiklas Söderlund 	default:
15871d99e68cSNiklas Söderlund 		goto out;
15881d99e68cSNiklas Söderlund 	}
15891d99e68cSNiklas Söderlund 
15901d99e68cSNiklas Söderlund 	rvin_write(vin, dmr,  VNDMR_REG);
15911d99e68cSNiklas Söderlund out:
15921d99e68cSNiklas Söderlund 	spin_unlock_irqrestore(&vin->qlock, flags);
15935720c733SNiklas Söderlund }
1594