xref: /linux/drivers/media/platform/ti/vpe/vip.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
1fc2873aaSDale Farnsworth // SPDX-License-Identifier: GPL-2.0
2fc2873aaSDale Farnsworth /*
3fc2873aaSDale Farnsworth  * TI VIP capture driver
4fc2873aaSDale Farnsworth  *
5fc2873aaSDale Farnsworth  * Copyright (C) 2025 Texas Instruments Incorporated -  http://www.ti.com/
6fc2873aaSDale Farnsworth  * David Griego, <dagriego@biglakesoftware.com>
7fc2873aaSDale Farnsworth  * Dale Farnsworth, <dale@farnsworth.org>
8fc2873aaSDale Farnsworth  * Yemike Abhilash Chandra, <y-abhilashchandra@ti.com>
9fc2873aaSDale Farnsworth  */
10fc2873aaSDale Farnsworth 
11fc2873aaSDale Farnsworth #include <linux/clk.h>
12fc2873aaSDale Farnsworth #include <linux/delay.h>
13fc2873aaSDale Farnsworth #include <linux/dma-mapping.h>
14fc2873aaSDale Farnsworth #include <linux/err.h>
15fc2873aaSDale Farnsworth #include <linux/interrupt.h>
16fc2873aaSDale Farnsworth #include <linux/module.h>
17fc2873aaSDale Farnsworth #include <linux/workqueue.h>
18fc2873aaSDale Farnsworth #include <linux/pm_runtime.h>
19fc2873aaSDale Farnsworth #include <linux/sched.h>
20fc2873aaSDale Farnsworth #include <linux/mfd/syscon.h>
21fc2873aaSDale Farnsworth #include <linux/regmap.h>
22fc2873aaSDale Farnsworth 
23fc2873aaSDale Farnsworth #include <linux/pinctrl/consumer.h>
24fc2873aaSDale Farnsworth #include <linux/of_device.h>
25fc2873aaSDale Farnsworth #include <linux/of_graph.h>
26fc2873aaSDale Farnsworth 
27fc2873aaSDale Farnsworth #include "vip.h"
28fc2873aaSDale Farnsworth 
29fc2873aaSDale Farnsworth #define VIP_MODULE_NAME "vip"
30fc2873aaSDale Farnsworth 
31fc2873aaSDale Farnsworth static int debug;
32fc2873aaSDale Farnsworth module_param(debug, int, 0644);
33fc2873aaSDale Farnsworth MODULE_PARM_DESC(debug, "debug level (0-8)");
34fc2873aaSDale Farnsworth 
35fc2873aaSDale Farnsworth /*
36fc2873aaSDale Farnsworth  * Minimum and maximum frame sizes
37fc2873aaSDale Farnsworth  */
38fc2873aaSDale Farnsworth #define MIN_W		128
39fc2873aaSDale Farnsworth #define MIN_H		128
40fc2873aaSDale Farnsworth #define MAX_W		2048
41fc2873aaSDale Farnsworth #define MAX_H		1536
42fc2873aaSDale Farnsworth 
43fc2873aaSDale Farnsworth /*
44fc2873aaSDale Farnsworth  * Required alignments
45fc2873aaSDale Farnsworth  */
46fc2873aaSDale Farnsworth #define S_ALIGN		0 /* multiple of 1 */
47fc2873aaSDale Farnsworth #define H_ALIGN		1 /* multiple of 2 */
48fc2873aaSDale Farnsworth #define W_ALIGN		1 /* multiple of 2 */
49fc2873aaSDale Farnsworth 
50fc2873aaSDale Farnsworth /*
51fc2873aaSDale Farnsworth  * Need a descriptor entry for each of up to 15 outputs,
52fc2873aaSDale Farnsworth  * and up to 2 control transfers.
53fc2873aaSDale Farnsworth  */
54fc2873aaSDale Farnsworth #define VIP_DESC_LIST_SIZE	(17 * sizeof(struct vpdma_dtd))
55fc2873aaSDale Farnsworth 
56fc2873aaSDale Farnsworth /*
57fc2873aaSDale Farnsworth  * port flag bits
58fc2873aaSDale Farnsworth  */
59fc2873aaSDale Farnsworth #define FLAG_INTERLACED	BIT(4)
60fc2873aaSDale Farnsworth #define FLAG_MULT_PORT		BIT(6)
61fc2873aaSDale Farnsworth #define FLAG_MULT_ANC		BIT(7)
62fc2873aaSDale Farnsworth 
63fc2873aaSDale Farnsworth #define VIP_VPDMA_FIFO_SIZE	2
64fc2873aaSDale Farnsworth #define VIP_DROPQ_SIZE		3
65fc2873aaSDale Farnsworth 
66fc2873aaSDale Farnsworth /*
67fc2873aaSDale Farnsworth  * Define indices into the srce_info tables
68fc2873aaSDale Farnsworth  */
69fc2873aaSDale Farnsworth 
70fc2873aaSDale Farnsworth #define VIP_SRCE_MULT_PORT	0
71fc2873aaSDale Farnsworth #define VIP_SRCE_MULT_ANC	1
72fc2873aaSDale Farnsworth #define VIP_SRCE_LUMA		2
73fc2873aaSDale Farnsworth #define VIP_SRCE_CHROMA	3
74fc2873aaSDale Farnsworth #define VIP_SRCE_RGB		4
75fc2873aaSDale Farnsworth 
76fc2873aaSDale Farnsworth #define reg_read(dev, offset) ioread32((dev)->base + (offset))
77fc2873aaSDale Farnsworth #define reg_write(dev, offset, val) iowrite32((val), (dev)->base + (offset))
78fc2873aaSDale Farnsworth 
79fc2873aaSDale Farnsworth #define GET_OFFSET_TOP(port, obj, reg)	\
80fc2873aaSDale Farnsworth 	((obj)->base - (port)->dev->base + (reg))
81fc2873aaSDale Farnsworth 
82fc2873aaSDale Farnsworth #define VIP_SET_MMR_ADB_HDR(port, hdr, regs, offset_a)	\
83fc2873aaSDale Farnsworth 	VPDMA_SET_MMR_ADB_HDR((port)->mmr_adb, vip_mmr_adb, hdr, regs, offset_a)
84fc2873aaSDale Farnsworth 
85fc2873aaSDale Farnsworth /*
86fc2873aaSDale Farnsworth  * These represent the module resets bit for slice 1
87fc2873aaSDale Farnsworth  * Upon detecting slice2 we simply left shift by 1
88fc2873aaSDale Farnsworth  */
89fc2873aaSDale Farnsworth #define VIP_DP_RST	BIT(16)
90fc2873aaSDale Farnsworth #define VIP_CSC_RST	BIT(20)
91fc2873aaSDale Farnsworth #define VIP_SC_RST	BIT(22)
92fc2873aaSDale Farnsworth 
93fc2873aaSDale Farnsworth #define VIP_PARSER_PORT(p)		(VIP_PARSER_PORTA_0 + ((p) * 0x8U))
94fc2873aaSDale Farnsworth #define VIP_PARSER_CROP_H_PORT(p) \
95fc2873aaSDale Farnsworth 		(VIP_PARSER_PORTA_EXTRA4 + ((p) * 0x10U))
96fc2873aaSDale Farnsworth #define VIP_PARSER_CROP_V_PORT(p) \
97fc2873aaSDale Farnsworth 		(VIP_PARSER_PORTA_EXTRA5 + ((p) * 0x10U))
98fc2873aaSDale Farnsworth #define VIP_PARSER_STOP_IMM_PORT(p)	(VIP_PARSER_PORTA_EXTRA6 + ((p) * 0x4U))
99fc2873aaSDale Farnsworth 
100fc2873aaSDale Farnsworth #define PARSER_IRQ_MASK (VIP_PORTA_OUTPUT_FIFO_YUV | \
101fc2873aaSDale Farnsworth 			 VIP_PORTB_OUTPUT_FIFO_YUV)
102fc2873aaSDale Farnsworth 
103fc2873aaSDale Farnsworth /*
104fc2873aaSDale Farnsworth  * The srce_info structure contains per-srce data.
105fc2873aaSDale Farnsworth  */
106fc2873aaSDale Farnsworth struct vip_srce_info {
107fc2873aaSDale Farnsworth 	u8	base_channel;	/* the VPDMA channel number */
108fc2873aaSDale Farnsworth 	u8	vb_index;	/* input frame f, f-1, f-2 index */
109fc2873aaSDale Farnsworth 	u8	vb_part;	/* identifies section of co-planar formats */
110fc2873aaSDale Farnsworth };
111fc2873aaSDale Farnsworth 
112fc2873aaSDale Farnsworth static struct vip_srce_info srce_info[5] = {
113fc2873aaSDale Farnsworth 	[VIP_SRCE_MULT_PORT] = {
114fc2873aaSDale Farnsworth 		.base_channel	= VIP1_CHAN_NUM_MULT_PORT_A_SRC0,
115fc2873aaSDale Farnsworth 		.vb_index	= 0,
116fc2873aaSDale Farnsworth 		.vb_part	= VIP_CHROMA,
117fc2873aaSDale Farnsworth 	},
118fc2873aaSDale Farnsworth 	[VIP_SRCE_MULT_ANC] = {
119fc2873aaSDale Farnsworth 		.base_channel	= VIP1_CHAN_NUM_MULT_ANC_A_SRC0,
120fc2873aaSDale Farnsworth 		.vb_index	= 0,
121fc2873aaSDale Farnsworth 		.vb_part	= VIP_LUMA,
122fc2873aaSDale Farnsworth 	},
123fc2873aaSDale Farnsworth 	[VIP_SRCE_LUMA] = {
124fc2873aaSDale Farnsworth 		.base_channel	= VIP1_CHAN_NUM_PORT_A_LUMA,
125fc2873aaSDale Farnsworth 		.vb_index	= 1,
126fc2873aaSDale Farnsworth 		.vb_part	= VIP_LUMA,
127fc2873aaSDale Farnsworth 	},
128fc2873aaSDale Farnsworth 	[VIP_SRCE_CHROMA] = {
129fc2873aaSDale Farnsworth 		.base_channel	= VIP1_CHAN_NUM_PORT_A_CHROMA,
130fc2873aaSDale Farnsworth 		.vb_index	= 1,
131fc2873aaSDale Farnsworth 		.vb_part	= VIP_CHROMA,
132fc2873aaSDale Farnsworth 	},
133fc2873aaSDale Farnsworth 	[VIP_SRCE_RGB] = {
134fc2873aaSDale Farnsworth 		.base_channel	= VIP1_CHAN_NUM_PORT_A_RGB,
135fc2873aaSDale Farnsworth 		.vb_part	= VIP_LUMA,
136fc2873aaSDale Farnsworth 	},
137fc2873aaSDale Farnsworth };
138fc2873aaSDale Farnsworth 
139fc2873aaSDale Farnsworth static struct vip_fmt vip_formats[VIP_MAX_ACTIVE_FMT] = {
140fc2873aaSDale Farnsworth 	{
141fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_NV12,
142fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
143fc2873aaSDale Farnsworth 		.coplanar	= 1,
144fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],
145fc2873aaSDale Farnsworth 				    &vpdma_yuv_fmts[VPDMA_DATA_FMT_C420],
146fc2873aaSDale Farnsworth 				  },
147fc2873aaSDale Farnsworth 	},
148fc2873aaSDale Farnsworth 	{
149fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_UYVY,
150fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
151fc2873aaSDale Farnsworth 		.coplanar	= 0,
152fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],
153fc2873aaSDale Farnsworth 				  },
154fc2873aaSDale Farnsworth 	},
155fc2873aaSDale Farnsworth 	{
156fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_YUYV,
157fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
158fc2873aaSDale Farnsworth 		.coplanar	= 0,
159fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422],
160fc2873aaSDale Farnsworth 				  },
161fc2873aaSDale Farnsworth 	},
162fc2873aaSDale Farnsworth 	{
163fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_VYUY,
164fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
165fc2873aaSDale Farnsworth 		.coplanar	= 0,
166fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CRY422],
167fc2873aaSDale Farnsworth 				  },
168fc2873aaSDale Farnsworth 	},
169fc2873aaSDale Farnsworth 	{
170fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_YVYU,
171fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
172fc2873aaSDale Farnsworth 		.coplanar	= 0,
173fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCR422],
174fc2873aaSDale Farnsworth 				  },
175fc2873aaSDale Farnsworth 	},
176fc2873aaSDale Farnsworth 	{
177fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_RGB24,
178fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
179fc2873aaSDale Farnsworth 		.coplanar	= 0,
180fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24],
181fc2873aaSDale Farnsworth 				  },
182fc2873aaSDale Farnsworth 	},
183fc2873aaSDale Farnsworth 	{
184fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_RGB32,
185fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
186fc2873aaSDale Farnsworth 		.coplanar	= 0,
187fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32],
188fc2873aaSDale Farnsworth 				  },
189fc2873aaSDale Farnsworth 	},
190fc2873aaSDale Farnsworth 	{
191fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_BGR24,
192fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
193fc2873aaSDale Farnsworth 		.coplanar	= 0,
194fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24],
195fc2873aaSDale Farnsworth 				  },
196fc2873aaSDale Farnsworth 	},
197fc2873aaSDale Farnsworth 	{
198fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_BGR32,
199fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
200fc2873aaSDale Farnsworth 		.coplanar	= 0,
201fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32],
202fc2873aaSDale Farnsworth 				  },
203fc2873aaSDale Farnsworth 	},
204fc2873aaSDale Farnsworth 	{
205fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_RGB24,
206fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_RGB888_1X24,
207fc2873aaSDale Farnsworth 		.coplanar	= 0,
208fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24],
209fc2873aaSDale Farnsworth 				  },
210fc2873aaSDale Farnsworth 	},
211fc2873aaSDale Farnsworth 	{
212fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_RGB32,
213fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_ARGB8888_1X32,
214fc2873aaSDale Farnsworth 		.coplanar	= 0,
215fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32],
216fc2873aaSDale Farnsworth 				  },
217fc2873aaSDale Farnsworth 	},
218fc2873aaSDale Farnsworth 	{
219fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_SBGGR8,
220fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
221fc2873aaSDale Farnsworth 		.coplanar	= 0,
222fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8],
223fc2873aaSDale Farnsworth 				  },
224fc2873aaSDale Farnsworth 	},
225fc2873aaSDale Farnsworth 	{
226fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_SGBRG8,
227fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
228fc2873aaSDale Farnsworth 		.coplanar	= 0,
229fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8],
230fc2873aaSDale Farnsworth 				  },
231fc2873aaSDale Farnsworth 	},
232fc2873aaSDale Farnsworth 	{
233fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_SGRBG8,
234fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
235fc2873aaSDale Farnsworth 		.coplanar	= 0,
236fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8],
237fc2873aaSDale Farnsworth 				  },
238fc2873aaSDale Farnsworth 	},
239fc2873aaSDale Farnsworth 	{
240fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_SRGGB8,
241fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
242fc2873aaSDale Farnsworth 		.coplanar	= 0,
243fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8],
244fc2873aaSDale Farnsworth 				  },
245fc2873aaSDale Farnsworth 	},
246fc2873aaSDale Farnsworth 	{
247fc2873aaSDale Farnsworth 		/* V4L2 currently only defines one 16 bit variant */
248fc2873aaSDale Farnsworth 		.fourcc		= V4L2_PIX_FMT_SBGGR16,
249fc2873aaSDale Farnsworth 		.code		= MEDIA_BUS_FMT_SBGGR16_1X16,
250fc2873aaSDale Farnsworth 		.coplanar	= 0,
251fc2873aaSDale Farnsworth 		.vpdma_fmt	= { &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW16],
252fc2873aaSDale Farnsworth 				  },
253fc2873aaSDale Farnsworth 	},
254fc2873aaSDale Farnsworth };
255fc2873aaSDale Farnsworth 
256fc2873aaSDale Farnsworth /*
257fc2873aaSDale Farnsworth  * DMA address/data block for the shadow registers
258fc2873aaSDale Farnsworth  */
259fc2873aaSDale Farnsworth struct vip_mmr_adb {
260fc2873aaSDale Farnsworth 	struct vpdma_adb_hdr	sc_hdr0;
261fc2873aaSDale Farnsworth 	u32			sc_regs0[7];
262fc2873aaSDale Farnsworth 	u32			sc_pad0[1];
263fc2873aaSDale Farnsworth 	struct vpdma_adb_hdr	sc_hdr8;
264fc2873aaSDale Farnsworth 	u32			sc_regs8[6];
265fc2873aaSDale Farnsworth 	u32			sc_pad8[2];
266fc2873aaSDale Farnsworth 	struct vpdma_adb_hdr	sc_hdr17;
267fc2873aaSDale Farnsworth 	u32			sc_regs17[9];
268fc2873aaSDale Farnsworth 	u32			sc_pad17[3];
269fc2873aaSDale Farnsworth 	struct vpdma_adb_hdr	csc_hdr;
270fc2873aaSDale Farnsworth 	u32			csc_regs[6];
271fc2873aaSDale Farnsworth 	u32			csc_pad[2];
272fc2873aaSDale Farnsworth };
273fc2873aaSDale Farnsworth 
274fc2873aaSDale Farnsworth /*
275fc2873aaSDale Farnsworth  * Function prototype declarations
276fc2873aaSDale Farnsworth  */
277fc2873aaSDale Farnsworth static int alloc_port(struct vip_dev *, int);
278fc2873aaSDale Farnsworth static void free_port(struct vip_port *);
279fc2873aaSDale Farnsworth static int vip_setup_parser(struct vip_port *port);
280fc2873aaSDale Farnsworth static int vip_setup_scaler(struct vip_stream *stream);
281fc2873aaSDale Farnsworth static void vip_enable_parser(struct vip_port *port, bool on);
282fc2873aaSDale Farnsworth static void vip_reset_parser(struct vip_port *port, bool on);
283fc2873aaSDale Farnsworth static void vip_parser_stop_imm(struct vip_port *port, bool on);
284fc2873aaSDale Farnsworth static void stop_dma(struct vip_stream *stream, bool clear_list);
285fc2873aaSDale Farnsworth static int vip_load_vpdma_list_fifo(struct vip_stream *stream);
286fc2873aaSDale Farnsworth static inline bool is_scaler_available(struct vip_port *port);
287fc2873aaSDale Farnsworth static inline bool allocate_scaler(struct vip_port *port);
288fc2873aaSDale Farnsworth static inline void free_scaler(struct vip_port *port);
289fc2873aaSDale Farnsworth static bool is_csc_available(struct vip_port *port);
290fc2873aaSDale Farnsworth static bool allocate_csc(struct vip_port *port,
291fc2873aaSDale Farnsworth 			 enum vip_csc_state csc_direction);
292fc2873aaSDale Farnsworth static void free_csc(struct vip_port *port);
293fc2873aaSDale Farnsworth 
294fc2873aaSDale Farnsworth /* initialize  v4l2_format_info member in vip_formats array */
vip_init_format_info(struct device * dev)295fc2873aaSDale Farnsworth static void vip_init_format_info(struct device *dev)
296fc2873aaSDale Farnsworth {
297fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
298fc2873aaSDale Farnsworth 	int i;
299fc2873aaSDale Farnsworth 
300fc2873aaSDale Farnsworth 	for (i = 0; i < ARRAY_SIZE(vip_formats); i++) {
301fc2873aaSDale Farnsworth 		fmt = &vip_formats[i];
302fc2873aaSDale Farnsworth 		fmt->finfo = v4l2_format_info(fmt->fourcc);
303fc2873aaSDale Farnsworth 	}
304fc2873aaSDale Farnsworth }
305fc2873aaSDale Farnsworth 
306fc2873aaSDale Farnsworth /*  Print Four-character-code (FOURCC) */
fourcc_to_str(u32 fmt)307fc2873aaSDale Farnsworth static char *fourcc_to_str(u32 fmt)
308fc2873aaSDale Farnsworth {
309fc2873aaSDale Farnsworth 	static char code[5];
310fc2873aaSDale Farnsworth 
311fc2873aaSDale Farnsworth 	code[0] = (unsigned char)(fmt & 0xff);
312fc2873aaSDale Farnsworth 	code[1] = (unsigned char)((fmt >> 8) & 0xff);
313fc2873aaSDale Farnsworth 	code[2] = (unsigned char)((fmt >> 16) & 0xff);
314fc2873aaSDale Farnsworth 	code[3] = (unsigned char)((fmt >> 24) & 0xff);
315fc2873aaSDale Farnsworth 	code[4] = '\0';
316fc2873aaSDale Farnsworth 
317fc2873aaSDale Farnsworth 	return code;
318fc2873aaSDale Farnsworth }
319fc2873aaSDale Farnsworth 
320fc2873aaSDale Farnsworth /*
321fc2873aaSDale Farnsworth  * Find our format description corresponding to the passed v4l2_format
322fc2873aaSDale Farnsworth  */
find_port_format_by_pix(struct vip_port * port,u32 pixelformat)323fc2873aaSDale Farnsworth static struct vip_fmt *find_port_format_by_pix(struct vip_port *port,
324fc2873aaSDale Farnsworth 					       u32 pixelformat)
325fc2873aaSDale Farnsworth {
326fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
327fc2873aaSDale Farnsworth 	unsigned int index;
328fc2873aaSDale Farnsworth 
329fc2873aaSDale Farnsworth 	for (index = 0; index < port->num_active_fmt; index++) {
330fc2873aaSDale Farnsworth 		fmt = port->active_fmt[index];
331fc2873aaSDale Farnsworth 		if (fmt->fourcc == pixelformat)
332fc2873aaSDale Farnsworth 			return fmt;
333fc2873aaSDale Farnsworth 	}
334fc2873aaSDale Farnsworth 
335fc2873aaSDale Farnsworth 	return NULL;
336fc2873aaSDale Farnsworth }
337fc2873aaSDale Farnsworth 
find_port_format_by_code(struct vip_port * port,u32 code)338fc2873aaSDale Farnsworth static struct vip_fmt *find_port_format_by_code(struct vip_port *port,
339fc2873aaSDale Farnsworth 						u32 code)
340fc2873aaSDale Farnsworth {
341fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
342fc2873aaSDale Farnsworth 	unsigned int index;
343fc2873aaSDale Farnsworth 
344fc2873aaSDale Farnsworth 	for (index = 0; index < port->num_active_fmt; index++) {
345fc2873aaSDale Farnsworth 		fmt = port->active_fmt[index];
346fc2873aaSDale Farnsworth 		if (fmt->code == code)
347fc2873aaSDale Farnsworth 			return fmt;
348fc2873aaSDale Farnsworth 	}
349fc2873aaSDale Farnsworth 
350fc2873aaSDale Farnsworth 	return NULL;
351fc2873aaSDale Farnsworth }
352fc2873aaSDale Farnsworth 
notifier_to_vip_port(struct v4l2_async_notifier * n)353fc2873aaSDale Farnsworth inline struct vip_port *notifier_to_vip_port(struct v4l2_async_notifier *n)
354fc2873aaSDale Farnsworth {
355fc2873aaSDale Farnsworth 	return container_of(n, struct vip_port, notifier);
356fc2873aaSDale Farnsworth }
357fc2873aaSDale Farnsworth 
vip_is_mbuscode_yuv(u32 code)358fc2873aaSDale Farnsworth static bool vip_is_mbuscode_yuv(u32 code)
359fc2873aaSDale Farnsworth {
360fc2873aaSDale Farnsworth 	return ((code & 0xff00) == 0x2000);
361fc2873aaSDale Farnsworth }
362fc2873aaSDale Farnsworth 
vip_is_mbuscode_rgb(u32 code)363fc2873aaSDale Farnsworth static bool vip_is_mbuscode_rgb(u32 code)
364fc2873aaSDale Farnsworth {
365fc2873aaSDale Farnsworth 	return ((code & 0xff00) == 0x1000);
366fc2873aaSDale Farnsworth }
367fc2873aaSDale Farnsworth 
vip_is_mbuscode_raw(u32 code)368fc2873aaSDale Farnsworth static bool vip_is_mbuscode_raw(u32 code)
369fc2873aaSDale Farnsworth {
370fc2873aaSDale Farnsworth 	return ((code & 0xff00) == 0x3000);
371fc2873aaSDale Farnsworth }
372fc2873aaSDale Farnsworth 
373fc2873aaSDale Farnsworth /*
374fc2873aaSDale Farnsworth  * This is not an accurate conversion but it is only used to
375fc2873aaSDale Farnsworth  * assess if color conversion is needed.
376fc2873aaSDale Farnsworth  */
vip_mbus_code_to_fourcc(u32 code)377fc2873aaSDale Farnsworth static u32 vip_mbus_code_to_fourcc(u32 code)
378fc2873aaSDale Farnsworth {
379fc2873aaSDale Farnsworth 	if (vip_is_mbuscode_rgb(code))
380fc2873aaSDale Farnsworth 		return V4L2_PIX_FMT_RGB24;
381fc2873aaSDale Farnsworth 
382fc2873aaSDale Farnsworth 	if (vip_is_mbuscode_yuv(code))
383fc2873aaSDale Farnsworth 		return V4L2_PIX_FMT_UYVY;
384fc2873aaSDale Farnsworth 
385fc2873aaSDale Farnsworth 	return V4L2_PIX_FMT_SBGGR8;
386fc2873aaSDale Farnsworth }
387fc2873aaSDale Farnsworth 
388fc2873aaSDale Farnsworth static enum vip_csc_state
vip_csc_direction(u32 src_code,const struct v4l2_format_info * dfinfo)389fc2873aaSDale Farnsworth vip_csc_direction(u32 src_code, const struct v4l2_format_info *dfinfo)
390fc2873aaSDale Farnsworth {
391fc2873aaSDale Farnsworth 	if (vip_is_mbuscode_yuv(src_code) && v4l2_is_format_rgb(dfinfo))
392fc2873aaSDale Farnsworth 		return VIP_CSC_Y2R;
393fc2873aaSDale Farnsworth 	else if (vip_is_mbuscode_rgb(src_code) && v4l2_is_format_yuv(dfinfo))
394fc2873aaSDale Farnsworth 		return VIP_CSC_R2Y;
395fc2873aaSDale Farnsworth 	else
396fc2873aaSDale Farnsworth 		return VIP_CSC_NA;
397fc2873aaSDale Farnsworth }
398fc2873aaSDale Farnsworth 
399fc2873aaSDale Farnsworth /*
400fc2873aaSDale Farnsworth  * Insert a masked field into a 32-bit field
401fc2873aaSDale Farnsworth  */
insert_field(u32 * valp,u32 field,u32 mask,int shift)402fc2873aaSDale Farnsworth static void insert_field(u32 *valp, u32 field, u32 mask, int shift)
403fc2873aaSDale Farnsworth {
404fc2873aaSDale Farnsworth 	u32 val = *valp;
405fc2873aaSDale Farnsworth 
406fc2873aaSDale Farnsworth 	val &= ~(mask << shift);
407fc2873aaSDale Farnsworth 	val |= (field & mask) << shift;
408fc2873aaSDale Farnsworth 	*valp = val;
409fc2873aaSDale Farnsworth }
410fc2873aaSDale Farnsworth 
411fc2873aaSDale Farnsworth /*
412fc2873aaSDale Farnsworth  * Set the headers for all of the address/data block structures.
413fc2873aaSDale Farnsworth  */
init_adb_hdrs(struct vip_port * port)414fc2873aaSDale Farnsworth static void init_adb_hdrs(struct vip_port *port)
415fc2873aaSDale Farnsworth {
416fc2873aaSDale Farnsworth 	VIP_SET_MMR_ADB_HDR(port, sc_hdr0, sc_regs0,
417fc2873aaSDale Farnsworth 			    GET_OFFSET_TOP(port, port->dev->sc, CFG_SC0));
418fc2873aaSDale Farnsworth 	VIP_SET_MMR_ADB_HDR(port, sc_hdr8, sc_regs8,
419fc2873aaSDale Farnsworth 			    GET_OFFSET_TOP(port, port->dev->sc, CFG_SC8));
420fc2873aaSDale Farnsworth 	VIP_SET_MMR_ADB_HDR(port, sc_hdr17, sc_regs17,
421fc2873aaSDale Farnsworth 			    GET_OFFSET_TOP(port, port->dev->sc, CFG_SC17));
422fc2873aaSDale Farnsworth 	VIP_SET_MMR_ADB_HDR(port, csc_hdr, csc_regs,
423fc2873aaSDale Farnsworth 			    GET_OFFSET_TOP(port, port->dev->csc, CSC_CSC00));
424fc2873aaSDale Farnsworth 
425fc2873aaSDale Farnsworth };
426fc2873aaSDale Farnsworth 
vip_module_toggle(struct vip_dev * dev,uint32_t module,bool on)427fc2873aaSDale Farnsworth static void vip_module_toggle(struct vip_dev *dev, uint32_t module, bool on)
428fc2873aaSDale Farnsworth {
429fc2873aaSDale Farnsworth 	u32 val = 0;
430fc2873aaSDale Farnsworth 
431fc2873aaSDale Farnsworth 	val = reg_read(dev, VIP_CLK_RESET);
432fc2873aaSDale Farnsworth 
433fc2873aaSDale Farnsworth 	if (dev->slice_id == VIP_SLICE2)
434fc2873aaSDale Farnsworth 		module <<= 1;
435fc2873aaSDale Farnsworth 
436fc2873aaSDale Farnsworth 	if (on)
437fc2873aaSDale Farnsworth 		val |= module;
438fc2873aaSDale Farnsworth 	else
439fc2873aaSDale Farnsworth 		val &= ~module;
440fc2873aaSDale Farnsworth 
441fc2873aaSDale Farnsworth 	reg_write(dev, VIP_CLK_RESET, val);
442fc2873aaSDale Farnsworth }
443fc2873aaSDale Farnsworth 
444fc2873aaSDale Farnsworth /*
445fc2873aaSDale Farnsworth  * Enable or disable the VIP clocks
446fc2873aaSDale Farnsworth  */
vip_set_clock_enable(struct vip_dev * dev,bool on)447fc2873aaSDale Farnsworth static void vip_set_clock_enable(struct vip_dev *dev, bool on)
448fc2873aaSDale Farnsworth {
449fc2873aaSDale Farnsworth 	u32 val = 0;
450fc2873aaSDale Farnsworth 
451fc2873aaSDale Farnsworth 	val = reg_read(dev, VIP_CLK_ENABLE);
452fc2873aaSDale Farnsworth 	if (on) {
453fc2873aaSDale Farnsworth 		val |= VIP_VPDMA_CLK_ENABLE;
454fc2873aaSDale Farnsworth 		if (dev->slice_id == VIP_SLICE1)
455fc2873aaSDale Farnsworth 			val |= VIP_VIP1_DATA_PATH_CLK_ENABLE;
456fc2873aaSDale Farnsworth 		else
457fc2873aaSDale Farnsworth 			val |= VIP_VIP2_DATA_PATH_CLK_ENABLE;
458fc2873aaSDale Farnsworth 	} else {
459fc2873aaSDale Farnsworth 		if (dev->slice_id == VIP_SLICE1)
460fc2873aaSDale Farnsworth 			val &= ~VIP_VIP1_DATA_PATH_CLK_ENABLE;
461fc2873aaSDale Farnsworth 		else
462fc2873aaSDale Farnsworth 			val &= ~VIP_VIP2_DATA_PATH_CLK_ENABLE;
463fc2873aaSDale Farnsworth 
464fc2873aaSDale Farnsworth 		/* Both VIP are disabled then shutdown VPDMA also */
465fc2873aaSDale Farnsworth 		if (!(val & (VIP_VIP1_DATA_PATH_CLK_ENABLE |
466fc2873aaSDale Farnsworth 			     VIP_VIP2_DATA_PATH_CLK_ENABLE)))
467fc2873aaSDale Farnsworth 			val = 0;
468fc2873aaSDale Farnsworth 	}
469fc2873aaSDale Farnsworth 
470fc2873aaSDale Farnsworth 	reg_write(dev, VIP_CLK_ENABLE, val);
471fc2873aaSDale Farnsworth }
472fc2873aaSDale Farnsworth 
473fc2873aaSDale Farnsworth /* This helper function is used to enable the clock early on to
474fc2873aaSDale Farnsworth  * enable vpdma firmware loading before the slice device are created
475fc2873aaSDale Farnsworth  */
vip_shared_set_clock_enable(struct vip_shared * shared,bool on)476fc2873aaSDale Farnsworth static void vip_shared_set_clock_enable(struct vip_shared *shared, bool on)
477fc2873aaSDale Farnsworth {
478fc2873aaSDale Farnsworth 	u32 val = 0;
479fc2873aaSDale Farnsworth 
480fc2873aaSDale Farnsworth 	val = VIP_VIP1_DATA_PATH_CLK_ENABLE | VIP_VPDMA_CLK_ENABLE;
481fc2873aaSDale Farnsworth 
482fc2873aaSDale Farnsworth 	reg_write(shared, VIP_CLK_ENABLE, val);
483fc2873aaSDale Farnsworth }
484fc2873aaSDale Farnsworth 
vip_top_reset(struct vip_dev * dev)485fc2873aaSDale Farnsworth static void vip_top_reset(struct vip_dev *dev)
486fc2873aaSDale Farnsworth {
487fc2873aaSDale Farnsworth 	u32 val = 0;
488fc2873aaSDale Farnsworth 
489fc2873aaSDale Farnsworth 	val = reg_read(dev, VIP_CLK_RESET);
490fc2873aaSDale Farnsworth 
491fc2873aaSDale Farnsworth 	if (dev->slice_id == VIP_SLICE1)
492fc2873aaSDale Farnsworth 		insert_field(&val, 1, VIP_DATA_PATH_CLK_RESET_MASK,
493fc2873aaSDale Farnsworth 			     VIP_VIP1_DATA_PATH_RESET_SHIFT);
494fc2873aaSDale Farnsworth 	else
495fc2873aaSDale Farnsworth 		insert_field(&val, 1, VIP_DATA_PATH_CLK_RESET_MASK,
496fc2873aaSDale Farnsworth 			     VIP_VIP2_DATA_PATH_RESET_SHIFT);
497fc2873aaSDale Farnsworth 
498fc2873aaSDale Farnsworth 	reg_write(dev, VIP_CLK_RESET, val);
499fc2873aaSDale Farnsworth 
500fc2873aaSDale Farnsworth 	usleep_range(200, 250);
501fc2873aaSDale Farnsworth 
502fc2873aaSDale Farnsworth 	val = reg_read(dev, VIP_CLK_RESET);
503fc2873aaSDale Farnsworth 
504fc2873aaSDale Farnsworth 	if (dev->slice_id == VIP_SLICE1)
505fc2873aaSDale Farnsworth 		insert_field(&val, 0, VIP_DATA_PATH_CLK_RESET_MASK,
506fc2873aaSDale Farnsworth 			     VIP_VIP1_DATA_PATH_RESET_SHIFT);
507fc2873aaSDale Farnsworth 	else
508fc2873aaSDale Farnsworth 		insert_field(&val, 0, VIP_DATA_PATH_CLK_RESET_MASK,
509fc2873aaSDale Farnsworth 			     VIP_VIP2_DATA_PATH_RESET_SHIFT);
510fc2873aaSDale Farnsworth 	reg_write(dev, VIP_CLK_RESET, val);
511fc2873aaSDale Farnsworth }
512fc2873aaSDale Farnsworth 
vip_top_vpdma_reset(struct vip_shared * shared)513fc2873aaSDale Farnsworth static void vip_top_vpdma_reset(struct vip_shared *shared)
514fc2873aaSDale Farnsworth {
515fc2873aaSDale Farnsworth 	u32 val;
516fc2873aaSDale Farnsworth 
517fc2873aaSDale Farnsworth 	val = reg_read(shared, VIP_CLK_RESET);
518fc2873aaSDale Farnsworth 	insert_field(&val, 1, VIP_VPDMA_CLK_RESET_MASK,
519fc2873aaSDale Farnsworth 		     VIP_VPDMA_CLK_RESET_SHIFT);
520fc2873aaSDale Farnsworth 	reg_write(shared, VIP_CLK_RESET, val);
521fc2873aaSDale Farnsworth 
522fc2873aaSDale Farnsworth 	usleep_range(200, 250);
523fc2873aaSDale Farnsworth 
524fc2873aaSDale Farnsworth 	val = reg_read(shared, VIP_CLK_RESET);
525fc2873aaSDale Farnsworth 	insert_field(&val, 0, VIP_VPDMA_CLK_RESET_MASK,
526fc2873aaSDale Farnsworth 		     VIP_VPDMA_CLK_RESET_SHIFT);
527fc2873aaSDale Farnsworth 	reg_write(shared, VIP_CLK_RESET, val);
528fc2873aaSDale Farnsworth }
529fc2873aaSDale Farnsworth 
vip_set_pclk_invert(struct vip_port * port)530fc2873aaSDale Farnsworth static void vip_set_pclk_invert(struct vip_port *port)
531fc2873aaSDale Farnsworth {
532fc2873aaSDale Farnsworth 	struct vip_ctrl_module *ctrl = port->dev->syscon;
533fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
534fc2873aaSDale Farnsworth 	u32 index;
535fc2873aaSDale Farnsworth 	/*
536fc2873aaSDale Farnsworth 	 * When the VIP parser is configured to so that the pixel clock
537fc2873aaSDale Farnsworth 	 * is to be sampled at falling edge, the pixel clock needs to be
538fc2873aaSDale Farnsworth 	 * inverted before it is given to the VIP module. This is done
539fc2873aaSDale Farnsworth 	 * by setting a bit in the CTRL_CORE_SMA_SW1 register.
540fc2873aaSDale Farnsworth 	 */
541fc2873aaSDale Farnsworth 
542fc2873aaSDale Farnsworth 	index = 2 * port->dev->slice_id + port->port_id;
543fc2873aaSDale Farnsworth 
544fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: slice%d:port%d -> index: %d\n", __func__,
545fc2873aaSDale Farnsworth 		 port->dev->slice_id, port->port_id, index);
546fc2873aaSDale Farnsworth 
547fc2873aaSDale Farnsworth 	if (ctrl->syscon_pol)
548fc2873aaSDale Farnsworth 		regmap_update_bits(ctrl->syscon_pol,
549fc2873aaSDale Farnsworth 				   ctrl->syscon_offset,
550fc2873aaSDale Farnsworth 				   ctrl->syscon_bit_field[index],
551fc2873aaSDale Farnsworth 				   ctrl->syscon_bit_field[index]);
552fc2873aaSDale Farnsworth }
553fc2873aaSDale Farnsworth 
vip_set_data_interface(struct vip_port * port,enum data_interface_modes mode)554fc2873aaSDale Farnsworth static void vip_set_data_interface(struct vip_port *port,
555fc2873aaSDale Farnsworth 				   enum data_interface_modes mode)
556fc2873aaSDale Farnsworth {
557fc2873aaSDale Farnsworth 	u32 val = 0;
558fc2873aaSDale Farnsworth 
559fc2873aaSDale Farnsworth 	insert_field(&val, mode, VIP_DATA_INTERFACE_MODE_MASK,
560fc2873aaSDale Farnsworth 		     VIP_DATA_INTERFACE_MODE_SHFT);
561fc2873aaSDale Farnsworth 
562fc2873aaSDale Farnsworth 	reg_write(port->dev->parser, VIP_PARSER_MAIN_CFG, val);
563fc2873aaSDale Farnsworth }
564fc2873aaSDale Farnsworth 
vip_set_slice_path(struct vip_dev * dev,enum data_path_select data_path,u32 path_val)565fc2873aaSDale Farnsworth static void vip_set_slice_path(struct vip_dev *dev,
566fc2873aaSDale Farnsworth 			       enum data_path_select data_path, u32 path_val)
567fc2873aaSDale Farnsworth {
568fc2873aaSDale Farnsworth 	u32 val = 0;
569fc2873aaSDale Farnsworth 	int data_path_reg;
570fc2873aaSDale Farnsworth 
571fc2873aaSDale Farnsworth 	data_path_reg = VIP_VIP1_DATA_PATH_SELECT + 4 * dev->slice_id;
572fc2873aaSDale Farnsworth 
573fc2873aaSDale Farnsworth 	switch (data_path) {
574fc2873aaSDale Farnsworth 	case ALL_FIELDS_DATA_SELECT:
575fc2873aaSDale Farnsworth 		val |= path_val;
576fc2873aaSDale Farnsworth 		break;
577fc2873aaSDale Farnsworth 	case VIP_CSC_SRC_DATA_SELECT:
578fc2873aaSDale Farnsworth 		insert_field(&val, path_val, VIP_CSC_SRC_SELECT_MASK,
579fc2873aaSDale Farnsworth 			     VIP_CSC_SRC_SELECT_SHFT);
580fc2873aaSDale Farnsworth 		break;
581fc2873aaSDale Farnsworth 	case VIP_SC_SRC_DATA_SELECT:
582fc2873aaSDale Farnsworth 		insert_field(&val, path_val, VIP_SC_SRC_SELECT_MASK,
583fc2873aaSDale Farnsworth 			     VIP_SC_SRC_SELECT_SHFT);
584fc2873aaSDale Farnsworth 		break;
585fc2873aaSDale Farnsworth 	case VIP_RGB_SRC_DATA_SELECT:
586fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_RGB_SRC_SELECT : 0;
587fc2873aaSDale Farnsworth 		break;
588fc2873aaSDale Farnsworth 	case VIP_RGB_OUT_LO_DATA_SELECT:
589fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_RGB_OUT_LO_SRC_SELECT : 0;
590fc2873aaSDale Farnsworth 		break;
591fc2873aaSDale Farnsworth 	case VIP_RGB_OUT_HI_DATA_SELECT:
592fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_RGB_OUT_HI_SRC_SELECT : 0;
593fc2873aaSDale Farnsworth 		break;
594fc2873aaSDale Farnsworth 	case VIP_CHR_DS_1_SRC_DATA_SELECT:
595fc2873aaSDale Farnsworth 		insert_field(&val, path_val, VIP_DS1_SRC_SELECT_MASK,
596fc2873aaSDale Farnsworth 			     VIP_DS1_SRC_SELECT_SHFT);
597fc2873aaSDale Farnsworth 		break;
598fc2873aaSDale Farnsworth 	case VIP_CHR_DS_2_SRC_DATA_SELECT:
599fc2873aaSDale Farnsworth 		insert_field(&val, path_val, VIP_DS2_SRC_SELECT_MASK,
600fc2873aaSDale Farnsworth 			     VIP_DS2_SRC_SELECT_SHFT);
601fc2873aaSDale Farnsworth 		break;
602fc2873aaSDale Farnsworth 	case VIP_MULTI_CHANNEL_DATA_SELECT:
603fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_MULTI_CHANNEL_SELECT : 0;
604fc2873aaSDale Farnsworth 		break;
605fc2873aaSDale Farnsworth 	case VIP_CHR_DS_1_DATA_BYPASS:
606fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_DS1_BYPASS : 0;
607fc2873aaSDale Farnsworth 		break;
608fc2873aaSDale Farnsworth 	case VIP_CHR_DS_2_DATA_BYPASS:
609fc2873aaSDale Farnsworth 		val |= (path_val) ? VIP_DS2_BYPASS : 0;
610fc2873aaSDale Farnsworth 		break;
611fc2873aaSDale Farnsworth 	default:
612fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "%s: data_path 0x%x is not valid\n",
613fc2873aaSDale Farnsworth 			 __func__, data_path);
614fc2873aaSDale Farnsworth 		return;
615fc2873aaSDale Farnsworth 	}
616fc2873aaSDale Farnsworth 	insert_field(&val, data_path, VIP_DATAPATH_SELECT_MASK,
617fc2873aaSDale Farnsworth 		     VIP_DATAPATH_SELECT_SHFT);
618fc2873aaSDale Farnsworth 	reg_write(dev, data_path_reg, val);
619fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: DATA_PATH_SELECT(%08X): %08X\n", __func__,
620fc2873aaSDale Farnsworth 		 data_path_reg, reg_read(dev, data_path_reg));
621fc2873aaSDale Farnsworth }
622fc2873aaSDale Farnsworth 
623fc2873aaSDale Farnsworth /*
624fc2873aaSDale Farnsworth  * Return the vip_stream structure for a given struct file
625fc2873aaSDale Farnsworth  */
file2stream(struct file * file)626fc2873aaSDale Farnsworth static inline struct vip_stream *file2stream(struct file *file)
627fc2873aaSDale Farnsworth {
628fc2873aaSDale Farnsworth 	return video_drvdata(file);
629fc2873aaSDale Farnsworth }
630fc2873aaSDale Farnsworth 
631fc2873aaSDale Farnsworth /*
632fc2873aaSDale Farnsworth  * Append a destination descriptor to the current descriptor list,
633fc2873aaSDale Farnsworth  * setting up dma to the given srce.
634fc2873aaSDale Farnsworth  */
add_out_dtd(struct vip_stream * stream,int srce_type)635fc2873aaSDale Farnsworth static int add_out_dtd(struct vip_stream *stream, int srce_type)
636fc2873aaSDale Farnsworth {
637fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
638fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
639fc2873aaSDale Farnsworth 	struct vip_srce_info *sinfo = &srce_info[srce_type];
640fc2873aaSDale Farnsworth 	struct v4l2_rect *c_rect = &port->c_rect;
641fc2873aaSDale Farnsworth 	struct vip_fmt *fmt = port->fmt;
642fc2873aaSDale Farnsworth 	int channel, plane = 0;
643fc2873aaSDale Farnsworth 	int max_width, max_height;
644fc2873aaSDale Farnsworth 	dma_addr_t dma_addr = 0;
645fc2873aaSDale Farnsworth 	u32 flags;
646fc2873aaSDale Farnsworth 	u32 width = stream->width;
647fc2873aaSDale Farnsworth 
648fc2873aaSDale Farnsworth 	channel = sinfo->base_channel;
649fc2873aaSDale Farnsworth 
650fc2873aaSDale Farnsworth 	switch (srce_type) {
651fc2873aaSDale Farnsworth 	case VIP_SRCE_MULT_PORT:
652fc2873aaSDale Farnsworth 	case VIP_SRCE_MULT_ANC:
653fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTB)
654fc2873aaSDale Farnsworth 			channel += VIP_CHAN_MULT_PORTB_OFFSET;
655fc2873aaSDale Farnsworth 		channel += stream->stream_id;
656fc2873aaSDale Farnsworth 		flags = 0;
657fc2873aaSDale Farnsworth 		break;
658fc2873aaSDale Farnsworth 	case VIP_SRCE_CHROMA:
659fc2873aaSDale Farnsworth 		plane = 1;
660fc2873aaSDale Farnsworth 		fallthrough;
661fc2873aaSDale Farnsworth 	case VIP_SRCE_LUMA:
662fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTB) {
663fc2873aaSDale Farnsworth 			if (port->scaler && !port->fmt->coplanar)
664fc2873aaSDale Farnsworth 				/*
665fc2873aaSDale Farnsworth 				 * In this case Port A Chroma channel
666fc2873aaSDale Farnsworth 				 * is used to carry Port B scaled YUV422
667fc2873aaSDale Farnsworth 				 */
668fc2873aaSDale Farnsworth 				channel += 1;
669fc2873aaSDale Farnsworth 			else
670fc2873aaSDale Farnsworth 				channel += VIP_CHAN_YUV_PORTB_OFFSET;
671fc2873aaSDale Farnsworth 		}
672fc2873aaSDale Farnsworth 		flags = port->flags;
673fc2873aaSDale Farnsworth 		break;
674fc2873aaSDale Farnsworth 	case VIP_SRCE_RGB:
675fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTB ||
676fc2873aaSDale Farnsworth 		    (port->port_id == VIP_PORTA &&
677fc2873aaSDale Farnsworth 		     port->csc == VIP_CSC_NA &&
678fc2873aaSDale Farnsworth 		     v4l2_is_format_rgb(port->fmt->finfo)))
679fc2873aaSDale Farnsworth 			/*
680fc2873aaSDale Farnsworth 			 * RGB sensor only connect to Y_LO
681fc2873aaSDale Farnsworth 			 * channel i.e. port B channel.
682fc2873aaSDale Farnsworth 			 */
683fc2873aaSDale Farnsworth 			channel += VIP_CHAN_RGB_PORTB_OFFSET;
684fc2873aaSDale Farnsworth 		flags = port->flags;
685fc2873aaSDale Farnsworth 		break;
686fc2873aaSDale Farnsworth 	default:
687fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "%s: srce_type 0x%x is not valid\n",
688fc2873aaSDale Farnsworth 			 __func__, srce_type);
689fc2873aaSDale Farnsworth 		return -1;
690fc2873aaSDale Farnsworth 	}
691fc2873aaSDale Farnsworth 
692fc2873aaSDale Farnsworth 	if (dev->slice_id == VIP_SLICE2)
693fc2873aaSDale Farnsworth 		channel += VIP_CHAN_VIP2_OFFSET;
694fc2873aaSDale Farnsworth 
695fc2873aaSDale Farnsworth 	if (port->fmt->vpdma_fmt[0] == &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8]) {
696fc2873aaSDale Farnsworth 		/*
697fc2873aaSDale Farnsworth 		 * Special case since we are faking a YUV422 16bit format
698fc2873aaSDale Farnsworth 		 * to have the vpdma perform the needed byte swap
699fc2873aaSDale Farnsworth 		 * we need to adjust the pixel width accordingly
700fc2873aaSDale Farnsworth 		 * otherwise the parser will attempt to collect more pixels
701fc2873aaSDale Farnsworth 		 * then available and the vpdma transfer will exceed the
702fc2873aaSDale Farnsworth 		 * allocated frame buffer.
703fc2873aaSDale Farnsworth 		 */
704fc2873aaSDale Farnsworth 		width >>= 1;
705fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: 8 bit raw detected, adjusting width to %d\n",
706fc2873aaSDale Farnsworth 			 __func__, width);
707fc2873aaSDale Farnsworth 	}
708fc2873aaSDale Farnsworth 
709fc2873aaSDale Farnsworth 	/*
710fc2873aaSDale Farnsworth 	 * Use VPDMA_MAX_SIZE1 or VPDMA_MAX_SIZE2 register for slice0/1
711fc2873aaSDale Farnsworth 	 */
712fc2873aaSDale Farnsworth 
713fc2873aaSDale Farnsworth 	if (dev->slice_id == VIP_SLICE1) {
714fc2873aaSDale Farnsworth 		vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE1,
715fc2873aaSDale Farnsworth 				   width, stream->height);
716fc2873aaSDale Farnsworth 
717fc2873aaSDale Farnsworth 		max_width = MAX_OUT_WIDTH_REG1;
718fc2873aaSDale Farnsworth 		max_height = MAX_OUT_HEIGHT_REG1;
719fc2873aaSDale Farnsworth 	} else {
720fc2873aaSDale Farnsworth 		vpdma_set_max_size(dev->shared->vpdma, VPDMA_MAX_SIZE2,
721fc2873aaSDale Farnsworth 				   width, stream->height);
722fc2873aaSDale Farnsworth 
723fc2873aaSDale Farnsworth 		max_width = MAX_OUT_WIDTH_REG2;
724fc2873aaSDale Farnsworth 		max_height = MAX_OUT_HEIGHT_REG2;
725fc2873aaSDale Farnsworth 	}
726fc2873aaSDale Farnsworth 
727fc2873aaSDale Farnsworth 	/*
728fc2873aaSDale Farnsworth 	 * Mark this channel to be cleared while cleaning up resources
729fc2873aaSDale Farnsworth 	 * This will make sure that an abort descriptor for this channel
730fc2873aaSDale Farnsworth 	 * would be submitted to VPDMA causing any ongoing  transaction to be
731fc2873aaSDale Farnsworth 	 * aborted and cleanup the VPDMA FSM for this channel
732fc2873aaSDale Farnsworth 	 */
733fc2873aaSDale Farnsworth 	stream->vpdma_channels[channel] = 1;
734fc2873aaSDale Farnsworth 
735fc2873aaSDale Farnsworth 	vpdma_rawchan_add_out_dtd(&stream->desc_list, c_rect->width,
736fc2873aaSDale Farnsworth 				  stream->bytesperline, c_rect,
737fc2873aaSDale Farnsworth 				  fmt->vpdma_fmt[plane], dma_addr,
738fc2873aaSDale Farnsworth 				  max_width, max_height, channel, flags);
739fc2873aaSDale Farnsworth 	return 0;
740fc2873aaSDale Farnsworth }
741fc2873aaSDale Farnsworth 
742fc2873aaSDale Farnsworth /*
743fc2873aaSDale Farnsworth  * add_stream_dtds - prepares and starts DMA for pending transfers
744fc2873aaSDale Farnsworth  */
add_stream_dtds(struct vip_stream * stream)745fc2873aaSDale Farnsworth static void add_stream_dtds(struct vip_stream *stream)
746fc2873aaSDale Farnsworth {
747fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
748fc2873aaSDale Farnsworth 	int srce_type;
749fc2873aaSDale Farnsworth 
750fc2873aaSDale Farnsworth 	if (port->flags & FLAG_MULT_PORT)
751fc2873aaSDale Farnsworth 		srce_type = VIP_SRCE_MULT_PORT;
752fc2873aaSDale Farnsworth 	else if (port->flags & FLAG_MULT_ANC)
753fc2873aaSDale Farnsworth 		srce_type = VIP_SRCE_MULT_ANC;
754fc2873aaSDale Farnsworth 	else if (v4l2_is_format_rgb(port->fmt->finfo))
755fc2873aaSDale Farnsworth 		srce_type = VIP_SRCE_RGB;
756fc2873aaSDale Farnsworth 	else
757fc2873aaSDale Farnsworth 		srce_type = VIP_SRCE_LUMA;
758fc2873aaSDale Farnsworth 
759fc2873aaSDale Farnsworth 	add_out_dtd(stream, srce_type);
760fc2873aaSDale Farnsworth 
761fc2873aaSDale Farnsworth 	if (srce_type == VIP_SRCE_LUMA && port->fmt->coplanar)
762fc2873aaSDale Farnsworth 		add_out_dtd(stream, VIP_SRCE_CHROMA);
763fc2873aaSDale Farnsworth }
764fc2873aaSDale Farnsworth 
enable_irqs(struct vip_dev * dev,int irq_num,int list_num)765fc2873aaSDale Farnsworth static void enable_irqs(struct vip_dev *dev, int irq_num, int list_num)
766fc2873aaSDale Farnsworth {
767fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
768fc2873aaSDale Farnsworth 	u32 reg_addr = VIP_INT0_ENABLE0_SET +
769fc2873aaSDale Farnsworth 			VIP_INTC_INTX_OFFSET * irq_num;
770fc2873aaSDale Farnsworth 	u32 irq_val = (1 << (list_num * 2)) |
771fc2873aaSDale Farnsworth 		      (VIP_VIP1_PARSER_INT << (irq_num * 1));
772fc2873aaSDale Farnsworth 
773fc2873aaSDale Farnsworth 	/* Enable Parser Interrupt */
774fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_MASK, (u32)~PARSER_IRQ_MASK);
775fc2873aaSDale Farnsworth 
776fc2873aaSDale Farnsworth 	reg_write(dev->shared, reg_addr, irq_val);
777fc2873aaSDale Farnsworth 
778fc2873aaSDale Farnsworth 	vpdma_enable_list_complete_irq(dev->shared->vpdma,
779fc2873aaSDale Farnsworth 				       irq_num, list_num, true);
780fc2873aaSDale Farnsworth }
781fc2873aaSDale Farnsworth 
disable_irqs(struct vip_dev * dev,int irq_num,int list_num)782fc2873aaSDale Farnsworth static void disable_irqs(struct vip_dev *dev, int irq_num, int list_num)
783fc2873aaSDale Farnsworth {
784fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
785fc2873aaSDale Farnsworth 	u32 reg_addr = VIP_INT0_ENABLE0_CLR +
786fc2873aaSDale Farnsworth 			VIP_INTC_INTX_OFFSET * irq_num;
787fc2873aaSDale Farnsworth 	u32 irq_val = (1 << (list_num * 2)) |
788fc2873aaSDale Farnsworth 		      (VIP_VIP1_PARSER_INT << (irq_num * 1));
789fc2873aaSDale Farnsworth 
790fc2873aaSDale Farnsworth 	/* Disable all Parser Interrupt */
791fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_MASK, 0xffffffff);
792fc2873aaSDale Farnsworth 
793fc2873aaSDale Farnsworth 	reg_write(dev->shared, reg_addr, irq_val);
794fc2873aaSDale Farnsworth 
795fc2873aaSDale Farnsworth 	vpdma_enable_list_complete_irq(dev->shared->vpdma,
796fc2873aaSDale Farnsworth 				       irq_num, list_num, false);
797fc2873aaSDale Farnsworth }
798fc2873aaSDale Farnsworth 
clear_irqs(struct vip_dev * dev,int irq_num,int list_num)799fc2873aaSDale Farnsworth static void clear_irqs(struct vip_dev *dev, int irq_num, int list_num)
800fc2873aaSDale Farnsworth {
801fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
802fc2873aaSDale Farnsworth 	u32 reg_addr = VIP_INT0_STATUS0_CLR +
803fc2873aaSDale Farnsworth 			VIP_INTC_INTX_OFFSET * irq_num;
804fc2873aaSDale Farnsworth 	u32 irq_val = (1 << (list_num * 2)) |
805fc2873aaSDale Farnsworth 		      (VIP_VIP1_PARSER_INT << (irq_num * 1));
806fc2873aaSDale Farnsworth 
807fc2873aaSDale Farnsworth 	/* Clear all Parser Interrupt */
808fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_CLR, 0xffffffff);
809fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_CLR, 0x0);
810fc2873aaSDale Farnsworth 
811fc2873aaSDale Farnsworth 	reg_write(dev->shared, reg_addr, irq_val);
812fc2873aaSDale Farnsworth 
813fc2873aaSDale Farnsworth 	vpdma_clear_list_stat(dev->shared->vpdma, irq_num, dev->slice_id);
814fc2873aaSDale Farnsworth }
815fc2873aaSDale Farnsworth 
populate_desc_list(struct vip_stream * stream)816fc2873aaSDale Farnsworth static void populate_desc_list(struct vip_stream *stream)
817fc2873aaSDale Farnsworth {
818fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
819fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
820fc2873aaSDale Farnsworth 
821fc2873aaSDale Farnsworth 	stream->desc_next = stream->desc_list.buf.addr;
822fc2873aaSDale Farnsworth 	add_stream_dtds(stream);
823fc2873aaSDale Farnsworth 
824fc2873aaSDale Farnsworth 	vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
825fc2873aaSDale Farnsworth }
826fc2873aaSDale Farnsworth 
827fc2873aaSDale Farnsworth /*
828fc2873aaSDale Farnsworth  * start_dma - adds descriptors to the dma list and submits them.
829fc2873aaSDale Farnsworth  * Should be called after a new vb is queued and on a vpdma list
830fc2873aaSDale Farnsworth  * completion interrupt.
831fc2873aaSDale Farnsworth  */
start_dma(struct vip_stream * stream,struct vip_buffer * buf)832fc2873aaSDale Farnsworth static void start_dma(struct vip_stream *stream, struct vip_buffer *buf)
833fc2873aaSDale Farnsworth {
834fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
835fc2873aaSDale Farnsworth 	struct vpdma_data *vpdma = dev->shared->vpdma;
836fc2873aaSDale Farnsworth 	int list_num = stream->list_num;
837fc2873aaSDale Farnsworth 	dma_addr_t dma_addr;
838fc2873aaSDale Farnsworth 	int drop_data;
839fc2873aaSDale Farnsworth 
840fc2873aaSDale Farnsworth 	if (vpdma_list_busy(vpdma, list_num)) {
841fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "vpdma list busy, cannot post\n");
842fc2873aaSDale Farnsworth 		return;				/* nothing to do */
843fc2873aaSDale Farnsworth 	}
844fc2873aaSDale Farnsworth 
845fc2873aaSDale Farnsworth 	if (buf) {
846fc2873aaSDale Farnsworth 		dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
847fc2873aaSDale Farnsworth 		drop_data = 0;
848fc2873aaSDale Farnsworth 		v4l2_dbg(4, debug, &dev->v4l2_dev, "%s: vb2 buf idx:%d, dma_addr:%pad\n",
849fc2873aaSDale Farnsworth 			 __func__, buf->vb.vb2_buf.index, &dma_addr);
850fc2873aaSDale Farnsworth 	} else {
851fc2873aaSDale Farnsworth 		dma_addr = 0;
852fc2873aaSDale Farnsworth 		drop_data = 1;
853fc2873aaSDale Farnsworth 		v4l2_dbg(4, debug, &dev->v4l2_dev, "%s: dropped\n", __func__);
854fc2873aaSDale Farnsworth 	}
855fc2873aaSDale Farnsworth 
856fc2873aaSDale Farnsworth 	vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
857fc2873aaSDale Farnsworth 			      dma_addr, stream->write_desc, drop_data, 0);
858fc2873aaSDale Farnsworth 
859fc2873aaSDale Farnsworth 	if (stream->port->fmt->coplanar) {
860fc2873aaSDale Farnsworth 		dma_addr += stream->bytesperline * stream->height;
861fc2873aaSDale Farnsworth 		vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
862fc2873aaSDale Farnsworth 				      dma_addr, stream->write_desc + 1,
863fc2873aaSDale Farnsworth 				      drop_data, 1);
864fc2873aaSDale Farnsworth 	}
865fc2873aaSDale Farnsworth 
866fc2873aaSDale Farnsworth 	vpdma_submit_descs(dev->shared->vpdma,
867fc2873aaSDale Farnsworth 			   &stream->desc_list, stream->list_num);
868fc2873aaSDale Farnsworth }
869fc2873aaSDale Farnsworth 
vip_schedule_next_buffer(struct vip_stream * stream)870fc2873aaSDale Farnsworth static void vip_schedule_next_buffer(struct vip_stream *stream)
871fc2873aaSDale Farnsworth {
872fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
873fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
874fc2873aaSDale Farnsworth 	unsigned long flags;
875fc2873aaSDale Farnsworth 
876fc2873aaSDale Farnsworth 	spin_lock_irqsave(&dev->slock, flags);
877fc2873aaSDale Farnsworth 	if (list_empty(&stream->vidq)) {
878fc2873aaSDale Farnsworth 		v4l2_dbg(4, debug, &dev->v4l2_dev, "Dropping frame\n");
879fc2873aaSDale Farnsworth 		if (list_empty(&stream->dropq)) {
880fc2873aaSDale Farnsworth 			v4l2_err(&dev->v4l2_dev, "No dropq buffer left!");
881fc2873aaSDale Farnsworth 			spin_unlock_irqrestore(&dev->slock, flags);
882fc2873aaSDale Farnsworth 			return;
883fc2873aaSDale Farnsworth 		}
884fc2873aaSDale Farnsworth 		buf = list_entry(stream->dropq.next,
885fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
886fc2873aaSDale Farnsworth 
887fc2873aaSDale Farnsworth 		buf->drop = true;
888fc2873aaSDale Farnsworth 		list_move_tail(&buf->list, &stream->post_bufs);
889fc2873aaSDale Farnsworth 		buf = NULL;
890fc2873aaSDale Farnsworth 	} else {
891fc2873aaSDale Farnsworth 		buf = list_entry(stream->vidq.next,
892fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
893fc2873aaSDale Farnsworth 		buf->drop = false;
894fc2873aaSDale Farnsworth 		list_move_tail(&buf->list, &stream->post_bufs);
895fc2873aaSDale Farnsworth 		v4l2_dbg(4, debug, &dev->v4l2_dev, "added next buffer\n");
896fc2873aaSDale Farnsworth 	}
897fc2873aaSDale Farnsworth 
898fc2873aaSDale Farnsworth 	spin_unlock_irqrestore(&dev->slock, flags);
899fc2873aaSDale Farnsworth 	start_dma(stream, buf);
900fc2873aaSDale Farnsworth }
901fc2873aaSDale Farnsworth 
vip_process_buffer_complete(struct vip_stream * stream)902fc2873aaSDale Farnsworth static void vip_process_buffer_complete(struct vip_stream *stream)
903fc2873aaSDale Farnsworth {
904fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
905fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
906fc2873aaSDale Farnsworth 	struct vb2_v4l2_buffer *vb = NULL;
907fc2873aaSDale Farnsworth 	unsigned long flags, fld;
908fc2873aaSDale Farnsworth 
909fc2873aaSDale Farnsworth 	buf = list_first_entry_or_null(&stream->post_bufs, struct vip_buffer, list);
910fc2873aaSDale Farnsworth 
911fc2873aaSDale Farnsworth 	if (stream->port->flags & FLAG_INTERLACED) {
912fc2873aaSDale Farnsworth 		vpdma_unmap_desc_buf(dev->shared->vpdma,
913fc2873aaSDale Farnsworth 				     &stream->desc_list.buf);
914fc2873aaSDale Farnsworth 
915fc2873aaSDale Farnsworth 		fld = dtd_get_field(stream->write_desc);
916fc2873aaSDale Farnsworth 		stream->field = fld ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
917fc2873aaSDale Farnsworth 
918fc2873aaSDale Farnsworth 		vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
919fc2873aaSDale Farnsworth 	}
920fc2873aaSDale Farnsworth 
921fc2873aaSDale Farnsworth 	if (buf) {
922fc2873aaSDale Farnsworth 		vb = &buf->vb;
923fc2873aaSDale Farnsworth 		vb->sequence = stream->sequence;
924fc2873aaSDale Farnsworth 		vb->vb2_buf.timestamp = ktime_get_ns();
925fc2873aaSDale Farnsworth 		vb->field = V4L2_FIELD_NONE;
926fc2873aaSDale Farnsworth 
927fc2873aaSDale Farnsworth 		if (buf->drop) {
928fc2873aaSDale Farnsworth 			spin_lock_irqsave(&dev->slock, flags);
929fc2873aaSDale Farnsworth 			list_move_tail(&buf->list, &stream->dropq);
930fc2873aaSDale Farnsworth 			spin_unlock_irqrestore(&dev->slock, flags);
931fc2873aaSDale Farnsworth 		} else {
932fc2873aaSDale Farnsworth 			spin_lock_irqsave(&dev->slock, flags);
933fc2873aaSDale Farnsworth 			list_del(&buf->list);
934fc2873aaSDale Farnsworth 			spin_unlock_irqrestore(&dev->slock, flags);
935fc2873aaSDale Farnsworth 			vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE);
936fc2873aaSDale Farnsworth 		}
937fc2873aaSDale Farnsworth 	} else {
938fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "%s: buf is null!!!\n", __func__);
939fc2873aaSDale Farnsworth 		return;
940fc2873aaSDale Farnsworth 	}
941fc2873aaSDale Farnsworth 
942fc2873aaSDale Farnsworth 	stream->sequence++;
943fc2873aaSDale Farnsworth }
944fc2873aaSDale Farnsworth 
vip_reset_vpdma(struct vip_stream * stream)945fc2873aaSDale Farnsworth static int vip_reset_vpdma(struct vip_stream *stream)
946fc2873aaSDale Farnsworth {
947fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
948fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
949fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
950fc2873aaSDale Farnsworth 	unsigned long flags;
951fc2873aaSDale Farnsworth 
952fc2873aaSDale Farnsworth 	stop_dma(stream, false);
953fc2873aaSDale Farnsworth 
954fc2873aaSDale Farnsworth 	spin_lock_irqsave(&dev->slock, flags);
955fc2873aaSDale Farnsworth 	/* requeue all active buffers in the opposite order */
956fc2873aaSDale Farnsworth 	while (!list_empty(&stream->post_bufs)) {
957fc2873aaSDale Farnsworth 		buf = list_last_entry(&stream->post_bufs,
958fc2873aaSDale Farnsworth 				      struct vip_buffer, list);
959fc2873aaSDale Farnsworth 		list_del(&buf->list);
960fc2873aaSDale Farnsworth 		if (buf->drop == 1) {
961fc2873aaSDale Farnsworth 			list_add_tail(&buf->list, &stream->dropq);
962fc2873aaSDale Farnsworth 			v4l2_dbg(4, debug, &dev->v4l2_dev, "requeueing drop buffer on dropq\n");
963fc2873aaSDale Farnsworth 		} else {
964fc2873aaSDale Farnsworth 			list_add(&buf->list, &stream->vidq);
965fc2873aaSDale Farnsworth 			v4l2_dbg(4, debug, &dev->v4l2_dev, "requeueing vb2 buf idx:%d on vidq\n",
966fc2873aaSDale Farnsworth 				 buf->vb.vb2_buf.index);
967fc2873aaSDale Farnsworth 		}
968fc2873aaSDale Farnsworth 	}
969fc2873aaSDale Farnsworth 	spin_unlock_irqrestore(&dev->slock, flags);
970fc2873aaSDale Farnsworth 
971fc2873aaSDale Farnsworth 	/* Make sure the desc_list is unmapped */
972fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
973fc2873aaSDale Farnsworth 
974fc2873aaSDale Farnsworth 	return 0;
975fc2873aaSDale Farnsworth }
976fc2873aaSDale Farnsworth 
vip_overflow_recovery_work(struct work_struct * work)977fc2873aaSDale Farnsworth static void vip_overflow_recovery_work(struct work_struct *work)
978fc2873aaSDale Farnsworth {
979fc2873aaSDale Farnsworth 	struct vip_stream *stream = container_of(work, struct vip_stream,
980fc2873aaSDale Farnsworth 						 recovery_work);
981fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
982fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
983fc2873aaSDale Farnsworth 
984fc2873aaSDale Farnsworth 	v4l2_err(&dev->v4l2_dev, "%s: Port %c\n", __func__,
985fc2873aaSDale Farnsworth 		 port->port_id == VIP_PORTA ? 'A' : 'B');
986fc2873aaSDale Farnsworth 
987fc2873aaSDale Farnsworth 	disable_irqs(dev, dev->slice_id, stream->list_num);
988fc2873aaSDale Farnsworth 	clear_irqs(dev, dev->slice_id, stream->list_num);
989fc2873aaSDale Farnsworth 
990fc2873aaSDale Farnsworth 	/* 1.	Set VIP_XTRA6_PORT_A[31:16] YUV_SRCNUM_STOP_IMMEDIATELY */
991fc2873aaSDale Farnsworth 	/* 2.	Set VIP_XTRA6_PORT_A[15:0] ANC_SRCNUM_STOP_IMMEDIATELY */
992fc2873aaSDale Farnsworth 	vip_parser_stop_imm(port, 1);
993fc2873aaSDale Farnsworth 
994fc2873aaSDale Farnsworth 	/* 3.	Clear VIP_PORT_A[8] ENABLE */
995fc2873aaSDale Farnsworth 	/*
996fc2873aaSDale Farnsworth 	 * 4.	Set VIP_PORT_A[7] CLR_ASYNC_FIFO_RD
997fc2873aaSDale Farnsworth 	 *      Set VIP_PORT_A[6] CLR_ASYNC_FIFO_WR
998fc2873aaSDale Farnsworth 	 */
999fc2873aaSDale Farnsworth 	vip_enable_parser(port, false);
1000fc2873aaSDale Farnsworth 
1001fc2873aaSDale Farnsworth 	/* 5.	Set VIP_PORT_A[23] SW_RESET */
1002fc2873aaSDale Farnsworth 	vip_reset_parser(port, 1);
1003fc2873aaSDale Farnsworth 
1004fc2873aaSDale Farnsworth 	/*
1005fc2873aaSDale Farnsworth 	 * 6.	Reset other VIP modules
1006fc2873aaSDale Farnsworth 	 *	For each module used downstream of VIP_PARSER, write 1 to the
1007fc2873aaSDale Farnsworth 	 *      bit location of the VIP_CLKC_RST register which is connected
1008fc2873aaSDale Farnsworth 	 *      to VIP_PARSER
1009fc2873aaSDale Farnsworth 	 */
1010fc2873aaSDale Farnsworth 	vip_module_toggle(dev, VIP_DP_RST, true);
1011fc2873aaSDale Farnsworth 
1012fc2873aaSDale Farnsworth 	usleep_range(200, 250);
1013fc2873aaSDale Farnsworth 
1014fc2873aaSDale Farnsworth 	/*
1015fc2873aaSDale Farnsworth 	 * 7.	Abort VPDMA channels
1016fc2873aaSDale Farnsworth 	 *	Write to list attribute to stop list 0
1017fc2873aaSDale Farnsworth 	 *	Write to list address register location of abort list
1018fc2873aaSDale Farnsworth 	 *	Write to list attribute register list 0 and size of abort list
1019fc2873aaSDale Farnsworth 	 */
1020fc2873aaSDale Farnsworth 	vip_reset_vpdma(stream);
1021fc2873aaSDale Farnsworth 
1022fc2873aaSDale Farnsworth 	/* 8.	Clear VIP_PORT_A[23] SW_RESET */
1023fc2873aaSDale Farnsworth 	vip_reset_parser(port, 0);
1024fc2873aaSDale Farnsworth 
1025fc2873aaSDale Farnsworth 	/*
1026fc2873aaSDale Farnsworth 	 * 9.	Un-reset other VIP modules
1027fc2873aaSDale Farnsworth 	 *	For each module used downstream of VIP_PARSER, write 0 to
1028fc2873aaSDale Farnsworth 	 *	the bit location of the VIP_CLKC_RST register which is
1029fc2873aaSDale Farnsworth 	 *	connected to VIP_PARSER
1030fc2873aaSDale Farnsworth 	 */
1031fc2873aaSDale Farnsworth 	vip_module_toggle(dev, VIP_DP_RST, false);
1032fc2873aaSDale Farnsworth 
1033fc2873aaSDale Farnsworth 	/* 10.	(Delay) */
1034fc2873aaSDale Farnsworth 	/* 11.	SC coeff downloaded (if VIP_SCALER is being used) */
1035fc2873aaSDale Farnsworth 	vip_setup_scaler(stream);
1036fc2873aaSDale Farnsworth 
1037fc2873aaSDale Farnsworth 	/* 12.	(Delay) */
1038fc2873aaSDale Farnsworth 		/* the above are not needed here yet */
1039fc2873aaSDale Farnsworth 
1040fc2873aaSDale Farnsworth 	populate_desc_list(stream);
1041fc2873aaSDale Farnsworth 	stream->num_recovery++;
1042fc2873aaSDale Farnsworth 	if (stream->num_recovery < 5) {
1043fc2873aaSDale Farnsworth 		/* Reload the vpdma */
1044fc2873aaSDale Farnsworth 		vip_load_vpdma_list_fifo(stream);
1045fc2873aaSDale Farnsworth 
1046fc2873aaSDale Farnsworth 		enable_irqs(dev, dev->slice_id, stream->list_num);
1047fc2873aaSDale Farnsworth 		vip_schedule_next_buffer(stream);
1048fc2873aaSDale Farnsworth 
1049fc2873aaSDale Farnsworth 		/* 13.	Clear VIP_XTRA6_PORT_A[31:16] YUV_SRCNUM_STOP_IMM */
1050fc2873aaSDale Farnsworth 		/* 14.	Clear VIP_XTRA6_PORT_A[15:0] ANC_SRCNUM_STOP_IMM */
1051fc2873aaSDale Farnsworth 
1052fc2873aaSDale Farnsworth 		vip_parser_stop_imm(port, 0);
1053fc2873aaSDale Farnsworth 
1054fc2873aaSDale Farnsworth 		/* 15.	Set VIP_PORT_A[8] ENABLE */
1055fc2873aaSDale Farnsworth 		/*
1056fc2873aaSDale Farnsworth 		 * 16.	Clear VIP_PORT_A[7] CLR_ASYNC_FIFO_RD
1057fc2873aaSDale Farnsworth 		 *	Clear VIP_PORT_A[6] CLR_ASYNC_FIFO_WR
1058fc2873aaSDale Farnsworth 		 */
1059fc2873aaSDale Farnsworth 		vip_enable_parser(port, true);
1060fc2873aaSDale Farnsworth 	} else {
1061fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "%s: num_recovery limit exceeded leaving disabled\n",
1062fc2873aaSDale Farnsworth 			 __func__);
1063fc2873aaSDale Farnsworth 	}
1064fc2873aaSDale Farnsworth }
1065fc2873aaSDale Farnsworth 
handle_parser_irqs(struct vip_dev * dev)1066fc2873aaSDale Farnsworth static void handle_parser_irqs(struct vip_dev *dev)
1067fc2873aaSDale Farnsworth {
1068fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
1069fc2873aaSDale Farnsworth 	struct vip_port *porta = dev->ports[VIP_PORTA];
1070fc2873aaSDale Farnsworth 	struct vip_port *portb = dev->ports[VIP_PORTB];
1071fc2873aaSDale Farnsworth 	struct vip_stream *stream = NULL;
1072fc2873aaSDale Farnsworth 	u32 vip_irq_stat = reg_read(parser, VIP_PARSER_FIQ_STATUS);
1073fc2873aaSDale Farnsworth 	int i;
1074fc2873aaSDale Farnsworth 
1075fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: FIQ_STATUS: 0x%08x\n", __func__, vip_irq_stat);
1076fc2873aaSDale Farnsworth 
1077fc2873aaSDale Farnsworth 	/* Clear all Parser Interrupt */
1078fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_CLR, vip_irq_stat);
1079fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_FIQ_CLR, 0x0);
1080fc2873aaSDale Farnsworth 
1081fc2873aaSDale Farnsworth 	#ifdef DEBUG
1082fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_VDET)
1083fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_VDET\n");
1084fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_VDET)
1085fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_VDET\n");
1086fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_ASYNC_FIFO_OF)
1087fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTA_ASYNC_FIFO_OF\n");
1088fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_ASYNC_FIFO_OF)
1089fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTB_ASYNC_FIFO_OF\n");
1090fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_OUTPUT_FIFO_YUV)
1091fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTA_OUTPUT_FIFO_YUV\n");
1092fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_OUTPUT_FIFO_ANC)
1093fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTA_OUTPUT_FIFO_ANC\n");
1094fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_OUTPUT_FIFO_YUV)
1095fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTB_OUTPUT_FIFO_YUV\n");
1096fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_OUTPUT_FIFO_ANC)
1097fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "VIP_PORTB_OUTPUT_FIFO_ANC\n");
1098fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_CONN)
1099fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_CONN\n");
1100fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_DISCONN)
1101fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_DISCONN\n");
1102fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_CONN)
1103fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_CONN\n");
1104fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_DISCONN)
1105fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_DISCONN\n");
1106fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_SRC0_SIZE)
1107fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_SRC0_SIZE\n");
1108fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_SRC0_SIZE)
1109fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_SRC0_SIZE\n");
1110fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_YUV_PROTO_VIOLATION)
1111fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_YUV_PROTO_VIOLATION\n");
1112fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_ANC_PROTO_VIOLATION)
1113fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_ANC_PROTO_VIOLATION\n");
1114fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_YUV_PROTO_VIOLATION)
1115fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_YUV_PROTO_VIOLATION\n");
1116fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_ANC_PROTO_VIOLATION)
1117fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_ANC_PROTO_VIOLATION\n");
1118fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTA_CFG_DISABLE_COMPLETE)
1119fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTA_CFG_DISABLE_COMPLETE\n");
1120fc2873aaSDale Farnsworth 	if (vip_irq_stat & VIP_PORTB_CFG_DISABLE_COMPLETE)
1121fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "VIP_PORTB_CFG_DISABLE_COMPLETE\n");
1122fc2873aaSDale Farnsworth 	#endif
1123fc2873aaSDale Farnsworth 
1124fc2873aaSDale Farnsworth 	if (vip_irq_stat & (VIP_PORTA_ASYNC_FIFO_OF |
1125fc2873aaSDale Farnsworth 			VIP_PORTA_OUTPUT_FIFO_YUV |
1126fc2873aaSDale Farnsworth 			VIP_PORTA_OUTPUT_FIFO_ANC)) {
1127fc2873aaSDale Farnsworth 		for (i = 0; i < VIP_CAP_STREAMS_PER_PORT; i++) {
1128fc2873aaSDale Farnsworth 			if (porta->cap_streams[i] &&
1129fc2873aaSDale Farnsworth 			    porta->cap_streams[i]->port->port_id ==
1130fc2873aaSDale Farnsworth 			    porta->port_id) {
1131fc2873aaSDale Farnsworth 				stream = porta->cap_streams[i];
1132fc2873aaSDale Farnsworth 				break;
1133fc2873aaSDale Farnsworth 			}
1134fc2873aaSDale Farnsworth 		}
1135fc2873aaSDale Farnsworth 		if (stream) {
1136fc2873aaSDale Farnsworth 			disable_irqs(dev, dev->slice_id,
1137fc2873aaSDale Farnsworth 				     stream->list_num);
1138fc2873aaSDale Farnsworth 			schedule_work(&stream->recovery_work);
1139fc2873aaSDale Farnsworth 			return;
1140fc2873aaSDale Farnsworth 		}
1141fc2873aaSDale Farnsworth 	}
1142fc2873aaSDale Farnsworth 	if (vip_irq_stat & (VIP_PORTB_ASYNC_FIFO_OF |
1143fc2873aaSDale Farnsworth 			VIP_PORTB_OUTPUT_FIFO_YUV |
1144fc2873aaSDale Farnsworth 			VIP_PORTB_OUTPUT_FIFO_ANC)) {
1145fc2873aaSDale Farnsworth 		for (i = 0; i < VIP_CAP_STREAMS_PER_PORT; i++) {
1146fc2873aaSDale Farnsworth 			if (portb->cap_streams[i] &&
1147fc2873aaSDale Farnsworth 			    portb->cap_streams[i]->port->port_id ==
1148fc2873aaSDale Farnsworth 			    portb->port_id) {
1149fc2873aaSDale Farnsworth 				stream = portb->cap_streams[i];
1150fc2873aaSDale Farnsworth 				break;
1151fc2873aaSDale Farnsworth 			}
1152fc2873aaSDale Farnsworth 		}
1153fc2873aaSDale Farnsworth 		if (stream) {
1154fc2873aaSDale Farnsworth 			disable_irqs(dev, dev->slice_id,
1155fc2873aaSDale Farnsworth 				     stream->list_num);
1156fc2873aaSDale Farnsworth 			schedule_work(&stream->recovery_work);
1157fc2873aaSDale Farnsworth 			return;
1158fc2873aaSDale Farnsworth 		}
1159fc2873aaSDale Farnsworth 	}
1160fc2873aaSDale Farnsworth }
1161fc2873aaSDale Farnsworth 
vip_irq(int irq_vip,void * data)1162fc2873aaSDale Farnsworth static irqreturn_t vip_irq(int irq_vip, void *data)
1163fc2873aaSDale Farnsworth {
1164fc2873aaSDale Farnsworth 	struct vip_dev *dev = (struct vip_dev *)data;
1165fc2873aaSDale Farnsworth 	struct vpdma_data *vpdma;
1166fc2873aaSDale Farnsworth 	struct vip_stream *stream;
1167fc2873aaSDale Farnsworth 	int list_num;
1168fc2873aaSDale Farnsworth 	int irq_num = dev->slice_id;
1169fc2873aaSDale Farnsworth 	u32 irqst, irqst_saved, reg_addr;
1170fc2873aaSDale Farnsworth 
1171fc2873aaSDale Farnsworth 	if (!dev->shared)
1172fc2873aaSDale Farnsworth 		return IRQ_HANDLED;
1173fc2873aaSDale Farnsworth 
1174fc2873aaSDale Farnsworth 	vpdma = dev->shared->vpdma;
1175fc2873aaSDale Farnsworth 	reg_addr = VIP_INT0_STATUS0 +
1176fc2873aaSDale Farnsworth 			VIP_INTC_INTX_OFFSET * irq_num;
1177fc2873aaSDale Farnsworth 	irqst_saved = reg_read(dev->shared, reg_addr);
1178fc2873aaSDale Farnsworth 	irqst = irqst_saved;
1179fc2873aaSDale Farnsworth 
1180fc2873aaSDale Farnsworth 	v4l2_dbg(8, debug, &dev->v4l2_dev, "IRQ %d VIP_INT%d_STATUS0 0x%x\n",
1181fc2873aaSDale Farnsworth 		 irq_vip, irq_num, irqst);
1182fc2873aaSDale Farnsworth 	if (irqst) {
1183fc2873aaSDale Farnsworth 		if (irqst & (VIP_VIP1_PARSER_INT << (irq_num * 1))) {
1184fc2873aaSDale Farnsworth 			irqst &= ~(VIP_VIP1_PARSER_INT << (irq_num * 1));
1185fc2873aaSDale Farnsworth 			handle_parser_irqs(dev);
1186fc2873aaSDale Farnsworth 		}
1187fc2873aaSDale Farnsworth 
1188fc2873aaSDale Farnsworth 		for (list_num = 0; irqst && (list_num < 8);  list_num++) {
1189fc2873aaSDale Farnsworth 			/* Check for LIST_COMPLETE IRQ */
1190fc2873aaSDale Farnsworth 			if (!(irqst & (1 << list_num * 2)))
1191fc2873aaSDale Farnsworth 				continue;
1192fc2873aaSDale Farnsworth 
1193fc2873aaSDale Farnsworth 			v4l2_dbg(8, debug, &dev->v4l2_dev, "IRQ %d: handling LIST%d_COMPLETE\n",
1194fc2873aaSDale Farnsworth 				 irq_num, list_num);
1195fc2873aaSDale Farnsworth 
1196fc2873aaSDale Farnsworth 			stream = vpdma_hwlist_get_priv(vpdma, list_num);
1197fc2873aaSDale Farnsworth 			if (!stream || stream->list_num != list_num) {
1198fc2873aaSDale Farnsworth 				v4l2_err(&dev->v4l2_dev, "IRQ occurred for unused list");
1199fc2873aaSDale Farnsworth 				continue;
1200fc2873aaSDale Farnsworth 			}
1201fc2873aaSDale Farnsworth 
1202fc2873aaSDale Farnsworth 			vpdma_clear_list_stat(vpdma, irq_num, list_num);
1203fc2873aaSDale Farnsworth 
1204fc2873aaSDale Farnsworth 			vip_process_buffer_complete(stream);
1205fc2873aaSDale Farnsworth 
1206fc2873aaSDale Farnsworth 			vip_schedule_next_buffer(stream);
1207fc2873aaSDale Farnsworth 
1208fc2873aaSDale Farnsworth 			irqst &= ~((1 << list_num * 2));
1209fc2873aaSDale Farnsworth 		}
1210fc2873aaSDale Farnsworth 	}
1211fc2873aaSDale Farnsworth 
1212fc2873aaSDale Farnsworth 	/* Acknowledge that we are done with all interrupts */
1213fc2873aaSDale Farnsworth 	reg_write(dev->shared, VIP_INTC_E0I, 1 << irq_num);
1214fc2873aaSDale Farnsworth 
1215fc2873aaSDale Farnsworth 	/* Clear handled events from status register */
1216fc2873aaSDale Farnsworth 	reg_addr = VIP_INT0_STATUS0_CLR +
1217fc2873aaSDale Farnsworth 		   VIP_INTC_INTX_OFFSET * irq_num;
1218fc2873aaSDale Farnsworth 	reg_write(dev->shared, reg_addr, irqst_saved);
1219fc2873aaSDale Farnsworth 
1220fc2873aaSDale Farnsworth 	return IRQ_HANDLED;
1221fc2873aaSDale Farnsworth }
1222fc2873aaSDale Farnsworth 
1223fc2873aaSDale Farnsworth /*
1224fc2873aaSDale Farnsworth  * video ioctls
1225fc2873aaSDale Farnsworth  */
vip_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1226fc2873aaSDale Farnsworth static int vip_querycap(struct file *file, void *priv,
1227fc2873aaSDale Farnsworth 			struct v4l2_capability *cap)
1228fc2873aaSDale Farnsworth {
1229fc2873aaSDale Farnsworth 	strscpy(cap->driver, VIP_MODULE_NAME, sizeof(cap->driver));
1230fc2873aaSDale Farnsworth 	strscpy(cap->card, VIP_MODULE_NAME, sizeof(cap->card));
1231fc2873aaSDale Farnsworth 	return 0;
1232fc2873aaSDale Farnsworth }
1233fc2873aaSDale Farnsworth 
vip_enuminput(struct file * file,void * priv,struct v4l2_input * inp)1234fc2873aaSDale Farnsworth static int vip_enuminput(struct file *file, void *priv,
1235fc2873aaSDale Farnsworth 			 struct v4l2_input *inp)
1236fc2873aaSDale Farnsworth {
1237fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1238fc2873aaSDale Farnsworth 
1239fc2873aaSDale Farnsworth 	if (inp->index)
1240fc2873aaSDale Farnsworth 		return -EINVAL;
1241fc2873aaSDale Farnsworth 
1242fc2873aaSDale Farnsworth 	inp->type = V4L2_INPUT_TYPE_CAMERA;
1243fc2873aaSDale Farnsworth 	inp->std = stream->vfd->tvnorms;
1244fc2873aaSDale Farnsworth 	sprintf(inp->name, "Camera %u", stream->vfd->num);
1245fc2873aaSDale Farnsworth 
1246fc2873aaSDale Farnsworth 	return 0;
1247fc2873aaSDale Farnsworth }
1248fc2873aaSDale Farnsworth 
vip_g_input(struct file * file,void * priv,unsigned int * i)1249fc2873aaSDale Farnsworth static int vip_g_input(struct file *file, void *priv, unsigned int *i)
1250fc2873aaSDale Farnsworth {
1251fc2873aaSDale Farnsworth 	*i = 0;
1252fc2873aaSDale Farnsworth 	return 0;
1253fc2873aaSDale Farnsworth }
1254fc2873aaSDale Farnsworth 
vip_s_input(struct file * file,void * priv,unsigned int i)1255fc2873aaSDale Farnsworth static int vip_s_input(struct file *file, void *priv, unsigned int i)
1256fc2873aaSDale Farnsworth {
1257fc2873aaSDale Farnsworth 	if (i != 0)
1258fc2873aaSDale Farnsworth 		return -EINVAL;
1259fc2873aaSDale Farnsworth 	return 0;
1260fc2873aaSDale Farnsworth }
1261fc2873aaSDale Farnsworth 
vip_querystd(struct file * file,void * fh,v4l2_std_id * std)1262fc2873aaSDale Farnsworth static int vip_querystd(struct file *file, void *fh, v4l2_std_id *std)
1263fc2873aaSDale Farnsworth {
1264fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1265fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1266fc2873aaSDale Farnsworth 
1267fc2873aaSDale Farnsworth 	*std = stream->vfd->tvnorms;
1268fc2873aaSDale Farnsworth 	v4l2_subdev_call(port->subdev, video, querystd, std);
1269fc2873aaSDale Farnsworth 	return 0;
1270fc2873aaSDale Farnsworth }
1271fc2873aaSDale Farnsworth 
vip_g_std(struct file * file,void * fh,v4l2_std_id * std)1272fc2873aaSDale Farnsworth static int vip_g_std(struct file *file, void *fh, v4l2_std_id *std)
1273fc2873aaSDale Farnsworth {
1274fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1275fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1276fc2873aaSDale Farnsworth 
1277fc2873aaSDale Farnsworth 	*std = stream->vfd->tvnorms;
1278fc2873aaSDale Farnsworth 	v4l2_subdev_call(port->subdev, video, g_std, std);
1279fc2873aaSDale Farnsworth 
1280fc2873aaSDale Farnsworth 	return 0;
1281fc2873aaSDale Farnsworth }
1282fc2873aaSDale Farnsworth 
vip_s_std(struct file * file,void * fh,v4l2_std_id std)1283fc2873aaSDale Farnsworth static int vip_s_std(struct file *file, void *fh, v4l2_std_id std)
1284fc2873aaSDale Farnsworth {
1285fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1286fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1287fc2873aaSDale Farnsworth 
1288fc2873aaSDale Farnsworth 	if (stream->vfd->tvnorms == std)
1289fc2873aaSDale Farnsworth 		return 0;
1290fc2873aaSDale Farnsworth 
1291fc2873aaSDale Farnsworth 	if (!(std & stream->vfd->tvnorms))
1292fc2873aaSDale Farnsworth 		return -EINVAL;
1293fc2873aaSDale Farnsworth 
1294fc2873aaSDale Farnsworth 	if (vb2_is_busy(&stream->vb_vidq))
1295fc2873aaSDale Farnsworth 		return -EBUSY;
1296fc2873aaSDale Farnsworth 
1297fc2873aaSDale Farnsworth 	v4l2_subdev_call(port->subdev, video, s_std, std);
1298fc2873aaSDale Farnsworth 	return 0;
1299fc2873aaSDale Farnsworth }
1300fc2873aaSDale Farnsworth 
vip_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)1301fc2873aaSDale Farnsworth static int vip_enum_fmt_vid_cap(struct file *file, void *priv,
1302fc2873aaSDale Farnsworth 				struct v4l2_fmtdesc *f)
1303fc2873aaSDale Farnsworth {
1304fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1305fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1306fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
1307fc2873aaSDale Farnsworth 
1308fc2873aaSDale Farnsworth 	if (f->index >= port->num_active_fmt)
1309fc2873aaSDale Farnsworth 		return -EINVAL;
1310fc2873aaSDale Farnsworth 
1311fc2873aaSDale Farnsworth 	fmt = port->active_fmt[f->index];
1312fc2873aaSDale Farnsworth 	f->pixelformat = fmt->fourcc;
1313fc2873aaSDale Farnsworth 
1314fc2873aaSDale Farnsworth 	return 0;
1315fc2873aaSDale Farnsworth }
1316fc2873aaSDale Farnsworth 
vip_enum_framesizes(struct file * file,void * priv,struct v4l2_frmsizeenum * f)1317fc2873aaSDale Farnsworth static int vip_enum_framesizes(struct file *file, void *priv,
1318fc2873aaSDale Farnsworth 			       struct v4l2_frmsizeenum *f)
1319fc2873aaSDale Farnsworth {
1320fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1321fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1322fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
1323fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
1324fc2873aaSDale Farnsworth 	int ret;
1325fc2873aaSDale Farnsworth 	struct v4l2_subdev_frame_size_enum fse = {
1326fc2873aaSDale Farnsworth 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1327fc2873aaSDale Farnsworth 		.pad = 0,
1328fc2873aaSDale Farnsworth 	};
1329fc2873aaSDale Farnsworth 
1330fc2873aaSDale Farnsworth 	fmt = find_port_format_by_pix(port, f->pixel_format);
1331fc2873aaSDale Farnsworth 	if (!fmt)
1332fc2873aaSDale Farnsworth 		return -EINVAL;
1333fc2873aaSDale Farnsworth 
1334fc2873aaSDale Farnsworth 	fse.index = f->index;
1335fc2873aaSDale Farnsworth 	fse.code = fmt->code;
1336fc2873aaSDale Farnsworth 	ret = v4l2_subdev_call(port->subdev, pad, enum_frame_size, NULL, &fse);
1337fc2873aaSDale Farnsworth 	if (ret)
1338fc2873aaSDale Farnsworth 		return -EINVAL;
1339fc2873aaSDale Farnsworth 
1340fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
1341fc2873aaSDale Farnsworth 		 __func__, fse.index, fse.code, fse.min_width, fse.max_width,
1342fc2873aaSDale Farnsworth 		 fse.min_height, fse.max_height);
1343fc2873aaSDale Farnsworth 
1344fc2873aaSDale Farnsworth 	f->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1345fc2873aaSDale Farnsworth 	f->discrete.width = fse.max_width;
1346fc2873aaSDale Farnsworth 	f->discrete.height = fse.max_height;
1347fc2873aaSDale Farnsworth 
1348fc2873aaSDale Farnsworth 	return 0;
1349fc2873aaSDale Farnsworth }
1350fc2873aaSDale Farnsworth 
vip_enum_frameintervals(struct file * file,void * priv,struct v4l2_frmivalenum * f)1351fc2873aaSDale Farnsworth static int vip_enum_frameintervals(struct file *file, void *priv,
1352fc2873aaSDale Farnsworth 				   struct v4l2_frmivalenum *f)
1353fc2873aaSDale Farnsworth {
1354fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1355fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1356fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
1357fc2873aaSDale Farnsworth 	struct v4l2_subdev_frame_interval_enum fie = {
1358fc2873aaSDale Farnsworth 		.index = f->index,
1359fc2873aaSDale Farnsworth 		.width = f->width,
1360fc2873aaSDale Farnsworth 		.height = f->height,
1361fc2873aaSDale Farnsworth 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1362fc2873aaSDale Farnsworth 	};
1363fc2873aaSDale Farnsworth 	int ret;
1364fc2873aaSDale Farnsworth 
1365fc2873aaSDale Farnsworth 	fmt = find_port_format_by_pix(port, f->pixel_format);
1366fc2873aaSDale Farnsworth 	if (!fmt)
1367fc2873aaSDale Farnsworth 		return -EINVAL;
1368fc2873aaSDale Farnsworth 
1369fc2873aaSDale Farnsworth 	fie.code = fmt->code;
1370fc2873aaSDale Farnsworth 	ret = v4l2_subdev_call(port->subdev, pad, enum_frame_interval,
1371fc2873aaSDale Farnsworth 			       NULL, &fie);
1372fc2873aaSDale Farnsworth 	if (ret)
1373fc2873aaSDale Farnsworth 		return ret;
1374fc2873aaSDale Farnsworth 	f->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1375fc2873aaSDale Farnsworth 	f->discrete = fie.interval;
1376fc2873aaSDale Farnsworth 
1377fc2873aaSDale Farnsworth 	return 0;
1378fc2873aaSDale Farnsworth }
1379fc2873aaSDale Farnsworth 
vip_g_parm(struct file * file,void * fh,struct v4l2_streamparm * a)1380fc2873aaSDale Farnsworth static int vip_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1381fc2873aaSDale Farnsworth {
1382fc2873aaSDale Farnsworth 	struct vip_stream *stream = video_drvdata(file);
1383fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1384fc2873aaSDale Farnsworth 
1385fc2873aaSDale Farnsworth 	return v4l2_g_parm_cap(video_devdata(file), port->subdev, a);
1386fc2873aaSDale Farnsworth }
1387fc2873aaSDale Farnsworth 
vip_s_parm(struct file * file,void * fh,struct v4l2_streamparm * a)1388fc2873aaSDale Farnsworth static int vip_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1389fc2873aaSDale Farnsworth {
1390fc2873aaSDale Farnsworth 	struct vip_stream *stream = video_drvdata(file);
1391fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1392fc2873aaSDale Farnsworth 
1393fc2873aaSDale Farnsworth 	return v4l2_s_parm_cap(video_devdata(file), port->subdev, a);
1394fc2873aaSDale Farnsworth }
1395fc2873aaSDale Farnsworth 
vip_calc_format_size(struct vip_port * port,struct vip_fmt * fmt,struct v4l2_format * f)1396fc2873aaSDale Farnsworth static int vip_calc_format_size(struct vip_port *port,
1397fc2873aaSDale Farnsworth 				struct vip_fmt *fmt,
1398fc2873aaSDale Farnsworth 				struct v4l2_format *f)
1399fc2873aaSDale Farnsworth {
1400fc2873aaSDale Farnsworth 	enum v4l2_field *field;
1401fc2873aaSDale Farnsworth 	unsigned int stride;
1402fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
1403fc2873aaSDale Farnsworth 
1404fc2873aaSDale Farnsworth 	if (!fmt) {
1405fc2873aaSDale Farnsworth 		v4l2_dbg(2, debug, &dev->v4l2_dev,
1406fc2873aaSDale Farnsworth 			 "no vip_fmt format provided!\n");
1407fc2873aaSDale Farnsworth 		return -EINVAL;
1408fc2873aaSDale Farnsworth 	}
1409fc2873aaSDale Farnsworth 
1410fc2873aaSDale Farnsworth 	field = &f->fmt.pix.field;
1411fc2873aaSDale Farnsworth 	if (*field == V4L2_FIELD_ANY)
1412fc2873aaSDale Farnsworth 		*field = V4L2_FIELD_NONE;
1413fc2873aaSDale Farnsworth 	else if (V4L2_FIELD_NONE != *field && V4L2_FIELD_ALTERNATE != *field)
1414fc2873aaSDale Farnsworth 		return -EINVAL;
1415fc2873aaSDale Farnsworth 
1416fc2873aaSDale Farnsworth 	v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, W_ALIGN,
1417fc2873aaSDale Farnsworth 			      &f->fmt.pix.height, MIN_H, MAX_H, H_ALIGN,
1418fc2873aaSDale Farnsworth 			      S_ALIGN);
1419fc2873aaSDale Farnsworth 
1420fc2873aaSDale Farnsworth 	stride = f->fmt.pix.width * (fmt->vpdma_fmt[0]->depth >> 3);
1421fc2873aaSDale Farnsworth 	f->fmt.pix.bytesperline = ALIGN(stride, VPDMA_STRIDE_ALIGN);
1422fc2873aaSDale Farnsworth 
1423fc2873aaSDale Farnsworth 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
1424fc2873aaSDale Farnsworth 	if (fmt->coplanar) {
1425fc2873aaSDale Farnsworth 		f->fmt.pix.sizeimage += f->fmt.pix.height *
1426fc2873aaSDale Farnsworth 					f->fmt.pix.bytesperline *
1427fc2873aaSDale Farnsworth 					fmt->vpdma_fmt[VIP_CHROMA]->depth >> 3;
1428fc2873aaSDale Farnsworth 	}
1429fc2873aaSDale Farnsworth 
1430fc2873aaSDale Farnsworth 	f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
1431fc2873aaSDale Farnsworth 
1432fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "calc_format_size: fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
1433fc2873aaSDale Farnsworth 		 fourcc_to_str(f->fmt.pix.pixelformat),
1434fc2873aaSDale Farnsworth 		 f->fmt.pix.width, f->fmt.pix.height,
1435fc2873aaSDale Farnsworth 		 f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
1436fc2873aaSDale Farnsworth 
1437fc2873aaSDale Farnsworth 	return 0;
1438fc2873aaSDale Farnsworth }
1439fc2873aaSDale Farnsworth 
vip_is_size_dma_aligned(u32 bpp,u32 width)1440fc2873aaSDale Farnsworth static inline bool vip_is_size_dma_aligned(u32 bpp, u32 width)
1441fc2873aaSDale Farnsworth {
1442fc2873aaSDale Farnsworth 	return ((width * bpp) == ALIGN(width * bpp, VPDMA_STRIDE_ALIGN));
1443fc2873aaSDale Farnsworth }
1444fc2873aaSDale Farnsworth 
vip_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1445fc2873aaSDale Farnsworth static int vip_try_fmt_vid_cap(struct file *file, void *priv,
1446fc2873aaSDale Farnsworth 			       struct v4l2_format *f)
1447fc2873aaSDale Farnsworth {
1448fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1449fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1450fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
1451fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
1452fc2873aaSDale Farnsworth 	u32 best_width, best_height, largest_width, largest_height;
1453fc2873aaSDale Farnsworth 	int ret, found;
1454fc2873aaSDale Farnsworth 	enum vip_csc_state csc_direction;
1455fc2873aaSDale Farnsworth 	struct v4l2_subdev_frame_size_enum fse = {
1456fc2873aaSDale Farnsworth 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1457fc2873aaSDale Farnsworth 		.pad = 0,
1458fc2873aaSDale Farnsworth 	};
1459fc2873aaSDale Farnsworth 
1460fc2873aaSDale Farnsworth 	fmt = find_port_format_by_pix(port, f->fmt.pix.pixelformat);
1461fc2873aaSDale Farnsworth 	if (!fmt) {
1462fc2873aaSDale Farnsworth 		/* Just get the first one enumerated */
1463fc2873aaSDale Farnsworth 		fmt = port->active_fmt[0];
1464fc2873aaSDale Farnsworth 		f->fmt.pix.pixelformat = fmt->fourcc;
1465fc2873aaSDale Farnsworth 	}
1466fc2873aaSDale Farnsworth 
1467fc2873aaSDale Farnsworth 	csc_direction =  vip_csc_direction(fmt->code, fmt->finfo);
1468fc2873aaSDale Farnsworth 	if (csc_direction != VIP_CSC_NA) {
1469fc2873aaSDale Farnsworth 		if (!is_csc_available(port)) {
1470fc2873aaSDale Farnsworth 			v4l2_dbg(2, debug, &dev->v4l2_dev,
1471fc2873aaSDale Farnsworth 				 "CSC not available for Fourcc format (0x%08x).\n",
1472fc2873aaSDale Farnsworth 				 f->fmt.pix.pixelformat);
1473fc2873aaSDale Farnsworth 
1474fc2873aaSDale Farnsworth 			/* Just get the first one enumerated */
1475fc2873aaSDale Farnsworth 			fmt = port->active_fmt[0];
1476fc2873aaSDale Farnsworth 			f->fmt.pix.pixelformat = fmt->fourcc;
1477fc2873aaSDale Farnsworth 			/* re-evaluate the csc_direction here */
1478fc2873aaSDale Farnsworth 			csc_direction =  vip_csc_direction(fmt->code,
1479fc2873aaSDale Farnsworth 							   fmt->finfo);
1480fc2873aaSDale Farnsworth 		} else {
1481fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "CSC active on Port %c: going %s\n",
1482fc2873aaSDale Farnsworth 				 port->port_id == VIP_PORTA ? 'A' : 'B',
1483fc2873aaSDale Farnsworth 				 (csc_direction == VIP_CSC_Y2R) ? "Y2R" : "R2Y");
1484fc2873aaSDale Farnsworth 		}
1485fc2873aaSDale Farnsworth 	}
1486fc2873aaSDale Farnsworth 
1487fc2873aaSDale Farnsworth 	/*
1488fc2873aaSDale Farnsworth 	 * Given that sensors might support multiple mbus code we need
1489fc2873aaSDale Farnsworth 	 * to use the one that matches the requested pixel format
1490fc2873aaSDale Farnsworth 	 */
1491fc2873aaSDale Farnsworth 	port->try_mbus_framefmt = port->mbus_framefmt;
1492fc2873aaSDale Farnsworth 	port->try_mbus_framefmt.code = fmt->code;
1493fc2873aaSDale Farnsworth 
1494fc2873aaSDale Farnsworth 	/* check for/find a valid width/height */
1495fc2873aaSDale Farnsworth 	ret = 0;
1496fc2873aaSDale Farnsworth 	found = false;
1497fc2873aaSDale Farnsworth 	best_width = 0;
1498fc2873aaSDale Farnsworth 	best_height = 0;
1499fc2873aaSDale Farnsworth 	largest_width = 0;
1500fc2873aaSDale Farnsworth 	largest_height = 0;
1501fc2873aaSDale Farnsworth 
1502fc2873aaSDale Farnsworth 	fse.code = fmt->code;
1503fc2873aaSDale Farnsworth 	for (fse.index = 0; ; fse.index++) {
1504fc2873aaSDale Farnsworth 		u32 bpp = fmt->vpdma_fmt[0]->depth >> 3;
1505fc2873aaSDale Farnsworth 
1506fc2873aaSDale Farnsworth 		ret = v4l2_subdev_call(port->subdev, pad,
1507fc2873aaSDale Farnsworth 				       enum_frame_size, NULL, &fse);
1508fc2873aaSDale Farnsworth 		if (ret)
1509fc2873aaSDale Farnsworth 			break;
1510fc2873aaSDale Farnsworth 
1511fc2873aaSDale Farnsworth 		if (!vip_is_size_dma_aligned(bpp, fse.max_width))
1512fc2873aaSDale Farnsworth 			continue;
1513fc2873aaSDale Farnsworth 
1514fc2873aaSDale Farnsworth 		if (fse.max_width >= largest_width &&
1515fc2873aaSDale Farnsworth 		    fse.max_height >= largest_height) {
1516fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt loop:%d found new larger: %dx%d\n",
1517fc2873aaSDale Farnsworth 				 fse.index, fse.max_width, fse.max_height);
1518fc2873aaSDale Farnsworth 			largest_width = fse.max_width;
1519fc2873aaSDale Farnsworth 			largest_height = fse.max_height;
1520fc2873aaSDale Farnsworth 		}
1521fc2873aaSDale Farnsworth 
1522fc2873aaSDale Farnsworth 		if (fse.max_width >= f->fmt.pix.width &&
1523fc2873aaSDale Farnsworth 		    fse.max_height >= f->fmt.pix.height) {
1524fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt loop:%d found at least larger: %dx%d\n",
1525fc2873aaSDale Farnsworth 				 fse.index, fse.max_width, fse.max_height);
1526fc2873aaSDale Farnsworth 
1527fc2873aaSDale Farnsworth 			if (!best_width ||
1528fc2873aaSDale Farnsworth 			    ((abs(best_width - f->fmt.pix.width) >=
1529fc2873aaSDale Farnsworth 			      abs(fse.max_width - f->fmt.pix.width)) &&
1530fc2873aaSDale Farnsworth 			     (abs(best_height - f->fmt.pix.height) >=
1531fc2873aaSDale Farnsworth 			      abs(fse.max_height - f->fmt.pix.height)))) {
1532fc2873aaSDale Farnsworth 				best_width = fse.max_width;
1533fc2873aaSDale Farnsworth 				best_height = fse.max_height;
1534fc2873aaSDale Farnsworth 				v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt loop:%d found new best: %dx%d\n",
1535fc2873aaSDale Farnsworth 					 fse.index, fse.max_width,
1536fc2873aaSDale Farnsworth 					 fse.max_height);
1537fc2873aaSDale Farnsworth 			}
1538fc2873aaSDale Farnsworth 		}
1539fc2873aaSDale Farnsworth 
1540fc2873aaSDale Farnsworth 		if (f->fmt.pix.width == fse.max_width &&
1541fc2873aaSDale Farnsworth 		    f->fmt.pix.height == fse.max_height) {
1542fc2873aaSDale Farnsworth 			found = true;
1543fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt loop:%d found direct match: %dx%d\n",
1544fc2873aaSDale Farnsworth 				 fse.index, fse.max_width,
1545fc2873aaSDale Farnsworth 				 fse.max_height);
1546fc2873aaSDale Farnsworth 			break;
1547fc2873aaSDale Farnsworth 		}
1548fc2873aaSDale Farnsworth 
1549fc2873aaSDale Farnsworth 		if (f->fmt.pix.width >= fse.min_width &&
1550fc2873aaSDale Farnsworth 		    f->fmt.pix.width <= fse.max_width &&
1551fc2873aaSDale Farnsworth 		    f->fmt.pix.height >= fse.min_height &&
1552fc2873aaSDale Farnsworth 		    f->fmt.pix.height <= fse.max_height) {
1553fc2873aaSDale Farnsworth 			found = true;
1554fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt loop:%d found direct range match: %dx%d\n",
1555fc2873aaSDale Farnsworth 				 fse.index, fse.max_width,
1556fc2873aaSDale Farnsworth 				 fse.max_height);
1557fc2873aaSDale Farnsworth 			break;
1558fc2873aaSDale Farnsworth 		}
1559fc2873aaSDale Farnsworth 	}
1560fc2873aaSDale Farnsworth 
1561fc2873aaSDale Farnsworth 	if (found) {
1562fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.width = f->fmt.pix.width;
1563fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.height = f->fmt.pix.height;
1564fc2873aaSDale Farnsworth 		/* No need to check for scaling */
1565fc2873aaSDale Farnsworth 		goto calc_size;
1566fc2873aaSDale Farnsworth 	} else if (f->fmt.pix.width > largest_width) {
1567fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.width = largest_width;
1568fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.height = largest_height;
1569fc2873aaSDale Farnsworth 	} else if (best_width) {
1570fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.width = best_width;
1571fc2873aaSDale Farnsworth 		port->try_mbus_framefmt.height = best_height;
1572fc2873aaSDale Farnsworth 	} else {
1573fc2873aaSDale Farnsworth 		/* use existing values as default */
1574fc2873aaSDale Farnsworth 	}
1575fc2873aaSDale Farnsworth 
1576fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "try_fmt best subdev size: %dx%d\n",
1577fc2873aaSDale Farnsworth 		 port->try_mbus_framefmt.width,
1578fc2873aaSDale Farnsworth 		 port->try_mbus_framefmt.height);
1579fc2873aaSDale Farnsworth 
1580fc2873aaSDale Farnsworth 	if (is_scaler_available(port) &&
1581fc2873aaSDale Farnsworth 	    csc_direction != VIP_CSC_Y2R &&
1582fc2873aaSDale Farnsworth 	    !vip_is_mbuscode_raw(fmt->code) &&
1583fc2873aaSDale Farnsworth 	    f->fmt.pix.height <= port->try_mbus_framefmt.height &&
1584fc2873aaSDale Farnsworth 	    port->try_mbus_framefmt.height <= SC_MAX_PIXEL_HEIGHT &&
1585fc2873aaSDale Farnsworth 	    port->try_mbus_framefmt.width <= SC_MAX_PIXEL_WIDTH) {
1586fc2873aaSDale Farnsworth 		/*
1587fc2873aaSDale Farnsworth 		 * Scaler is only accessible if the dst colorspace is YUV.
1588fc2873aaSDale Farnsworth 		 * As the input to the scaler must be in YUV mode only.
1589fc2873aaSDale Farnsworth 		 *
1590fc2873aaSDale Farnsworth 		 * Scaling up is allowed only horizontally.
1591fc2873aaSDale Farnsworth 		 */
1592fc2873aaSDale Farnsworth 		unsigned int hratio, vratio, width_align, height_align;
1593fc2873aaSDale Farnsworth 		u32 bpp = fmt->vpdma_fmt[0]->depth >> 3;
1594fc2873aaSDale Farnsworth 
1595fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Scaler active on Port %c: requesting %dx%d\n",
1596fc2873aaSDale Farnsworth 			 port->port_id == VIP_PORTA ? 'A' : 'B',
1597fc2873aaSDale Farnsworth 			 f->fmt.pix.width, f->fmt.pix.height);
1598fc2873aaSDale Farnsworth 
1599fc2873aaSDale Farnsworth 		/* Just make sure everything is properly aligned */
1600fc2873aaSDale Farnsworth 		width_align = ALIGN(f->fmt.pix.width * bpp, VPDMA_STRIDE_ALIGN);
1601fc2873aaSDale Farnsworth 		width_align /= bpp;
1602fc2873aaSDale Farnsworth 		height_align = ALIGN(f->fmt.pix.height, 2);
1603fc2873aaSDale Farnsworth 
1604fc2873aaSDale Farnsworth 		f->fmt.pix.width = width_align;
1605fc2873aaSDale Farnsworth 		f->fmt.pix.height = height_align;
1606fc2873aaSDale Farnsworth 
1607fc2873aaSDale Farnsworth 		hratio = f->fmt.pix.width * 1000 /
1608fc2873aaSDale Farnsworth 			 port->try_mbus_framefmt.width;
1609fc2873aaSDale Farnsworth 		vratio = f->fmt.pix.height * 1000 /
1610fc2873aaSDale Farnsworth 			 port->try_mbus_framefmt.height;
1611fc2873aaSDale Farnsworth 		if (hratio < 125) {
1612fc2873aaSDale Farnsworth 			f->fmt.pix.width = port->try_mbus_framefmt.width / 8;
1613fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "Horizontal scaling ratio out of range adjusting -> %d\n",
1614fc2873aaSDale Farnsworth 				 f->fmt.pix.width);
1615fc2873aaSDale Farnsworth 		}
1616fc2873aaSDale Farnsworth 
1617fc2873aaSDale Farnsworth 		if (vratio < 188) {
1618fc2873aaSDale Farnsworth 			f->fmt.pix.height = port->try_mbus_framefmt.height / 4;
1619fc2873aaSDale Farnsworth 			v4l2_dbg(3, debug, &dev->v4l2_dev, "Vertical scaling ratio out of range adjusting -> %d\n",
1620fc2873aaSDale Farnsworth 				 f->fmt.pix.height);
1621fc2873aaSDale Farnsworth 		}
1622fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Scaler: got %dx%d\n",
1623fc2873aaSDale Farnsworth 			 f->fmt.pix.width, f->fmt.pix.height);
1624fc2873aaSDale Farnsworth 	} else {
1625fc2873aaSDale Farnsworth 		/* use existing values as default */
1626fc2873aaSDale Farnsworth 		f->fmt.pix.width = port->try_mbus_framefmt.width;
1627fc2873aaSDale Farnsworth 		f->fmt.pix.height = port->try_mbus_framefmt.height;
1628fc2873aaSDale Farnsworth 	}
1629fc2873aaSDale Farnsworth 
1630fc2873aaSDale Farnsworth calc_size:
1631fc2873aaSDale Farnsworth 	/* That we have a fmt calculate imagesize and bytesperline */
1632fc2873aaSDale Farnsworth 	return vip_calc_format_size(port, fmt, f);
1633fc2873aaSDale Farnsworth }
1634fc2873aaSDale Farnsworth 
vip_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1635fc2873aaSDale Farnsworth static int vip_g_fmt_vid_cap(struct file *file, void *priv,
1636fc2873aaSDale Farnsworth 			     struct v4l2_format *f)
1637fc2873aaSDale Farnsworth {
1638fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1639fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1640fc2873aaSDale Farnsworth 
1641fc2873aaSDale Farnsworth 	/* Use last known values or defaults */
1642fc2873aaSDale Farnsworth 	f->fmt.pix.width	= stream->width;
1643fc2873aaSDale Farnsworth 	f->fmt.pix.height	= stream->height;
1644fc2873aaSDale Farnsworth 	f->fmt.pix.pixelformat	= port->fmt->fourcc;
1645fc2873aaSDale Farnsworth 	f->fmt.pix.field	= stream->sup_field;
1646fc2873aaSDale Farnsworth 	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;
1647fc2873aaSDale Farnsworth 	f->fmt.pix.bytesperline	= stream->bytesperline;
1648fc2873aaSDale Farnsworth 	f->fmt.pix.sizeimage	= stream->sizeimage;
1649fc2873aaSDale Farnsworth 
1650fc2873aaSDale Farnsworth 	return 0;
1651fc2873aaSDale Farnsworth }
1652fc2873aaSDale Farnsworth 
vip_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)1653fc2873aaSDale Farnsworth static int vip_s_fmt_vid_cap(struct file *file, void *priv,
1654fc2873aaSDale Farnsworth 			     struct v4l2_format *f)
1655fc2873aaSDale Farnsworth {
1656fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
1657fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1658fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
1659fc2873aaSDale Farnsworth 	struct v4l2_subdev_format sfmt;
1660fc2873aaSDale Farnsworth 	struct v4l2_mbus_framefmt *mf;
1661fc2873aaSDale Farnsworth 	enum vip_csc_state csc_direction;
1662fc2873aaSDale Farnsworth 	int ret;
1663fc2873aaSDale Farnsworth 
1664fc2873aaSDale Farnsworth 	ret = vip_try_fmt_vid_cap(file, priv, f);
1665fc2873aaSDale Farnsworth 	if (ret)
1666fc2873aaSDale Farnsworth 		return ret;
1667fc2873aaSDale Farnsworth 
1668fc2873aaSDale Farnsworth 	if (vb2_is_busy(&stream->vb_vidq)) {
1669fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
1670fc2873aaSDale Farnsworth 		return -EBUSY;
1671fc2873aaSDale Farnsworth 	}
1672fc2873aaSDale Farnsworth 
1673fc2873aaSDale Farnsworth 	/*
1674fc2873aaSDale Farnsworth 	 * Check if we need the scaler or not
1675fc2873aaSDale Farnsworth 	 *
1676fc2873aaSDale Farnsworth 	 * Since on previous S_FMT call the scaler might have been
1677fc2873aaSDale Farnsworth 	 * allocated if it is not needed in this instance we will
1678fc2873aaSDale Farnsworth 	 * attempt to free it just in case.
1679fc2873aaSDale Farnsworth 	 *
1680fc2873aaSDale Farnsworth 	 * free_scaler() is harmless unless the current port
1681fc2873aaSDale Farnsworth 	 * allocated it.
1682fc2873aaSDale Farnsworth 	 */
1683fc2873aaSDale Farnsworth 	if (f->fmt.pix.width == port->try_mbus_framefmt.width &&
1684fc2873aaSDale Farnsworth 	    f->fmt.pix.height == port->try_mbus_framefmt.height)
1685fc2873aaSDale Farnsworth 		free_scaler(port);
1686fc2873aaSDale Farnsworth 	else
1687fc2873aaSDale Farnsworth 		allocate_scaler(port);
1688fc2873aaSDale Farnsworth 
1689fc2873aaSDale Farnsworth 	port->fmt = find_port_format_by_pix(port,
1690fc2873aaSDale Farnsworth 					    f->fmt.pix.pixelformat);
1691fc2873aaSDale Farnsworth 	stream->width		= f->fmt.pix.width;
1692fc2873aaSDale Farnsworth 	stream->height		= f->fmt.pix.height;
1693fc2873aaSDale Farnsworth 	stream->bytesperline	= f->fmt.pix.bytesperline;
1694fc2873aaSDale Farnsworth 	stream->sizeimage	= f->fmt.pix.sizeimage;
1695fc2873aaSDale Farnsworth 	stream->sup_field	= f->fmt.pix.field;
1696fc2873aaSDale Farnsworth 	stream->field		= f->fmt.pix.field;
1697fc2873aaSDale Farnsworth 
1698fc2873aaSDale Farnsworth 	port->c_rect.left	= 0;
1699fc2873aaSDale Farnsworth 	port->c_rect.top	= 0;
1700fc2873aaSDale Farnsworth 	port->c_rect.width	= stream->width;
1701fc2873aaSDale Farnsworth 	port->c_rect.height	= stream->height;
1702fc2873aaSDale Farnsworth 
1703fc2873aaSDale Farnsworth 	/*
1704fc2873aaSDale Farnsworth 	 * Check if we need the csc unit or not
1705fc2873aaSDale Farnsworth 	 *
1706fc2873aaSDale Farnsworth 	 * Since on previous S_FMT call, the csc might have been
1707fc2873aaSDale Farnsworth 	 * allocated if it is not needed in this instance we will
1708fc2873aaSDale Farnsworth 	 * attempt to free it just in case.
1709fc2873aaSDale Farnsworth 	 *
1710fc2873aaSDale Farnsworth 	 * free_csc() is harmless unless the current port
1711fc2873aaSDale Farnsworth 	 * allocated it.
1712fc2873aaSDale Farnsworth 	 */
1713fc2873aaSDale Farnsworth 	csc_direction =  vip_csc_direction(port->fmt->code, port->fmt->finfo);
1714fc2873aaSDale Farnsworth 	if (csc_direction == VIP_CSC_NA)
1715fc2873aaSDale Farnsworth 		free_csc(port);
1716fc2873aaSDale Farnsworth 	else
1717fc2873aaSDale Farnsworth 		allocate_csc(port, csc_direction);
1718fc2873aaSDale Farnsworth 
1719fc2873aaSDale Farnsworth 	if (stream->sup_field == V4L2_FIELD_ALTERNATE)
1720fc2873aaSDale Farnsworth 		port->flags |= FLAG_INTERLACED;
1721fc2873aaSDale Farnsworth 	else
1722fc2873aaSDale Farnsworth 		port->flags &= ~FLAG_INTERLACED;
1723fc2873aaSDale Farnsworth 
1724fc2873aaSDale Farnsworth 	memset(&sfmt, 0, sizeof(sfmt));
1725fc2873aaSDale Farnsworth 	mf = &sfmt.format;
1726fc2873aaSDale Farnsworth 	v4l2_fill_mbus_format(mf, &f->fmt.pix, port->fmt->code);
1727fc2873aaSDale Farnsworth 	/* Make sure to use the subdev size found in the try_fmt */
1728fc2873aaSDale Farnsworth 	mf->width = port->try_mbus_framefmt.width;
1729fc2873aaSDale Farnsworth 	mf->height = port->try_mbus_framefmt.height;
1730fc2873aaSDale Farnsworth 
1731fc2873aaSDale Farnsworth 	sfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
1732fc2873aaSDale Farnsworth 	sfmt.pad = 0;
1733fc2873aaSDale Farnsworth 	ret = v4l2_subdev_call(port->subdev, pad, set_fmt, NULL, &sfmt);
1734fc2873aaSDale Farnsworth 	if (ret) {
1735fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "set_fmt failed in subdev\n");
1736fc2873aaSDale Farnsworth 		return ret;
1737fc2873aaSDale Farnsworth 	}
1738fc2873aaSDale Farnsworth 
1739fc2873aaSDale Farnsworth 	/* Save it */
1740fc2873aaSDale Farnsworth 	port->mbus_framefmt = *mf;
1741fc2873aaSDale Farnsworth 
1742fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "s_fmt subdev fmt mbus_code: %04X size: %dx%d\n",
1743fc2873aaSDale Farnsworth 		 port->mbus_framefmt.code,
1744fc2873aaSDale Farnsworth 		 port->mbus_framefmt.width, port->mbus_framefmt.height);
1745fc2873aaSDale Farnsworth 
1746fc2873aaSDale Farnsworth 	return 0;
1747fc2873aaSDale Farnsworth }
1748fc2873aaSDale Farnsworth 
vip_unset_csc_y2r(struct vip_dev * dev,struct vip_port * port)1749fc2873aaSDale Farnsworth static void vip_unset_csc_y2r(struct vip_dev *dev, struct vip_port *port)
1750fc2873aaSDale Farnsworth {
1751fc2873aaSDale Farnsworth 	if (port->port_id == VIP_PORTA) {
1752fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 0);
1753fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1754fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1755fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_SRC_DATA_SELECT, 0);
1756fc2873aaSDale Farnsworth 	} else {
1757fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 0);
1758fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1759fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1760fc2873aaSDale Farnsworth 	}
1761fc2873aaSDale Farnsworth }
1762fc2873aaSDale Farnsworth 
vip_unset_csc_r2y(struct vip_dev * dev,struct vip_port * port)1763fc2873aaSDale Farnsworth static void vip_unset_csc_r2y(struct vip_dev *dev, struct vip_port *port)
1764fc2873aaSDale Farnsworth {
1765fc2873aaSDale Farnsworth 	if (port->port_id != VIP_PORTA) {
1766fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "RGB sensor can only be on Port A\n");
1767fc2873aaSDale Farnsworth 		return;
1768fc2873aaSDale Farnsworth 	}
1769fc2873aaSDale Farnsworth 
1770fc2873aaSDale Farnsworth 	if (port->scaler && port->fmt->coplanar) {
1771fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 0);
1772fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1773fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1774fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1775fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1776fc2873aaSDale Farnsworth 	} else if (port->scaler) {
1777fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 0);
1778fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1779fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1780fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1781fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1782fc2873aaSDale Farnsworth 	} else if (port->fmt->coplanar) {
1783fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 0);
1784fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1785fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1786fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1787fc2873aaSDale Farnsworth 	}
1788fc2873aaSDale Farnsworth }
1789fc2873aaSDale Farnsworth 
vip_unset_rgb(struct vip_dev * dev,struct vip_port * port)1790fc2873aaSDale Farnsworth static void vip_unset_rgb(struct vip_dev *dev, struct vip_port *port)
1791fc2873aaSDale Farnsworth {
1792fc2873aaSDale Farnsworth 	if (port->port_id != VIP_PORTA) {
1793fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "RGB sensor can only be on Port A\n");
1794fc2873aaSDale Farnsworth 		return;
1795fc2873aaSDale Farnsworth 	}
1796fc2873aaSDale Farnsworth 
1797fc2873aaSDale Farnsworth 	vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1798fc2873aaSDale Farnsworth 	vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1799fc2873aaSDale Farnsworth }
1800fc2873aaSDale Farnsworth 
vip_unset_yuv(struct vip_dev * dev,struct vip_port * port)1801fc2873aaSDale Farnsworth static void vip_unset_yuv(struct vip_dev *dev, struct vip_port *port)
1802fc2873aaSDale Farnsworth {
1803fc2873aaSDale Farnsworth 	if (port->scaler && port->fmt->coplanar) {
1804fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1805fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1806fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1807fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1808fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1809fc2873aaSDale Farnsworth 		} else {
1810fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1811fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 0);
1812fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1813fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1814fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1815fc2873aaSDale Farnsworth 		}
1816fc2873aaSDale Farnsworth 	} else if (port->scaler) {
1817fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1818fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1819fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1820fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1821fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1822fc2873aaSDale Farnsworth 		} else {
1823fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 0);
1824fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 0);
1825fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1826fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_DATA_BYPASS, 0);
1827fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1828fc2873aaSDale Farnsworth 		}
1829fc2873aaSDale Farnsworth 	} else if (port->fmt->coplanar) {
1830fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1831fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 0);
1832fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1833fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1834fc2873aaSDale Farnsworth 		} else {
1835fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 0);
1836fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_DATA_BYPASS, 0);
1837fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1838fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1839fc2873aaSDale Farnsworth 		}
1840fc2873aaSDale Farnsworth 	} else {
1841fc2873aaSDale Farnsworth 		/*
1842fc2873aaSDale Farnsworth 		 * We undo all data path setting except for the multi
1843fc2873aaSDale Farnsworth 		 * stream case.
1844fc2873aaSDale Farnsworth 		 * Because we cannot disrupt other on-going capture if only
1845fc2873aaSDale Farnsworth 		 * one stream is terminated the other might still be going
1846fc2873aaSDale Farnsworth 		 */
1847fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 1);
1848fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1849fc2873aaSDale Farnsworth 	}
1850fc2873aaSDale Farnsworth }
1851fc2873aaSDale Farnsworth 
1852fc2873aaSDale Farnsworth /*
1853fc2873aaSDale Farnsworth  * Does the exact opposite of set_fmt_params
1854fc2873aaSDale Farnsworth  * It makes sure the DataPath register is sane after tear down
1855fc2873aaSDale Farnsworth  */
unset_fmt_params(struct vip_stream * stream)1856fc2873aaSDale Farnsworth static void unset_fmt_params(struct vip_stream *stream)
1857fc2873aaSDale Farnsworth {
1858fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
1859fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
1860fc2873aaSDale Farnsworth 
1861fc2873aaSDale Farnsworth 	stream->sequence = 0;
1862fc2873aaSDale Farnsworth 	stream->field = V4L2_FIELD_TOP;
1863fc2873aaSDale Farnsworth 
1864fc2873aaSDale Farnsworth 	/* Undo CSC Y2R routing */
1865fc2873aaSDale Farnsworth 	if (port->csc == VIP_CSC_Y2R) {
1866fc2873aaSDale Farnsworth 		vip_unset_csc_y2r(dev, port);
1867fc2873aaSDale Farnsworth 	/* Undo CSC R2Y routing */
1868fc2873aaSDale Farnsworth 	} else if (port->csc == VIP_CSC_R2Y) {
1869fc2873aaSDale Farnsworth 		vip_unset_csc_r2y(dev, port);
1870fc2873aaSDale Farnsworth 	/* Undo RGB output routing (no CSC) */
1871fc2873aaSDale Farnsworth 	} else if (v4l2_is_format_rgb(port->fmt->finfo)) {
1872fc2873aaSDale Farnsworth 		vip_unset_rgb(dev, port);
1873fc2873aaSDale Farnsworth 	/* Undo YUV routing with no CSC */
1874fc2873aaSDale Farnsworth 	} else {
1875fc2873aaSDale Farnsworth 		vip_unset_yuv(dev, port);
1876fc2873aaSDale Farnsworth 	}
1877fc2873aaSDale Farnsworth }
1878fc2873aaSDale Farnsworth 
vip_config_csc_y2r(struct vip_dev * dev,struct vip_port * port)1879fc2873aaSDale Farnsworth static void vip_config_csc_y2r(struct vip_dev *dev, struct vip_port *port)
1880fc2873aaSDale Farnsworth {
1881fc2873aaSDale Farnsworth 	port->flags &= ~FLAG_MULT_PORT;
1882fc2873aaSDale Farnsworth 
1883fc2873aaSDale Farnsworth 	/* Set alpha component in background color */
1884fc2873aaSDale Farnsworth 	vpdma_set_bg_color(dev->shared->vpdma,
1885fc2873aaSDale Farnsworth 			   (struct vpdma_data_format *)
1886fc2873aaSDale Farnsworth 			   port->fmt->vpdma_fmt[0],
1887fc2873aaSDale Farnsworth 			   0xff);
1888fc2873aaSDale Farnsworth 
1889fc2873aaSDale Farnsworth 	if (port->port_id == VIP_PORTA) {
1890fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 1);
1891fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1892fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 1);
1893fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_SRC_DATA_SELECT, 1);
1894fc2873aaSDale Farnsworth 	} else {
1895fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 2);
1896fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1897fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 1);
1898fc2873aaSDale Farnsworth 	}
1899fc2873aaSDale Farnsworth }
1900fc2873aaSDale Farnsworth 
vip_config_csc_r2y(struct vip_dev * dev,struct vip_port * port)1901fc2873aaSDale Farnsworth static void vip_config_csc_r2y(struct vip_dev *dev, struct vip_port *port)
1902fc2873aaSDale Farnsworth {
1903fc2873aaSDale Farnsworth 	if (port->port_id != VIP_PORTA) {
1904fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "RGB sensor can only be on Port A\n");
1905fc2873aaSDale Farnsworth 		return;
1906fc2873aaSDale Farnsworth 	}
1907fc2873aaSDale Farnsworth 
1908fc2873aaSDale Farnsworth 	port->flags &= ~FLAG_MULT_PORT;
1909fc2873aaSDale Farnsworth 
1910fc2873aaSDale Farnsworth 	if (port->scaler && port->fmt->coplanar) {
1911fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 4);
1912fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 1);
1913fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 1);
1914fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1915fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1916fc2873aaSDale Farnsworth 	} else if (port->scaler) {
1917fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 4);
1918fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 1);
1919fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 1);
1920fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 1);
1921fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1922fc2873aaSDale Farnsworth 	} else if (port->fmt->coplanar) {
1923fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 4);
1924fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 2);
1925fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1926fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1927fc2873aaSDale Farnsworth 	} else {
1928fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CSC_SRC_DATA_SELECT, 4);
1929fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 2);
1930fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 1);
1931fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1932fc2873aaSDale Farnsworth 	}
1933fc2873aaSDale Farnsworth }
1934fc2873aaSDale Farnsworth 
vip_config_rgb(struct vip_dev * dev,struct vip_port * port)1935fc2873aaSDale Farnsworth static void vip_config_rgb(struct vip_dev *dev, struct vip_port *port)
1936fc2873aaSDale Farnsworth {
1937fc2873aaSDale Farnsworth 	if (port->port_id != VIP_PORTA) {
1938fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "RGB sensor can only be on Port A\n");
1939fc2873aaSDale Farnsworth 		return;
1940fc2873aaSDale Farnsworth 	}
1941fc2873aaSDale Farnsworth 
1942fc2873aaSDale Farnsworth 	port->flags &= ~FLAG_MULT_PORT;
1943fc2873aaSDale Farnsworth 
1944fc2873aaSDale Farnsworth 	/* Set alpha component in background color */
1945fc2873aaSDale Farnsworth 	vpdma_set_bg_color(dev->shared->vpdma,
1946fc2873aaSDale Farnsworth 			   (struct vpdma_data_format *)
1947fc2873aaSDale Farnsworth 			   port->fmt->vpdma_fmt[0],
1948fc2873aaSDale Farnsworth 			   0xff);
1949fc2873aaSDale Farnsworth 
1950fc2873aaSDale Farnsworth 	vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 1);
1951fc2873aaSDale Farnsworth 	vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 1);
1952fc2873aaSDale Farnsworth }
1953fc2873aaSDale Farnsworth 
vip_config_yuv(struct vip_dev * dev,struct vip_port * port)1954fc2873aaSDale Farnsworth static void vip_config_yuv(struct vip_dev *dev, struct vip_port *port)
1955fc2873aaSDale Farnsworth {
1956fc2873aaSDale Farnsworth 	if (port->scaler && port->fmt->coplanar) {
1957fc2873aaSDale Farnsworth 		port->flags &= ~FLAG_MULT_PORT;
1958fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1959fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 2);
1960fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 1);
1961fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1962fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1963fc2873aaSDale Farnsworth 		} else {
1964fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 3);
1965fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 1);
1966fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1967fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1968fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1969fc2873aaSDale Farnsworth 		}
1970fc2873aaSDale Farnsworth 	} else if (port->scaler) {
1971fc2873aaSDale Farnsworth 		port->flags &= ~FLAG_MULT_PORT;
1972fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1973fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 2);
1974fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 1);
1975fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 1);
1976fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1977fc2873aaSDale Farnsworth 		} else {
1978fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_SC_SRC_DATA_SELECT, 3);
1979fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 1);
1980fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 1);
1981fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_DATA_BYPASS, 1);
1982fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1983fc2873aaSDale Farnsworth 		}
1984fc2873aaSDale Farnsworth 	} else if (port->fmt->coplanar) {
1985fc2873aaSDale Farnsworth 		port->flags &= ~FLAG_MULT_PORT;
1986fc2873aaSDale Farnsworth 		if (port->port_id == VIP_PORTA) {
1987fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_SRC_DATA_SELECT, 3);
1988fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_1_DATA_BYPASS, 0);
1989fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_HI_DATA_SELECT, 0);
1990fc2873aaSDale Farnsworth 		} else {
1991fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_SRC_DATA_SELECT, 4);
1992fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_CHR_DS_2_DATA_BYPASS, 0);
1993fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 0);
1994fc2873aaSDale Farnsworth 			vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
1995fc2873aaSDale Farnsworth 		}
1996fc2873aaSDale Farnsworth 	} else {
1997fc2873aaSDale Farnsworth 		port->flags |= FLAG_MULT_PORT;
1998fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 1);
1999fc2873aaSDale Farnsworth 		vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT, 0);
2000fc2873aaSDale Farnsworth 	}
2001fc2873aaSDale Farnsworth }
2002fc2873aaSDale Farnsworth 
2003fc2873aaSDale Farnsworth /*
2004fc2873aaSDale Farnsworth  * Set the registers that are modified when the video format changes.
2005fc2873aaSDale Farnsworth  */
set_fmt_params(struct vip_stream * stream)2006fc2873aaSDale Farnsworth static void set_fmt_params(struct vip_stream *stream)
2007fc2873aaSDale Farnsworth {
2008fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2009fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2010fc2873aaSDale Farnsworth 
2011fc2873aaSDale Farnsworth 	stream->sequence = 0;
2012fc2873aaSDale Farnsworth 	stream->field = V4L2_FIELD_TOP;
2013fc2873aaSDale Farnsworth 
2014fc2873aaSDale Farnsworth 	/* YUV input, RGB output using CSC (Y2R) */
2015fc2873aaSDale Farnsworth 	if (port->csc == VIP_CSC_Y2R) {
2016fc2873aaSDale Farnsworth 		vip_config_csc_y2r(dev, port);
2017fc2873aaSDale Farnsworth 	/* RGB input, YUV output using CSC (R2Y) */
2018fc2873aaSDale Farnsworth 	} else if (port->csc == VIP_CSC_R2Y) {
2019fc2873aaSDale Farnsworth 		vip_config_csc_r2y(dev, port);
2020fc2873aaSDale Farnsworth 	/* RGB output without CSC */
2021fc2873aaSDale Farnsworth 	} else if (v4l2_is_format_rgb(port->fmt->finfo)) {
2022fc2873aaSDale Farnsworth 		vip_config_rgb(dev, port);
2023fc2873aaSDale Farnsworth 	/* YUV output without CSC */
2024fc2873aaSDale Farnsworth 	} else {
2025fc2873aaSDale Farnsworth 		vip_config_yuv(dev, port);
2026fc2873aaSDale Farnsworth 	}
2027fc2873aaSDale Farnsworth }
2028fc2873aaSDale Farnsworth 
vip_g_selection(struct file * file,void * fh,struct v4l2_selection * s)2029fc2873aaSDale Farnsworth static int vip_g_selection(struct file *file, void *fh,
2030fc2873aaSDale Farnsworth 			   struct v4l2_selection *s)
2031fc2873aaSDale Farnsworth {
2032fc2873aaSDale Farnsworth 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2033fc2873aaSDale Farnsworth 		return -EINVAL;
2034fc2873aaSDale Farnsworth 
2035fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
2036fc2873aaSDale Farnsworth 
2037fc2873aaSDale Farnsworth 	switch (s->target) {
2038fc2873aaSDale Farnsworth 	case V4L2_SEL_TGT_CROP_BOUNDS:
2039fc2873aaSDale Farnsworth 	case V4L2_SEL_TGT_CROP_DEFAULT:
2040fc2873aaSDale Farnsworth 		s->r.left = 0;
2041fc2873aaSDale Farnsworth 		s->r.top = 0;
2042fc2873aaSDale Farnsworth 		s->r.width = stream->width;
2043fc2873aaSDale Farnsworth 		s->r.height = stream->height;
2044fc2873aaSDale Farnsworth 		return 0;
2045fc2873aaSDale Farnsworth 
2046fc2873aaSDale Farnsworth 	case V4L2_SEL_TGT_CROP:
2047fc2873aaSDale Farnsworth 		s->r = stream->port->c_rect;
2048fc2873aaSDale Farnsworth 		return 0;
2049fc2873aaSDale Farnsworth 	}
2050fc2873aaSDale Farnsworth 
2051fc2873aaSDale Farnsworth 	return -EINVAL;
2052fc2873aaSDale Farnsworth }
2053fc2873aaSDale Farnsworth 
enclosed_rectangle(struct v4l2_rect * a,struct v4l2_rect * b)2054fc2873aaSDale Farnsworth static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
2055fc2873aaSDale Farnsworth {
2056fc2873aaSDale Farnsworth 	if (a->left < b->left || a->top < b->top)
2057fc2873aaSDale Farnsworth 		return 0;
2058fc2873aaSDale Farnsworth 	if (a->left + a->width > b->left + b->width)
2059fc2873aaSDale Farnsworth 		return 0;
2060fc2873aaSDale Farnsworth 	if (a->top + a->height > b->top + b->height)
2061fc2873aaSDale Farnsworth 		return 0;
2062fc2873aaSDale Farnsworth 
2063fc2873aaSDale Farnsworth 	return 1;
2064fc2873aaSDale Farnsworth }
2065fc2873aaSDale Farnsworth 
vip_s_selection(struct file * file,void * fh,struct v4l2_selection * s)2066fc2873aaSDale Farnsworth static int vip_s_selection(struct file *file, void *fh,
2067fc2873aaSDale Farnsworth 			   struct v4l2_selection *s)
2068fc2873aaSDale Farnsworth {
2069fc2873aaSDale Farnsworth 	struct vip_stream *stream = file2stream(file);
2070fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2071fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2072fc2873aaSDale Farnsworth 	struct v4l2_rect r = s->r;
2073fc2873aaSDale Farnsworth 
2074fc2873aaSDale Farnsworth 	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2075fc2873aaSDale Farnsworth 		return -EINVAL;
2076fc2873aaSDale Farnsworth 
2077fc2873aaSDale Farnsworth 	if (s->target != V4L2_SEL_TGT_CROP)
2078fc2873aaSDale Farnsworth 		return -EINVAL;
2079fc2873aaSDale Farnsworth 
2080fc2873aaSDale Farnsworth 	if (vb2_is_busy(&stream->vb_vidq))
2081fc2873aaSDale Farnsworth 		return -EBUSY;
2082fc2873aaSDale Farnsworth 
2083fc2873aaSDale Farnsworth 	v4l_bound_align_image(&r.width, 0, stream->width, 0,
2084fc2873aaSDale Farnsworth 			      &r.height, 0, stream->height, 0, 0);
2085fc2873aaSDale Farnsworth 
2086fc2873aaSDale Farnsworth 	r.left = clamp_t(unsigned int, r.left, 0, stream->width - r.width);
2087fc2873aaSDale Farnsworth 	r.top  = clamp_t(unsigned int, r.top, 0, stream->height - r.height);
2088fc2873aaSDale Farnsworth 
2089fc2873aaSDale Farnsworth 	if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r))
2090fc2873aaSDale Farnsworth 		return -ERANGE;
2091fc2873aaSDale Farnsworth 
2092fc2873aaSDale Farnsworth 	if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r))
2093fc2873aaSDale Farnsworth 		return -ERANGE;
2094fc2873aaSDale Farnsworth 
2095fc2873aaSDale Farnsworth 	s->r = r;
2096fc2873aaSDale Farnsworth 	stream->port->c_rect = r;
2097fc2873aaSDale Farnsworth 
2098fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "cropped (%d,%d)/%dx%d of %dx%d\n",
2099fc2873aaSDale Farnsworth 		 r.left, r.top, r.width, r.height,
2100fc2873aaSDale Farnsworth 		 stream->width, stream->height);
2101fc2873aaSDale Farnsworth 
2102fc2873aaSDale Farnsworth 	return 0;
2103fc2873aaSDale Farnsworth }
2104fc2873aaSDale Farnsworth 
2105fc2873aaSDale Farnsworth static const struct v4l2_ioctl_ops vip_ioctl_ops = {
2106fc2873aaSDale Farnsworth 	.vidioc_querycap	= vip_querycap,
2107fc2873aaSDale Farnsworth 	.vidioc_enum_input	= vip_enuminput,
2108fc2873aaSDale Farnsworth 	.vidioc_g_input		= vip_g_input,
2109fc2873aaSDale Farnsworth 	.vidioc_s_input		= vip_s_input,
2110fc2873aaSDale Farnsworth 
2111fc2873aaSDale Farnsworth 	.vidioc_querystd	= vip_querystd,
2112fc2873aaSDale Farnsworth 	.vidioc_g_std		= vip_g_std,
2113fc2873aaSDale Farnsworth 	.vidioc_s_std		= vip_s_std,
2114fc2873aaSDale Farnsworth 
2115fc2873aaSDale Farnsworth 	.vidioc_enum_fmt_vid_cap = vip_enum_fmt_vid_cap,
2116fc2873aaSDale Farnsworth 	.vidioc_g_fmt_vid_cap	= vip_g_fmt_vid_cap,
2117fc2873aaSDale Farnsworth 	.vidioc_try_fmt_vid_cap	= vip_try_fmt_vid_cap,
2118fc2873aaSDale Farnsworth 	.vidioc_s_fmt_vid_cap	= vip_s_fmt_vid_cap,
2119fc2873aaSDale Farnsworth 
2120fc2873aaSDale Farnsworth 	.vidioc_enum_frameintervals	= vip_enum_frameintervals,
2121fc2873aaSDale Farnsworth 	.vidioc_enum_framesizes		= vip_enum_framesizes,
2122fc2873aaSDale Farnsworth 	.vidioc_s_parm			= vip_s_parm,
2123fc2873aaSDale Farnsworth 	.vidioc_g_parm			= vip_g_parm,
2124fc2873aaSDale Farnsworth 	.vidioc_g_selection	= vip_g_selection,
2125fc2873aaSDale Farnsworth 	.vidioc_s_selection	= vip_s_selection,
2126fc2873aaSDale Farnsworth 	.vidioc_reqbufs		= vb2_ioctl_reqbufs,
2127fc2873aaSDale Farnsworth 	.vidioc_create_bufs	= vb2_ioctl_create_bufs,
2128fc2873aaSDale Farnsworth 	.vidioc_prepare_buf	= vb2_ioctl_prepare_buf,
2129fc2873aaSDale Farnsworth 	.vidioc_querybuf	= vb2_ioctl_querybuf,
2130fc2873aaSDale Farnsworth 	.vidioc_qbuf		= vb2_ioctl_qbuf,
2131fc2873aaSDale Farnsworth 	.vidioc_dqbuf		= vb2_ioctl_dqbuf,
2132fc2873aaSDale Farnsworth 	.vidioc_expbuf		= vb2_ioctl_expbuf,
2133fc2873aaSDale Farnsworth 
2134fc2873aaSDale Farnsworth 	.vidioc_streamon	= vb2_ioctl_streamon,
2135fc2873aaSDale Farnsworth 	.vidioc_streamoff	= vb2_ioctl_streamoff,
2136fc2873aaSDale Farnsworth 	.vidioc_log_status	= v4l2_ctrl_log_status,
2137fc2873aaSDale Farnsworth 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
2138fc2873aaSDale Farnsworth 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
2139fc2873aaSDale Farnsworth };
2140fc2873aaSDale Farnsworth 
2141fc2873aaSDale Farnsworth /*
2142fc2873aaSDale Farnsworth  * Videobuf operations
2143fc2873aaSDale Farnsworth  */
vip_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])2144fc2873aaSDale Farnsworth static int vip_queue_setup(struct vb2_queue *vq,
2145fc2873aaSDale Farnsworth 			   unsigned int *nbuffers, unsigned int *nplanes,
2146fc2873aaSDale Farnsworth 			   unsigned int sizes[], struct device *alloc_devs[])
2147fc2873aaSDale Farnsworth {
2148fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vq);
2149fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2150fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2151fc2873aaSDale Farnsworth 	unsigned int size = stream->sizeimage;
2152fc2873aaSDale Farnsworth 
2153fc2873aaSDale Farnsworth 	if (*nplanes)
2154fc2873aaSDale Farnsworth 		return sizes[0] < size ? -EINVAL : 0;
2155fc2873aaSDale Farnsworth 
2156fc2873aaSDale Farnsworth 	*nplanes = 1;
2157fc2873aaSDale Farnsworth 	sizes[0] = size;
2158fc2873aaSDale Farnsworth 
2159fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "get %d buffer(s) of size %d each.\n",
2160fc2873aaSDale Farnsworth 		 *nbuffers, sizes[0]);
2161fc2873aaSDale Farnsworth 
2162fc2873aaSDale Farnsworth 	return 0;
2163fc2873aaSDale Farnsworth }
2164fc2873aaSDale Farnsworth 
vip_buf_prepare(struct vb2_buffer * vb)2165fc2873aaSDale Farnsworth static int vip_buf_prepare(struct vb2_buffer *vb)
2166fc2873aaSDale Farnsworth {
2167fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vb->vb2_queue);
2168fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2169fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2170fc2873aaSDale Farnsworth 
2171fc2873aaSDale Farnsworth 	if (vb2_plane_size(vb, 0) < stream->sizeimage) {
2172fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev,
2173fc2873aaSDale Farnsworth 			 "%s data will not fit into plane (%lu < %lu)\n",
2174fc2873aaSDale Farnsworth 			 __func__, vb2_plane_size(vb, 0),
2175fc2873aaSDale Farnsworth 			(long)stream->sizeimage);
2176fc2873aaSDale Farnsworth 		return -EINVAL;
2177fc2873aaSDale Farnsworth 	}
2178fc2873aaSDale Farnsworth 
2179fc2873aaSDale Farnsworth 	vb2_set_plane_payload(vb, 0, stream->sizeimage);
2180fc2873aaSDale Farnsworth 
2181fc2873aaSDale Farnsworth 	return 0;
2182fc2873aaSDale Farnsworth }
2183fc2873aaSDale Farnsworth 
vip_buf_queue(struct vb2_buffer * vb)2184fc2873aaSDale Farnsworth static void vip_buf_queue(struct vb2_buffer *vb)
2185fc2873aaSDale Farnsworth {
2186fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vb->vb2_queue);
2187fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
2188fc2873aaSDale Farnsworth 	struct vip_buffer *buf = container_of(vb, struct vip_buffer,
2189fc2873aaSDale Farnsworth 					      vb.vb2_buf);
2190fc2873aaSDale Farnsworth 	unsigned long flags;
2191fc2873aaSDale Farnsworth 
2192fc2873aaSDale Farnsworth 	spin_lock_irqsave(&dev->slock, flags);
2193fc2873aaSDale Farnsworth 	list_add_tail(&buf->list, &stream->vidq);
2194fc2873aaSDale Farnsworth 	spin_unlock_irqrestore(&dev->slock, flags);
2195fc2873aaSDale Farnsworth }
2196fc2873aaSDale Farnsworth 
return_buffers(struct vb2_queue * vq,int state)2197fc2873aaSDale Farnsworth static void return_buffers(struct vb2_queue *vq, int state)
2198fc2873aaSDale Farnsworth {
2199fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vq);
2200fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
2201fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
2202fc2873aaSDale Farnsworth 	unsigned long flags;
2203fc2873aaSDale Farnsworth 
2204fc2873aaSDale Farnsworth 	spin_lock_irqsave(&dev->slock, flags);
2205fc2873aaSDale Farnsworth 
2206fc2873aaSDale Farnsworth 	/* release all active buffers */
2207fc2873aaSDale Farnsworth 	while (!list_empty(&stream->post_bufs)) {
2208fc2873aaSDale Farnsworth 		buf = list_entry(stream->post_bufs.next,
2209fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
2210fc2873aaSDale Farnsworth 		list_del(&buf->list);
2211fc2873aaSDale Farnsworth 		if (buf->drop == 1)
2212fc2873aaSDale Farnsworth 			list_add_tail(&buf->list, &stream->dropq);
2213fc2873aaSDale Farnsworth 		else
2214fc2873aaSDale Farnsworth 			vb2_buffer_done(&buf->vb.vb2_buf, state);
2215fc2873aaSDale Farnsworth 	}
2216fc2873aaSDale Farnsworth 	while (!list_empty(&stream->vidq)) {
2217fc2873aaSDale Farnsworth 		buf = list_entry(stream->vidq.next, struct vip_buffer, list);
2218fc2873aaSDale Farnsworth 		list_del(&buf->list);
2219fc2873aaSDale Farnsworth 		vb2_buffer_done(&buf->vb.vb2_buf, state);
2220fc2873aaSDale Farnsworth 	}
2221fc2873aaSDale Farnsworth 
2222fc2873aaSDale Farnsworth 	INIT_LIST_HEAD(&stream->post_bufs);
2223fc2873aaSDale Farnsworth 	INIT_LIST_HEAD(&stream->vidq);
2224fc2873aaSDale Farnsworth 
2225fc2873aaSDale Farnsworth 	spin_unlock_irqrestore(&dev->slock, flags);
2226fc2873aaSDale Farnsworth }
2227fc2873aaSDale Farnsworth 
vip_setup_scaler(struct vip_stream * stream)2228fc2873aaSDale Farnsworth static int vip_setup_scaler(struct vip_stream *stream)
2229fc2873aaSDale Farnsworth {
2230fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2231fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2232fc2873aaSDale Farnsworth 	struct sc_data *sc = dev->sc;
2233fc2873aaSDale Farnsworth 	struct csc_data *csc = dev->csc;
2234fc2873aaSDale Farnsworth 	struct vpdma_data *vpdma = dev->shared->vpdma;
2235fc2873aaSDale Farnsworth 	struct vip_mmr_adb *mmr_adb = port->mmr_adb.addr;
2236fc2873aaSDale Farnsworth 	int list_num = stream->list_num;
2237fc2873aaSDale Farnsworth 	int timeout = 500;
2238fc2873aaSDale Farnsworth 	struct v4l2_format dst_f;
2239fc2873aaSDale Farnsworth 	struct v4l2_format src_f;
2240fc2873aaSDale Farnsworth 
2241fc2873aaSDale Farnsworth 	memset(&src_f, 0, sizeof(src_f));
2242fc2873aaSDale Farnsworth 	src_f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2243fc2873aaSDale Farnsworth 	v4l2_fill_pix_format(&src_f.fmt.pix, &port->mbus_framefmt);
2244fc2873aaSDale Farnsworth 	src_f.fmt.pix.pixelformat = vip_mbus_code_to_fourcc(port->fmt->code);
2245fc2873aaSDale Farnsworth 
2246fc2873aaSDale Farnsworth 	dst_f = src_f;
2247fc2873aaSDale Farnsworth 	dst_f.fmt.pix.pixelformat = port->fmt->fourcc;
2248fc2873aaSDale Farnsworth 	dst_f.fmt.pix.width = stream->width;
2249fc2873aaSDale Farnsworth 	dst_f.fmt.pix.height = stream->height;
2250fc2873aaSDale Farnsworth 
2251fc2873aaSDale Farnsworth 	/* if scaler not associated with this port then skip */
2252fc2873aaSDale Farnsworth 	if (port->scaler) {
2253fc2873aaSDale Farnsworth 		sc_set_hs_coeffs(sc, port->sc_coeff_h.addr,
2254fc2873aaSDale Farnsworth 				 port->mbus_framefmt.width,
2255fc2873aaSDale Farnsworth 				 port->c_rect.width);
2256fc2873aaSDale Farnsworth 		sc_set_vs_coeffs(sc, port->sc_coeff_v.addr,
2257fc2873aaSDale Farnsworth 				 port->mbus_framefmt.height,
2258fc2873aaSDale Farnsworth 				 port->c_rect.height);
2259fc2873aaSDale Farnsworth 		sc_config_scaler(sc, &mmr_adb->sc_regs0[0],
2260fc2873aaSDale Farnsworth 				 &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0],
2261fc2873aaSDale Farnsworth 				 port->mbus_framefmt.width,
2262fc2873aaSDale Farnsworth 				 port->mbus_framefmt.height,
2263fc2873aaSDale Farnsworth 				 port->c_rect.width,
2264fc2873aaSDale Farnsworth 				 port->c_rect.height);
2265fc2873aaSDale Farnsworth 		port->load_mmrs = true;
2266fc2873aaSDale Farnsworth 	}
2267fc2873aaSDale Farnsworth 
2268fc2873aaSDale Farnsworth 	/* if csc not associated with this port then skip */
2269fc2873aaSDale Farnsworth 	if (port->csc) {
2270fc2873aaSDale Farnsworth 		csc_set_coeff(csc, &mmr_adb->csc_regs[0],
2271fc2873aaSDale Farnsworth 			      &src_f, &dst_f);
2272fc2873aaSDale Farnsworth 
2273fc2873aaSDale Farnsworth 		port->load_mmrs = true;
2274fc2873aaSDale Farnsworth 	}
2275fc2873aaSDale Farnsworth 
2276fc2873aaSDale Farnsworth 	/* If coeff are already loaded then skip */
2277fc2873aaSDale Farnsworth 	if (!sc->load_coeff_v && !sc->load_coeff_h && !port->load_mmrs)
2278fc2873aaSDale Farnsworth 		return 0;
2279fc2873aaSDale Farnsworth 
2280fc2873aaSDale Farnsworth 	if (vpdma_list_busy(vpdma, list_num)) {
2281fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: List %d is busy\n",
2282fc2873aaSDale Farnsworth 			 __func__, list_num);
2283fc2873aaSDale Farnsworth 	}
2284fc2873aaSDale Farnsworth 
2285fc2873aaSDale Farnsworth 	/* Make sure we start with a clean list */
2286fc2873aaSDale Farnsworth 	vpdma_reset_desc_list(&stream->desc_list);
2287fc2873aaSDale Farnsworth 
2288fc2873aaSDale Farnsworth 	/* config descriptors */
2289fc2873aaSDale Farnsworth 	if (port->load_mmrs) {
2290fc2873aaSDale Farnsworth 		vpdma_map_desc_buf(vpdma, &port->mmr_adb);
2291fc2873aaSDale Farnsworth 		vpdma_add_cfd_adb(&stream->desc_list, CFD_MMR_CLIENT,
2292fc2873aaSDale Farnsworth 				  &port->mmr_adb);
2293fc2873aaSDale Farnsworth 
2294fc2873aaSDale Farnsworth 		port->load_mmrs = false;
2295fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Added mmr_adb config desc\n");
2296fc2873aaSDale Farnsworth 	}
2297fc2873aaSDale Farnsworth 
2298fc2873aaSDale Farnsworth 	if (sc->loaded_coeff_h != port->sc_coeff_h.dma_addr ||
2299fc2873aaSDale Farnsworth 	    sc->load_coeff_h) {
2300fc2873aaSDale Farnsworth 		vpdma_map_desc_buf(vpdma, &port->sc_coeff_h);
2301fc2873aaSDale Farnsworth 		vpdma_add_cfd_block(&stream->desc_list,
2302fc2873aaSDale Farnsworth 				    VIP_SLICE1_CFD_SC_CLIENT + dev->slice_id,
2303fc2873aaSDale Farnsworth 				    &port->sc_coeff_h, 0);
2304fc2873aaSDale Farnsworth 
2305fc2873aaSDale Farnsworth 		sc->loaded_coeff_h = port->sc_coeff_h.dma_addr;
2306fc2873aaSDale Farnsworth 		sc->load_coeff_h = false;
2307fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Added sc_coeff_h config desc\n");
2308fc2873aaSDale Farnsworth 	}
2309fc2873aaSDale Farnsworth 
2310fc2873aaSDale Farnsworth 	if (sc->loaded_coeff_v != port->sc_coeff_v.dma_addr ||
2311fc2873aaSDale Farnsworth 	    sc->load_coeff_v) {
2312fc2873aaSDale Farnsworth 		vpdma_map_desc_buf(vpdma, &port->sc_coeff_v);
2313fc2873aaSDale Farnsworth 		vpdma_add_cfd_block(&stream->desc_list,
2314fc2873aaSDale Farnsworth 				    VIP_SLICE1_CFD_SC_CLIENT + dev->slice_id,
2315fc2873aaSDale Farnsworth 				    &port->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4);
2316fc2873aaSDale Farnsworth 
2317fc2873aaSDale Farnsworth 		sc->loaded_coeff_v = port->sc_coeff_v.dma_addr;
2318fc2873aaSDale Farnsworth 		sc->load_coeff_v = false;
2319fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Added sc_coeff_v config desc\n");
2320fc2873aaSDale Farnsworth 	}
2321fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, stream, "CFD_SC_CLIENT %d slice_id: %d\n",
2322fc2873aaSDale Farnsworth 		 VIP_SLICE1_CFD_SC_CLIENT + dev->slice_id, dev->slice_id);
2323fc2873aaSDale Farnsworth 
2324fc2873aaSDale Farnsworth 	vpdma_map_desc_buf(vpdma, &stream->desc_list.buf);
2325fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "Submitting desc on list# %d\n", list_num);
2326fc2873aaSDale Farnsworth 	vpdma_submit_descs(vpdma, &stream->desc_list, list_num);
2327fc2873aaSDale Farnsworth 
2328fc2873aaSDale Farnsworth 	while (vpdma_list_busy(vpdma, list_num) && timeout--)
2329fc2873aaSDale Farnsworth 		usleep_range(1000, 1100);
2330fc2873aaSDale Farnsworth 
2331fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &port->mmr_adb);
2332fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &port->sc_coeff_h);
2333fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &port->sc_coeff_v);
2334fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
2335fc2873aaSDale Farnsworth 
2336fc2873aaSDale Farnsworth 	vpdma_reset_desc_list(&stream->desc_list);
2337fc2873aaSDale Farnsworth 
2338fc2873aaSDale Farnsworth 	if (timeout <= 0) {
2339fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "Timed out setting up scaler through VPDMA list\n");
2340fc2873aaSDale Farnsworth 		return -EBUSY;
2341fc2873aaSDale Farnsworth 	}
2342fc2873aaSDale Farnsworth 
2343fc2873aaSDale Farnsworth 	return 0;
2344fc2873aaSDale Farnsworth }
2345fc2873aaSDale Farnsworth 
vip_load_vpdma_list_fifo(struct vip_stream * stream)2346fc2873aaSDale Farnsworth static int vip_load_vpdma_list_fifo(struct vip_stream *stream)
2347fc2873aaSDale Farnsworth {
2348fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2349fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2350fc2873aaSDale Farnsworth 	struct vpdma_data *vpdma = dev->shared->vpdma;
2351fc2873aaSDale Farnsworth 	int list_num = stream->list_num;
2352fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
2353fc2873aaSDale Farnsworth 	unsigned long flags;
2354fc2873aaSDale Farnsworth 	int timeout, i;
2355fc2873aaSDale Farnsworth 
2356fc2873aaSDale Farnsworth 	if (vpdma_list_busy(dev->shared->vpdma, stream->list_num))
2357fc2873aaSDale Farnsworth 		return -EBUSY;
2358fc2873aaSDale Farnsworth 
2359fc2873aaSDale Farnsworth 	for (i = 0; i < VIP_VPDMA_FIFO_SIZE; i++) {
2360fc2873aaSDale Farnsworth 		spin_lock_irqsave(&dev->slock, flags);
2361fc2873aaSDale Farnsworth 		if (list_empty(&stream->vidq)) {
2362fc2873aaSDale Farnsworth 			v4l2_err(&dev->v4l2_dev, "No buffer left!");
2363fc2873aaSDale Farnsworth 			spin_unlock_irqrestore(&dev->slock, flags);
2364fc2873aaSDale Farnsworth 			return -EINVAL;
2365fc2873aaSDale Farnsworth 		}
2366fc2873aaSDale Farnsworth 
2367fc2873aaSDale Farnsworth 		buf = list_entry(stream->vidq.next,
2368fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
2369fc2873aaSDale Farnsworth 		buf->drop = false;
2370fc2873aaSDale Farnsworth 
2371fc2873aaSDale Farnsworth 		list_move_tail(&buf->list, &stream->post_bufs);
2372fc2873aaSDale Farnsworth 		spin_unlock_irqrestore(&dev->slock, flags);
2373fc2873aaSDale Farnsworth 
2374fc2873aaSDale Farnsworth 		v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: start_dma vb2 buf idx:%d\n",
2375fc2873aaSDale Farnsworth 			 __func__, buf->vb.vb2_buf.index);
2376fc2873aaSDale Farnsworth 		start_dma(stream, buf);
2377fc2873aaSDale Farnsworth 
2378fc2873aaSDale Farnsworth 		timeout = 500;
2379fc2873aaSDale Farnsworth 		while (vpdma_list_busy(vpdma, list_num) && timeout--)
2380fc2873aaSDale Farnsworth 			usleep_range(1000, 1100);
2381fc2873aaSDale Farnsworth 
2382fc2873aaSDale Farnsworth 		if (timeout <= 0) {
2383fc2873aaSDale Farnsworth 			v4l2_err(&dev->v4l2_dev, "Timed out loading VPDMA list fifo\n");
2384fc2873aaSDale Farnsworth 			return -EBUSY;
2385fc2873aaSDale Farnsworth 		}
2386fc2873aaSDale Farnsworth 	}
2387fc2873aaSDale Farnsworth 	return 0;
2388fc2873aaSDale Farnsworth }
2389fc2873aaSDale Farnsworth 
vip_start_streaming(struct vb2_queue * vq,unsigned int count)2390fc2873aaSDale Farnsworth static int vip_start_streaming(struct vb2_queue *vq, unsigned int count)
2391fc2873aaSDale Farnsworth {
2392fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vq);
2393fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2394fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2395fc2873aaSDale Farnsworth 	int ret;
2396fc2873aaSDale Farnsworth 
2397fc2873aaSDale Farnsworth 	ret = vip_setup_scaler(stream);
2398fc2873aaSDale Farnsworth 	if (ret)
2399fc2873aaSDale Farnsworth 		goto err;
2400fc2873aaSDale Farnsworth 
2401fc2873aaSDale Farnsworth 	/*
2402fc2873aaSDale Farnsworth 	 * Make sure the scaler is configured before the datapath is
2403fc2873aaSDale Farnsworth 	 * enabled. The scaler can only load the coefficient
2404fc2873aaSDale Farnsworth 	 * parameters when it is idle. If the scaler path is enabled
2405fc2873aaSDale Farnsworth 	 * and video data is being received then the VPDMA transfer will
2406fc2873aaSDale Farnsworth 	 * stall indefinitely.
2407fc2873aaSDale Farnsworth 	 */
2408fc2873aaSDale Farnsworth 	set_fmt_params(stream);
2409fc2873aaSDale Farnsworth 	ret = vip_setup_parser(port);
2410fc2873aaSDale Farnsworth 	if (ret)
2411fc2873aaSDale Farnsworth 		goto err;
2412fc2873aaSDale Farnsworth 
2413fc2873aaSDale Farnsworth 	if (port->subdev) {
2414fc2873aaSDale Farnsworth 		ret = v4l2_subdev_call(port->subdev, video, s_stream, 1);
2415fc2873aaSDale Farnsworth 		if (ret) {
2416fc2873aaSDale Farnsworth 			v4l2_err(&dev->v4l2_dev, "stream on failed in subdev\n");
2417fc2873aaSDale Farnsworth 			goto err;
2418fc2873aaSDale Farnsworth 		}
2419fc2873aaSDale Farnsworth 	}
2420fc2873aaSDale Farnsworth 
2421fc2873aaSDale Farnsworth 	stream->sequence = 0;
2422fc2873aaSDale Farnsworth 	stream->field = V4L2_FIELD_TOP;
2423fc2873aaSDale Farnsworth 	populate_desc_list(stream);
2424fc2873aaSDale Farnsworth 
2425fc2873aaSDale Farnsworth 	ret = vip_load_vpdma_list_fifo(stream);
2426fc2873aaSDale Farnsworth 	if (ret)
2427fc2873aaSDale Farnsworth 		goto err;
2428fc2873aaSDale Farnsworth 
2429fc2873aaSDale Farnsworth 	stream->num_recovery = 0;
2430fc2873aaSDale Farnsworth 
2431fc2873aaSDale Farnsworth 	clear_irqs(dev, dev->slice_id, stream->list_num);
2432fc2873aaSDale Farnsworth 	enable_irqs(dev, dev->slice_id, stream->list_num);
2433fc2873aaSDale Farnsworth 	vip_schedule_next_buffer(stream);
2434fc2873aaSDale Farnsworth 	vip_parser_stop_imm(port, false);
2435fc2873aaSDale Farnsworth 	vip_enable_parser(port, true);
2436fc2873aaSDale Farnsworth 
2437fc2873aaSDale Farnsworth 	return 0;
2438fc2873aaSDale Farnsworth 
2439fc2873aaSDale Farnsworth err:
2440fc2873aaSDale Farnsworth 	return_buffers(vq, VB2_BUF_STATE_QUEUED);
2441fc2873aaSDale Farnsworth 	return ret;
2442fc2873aaSDale Farnsworth }
2443fc2873aaSDale Farnsworth 
2444fc2873aaSDale Farnsworth /*
2445fc2873aaSDale Farnsworth  * Abort streaming and wait for last buffer
2446fc2873aaSDale Farnsworth  */
vip_stop_streaming(struct vb2_queue * vq)2447fc2873aaSDale Farnsworth static void vip_stop_streaming(struct vb2_queue *vq)
2448fc2873aaSDale Farnsworth {
2449fc2873aaSDale Farnsworth 	struct vip_stream *stream = vb2_get_drv_priv(vq);
2450fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2451fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2452fc2873aaSDale Farnsworth 	int ret;
2453fc2873aaSDale Farnsworth 
2454fc2873aaSDale Farnsworth 	vip_parser_stop_imm(port, true);
2455fc2873aaSDale Farnsworth 	vip_enable_parser(port, false);
2456fc2873aaSDale Farnsworth 	unset_fmt_params(stream);
2457fc2873aaSDale Farnsworth 
2458fc2873aaSDale Farnsworth 	disable_irqs(dev, dev->slice_id, stream->list_num);
2459fc2873aaSDale Farnsworth 	clear_irqs(dev, dev->slice_id, stream->list_num);
2460fc2873aaSDale Farnsworth 
2461fc2873aaSDale Farnsworth 	if (port->subdev) {
2462fc2873aaSDale Farnsworth 		ret = v4l2_subdev_call(port->subdev, video, s_stream, 0);
2463fc2873aaSDale Farnsworth 		if (ret)
2464fc2873aaSDale Farnsworth 			v4l2_err(&dev->v4l2_dev, "Failed to stop subdev stream");
2465fc2873aaSDale Farnsworth 	}
2466fc2873aaSDale Farnsworth 
2467fc2873aaSDale Farnsworth 	stop_dma(stream, true);
2468fc2873aaSDale Farnsworth 
2469fc2873aaSDale Farnsworth 	return_buffers(vq, VB2_BUF_STATE_ERROR);
2470fc2873aaSDale Farnsworth 
2471fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
2472fc2873aaSDale Farnsworth 	vpdma_reset_desc_list(&stream->desc_list);
2473fc2873aaSDale Farnsworth }
2474fc2873aaSDale Farnsworth 
2475fc2873aaSDale Farnsworth static const struct vb2_ops vip_video_qops = {
2476fc2873aaSDale Farnsworth 	.queue_setup		= vip_queue_setup,
2477fc2873aaSDale Farnsworth 	.buf_prepare		= vip_buf_prepare,
2478fc2873aaSDale Farnsworth 	.buf_queue		= vip_buf_queue,
2479fc2873aaSDale Farnsworth 	.start_streaming	= vip_start_streaming,
2480fc2873aaSDale Farnsworth 	.stop_streaming		= vip_stop_streaming,
2481fc2873aaSDale Farnsworth };
2482fc2873aaSDale Farnsworth 
vip_init_dev(struct vip_dev * dev)2483fc2873aaSDale Farnsworth static int vip_init_dev(struct vip_dev *dev)
2484fc2873aaSDale Farnsworth {
2485fc2873aaSDale Farnsworth 	if (dev->num_ports != 0)
2486fc2873aaSDale Farnsworth 		goto done;
2487fc2873aaSDale Farnsworth 
2488fc2873aaSDale Farnsworth 	vip_set_clock_enable(dev, 1);
2489fc2873aaSDale Farnsworth 	vip_module_toggle(dev, VIP_SC_RST, false);
2490fc2873aaSDale Farnsworth 	vip_module_toggle(dev, VIP_CSC_RST, false);
2491fc2873aaSDale Farnsworth done:
2492fc2873aaSDale Farnsworth 	dev->num_ports++;
2493fc2873aaSDale Farnsworth 
2494fc2873aaSDale Farnsworth 	return 0;
2495fc2873aaSDale Farnsworth }
2496fc2873aaSDale Farnsworth 
is_scaler_available(struct vip_port * port)2497fc2873aaSDale Farnsworth static inline bool is_scaler_available(struct vip_port *port)
2498fc2873aaSDale Farnsworth {
2499fc2873aaSDale Farnsworth 	if (port->endpoint.bus_type == V4L2_MBUS_PARALLEL)
2500fc2873aaSDale Farnsworth 		if (port->dev->sc_assigned == VIP_NOT_ASSIGNED ||
2501fc2873aaSDale Farnsworth 		    port->dev->sc_assigned == port->port_id)
2502fc2873aaSDale Farnsworth 			return true;
2503fc2873aaSDale Farnsworth 	return false;
2504fc2873aaSDale Farnsworth }
2505fc2873aaSDale Farnsworth 
allocate_scaler(struct vip_port * port)2506fc2873aaSDale Farnsworth static inline bool allocate_scaler(struct vip_port *port)
2507fc2873aaSDale Farnsworth {
2508fc2873aaSDale Farnsworth 	if (is_scaler_available(port)) {
2509fc2873aaSDale Farnsworth 		if (port->dev->sc_assigned == VIP_NOT_ASSIGNED ||
2510fc2873aaSDale Farnsworth 		    port->dev->sc_assigned == port->port_id) {
2511fc2873aaSDale Farnsworth 			port->dev->sc_assigned = port->port_id;
2512fc2873aaSDale Farnsworth 			port->scaler = true;
2513fc2873aaSDale Farnsworth 			return true;
2514fc2873aaSDale Farnsworth 		}
2515fc2873aaSDale Farnsworth 	}
2516fc2873aaSDale Farnsworth 	return false;
2517fc2873aaSDale Farnsworth }
2518fc2873aaSDale Farnsworth 
free_scaler(struct vip_port * port)2519fc2873aaSDale Farnsworth static inline void free_scaler(struct vip_port *port)
2520fc2873aaSDale Farnsworth {
2521fc2873aaSDale Farnsworth 	if (port->dev->sc_assigned == port->port_id) {
2522fc2873aaSDale Farnsworth 		port->dev->sc_assigned = VIP_NOT_ASSIGNED;
2523fc2873aaSDale Farnsworth 		port->scaler = false;
2524fc2873aaSDale Farnsworth 	}
2525fc2873aaSDale Farnsworth }
2526fc2873aaSDale Farnsworth 
is_csc_available(struct vip_port * port)2527fc2873aaSDale Farnsworth static bool is_csc_available(struct vip_port *port)
2528fc2873aaSDale Farnsworth {
2529fc2873aaSDale Farnsworth 	if (port->endpoint.bus_type == V4L2_MBUS_PARALLEL)
2530fc2873aaSDale Farnsworth 		if (port->dev->csc_assigned == VIP_NOT_ASSIGNED ||
2531fc2873aaSDale Farnsworth 		    port->dev->csc_assigned == port->port_id)
2532fc2873aaSDale Farnsworth 			return true;
2533fc2873aaSDale Farnsworth 	return false;
2534fc2873aaSDale Farnsworth }
2535fc2873aaSDale Farnsworth 
allocate_csc(struct vip_port * port,enum vip_csc_state csc_direction)2536fc2873aaSDale Farnsworth static bool allocate_csc(struct vip_port *port,
2537fc2873aaSDale Farnsworth 			 enum vip_csc_state csc_direction)
2538fc2873aaSDale Farnsworth {
2539fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2540fc2873aaSDale Farnsworth 	/* Is CSC needed? */
2541fc2873aaSDale Farnsworth 	if (csc_direction != VIP_CSC_NA) {
2542fc2873aaSDale Farnsworth 		if (is_csc_available(port)) {
2543fc2873aaSDale Farnsworth 			port->dev->csc_assigned = port->port_id;
2544fc2873aaSDale Farnsworth 			port->csc = csc_direction;
2545fc2873aaSDale Farnsworth 			v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: csc allocated: dir: %d\n",
2546fc2873aaSDale Farnsworth 				 __func__, csc_direction);
2547fc2873aaSDale Farnsworth 			return true;
2548fc2873aaSDale Farnsworth 		}
2549fc2873aaSDale Farnsworth 	}
2550fc2873aaSDale Farnsworth 	return false;
2551fc2873aaSDale Farnsworth }
2552fc2873aaSDale Farnsworth 
free_csc(struct vip_port * port)2553fc2873aaSDale Farnsworth static void free_csc(struct vip_port *port)
2554fc2873aaSDale Farnsworth {
2555fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2556fc2873aaSDale Farnsworth 
2557fc2873aaSDale Farnsworth 	if (port->dev->csc_assigned == port->port_id) {
2558fc2873aaSDale Farnsworth 		port->dev->csc_assigned = VIP_NOT_ASSIGNED;
2559fc2873aaSDale Farnsworth 		port->csc = VIP_CSC_NA;
2560fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: csc freed\n",
2561fc2873aaSDale Farnsworth 			 __func__);
2562fc2873aaSDale Farnsworth 	}
2563fc2873aaSDale Farnsworth }
2564fc2873aaSDale Farnsworth 
vip_init_port(struct vip_port * port)2565fc2873aaSDale Farnsworth static int vip_init_port(struct vip_port *port)
2566fc2873aaSDale Farnsworth {
2567fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2568fc2873aaSDale Farnsworth 	int ret;
2569fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
2570fc2873aaSDale Farnsworth 	struct v4l2_subdev_format sd_fmt = {
2571fc2873aaSDale Farnsworth 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
2572fc2873aaSDale Farnsworth 		.pad = 0,
2573fc2873aaSDale Farnsworth 	};
2574fc2873aaSDale Farnsworth 	struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
2575fc2873aaSDale Farnsworth 
2576fc2873aaSDale Farnsworth 	if (port->num_streams != 0)
2577fc2873aaSDale Farnsworth 		goto done;
2578fc2873aaSDale Farnsworth 
2579fc2873aaSDale Farnsworth 	ret = vip_init_dev(port->dev);
2580fc2873aaSDale Farnsworth 	if (ret)
2581fc2873aaSDale Farnsworth 		goto done;
2582fc2873aaSDale Farnsworth 
2583fc2873aaSDale Farnsworth 	/* Get subdevice current frame format */
2584fc2873aaSDale Farnsworth 	ret = v4l2_subdev_call(port->subdev, pad, get_fmt, NULL, &sd_fmt);
2585fc2873aaSDale Farnsworth 	if (ret)
2586fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "init_port get_fmt failed in subdev: (%d)\n",
2587fc2873aaSDale Farnsworth 			 ret);
2588fc2873aaSDale Farnsworth 
2589fc2873aaSDale Farnsworth 	/* try to find one that matches */
2590fc2873aaSDale Farnsworth 	fmt = find_port_format_by_code(port, mbus_fmt->code);
2591fc2873aaSDale Farnsworth 	if (!fmt) {
2592fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "subdev default mbus_fmt %04x is not matched.\n",
2593fc2873aaSDale Farnsworth 			 mbus_fmt->code);
2594fc2873aaSDale Farnsworth 		/* if all else fails just pick the first one */
2595fc2873aaSDale Farnsworth 		fmt = port->active_fmt[0];
2596fc2873aaSDale Farnsworth 
2597fc2873aaSDale Farnsworth 		mbus_fmt->code = fmt->code;
2598fc2873aaSDale Farnsworth 		sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
2599fc2873aaSDale Farnsworth 		sd_fmt.pad = 0;
2600fc2873aaSDale Farnsworth 		ret = v4l2_subdev_call(port->subdev, pad, set_fmt,
2601fc2873aaSDale Farnsworth 				       NULL, &sd_fmt);
2602fc2873aaSDale Farnsworth 		if (ret)
2603fc2873aaSDale Farnsworth 			v4l2_dbg(1, debug, &dev->v4l2_dev, "init_port set_fmt failed in subdev: (%d)\n",
2604fc2873aaSDale Farnsworth 				 ret);
2605fc2873aaSDale Farnsworth 	}
2606fc2873aaSDale Farnsworth 
2607fc2873aaSDale Farnsworth 	/* Assign current format */
2608fc2873aaSDale Farnsworth 	port->fmt = fmt;
2609fc2873aaSDale Farnsworth 	port->mbus_framefmt = *mbus_fmt;
2610fc2873aaSDale Farnsworth 
2611fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "%s: g_mbus_fmt subdev mbus_code: %04X fourcc:%s size: %dx%d\n",
2612fc2873aaSDale Farnsworth 		 __func__, fmt->code,
2613fc2873aaSDale Farnsworth 		fourcc_to_str(fmt->fourcc),
2614fc2873aaSDale Farnsworth 		mbus_fmt->width, mbus_fmt->height);
2615fc2873aaSDale Farnsworth 
2616fc2873aaSDale Farnsworth 	if (mbus_fmt->field == V4L2_FIELD_ALTERNATE)
2617fc2873aaSDale Farnsworth 		port->flags |= FLAG_INTERLACED;
2618fc2873aaSDale Farnsworth 	else
2619fc2873aaSDale Farnsworth 		port->flags &= ~FLAG_INTERLACED;
2620fc2873aaSDale Farnsworth 
2621fc2873aaSDale Farnsworth 	port->c_rect.left	= 0;
2622fc2873aaSDale Farnsworth 	port->c_rect.top	= 0;
2623fc2873aaSDale Farnsworth 	port->c_rect.width	= mbus_fmt->width;
2624fc2873aaSDale Farnsworth 	port->c_rect.height	= mbus_fmt->height;
2625fc2873aaSDale Farnsworth 
2626fc2873aaSDale Farnsworth 	ret = vpdma_alloc_desc_buf(&port->sc_coeff_h, SC_COEF_SRAM_SIZE);
2627fc2873aaSDale Farnsworth 	if (ret != 0)
2628fc2873aaSDale Farnsworth 		return ret;
2629fc2873aaSDale Farnsworth 
2630fc2873aaSDale Farnsworth 	ret = vpdma_alloc_desc_buf(&port->sc_coeff_v, SC_COEF_SRAM_SIZE);
2631fc2873aaSDale Farnsworth 	if (ret != 0)
2632fc2873aaSDale Farnsworth 		goto free_sc_h;
2633fc2873aaSDale Farnsworth 
2634fc2873aaSDale Farnsworth 	ret = vpdma_alloc_desc_buf(&port->mmr_adb, sizeof(struct vip_mmr_adb));
2635fc2873aaSDale Farnsworth 	if (ret != 0)
2636fc2873aaSDale Farnsworth 		goto free_sc_v;
2637fc2873aaSDale Farnsworth 
2638fc2873aaSDale Farnsworth 	init_adb_hdrs(port);
2639fc2873aaSDale Farnsworth 
2640fc2873aaSDale Farnsworth 	vip_enable_parser(port, false);
2641fc2873aaSDale Farnsworth done:
2642fc2873aaSDale Farnsworth 	port->num_streams++;
2643fc2873aaSDale Farnsworth 	return 0;
2644fc2873aaSDale Farnsworth 
2645fc2873aaSDale Farnsworth free_sc_v:
2646fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&port->sc_coeff_v);
2647fc2873aaSDale Farnsworth free_sc_h:
2648fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&port->sc_coeff_h);
2649fc2873aaSDale Farnsworth 	return ret;
2650fc2873aaSDale Farnsworth }
2651fc2873aaSDale Farnsworth 
vip_init_stream(struct vip_stream * stream)2652fc2873aaSDale Farnsworth static int vip_init_stream(struct vip_stream *stream)
2653fc2873aaSDale Farnsworth {
2654fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2655fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2656fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
2657fc2873aaSDale Farnsworth 	struct v4l2_mbus_framefmt *mbus_fmt;
2658fc2873aaSDale Farnsworth 	struct v4l2_format f;
2659fc2873aaSDale Farnsworth 	int ret;
2660fc2873aaSDale Farnsworth 
2661fc2873aaSDale Farnsworth 	ret = vip_init_port(port);
2662fc2873aaSDale Farnsworth 	if (ret != 0)
2663fc2873aaSDale Farnsworth 		return ret;
2664fc2873aaSDale Farnsworth 
2665fc2873aaSDale Farnsworth 	fmt = port->fmt;
2666fc2873aaSDale Farnsworth 	mbus_fmt = &port->mbus_framefmt;
2667fc2873aaSDale Farnsworth 
2668fc2873aaSDale Farnsworth 	memset(&f, 0, sizeof(f));
2669fc2873aaSDale Farnsworth 
2670fc2873aaSDale Farnsworth 	/* Properly calculate the sizeimage and bytesperline values. */
2671fc2873aaSDale Farnsworth 	v4l2_fill_pix_format(&f.fmt.pix, mbus_fmt);
2672fc2873aaSDale Farnsworth 	f.fmt.pix.pixelformat = fmt->fourcc;
2673fc2873aaSDale Farnsworth 	ret = vip_calc_format_size(port, fmt, &f);
2674fc2873aaSDale Farnsworth 	if (ret)
2675fc2873aaSDale Farnsworth 		return ret;
2676fc2873aaSDale Farnsworth 
2677fc2873aaSDale Farnsworth 	stream->width = f.fmt.pix.width;
2678fc2873aaSDale Farnsworth 	stream->height = f.fmt.pix.height;
2679fc2873aaSDale Farnsworth 	stream->sup_field = f.fmt.pix.field;
2680fc2873aaSDale Farnsworth 	stream->bytesperline = f.fmt.pix.bytesperline;
2681fc2873aaSDale Farnsworth 	stream->sizeimage = f.fmt.pix.sizeimage;
2682fc2873aaSDale Farnsworth 
2683fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "init_stream fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
2684fc2873aaSDale Farnsworth 		 fourcc_to_str(f.fmt.pix.pixelformat),
2685fc2873aaSDale Farnsworth 		 f.fmt.pix.width, f.fmt.pix.height,
2686fc2873aaSDale Farnsworth 		 f.fmt.pix.bytesperline, f.fmt.pix.sizeimage);
2687fc2873aaSDale Farnsworth 	v4l2_dbg(3, debug, &dev->v4l2_dev, "init_stream vpdma data type: 0x%02X\n",
2688fc2873aaSDale Farnsworth 		 port->fmt->vpdma_fmt[0]->data_type);
2689fc2873aaSDale Farnsworth 
2690fc2873aaSDale Farnsworth 	ret = vpdma_create_desc_list(&stream->desc_list, VIP_DESC_LIST_SIZE,
2691fc2873aaSDale Farnsworth 				     VPDMA_LIST_TYPE_NORMAL);
2692fc2873aaSDale Farnsworth 
2693fc2873aaSDale Farnsworth 	if (ret != 0)
2694fc2873aaSDale Farnsworth 		return ret;
2695fc2873aaSDale Farnsworth 
2696fc2873aaSDale Farnsworth 	stream->write_desc = (struct vpdma_dtd *)stream->desc_list.buf.addr
2697fc2873aaSDale Farnsworth 				+ 15;
2698fc2873aaSDale Farnsworth 
2699fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: stream instance %pa\n",
2700fc2873aaSDale Farnsworth 		 __func__, &stream);
2701fc2873aaSDale Farnsworth 
2702fc2873aaSDale Farnsworth 	return 0;
2703fc2873aaSDale Farnsworth }
2704fc2873aaSDale Farnsworth 
vip_release_dev(struct vip_dev * dev)2705fc2873aaSDale Farnsworth static void vip_release_dev(struct vip_dev *dev)
2706fc2873aaSDale Farnsworth {
2707fc2873aaSDale Farnsworth 	/*
2708fc2873aaSDale Farnsworth 	 * On last close, disable clocks to conserve power
2709fc2873aaSDale Farnsworth 	 */
2710fc2873aaSDale Farnsworth 
2711fc2873aaSDale Farnsworth 	if (--dev->num_ports == 0) {
2712fc2873aaSDale Farnsworth 		/* reset the scaler module */
2713fc2873aaSDale Farnsworth 		vip_module_toggle(dev, VIP_SC_RST, true);
2714fc2873aaSDale Farnsworth 		vip_module_toggle(dev, VIP_CSC_RST, true);
2715fc2873aaSDale Farnsworth 		vip_set_clock_enable(dev, 0);
2716fc2873aaSDale Farnsworth 	}
2717fc2873aaSDale Farnsworth }
2718fc2873aaSDale Farnsworth 
vip_set_crop_parser(struct vip_port * port)2719fc2873aaSDale Farnsworth static int vip_set_crop_parser(struct vip_port *port)
2720fc2873aaSDale Farnsworth {
2721fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2722fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
2723fc2873aaSDale Farnsworth 	u32 hcrop = 0, vcrop = 0;
2724fc2873aaSDale Farnsworth 	u32 width = port->mbus_framefmt.width;
2725fc2873aaSDale Farnsworth 
2726fc2873aaSDale Farnsworth 	if (port->fmt->vpdma_fmt[0] == &vpdma_raw_fmts[VPDMA_DATA_FMT_RAW8]) {
2727fc2873aaSDale Farnsworth 		/*
2728fc2873aaSDale Farnsworth 		 * Special case since we are faking a YUV422 16bit format
2729fc2873aaSDale Farnsworth 		 * to have the vpdma perform the needed byte swap
2730fc2873aaSDale Farnsworth 		 * we need to adjust the pixel width accordingly
2731fc2873aaSDale Farnsworth 		 * otherwise the parser will attempt to collect more pixels
2732fc2873aaSDale Farnsworth 		 * then available and the vpdma transfer will exceed the
2733fc2873aaSDale Farnsworth 		 * allocated frame buffer.
2734fc2873aaSDale Farnsworth 		 */
2735fc2873aaSDale Farnsworth 		width >>= 1;
2736fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: 8 bit raw detected, adjusting width to %d\n",
2737fc2873aaSDale Farnsworth 			 __func__, width);
2738fc2873aaSDale Farnsworth 	}
2739fc2873aaSDale Farnsworth 
2740fc2873aaSDale Farnsworth 	/*
2741fc2873aaSDale Farnsworth 	 * Set Parser Crop parameters to source size otherwise
2742fc2873aaSDale Farnsworth 	 * scaler and colorspace converter will yield garbage.
2743fc2873aaSDale Farnsworth 	 */
2744fc2873aaSDale Farnsworth 	hcrop = VIP_ACT_BYPASS;
2745fc2873aaSDale Farnsworth 	insert_field(&hcrop, 0, VIP_ACT_SKIP_NUMPIX_MASK,
2746fc2873aaSDale Farnsworth 		     VIP_ACT_SKIP_NUMPIX_SHFT);
2747fc2873aaSDale Farnsworth 	insert_field(&hcrop, width,
2748fc2873aaSDale Farnsworth 		     VIP_ACT_USE_NUMPIX_MASK, VIP_ACT_USE_NUMPIX_SHFT);
2749fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_CROP_H_PORT(port->port_id), hcrop);
2750fc2873aaSDale Farnsworth 
2751fc2873aaSDale Farnsworth 	insert_field(&vcrop, 0, VIP_ACT_SKIP_NUMLINES_MASK,
2752fc2873aaSDale Farnsworth 		     VIP_ACT_SKIP_NUMLINES_SHFT);
2753fc2873aaSDale Farnsworth 	insert_field(&vcrop, port->mbus_framefmt.height,
2754fc2873aaSDale Farnsworth 		     VIP_ACT_USE_NUMLINES_MASK, VIP_ACT_USE_NUMLINES_SHFT);
2755fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_CROP_V_PORT(port->port_id), vcrop);
2756fc2873aaSDale Farnsworth 
2757fc2873aaSDale Farnsworth 	return 0;
2758fc2873aaSDale Farnsworth }
2759fc2873aaSDale Farnsworth 
vip_setup_parser(struct vip_port * port)2760fc2873aaSDale Farnsworth static int vip_setup_parser(struct vip_port *port)
2761fc2873aaSDale Farnsworth {
2762fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2763fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
2764fc2873aaSDale Farnsworth 	struct v4l2_fwnode_endpoint *endpoint = &port->endpoint;
2765fc2873aaSDale Farnsworth 	int iface, sync_type;
2766fc2873aaSDale Farnsworth 	u32 flags = 0, config0;
2767fc2873aaSDale Farnsworth 
2768fc2873aaSDale Farnsworth 	/* Reset the port */
2769fc2873aaSDale Farnsworth 	vip_reset_parser(port, true);
2770fc2873aaSDale Farnsworth 	usleep_range(200, 250);
2771fc2873aaSDale Farnsworth 	vip_reset_parser(port, false);
2772fc2873aaSDale Farnsworth 
2773fc2873aaSDale Farnsworth 	config0 = reg_read(parser, VIP_PARSER_PORT(port->port_id));
2774fc2873aaSDale Farnsworth 
2775fc2873aaSDale Farnsworth 	if (endpoint->bus_type == V4L2_MBUS_BT656) {
2776fc2873aaSDale Farnsworth 		flags = endpoint->bus.parallel.flags;
2777fc2873aaSDale Farnsworth 		iface = DUAL_8B_INTERFACE;
2778fc2873aaSDale Farnsworth 
2779fc2873aaSDale Farnsworth 		/*
2780fc2873aaSDale Farnsworth 		 * Ideally, this should come from subdev
2781fc2873aaSDale Farnsworth 		 * port->fmt can be anything once CSC is enabled
2782fc2873aaSDale Farnsworth 		 */
2783fc2873aaSDale Farnsworth 		if (vip_is_mbuscode_rgb(port->fmt->code))
2784fc2873aaSDale Farnsworth 			sync_type = EMBEDDED_SYNC_SINGLE_RGB_OR_YUV444;
2785fc2873aaSDale Farnsworth 		else
2786fc2873aaSDale Farnsworth 			sync_type = EMBEDDED_SYNC_LINE_MULTIPLEXED_YUV422;
2787fc2873aaSDale Farnsworth 
2788fc2873aaSDale Farnsworth 	} else if (endpoint->bus_type == V4L2_MBUS_PARALLEL) {
2789fc2873aaSDale Farnsworth 		flags = endpoint->bus.parallel.flags;
2790fc2873aaSDale Farnsworth 
2791fc2873aaSDale Farnsworth 		switch (endpoint->bus.parallel.bus_width) {
2792fc2873aaSDale Farnsworth 		case 24:
2793fc2873aaSDale Farnsworth 			iface = SINGLE_24B_INTERFACE;
2794fc2873aaSDale Farnsworth 		break;
2795fc2873aaSDale Farnsworth 		case 16:
2796fc2873aaSDale Farnsworth 			iface = SINGLE_16B_INTERFACE;
2797fc2873aaSDale Farnsworth 		break;
2798fc2873aaSDale Farnsworth 		case 8:
2799fc2873aaSDale Farnsworth 		default:
2800fc2873aaSDale Farnsworth 			iface = DUAL_8B_INTERFACE;
2801fc2873aaSDale Farnsworth 		}
2802fc2873aaSDale Farnsworth 
2803fc2873aaSDale Farnsworth 		if (vip_is_mbuscode_rgb(port->fmt->code))
2804fc2873aaSDale Farnsworth 			sync_type = DISCRETE_SYNC_SINGLE_RGB_24B;
2805fc2873aaSDale Farnsworth 		else
2806fc2873aaSDale Farnsworth 			sync_type = DISCRETE_SYNC_SINGLE_YUV422;
2807fc2873aaSDale Farnsworth 
2808fc2873aaSDale Farnsworth 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
2809fc2873aaSDale Farnsworth 			config0 |= VIP_HSYNC_POLARITY;
2810fc2873aaSDale Farnsworth 		else if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
2811fc2873aaSDale Farnsworth 			config0 &= ~VIP_HSYNC_POLARITY;
2812fc2873aaSDale Farnsworth 
2813fc2873aaSDale Farnsworth 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
2814fc2873aaSDale Farnsworth 			config0 |= VIP_VSYNC_POLARITY;
2815fc2873aaSDale Farnsworth 		else if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
2816fc2873aaSDale Farnsworth 			config0 &= ~VIP_VSYNC_POLARITY;
2817fc2873aaSDale Farnsworth 
2818fc2873aaSDale Farnsworth 		config0 &= ~VIP_USE_ACTVID_HSYNC_ONLY;
2819fc2873aaSDale Farnsworth 		config0 |= VIP_ACTVID_POLARITY;
2820fc2873aaSDale Farnsworth 		config0 |= VIP_DISCRETE_BASIC_MODE;
2821fc2873aaSDale Farnsworth 
2822fc2873aaSDale Farnsworth 	} else {
2823fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "Device doesn't support CSI2");
2824fc2873aaSDale Farnsworth 		return -EINVAL;
2825fc2873aaSDale Farnsworth 	}
2826fc2873aaSDale Farnsworth 
2827fc2873aaSDale Farnsworth 	if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) {
2828fc2873aaSDale Farnsworth 		vip_set_pclk_invert(port);
2829fc2873aaSDale Farnsworth 		config0 |= VIP_PIXCLK_EDGE_POLARITY;
2830fc2873aaSDale Farnsworth 	} else {
2831fc2873aaSDale Farnsworth 		config0 &= ~VIP_PIXCLK_EDGE_POLARITY;
2832fc2873aaSDale Farnsworth 	}
2833fc2873aaSDale Farnsworth 
2834fc2873aaSDale Farnsworth 	config0 |= ((sync_type & VIP_SYNC_TYPE_MASK) << VIP_SYNC_TYPE_SHFT);
2835fc2873aaSDale Farnsworth 
2836fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_PORT(port->port_id), config0);
2837fc2873aaSDale Farnsworth 
2838fc2873aaSDale Farnsworth 	vip_set_data_interface(port, iface);
2839fc2873aaSDale Farnsworth 	vip_set_crop_parser(port);
2840fc2873aaSDale Farnsworth 
2841fc2873aaSDale Farnsworth 	return 0;
2842fc2873aaSDale Farnsworth }
2843fc2873aaSDale Farnsworth 
vip_enable_parser(struct vip_port * port,bool on)2844fc2873aaSDale Farnsworth static void vip_enable_parser(struct vip_port *port, bool on)
2845fc2873aaSDale Farnsworth {
2846fc2873aaSDale Farnsworth 	u32 config0;
2847fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2848fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
2849fc2873aaSDale Farnsworth 
2850fc2873aaSDale Farnsworth 	config0 = reg_read(parser, VIP_PARSER_PORT(port->port_id));
2851fc2873aaSDale Farnsworth 
2852fc2873aaSDale Farnsworth 	if (on) {
2853fc2873aaSDale Farnsworth 		config0 |= VIP_PORT_ENABLE;
2854fc2873aaSDale Farnsworth 		config0 &= ~(VIP_ASYNC_FIFO_RD | VIP_ASYNC_FIFO_WR);
2855fc2873aaSDale Farnsworth 	} else {
2856fc2873aaSDale Farnsworth 		config0 &= ~VIP_PORT_ENABLE;
2857fc2873aaSDale Farnsworth 		config0 |= (VIP_ASYNC_FIFO_RD | VIP_ASYNC_FIFO_WR);
2858fc2873aaSDale Farnsworth 	}
2859fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_PORT(port->port_id), config0);
2860fc2873aaSDale Farnsworth }
2861fc2873aaSDale Farnsworth 
vip_reset_parser(struct vip_port * port,bool on)2862fc2873aaSDale Farnsworth static void vip_reset_parser(struct vip_port *port, bool on)
2863fc2873aaSDale Farnsworth {
2864fc2873aaSDale Farnsworth 	u32 config0;
2865fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2866fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
2867fc2873aaSDale Farnsworth 
2868fc2873aaSDale Farnsworth 	config0 = reg_read(parser, VIP_PARSER_PORT(port->port_id));
2869fc2873aaSDale Farnsworth 
2870fc2873aaSDale Farnsworth 	if (on)
2871fc2873aaSDale Farnsworth 		config0 |= VIP_SW_RESET;
2872fc2873aaSDale Farnsworth 	else
2873fc2873aaSDale Farnsworth 		config0 &= ~VIP_SW_RESET;
2874fc2873aaSDale Farnsworth 
2875fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_PORT(port->port_id), config0);
2876fc2873aaSDale Farnsworth }
2877fc2873aaSDale Farnsworth 
vip_parser_stop_imm(struct vip_port * port,bool on)2878fc2873aaSDale Farnsworth static void vip_parser_stop_imm(struct vip_port *port, bool on)
2879fc2873aaSDale Farnsworth {
2880fc2873aaSDale Farnsworth 	u32 config0;
2881fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2882fc2873aaSDale Farnsworth 	struct vip_parser_data *parser = dev->parser;
2883fc2873aaSDale Farnsworth 
2884fc2873aaSDale Farnsworth 	config0 = reg_read(parser, VIP_PARSER_STOP_IMM_PORT(port->port_id));
2885fc2873aaSDale Farnsworth 
2886fc2873aaSDale Farnsworth 	if (on)
2887fc2873aaSDale Farnsworth 		config0 = 0xffffffff;
2888fc2873aaSDale Farnsworth 	else
2889fc2873aaSDale Farnsworth 		config0 = 0;
2890fc2873aaSDale Farnsworth 
2891fc2873aaSDale Farnsworth 	reg_write(parser, VIP_PARSER_STOP_IMM_PORT(port->port_id), config0);
2892fc2873aaSDale Farnsworth }
2893fc2873aaSDale Farnsworth 
vip_release_stream(struct vip_stream * stream)2894fc2873aaSDale Farnsworth static void vip_release_stream(struct vip_stream *stream)
2895fc2873aaSDale Farnsworth {
2896fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
2897fc2873aaSDale Farnsworth 
2898fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: stream instance %pa\n",
2899fc2873aaSDale Farnsworth 		 __func__, &stream);
2900fc2873aaSDale Farnsworth 
2901fc2873aaSDale Farnsworth 	vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
2902fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&stream->desc_list.buf);
2903fc2873aaSDale Farnsworth 	vpdma_free_desc_list(&stream->desc_list);
2904fc2873aaSDale Farnsworth }
2905fc2873aaSDale Farnsworth 
vip_release_port(struct vip_port * port)2906fc2873aaSDale Farnsworth static void vip_release_port(struct vip_port *port)
2907fc2873aaSDale Farnsworth {
2908fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2909fc2873aaSDale Farnsworth 
2910fc2873aaSDale Farnsworth 	v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: port instance %pa\n",
2911fc2873aaSDale Farnsworth 		 __func__, &port);
2912fc2873aaSDale Farnsworth 
2913fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&port->mmr_adb);
2914fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&port->sc_coeff_h);
2915fc2873aaSDale Farnsworth 	vpdma_free_desc_buf(&port->sc_coeff_v);
2916fc2873aaSDale Farnsworth }
2917fc2873aaSDale Farnsworth 
stop_dma(struct vip_stream * stream,bool clear_list)2918fc2873aaSDale Farnsworth static void stop_dma(struct vip_stream *stream, bool clear_list)
2919fc2873aaSDale Farnsworth {
2920fc2873aaSDale Farnsworth 	struct vip_dev *dev = stream->port->dev;
2921fc2873aaSDale Farnsworth 	int ch, size = 0;
2922fc2873aaSDale Farnsworth 
2923fc2873aaSDale Farnsworth 	/* Create a list of channels to be cleared */
2924fc2873aaSDale Farnsworth 	for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++) {
2925fc2873aaSDale Farnsworth 		if (stream->vpdma_channels[ch] == 1) {
2926fc2873aaSDale Farnsworth 			stream->vpdma_channels_to_abort[size++] = ch;
2927fc2873aaSDale Farnsworth 			v4l2_dbg(2, debug, &dev->v4l2_dev, "Clear channel no: %d\n", ch);
2928fc2873aaSDale Farnsworth 		}
2929fc2873aaSDale Farnsworth 	}
2930fc2873aaSDale Farnsworth 
2931fc2873aaSDale Farnsworth 	/* Clear all the used channels for the list */
2932fc2873aaSDale Farnsworth 	vpdma_list_cleanup(dev->shared->vpdma, stream->list_num,
2933fc2873aaSDale Farnsworth 			   stream->vpdma_channels_to_abort, size);
2934fc2873aaSDale Farnsworth 
2935fc2873aaSDale Farnsworth 	if (clear_list)
2936fc2873aaSDale Farnsworth 		for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++)
2937fc2873aaSDale Farnsworth 			stream->vpdma_channels[ch] = 0;
2938fc2873aaSDale Farnsworth }
2939fc2873aaSDale Farnsworth 
vip_open(struct file * file)2940fc2873aaSDale Farnsworth static int vip_open(struct file *file)
2941fc2873aaSDale Farnsworth {
2942fc2873aaSDale Farnsworth 	struct vip_stream *stream = video_drvdata(file);
2943fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2944fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2945fc2873aaSDale Farnsworth 	int ret = 0;
2946fc2873aaSDale Farnsworth 
2947fc2873aaSDale Farnsworth 	mutex_lock(&dev->mutex);
2948fc2873aaSDale Farnsworth 
2949fc2873aaSDale Farnsworth 	ret = v4l2_fh_open(file);
2950fc2873aaSDale Farnsworth 	if (ret) {
2951fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "v4l2_fh_open failed\n");
2952fc2873aaSDale Farnsworth 		goto unlock;
2953fc2873aaSDale Farnsworth 	}
2954fc2873aaSDale Farnsworth 
2955fc2873aaSDale Farnsworth 	/*
2956fc2873aaSDale Farnsworth 	 * If this is the first open file.
2957fc2873aaSDale Farnsworth 	 * Then initialize hw module.
2958fc2873aaSDale Farnsworth 	 */
2959fc2873aaSDale Farnsworth 	if (!v4l2_fh_is_singular_file(file))
2960fc2873aaSDale Farnsworth 		goto unlock;
2961fc2873aaSDale Farnsworth 
2962fc2873aaSDale Farnsworth 	if (vip_init_stream(stream))
2963fc2873aaSDale Farnsworth 		ret = -ENODEV;
2964fc2873aaSDale Farnsworth unlock:
2965fc2873aaSDale Farnsworth 	mutex_unlock(&dev->mutex);
2966fc2873aaSDale Farnsworth 	return ret;
2967fc2873aaSDale Farnsworth }
2968fc2873aaSDale Farnsworth 
vip_release(struct file * file)2969fc2873aaSDale Farnsworth static int vip_release(struct file *file)
2970fc2873aaSDale Farnsworth {
2971fc2873aaSDale Farnsworth 	struct vip_stream *stream = video_drvdata(file);
2972fc2873aaSDale Farnsworth 	struct vip_port *port = stream->port;
2973fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
2974fc2873aaSDale Farnsworth 	bool fh_singular;
2975fc2873aaSDale Farnsworth 	int ret;
2976fc2873aaSDale Farnsworth 
2977fc2873aaSDale Farnsworth 	mutex_lock(&dev->mutex);
2978fc2873aaSDale Farnsworth 
2979fc2873aaSDale Farnsworth 	/* Save the singular status before we call the clean-up helper */
2980fc2873aaSDale Farnsworth 	fh_singular = v4l2_fh_is_singular_file(file);
2981fc2873aaSDale Farnsworth 
2982fc2873aaSDale Farnsworth 	/* the release helper will cleanup any on-going streaming */
2983fc2873aaSDale Farnsworth 	ret = _vb2_fop_release(file, NULL);
2984fc2873aaSDale Farnsworth 
2985fc2873aaSDale Farnsworth 	free_csc(port);
2986fc2873aaSDale Farnsworth 	free_scaler(port);
2987fc2873aaSDale Farnsworth 
2988fc2873aaSDale Farnsworth 	/*
2989fc2873aaSDale Farnsworth 	 * If this is the last open file.
2990fc2873aaSDale Farnsworth 	 * Then de-initialize hw module.
2991fc2873aaSDale Farnsworth 	 */
2992fc2873aaSDale Farnsworth 	if (fh_singular) {
2993fc2873aaSDale Farnsworth 		vip_release_stream(stream);
2994fc2873aaSDale Farnsworth 
2995fc2873aaSDale Farnsworth 		if (--port->num_streams == 0) {
2996fc2873aaSDale Farnsworth 			vip_release_port(port);
2997fc2873aaSDale Farnsworth 			vip_release_dev(port->dev);
2998fc2873aaSDale Farnsworth 		}
2999fc2873aaSDale Farnsworth 	}
3000fc2873aaSDale Farnsworth 
3001fc2873aaSDale Farnsworth 	mutex_unlock(&dev->mutex);
3002fc2873aaSDale Farnsworth 
3003fc2873aaSDale Farnsworth 	return ret;
3004fc2873aaSDale Farnsworth }
3005fc2873aaSDale Farnsworth 
3006fc2873aaSDale Farnsworth /*
3007fc2873aaSDale Farnsworth  * File operations
3008fc2873aaSDale Farnsworth  */
3009fc2873aaSDale Farnsworth static const struct v4l2_file_operations vip_fops = {
3010fc2873aaSDale Farnsworth 	.owner		= THIS_MODULE,
3011fc2873aaSDale Farnsworth 	.open		= vip_open,
3012fc2873aaSDale Farnsworth 	.release	= vip_release,
3013fc2873aaSDale Farnsworth 	.poll		= vb2_fop_poll,
3014fc2873aaSDale Farnsworth 	.unlocked_ioctl	= video_ioctl2,
3015fc2873aaSDale Farnsworth 	.mmap		= vb2_fop_mmap,
3016fc2873aaSDale Farnsworth };
3017fc2873aaSDale Farnsworth 
3018fc2873aaSDale Farnsworth static struct video_device vip_videodev = {
3019fc2873aaSDale Farnsworth 	.name		= VIP_MODULE_NAME,
3020fc2873aaSDale Farnsworth 	.fops		= &vip_fops,
3021fc2873aaSDale Farnsworth 	.ioctl_ops	= &vip_ioctl_ops,
3022fc2873aaSDale Farnsworth 	.minor		= -1,
3023fc2873aaSDale Farnsworth 	.release	= video_device_release,
3024fc2873aaSDale Farnsworth 	.tvnorms	= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
3025fc2873aaSDale Farnsworth 	.device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE,
3026fc2873aaSDale Farnsworth };
3027fc2873aaSDale Farnsworth 
alloc_stream(struct vip_port * port,int stream_id,int vfl_type)3028fc2873aaSDale Farnsworth static int alloc_stream(struct vip_port *port, int stream_id, int vfl_type)
3029fc2873aaSDale Farnsworth {
3030fc2873aaSDale Farnsworth 	struct vip_stream *stream;
3031fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
3032fc2873aaSDale Farnsworth 	struct vb2_queue *q;
3033fc2873aaSDale Farnsworth 	struct video_device *vfd;
3034fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
3035fc2873aaSDale Farnsworth 	struct list_head *pos, *tmp;
3036fc2873aaSDale Farnsworth 	int ret, i;
3037fc2873aaSDale Farnsworth 
3038*bf4afc53SLinus Torvalds 	stream = kzalloc_obj(*stream);
3039fc2873aaSDale Farnsworth 	if (!stream)
3040fc2873aaSDale Farnsworth 		return -ENOMEM;
3041fc2873aaSDale Farnsworth 
3042fc2873aaSDale Farnsworth 	stream->port = port;
3043fc2873aaSDale Farnsworth 	stream->stream_id = stream_id;
3044fc2873aaSDale Farnsworth 	stream->vfl_type = vfl_type;
3045fc2873aaSDale Farnsworth 	port->cap_streams[stream_id] = stream;
3046fc2873aaSDale Farnsworth 
3047fc2873aaSDale Farnsworth 	stream->list_num = vpdma_hwlist_alloc(dev->shared->vpdma, stream);
3048fc2873aaSDale Farnsworth 	if (stream->list_num < 0) {
3049fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "Could not get VPDMA hwlist");
3050fc2873aaSDale Farnsworth 		ret = -ENODEV;
3051fc2873aaSDale Farnsworth 		goto do_free_stream;
3052fc2873aaSDale Farnsworth 	}
3053fc2873aaSDale Farnsworth 
3054fc2873aaSDale Farnsworth 	INIT_LIST_HEAD(&stream->post_bufs);
3055fc2873aaSDale Farnsworth 
3056fc2873aaSDale Farnsworth 	/*
3057fc2873aaSDale Farnsworth 	 * Initialize queue
3058fc2873aaSDale Farnsworth 	 */
3059fc2873aaSDale Farnsworth 	q = &stream->vb_vidq;
3060fc2873aaSDale Farnsworth 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3061fc2873aaSDale Farnsworth 	q->io_modes = VB2_MMAP | VB2_DMABUF;
3062fc2873aaSDale Farnsworth 	q->drv_priv = stream;
3063fc2873aaSDale Farnsworth 	q->buf_struct_size = sizeof(struct vip_buffer);
3064fc2873aaSDale Farnsworth 	q->ops = &vip_video_qops;
3065fc2873aaSDale Farnsworth 	q->mem_ops = &vb2_dma_contig_memops;
3066fc2873aaSDale Farnsworth 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
3067fc2873aaSDale Farnsworth 	q->lock = &dev->mutex;
3068fc2873aaSDale Farnsworth 	q->min_queued_buffers = 2;
3069fc2873aaSDale Farnsworth 	q->dev = dev->v4l2_dev.dev;
3070fc2873aaSDale Farnsworth 
3071fc2873aaSDale Farnsworth 	ret = vb2_queue_init(q);
3072fc2873aaSDale Farnsworth 	if (ret)
3073fc2873aaSDale Farnsworth 		goto do_free_hwlist;
3074fc2873aaSDale Farnsworth 
3075fc2873aaSDale Farnsworth 	INIT_WORK(&stream->recovery_work, vip_overflow_recovery_work);
3076fc2873aaSDale Farnsworth 
3077fc2873aaSDale Farnsworth 	INIT_LIST_HEAD(&stream->vidq);
3078fc2873aaSDale Farnsworth 
3079fc2873aaSDale Farnsworth 	/* Allocate/populate Drop queue entries */
3080fc2873aaSDale Farnsworth 	INIT_LIST_HEAD(&stream->dropq);
3081fc2873aaSDale Farnsworth 	for (i = 0; i < VIP_DROPQ_SIZE; i++) {
308269050f8dSKees Cook 		buf = kzalloc_obj(*buf, GFP_ATOMIC);
3083fc2873aaSDale Farnsworth 		if (!buf) {
3084fc2873aaSDale Farnsworth 			ret = -ENOMEM;
3085fc2873aaSDale Farnsworth 			goto do_free_dropq;
3086fc2873aaSDale Farnsworth 		}
3087fc2873aaSDale Farnsworth 		buf->drop = true;
3088fc2873aaSDale Farnsworth 		list_add(&buf->list, &stream->dropq);
3089fc2873aaSDale Farnsworth 	}
3090fc2873aaSDale Farnsworth 
3091fc2873aaSDale Farnsworth 	vfd = video_device_alloc();
3092fc2873aaSDale Farnsworth 	if (!vfd) {
3093fc2873aaSDale Farnsworth 		ret = -ENOMEM;
3094fc2873aaSDale Farnsworth 		goto do_free_dropq;
3095fc2873aaSDale Farnsworth 	}
3096fc2873aaSDale Farnsworth 	*vfd = vip_videodev;
3097fc2873aaSDale Farnsworth 	vfd->v4l2_dev = &dev->v4l2_dev;
3098fc2873aaSDale Farnsworth 	vfd->queue = q;
3099fc2873aaSDale Farnsworth 
3100fc2873aaSDale Farnsworth 	vfd->lock = &dev->mutex;
3101fc2873aaSDale Farnsworth 	video_set_drvdata(vfd, stream);
3102fc2873aaSDale Farnsworth 	stream->vfd = vfd;
3103fc2873aaSDale Farnsworth 
3104fc2873aaSDale Farnsworth 	ret = video_register_device(vfd, vfl_type, -1);
3105fc2873aaSDale Farnsworth 	if (ret) {
3106fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
3107fc2873aaSDale Farnsworth 		goto do_free_vfd;
3108fc2873aaSDale Farnsworth 	}
3109fc2873aaSDale Farnsworth 
3110fc2873aaSDale Farnsworth 	v4l2_info(&dev->v4l2_dev, "device registered as %s\n",
3111fc2873aaSDale Farnsworth 		  video_device_node_name(vfd));
3112fc2873aaSDale Farnsworth 	return 0;
3113fc2873aaSDale Farnsworth 
3114fc2873aaSDale Farnsworth do_free_vfd:
3115fc2873aaSDale Farnsworth 	video_device_release(vfd);
3116fc2873aaSDale Farnsworth do_free_dropq:
3117fc2873aaSDale Farnsworth 	list_for_each_safe(pos, tmp, &stream->dropq) {
3118fc2873aaSDale Farnsworth 		buf = list_entry(pos,
3119fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
3120fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "dropq buffer\n");
3121fc2873aaSDale Farnsworth 		list_del(pos);
3122fc2873aaSDale Farnsworth 		kfree(buf);
3123fc2873aaSDale Farnsworth 	}
3124fc2873aaSDale Farnsworth do_free_hwlist:
3125fc2873aaSDale Farnsworth 	vpdma_hwlist_release(dev->shared->vpdma, stream->list_num);
3126fc2873aaSDale Farnsworth do_free_stream:
3127fc2873aaSDale Farnsworth 	kfree(stream);
3128fc2873aaSDale Farnsworth 	return ret;
3129fc2873aaSDale Farnsworth }
3130fc2873aaSDale Farnsworth 
free_stream(struct vip_stream * stream)3131fc2873aaSDale Farnsworth static void free_stream(struct vip_stream *stream)
3132fc2873aaSDale Farnsworth {
3133fc2873aaSDale Farnsworth 	struct vip_dev *dev;
3134fc2873aaSDale Farnsworth 	struct vip_buffer *buf;
3135fc2873aaSDale Farnsworth 	struct list_head *pos, *q;
3136fc2873aaSDale Farnsworth 
3137fc2873aaSDale Farnsworth 	if (!stream)
3138fc2873aaSDale Farnsworth 		return;
3139fc2873aaSDale Farnsworth 
3140fc2873aaSDale Farnsworth 	dev = stream->port->dev;
3141fc2873aaSDale Farnsworth 	/* Free up the Drop queue */
3142fc2873aaSDale Farnsworth 	list_for_each_safe(pos, q, &stream->dropq) {
3143fc2873aaSDale Farnsworth 		buf = list_entry(pos,
3144fc2873aaSDale Farnsworth 				 struct vip_buffer, list);
3145fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "dropq buffer\n");
3146fc2873aaSDale Farnsworth 		list_del(pos);
3147fc2873aaSDale Farnsworth 		kfree(buf);
3148fc2873aaSDale Farnsworth 	}
3149fc2873aaSDale Farnsworth 
3150fc2873aaSDale Farnsworth 	video_unregister_device(stream->vfd);
3151fc2873aaSDale Farnsworth 	vpdma_hwlist_release(dev->shared->vpdma, stream->list_num);
3152fc2873aaSDale Farnsworth 	stream->port->cap_streams[stream->stream_id] = NULL;
3153fc2873aaSDale Farnsworth 	kfree(stream);
3154fc2873aaSDale Farnsworth }
3155fc2873aaSDale Farnsworth 
get_subdev_active_format(struct vip_port * port,struct v4l2_subdev * subdev)3156fc2873aaSDale Farnsworth static int get_subdev_active_format(struct vip_port *port,
3157fc2873aaSDale Farnsworth 				    struct v4l2_subdev *subdev)
3158fc2873aaSDale Farnsworth {
3159fc2873aaSDale Farnsworth 	struct vip_fmt *fmt;
3160fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
3161fc2873aaSDale Farnsworth 	struct v4l2_subdev_mbus_code_enum mbus_code;
3162fc2873aaSDale Farnsworth 	int ret = 0;
3163fc2873aaSDale Farnsworth 	unsigned int k, i, j;
3164fc2873aaSDale Farnsworth 	enum vip_csc_state csc;
3165fc2873aaSDale Farnsworth 
3166fc2873aaSDale Farnsworth 	/* Enumerate sub device formats and enable all matching local formats */
3167fc2873aaSDale Farnsworth 	port->num_active_fmt = 0;
3168fc2873aaSDale Farnsworth 	for (k = 0, i = 0; (ret != -EINVAL); k++) {
3169fc2873aaSDale Farnsworth 		memset(&mbus_code, 0, sizeof(mbus_code));
3170fc2873aaSDale Farnsworth 		mbus_code.index = k;
3171fc2873aaSDale Farnsworth 		mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
3172fc2873aaSDale Farnsworth 		ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
3173fc2873aaSDale Farnsworth 				       NULL, &mbus_code);
3174fc2873aaSDale Farnsworth 		if (ret)
3175fc2873aaSDale Farnsworth 			continue;
3176fc2873aaSDale Farnsworth 
3177fc2873aaSDale Farnsworth 		v4l2_dbg(2, debug, &dev->v4l2_dev,
3178fc2873aaSDale Farnsworth 			 "subdev %s: code: %04x idx: %d\n",
3179fc2873aaSDale Farnsworth 			 subdev->name, mbus_code.code, k);
3180fc2873aaSDale Farnsworth 
3181fc2873aaSDale Farnsworth 		for (j = 0; j < ARRAY_SIZE(vip_formats); j++) {
3182fc2873aaSDale Farnsworth 			fmt = &vip_formats[j];
3183fc2873aaSDale Farnsworth 			if (mbus_code.code != fmt->code)
3184fc2873aaSDale Farnsworth 				continue;
3185fc2873aaSDale Farnsworth 
3186fc2873aaSDale Farnsworth 			/*
3187fc2873aaSDale Farnsworth 			 * When the port is configured for BT656
3188fc2873aaSDale Farnsworth 			 * then none of the downstream unit can be used.
3189fc2873aaSDale Farnsworth 			 * So here we need to skip all format requiring
3190fc2873aaSDale Farnsworth 			 * either CSC or CHR_DS
3191fc2873aaSDale Farnsworth 			 */
3192fc2873aaSDale Farnsworth 			csc = vip_csc_direction(fmt->code, fmt->finfo);
3193fc2873aaSDale Farnsworth 			if (port->endpoint.bus_type == V4L2_MBUS_BT656 &&
3194fc2873aaSDale Farnsworth 			    (csc != VIP_CSC_NA || fmt->coplanar))
3195fc2873aaSDale Farnsworth 				continue;
3196fc2873aaSDale Farnsworth 
3197fc2873aaSDale Farnsworth 			port->active_fmt[i] = fmt;
3198fc2873aaSDale Farnsworth 			v4l2_dbg(2, debug, &dev->v4l2_dev,
3199fc2873aaSDale Farnsworth 				 "matched fourcc: %s: code: %04x idx: %d\n",
3200fc2873aaSDale Farnsworth 				 fourcc_to_str(fmt->fourcc), fmt->code, i);
3201fc2873aaSDale Farnsworth 			port->num_active_fmt = ++i;
3202fc2873aaSDale Farnsworth 		}
3203fc2873aaSDale Farnsworth 	}
3204fc2873aaSDale Farnsworth 
3205fc2873aaSDale Farnsworth 	if (i == 0) {
3206fc2873aaSDale Farnsworth 		v4l2_err(&dev->v4l2_dev, "No suitable format reported by subdev %s\n",
3207fc2873aaSDale Farnsworth 			 subdev->name);
3208fc2873aaSDale Farnsworth 		return -EINVAL;
3209fc2873aaSDale Farnsworth 	}
3210fc2873aaSDale Farnsworth 	return 0;
3211fc2873aaSDale Farnsworth }
3212fc2873aaSDale Farnsworth 
alloc_port(struct vip_dev * dev,int id)3213fc2873aaSDale Farnsworth static int alloc_port(struct vip_dev *dev, int id)
3214fc2873aaSDale Farnsworth {
3215fc2873aaSDale Farnsworth 	struct vip_port *port;
3216fc2873aaSDale Farnsworth 
3217fc2873aaSDale Farnsworth 	if (dev->ports[id])
3218fc2873aaSDale Farnsworth 		return -EINVAL;
3219fc2873aaSDale Farnsworth 
3220fc2873aaSDale Farnsworth 	port = devm_kzalloc(&dev->pdev->dev, sizeof(*port), GFP_KERNEL);
3221fc2873aaSDale Farnsworth 	if (!port)
3222fc2873aaSDale Farnsworth 		return -ENOMEM;
3223fc2873aaSDale Farnsworth 
3224fc2873aaSDale Farnsworth 	dev->ports[id] = port;
3225fc2873aaSDale Farnsworth 	port->dev = dev;
3226fc2873aaSDale Farnsworth 	port->port_id = id;
3227fc2873aaSDale Farnsworth 	port->num_streams = 0;
3228fc2873aaSDale Farnsworth 	return 0;
3229fc2873aaSDale Farnsworth }
3230fc2873aaSDale Farnsworth 
free_port(struct vip_port * port)3231fc2873aaSDale Farnsworth static void free_port(struct vip_port *port)
3232fc2873aaSDale Farnsworth {
3233fc2873aaSDale Farnsworth 	if (!port)
3234fc2873aaSDale Farnsworth 		return;
3235fc2873aaSDale Farnsworth 
3236fc2873aaSDale Farnsworth 	v4l2_async_nf_unregister(&port->notifier);
3237fc2873aaSDale Farnsworth 	v4l2_async_nf_cleanup(&port->notifier);
3238fc2873aaSDale Farnsworth 	free_stream(port->cap_streams[0]);
3239fc2873aaSDale Farnsworth }
3240fc2873aaSDale Farnsworth 
get_field(u32 value,u32 mask,int shift)3241fc2873aaSDale Farnsworth static int get_field(u32 value, u32 mask, int shift)
3242fc2873aaSDale Farnsworth {
3243fc2873aaSDale Farnsworth 	return (value & (mask << shift)) >> shift;
3244fc2873aaSDale Farnsworth }
3245fc2873aaSDale Farnsworth 
3246fc2873aaSDale Farnsworth static int vip_probe_complete(struct platform_device *pdev);
vip_vpdma_fw_cb(struct platform_device * pdev)3247fc2873aaSDale Farnsworth static void vip_vpdma_fw_cb(struct platform_device *pdev)
3248fc2873aaSDale Farnsworth {
3249fc2873aaSDale Farnsworth 	dev_info(&pdev->dev, "VPDMA firmware loaded\n");
3250fc2873aaSDale Farnsworth 
3251fc2873aaSDale Farnsworth 	if (pdev->dev.of_node)
3252fc2873aaSDale Farnsworth 		vip_probe_complete(pdev);
3253fc2873aaSDale Farnsworth }
3254fc2873aaSDale Farnsworth 
vip_create_streams(struct vip_port * port,struct v4l2_subdev * subdev)3255fc2873aaSDale Farnsworth static int vip_create_streams(struct vip_port *port,
3256fc2873aaSDale Farnsworth 			      struct v4l2_subdev *subdev)
3257fc2873aaSDale Farnsworth {
3258fc2873aaSDale Farnsworth 	int i;
3259fc2873aaSDale Farnsworth 
3260fc2873aaSDale Farnsworth 	for (i = 0; i < VIP_CAP_STREAMS_PER_PORT; i++)
3261fc2873aaSDale Farnsworth 		free_stream(port->cap_streams[i]);
3262fc2873aaSDale Farnsworth 
3263fc2873aaSDale Farnsworth 	if (get_subdev_active_format(port, subdev))
3264fc2873aaSDale Farnsworth 		return -ENODEV;
3265fc2873aaSDale Farnsworth 
3266fc2873aaSDale Farnsworth 	port->subdev = subdev;
3267fc2873aaSDale Farnsworth 
3268fc2873aaSDale Farnsworth 	if (port->endpoint.bus_type == V4L2_MBUS_PARALLEL) {
3269fc2873aaSDale Farnsworth 		port->flags |= FLAG_MULT_PORT;
3270fc2873aaSDale Farnsworth 		port->num_streams_configured = 1;
3271fc2873aaSDale Farnsworth 		alloc_stream(port, 0, VFL_TYPE_VIDEO);
3272fc2873aaSDale Farnsworth 	} else if (port->endpoint.bus_type == V4L2_MBUS_BT656) {
3273fc2873aaSDale Farnsworth 		port->flags |= FLAG_MULT_PORT;
3274fc2873aaSDale Farnsworth 		port->num_streams_configured = 1;
3275fc2873aaSDale Farnsworth 		alloc_stream(port, 0, VFL_TYPE_VIDEO);
3276fc2873aaSDale Farnsworth 	}
3277fc2873aaSDale Farnsworth 	return 0;
3278fc2873aaSDale Farnsworth }
3279fc2873aaSDale Farnsworth 
vip_async_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)3280fc2873aaSDale Farnsworth static int vip_async_bound(struct v4l2_async_notifier *notifier,
3281fc2873aaSDale Farnsworth 			   struct v4l2_subdev *subdev,
3282fc2873aaSDale Farnsworth 			   struct v4l2_async_connection *asd)
3283fc2873aaSDale Farnsworth {
3284fc2873aaSDale Farnsworth 	struct vip_port *port = notifier_to_vip_port(notifier);
3285fc2873aaSDale Farnsworth 	int ret;
3286fc2873aaSDale Farnsworth 
3287fc2873aaSDale Farnsworth 	if (port->subdev) {
3288fc2873aaSDale Farnsworth 		v4l2_info(&port->dev->v4l2_dev, "Rejecting subdev %s (Already set!!)",
3289fc2873aaSDale Farnsworth 			  subdev->name);
3290fc2873aaSDale Farnsworth 		return 0;
3291fc2873aaSDale Farnsworth 	}
3292fc2873aaSDale Farnsworth 
3293fc2873aaSDale Farnsworth 	v4l2_info(&port->dev->v4l2_dev, "Port %c: Using subdev %s for capture\n",
3294fc2873aaSDale Farnsworth 		  port->port_id == VIP_PORTA ? 'A' : 'B', subdev->name);
3295fc2873aaSDale Farnsworth 
3296fc2873aaSDale Farnsworth 	ret = vip_create_streams(port, subdev);
3297fc2873aaSDale Farnsworth 	if (ret)
3298fc2873aaSDale Farnsworth 		return ret;
3299fc2873aaSDale Farnsworth 
3300fc2873aaSDale Farnsworth 	return 0;
3301fc2873aaSDale Farnsworth }
3302fc2873aaSDale Farnsworth 
vip_async_complete(struct v4l2_async_notifier * notifier)3303fc2873aaSDale Farnsworth static int vip_async_complete(struct v4l2_async_notifier *notifier)
3304fc2873aaSDale Farnsworth {
3305fc2873aaSDale Farnsworth 	return 0;
3306fc2873aaSDale Farnsworth }
3307fc2873aaSDale Farnsworth 
3308fc2873aaSDale Farnsworth static const struct v4l2_async_notifier_operations vip_async_ops = {
3309fc2873aaSDale Farnsworth 	.bound = vip_async_bound,
3310fc2873aaSDale Farnsworth 	.complete = vip_async_complete,
3311fc2873aaSDale Farnsworth };
3312fc2873aaSDale Farnsworth 
3313fc2873aaSDale Farnsworth static struct fwnode_handle *
fwnode_graph_get_next_endpoint_by_regs(const struct fwnode_handle * fwnode,int port_reg,int reg)3314fc2873aaSDale Farnsworth fwnode_graph_get_next_endpoint_by_regs(const struct fwnode_handle *fwnode,
3315fc2873aaSDale Farnsworth 				       int port_reg, int reg)
3316fc2873aaSDale Farnsworth {
3317fc2873aaSDale Farnsworth 	return of_fwnode_handle(of_graph_get_endpoint_by_regs(to_of_node(fwnode),
3318fc2873aaSDale Farnsworth 							      port_reg, reg));
3319fc2873aaSDale Farnsworth }
3320fc2873aaSDale Farnsworth 
vip_register_subdev_notify(struct vip_port * port,struct fwnode_handle * ep)3321fc2873aaSDale Farnsworth static int vip_register_subdev_notify(struct vip_port *port,
3322fc2873aaSDale Farnsworth 				      struct fwnode_handle *ep)
3323fc2873aaSDale Farnsworth {
3324fc2873aaSDale Farnsworth 	struct v4l2_async_notifier *notifier = &port->notifier;
3325fc2873aaSDale Farnsworth 	struct fwnode_handle *subdev;
3326fc2873aaSDale Farnsworth 	struct v4l2_fwnode_endpoint *vep;
3327fc2873aaSDale Farnsworth 	struct v4l2_async_connection *asd;
3328fc2873aaSDale Farnsworth 	int ret;
3329fc2873aaSDale Farnsworth 	struct vip_dev *dev = port->dev;
3330fc2873aaSDale Farnsworth 
3331fc2873aaSDale Farnsworth 	vep = &port->endpoint;
3332fc2873aaSDale Farnsworth 
3333fc2873aaSDale Farnsworth 	subdev = fwnode_graph_get_remote_port_parent(ep);
3334fc2873aaSDale Farnsworth 	if (!subdev) {
3335fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "can't get remote parent\n");
3336fc2873aaSDale Farnsworth 		return -EINVAL;
3337fc2873aaSDale Farnsworth 	}
3338fc2873aaSDale Farnsworth 
3339fc2873aaSDale Farnsworth 	ret = v4l2_fwnode_endpoint_parse(ep, vep);
3340fc2873aaSDale Farnsworth 	if (ret) {
3341fc2873aaSDale Farnsworth 		v4l2_dbg(3, debug, &dev->v4l2_dev, "Failed to parse endpoint:\n");
3342fc2873aaSDale Farnsworth 		fwnode_handle_put(subdev);
3343fc2873aaSDale Farnsworth 		return -EINVAL;
3344fc2873aaSDale Farnsworth 	}
3345fc2873aaSDale Farnsworth 
3346fc2873aaSDale Farnsworth 	v4l2_async_nf_init(notifier, &port->dev->shared->v4l2_dev);
3347fc2873aaSDale Farnsworth 
3348fc2873aaSDale Farnsworth 	asd = v4l2_async_nf_add_fwnode(notifier, subdev, struct v4l2_async_connection);
3349fc2873aaSDale Farnsworth 	if (IS_ERR(asd)) {
3350fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "Error adding asd\n");
3351fc2873aaSDale Farnsworth 		fwnode_handle_put(subdev);
3352fc2873aaSDale Farnsworth 		v4l2_async_nf_cleanup(notifier);
3353fc2873aaSDale Farnsworth 		return -EINVAL;
3354fc2873aaSDale Farnsworth 	}
3355fc2873aaSDale Farnsworth 
3356fc2873aaSDale Farnsworth 	notifier->ops = &vip_async_ops;
3357fc2873aaSDale Farnsworth 	ret = v4l2_async_nf_register(notifier);
3358fc2873aaSDale Farnsworth 	if (ret) {
3359fc2873aaSDale Farnsworth 		v4l2_dbg(1, debug, &dev->v4l2_dev, "Error registering async notifier\n");
3360fc2873aaSDale Farnsworth 		v4l2_async_nf_cleanup(notifier);
3361fc2873aaSDale Farnsworth 		ret = -EINVAL;
3362fc2873aaSDale Farnsworth 	}
3363fc2873aaSDale Farnsworth 
3364fc2873aaSDale Farnsworth 	return ret;
3365fc2873aaSDale Farnsworth }
3366fc2873aaSDale Farnsworth 
vip_endpoint_scan(struct platform_device * pdev)3367fc2873aaSDale Farnsworth static int vip_endpoint_scan(struct platform_device *pdev)
3368fc2873aaSDale Farnsworth {
3369fc2873aaSDale Farnsworth 	struct device_node *parent = pdev->dev.of_node;
3370fc2873aaSDale Farnsworth 	struct device_node *ep = NULL;
3371fc2873aaSDale Farnsworth 	int count = 0, p;
3372fc2873aaSDale Farnsworth 
3373fc2873aaSDale Farnsworth 	for (p = 0; p < (VIP_NUM_PORTS * VIP_NUM_SLICES); p++) {
3374fc2873aaSDale Farnsworth 		ep = of_graph_get_endpoint_by_regs(parent, p, 0);
3375fc2873aaSDale Farnsworth 		if (!ep)
3376fc2873aaSDale Farnsworth 			continue;
3377fc2873aaSDale Farnsworth 
3378fc2873aaSDale Farnsworth 		count++;
3379fc2873aaSDale Farnsworth 		of_node_put(ep);
3380fc2873aaSDale Farnsworth 	}
3381fc2873aaSDale Farnsworth 
3382fc2873aaSDale Farnsworth 	return count;
3383fc2873aaSDale Farnsworth }
3384fc2873aaSDale Farnsworth 
vip_probe_complete(struct platform_device * pdev)3385fc2873aaSDale Farnsworth static int vip_probe_complete(struct platform_device *pdev)
3386fc2873aaSDale Farnsworth {
3387fc2873aaSDale Farnsworth 	struct vip_shared *shared = platform_get_drvdata(pdev);
3388fc2873aaSDale Farnsworth 	struct vip_ctrl_module *ctrl = NULL;
3389fc2873aaSDale Farnsworth 	struct vip_port *port;
3390fc2873aaSDale Farnsworth 	struct vip_dev *dev;
3391fc2873aaSDale Farnsworth 	struct device_node *parent = pdev->dev.of_node;
3392fc2873aaSDale Farnsworth 	struct fwnode_handle *ep = NULL;
3393fc2873aaSDale Farnsworth 	unsigned int syscon_args[5];
3394fc2873aaSDale Farnsworth 	int ret, i, slice_id, port_id, p;
3395fc2873aaSDale Farnsworth 
3396fc2873aaSDale Farnsworth 	/* Allocate ctrl before using it */
3397fc2873aaSDale Farnsworth 	ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
3398fc2873aaSDale Farnsworth 	if (!ctrl)
3399fc2873aaSDale Farnsworth 		return -ENOMEM;
3400fc2873aaSDale Farnsworth 
3401fc2873aaSDale Farnsworth 	ctrl->syscon_pol = syscon_regmap_lookup_by_phandle_args(parent, "ti,ctrl-module",
3402fc2873aaSDale Farnsworth 								5, syscon_args);
3403fc2873aaSDale Farnsworth 
3404fc2873aaSDale Farnsworth 	if (IS_ERR(ctrl->syscon_pol))
3405fc2873aaSDale Farnsworth 		return dev_err_probe(&pdev->dev, PTR_ERR(ctrl->syscon_pol),
3406fc2873aaSDale Farnsworth 				     "Failed to get ti,ctrl-module\n");
3407fc2873aaSDale Farnsworth 
3408fc2873aaSDale Farnsworth 	ctrl->syscon_offset = syscon_args[0];
3409fc2873aaSDale Farnsworth 
3410fc2873aaSDale Farnsworth 	for (i = 0; i < ARRAY_SIZE(ctrl->syscon_bit_field); i++)
3411fc2873aaSDale Farnsworth 		ctrl->syscon_bit_field[i] = syscon_args[i + 1];
3412fc2873aaSDale Farnsworth 
3413fc2873aaSDale Farnsworth 	for (p = 0; p < (VIP_NUM_PORTS * VIP_NUM_SLICES); p++) {
3414fc2873aaSDale Farnsworth 		ep = fwnode_graph_get_next_endpoint_by_regs(of_fwnode_handle(parent),
3415fc2873aaSDale Farnsworth 							    p, 0);
3416fc2873aaSDale Farnsworth 		if (!ep)
3417fc2873aaSDale Farnsworth 			continue;
3418fc2873aaSDale Farnsworth 
3419fc2873aaSDale Farnsworth 		switch (p) {
3420fc2873aaSDale Farnsworth 		case 0:
3421fc2873aaSDale Farnsworth 			slice_id = VIP_SLICE1;
3422fc2873aaSDale Farnsworth 			port_id = VIP_PORTA;
3423fc2873aaSDale Farnsworth 			break;
3424fc2873aaSDale Farnsworth 		case 1:
3425fc2873aaSDale Farnsworth 			slice_id = VIP_SLICE2;
3426fc2873aaSDale Farnsworth 			port_id = VIP_PORTA;
3427fc2873aaSDale Farnsworth 			break;
3428fc2873aaSDale Farnsworth 		case 2:
3429fc2873aaSDale Farnsworth 			slice_id = VIP_SLICE1;
3430fc2873aaSDale Farnsworth 			port_id = VIP_PORTB;
3431fc2873aaSDale Farnsworth 			break;
3432fc2873aaSDale Farnsworth 		case 3:
3433fc2873aaSDale Farnsworth 			slice_id = VIP_SLICE2;
3434fc2873aaSDale Farnsworth 			port_id = VIP_PORTB;
3435fc2873aaSDale Farnsworth 			break;
3436fc2873aaSDale Farnsworth 		default:
3437fc2873aaSDale Farnsworth 			dev_err(&pdev->dev, "Unknown port reg=<%d>\n", p);
3438fc2873aaSDale Farnsworth 			continue;
3439fc2873aaSDale Farnsworth 		}
3440fc2873aaSDale Farnsworth 
3441fc2873aaSDale Farnsworth 		ret = alloc_port(shared->devs[slice_id], port_id);
3442fc2873aaSDale Farnsworth 		if (ret < 0)
3443fc2873aaSDale Farnsworth 			continue;
3444fc2873aaSDale Farnsworth 
3445fc2873aaSDale Farnsworth 		dev = shared->devs[slice_id];
3446fc2873aaSDale Farnsworth 		dev->syscon = ctrl;
3447fc2873aaSDale Farnsworth 		port = dev->ports[port_id];
3448fc2873aaSDale Farnsworth 
3449fc2873aaSDale Farnsworth 		vip_register_subdev_notify(port, ep);
3450fc2873aaSDale Farnsworth 		fwnode_handle_put(ep);
3451fc2873aaSDale Farnsworth 	}
3452fc2873aaSDale Farnsworth 	return 0;
3453fc2873aaSDale Farnsworth }
3454fc2873aaSDale Farnsworth 
vip_probe_slice(struct platform_device * pdev,int slice)3455fc2873aaSDale Farnsworth static int vip_probe_slice(struct platform_device *pdev, int slice)
3456fc2873aaSDale Farnsworth {
3457fc2873aaSDale Farnsworth 	struct vip_shared *shared = platform_get_drvdata(pdev);
3458fc2873aaSDale Farnsworth 	struct vip_dev *dev;
3459fc2873aaSDale Farnsworth 	struct vip_parser_data *parser;
3460fc2873aaSDale Farnsworth 	struct sc_data *sc;
3461fc2873aaSDale Farnsworth 	struct csc_data *csc;
3462fc2873aaSDale Farnsworth 	int ret;
3463fc2873aaSDale Farnsworth 
3464fc2873aaSDale Farnsworth 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
3465fc2873aaSDale Farnsworth 	if (!dev)
3466fc2873aaSDale Farnsworth 		return -ENOMEM;
3467fc2873aaSDale Farnsworth 
3468fc2873aaSDale Farnsworth 	dev->irq = platform_get_irq(pdev, slice);
3469fc2873aaSDale Farnsworth 	if (dev->irq < 0)
3470fc2873aaSDale Farnsworth 		return dev->irq;
3471fc2873aaSDale Farnsworth 
3472fc2873aaSDale Farnsworth 	ret = devm_request_irq(&pdev->dev, dev->irq, vip_irq,
3473fc2873aaSDale Farnsworth 			       0, VIP_MODULE_NAME, dev);
3474fc2873aaSDale Farnsworth 	if (ret < 0)
3475fc2873aaSDale Farnsworth 		return -ENOMEM;
3476fc2873aaSDale Farnsworth 
3477fc2873aaSDale Farnsworth 	spin_lock_init(&dev->slock);
3478fc2873aaSDale Farnsworth 	mutex_init(&dev->mutex);
3479fc2873aaSDale Farnsworth 
3480fc2873aaSDale Farnsworth 	dev->slice_id = slice;
3481fc2873aaSDale Farnsworth 	dev->pdev = pdev;
3482fc2873aaSDale Farnsworth 	dev->base = shared->base;
3483fc2873aaSDale Farnsworth 	dev->v4l2_dev = shared->v4l2_dev;
3484fc2873aaSDale Farnsworth 
3485fc2873aaSDale Farnsworth 	dev->shared = shared;
3486fc2873aaSDale Farnsworth 	shared->devs[slice] = dev;
3487fc2873aaSDale Farnsworth 
3488fc2873aaSDale Farnsworth 	vip_top_reset(dev);
3489fc2873aaSDale Farnsworth 	vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT, 1);
3490fc2873aaSDale Farnsworth 
3491fc2873aaSDale Farnsworth 	parser = devm_kzalloc(&pdev->dev, sizeof(*dev->parser), GFP_KERNEL);
3492fc2873aaSDale Farnsworth 	if (!parser)
3493fc2873aaSDale Farnsworth 		return PTR_ERR_OR_ZERO(parser);
3494fc2873aaSDale Farnsworth 
3495fc2873aaSDale Farnsworth 	parser->base = dev->base + (slice ? VIP_SLICE1_PARSER : VIP_SLICE0_PARSER);
3496fc2873aaSDale Farnsworth 	if (IS_ERR(parser->base))
3497fc2873aaSDale Farnsworth 		return PTR_ERR(parser->base);
3498fc2873aaSDale Farnsworth 
3499fc2873aaSDale Farnsworth 	parser->pdev = pdev;
3500fc2873aaSDale Farnsworth 	dev->parser = parser;
3501fc2873aaSDale Farnsworth 
3502fc2873aaSDale Farnsworth 	dev->sc_assigned = VIP_NOT_ASSIGNED;
3503fc2873aaSDale Farnsworth 	sc = devm_kzalloc(&pdev->dev, sizeof(*dev->sc), GFP_KERNEL);
3504fc2873aaSDale Farnsworth 	if (!sc)
3505fc2873aaSDale Farnsworth 		return PTR_ERR_OR_ZERO(sc);
3506fc2873aaSDale Farnsworth 
3507fc2873aaSDale Farnsworth 	sc->base = dev->base + (slice ? VIP_SLICE1_SC : VIP_SLICE0_SC);
3508fc2873aaSDale Farnsworth 	if (IS_ERR(sc->base))
3509fc2873aaSDale Farnsworth 		return PTR_ERR(sc->base);
3510fc2873aaSDale Farnsworth 
3511fc2873aaSDale Farnsworth 	sc->pdev = pdev;
3512fc2873aaSDale Farnsworth 	dev->sc = sc;
3513fc2873aaSDale Farnsworth 
3514fc2873aaSDale Farnsworth 	dev->csc_assigned = VIP_NOT_ASSIGNED;
3515fc2873aaSDale Farnsworth 	csc = devm_kzalloc(&pdev->dev, sizeof(*dev->csc), GFP_KERNEL);
3516fc2873aaSDale Farnsworth 	if (!csc)
3517fc2873aaSDale Farnsworth 		return PTR_ERR_OR_ZERO(csc);
3518fc2873aaSDale Farnsworth 
3519fc2873aaSDale Farnsworth 	csc->base = dev->base + (slice ? VIP_SLICE1_CSC : VIP_SLICE0_CSC);
3520fc2873aaSDale Farnsworth 	if (IS_ERR(csc->base))
3521fc2873aaSDale Farnsworth 		return PTR_ERR(csc->base);
3522fc2873aaSDale Farnsworth 
3523fc2873aaSDale Farnsworth 	csc->pdev = pdev;
3524fc2873aaSDale Farnsworth 	dev->csc = csc;
3525fc2873aaSDale Farnsworth 
3526fc2873aaSDale Farnsworth 	return 0;
3527fc2873aaSDale Farnsworth }
3528fc2873aaSDale Farnsworth 
vip_probe(struct platform_device * pdev)3529fc2873aaSDale Farnsworth static int vip_probe(struct platform_device *pdev)
3530fc2873aaSDale Farnsworth {
3531fc2873aaSDale Farnsworth 	struct vip_shared *shared;
3532fc2873aaSDale Farnsworth 	int ret, slice = VIP_SLICE1;
3533fc2873aaSDale Farnsworth 	u32 tmp, pid;
3534fc2873aaSDale Farnsworth 
3535fc2873aaSDale Farnsworth 	/* If there are no endpoint defined there is nothing to do */
3536fc2873aaSDale Farnsworth 	if (!vip_endpoint_scan(pdev)) {
3537fc2873aaSDale Farnsworth 		dev_err(&pdev->dev, "%s: No sensor", __func__);
3538fc2873aaSDale Farnsworth 		return -ENODEV;
3539fc2873aaSDale Farnsworth 	}
3540fc2873aaSDale Farnsworth 
3541fc2873aaSDale Farnsworth 	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
3542fc2873aaSDale Farnsworth 	if (ret) {
3543fc2873aaSDale Farnsworth 		dev_err(&pdev->dev,
3544fc2873aaSDale Farnsworth 			"32-bit consistent DMA enable failed\n");
3545fc2873aaSDale Farnsworth 		return ret;
3546fc2873aaSDale Farnsworth 	}
3547fc2873aaSDale Farnsworth 
3548fc2873aaSDale Farnsworth 	shared = devm_kzalloc(&pdev->dev, sizeof(*shared), GFP_KERNEL);
3549fc2873aaSDale Farnsworth 	if (!shared)
3550fc2873aaSDale Farnsworth 		return -ENOMEM;
3551fc2873aaSDale Farnsworth 
3552fc2873aaSDale Farnsworth 	shared->base = devm_platform_ioremap_resource(pdev, 0);
3553fc2873aaSDale Farnsworth 	if (IS_ERR(shared->base))
3554fc2873aaSDale Farnsworth 		return PTR_ERR(shared->base);
3555fc2873aaSDale Farnsworth 
3556fc2873aaSDale Farnsworth 	vip_init_format_info(&pdev->dev);
3557fc2873aaSDale Farnsworth 
3558fc2873aaSDale Farnsworth 	pm_runtime_enable(&pdev->dev);
3559fc2873aaSDale Farnsworth 
3560fc2873aaSDale Farnsworth 	ret = pm_runtime_get_sync(&pdev->dev);
3561fc2873aaSDale Farnsworth 	if (ret < 0)
3562fc2873aaSDale Farnsworth 		goto err_runtime_disable;
3563fc2873aaSDale Farnsworth 
3564fc2873aaSDale Farnsworth 	/* Make sure H/W module has the right functionality */
3565fc2873aaSDale Farnsworth 	pid = reg_read(shared, VIP_PID);
3566fc2873aaSDale Farnsworth 	tmp = get_field(pid, VIP_PID_FUNC_MASK, VIP_PID_FUNC_SHIFT);
3567fc2873aaSDale Farnsworth 
3568fc2873aaSDale Farnsworth 	if (tmp != VIP_PID_FUNC) {
3569fc2873aaSDale Farnsworth 		dev_info(&pdev->dev, "vip: unexpected PID function: 0x%x\n",
3570fc2873aaSDale Farnsworth 			 tmp);
3571fc2873aaSDale Farnsworth 		ret = -ENODEV;
3572fc2873aaSDale Farnsworth 		goto err_runtime_put;
3573fc2873aaSDale Farnsworth 	}
3574fc2873aaSDale Farnsworth 
3575fc2873aaSDale Farnsworth 	ret = v4l2_device_register(&pdev->dev, &shared->v4l2_dev);
3576fc2873aaSDale Farnsworth 	if (ret)
3577fc2873aaSDale Farnsworth 		goto err_runtime_put;
3578fc2873aaSDale Farnsworth 
3579fc2873aaSDale Farnsworth 	/* enable clocks, so the firmware will load properly */
3580fc2873aaSDale Farnsworth 	vip_shared_set_clock_enable(shared, 1);
3581fc2873aaSDale Farnsworth 	vip_top_vpdma_reset(shared);
3582fc2873aaSDale Farnsworth 
3583fc2873aaSDale Farnsworth 	platform_set_drvdata(pdev, shared);
3584fc2873aaSDale Farnsworth 
3585fc2873aaSDale Farnsworth 	v4l2_ctrl_handler_init(&shared->ctrl_handler, 11);
3586fc2873aaSDale Farnsworth 	shared->v4l2_dev.ctrl_handler = &shared->ctrl_handler;
3587fc2873aaSDale Farnsworth 
3588fc2873aaSDale Farnsworth 	for (slice = VIP_SLICE1; slice < VIP_NUM_SLICES; slice++) {
3589fc2873aaSDale Farnsworth 		ret = vip_probe_slice(pdev, slice);
3590fc2873aaSDale Farnsworth 		if (ret) {
3591fc2873aaSDale Farnsworth 			dev_err(&pdev->dev, "Creating slice failed");
3592fc2873aaSDale Farnsworth 			goto err_dev_unreg;
3593fc2873aaSDale Farnsworth 		}
3594fc2873aaSDale Farnsworth 	}
3595fc2873aaSDale Farnsworth 
3596fc2873aaSDale Farnsworth 	shared->vpdma = &shared->vpdma_data;
3597fc2873aaSDale Farnsworth 
3598fc2873aaSDale Farnsworth 	shared->vpdma->pdev = pdev;
3599fc2873aaSDale Farnsworth 	shared->vpdma->cb = vip_vpdma_fw_cb;
3600fc2873aaSDale Farnsworth 	spin_lock_init(&shared->vpdma->lock);
3601fc2873aaSDale Farnsworth 
3602fc2873aaSDale Farnsworth 	shared->vpdma->base = shared->base + VIP_VPDMA_BASE;
3603fc2873aaSDale Farnsworth 	if (!shared->vpdma->base) {
3604fc2873aaSDale Farnsworth 		dev_err(&pdev->dev, "failed to ioremap\n");
3605fc2873aaSDale Farnsworth 		ret = -ENOMEM;
3606fc2873aaSDale Farnsworth 		goto err_dev_unreg;
3607fc2873aaSDale Farnsworth 	}
3608fc2873aaSDale Farnsworth 
3609fc2873aaSDale Farnsworth 	ret = vpdma_load_firmware(shared->vpdma);
3610fc2873aaSDale Farnsworth 	if (ret) {
3611fc2873aaSDale Farnsworth 		dev_err(&pdev->dev, "Creating VPDMA failed");
3612fc2873aaSDale Farnsworth 		goto err_dev_unreg;
3613fc2873aaSDale Farnsworth 	}
3614fc2873aaSDale Farnsworth 
3615fc2873aaSDale Farnsworth 	return 0;
3616fc2873aaSDale Farnsworth 
3617fc2873aaSDale Farnsworth err_dev_unreg:
3618fc2873aaSDale Farnsworth 	v4l2_ctrl_handler_free(&shared->ctrl_handler);
3619fc2873aaSDale Farnsworth 	v4l2_device_unregister(&shared->v4l2_dev);
3620fc2873aaSDale Farnsworth err_runtime_put:
3621fc2873aaSDale Farnsworth 	pm_runtime_put_sync(&pdev->dev);
3622fc2873aaSDale Farnsworth err_runtime_disable:
3623fc2873aaSDale Farnsworth 	pm_runtime_disable(&pdev->dev);
3624fc2873aaSDale Farnsworth 
3625fc2873aaSDale Farnsworth 	return ret;
3626fc2873aaSDale Farnsworth }
3627fc2873aaSDale Farnsworth 
vip_remove(struct platform_device * pdev)3628fc2873aaSDale Farnsworth static void vip_remove(struct platform_device *pdev)
3629fc2873aaSDale Farnsworth {
3630fc2873aaSDale Farnsworth 	struct vip_shared *shared = platform_get_drvdata(pdev);
3631fc2873aaSDale Farnsworth 	struct vip_dev *dev;
3632fc2873aaSDale Farnsworth 	int slice;
3633fc2873aaSDale Farnsworth 
3634fc2873aaSDale Farnsworth 	for (slice = 0; slice < VIP_NUM_SLICES; slice++) {
3635fc2873aaSDale Farnsworth 		dev = shared->devs[slice];
3636fc2873aaSDale Farnsworth 		if (!dev)
3637fc2873aaSDale Farnsworth 			continue;
3638fc2873aaSDale Farnsworth 
3639fc2873aaSDale Farnsworth 		free_port(dev->ports[VIP_PORTA]);
3640fc2873aaSDale Farnsworth 		free_port(dev->ports[VIP_PORTB]);
3641fc2873aaSDale Farnsworth 	}
3642fc2873aaSDale Farnsworth 
3643fc2873aaSDale Farnsworth 	v4l2_ctrl_handler_free(&shared->ctrl_handler);
3644fc2873aaSDale Farnsworth 
3645fc2873aaSDale Farnsworth 	pm_runtime_put_sync(&pdev->dev);
3646fc2873aaSDale Farnsworth 	pm_runtime_disable(&pdev->dev);
3647fc2873aaSDale Farnsworth }
3648fc2873aaSDale Farnsworth 
3649fc2873aaSDale Farnsworth #if defined(CONFIG_OF)
3650fc2873aaSDale Farnsworth static const struct of_device_id vip_of_match[] = {
3651fc2873aaSDale Farnsworth 	{
3652fc2873aaSDale Farnsworth 		.compatible = "ti,dra7-vip",
3653fc2873aaSDale Farnsworth 	},
3654fc2873aaSDale Farnsworth 	{},
3655fc2873aaSDale Farnsworth };
3656fc2873aaSDale Farnsworth 
3657fc2873aaSDale Farnsworth MODULE_DEVICE_TABLE(of, vip_of_match);
3658fc2873aaSDale Farnsworth #endif
3659fc2873aaSDale Farnsworth 
3660fc2873aaSDale Farnsworth static struct platform_driver vip_pdrv = {
3661fc2873aaSDale Farnsworth 	.probe		= vip_probe,
3662fc2873aaSDale Farnsworth 	.remove		= vip_remove,
3663fc2873aaSDale Farnsworth 	.driver		= {
3664fc2873aaSDale Farnsworth 		.name	= VIP_MODULE_NAME,
3665fc2873aaSDale Farnsworth 		.of_match_table = of_match_ptr(vip_of_match),
3666fc2873aaSDale Farnsworth 	},
3667fc2873aaSDale Farnsworth };
3668fc2873aaSDale Farnsworth 
3669fc2873aaSDale Farnsworth module_platform_driver(vip_pdrv);
3670fc2873aaSDale Farnsworth 
3671fc2873aaSDale Farnsworth MODULE_DESCRIPTION("TI VIP driver");
3672fc2873aaSDale Farnsworth MODULE_AUTHOR("Texas Instruments");
3673fc2873aaSDale Farnsworth MODULE_LICENSE("GPL");
3674