xref: /openbmc/linux/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c (revision 5ee9cd065836e5934710ca35653bce7905add20b)
1e6938cc1SHelen Koike // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2e6938cc1SHelen Koike /*
3e6938cc1SHelen Koike  * Rockchip ISP1 Driver - V4l capture device
4e6938cc1SHelen Koike  *
5e6938cc1SHelen Koike  * Copyright (C) 2019 Collabora, Ltd.
6e6938cc1SHelen Koike  *
7e6938cc1SHelen Koike  * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
8e6938cc1SHelen Koike  * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
9e6938cc1SHelen Koike  */
10e6938cc1SHelen Koike 
11e6938cc1SHelen Koike #include <linux/delay.h>
12e6938cc1SHelen Koike #include <linux/pm_runtime.h>
13e6938cc1SHelen Koike #include <media/v4l2-common.h>
14e6938cc1SHelen Koike #include <media/v4l2-event.h>
15e6938cc1SHelen Koike #include <media/v4l2-fh.h>
16e6938cc1SHelen Koike #include <media/v4l2-ioctl.h>
17e6938cc1SHelen Koike #include <media/v4l2-mc.h>
18e6938cc1SHelen Koike #include <media/v4l2-subdev.h>
19e6938cc1SHelen Koike #include <media/videobuf2-dma-contig.h>
20e6938cc1SHelen Koike 
21e6938cc1SHelen Koike #include "rkisp1-common.h"
22e6938cc1SHelen Koike 
23e6938cc1SHelen Koike /*
24e6938cc1SHelen Koike  * NOTE: There are two capture video devices in rkisp1, selfpath and mainpath.
25e6938cc1SHelen Koike  *
26e6938cc1SHelen Koike  * differences between selfpath and mainpath
27e6938cc1SHelen Koike  * available mp sink input: isp
28e6938cc1SHelen Koike  * available sp sink input : isp, dma(TODO)
29e6938cc1SHelen Koike  * available mp sink pad fmts: yuv422, raw
30e6938cc1SHelen Koike  * available sp sink pad fmts: yuv422, yuv420......
31e6938cc1SHelen Koike  * available mp source fmts: yuv, raw, jpeg(TODO)
32e6938cc1SHelen Koike  * available sp source fmts: yuv, rgb
33e6938cc1SHelen Koike  */
34e6938cc1SHelen Koike 
35e6938cc1SHelen Koike #define RKISP1_SP_DEV_NAME	RKISP1_DRIVER_NAME "_selfpath"
36e6938cc1SHelen Koike #define RKISP1_MP_DEV_NAME	RKISP1_DRIVER_NAME "_mainpath"
37e6938cc1SHelen Koike 
38e6938cc1SHelen Koike #define RKISP1_MIN_BUFFERS_NEEDED 3
39e6938cc1SHelen Koike 
40e6938cc1SHelen Koike enum rkisp1_plane {
41e6938cc1SHelen Koike 	RKISP1_PLANE_Y	= 0,
42e6938cc1SHelen Koike 	RKISP1_PLANE_CB	= 1,
43e6938cc1SHelen Koike 	RKISP1_PLANE_CR	= 2
44e6938cc1SHelen Koike };
45e6938cc1SHelen Koike 
46e6938cc1SHelen Koike /*
47e6938cc1SHelen Koike  * @fourcc: pixel format
48e6938cc1SHelen Koike  * @fmt_type: helper filed for pixel format
496b94c09fSPeilin Ye  * @uv_swap: if cb cr swapped, for yuv
50e6938cc1SHelen Koike  * @write_format: defines how YCbCr self picture data is written to memory
51e6938cc1SHelen Koike  * @output_format: defines sp output format
52e6938cc1SHelen Koike  * @mbus: the mbus code on the src resizer pad that matches the pixel format
53e6938cc1SHelen Koike  */
54e6938cc1SHelen Koike struct rkisp1_capture_fmt_cfg {
55e6938cc1SHelen Koike 	u32 fourcc;
56e6938cc1SHelen Koike 	u8 uv_swap;
57e6938cc1SHelen Koike 	u32 write_format;
58e6938cc1SHelen Koike 	u32 output_format;
59e6938cc1SHelen Koike 	u32 mbus;
60e6938cc1SHelen Koike };
61e6938cc1SHelen Koike 
62e6938cc1SHelen Koike struct rkisp1_capture_ops {
63e6938cc1SHelen Koike 	void (*config)(struct rkisp1_capture *cap);
64e6938cc1SHelen Koike 	void (*stop)(struct rkisp1_capture *cap);
65e6938cc1SHelen Koike 	void (*enable)(struct rkisp1_capture *cap);
66e6938cc1SHelen Koike 	void (*disable)(struct rkisp1_capture *cap);
67e6938cc1SHelen Koike 	void (*set_data_path)(struct rkisp1_capture *cap);
68e6938cc1SHelen Koike 	bool (*is_stopped)(struct rkisp1_capture *cap);
69e6938cc1SHelen Koike };
70e6938cc1SHelen Koike 
71e6938cc1SHelen Koike struct rkisp1_capture_config {
72e6938cc1SHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmts;
73e6938cc1SHelen Koike 	int fmt_size;
74e6938cc1SHelen Koike 	struct {
75e6938cc1SHelen Koike 		u32 y_size_init;
76e6938cc1SHelen Koike 		u32 cb_size_init;
77e6938cc1SHelen Koike 		u32 cr_size_init;
78e6938cc1SHelen Koike 		u32 y_base_ad_init;
79e6938cc1SHelen Koike 		u32 cb_base_ad_init;
80e6938cc1SHelen Koike 		u32 cr_base_ad_init;
81e6938cc1SHelen Koike 		u32 y_offs_cnt_init;
82e6938cc1SHelen Koike 		u32 cb_offs_cnt_init;
83e6938cc1SHelen Koike 		u32 cr_offs_cnt_init;
84e6938cc1SHelen Koike 	} mi;
85e6938cc1SHelen Koike };
86e6938cc1SHelen Koike 
87e6938cc1SHelen Koike /*
88e6938cc1SHelen Koike  * The supported pixel formats for mainpath. NOTE, pixel formats with identical 'mbus'
89e6938cc1SHelen Koike  * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes
90e6938cc1SHelen Koike  */
91e6938cc1SHelen Koike static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
92e6938cc1SHelen Koike 	/* yuv422 */
93e6938cc1SHelen Koike 	{
94e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUYV,
95e6938cc1SHelen Koike 		.uv_swap = 0,
96e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT,
97e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
98e6938cc1SHelen Koike 	}, {
99e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV422P,
100e6938cc1SHelen Koike 		.uv_swap = 0,
101e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
102e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
103e6938cc1SHelen Koike 	}, {
104e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV16,
105e6938cc1SHelen Koike 		.uv_swap = 0,
106e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
107e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
108e6938cc1SHelen Koike 	}, {
109e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV61,
110e6938cc1SHelen Koike 		.uv_swap = 1,
111e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
112e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
113e6938cc1SHelen Koike 	}, {
1147cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV16M,
1157cb7018cSPaul Elder 		.uv_swap = 0,
1167cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1177cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
1187cb7018cSPaul Elder 	}, {
1197cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV61M,
1207cb7018cSPaul Elder 		.uv_swap = 1,
1217cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1227cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
1237cb7018cSPaul Elder 	}, {
124e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU422M,
125e6938cc1SHelen Koike 		.uv_swap = 1,
126e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
127e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
128e6938cc1SHelen Koike 	},
129e6938cc1SHelen Koike 	/* yuv400 */
130e6938cc1SHelen Koike 	{
131e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_GREY,
132e6938cc1SHelen Koike 		.uv_swap = 0,
133e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
134e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
135e6938cc1SHelen Koike 	},
136e6938cc1SHelen Koike 	/* yuv420 */
137e6938cc1SHelen Koike 	{
138e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21,
139e6938cc1SHelen Koike 		.uv_swap = 1,
140e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
141e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
142e6938cc1SHelen Koike 	}, {
143e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12,
144e6938cc1SHelen Koike 		.uv_swap = 0,
145e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
146e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
147e6938cc1SHelen Koike 	}, {
148e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21M,
149e6938cc1SHelen Koike 		.uv_swap = 1,
150e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
151e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
152e6938cc1SHelen Koike 	}, {
153e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12M,
154e6938cc1SHelen Koike 		.uv_swap = 0,
155e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
156e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
157e6938cc1SHelen Koike 	}, {
158e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV420,
159e6938cc1SHelen Koike 		.uv_swap = 0,
160e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
161e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
162e6938cc1SHelen Koike 	}, {
163e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU420,
164e6938cc1SHelen Koike 		.uv_swap = 1,
165e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
166e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
167e6938cc1SHelen Koike 	},
168e6938cc1SHelen Koike 	/* raw */
169e6938cc1SHelen Koike 	{
170e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB8,
171e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
172e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SRGGB8_1X8,
173e6938cc1SHelen Koike 	}, {
174e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG8,
175e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
176e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGRBG8_1X8,
177e6938cc1SHelen Koike 	}, {
178e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG8,
179e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
180e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGBRG8_1X8,
181e6938cc1SHelen Koike 	}, {
182e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR8,
183e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
184e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SBGGR8_1X8,
185e6938cc1SHelen Koike 	}, {
186e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB10,
187e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
188e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SRGGB10_1X10,
189e6938cc1SHelen Koike 	}, {
190e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG10,
191e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
192e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGRBG10_1X10,
193e6938cc1SHelen Koike 	}, {
194e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG10,
195e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
196e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGBRG10_1X10,
197e6938cc1SHelen Koike 	}, {
198e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR10,
199e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
200e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SBGGR10_1X10,
201e6938cc1SHelen Koike 	}, {
202e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB12,
203e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
204e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SRGGB12_1X12,
205e6938cc1SHelen Koike 	}, {
206e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG12,
207e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
208e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGRBG12_1X12,
209e6938cc1SHelen Koike 	}, {
210e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG12,
211e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
212e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SGBRG12_1X12,
213e6938cc1SHelen Koike 	}, {
214e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR12,
215e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
216e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_SBGGR12_1X12,
217e6938cc1SHelen Koike 	},
218e6938cc1SHelen Koike };
219e6938cc1SHelen Koike 
220e6938cc1SHelen Koike /*
221e6938cc1SHelen Koike  * The supported pixel formats for selfpath. NOTE, pixel formats with identical 'mbus'
222e6938cc1SHelen Koike  * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes
223e6938cc1SHelen Koike  */
224e6938cc1SHelen Koike static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = {
225e6938cc1SHelen Koike 	/* yuv422 */
226e6938cc1SHelen Koike 	{
227e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUYV,
228e6938cc1SHelen Koike 		.uv_swap = 0,
229e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_INT,
230e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
231e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
232e6938cc1SHelen Koike 	}, {
233e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV422P,
234e6938cc1SHelen Koike 		.uv_swap = 0,
235e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
236e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
237e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
238e6938cc1SHelen Koike 	}, {
239e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV16,
240e6938cc1SHelen Koike 		.uv_swap = 0,
241e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
242e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
243e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
244e6938cc1SHelen Koike 	}, {
245e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV61,
246e6938cc1SHelen Koike 		.uv_swap = 1,
247e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
248e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
249e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
250e6938cc1SHelen Koike 	}, {
2517cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV16M,
2527cb7018cSPaul Elder 		.uv_swap = 0,
2537cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
2547cb7018cSPaul Elder 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2557cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
2567cb7018cSPaul Elder 	}, {
2577cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV61M,
2587cb7018cSPaul Elder 		.uv_swap = 1,
2597cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
2607cb7018cSPaul Elder 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2617cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
2627cb7018cSPaul Elder 	}, {
263e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU422M,
264e6938cc1SHelen Koike 		.uv_swap = 1,
265e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
266e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
267e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
268e6938cc1SHelen Koike 	},
269e6938cc1SHelen Koike 	/* yuv400 */
270e6938cc1SHelen Koike 	{
271e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_GREY,
272e6938cc1SHelen Koike 		.uv_swap = 0,
273e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
2749a0e3cd5SDafna Hirschfeld 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
275e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
276e6938cc1SHelen Koike 	},
277e6938cc1SHelen Koike 	/* rgb */
278e6938cc1SHelen Koike 	{
279e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_XBGR32,
280e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
281e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB888,
282e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
283e6938cc1SHelen Koike 	}, {
284e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_RGB565,
285e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
286e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB565,
287e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
288e6938cc1SHelen Koike 	},
289e6938cc1SHelen Koike 	/* yuv420 */
290e6938cc1SHelen Koike 	{
291e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21,
292e6938cc1SHelen Koike 		.uv_swap = 1,
293e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
294e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
295e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
296e6938cc1SHelen Koike 	}, {
297e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12,
298e6938cc1SHelen Koike 		.uv_swap = 0,
299e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
300e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
301e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
302e6938cc1SHelen Koike 	}, {
303e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21M,
304e6938cc1SHelen Koike 		.uv_swap = 1,
305e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
306e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
307e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
308e6938cc1SHelen Koike 	}, {
309e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12M,
310e6938cc1SHelen Koike 		.uv_swap = 0,
311e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
312e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
313e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
314e6938cc1SHelen Koike 	}, {
315e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV420,
316e6938cc1SHelen Koike 		.uv_swap = 0,
317e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
318e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
319e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
320e6938cc1SHelen Koike 	}, {
321e6938cc1SHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU420,
322e6938cc1SHelen Koike 		.uv_swap = 1,
323e6938cc1SHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
324e6938cc1SHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
325e6938cc1SHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
326e6938cc1SHelen Koike 	},
327e6938cc1SHelen Koike };
328e6938cc1SHelen Koike 
329e6938cc1SHelen Koike static const struct rkisp1_capture_config rkisp1_capture_config_mp = {
330e6938cc1SHelen Koike 	.fmts = rkisp1_mp_fmts,
331e6938cc1SHelen Koike 	.fmt_size = ARRAY_SIZE(rkisp1_mp_fmts),
332e6938cc1SHelen Koike 	.mi = {
333e6938cc1SHelen Koike 		.y_size_init =		RKISP1_CIF_MI_MP_Y_SIZE_INIT,
334e6938cc1SHelen Koike 		.cb_size_init =		RKISP1_CIF_MI_MP_CB_SIZE_INIT,
335e6938cc1SHelen Koike 		.cr_size_init =		RKISP1_CIF_MI_MP_CR_SIZE_INIT,
336e6938cc1SHelen Koike 		.y_base_ad_init =	RKISP1_CIF_MI_MP_Y_BASE_AD_INIT,
337e6938cc1SHelen Koike 		.cb_base_ad_init =	RKISP1_CIF_MI_MP_CB_BASE_AD_INIT,
338e6938cc1SHelen Koike 		.cr_base_ad_init =	RKISP1_CIF_MI_MP_CR_BASE_AD_INIT,
339e6938cc1SHelen Koike 		.y_offs_cnt_init =	RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT,
340e6938cc1SHelen Koike 		.cb_offs_cnt_init =	RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT,
341e6938cc1SHelen Koike 		.cr_offs_cnt_init =	RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT,
342e6938cc1SHelen Koike 	},
343e6938cc1SHelen Koike };
344e6938cc1SHelen Koike 
345e6938cc1SHelen Koike static const struct rkisp1_capture_config rkisp1_capture_config_sp = {
346e6938cc1SHelen Koike 	.fmts = rkisp1_sp_fmts,
347e6938cc1SHelen Koike 	.fmt_size = ARRAY_SIZE(rkisp1_sp_fmts),
348e6938cc1SHelen Koike 	.mi = {
349e6938cc1SHelen Koike 		.y_size_init =		RKISP1_CIF_MI_SP_Y_SIZE_INIT,
350e6938cc1SHelen Koike 		.cb_size_init =		RKISP1_CIF_MI_SP_CB_SIZE_INIT,
351e6938cc1SHelen Koike 		.cr_size_init =		RKISP1_CIF_MI_SP_CR_SIZE_INIT,
352e6938cc1SHelen Koike 		.y_base_ad_init =	RKISP1_CIF_MI_SP_Y_BASE_AD_INIT,
353e6938cc1SHelen Koike 		.cb_base_ad_init =	RKISP1_CIF_MI_SP_CB_BASE_AD_INIT,
354e6938cc1SHelen Koike 		.cr_base_ad_init =	RKISP1_CIF_MI_SP_CR_BASE_AD_INIT,
355e6938cc1SHelen Koike 		.y_offs_cnt_init =	RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT,
356e6938cc1SHelen Koike 		.cb_offs_cnt_init =	RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT,
357e6938cc1SHelen Koike 		.cr_offs_cnt_init =	RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT,
358e6938cc1SHelen Koike 	},
359e6938cc1SHelen Koike };
360e6938cc1SHelen Koike 
361e6938cc1SHelen Koike static inline struct rkisp1_vdev_node *
rkisp1_vdev_to_node(struct video_device * vdev)362e6938cc1SHelen Koike rkisp1_vdev_to_node(struct video_device *vdev)
363e6938cc1SHelen Koike {
364e6938cc1SHelen Koike 	return container_of(vdev, struct rkisp1_vdev_node, vdev);
365e6938cc1SHelen Koike }
366e6938cc1SHelen Koike 
rkisp1_cap_enum_mbus_codes(struct rkisp1_capture * cap,struct v4l2_subdev_mbus_code_enum * code)367e6938cc1SHelen Koike int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap,
368e6938cc1SHelen Koike 			       struct v4l2_subdev_mbus_code_enum *code)
369e6938cc1SHelen Koike {
370e6938cc1SHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmts = cap->config->fmts;
371e6938cc1SHelen Koike 	/*
372e6938cc1SHelen Koike 	 * initialize curr_mbus to non existing mbus code 0 to ensure it is
373e6938cc1SHelen Koike 	 * different from fmts[0].mbus
374e6938cc1SHelen Koike 	 */
375e6938cc1SHelen Koike 	u32 curr_mbus = 0;
376e6938cc1SHelen Koike 	int i, n = 0;
377e6938cc1SHelen Koike 
378e6938cc1SHelen Koike 	for (i = 0; i < cap->config->fmt_size; i++) {
379e6938cc1SHelen Koike 		if (fmts[i].mbus == curr_mbus)
380e6938cc1SHelen Koike 			continue;
381e6938cc1SHelen Koike 
382e6938cc1SHelen Koike 		curr_mbus = fmts[i].mbus;
383e6938cc1SHelen Koike 		if (n++ == code->index) {
384e6938cc1SHelen Koike 			code->code = curr_mbus;
385e6938cc1SHelen Koike 			return 0;
386e6938cc1SHelen Koike 		}
387e6938cc1SHelen Koike 	}
388e6938cc1SHelen Koike 	return -EINVAL;
389e6938cc1SHelen Koike }
390e6938cc1SHelen Koike 
391e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
392e6938cc1SHelen Koike  * Stream operations for self-picture path (sp) and main-picture path (mp)
393e6938cc1SHelen Koike  */
394e6938cc1SHelen Koike 
rkisp1_mi_config_ctrl(struct rkisp1_capture * cap)395e6938cc1SHelen Koike static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap)
396e6938cc1SHelen Koike {
397e6938cc1SHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
398e6938cc1SHelen Koike 
399e6938cc1SHelen Koike 	mi_ctrl &= ~GENMASK(17, 16);
400e6938cc1SHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64;
401e6938cc1SHelen Koike 
402e6938cc1SHelen Koike 	mi_ctrl &= ~GENMASK(19, 18);
403e6938cc1SHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64;
404e6938cc1SHelen Koike 
405e6938cc1SHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN |
406e6938cc1SHelen Koike 		   RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN;
407e6938cc1SHelen Koike 
4080ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
409e6938cc1SHelen Koike }
410e6938cc1SHelen Koike 
rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane * pixm,unsigned int component)411e6938cc1SHelen Koike static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm,
412e6938cc1SHelen Koike 				   unsigned int component)
413e6938cc1SHelen Koike {
414e6938cc1SHelen Koike 	/*
415e6938cc1SHelen Koike 	 * If packed format, then plane_fmt[0].sizeimage is the sum of all
416e6938cc1SHelen Koike 	 * components, so we need to calculate just the size of Y component.
417e6938cc1SHelen Koike 	 * See rkisp1_fill_pixfmt().
418e6938cc1SHelen Koike 	 */
419e6938cc1SHelen Koike 	if (!component && pixm->num_planes == 1)
420e6938cc1SHelen Koike 		return pixm->plane_fmt[0].bytesperline * pixm->height;
421e6938cc1SHelen Koike 	return pixm->plane_fmt[component].sizeimage;
422e6938cc1SHelen Koike }
423e6938cc1SHelen Koike 
rkisp1_irq_frame_end_enable(struct rkisp1_capture * cap)424e6938cc1SHelen Koike static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap)
425e6938cc1SHelen Koike {
426e6938cc1SHelen Koike 	u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC);
427e6938cc1SHelen Koike 
428e6938cc1SHelen Koike 	mi_imsc |= RKISP1_CIF_MI_FRAME(cap);
4290ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_IMSC, mi_imsc);
430e6938cc1SHelen Koike }
431e6938cc1SHelen Koike 
rkisp1_mp_config(struct rkisp1_capture * cap)432e6938cc1SHelen Koike static void rkisp1_mp_config(struct rkisp1_capture *cap)
433e6938cc1SHelen Koike {
434e6938cc1SHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
435e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
436e6938cc1SHelen Koike 	u32 reg;
437e6938cc1SHelen Koike 
4380ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.y_size_init,
4390ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
4400ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
4410ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
4420ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
4430ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
444e6938cc1SHelen Koike 
445e6938cc1SHelen Koike 	rkisp1_irq_frame_end_enable(cap);
446e6938cc1SHelen Koike 
447e6938cc1SHelen Koike 	/* set uv swapping for semiplanar formats */
448e6938cc1SHelen Koike 	if (cap->pix.info->comp_planes == 2) {
449e6938cc1SHelen Koike 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
450e6938cc1SHelen Koike 		if (cap->pix.cfg->uv_swap)
451e6938cc1SHelen Koike 			reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
452e6938cc1SHelen Koike 		else
453e6938cc1SHelen Koike 			reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
4540ef7dc30SLaurent Pinchart 		rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
455e6938cc1SHelen Koike 	}
456e6938cc1SHelen Koike 
457e6938cc1SHelen Koike 	rkisp1_mi_config_ctrl(cap);
458e6938cc1SHelen Koike 
459e6938cc1SHelen Koike 	reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
460e6938cc1SHelen Koike 	reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK;
461e6938cc1SHelen Koike 	reg |= cap->pix.cfg->write_format;
4620ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
463e6938cc1SHelen Koike 
464e6938cc1SHelen Koike 	reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
465e6938cc1SHelen Koike 	reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE;
4660ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
467e6938cc1SHelen Koike }
468e6938cc1SHelen Koike 
rkisp1_sp_config(struct rkisp1_capture * cap)469e6938cc1SHelen Koike static void rkisp1_sp_config(struct rkisp1_capture *cap)
470e6938cc1SHelen Koike {
471e6938cc1SHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
472e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
473e6938cc1SHelen Koike 	u32 mi_ctrl, reg;
474e6938cc1SHelen Koike 
4750ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.y_size_init,
4760ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
4770ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
4780ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
4790ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
4800ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
481e6938cc1SHelen Koike 
4820ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width);
4830ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height);
4840ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride);
485e6938cc1SHelen Koike 
486e6938cc1SHelen Koike 	rkisp1_irq_frame_end_enable(cap);
487e6938cc1SHelen Koike 
488e6938cc1SHelen Koike 	/* set uv swapping for semiplanar formats */
489e6938cc1SHelen Koike 	if (cap->pix.info->comp_planes == 2) {
490e6938cc1SHelen Koike 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
491e6938cc1SHelen Koike 		if (cap->pix.cfg->uv_swap)
492e6938cc1SHelen Koike 			reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
493e6938cc1SHelen Koike 		else
494e6938cc1SHelen Koike 			reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
4950ef7dc30SLaurent Pinchart 		rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
496e6938cc1SHelen Koike 	}
497e6938cc1SHelen Koike 
498e6938cc1SHelen Koike 	rkisp1_mi_config_ctrl(cap);
499e6938cc1SHelen Koike 
500e6938cc1SHelen Koike 	mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
501e6938cc1SHelen Koike 	mi_ctrl &= ~RKISP1_MI_CTRL_SP_FMT_MASK;
502e6938cc1SHelen Koike 	mi_ctrl |= cap->pix.cfg->write_format |
503e6938cc1SHelen Koike 		   RKISP1_MI_CTRL_SP_INPUT_YUV422 |
504e6938cc1SHelen Koike 		   cap->pix.cfg->output_format |
505e6938cc1SHelen Koike 		   RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE;
5060ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
507e6938cc1SHelen Koike }
508e6938cc1SHelen Koike 
rkisp1_mp_disable(struct rkisp1_capture * cap)509e6938cc1SHelen Koike static void rkisp1_mp_disable(struct rkisp1_capture *cap)
510e6938cc1SHelen Koike {
511e6938cc1SHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
512e6938cc1SHelen Koike 
513e6938cc1SHelen Koike 	mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE |
514e6938cc1SHelen Koike 		     RKISP1_CIF_MI_CTRL_RAW_ENABLE);
5150ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
516e6938cc1SHelen Koike }
517e6938cc1SHelen Koike 
rkisp1_sp_disable(struct rkisp1_capture * cap)518e6938cc1SHelen Koike static void rkisp1_sp_disable(struct rkisp1_capture *cap)
519e6938cc1SHelen Koike {
520e6938cc1SHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
521e6938cc1SHelen Koike 
522e6938cc1SHelen Koike 	mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE;
5230ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
524e6938cc1SHelen Koike }
525e6938cc1SHelen Koike 
rkisp1_mp_enable(struct rkisp1_capture * cap)526e6938cc1SHelen Koike static void rkisp1_mp_enable(struct rkisp1_capture *cap)
527e6938cc1SHelen Koike {
528e6938cc1SHelen Koike 	u32 mi_ctrl;
529e6938cc1SHelen Koike 
530e6938cc1SHelen Koike 	rkisp1_mp_disable(cap);
531e6938cc1SHelen Koike 
532e6938cc1SHelen Koike 	mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
533e6938cc1SHelen Koike 	if (v4l2_is_format_bayer(cap->pix.info))
534e6938cc1SHelen Koike 		mi_ctrl |= RKISP1_CIF_MI_CTRL_RAW_ENABLE;
535e6938cc1SHelen Koike 	/* YUV */
536e6938cc1SHelen Koike 	else
537e6938cc1SHelen Koike 		mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE;
538e6938cc1SHelen Koike 
5390ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
540e6938cc1SHelen Koike }
541e6938cc1SHelen Koike 
rkisp1_sp_enable(struct rkisp1_capture * cap)542e6938cc1SHelen Koike static void rkisp1_sp_enable(struct rkisp1_capture *cap)
543e6938cc1SHelen Koike {
544e6938cc1SHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
545e6938cc1SHelen Koike 
546e6938cc1SHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE;
5470ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
548e6938cc1SHelen Koike }
549e6938cc1SHelen Koike 
rkisp1_mp_sp_stop(struct rkisp1_capture * cap)550e6938cc1SHelen Koike static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap)
551e6938cc1SHelen Koike {
552e6938cc1SHelen Koike 	if (!cap->is_streaming)
553e6938cc1SHelen Koike 		return;
5540ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_ICR, RKISP1_CIF_MI_FRAME(cap));
555e6938cc1SHelen Koike 	cap->ops->disable(cap);
556e6938cc1SHelen Koike }
557e6938cc1SHelen Koike 
rkisp1_mp_is_stopped(struct rkisp1_capture * cap)558e6938cc1SHelen Koike static bool rkisp1_mp_is_stopped(struct rkisp1_capture *cap)
559e6938cc1SHelen Koike {
560e6938cc1SHelen Koike 	u32 en = RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED |
561e6938cc1SHelen Koike 		 RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED;
562e6938cc1SHelen Koike 
563e6938cc1SHelen Koike 	return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & en);
564e6938cc1SHelen Koike }
565e6938cc1SHelen Koike 
rkisp1_sp_is_stopped(struct rkisp1_capture * cap)566e6938cc1SHelen Koike static bool rkisp1_sp_is_stopped(struct rkisp1_capture *cap)
567e6938cc1SHelen Koike {
568e6938cc1SHelen Koike 	return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) &
569e6938cc1SHelen Koike 		 RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED);
570e6938cc1SHelen Koike }
571e6938cc1SHelen Koike 
rkisp1_mp_set_data_path(struct rkisp1_capture * cap)572e6938cc1SHelen Koike static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap)
573e6938cc1SHelen Koike {
574e6938cc1SHelen Koike 	u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL);
575e6938cc1SHelen Koike 
576e6938cc1SHelen Koike 	dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP |
577e6938cc1SHelen Koike 	       RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI;
5780ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
579e6938cc1SHelen Koike }
580e6938cc1SHelen Koike 
rkisp1_sp_set_data_path(struct rkisp1_capture * cap)581e6938cc1SHelen Koike static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap)
582e6938cc1SHelen Koike {
583e6938cc1SHelen Koike 	u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL);
584e6938cc1SHelen Koike 
585e6938cc1SHelen Koike 	dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP;
5860ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
587e6938cc1SHelen Koike }
588e6938cc1SHelen Koike 
589a109073bSRikard Falkeborn static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = {
590e6938cc1SHelen Koike 	.config = rkisp1_mp_config,
591e6938cc1SHelen Koike 	.enable = rkisp1_mp_enable,
592e6938cc1SHelen Koike 	.disable = rkisp1_mp_disable,
593e6938cc1SHelen Koike 	.stop = rkisp1_mp_sp_stop,
594e6938cc1SHelen Koike 	.set_data_path = rkisp1_mp_set_data_path,
595e6938cc1SHelen Koike 	.is_stopped = rkisp1_mp_is_stopped,
596e6938cc1SHelen Koike };
597e6938cc1SHelen Koike 
598a109073bSRikard Falkeborn static const struct rkisp1_capture_ops rkisp1_capture_ops_sp = {
599e6938cc1SHelen Koike 	.config = rkisp1_sp_config,
600e6938cc1SHelen Koike 	.enable = rkisp1_sp_enable,
601e6938cc1SHelen Koike 	.disable = rkisp1_sp_disable,
602e6938cc1SHelen Koike 	.stop = rkisp1_mp_sp_stop,
603e6938cc1SHelen Koike 	.set_data_path = rkisp1_sp_set_data_path,
604e6938cc1SHelen Koike 	.is_stopped = rkisp1_sp_is_stopped,
605e6938cc1SHelen Koike };
606e6938cc1SHelen Koike 
607e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
608e6938cc1SHelen Koike  * Frame buffer operations
609e6938cc1SHelen Koike  */
610e6938cc1SHelen Koike 
rkisp1_dummy_buf_create(struct rkisp1_capture * cap)611e6938cc1SHelen Koike static int rkisp1_dummy_buf_create(struct rkisp1_capture *cap)
612e6938cc1SHelen Koike {
613e6938cc1SHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
614e6938cc1SHelen Koike 	struct rkisp1_dummy_buffer *dummy_buf = &cap->buf.dummy;
615e6938cc1SHelen Koike 
616e6938cc1SHelen Koike 	dummy_buf->size = max3(rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y),
617e6938cc1SHelen Koike 			       rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB),
618e6938cc1SHelen Koike 			       rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
619e6938cc1SHelen Koike 
620e6938cc1SHelen Koike 	/* The driver never access vaddr, no mapping is required */
621e6938cc1SHelen Koike 	dummy_buf->vaddr = dma_alloc_attrs(cap->rkisp1->dev,
622e6938cc1SHelen Koike 					   dummy_buf->size,
623e6938cc1SHelen Koike 					   &dummy_buf->dma_addr,
624e6938cc1SHelen Koike 					   GFP_KERNEL,
625e6938cc1SHelen Koike 					   DMA_ATTR_NO_KERNEL_MAPPING);
626e6938cc1SHelen Koike 	if (!dummy_buf->vaddr)
627e6938cc1SHelen Koike 		return -ENOMEM;
628e6938cc1SHelen Koike 
629e6938cc1SHelen Koike 	return 0;
630e6938cc1SHelen Koike }
631e6938cc1SHelen Koike 
rkisp1_dummy_buf_destroy(struct rkisp1_capture * cap)632e6938cc1SHelen Koike static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap)
633e6938cc1SHelen Koike {
634e6938cc1SHelen Koike 	dma_free_attrs(cap->rkisp1->dev,
635e6938cc1SHelen Koike 		       cap->buf.dummy.size, cap->buf.dummy.vaddr,
636e6938cc1SHelen Koike 		       cap->buf.dummy.dma_addr, DMA_ATTR_NO_KERNEL_MAPPING);
637e6938cc1SHelen Koike }
638e6938cc1SHelen Koike 
rkisp1_set_next_buf(struct rkisp1_capture * cap)639e6938cc1SHelen Koike static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
640e6938cc1SHelen Koike {
641e6938cc1SHelen Koike 	cap->buf.curr = cap->buf.next;
642e6938cc1SHelen Koike 	cap->buf.next = NULL;
643e6938cc1SHelen Koike 
644e6938cc1SHelen Koike 	if (!list_empty(&cap->buf.queue)) {
645e6938cc1SHelen Koike 		u32 *buff_addr;
646e6938cc1SHelen Koike 
647e6938cc1SHelen Koike 		cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue);
648e6938cc1SHelen Koike 		list_del(&cap->buf.next->queue);
649e6938cc1SHelen Koike 
650e6938cc1SHelen Koike 		buff_addr = cap->buf.next->buff_addr;
651e6938cc1SHelen Koike 
6520ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
6530ef7dc30SLaurent Pinchart 			     buff_addr[RKISP1_PLANE_Y]);
6549a0e3cd5SDafna Hirschfeld 		/*
6559a0e3cd5SDafna Hirschfeld 		 * In order to support grey format we capture
6569a0e3cd5SDafna Hirschfeld 		 * YUV422 planar format from the camera and
6579a0e3cd5SDafna Hirschfeld 		 * set the U and V planes to the dummy buffer
6589a0e3cd5SDafna Hirschfeld 		 */
6599a0e3cd5SDafna Hirschfeld 		if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) {
6609a0e3cd5SDafna Hirschfeld 			rkisp1_write(cap->rkisp1,
6610ef7dc30SLaurent Pinchart 				     cap->config->mi.cb_base_ad_init,
6620ef7dc30SLaurent Pinchart 				     cap->buf.dummy.dma_addr);
6639a0e3cd5SDafna Hirschfeld 			rkisp1_write(cap->rkisp1,
6640ef7dc30SLaurent Pinchart 				     cap->config->mi.cr_base_ad_init,
6650ef7dc30SLaurent Pinchart 				     cap->buf.dummy.dma_addr);
6669a0e3cd5SDafna Hirschfeld 		} else {
667e6938cc1SHelen Koike 			rkisp1_write(cap->rkisp1,
6680ef7dc30SLaurent Pinchart 				     cap->config->mi.cb_base_ad_init,
6690ef7dc30SLaurent Pinchart 				     buff_addr[RKISP1_PLANE_CB]);
670e6938cc1SHelen Koike 			rkisp1_write(cap->rkisp1,
6710ef7dc30SLaurent Pinchart 				     cap->config->mi.cr_base_ad_init,
6720ef7dc30SLaurent Pinchart 				     buff_addr[RKISP1_PLANE_CR]);
6739a0e3cd5SDafna Hirschfeld 		}
674e6938cc1SHelen Koike 	} else {
675e6938cc1SHelen Koike 		/*
676e6938cc1SHelen Koike 		 * Use the dummy space allocated by dma_alloc_coherent to
677e6938cc1SHelen Koike 		 * throw data if there is no available buffer.
678e6938cc1SHelen Koike 		 */
6790ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
6800ef7dc30SLaurent Pinchart 			     cap->buf.dummy.dma_addr);
6810ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init,
6820ef7dc30SLaurent Pinchart 			     cap->buf.dummy.dma_addr);
6830ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init,
6840ef7dc30SLaurent Pinchart 			     cap->buf.dummy.dma_addr);
685e6938cc1SHelen Koike 	}
686e6938cc1SHelen Koike 
687e6938cc1SHelen Koike 	/* Set plane offsets */
6880ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.y_offs_cnt_init, 0);
6890ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.cb_offs_cnt_init, 0);
6900ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.cr_offs_cnt_init, 0);
691e6938cc1SHelen Koike }
692e6938cc1SHelen Koike 
693e6938cc1SHelen Koike /*
694e6938cc1SHelen Koike  * This function is called when a frame end comes. The next frame
695e6938cc1SHelen Koike  * is processing and we should set up buffer for next-next frame,
696e6938cc1SHelen Koike  * otherwise it will overflow.
697e6938cc1SHelen Koike  */
rkisp1_handle_buffer(struct rkisp1_capture * cap)698e6938cc1SHelen Koike static void rkisp1_handle_buffer(struct rkisp1_capture *cap)
699e6938cc1SHelen Koike {
700e6938cc1SHelen Koike 	struct rkisp1_isp *isp = &cap->rkisp1->isp;
701e6938cc1SHelen Koike 	struct rkisp1_buffer *curr_buf;
702e6938cc1SHelen Koike 
703e6938cc1SHelen Koike 	spin_lock(&cap->buf.lock);
704e6938cc1SHelen Koike 	curr_buf = cap->buf.curr;
705e6938cc1SHelen Koike 
706e6938cc1SHelen Koike 	if (curr_buf) {
707e6938cc1SHelen Koike 		curr_buf->vb.sequence = isp->frame_sequence;
708e6938cc1SHelen Koike 		curr_buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns();
709e6938cc1SHelen Koike 		curr_buf->vb.field = V4L2_FIELD_NONE;
710e6938cc1SHelen Koike 		vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
711e6938cc1SHelen Koike 	} else {
712e6938cc1SHelen Koike 		cap->rkisp1->debug.frame_drop[cap->id]++;
713e6938cc1SHelen Koike 	}
714e6938cc1SHelen Koike 
715e6938cc1SHelen Koike 	rkisp1_set_next_buf(cap);
716e6938cc1SHelen Koike 	spin_unlock(&cap->buf.lock);
717e6938cc1SHelen Koike }
718e6938cc1SHelen Koike 
rkisp1_capture_isr(int irq,void * ctx)71908818e6aSHeiko Stuebner irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
720e6938cc1SHelen Koike {
72108818e6aSHeiko Stuebner 	struct device *dev = ctx;
72208818e6aSHeiko Stuebner 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
723e6938cc1SHelen Koike 	unsigned int i;
724e6938cc1SHelen Koike 	u32 status;
725e6938cc1SHelen Koike 
726*b39b4d20STomi Valkeinen 	if (!rkisp1->irqs_enabled)
727*b39b4d20STomi Valkeinen 		return IRQ_NONE;
728*b39b4d20STomi Valkeinen 
729e6938cc1SHelen Koike 	status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS);
73008818e6aSHeiko Stuebner 	if (!status)
73108818e6aSHeiko Stuebner 		return IRQ_NONE;
73208818e6aSHeiko Stuebner 
7330ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status);
734e6938cc1SHelen Koike 
735e6938cc1SHelen Koike 	for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) {
736e6938cc1SHelen Koike 		struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
737e6938cc1SHelen Koike 
738e6938cc1SHelen Koike 		if (!(status & RKISP1_CIF_MI_FRAME(cap)))
739e6938cc1SHelen Koike 			continue;
740e6938cc1SHelen Koike 		if (!cap->is_stopping) {
741e6938cc1SHelen Koike 			rkisp1_handle_buffer(cap);
742e6938cc1SHelen Koike 			continue;
743e6938cc1SHelen Koike 		}
744e6938cc1SHelen Koike 		/*
745e6938cc1SHelen Koike 		 * Make sure stream is actually stopped, whose state
746e6938cc1SHelen Koike 		 * can be read from the shadow register, before
747e6938cc1SHelen Koike 		 * wake_up() thread which would immediately free all
748e6938cc1SHelen Koike 		 * frame buffers. stop() takes effect at the next
749e6938cc1SHelen Koike 		 * frame end that sync the configurations to shadow
750e6938cc1SHelen Koike 		 * regs.
751e6938cc1SHelen Koike 		 */
752e6938cc1SHelen Koike 		if (!cap->ops->is_stopped(cap)) {
753e6938cc1SHelen Koike 			cap->ops->stop(cap);
754e6938cc1SHelen Koike 			continue;
755e6938cc1SHelen Koike 		}
756e6938cc1SHelen Koike 		cap->is_stopping = false;
757e6938cc1SHelen Koike 		cap->is_streaming = false;
758e6938cc1SHelen Koike 		wake_up(&cap->done);
759e6938cc1SHelen Koike 	}
76008818e6aSHeiko Stuebner 
76108818e6aSHeiko Stuebner 	return IRQ_HANDLED;
762e6938cc1SHelen Koike }
763e6938cc1SHelen Koike 
764e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
765e6938cc1SHelen Koike  * Vb2 operations
766e6938cc1SHelen Koike  */
767e6938cc1SHelen Koike 
rkisp1_vb2_queue_setup(struct vb2_queue * queue,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])768e6938cc1SHelen Koike static int rkisp1_vb2_queue_setup(struct vb2_queue *queue,
769e6938cc1SHelen Koike 				  unsigned int *num_buffers,
770e6938cc1SHelen Koike 				  unsigned int *num_planes,
771e6938cc1SHelen Koike 				  unsigned int sizes[],
772e6938cc1SHelen Koike 				  struct device *alloc_devs[])
773e6938cc1SHelen Koike {
774e6938cc1SHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
775e6938cc1SHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
776e6938cc1SHelen Koike 	unsigned int i;
777e6938cc1SHelen Koike 
778e6938cc1SHelen Koike 	if (*num_planes) {
779e6938cc1SHelen Koike 		if (*num_planes != pixm->num_planes)
780e6938cc1SHelen Koike 			return -EINVAL;
781e6938cc1SHelen Koike 
782e6938cc1SHelen Koike 		for (i = 0; i < pixm->num_planes; i++)
783e6938cc1SHelen Koike 			if (sizes[i] < pixm->plane_fmt[i].sizeimage)
784e6938cc1SHelen Koike 				return -EINVAL;
785e6938cc1SHelen Koike 	} else {
786e6938cc1SHelen Koike 		*num_planes = pixm->num_planes;
787e6938cc1SHelen Koike 		for (i = 0; i < pixm->num_planes; i++)
788e6938cc1SHelen Koike 			sizes[i] = pixm->plane_fmt[i].sizeimage;
789e6938cc1SHelen Koike 	}
790e6938cc1SHelen Koike 
791e6938cc1SHelen Koike 	return 0;
792e6938cc1SHelen Koike }
793e6938cc1SHelen Koike 
rkisp1_vb2_buf_init(struct vb2_buffer * vb)794f003d635SDafna Hirschfeld static int rkisp1_vb2_buf_init(struct vb2_buffer *vb)
795e6938cc1SHelen Koike {
796e6938cc1SHelen Koike 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
797e6938cc1SHelen Koike 	struct rkisp1_buffer *ispbuf =
798e6938cc1SHelen Koike 		container_of(vbuf, struct rkisp1_buffer, vb);
799e6938cc1SHelen Koike 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
800e6938cc1SHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
801e6938cc1SHelen Koike 	unsigned int i;
802e6938cc1SHelen Koike 
803e6938cc1SHelen Koike 	memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr));
804e6938cc1SHelen Koike 	for (i = 0; i < pixm->num_planes; i++)
805e6938cc1SHelen Koike 		ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
806e6938cc1SHelen Koike 
807e6938cc1SHelen Koike 	/* Convert to non-MPLANE */
808e6938cc1SHelen Koike 	if (pixm->num_planes == 1) {
809e6938cc1SHelen Koike 		ispbuf->buff_addr[RKISP1_PLANE_CB] =
810e6938cc1SHelen Koike 			ispbuf->buff_addr[RKISP1_PLANE_Y] +
811e6938cc1SHelen Koike 			rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y);
812e6938cc1SHelen Koike 		ispbuf->buff_addr[RKISP1_PLANE_CR] =
813e6938cc1SHelen Koike 			ispbuf->buff_addr[RKISP1_PLANE_CB] +
814e6938cc1SHelen Koike 			rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB);
815e6938cc1SHelen Koike 	}
816e6938cc1SHelen Koike 
817e6938cc1SHelen Koike 	/*
818e6938cc1SHelen Koike 	 * uv swap can be supported for planar formats by switching
819e6938cc1SHelen Koike 	 * the address of cb and cr
820e6938cc1SHelen Koike 	 */
821e6938cc1SHelen Koike 	if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap)
822e6938cc1SHelen Koike 		swap(ispbuf->buff_addr[RKISP1_PLANE_CR],
823e6938cc1SHelen Koike 		     ispbuf->buff_addr[RKISP1_PLANE_CB]);
824f003d635SDafna Hirschfeld 	return 0;
825f003d635SDafna Hirschfeld }
826f003d635SDafna Hirschfeld 
rkisp1_vb2_buf_queue(struct vb2_buffer * vb)827f003d635SDafna Hirschfeld static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb)
828f003d635SDafna Hirschfeld {
829f003d635SDafna Hirschfeld 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
830f003d635SDafna Hirschfeld 	struct rkisp1_buffer *ispbuf =
831f003d635SDafna Hirschfeld 		container_of(vbuf, struct rkisp1_buffer, vb);
832f003d635SDafna Hirschfeld 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
833e6938cc1SHelen Koike 
834e6938cc1SHelen Koike 	spin_lock_irq(&cap->buf.lock);
835e6938cc1SHelen Koike 	list_add_tail(&ispbuf->queue, &cap->buf.queue);
836e6938cc1SHelen Koike 	spin_unlock_irq(&cap->buf.lock);
837e6938cc1SHelen Koike }
838e6938cc1SHelen Koike 
rkisp1_vb2_buf_prepare(struct vb2_buffer * vb)839e6938cc1SHelen Koike static int rkisp1_vb2_buf_prepare(struct vb2_buffer *vb)
840e6938cc1SHelen Koike {
841e6938cc1SHelen Koike 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
842e6938cc1SHelen Koike 	unsigned int i;
843e6938cc1SHelen Koike 
844e6938cc1SHelen Koike 	for (i = 0; i < cap->pix.fmt.num_planes; i++) {
845e6938cc1SHelen Koike 		unsigned long size = cap->pix.fmt.plane_fmt[i].sizeimage;
846e6938cc1SHelen Koike 
847e6938cc1SHelen Koike 		if (vb2_plane_size(vb, i) < size) {
848e6938cc1SHelen Koike 			dev_err(cap->rkisp1->dev,
849e6938cc1SHelen Koike 				"User buffer too small (%ld < %ld)\n",
850e6938cc1SHelen Koike 				vb2_plane_size(vb, i), size);
851e6938cc1SHelen Koike 			return -EINVAL;
852e6938cc1SHelen Koike 		}
853e6938cc1SHelen Koike 		vb2_set_plane_payload(vb, i, size);
854e6938cc1SHelen Koike 	}
855e6938cc1SHelen Koike 
856e6938cc1SHelen Koike 	return 0;
857e6938cc1SHelen Koike }
858e6938cc1SHelen Koike 
rkisp1_return_all_buffers(struct rkisp1_capture * cap,enum vb2_buffer_state state)859e6938cc1SHelen Koike static void rkisp1_return_all_buffers(struct rkisp1_capture *cap,
860e6938cc1SHelen Koike 				      enum vb2_buffer_state state)
861e6938cc1SHelen Koike {
862e6938cc1SHelen Koike 	struct rkisp1_buffer *buf;
863e6938cc1SHelen Koike 
864e6938cc1SHelen Koike 	spin_lock_irq(&cap->buf.lock);
865e6938cc1SHelen Koike 	if (cap->buf.curr) {
866e6938cc1SHelen Koike 		vb2_buffer_done(&cap->buf.curr->vb.vb2_buf, state);
867e6938cc1SHelen Koike 		cap->buf.curr = NULL;
868e6938cc1SHelen Koike 	}
869e6938cc1SHelen Koike 	if (cap->buf.next) {
870e6938cc1SHelen Koike 		vb2_buffer_done(&cap->buf.next->vb.vb2_buf, state);
871e6938cc1SHelen Koike 		cap->buf.next = NULL;
872e6938cc1SHelen Koike 	}
873e6938cc1SHelen Koike 	while (!list_empty(&cap->buf.queue)) {
874e6938cc1SHelen Koike 		buf = list_first_entry(&cap->buf.queue,
875e6938cc1SHelen Koike 				       struct rkisp1_buffer, queue);
876e6938cc1SHelen Koike 		list_del(&buf->queue);
877e6938cc1SHelen Koike 		vb2_buffer_done(&buf->vb.vb2_buf, state);
878e6938cc1SHelen Koike 	}
879e6938cc1SHelen Koike 	spin_unlock_irq(&cap->buf.lock);
880e6938cc1SHelen Koike }
881e6938cc1SHelen Koike 
882e6938cc1SHelen Koike /*
88371c41518SSebastian Fricke  * Most registers inside the rockchip ISP1 have shadow register since
88471c41518SSebastian Fricke  * they must not be changed while processing a frame.
885e6938cc1SHelen Koike  * Usually, each sub-module updates its shadow register after
886e6938cc1SHelen Koike  * processing the last pixel of a frame.
887e6938cc1SHelen Koike  */
rkisp1_cap_stream_enable(struct rkisp1_capture * cap)888e6938cc1SHelen Koike static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
889e6938cc1SHelen Koike {
890e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
891e6938cc1SHelen Koike 	struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1];
892e6938cc1SHelen Koike 
893e6938cc1SHelen Koike 	cap->ops->set_data_path(cap);
894e6938cc1SHelen Koike 	cap->ops->config(cap);
895e6938cc1SHelen Koike 
896e6938cc1SHelen Koike 	/* Setup a buffer for the next frame */
897e6938cc1SHelen Koike 	spin_lock_irq(&cap->buf.lock);
898e6938cc1SHelen Koike 	rkisp1_set_next_buf(cap);
899e6938cc1SHelen Koike 	cap->ops->enable(cap);
90071c41518SSebastian Fricke 	/* It's safe to configure ACTIVE and SHADOW registers for the
901e6938cc1SHelen Koike 	 * first stream. While when the second is starting, do NOT
90271c41518SSebastian Fricke 	 * force update because it also updates the first one.
903e6938cc1SHelen Koike 	 *
90471c41518SSebastian Fricke 	 * The latter case would drop one more buffer(that is 2) since
90571c41518SSebastian Fricke 	 * there's no buffer in a shadow register when the second FE received.
90671c41518SSebastian Fricke 	 * This's also required because the second FE maybe corrupt
90771c41518SSebastian Fricke 	 * especially when run at 120fps.
908e6938cc1SHelen Koike 	 */
909e6938cc1SHelen Koike 	if (!other->is_streaming) {
910e6938cc1SHelen Koike 		/* force cfg update */
9110ef7dc30SLaurent Pinchart 		rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT,
9120ef7dc30SLaurent Pinchart 			     RKISP1_CIF_MI_INIT_SOFT_UPD);
913e6938cc1SHelen Koike 		rkisp1_set_next_buf(cap);
914e6938cc1SHelen Koike 	}
915e6938cc1SHelen Koike 	spin_unlock_irq(&cap->buf.lock);
916e6938cc1SHelen Koike 	cap->is_streaming = true;
917e6938cc1SHelen Koike }
918e6938cc1SHelen Koike 
rkisp1_cap_stream_disable(struct rkisp1_capture * cap)919e6938cc1SHelen Koike static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap)
920e6938cc1SHelen Koike {
921e6938cc1SHelen Koike 	int ret;
922e6938cc1SHelen Koike 
9236b94c09fSPeilin Ye 	/* Stream should stop in interrupt. If it doesn't, stop it by force. */
924e6938cc1SHelen Koike 	cap->is_stopping = true;
925e6938cc1SHelen Koike 	ret = wait_event_timeout(cap->done,
926e6938cc1SHelen Koike 				 !cap->is_streaming,
927e6938cc1SHelen Koike 				 msecs_to_jiffies(1000));
928e6938cc1SHelen Koike 	if (!ret) {
929e6938cc1SHelen Koike 		cap->rkisp1->debug.stop_timeout[cap->id]++;
930e6938cc1SHelen Koike 		cap->ops->stop(cap);
931e6938cc1SHelen Koike 		cap->is_stopping = false;
932e6938cc1SHelen Koike 		cap->is_streaming = false;
933e6938cc1SHelen Koike 	}
934e6938cc1SHelen Koike }
935e6938cc1SHelen Koike 
936e6938cc1SHelen Koike /*
937e6938cc1SHelen Koike  * rkisp1_pipeline_stream_disable - disable nodes in the pipeline
938e6938cc1SHelen Koike  *
939e6938cc1SHelen Koike  * Call s_stream(false) in the reverse order from
940e6938cc1SHelen Koike  * rkisp1_pipeline_stream_enable() and disable the DMA engine.
94112cecbf9STomi Valkeinen  * Should be called before video_device_pipeline_stop()
942e6938cc1SHelen Koike  */
rkisp1_pipeline_stream_disable(struct rkisp1_capture * cap)943e6938cc1SHelen Koike static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap)
944e6938cc1SHelen Koike 	__must_hold(&cap->rkisp1->stream_lock)
945e6938cc1SHelen Koike {
946e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
947e6938cc1SHelen Koike 
948e6938cc1SHelen Koike 	rkisp1_cap_stream_disable(cap);
949e6938cc1SHelen Koike 
950e6938cc1SHelen Koike 	/*
951e6938cc1SHelen Koike 	 * If the other capture is streaming, isp and sensor nodes shouldn't
952e6938cc1SHelen Koike 	 * be disabled, skip them.
953e6938cc1SHelen Koike 	 */
954b7319e2bSTomi Valkeinen 	if (rkisp1->pipe.start_count < 2)
955e6938cc1SHelen Koike 		v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false);
956e6938cc1SHelen Koike 
957e6938cc1SHelen Koike 	v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
958e6938cc1SHelen Koike 			 false);
959e6938cc1SHelen Koike }
960e6938cc1SHelen Koike 
961e6938cc1SHelen Koike /*
962e6938cc1SHelen Koike  * rkisp1_pipeline_stream_enable - enable nodes in the pipeline
963e6938cc1SHelen Koike  *
964e6938cc1SHelen Koike  * Enable the DMA Engine and call s_stream(true) through the pipeline.
96512cecbf9STomi Valkeinen  * Should be called after video_device_pipeline_start()
966e6938cc1SHelen Koike  */
rkisp1_pipeline_stream_enable(struct rkisp1_capture * cap)967e6938cc1SHelen Koike static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap)
968e6938cc1SHelen Koike 	__must_hold(&cap->rkisp1->stream_lock)
969e6938cc1SHelen Koike {
970e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
971e6938cc1SHelen Koike 	int ret;
972e6938cc1SHelen Koike 
973e6938cc1SHelen Koike 	rkisp1_cap_stream_enable(cap);
974e6938cc1SHelen Koike 
975e6938cc1SHelen Koike 	ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video,
976e6938cc1SHelen Koike 			       s_stream, true);
977e6938cc1SHelen Koike 	if (ret)
978e6938cc1SHelen Koike 		goto err_disable_cap;
979e6938cc1SHelen Koike 
980e6938cc1SHelen Koike 	/*
981e6938cc1SHelen Koike 	 * If the other capture is streaming, isp and sensor nodes are already
982e6938cc1SHelen Koike 	 * enabled, skip them.
983e6938cc1SHelen Koike 	 */
984b7319e2bSTomi Valkeinen 	if (rkisp1->pipe.start_count > 1)
985e6938cc1SHelen Koike 		return 0;
986e6938cc1SHelen Koike 
987e6938cc1SHelen Koike 	ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true);
988e6938cc1SHelen Koike 	if (ret)
989e6938cc1SHelen Koike 		goto err_disable_rsz;
990e6938cc1SHelen Koike 
991e6938cc1SHelen Koike 	return 0;
992e6938cc1SHelen Koike 
993e6938cc1SHelen Koike err_disable_rsz:
994e6938cc1SHelen Koike 	v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
995e6938cc1SHelen Koike 			 false);
996e6938cc1SHelen Koike err_disable_cap:
997e6938cc1SHelen Koike 	rkisp1_cap_stream_disable(cap);
998e6938cc1SHelen Koike 
999e6938cc1SHelen Koike 	return ret;
1000e6938cc1SHelen Koike }
1001e6938cc1SHelen Koike 
rkisp1_vb2_stop_streaming(struct vb2_queue * queue)1002e6938cc1SHelen Koike static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue)
1003e6938cc1SHelen Koike {
1004e6938cc1SHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
1005e6938cc1SHelen Koike 	struct rkisp1_vdev_node *node = &cap->vnode;
1006e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
1007e6938cc1SHelen Koike 	int ret;
1008e6938cc1SHelen Koike 
1009e6938cc1SHelen Koike 	mutex_lock(&cap->rkisp1->stream_lock);
1010e6938cc1SHelen Koike 
1011e6938cc1SHelen Koike 	rkisp1_pipeline_stream_disable(cap);
1012e6938cc1SHelen Koike 
1013e6938cc1SHelen Koike 	rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR);
1014e6938cc1SHelen Koike 
1015e6938cc1SHelen Koike 	v4l2_pipeline_pm_put(&node->vdev.entity);
1016e6938cc1SHelen Koike 	ret = pm_runtime_put(rkisp1->dev);
1017e6938cc1SHelen Koike 	if (ret < 0)
1018e6938cc1SHelen Koike 		dev_err(rkisp1->dev, "power down failed error:%d\n", ret);
1019e6938cc1SHelen Koike 
1020e6938cc1SHelen Koike 	rkisp1_dummy_buf_destroy(cap);
1021e6938cc1SHelen Koike 
102212cecbf9STomi Valkeinen 	video_device_pipeline_stop(&node->vdev);
1023e6938cc1SHelen Koike 
1024e6938cc1SHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
1025e6938cc1SHelen Koike }
1026e6938cc1SHelen Koike 
1027e6938cc1SHelen Koike static int
rkisp1_vb2_start_streaming(struct vb2_queue * queue,unsigned int count)1028e6938cc1SHelen Koike rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
1029e6938cc1SHelen Koike {
1030e6938cc1SHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
1031e6938cc1SHelen Koike 	struct media_entity *entity = &cap->vnode.vdev.entity;
1032e6938cc1SHelen Koike 	int ret;
1033e6938cc1SHelen Koike 
1034e6938cc1SHelen Koike 	mutex_lock(&cap->rkisp1->stream_lock);
1035e6938cc1SHelen Koike 
103612cecbf9STomi Valkeinen 	ret = video_device_pipeline_start(&cap->vnode.vdev, &cap->rkisp1->pipe);
1037e6938cc1SHelen Koike 	if (ret) {
1038e6938cc1SHelen Koike 		dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret);
1039e6938cc1SHelen Koike 		goto err_ret_buffers;
1040e6938cc1SHelen Koike 	}
1041e6938cc1SHelen Koike 
1042e6938cc1SHelen Koike 	ret = rkisp1_dummy_buf_create(cap);
1043e6938cc1SHelen Koike 	if (ret)
1044e6938cc1SHelen Koike 		goto err_pipeline_stop;
1045e6938cc1SHelen Koike 
10468102cf89SMauro Carvalho Chehab 	ret = pm_runtime_resume_and_get(cap->rkisp1->dev);
1047e6938cc1SHelen Koike 	if (ret < 0) {
1048e6938cc1SHelen Koike 		dev_err(cap->rkisp1->dev, "power up failed %d\n", ret);
1049e6938cc1SHelen Koike 		goto err_destroy_dummy;
1050e6938cc1SHelen Koike 	}
1051e6938cc1SHelen Koike 	ret = v4l2_pipeline_pm_get(entity);
1052e6938cc1SHelen Koike 	if (ret) {
1053e6938cc1SHelen Koike 		dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret);
1054e6938cc1SHelen Koike 		goto err_pipe_pm_put;
1055e6938cc1SHelen Koike 	}
1056e6938cc1SHelen Koike 
1057e6938cc1SHelen Koike 	ret = rkisp1_pipeline_stream_enable(cap);
1058e6938cc1SHelen Koike 	if (ret)
1059e6938cc1SHelen Koike 		goto err_v4l2_pm_put;
1060e6938cc1SHelen Koike 
1061e6938cc1SHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
1062e6938cc1SHelen Koike 
1063e6938cc1SHelen Koike 	return 0;
1064e6938cc1SHelen Koike 
1065e6938cc1SHelen Koike err_v4l2_pm_put:
1066e6938cc1SHelen Koike 	v4l2_pipeline_pm_put(entity);
1067e6938cc1SHelen Koike err_pipe_pm_put:
1068e6938cc1SHelen Koike 	pm_runtime_put(cap->rkisp1->dev);
1069e6938cc1SHelen Koike err_destroy_dummy:
1070e6938cc1SHelen Koike 	rkisp1_dummy_buf_destroy(cap);
1071e6938cc1SHelen Koike err_pipeline_stop:
107212cecbf9STomi Valkeinen 	video_device_pipeline_stop(&cap->vnode.vdev);
1073e6938cc1SHelen Koike err_ret_buffers:
1074e6938cc1SHelen Koike 	rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED);
1075e6938cc1SHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
1076e6938cc1SHelen Koike 
1077e6938cc1SHelen Koike 	return ret;
1078e6938cc1SHelen Koike }
1079e6938cc1SHelen Koike 
1080a109073bSRikard Falkeborn static const struct vb2_ops rkisp1_vb2_ops = {
1081e6938cc1SHelen Koike 	.queue_setup = rkisp1_vb2_queue_setup,
1082f003d635SDafna Hirschfeld 	.buf_init = rkisp1_vb2_buf_init,
1083e6938cc1SHelen Koike 	.buf_queue = rkisp1_vb2_buf_queue,
1084e6938cc1SHelen Koike 	.buf_prepare = rkisp1_vb2_buf_prepare,
1085e6938cc1SHelen Koike 	.wait_prepare = vb2_ops_wait_prepare,
1086e6938cc1SHelen Koike 	.wait_finish = vb2_ops_wait_finish,
1087e6938cc1SHelen Koike 	.stop_streaming = rkisp1_vb2_stop_streaming,
1088e6938cc1SHelen Koike 	.start_streaming = rkisp1_vb2_start_streaming,
1089e6938cc1SHelen Koike };
1090e6938cc1SHelen Koike 
1091e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
1092e6938cc1SHelen Koike  * IOCTLs operations
1093e6938cc1SHelen Koike  */
1094e6938cc1SHelen Koike 
1095e6938cc1SHelen Koike static const struct v4l2_format_info *
rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane * pixm,enum rkisp1_stream_id id)1096e6938cc1SHelen Koike rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm,
1097e6938cc1SHelen Koike 		   enum rkisp1_stream_id id)
1098e6938cc1SHelen Koike {
1099e6938cc1SHelen Koike 	struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0];
1100e6938cc1SHelen Koike 	const struct v4l2_format_info *info;
1101e6938cc1SHelen Koike 	unsigned int i;
1102e6938cc1SHelen Koike 	u32 stride;
1103e6938cc1SHelen Koike 
1104e6938cc1SHelen Koike 	memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt));
1105e6938cc1SHelen Koike 	info = v4l2_format_info(pixm->pixelformat);
1106e6938cc1SHelen Koike 	pixm->num_planes = info->mem_planes;
1107e6938cc1SHelen Koike 	stride = info->bpp[0] * pixm->width;
1108e6938cc1SHelen Koike 	/* Self path supports custom stride but Main path doesn't */
1109e6938cc1SHelen Koike 	if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride)
1110e6938cc1SHelen Koike 		plane_y->bytesperline = stride;
1111e6938cc1SHelen Koike 	plane_y->sizeimage = plane_y->bytesperline * pixm->height;
1112e6938cc1SHelen Koike 
1113e6938cc1SHelen Koike 	/* normalize stride to pixels per line */
1114e6938cc1SHelen Koike 	stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]);
1115e6938cc1SHelen Koike 
1116e6938cc1SHelen Koike 	for (i = 1; i < info->comp_planes; i++) {
1117e6938cc1SHelen Koike 		struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i];
1118e6938cc1SHelen Koike 
1119e6938cc1SHelen Koike 		/* bytesperline for other components derive from Y component */
1120e6938cc1SHelen Koike 		plane->bytesperline = DIV_ROUND_UP(stride, info->hdiv) *
1121e6938cc1SHelen Koike 				      info->bpp[i];
1122e6938cc1SHelen Koike 		plane->sizeimage = plane->bytesperline *
1123e6938cc1SHelen Koike 				   DIV_ROUND_UP(pixm->height, info->vdiv);
1124e6938cc1SHelen Koike 	}
1125e6938cc1SHelen Koike 
1126e6938cc1SHelen Koike 	/*
1127e6938cc1SHelen Koike 	 * If pixfmt is packed, then plane_fmt[0] should contain the total size
1128e6938cc1SHelen Koike 	 * considering all components. plane_fmt[i] for i > 0 should be ignored
1129e6938cc1SHelen Koike 	 * by userspace as mem_planes == 1, but we are keeping information there
1130e6938cc1SHelen Koike 	 * for convenience.
1131e6938cc1SHelen Koike 	 */
1132e6938cc1SHelen Koike 	if (info->mem_planes == 1)
1133e6938cc1SHelen Koike 		for (i = 1; i < info->comp_planes; i++)
1134e6938cc1SHelen Koike 			plane_y->sizeimage += pixm->plane_fmt[i].sizeimage;
1135e6938cc1SHelen Koike 
1136e6938cc1SHelen Koike 	return info;
1137e6938cc1SHelen Koike }
1138e6938cc1SHelen Koike 
1139e6938cc1SHelen Koike static const struct rkisp1_capture_fmt_cfg *
rkisp1_find_fmt_cfg(const struct rkisp1_capture * cap,const u32 pixelfmt)1140e6938cc1SHelen Koike rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt)
1141e6938cc1SHelen Koike {
1142e6938cc1SHelen Koike 	unsigned int i;
1143e6938cc1SHelen Koike 
1144e6938cc1SHelen Koike 	for (i = 0; i < cap->config->fmt_size; i++) {
1145e6938cc1SHelen Koike 		if (cap->config->fmts[i].fourcc == pixelfmt)
1146e6938cc1SHelen Koike 			return &cap->config->fmts[i];
1147e6938cc1SHelen Koike 	}
1148e6938cc1SHelen Koike 	return NULL;
1149e6938cc1SHelen Koike }
1150e6938cc1SHelen Koike 
rkisp1_try_fmt(const struct rkisp1_capture * cap,struct v4l2_pix_format_mplane * pixm,const struct rkisp1_capture_fmt_cfg ** fmt_cfg,const struct v4l2_format_info ** fmt_info)1151e6938cc1SHelen Koike static void rkisp1_try_fmt(const struct rkisp1_capture *cap,
1152e6938cc1SHelen Koike 			   struct v4l2_pix_format_mplane *pixm,
1153e6938cc1SHelen Koike 			   const struct rkisp1_capture_fmt_cfg **fmt_cfg,
1154e6938cc1SHelen Koike 			   const struct v4l2_format_info **fmt_info)
1155e6938cc1SHelen Koike {
1156e6938cc1SHelen Koike 	const struct rkisp1_capture_config *config = cap->config;
1157e6938cc1SHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmt;
1158e6938cc1SHelen Koike 	const struct v4l2_format_info *info;
11594ee8191cSColin Ian King 	static const unsigned int max_widths[] = {
11604ee8191cSColin Ian King 		RKISP1_RSZ_MP_SRC_MAX_WIDTH, RKISP1_RSZ_SP_SRC_MAX_WIDTH
11614ee8191cSColin Ian King 	};
11624ee8191cSColin Ian King 	static const unsigned int max_heights[] = {
11634ee8191cSColin Ian King 		RKISP1_RSZ_MP_SRC_MAX_HEIGHT, RKISP1_RSZ_SP_SRC_MAX_HEIGHT
11644ee8191cSColin Ian King 	};
1165e6938cc1SHelen Koike 
1166e6938cc1SHelen Koike 	fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat);
1167e6938cc1SHelen Koike 	if (!fmt) {
1168e6938cc1SHelen Koike 		fmt = config->fmts;
1169e6938cc1SHelen Koike 		pixm->pixelformat = fmt->fourcc;
1170e6938cc1SHelen Koike 	}
1171e6938cc1SHelen Koike 
1172e6938cc1SHelen Koike 	pixm->width = clamp_t(u32, pixm->width,
1173e6938cc1SHelen Koike 			      RKISP1_RSZ_SRC_MIN_WIDTH, max_widths[cap->id]);
1174e6938cc1SHelen Koike 	pixm->height = clamp_t(u32, pixm->height,
1175e6938cc1SHelen Koike 			       RKISP1_RSZ_SRC_MIN_HEIGHT, max_heights[cap->id]);
1176e6938cc1SHelen Koike 
1177e6938cc1SHelen Koike 	pixm->field = V4L2_FIELD_NONE;
1178e6938cc1SHelen Koike 	pixm->colorspace = V4L2_COLORSPACE_DEFAULT;
1179e6938cc1SHelen Koike 	pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
1180e6938cc1SHelen Koike 	pixm->quantization = V4L2_QUANTIZATION_DEFAULT;
1181e6938cc1SHelen Koike 
1182e6938cc1SHelen Koike 	info = rkisp1_fill_pixfmt(pixm, cap->id);
1183e6938cc1SHelen Koike 
1184e6938cc1SHelen Koike 	if (fmt_cfg)
1185e6938cc1SHelen Koike 		*fmt_cfg = fmt;
1186e6938cc1SHelen Koike 	if (fmt_info)
1187e6938cc1SHelen Koike 		*fmt_info = info;
1188e6938cc1SHelen Koike }
1189e6938cc1SHelen Koike 
rkisp1_set_fmt(struct rkisp1_capture * cap,struct v4l2_pix_format_mplane * pixm)1190e6938cc1SHelen Koike static void rkisp1_set_fmt(struct rkisp1_capture *cap,
1191e6938cc1SHelen Koike 			   struct v4l2_pix_format_mplane *pixm)
1192e6938cc1SHelen Koike {
1193e6938cc1SHelen Koike 	rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info);
1194e6938cc1SHelen Koike 	cap->pix.fmt = *pixm;
1195e6938cc1SHelen Koike 
1196e6938cc1SHelen Koike 	/* SP supports custom stride in number of pixels of the Y plane */
1197e6938cc1SHelen Koike 	if (cap->id == RKISP1_SELFPATH)
1198e6938cc1SHelen Koike 		cap->sp_y_stride = pixm->plane_fmt[0].bytesperline /
1199e6938cc1SHelen Koike 				   cap->pix.info->bpp[0];
1200e6938cc1SHelen Koike }
1201e6938cc1SHelen Koike 
rkisp1_try_fmt_vid_cap_mplane(struct file * file,void * fh,struct v4l2_format * f)1202e6938cc1SHelen Koike static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh,
1203e6938cc1SHelen Koike 					 struct v4l2_format *f)
1204e6938cc1SHelen Koike {
1205e6938cc1SHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
1206e6938cc1SHelen Koike 
1207e6938cc1SHelen Koike 	rkisp1_try_fmt(cap, &f->fmt.pix_mp, NULL, NULL);
1208e6938cc1SHelen Koike 
1209e6938cc1SHelen Koike 	return 0;
1210e6938cc1SHelen Koike }
1211e6938cc1SHelen Koike 
rkisp1_enum_fmt_vid_cap_mplane(struct file * file,void * priv,struct v4l2_fmtdesc * f)1212e6938cc1SHelen Koike static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
1213e6938cc1SHelen Koike 					  struct v4l2_fmtdesc *f)
1214e6938cc1SHelen Koike {
1215e6938cc1SHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
1216e6938cc1SHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmt = NULL;
1217e6938cc1SHelen Koike 	unsigned int i, n = 0;
1218e6938cc1SHelen Koike 
1219e6938cc1SHelen Koike 	if (!f->mbus_code) {
1220e6938cc1SHelen Koike 		if (f->index >= cap->config->fmt_size)
1221e6938cc1SHelen Koike 			return -EINVAL;
1222e6938cc1SHelen Koike 
1223e6938cc1SHelen Koike 		fmt = &cap->config->fmts[f->index];
1224e6938cc1SHelen Koike 		f->pixelformat = fmt->fourcc;
1225e6938cc1SHelen Koike 		return 0;
1226e6938cc1SHelen Koike 	}
1227e6938cc1SHelen Koike 
1228e6938cc1SHelen Koike 	for (i = 0; i < cap->config->fmt_size; i++) {
1229e6938cc1SHelen Koike 		if (cap->config->fmts[i].mbus != f->mbus_code)
1230e6938cc1SHelen Koike 			continue;
1231e6938cc1SHelen Koike 
1232e6938cc1SHelen Koike 		if (n++ == f->index) {
1233e6938cc1SHelen Koike 			f->pixelformat = cap->config->fmts[i].fourcc;
1234e6938cc1SHelen Koike 			return 0;
1235e6938cc1SHelen Koike 		}
1236e6938cc1SHelen Koike 	}
1237e6938cc1SHelen Koike 	return -EINVAL;
1238e6938cc1SHelen Koike }
1239e6938cc1SHelen Koike 
rkisp1_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)12407cfb35d3SPaul Elder static int rkisp1_enum_framesizes(struct file *file, void *fh,
12417cfb35d3SPaul Elder 				  struct v4l2_frmsizeenum *fsize)
12427cfb35d3SPaul Elder {
12437cfb35d3SPaul Elder 	static const unsigned int max_widths[] = {
12447cfb35d3SPaul Elder 		RKISP1_RSZ_MP_SRC_MAX_WIDTH,
12457cfb35d3SPaul Elder 		RKISP1_RSZ_SP_SRC_MAX_WIDTH,
12467cfb35d3SPaul Elder 	};
12477cfb35d3SPaul Elder 	static const unsigned int max_heights[] = {
12487cfb35d3SPaul Elder 		RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
12497cfb35d3SPaul Elder 		RKISP1_RSZ_SP_SRC_MAX_HEIGHT,
12507cfb35d3SPaul Elder 	};
12517cfb35d3SPaul Elder 	struct rkisp1_capture *cap = video_drvdata(file);
12527cfb35d3SPaul Elder 
12537cfb35d3SPaul Elder 	if (fsize->index != 0)
12547cfb35d3SPaul Elder 		return -EINVAL;
12557cfb35d3SPaul Elder 
12567cfb35d3SPaul Elder 	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
12577cfb35d3SPaul Elder 
12587cfb35d3SPaul Elder 	fsize->stepwise.min_width = RKISP1_RSZ_SRC_MIN_WIDTH;
12597cfb35d3SPaul Elder 	fsize->stepwise.max_width = max_widths[cap->id];
12607cfb35d3SPaul Elder 	fsize->stepwise.step_width = 2;
12617cfb35d3SPaul Elder 
12627cfb35d3SPaul Elder 	fsize->stepwise.min_height = RKISP1_RSZ_SRC_MIN_HEIGHT;
12637cfb35d3SPaul Elder 	fsize->stepwise.max_height = max_heights[cap->id];
12647cfb35d3SPaul Elder 	fsize->stepwise.step_height = 2;
12657cfb35d3SPaul Elder 
12667cfb35d3SPaul Elder 	return 0;
12677cfb35d3SPaul Elder }
12687cfb35d3SPaul Elder 
rkisp1_s_fmt_vid_cap_mplane(struct file * file,void * priv,struct v4l2_format * f)1269e6938cc1SHelen Koike static int rkisp1_s_fmt_vid_cap_mplane(struct file *file,
1270e6938cc1SHelen Koike 				       void *priv, struct v4l2_format *f)
1271e6938cc1SHelen Koike {
1272e6938cc1SHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
1273e6938cc1SHelen Koike 	struct rkisp1_vdev_node *node =
1274e6938cc1SHelen Koike 				rkisp1_vdev_to_node(&cap->vnode.vdev);
1275e6938cc1SHelen Koike 
1276e6938cc1SHelen Koike 	if (vb2_is_busy(&node->buf_queue))
1277e6938cc1SHelen Koike 		return -EBUSY;
1278e6938cc1SHelen Koike 
1279e6938cc1SHelen Koike 	rkisp1_set_fmt(cap, &f->fmt.pix_mp);
1280e6938cc1SHelen Koike 
1281e6938cc1SHelen Koike 	return 0;
1282e6938cc1SHelen Koike }
1283e6938cc1SHelen Koike 
rkisp1_g_fmt_vid_cap_mplane(struct file * file,void * fh,struct v4l2_format * f)1284e6938cc1SHelen Koike static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh,
1285e6938cc1SHelen Koike 				       struct v4l2_format *f)
1286e6938cc1SHelen Koike {
1287e6938cc1SHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
1288e6938cc1SHelen Koike 
1289e6938cc1SHelen Koike 	f->fmt.pix_mp = cap->pix.fmt;
1290e6938cc1SHelen Koike 
1291e6938cc1SHelen Koike 	return 0;
1292e6938cc1SHelen Koike }
1293e6938cc1SHelen Koike 
1294e6938cc1SHelen Koike static int
rkisp1_querycap(struct file * file,void * priv,struct v4l2_capability * cap)1295e6938cc1SHelen Koike rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
1296e6938cc1SHelen Koike {
12973d91b856SPaul Elder 	strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver));
12983d91b856SPaul Elder 	strscpy(cap->card, RKISP1_DRIVER_NAME, sizeof(cap->card));
1299e6938cc1SHelen Koike 	strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info));
1300e6938cc1SHelen Koike 
1301e6938cc1SHelen Koike 	return 0;
1302e6938cc1SHelen Koike }
1303e6938cc1SHelen Koike 
1304e6938cc1SHelen Koike static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = {
1305e6938cc1SHelen Koike 	.vidioc_reqbufs = vb2_ioctl_reqbufs,
1306e6938cc1SHelen Koike 	.vidioc_querybuf = vb2_ioctl_querybuf,
1307e6938cc1SHelen Koike 	.vidioc_create_bufs = vb2_ioctl_create_bufs,
1308e6938cc1SHelen Koike 	.vidioc_qbuf = vb2_ioctl_qbuf,
1309e6938cc1SHelen Koike 	.vidioc_expbuf = vb2_ioctl_expbuf,
1310e6938cc1SHelen Koike 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
1311e6938cc1SHelen Koike 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1312e6938cc1SHelen Koike 	.vidioc_streamon = vb2_ioctl_streamon,
1313e6938cc1SHelen Koike 	.vidioc_streamoff = vb2_ioctl_streamoff,
1314e6938cc1SHelen Koike 	.vidioc_try_fmt_vid_cap_mplane = rkisp1_try_fmt_vid_cap_mplane,
1315e6938cc1SHelen Koike 	.vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane,
1316e6938cc1SHelen Koike 	.vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane,
1317e6938cc1SHelen Koike 	.vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane,
13187cfb35d3SPaul Elder 	.vidioc_enum_framesizes = rkisp1_enum_framesizes,
1319e6938cc1SHelen Koike 	.vidioc_querycap = rkisp1_querycap,
1320e6938cc1SHelen Koike 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1321e6938cc1SHelen Koike 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
1322e6938cc1SHelen Koike };
1323e6938cc1SHelen Koike 
rkisp1_capture_link_validate(struct media_link * link)1324e6938cc1SHelen Koike static int rkisp1_capture_link_validate(struct media_link *link)
1325e6938cc1SHelen Koike {
1326e6938cc1SHelen Koike 	struct video_device *vdev =
1327e6938cc1SHelen Koike 		media_entity_to_video_device(link->sink->entity);
1328e6938cc1SHelen Koike 	struct v4l2_subdev *sd =
1329e6938cc1SHelen Koike 		media_entity_to_v4l2_subdev(link->source->entity);
1330e6938cc1SHelen Koike 	struct rkisp1_capture *cap = video_get_drvdata(vdev);
1331e6938cc1SHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmt =
1332e6938cc1SHelen Koike 		rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat);
1333c53e3a04SLaurent Pinchart 	struct v4l2_subdev_format sd_fmt = {
1334c53e3a04SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1335c53e3a04SLaurent Pinchart 		.pad = link->source->index,
1336c53e3a04SLaurent Pinchart 	};
1337e6938cc1SHelen Koike 	int ret;
1338e6938cc1SHelen Koike 
1339e6938cc1SHelen Koike 	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
1340e6938cc1SHelen Koike 	if (ret)
1341e6938cc1SHelen Koike 		return ret;
1342e6938cc1SHelen Koike 
1343e6938cc1SHelen Koike 	if (sd_fmt.format.height != cap->pix.fmt.height ||
1344e6938cc1SHelen Koike 	    sd_fmt.format.width != cap->pix.fmt.width ||
1345fc890f00SLaurent Pinchart 	    sd_fmt.format.code != fmt->mbus) {
1346fc890f00SLaurent Pinchart 		dev_dbg(cap->rkisp1->dev,
1347fc890f00SLaurent Pinchart 			"link '%s':%u -> '%s':%u not valid: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
1348fc890f00SLaurent Pinchart 			link->source->entity->name, link->source->index,
1349fc890f00SLaurent Pinchart 			link->sink->entity->name, link->sink->index,
1350fc890f00SLaurent Pinchart 			sd_fmt.format.code, sd_fmt.format.width,
1351fc890f00SLaurent Pinchart 			sd_fmt.format.height, fmt->mbus, cap->pix.fmt.width,
1352fc890f00SLaurent Pinchart 			cap->pix.fmt.height);
1353e6938cc1SHelen Koike 		return -EPIPE;
1354fc890f00SLaurent Pinchart 	}
1355e6938cc1SHelen Koike 
1356e6938cc1SHelen Koike 	return 0;
1357e6938cc1SHelen Koike }
1358e6938cc1SHelen Koike 
1359e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
1360e6938cc1SHelen Koike  * core functions
1361e6938cc1SHelen Koike  */
1362e6938cc1SHelen Koike 
1363e6938cc1SHelen Koike static const struct media_entity_operations rkisp1_media_ops = {
1364e6938cc1SHelen Koike 	.link_validate = rkisp1_capture_link_validate,
1365e6938cc1SHelen Koike };
1366e6938cc1SHelen Koike 
1367e6938cc1SHelen Koike static const struct v4l2_file_operations rkisp1_fops = {
1368e6938cc1SHelen Koike 	.open = v4l2_fh_open,
1369e6938cc1SHelen Koike 	.release = vb2_fop_release,
1370e6938cc1SHelen Koike 	.unlocked_ioctl = video_ioctl2,
1371e6938cc1SHelen Koike 	.poll = vb2_fop_poll,
1372e6938cc1SHelen Koike 	.mmap = vb2_fop_mmap,
1373e6938cc1SHelen Koike };
1374e6938cc1SHelen Koike 
rkisp1_unregister_capture(struct rkisp1_capture * cap)1375e6938cc1SHelen Koike static void rkisp1_unregister_capture(struct rkisp1_capture *cap)
1376e6938cc1SHelen Koike {
137755fcb913SLaurent Pinchart 	if (!video_is_registered(&cap->vnode.vdev))
137855fcb913SLaurent Pinchart 		return;
137955fcb913SLaurent Pinchart 
1380e6938cc1SHelen Koike 	media_entity_cleanup(&cap->vnode.vdev.entity);
1381e6938cc1SHelen Koike 	vb2_video_unregister_device(&cap->vnode.vdev);
138255fcb913SLaurent Pinchart 	mutex_destroy(&cap->vnode.vlock);
1383e6938cc1SHelen Koike }
1384e6938cc1SHelen Koike 
rkisp1_capture_devs_unregister(struct rkisp1_device * rkisp1)1385e6938cc1SHelen Koike void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1)
1386e6938cc1SHelen Koike {
1387e6938cc1SHelen Koike 	struct rkisp1_capture *mp = &rkisp1->capture_devs[RKISP1_MAINPATH];
1388e6938cc1SHelen Koike 	struct rkisp1_capture *sp = &rkisp1->capture_devs[RKISP1_SELFPATH];
1389e6938cc1SHelen Koike 
1390e6938cc1SHelen Koike 	rkisp1_unregister_capture(mp);
1391e6938cc1SHelen Koike 	rkisp1_unregister_capture(sp);
1392e6938cc1SHelen Koike }
1393e6938cc1SHelen Koike 
rkisp1_register_capture(struct rkisp1_capture * cap)1394e6938cc1SHelen Koike static int rkisp1_register_capture(struct rkisp1_capture *cap)
1395e6938cc1SHelen Koike {
13964ee8191cSColin Ian King 	static const char * const dev_names[] = {
13974ee8191cSColin Ian King 		RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME
13984ee8191cSColin Ian King 	};
1399e6938cc1SHelen Koike 	struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev;
1400e6938cc1SHelen Koike 	struct video_device *vdev = &cap->vnode.vdev;
1401e6938cc1SHelen Koike 	struct rkisp1_vdev_node *node;
1402e6938cc1SHelen Koike 	struct vb2_queue *q;
1403e6938cc1SHelen Koike 	int ret;
1404e6938cc1SHelen Koike 
1405e6938cc1SHelen Koike 	strscpy(vdev->name, dev_names[cap->id], sizeof(vdev->name));
1406e6938cc1SHelen Koike 	node = rkisp1_vdev_to_node(vdev);
1407e6938cc1SHelen Koike 	mutex_init(&node->vlock);
1408e6938cc1SHelen Koike 
1409e6938cc1SHelen Koike 	vdev->ioctl_ops = &rkisp1_v4l2_ioctl_ops;
1410e6938cc1SHelen Koike 	vdev->release = video_device_release_empty;
1411e6938cc1SHelen Koike 	vdev->fops = &rkisp1_fops;
1412e6938cc1SHelen Koike 	vdev->minor = -1;
1413e6938cc1SHelen Koike 	vdev->v4l2_dev = v4l2_dev;
1414e6938cc1SHelen Koike 	vdev->lock = &node->vlock;
1415e6938cc1SHelen Koike 	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
1416e6938cc1SHelen Koike 			    V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
1417e6938cc1SHelen Koike 	vdev->entity.ops = &rkisp1_media_ops;
1418e6938cc1SHelen Koike 	video_set_drvdata(vdev, cap);
1419e6938cc1SHelen Koike 	vdev->vfl_dir = VFL_DIR_RX;
1420e6938cc1SHelen Koike 	node->pad.flags = MEDIA_PAD_FL_SINK;
1421e6938cc1SHelen Koike 
1422e6938cc1SHelen Koike 	q = &node->buf_queue;
1423e6938cc1SHelen Koike 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1424e6938cc1SHelen Koike 	q->io_modes = VB2_MMAP | VB2_DMABUF;
1425e6938cc1SHelen Koike 	q->drv_priv = cap;
1426e6938cc1SHelen Koike 	q->ops = &rkisp1_vb2_ops;
1427e6938cc1SHelen Koike 	q->mem_ops = &vb2_dma_contig_memops;
1428e6938cc1SHelen Koike 	q->buf_struct_size = sizeof(struct rkisp1_buffer);
1429e6938cc1SHelen Koike 	q->min_buffers_needed = RKISP1_MIN_BUFFERS_NEEDED;
1430e6938cc1SHelen Koike 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1431e6938cc1SHelen Koike 	q->lock = &node->vlock;
1432e6938cc1SHelen Koike 	q->dev = cap->rkisp1->dev;
1433e6938cc1SHelen Koike 	ret = vb2_queue_init(q);
1434e6938cc1SHelen Koike 	if (ret) {
1435e6938cc1SHelen Koike 		dev_err(cap->rkisp1->dev,
1436e6938cc1SHelen Koike 			"vb2 queue init failed (err=%d)\n", ret);
143755fcb913SLaurent Pinchart 		goto error;
1438e6938cc1SHelen Koike 	}
1439e6938cc1SHelen Koike 
1440e6938cc1SHelen Koike 	vdev->queue = q;
1441e6938cc1SHelen Koike 
144256c8534eSLaurent Pinchart 	ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
144356c8534eSLaurent Pinchart 	if (ret)
144455fcb913SLaurent Pinchart 		goto error;
144556c8534eSLaurent Pinchart 
1446e6938cc1SHelen Koike 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1447e6938cc1SHelen Koike 	if (ret) {
1448e6938cc1SHelen Koike 		dev_err(cap->rkisp1->dev,
1449e6938cc1SHelen Koike 			"failed to register %s, ret=%d\n", vdev->name, ret);
145056c8534eSLaurent Pinchart 		goto error;
1451e6938cc1SHelen Koike 	}
145256c8534eSLaurent Pinchart 
1453e6938cc1SHelen Koike 	v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name,
1454e6938cc1SHelen Koike 		  vdev->num);
1455e6938cc1SHelen Koike 
1456e6938cc1SHelen Koike 	return 0;
145756c8534eSLaurent Pinchart 
145856c8534eSLaurent Pinchart error:
145956c8534eSLaurent Pinchart 	media_entity_cleanup(&vdev->entity);
146055fcb913SLaurent Pinchart 	mutex_destroy(&node->vlock);
146156c8534eSLaurent Pinchart 	return ret;
1462e6938cc1SHelen Koike }
1463e6938cc1SHelen Koike 
1464e6938cc1SHelen Koike static void
rkisp1_capture_init(struct rkisp1_device * rkisp1,enum rkisp1_stream_id id)1465e6938cc1SHelen Koike rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id)
1466e6938cc1SHelen Koike {
1467e6938cc1SHelen Koike 	struct rkisp1_capture *cap = &rkisp1->capture_devs[id];
1468e6938cc1SHelen Koike 	struct v4l2_pix_format_mplane pixm;
1469e6938cc1SHelen Koike 
1470e6938cc1SHelen Koike 	memset(cap, 0, sizeof(*cap));
1471e6938cc1SHelen Koike 	cap->id = id;
1472e6938cc1SHelen Koike 	cap->rkisp1 = rkisp1;
1473e6938cc1SHelen Koike 
1474e6938cc1SHelen Koike 	INIT_LIST_HEAD(&cap->buf.queue);
1475e6938cc1SHelen Koike 	init_waitqueue_head(&cap->done);
1476e6938cc1SHelen Koike 	spin_lock_init(&cap->buf.lock);
1477e6938cc1SHelen Koike 	if (cap->id == RKISP1_SELFPATH) {
1478e6938cc1SHelen Koike 		cap->ops = &rkisp1_capture_ops_sp;
1479e6938cc1SHelen Koike 		cap->config = &rkisp1_capture_config_sp;
1480e6938cc1SHelen Koike 	} else {
1481e6938cc1SHelen Koike 		cap->ops = &rkisp1_capture_ops_mp;
1482e6938cc1SHelen Koike 		cap->config = &rkisp1_capture_config_mp;
1483e6938cc1SHelen Koike 	}
1484e6938cc1SHelen Koike 
1485e6938cc1SHelen Koike 	cap->is_streaming = false;
1486e6938cc1SHelen Koike 
1487e6938cc1SHelen Koike 	memset(&pixm, 0, sizeof(pixm));
1488e6938cc1SHelen Koike 	pixm.pixelformat = V4L2_PIX_FMT_YUYV;
1489e6938cc1SHelen Koike 	pixm.width = RKISP1_DEFAULT_WIDTH;
1490e6938cc1SHelen Koike 	pixm.height = RKISP1_DEFAULT_HEIGHT;
1491e6938cc1SHelen Koike 	rkisp1_set_fmt(cap, &pixm);
1492e6938cc1SHelen Koike }
1493e6938cc1SHelen Koike 
rkisp1_capture_devs_register(struct rkisp1_device * rkisp1)1494e6938cc1SHelen Koike int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1)
1495e6938cc1SHelen Koike {
149655fcb913SLaurent Pinchart 	unsigned int i;
1497e6938cc1SHelen Koike 	int ret;
1498e6938cc1SHelen Koike 
1499e6938cc1SHelen Koike 	for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) {
150055fcb913SLaurent Pinchart 		struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
150155fcb913SLaurent Pinchart 
1502e6938cc1SHelen Koike 		rkisp1_capture_init(rkisp1, i);
150355fcb913SLaurent Pinchart 
1504e6938cc1SHelen Koike 		ret = rkisp1_register_capture(cap);
150555fcb913SLaurent Pinchart 		if (ret) {
150655fcb913SLaurent Pinchart 			rkisp1_capture_devs_unregister(rkisp1);
150755fcb913SLaurent Pinchart 			return ret;
150855fcb913SLaurent Pinchart 		}
1509e6938cc1SHelen Koike 	}
1510e6938cc1SHelen Koike 
1511e6938cc1SHelen Koike 	return 0;
1512e6938cc1SHelen Koike 
1513e6938cc1SHelen Koike }
1514