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