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