xref: /linux/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c (revision 1260ed77798502de9c98020040d2995008de10cc)
156e3b29fSHelen Koike // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
256e3b29fSHelen Koike /*
356e3b29fSHelen Koike  * Rockchip ISP1 Driver - V4l capture device
456e3b29fSHelen Koike  *
556e3b29fSHelen Koike  * Copyright (C) 2019 Collabora, Ltd.
656e3b29fSHelen Koike  *
756e3b29fSHelen Koike  * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
856e3b29fSHelen Koike  * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
956e3b29fSHelen Koike  */
1056e3b29fSHelen Koike 
1156e3b29fSHelen Koike #include <linux/delay.h>
1256e3b29fSHelen Koike #include <linux/pm_runtime.h>
1356e3b29fSHelen Koike #include <media/v4l2-common.h>
1456e3b29fSHelen Koike #include <media/v4l2-event.h>
1556e3b29fSHelen Koike #include <media/v4l2-fh.h>
1656e3b29fSHelen Koike #include <media/v4l2-ioctl.h>
1756e3b29fSHelen Koike #include <media/v4l2-mc.h>
1856e3b29fSHelen Koike #include <media/v4l2-subdev.h>
1956e3b29fSHelen Koike #include <media/videobuf2-dma-contig.h>
2056e3b29fSHelen Koike 
2156e3b29fSHelen Koike #include "rkisp1-common.h"
2256e3b29fSHelen Koike 
2356e3b29fSHelen Koike /*
2456e3b29fSHelen Koike  * NOTE: There are two capture video devices in rkisp1, selfpath and mainpath.
2556e3b29fSHelen Koike  *
2656e3b29fSHelen Koike  * differences between selfpath and mainpath
2756e3b29fSHelen Koike  * available mp sink input: isp
2856e3b29fSHelen Koike  * available sp sink input : isp, dma(TODO)
2956e3b29fSHelen Koike  * available mp sink pad fmts: yuv422, raw
3056e3b29fSHelen Koike  * available sp sink pad fmts: yuv422, yuv420......
3156e3b29fSHelen Koike  * available mp source fmts: yuv, raw, jpeg(TODO)
3256e3b29fSHelen Koike  * available sp source fmts: yuv, rgb
3356e3b29fSHelen Koike  */
3456e3b29fSHelen Koike 
3556e3b29fSHelen Koike #define RKISP1_SP_DEV_NAME	RKISP1_DRIVER_NAME "_selfpath"
3656e3b29fSHelen Koike #define RKISP1_MP_DEV_NAME	RKISP1_DRIVER_NAME "_mainpath"
3756e3b29fSHelen Koike 
3856e3b29fSHelen Koike enum rkisp1_plane {
3956e3b29fSHelen Koike 	RKISP1_PLANE_Y	= 0,
4056e3b29fSHelen Koike 	RKISP1_PLANE_CB	= 1,
4156e3b29fSHelen Koike 	RKISP1_PLANE_CR	= 2
4256e3b29fSHelen Koike };
4356e3b29fSHelen Koike 
4456e3b29fSHelen Koike /*
4556e3b29fSHelen Koike  * @fourcc: pixel format
4656e3b29fSHelen Koike  * @fmt_type: helper filed for pixel format
476b94c09fSPeilin Ye  * @uv_swap: if cb cr swapped, for yuv
48fd62bd4eSPaul Elder  * @yc_swap: if y and cb/cr swapped, for yuv
496c144351SPaul Elder  * @byte_swap: if byte pairs are swapped, for raw
5056e3b29fSHelen Koike  * @write_format: defines how YCbCr self picture data is written to memory
516c144351SPaul Elder  * @output_format: defines the output format (RKISP1_CIF_MI_INIT_MP_OUTPUT_* for
526c144351SPaul Elder  *	the main path and RKISP1_MI_CTRL_SP_OUTPUT_* for the self path)
535fc929aeSDafna Hirschfeld  * @mbus: the mbus code on the src resizer pad that matches the pixel format
5456e3b29fSHelen Koike  */
5556e3b29fSHelen Koike struct rkisp1_capture_fmt_cfg {
5656e3b29fSHelen Koike 	u32 fourcc;
57fd62bd4eSPaul Elder 	u32 uv_swap : 1;
58fd62bd4eSPaul Elder 	u32 yc_swap : 1;
596c144351SPaul Elder 	u32 byte_swap : 1;
6056e3b29fSHelen Koike 	u32 write_format;
6156e3b29fSHelen Koike 	u32 output_format;
625fc929aeSDafna Hirschfeld 	u32 mbus;
6356e3b29fSHelen Koike };
6456e3b29fSHelen Koike 
6556e3b29fSHelen Koike struct rkisp1_capture_ops {
6656e3b29fSHelen Koike 	void (*config)(struct rkisp1_capture *cap);
6756e3b29fSHelen Koike 	void (*stop)(struct rkisp1_capture *cap);
6856e3b29fSHelen Koike 	void (*enable)(struct rkisp1_capture *cap);
6956e3b29fSHelen Koike 	void (*disable)(struct rkisp1_capture *cap);
7056e3b29fSHelen Koike 	void (*set_data_path)(struct rkisp1_capture *cap);
7156e3b29fSHelen Koike 	bool (*is_stopped)(struct rkisp1_capture *cap);
7256e3b29fSHelen Koike };
7356e3b29fSHelen Koike 
7456e3b29fSHelen Koike struct rkisp1_capture_config {
7556e3b29fSHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmts;
7656e3b29fSHelen Koike 	int fmt_size;
7756e3b29fSHelen Koike 	struct {
7856e3b29fSHelen Koike 		u32 y_size_init;
7956e3b29fSHelen Koike 		u32 cb_size_init;
8056e3b29fSHelen Koike 		u32 cr_size_init;
8156e3b29fSHelen Koike 		u32 y_base_ad_init;
8256e3b29fSHelen Koike 		u32 cb_base_ad_init;
8356e3b29fSHelen Koike 		u32 cr_base_ad_init;
8456e3b29fSHelen Koike 		u32 y_offs_cnt_init;
8556e3b29fSHelen Koike 		u32 cb_offs_cnt_init;
8656e3b29fSHelen Koike 		u32 cr_offs_cnt_init;
8756e3b29fSHelen Koike 	} mi;
8856e3b29fSHelen Koike };
8956e3b29fSHelen Koike 
909a8e67b8SDafna Hirschfeld /*
919a8e67b8SDafna Hirschfeld  * The supported pixel formats for mainpath. NOTE, pixel formats with identical 'mbus'
929a8e67b8SDafna Hirschfeld  * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes
939a8e67b8SDafna Hirschfeld  */
9456e3b29fSHelen Koike static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = {
9556e3b29fSHelen Koike 	/* yuv422 */
9656e3b29fSHelen Koike 	{
9756e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUYV,
9856e3b29fSHelen Koike 		.uv_swap = 0,
9956e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT,
1006c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1015fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
10256e3b29fSHelen Koike 	}, {
1030a593f71SPaul Elder 		.fourcc = V4L2_PIX_FMT_UYVY,
1040a593f71SPaul Elder 		.uv_swap = 0,
1050a593f71SPaul Elder 		.yc_swap = 1,
1060a593f71SPaul Elder 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT,
1076c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
10856e3b29fSHelen Koike 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
10956e3b29fSHelen Koike 	}, {
11056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV422P,
11156e3b29fSHelen Koike 		.uv_swap = 0,
11256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1136c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1145fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
11556e3b29fSHelen Koike 	}, {
11656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV16,
11756e3b29fSHelen Koike 		.uv_swap = 0,
11856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1196c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1205fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
12156e3b29fSHelen Koike 	}, {
12256e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV61,
12356e3b29fSHelen Koike 		.uv_swap = 1,
12456e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1256c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1265fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
12756e3b29fSHelen Koike 	}, {
1287cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV16M,
1297cb7018cSPaul Elder 		.uv_swap = 0,
1307cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1316c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1327cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
1337cb7018cSPaul Elder 	}, {
1347cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV61M,
1357cb7018cSPaul Elder 		.uv_swap = 1,
1367cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1376c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1387cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
1397cb7018cSPaul Elder 	}, {
14056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU422M,
14156e3b29fSHelen Koike 		.uv_swap = 1,
14256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1436c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422,
1445fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
14556e3b29fSHelen Koike 	},
1469a8e67b8SDafna Hirschfeld 	/* yuv400 */
1479a8e67b8SDafna Hirschfeld 	{
1489a8e67b8SDafna Hirschfeld 		.fourcc = V4L2_PIX_FMT_GREY,
1499a8e67b8SDafna Hirschfeld 		.uv_swap = 0,
1500ec314ffSDafna Hirschfeld 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1516c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV400,
1529a8e67b8SDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
1539a8e67b8SDafna Hirschfeld 	},
15456e3b29fSHelen Koike 	/* yuv420 */
15556e3b29fSHelen Koike 	{
15656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21,
15756e3b29fSHelen Koike 		.uv_swap = 1,
15856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1596c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1605fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
16156e3b29fSHelen Koike 	}, {
16256e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12,
16356e3b29fSHelen Koike 		.uv_swap = 0,
16456e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1656c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1665fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
16756e3b29fSHelen Koike 	}, {
16856e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21M,
16956e3b29fSHelen Koike 		.uv_swap = 1,
17056e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1716c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1725fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
17356e3b29fSHelen Koike 	}, {
17456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12M,
17556e3b29fSHelen Koike 		.uv_swap = 0,
17656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA,
1776c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1785fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
17956e3b29fSHelen Koike 	}, {
18056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV420,
18156e3b29fSHelen Koike 		.uv_swap = 0,
18256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1836c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1845fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
18556e3b29fSHelen Koike 	}, {
18656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU420,
18756e3b29fSHelen Koike 		.uv_swap = 1,
18856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1896c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420,
1905fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
19156e3b29fSHelen Koike 	},
19256e3b29fSHelen Koike 	/* raw */
19356e3b29fSHelen Koike 	{
19456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB8,
19556e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
1966c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
1975fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SRGGB8_1X8,
19856e3b29fSHelen Koike 	}, {
19956e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG8,
20056e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
2016c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
2025fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGRBG8_1X8,
20356e3b29fSHelen Koike 	}, {
20456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG8,
20556e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
2066c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
2075fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGBRG8_1X8,
20856e3b29fSHelen Koike 	}, {
20956e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR8,
21056e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8,
2116c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8,
2125fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SBGGR8_1X8,
21356e3b29fSHelen Koike 	}, {
21456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB10,
2156c144351SPaul Elder 		.byte_swap = 1,
21656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2176c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
2185fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SRGGB10_1X10,
21956e3b29fSHelen Koike 	}, {
22056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG10,
2216c144351SPaul Elder 		.byte_swap = 1,
22256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2236c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
2245fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGRBG10_1X10,
22556e3b29fSHelen Koike 	}, {
22656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG10,
2276c144351SPaul Elder 		.byte_swap = 1,
22856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2296c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
2305fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGBRG10_1X10,
23156e3b29fSHelen Koike 	}, {
23256e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR10,
2336c144351SPaul Elder 		.byte_swap = 1,
23456e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2356c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10,
2365fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SBGGR10_1X10,
23756e3b29fSHelen Koike 	}, {
23856e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SRGGB12,
2396c144351SPaul Elder 		.byte_swap = 1,
24056e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2416c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
2425fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SRGGB12_1X12,
24356e3b29fSHelen Koike 	}, {
24456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGRBG12,
2456c144351SPaul Elder 		.byte_swap = 1,
24656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2476c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
2485fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGRBG12_1X12,
24956e3b29fSHelen Koike 	}, {
25056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SGBRG12,
2516c144351SPaul Elder 		.byte_swap = 1,
25256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2536c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
2545fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SGBRG12_1X12,
25556e3b29fSHelen Koike 	}, {
25656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_SBGGR12,
2576c144351SPaul Elder 		.byte_swap = 1,
25856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12,
2596c144351SPaul Elder 		.output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12,
2605fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_SBGGR12_1X12,
26156e3b29fSHelen Koike 	},
26256e3b29fSHelen Koike };
26356e3b29fSHelen Koike 
2649a8e67b8SDafna Hirschfeld /*
2659a8e67b8SDafna Hirschfeld  * The supported pixel formats for selfpath. NOTE, pixel formats with identical 'mbus'
2669a8e67b8SDafna Hirschfeld  * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes
2679a8e67b8SDafna Hirschfeld  */
26856e3b29fSHelen Koike static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = {
26956e3b29fSHelen Koike 	/* yuv422 */
27056e3b29fSHelen Koike 	{
27156e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUYV,
27256e3b29fSHelen Koike 		.uv_swap = 0,
27356e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_INT,
27456e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2755fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
27656e3b29fSHelen Koike 	}, {
2770a593f71SPaul Elder 		.fourcc = V4L2_PIX_FMT_UYVY,
2780a593f71SPaul Elder 		.uv_swap = 0,
2790a593f71SPaul Elder 		.yc_swap = 1,
2800a593f71SPaul Elder 		.write_format = RKISP1_MI_CTRL_SP_WRITE_INT,
2810a593f71SPaul Elder 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2820a593f71SPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
2830a593f71SPaul Elder 	}, {
28456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV422P,
28556e3b29fSHelen Koike 		.uv_swap = 0,
28656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
28756e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2885fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
28956e3b29fSHelen Koike 	}, {
29056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV16,
29156e3b29fSHelen Koike 		.uv_swap = 0,
29256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
29356e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
2945fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
29556e3b29fSHelen Koike 	}, {
29656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV61,
29756e3b29fSHelen Koike 		.uv_swap = 1,
29856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
29956e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
3005fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
30156e3b29fSHelen Koike 	}, {
3027cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV16M,
3037cb7018cSPaul Elder 		.uv_swap = 0,
3047cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
3057cb7018cSPaul Elder 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
3067cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
3077cb7018cSPaul Elder 	}, {
3087cb7018cSPaul Elder 		.fourcc = V4L2_PIX_FMT_NV61M,
3097cb7018cSPaul Elder 		.uv_swap = 1,
3107cb7018cSPaul Elder 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
3117cb7018cSPaul Elder 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
3127cb7018cSPaul Elder 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
3137cb7018cSPaul Elder 	}, {
31456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU422M,
31556e3b29fSHelen Koike 		.uv_swap = 1,
31656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
31756e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
3185fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
31956e3b29fSHelen Koike 	},
3209a8e67b8SDafna Hirschfeld 	/* yuv400 */
3219a8e67b8SDafna Hirschfeld 	{
3229a8e67b8SDafna Hirschfeld 		.fourcc = V4L2_PIX_FMT_GREY,
3239a8e67b8SDafna Hirschfeld 		.uv_swap = 0,
3240ec314ffSDafna Hirschfeld 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
3259a0e3cd5SDafna Hirschfeld 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422,
3269a8e67b8SDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
3279a8e67b8SDafna Hirschfeld 	},
3289a8e67b8SDafna Hirschfeld 	/* rgb */
3299a8e67b8SDafna Hirschfeld 	{
3309a8e67b8SDafna Hirschfeld 		.fourcc = V4L2_PIX_FMT_XBGR32,
3319a8e67b8SDafna Hirschfeld 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
3329a8e67b8SDafna Hirschfeld 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB888,
3339a8e67b8SDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
3349a8e67b8SDafna Hirschfeld 	}, {
3359a8e67b8SDafna Hirschfeld 		.fourcc = V4L2_PIX_FMT_RGB565,
3369a8e67b8SDafna Hirschfeld 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
3379a8e67b8SDafna Hirschfeld 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB565,
3389a8e67b8SDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_2X8,
3399a8e67b8SDafna Hirschfeld 	},
34056e3b29fSHelen Koike 	/* yuv420 */
34156e3b29fSHelen Koike 	{
34256e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21,
34356e3b29fSHelen Koike 		.uv_swap = 1,
34456e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
34556e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3465fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
34756e3b29fSHelen Koike 	}, {
34856e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12,
34956e3b29fSHelen Koike 		.uv_swap = 0,
35056e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
35156e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3525fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
35356e3b29fSHelen Koike 	}, {
35456e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV21M,
35556e3b29fSHelen Koike 		.uv_swap = 1,
35656e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
35756e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3585fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
35956e3b29fSHelen Koike 	}, {
36056e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_NV12M,
36156e3b29fSHelen Koike 		.uv_swap = 0,
36256e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA,
36356e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3645fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
36556e3b29fSHelen Koike 	}, {
36656e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YUV420,
36756e3b29fSHelen Koike 		.uv_swap = 0,
36856e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
36956e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3705fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
37156e3b29fSHelen Koike 	}, {
37256e3b29fSHelen Koike 		.fourcc = V4L2_PIX_FMT_YVU420,
37356e3b29fSHelen Koike 		.uv_swap = 1,
37456e3b29fSHelen Koike 		.write_format = RKISP1_MI_CTRL_SP_WRITE_PLA,
37556e3b29fSHelen Koike 		.output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420,
3765fc929aeSDafna Hirschfeld 		.mbus = MEDIA_BUS_FMT_YUYV8_1_5X8,
37756e3b29fSHelen Koike 	},
37856e3b29fSHelen Koike };
37956e3b29fSHelen Koike 
38056e3b29fSHelen Koike static const struct rkisp1_capture_config rkisp1_capture_config_mp = {
38156e3b29fSHelen Koike 	.fmts = rkisp1_mp_fmts,
38256e3b29fSHelen Koike 	.fmt_size = ARRAY_SIZE(rkisp1_mp_fmts),
38356e3b29fSHelen Koike 	.mi = {
38456e3b29fSHelen Koike 		.y_size_init =		RKISP1_CIF_MI_MP_Y_SIZE_INIT,
38556e3b29fSHelen Koike 		.cb_size_init =		RKISP1_CIF_MI_MP_CB_SIZE_INIT,
38656e3b29fSHelen Koike 		.cr_size_init =		RKISP1_CIF_MI_MP_CR_SIZE_INIT,
38756e3b29fSHelen Koike 		.y_base_ad_init =	RKISP1_CIF_MI_MP_Y_BASE_AD_INIT,
38856e3b29fSHelen Koike 		.cb_base_ad_init =	RKISP1_CIF_MI_MP_CB_BASE_AD_INIT,
38956e3b29fSHelen Koike 		.cr_base_ad_init =	RKISP1_CIF_MI_MP_CR_BASE_AD_INIT,
39056e3b29fSHelen Koike 		.y_offs_cnt_init =	RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT,
39156e3b29fSHelen Koike 		.cb_offs_cnt_init =	RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT,
39256e3b29fSHelen Koike 		.cr_offs_cnt_init =	RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT,
39356e3b29fSHelen Koike 	},
39456e3b29fSHelen Koike };
39556e3b29fSHelen Koike 
39656e3b29fSHelen Koike static const struct rkisp1_capture_config rkisp1_capture_config_sp = {
39756e3b29fSHelen Koike 	.fmts = rkisp1_sp_fmts,
39856e3b29fSHelen Koike 	.fmt_size = ARRAY_SIZE(rkisp1_sp_fmts),
39956e3b29fSHelen Koike 	.mi = {
40056e3b29fSHelen Koike 		.y_size_init =		RKISP1_CIF_MI_SP_Y_SIZE_INIT,
40156e3b29fSHelen Koike 		.cb_size_init =		RKISP1_CIF_MI_SP_CB_SIZE_INIT,
40256e3b29fSHelen Koike 		.cr_size_init =		RKISP1_CIF_MI_SP_CR_SIZE_INIT,
40356e3b29fSHelen Koike 		.y_base_ad_init =	RKISP1_CIF_MI_SP_Y_BASE_AD_INIT,
40456e3b29fSHelen Koike 		.cb_base_ad_init =	RKISP1_CIF_MI_SP_CB_BASE_AD_INIT,
40556e3b29fSHelen Koike 		.cr_base_ad_init =	RKISP1_CIF_MI_SP_CR_BASE_AD_INIT,
40656e3b29fSHelen Koike 		.y_offs_cnt_init =	RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT,
40756e3b29fSHelen Koike 		.cb_offs_cnt_init =	RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT,
40856e3b29fSHelen Koike 		.cr_offs_cnt_init =	RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT,
40956e3b29fSHelen Koike 	},
41056e3b29fSHelen Koike };
41156e3b29fSHelen Koike 
41256e3b29fSHelen Koike static inline struct rkisp1_vdev_node *
rkisp1_vdev_to_node(struct video_device * vdev)41356e3b29fSHelen Koike rkisp1_vdev_to_node(struct video_device *vdev)
41456e3b29fSHelen Koike {
41556e3b29fSHelen Koike 	return container_of(vdev, struct rkisp1_vdev_node, vdev);
41656e3b29fSHelen Koike }
41756e3b29fSHelen Koike 
rkisp1_cap_enum_mbus_codes(struct rkisp1_capture * cap,struct v4l2_subdev_mbus_code_enum * code)4189a8e67b8SDafna Hirschfeld int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap,
4199a8e67b8SDafna Hirschfeld 			       struct v4l2_subdev_mbus_code_enum *code)
4209a8e67b8SDafna Hirschfeld {
4219a8e67b8SDafna Hirschfeld 	const struct rkisp1_capture_fmt_cfg *fmts = cap->config->fmts;
4229a8e67b8SDafna Hirschfeld 	/*
4239a8e67b8SDafna Hirschfeld 	 * initialize curr_mbus to non existing mbus code 0 to ensure it is
4249a8e67b8SDafna Hirschfeld 	 * different from fmts[0].mbus
4259a8e67b8SDafna Hirschfeld 	 */
4269a8e67b8SDafna Hirschfeld 	u32 curr_mbus = 0;
4279a8e67b8SDafna Hirschfeld 	int i, n = 0;
4289a8e67b8SDafna Hirschfeld 
4299a8e67b8SDafna Hirschfeld 	for (i = 0; i < cap->config->fmt_size; i++) {
4309a8e67b8SDafna Hirschfeld 		if (fmts[i].mbus == curr_mbus)
4319a8e67b8SDafna Hirschfeld 			continue;
4329a8e67b8SDafna Hirschfeld 
4339a8e67b8SDafna Hirschfeld 		curr_mbus = fmts[i].mbus;
4349a8e67b8SDafna Hirschfeld 		if (n++ == code->index) {
4359a8e67b8SDafna Hirschfeld 			code->code = curr_mbus;
4369a8e67b8SDafna Hirschfeld 			return 0;
4379a8e67b8SDafna Hirschfeld 		}
4389a8e67b8SDafna Hirschfeld 	}
4399a8e67b8SDafna Hirschfeld 	return -EINVAL;
4409a8e67b8SDafna Hirschfeld }
4419a8e67b8SDafna Hirschfeld 
44256e3b29fSHelen Koike /* ----------------------------------------------------------------------------
44356e3b29fSHelen Koike  * Stream operations for self-picture path (sp) and main-picture path (mp)
44456e3b29fSHelen Koike  */
44556e3b29fSHelen Koike 
rkisp1_mi_config_ctrl(struct rkisp1_capture * cap)44656e3b29fSHelen Koike static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap)
44756e3b29fSHelen Koike {
44856e3b29fSHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
44956e3b29fSHelen Koike 
45056e3b29fSHelen Koike 	mi_ctrl &= ~GENMASK(17, 16);
45156e3b29fSHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64;
45256e3b29fSHelen Koike 
45356e3b29fSHelen Koike 	mi_ctrl &= ~GENMASK(19, 18);
45456e3b29fSHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64;
45556e3b29fSHelen Koike 
45656e3b29fSHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN |
45756e3b29fSHelen Koike 		   RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN;
45856e3b29fSHelen Koike 
4590ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
46056e3b29fSHelen Koike }
46156e3b29fSHelen Koike 
rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane * pixm,unsigned int component)46256e3b29fSHelen Koike static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm,
46356e3b29fSHelen Koike 				   unsigned int component)
46456e3b29fSHelen Koike {
46556e3b29fSHelen Koike 	/*
46656e3b29fSHelen Koike 	 * If packed format, then plane_fmt[0].sizeimage is the sum of all
46756e3b29fSHelen Koike 	 * components, so we need to calculate just the size of Y component.
46856e3b29fSHelen Koike 	 * See rkisp1_fill_pixfmt().
46956e3b29fSHelen Koike 	 */
47056e3b29fSHelen Koike 	if (!component && pixm->num_planes == 1)
47156e3b29fSHelen Koike 		return pixm->plane_fmt[0].bytesperline * pixm->height;
47256e3b29fSHelen Koike 	return pixm->plane_fmt[component].sizeimage;
47356e3b29fSHelen Koike }
47456e3b29fSHelen Koike 
rkisp1_irq_frame_end_enable(struct rkisp1_capture * cap)47556e3b29fSHelen Koike static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap)
47656e3b29fSHelen Koike {
47756e3b29fSHelen Koike 	u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC);
47856e3b29fSHelen Koike 
47956e3b29fSHelen Koike 	mi_imsc |= RKISP1_CIF_MI_FRAME(cap);
4800ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_IMSC, mi_imsc);
48156e3b29fSHelen Koike }
48256e3b29fSHelen Koike 
rkisp1_mp_config(struct rkisp1_capture * cap)48356e3b29fSHelen Koike static void rkisp1_mp_config(struct rkisp1_capture *cap)
48456e3b29fSHelen Koike {
48556e3b29fSHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
48656e3b29fSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
48756e3b29fSHelen Koike 	u32 reg;
48856e3b29fSHelen Koike 
4890ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.y_size_init,
4900ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
4910ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
4920ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
4930ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
4940ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
49556e3b29fSHelen Koike 
496bcb40cc1SPaul Elder 	if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
497bcb40cc1SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_LLENGTH, cap->stride);
498bcb40cc1SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_WIDTH, pixm->width);
499bcb40cc1SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_HEIGHT, pixm->height);
500bcb40cc1SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_SIZE,
501bcb40cc1SPaul Elder 			     cap->stride * pixm->height);
502bcb40cc1SPaul Elder 	}
503bcb40cc1SPaul Elder 
50456e3b29fSHelen Koike 	rkisp1_irq_frame_end_enable(cap);
505c6a86569SDafna Hirschfeld 
506c6a86569SDafna Hirschfeld 	/* set uv swapping for semiplanar formats */
507c6a86569SDafna Hirschfeld 	if (cap->pix.info->comp_planes == 2) {
50856e3b29fSHelen Koike 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
509b82b3993SDafna Hirschfeld 		if (cap->pix.cfg->uv_swap)
510ceb34869SDafna Hirschfeld 			reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
511b82b3993SDafna Hirschfeld 		else
512b82b3993SDafna Hirschfeld 			reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
5130ef7dc30SLaurent Pinchart 		rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
514c6a86569SDafna Hirschfeld 	}
51556e3b29fSHelen Koike 
5160a593f71SPaul Elder 	/*
5170a593f71SPaul Elder 	 * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for
5180a593f71SPaul Elder 	 * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY.
5190a593f71SPaul Elder 	 * YVYU and VYUY cannot be supported with this method.
5200a593f71SPaul Elder 	 */
5210a593f71SPaul Elder 	if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
5220a593f71SPaul Elder 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT);
5236c144351SPaul Elder 		if (cap->pix.cfg->yc_swap || cap->pix.cfg->byte_swap)
5240a593f71SPaul Elder 			reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES;
5250a593f71SPaul Elder 		else
5260a593f71SPaul Elder 			reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES;
5276c144351SPaul Elder 
5286c144351SPaul Elder 		reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_LSB_ALIGNMENT;
5290a593f71SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg);
5306c144351SPaul Elder 
5316c144351SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT,
5326c144351SPaul Elder 			     cap->pix.cfg->output_format);
5330a593f71SPaul Elder 	}
5340a593f71SPaul Elder 
53556e3b29fSHelen Koike 	rkisp1_mi_config_ctrl(cap);
53656e3b29fSHelen Koike 
53756e3b29fSHelen Koike 	reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
53856e3b29fSHelen Koike 	reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK;
53956e3b29fSHelen Koike 	reg |= cap->pix.cfg->write_format;
5400ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
54156e3b29fSHelen Koike 
54256e3b29fSHelen Koike 	reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
54356e3b29fSHelen Koike 	reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE;
5440ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
54556e3b29fSHelen Koike }
54656e3b29fSHelen Koike 
rkisp1_sp_config(struct rkisp1_capture * cap)54756e3b29fSHelen Koike static void rkisp1_sp_config(struct rkisp1_capture *cap)
54856e3b29fSHelen Koike {
54956e3b29fSHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
55056e3b29fSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
551b82b3993SDafna Hirschfeld 	u32 mi_ctrl, reg;
55256e3b29fSHelen Koike 
5530ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.y_size_init,
5540ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
5550ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
5560ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
5570ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
5580ef7dc30SLaurent Pinchart 		     rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
55956e3b29fSHelen Koike 
560bcb40cc1SPaul Elder 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->stride);
5610ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width);
5620ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height);
563f4bc9c79SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_SIZE,
564bcb40cc1SPaul Elder 		     cap->stride * pixm->height);
56556e3b29fSHelen Koike 
56656e3b29fSHelen Koike 	rkisp1_irq_frame_end_enable(cap);
56756e3b29fSHelen Koike 
568c6a86569SDafna Hirschfeld 	/* set uv swapping for semiplanar formats */
569c6a86569SDafna Hirschfeld 	if (cap->pix.info->comp_planes == 2) {
570b82b3993SDafna Hirschfeld 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
571b82b3993SDafna Hirschfeld 		if (cap->pix.cfg->uv_swap)
572a557c3faSDafna Hirschfeld 			reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
573b82b3993SDafna Hirschfeld 		else
574b82b3993SDafna Hirschfeld 			reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
5750ef7dc30SLaurent Pinchart 		rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
576c6a86569SDafna Hirschfeld 	}
57756e3b29fSHelen Koike 
5780a593f71SPaul Elder 	/*
5790a593f71SPaul Elder 	 * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for
5800a593f71SPaul Elder 	 * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY.
5810a593f71SPaul Elder 	 * YVYU and VYUY cannot be supported with this method.
5820a593f71SPaul Elder 	 */
5830a593f71SPaul Elder 	if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) {
5840a593f71SPaul Elder 		reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT);
5850a593f71SPaul Elder 		if (cap->pix.cfg->yc_swap)
5860a593f71SPaul Elder 			reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES;
5870a593f71SPaul Elder 		else
5880a593f71SPaul Elder 			reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES;
5890a593f71SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg);
5900a593f71SPaul Elder 	}
5910a593f71SPaul Elder 
59256e3b29fSHelen Koike 	rkisp1_mi_config_ctrl(cap);
59356e3b29fSHelen Koike 
59456e3b29fSHelen Koike 	mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
59556e3b29fSHelen Koike 	mi_ctrl &= ~RKISP1_MI_CTRL_SP_FMT_MASK;
59656e3b29fSHelen Koike 	mi_ctrl |= cap->pix.cfg->write_format |
59756e3b29fSHelen Koike 		   RKISP1_MI_CTRL_SP_INPUT_YUV422 |
59856e3b29fSHelen Koike 		   cap->pix.cfg->output_format |
59956e3b29fSHelen Koike 		   RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE;
6000ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
60156e3b29fSHelen Koike }
60256e3b29fSHelen Koike 
rkisp1_mp_disable(struct rkisp1_capture * cap)60356e3b29fSHelen Koike static void rkisp1_mp_disable(struct rkisp1_capture *cap)
60456e3b29fSHelen Koike {
60556e3b29fSHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
60656e3b29fSHelen Koike 
60756e3b29fSHelen Koike 	mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE |
60856e3b29fSHelen Koike 		     RKISP1_CIF_MI_CTRL_RAW_ENABLE);
6090ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
61056e3b29fSHelen Koike }
61156e3b29fSHelen Koike 
rkisp1_sp_disable(struct rkisp1_capture * cap)61256e3b29fSHelen Koike static void rkisp1_sp_disable(struct rkisp1_capture *cap)
61356e3b29fSHelen Koike {
61456e3b29fSHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
61556e3b29fSHelen Koike 
61656e3b29fSHelen Koike 	mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE;
6170ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
61856e3b29fSHelen Koike }
61956e3b29fSHelen Koike 
rkisp1_mp_enable(struct rkisp1_capture * cap)62056e3b29fSHelen Koike static void rkisp1_mp_enable(struct rkisp1_capture *cap)
62156e3b29fSHelen Koike {
62256e3b29fSHelen Koike 	u32 mi_ctrl;
62356e3b29fSHelen Koike 
62456e3b29fSHelen Koike 	rkisp1_mp_disable(cap);
62556e3b29fSHelen Koike 
62656e3b29fSHelen Koike 	mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
627b23096afSDafna Hirschfeld 	if (v4l2_is_format_bayer(cap->pix.info))
62856e3b29fSHelen Koike 		mi_ctrl |= RKISP1_CIF_MI_CTRL_RAW_ENABLE;
62956e3b29fSHelen Koike 	/* YUV */
63056e3b29fSHelen Koike 	else
63156e3b29fSHelen Koike 		mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE;
63256e3b29fSHelen Koike 
6330ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
63456e3b29fSHelen Koike }
63556e3b29fSHelen Koike 
rkisp1_sp_enable(struct rkisp1_capture * cap)63656e3b29fSHelen Koike static void rkisp1_sp_enable(struct rkisp1_capture *cap)
63756e3b29fSHelen Koike {
63856e3b29fSHelen Koike 	u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
63956e3b29fSHelen Koike 
64056e3b29fSHelen Koike 	mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE;
6410ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
64256e3b29fSHelen Koike }
64356e3b29fSHelen Koike 
rkisp1_mp_sp_stop(struct rkisp1_capture * cap)64456e3b29fSHelen Koike static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap)
64556e3b29fSHelen Koike {
64656e3b29fSHelen Koike 	if (!cap->is_streaming)
64756e3b29fSHelen Koike 		return;
6480ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_ICR, RKISP1_CIF_MI_FRAME(cap));
64956e3b29fSHelen Koike 	cap->ops->disable(cap);
65056e3b29fSHelen Koike }
65156e3b29fSHelen Koike 
rkisp1_mp_is_stopped(struct rkisp1_capture * cap)65256e3b29fSHelen Koike static bool rkisp1_mp_is_stopped(struct rkisp1_capture *cap)
65356e3b29fSHelen Koike {
65456e3b29fSHelen Koike 	u32 en = RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED |
65556e3b29fSHelen Koike 		 RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED;
65656e3b29fSHelen Koike 
65756e3b29fSHelen Koike 	return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & en);
65856e3b29fSHelen Koike }
65956e3b29fSHelen Koike 
rkisp1_sp_is_stopped(struct rkisp1_capture * cap)66056e3b29fSHelen Koike static bool rkisp1_sp_is_stopped(struct rkisp1_capture *cap)
66156e3b29fSHelen Koike {
66256e3b29fSHelen Koike 	return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) &
66356e3b29fSHelen Koike 		 RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED);
66456e3b29fSHelen Koike }
66556e3b29fSHelen Koike 
rkisp1_mp_set_data_path(struct rkisp1_capture * cap)66656e3b29fSHelen Koike static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap)
66756e3b29fSHelen Koike {
66856e3b29fSHelen Koike 	u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL);
66956e3b29fSHelen Koike 
67056e3b29fSHelen Koike 	dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP |
67156e3b29fSHelen Koike 	       RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI;
6720ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
67356e3b29fSHelen Koike }
67456e3b29fSHelen Koike 
rkisp1_sp_set_data_path(struct rkisp1_capture * cap)67556e3b29fSHelen Koike static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap)
67656e3b29fSHelen Koike {
67756e3b29fSHelen Koike 	u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL);
67856e3b29fSHelen Koike 
67956e3b29fSHelen Koike 	dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP;
6800ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
68156e3b29fSHelen Koike }
68256e3b29fSHelen Koike 
683a109073bSRikard Falkeborn static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = {
68456e3b29fSHelen Koike 	.config = rkisp1_mp_config,
68556e3b29fSHelen Koike 	.enable = rkisp1_mp_enable,
68656e3b29fSHelen Koike 	.disable = rkisp1_mp_disable,
68756e3b29fSHelen Koike 	.stop = rkisp1_mp_sp_stop,
68856e3b29fSHelen Koike 	.set_data_path = rkisp1_mp_set_data_path,
68956e3b29fSHelen Koike 	.is_stopped = rkisp1_mp_is_stopped,
69056e3b29fSHelen Koike };
69156e3b29fSHelen Koike 
692a109073bSRikard Falkeborn static const struct rkisp1_capture_ops rkisp1_capture_ops_sp = {
69356e3b29fSHelen Koike 	.config = rkisp1_sp_config,
69456e3b29fSHelen Koike 	.enable = rkisp1_sp_enable,
69556e3b29fSHelen Koike 	.disable = rkisp1_sp_disable,
69656e3b29fSHelen Koike 	.stop = rkisp1_mp_sp_stop,
69756e3b29fSHelen Koike 	.set_data_path = rkisp1_sp_set_data_path,
69856e3b29fSHelen Koike 	.is_stopped = rkisp1_sp_is_stopped,
69956e3b29fSHelen Koike };
70056e3b29fSHelen Koike 
70156e3b29fSHelen Koike /* ----------------------------------------------------------------------------
70256e3b29fSHelen Koike  * Frame buffer operations
70356e3b29fSHelen Koike  */
70456e3b29fSHelen Koike 
rkisp1_dummy_buf_create(struct rkisp1_capture * cap)70556e3b29fSHelen Koike static int rkisp1_dummy_buf_create(struct rkisp1_capture *cap)
70656e3b29fSHelen Koike {
70756e3b29fSHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
70856e3b29fSHelen Koike 	struct rkisp1_dummy_buffer *dummy_buf = &cap->buf.dummy;
70956e3b29fSHelen Koike 
71056e3b29fSHelen Koike 	dummy_buf->size = max3(rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y),
71156e3b29fSHelen Koike 			       rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB),
71256e3b29fSHelen Koike 			       rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
71356e3b29fSHelen Koike 
71456e3b29fSHelen Koike 	/* The driver never access vaddr, no mapping is required */
71556e3b29fSHelen Koike 	dummy_buf->vaddr = dma_alloc_attrs(cap->rkisp1->dev,
71656e3b29fSHelen Koike 					   dummy_buf->size,
71756e3b29fSHelen Koike 					   &dummy_buf->dma_addr,
71856e3b29fSHelen Koike 					   GFP_KERNEL,
71956e3b29fSHelen Koike 					   DMA_ATTR_NO_KERNEL_MAPPING);
72056e3b29fSHelen Koike 	if (!dummy_buf->vaddr)
72156e3b29fSHelen Koike 		return -ENOMEM;
72256e3b29fSHelen Koike 
72356e3b29fSHelen Koike 	return 0;
72456e3b29fSHelen Koike }
72556e3b29fSHelen Koike 
rkisp1_dummy_buf_destroy(struct rkisp1_capture * cap)72656e3b29fSHelen Koike static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap)
72756e3b29fSHelen Koike {
72856e3b29fSHelen Koike 	dma_free_attrs(cap->rkisp1->dev,
72956e3b29fSHelen Koike 		       cap->buf.dummy.size, cap->buf.dummy.vaddr,
73056e3b29fSHelen Koike 		       cap->buf.dummy.dma_addr, DMA_ATTR_NO_KERNEL_MAPPING);
73156e3b29fSHelen Koike }
73256e3b29fSHelen Koike 
rkisp1_set_next_buf(struct rkisp1_capture * cap)73356e3b29fSHelen Koike static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
73456e3b29fSHelen Koike {
735da1484c7SPaul Elder 	u8 shift = rkisp1_has_feature(cap->rkisp1, DMA_34BIT) ? 2 : 0;
736da1484c7SPaul Elder 
73723780e14SDafna Hirschfeld 	cap->buf.curr = cap->buf.next;
73823780e14SDafna Hirschfeld 	cap->buf.next = NULL;
73923780e14SDafna Hirschfeld 
74023780e14SDafna Hirschfeld 	if (!list_empty(&cap->buf.queue)) {
741da1484c7SPaul Elder 		dma_addr_t *buff_addr;
74223780e14SDafna Hirschfeld 
74323780e14SDafna Hirschfeld 		cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue);
74423780e14SDafna Hirschfeld 		list_del(&cap->buf.next->queue);
74523780e14SDafna Hirschfeld 
74623780e14SDafna Hirschfeld 		buff_addr = cap->buf.next->buff_addr;
74756e3b29fSHelen Koike 
7480ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
749da1484c7SPaul Elder 			     buff_addr[RKISP1_PLANE_Y] >> shift);
7509a0e3cd5SDafna Hirschfeld 		/*
7519a0e3cd5SDafna Hirschfeld 		 * In order to support grey format we capture
7529a0e3cd5SDafna Hirschfeld 		 * YUV422 planar format from the camera and
7539a0e3cd5SDafna Hirschfeld 		 * set the U and V planes to the dummy buffer
7549a0e3cd5SDafna Hirschfeld 		 */
7559a0e3cd5SDafna Hirschfeld 		if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) {
7569a0e3cd5SDafna Hirschfeld 			rkisp1_write(cap->rkisp1,
7570ef7dc30SLaurent Pinchart 				     cap->config->mi.cb_base_ad_init,
758da1484c7SPaul Elder 				     cap->buf.dummy.dma_addr >> shift);
7599a0e3cd5SDafna Hirschfeld 			rkisp1_write(cap->rkisp1,
7600ef7dc30SLaurent Pinchart 				     cap->config->mi.cr_base_ad_init,
761da1484c7SPaul Elder 				     cap->buf.dummy.dma_addr >> shift);
7629a0e3cd5SDafna Hirschfeld 		} else {
76356e3b29fSHelen Koike 			rkisp1_write(cap->rkisp1,
7640ef7dc30SLaurent Pinchart 				     cap->config->mi.cb_base_ad_init,
765da1484c7SPaul Elder 				     buff_addr[RKISP1_PLANE_CB] >> shift);
76656e3b29fSHelen Koike 			rkisp1_write(cap->rkisp1,
7670ef7dc30SLaurent Pinchart 				     cap->config->mi.cr_base_ad_init,
768da1484c7SPaul Elder 				     buff_addr[RKISP1_PLANE_CR] >> shift);
7699a0e3cd5SDafna Hirschfeld 		}
77056e3b29fSHelen Koike 	} else {
77123780e14SDafna Hirschfeld 		/*
77223780e14SDafna Hirschfeld 		 * Use the dummy space allocated by dma_alloc_coherent to
77323780e14SDafna Hirschfeld 		 * throw data if there is no available buffer.
77423780e14SDafna Hirschfeld 		 */
7750ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
776da1484c7SPaul Elder 			     cap->buf.dummy.dma_addr >> shift);
7770ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init,
778da1484c7SPaul Elder 			     cap->buf.dummy.dma_addr >> shift);
7790ef7dc30SLaurent Pinchart 		rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init,
780da1484c7SPaul Elder 			     cap->buf.dummy.dma_addr >> shift);
78156e3b29fSHelen Koike 	}
78256e3b29fSHelen Koike 
78356e3b29fSHelen Koike 	/* Set plane offsets */
7840ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.y_offs_cnt_init, 0);
7850ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.cb_offs_cnt_init, 0);
7860ef7dc30SLaurent Pinchart 	rkisp1_write(cap->rkisp1, cap->config->mi.cr_offs_cnt_init, 0);
78756e3b29fSHelen Koike }
78856e3b29fSHelen Koike 
78956e3b29fSHelen Koike /*
79056e3b29fSHelen Koike  * This function is called when a frame end comes. The next frame
79156e3b29fSHelen Koike  * is processing and we should set up buffer for next-next frame,
79256e3b29fSHelen Koike  * otherwise it will overflow.
79356e3b29fSHelen Koike  */
rkisp1_handle_buffer(struct rkisp1_capture * cap)79456e3b29fSHelen Koike static void rkisp1_handle_buffer(struct rkisp1_capture *cap)
79556e3b29fSHelen Koike {
79656e3b29fSHelen Koike 	struct rkisp1_isp *isp = &cap->rkisp1->isp;
797454748e3SDafna Hirschfeld 	struct rkisp1_buffer *curr_buf;
79856e3b29fSHelen Koike 
7991d509915SDafna Hirschfeld 	spin_lock(&cap->buf.lock);
800454748e3SDafna Hirschfeld 	curr_buf = cap->buf.curr;
80156e3b29fSHelen Koike 
80256e3b29fSHelen Koike 	if (curr_buf) {
80321f44172SDafna Hirschfeld 		curr_buf->vb.sequence = isp->frame_sequence;
80456e3b29fSHelen Koike 		curr_buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns();
80556e3b29fSHelen Koike 		curr_buf->vb.field = V4L2_FIELD_NONE;
80656e3b29fSHelen Koike 		vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
80756e3b29fSHelen Koike 	} else {
80856e3b29fSHelen Koike 		cap->rkisp1->debug.frame_drop[cap->id]++;
80956e3b29fSHelen Koike 	}
81056e3b29fSHelen Koike 
81156e3b29fSHelen Koike 	rkisp1_set_next_buf(cap);
8121d509915SDafna Hirschfeld 	spin_unlock(&cap->buf.lock);
81356e3b29fSHelen Koike }
81456e3b29fSHelen Koike 
rkisp1_capture_isr(int irq,void * ctx)81508818e6aSHeiko Stuebner irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
81656e3b29fSHelen Koike {
81708818e6aSHeiko Stuebner 	struct device *dev = ctx;
81808818e6aSHeiko Stuebner 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
81982754080SPaul Elder 	unsigned int dev_count = rkisp1_path_count(rkisp1);
82056e3b29fSHelen Koike 	unsigned int i;
82156e3b29fSHelen Koike 	u32 status;
82256e3b29fSHelen Koike 
823ffb635bbSTomi Valkeinen 	if (!rkisp1->irqs_enabled)
824ffb635bbSTomi Valkeinen 		return IRQ_NONE;
825ffb635bbSTomi Valkeinen 
82656e3b29fSHelen Koike 	status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS);
82708818e6aSHeiko Stuebner 	if (!status)
82808818e6aSHeiko Stuebner 		return IRQ_NONE;
82908818e6aSHeiko Stuebner 
8300ef7dc30SLaurent Pinchart 	rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status);
83156e3b29fSHelen Koike 
83282754080SPaul Elder 	for (i = 0; i < dev_count; ++i) {
83356e3b29fSHelen Koike 		struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
83456e3b29fSHelen Koike 
83556e3b29fSHelen Koike 		if (!(status & RKISP1_CIF_MI_FRAME(cap)))
83656e3b29fSHelen Koike 			continue;
83756e3b29fSHelen Koike 		if (!cap->is_stopping) {
83856e3b29fSHelen Koike 			rkisp1_handle_buffer(cap);
83956e3b29fSHelen Koike 			continue;
84056e3b29fSHelen Koike 		}
84156e3b29fSHelen Koike 		/*
84256e3b29fSHelen Koike 		 * Make sure stream is actually stopped, whose state
84356e3b29fSHelen Koike 		 * can be read from the shadow register, before
84456e3b29fSHelen Koike 		 * wake_up() thread which would immediately free all
84556e3b29fSHelen Koike 		 * frame buffers. stop() takes effect at the next
84656e3b29fSHelen Koike 		 * frame end that sync the configurations to shadow
84756e3b29fSHelen Koike 		 * regs.
84856e3b29fSHelen Koike 		 */
84956e3b29fSHelen Koike 		if (!cap->ops->is_stopped(cap)) {
85056e3b29fSHelen Koike 			cap->ops->stop(cap);
85156e3b29fSHelen Koike 			continue;
85256e3b29fSHelen Koike 		}
85356e3b29fSHelen Koike 		cap->is_stopping = false;
85456e3b29fSHelen Koike 		cap->is_streaming = false;
85556e3b29fSHelen Koike 		wake_up(&cap->done);
85656e3b29fSHelen Koike 	}
85708818e6aSHeiko Stuebner 
85808818e6aSHeiko Stuebner 	return IRQ_HANDLED;
85956e3b29fSHelen Koike }
86056e3b29fSHelen Koike 
86156e3b29fSHelen Koike /* ----------------------------------------------------------------------------
86256e3b29fSHelen Koike  * Vb2 operations
86356e3b29fSHelen Koike  */
86456e3b29fSHelen Koike 
rkisp1_vb2_queue_setup(struct vb2_queue * queue,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])86556e3b29fSHelen Koike static int rkisp1_vb2_queue_setup(struct vb2_queue *queue,
86656e3b29fSHelen Koike 				  unsigned int *num_buffers,
86756e3b29fSHelen Koike 				  unsigned int *num_planes,
86856e3b29fSHelen Koike 				  unsigned int sizes[],
86956e3b29fSHelen Koike 				  struct device *alloc_devs[])
87056e3b29fSHelen Koike {
87156e3b29fSHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
87256e3b29fSHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
87356e3b29fSHelen Koike 	unsigned int i;
87456e3b29fSHelen Koike 
87556e3b29fSHelen Koike 	if (*num_planes) {
87656e3b29fSHelen Koike 		if (*num_planes != pixm->num_planes)
87756e3b29fSHelen Koike 			return -EINVAL;
87856e3b29fSHelen Koike 
87956e3b29fSHelen Koike 		for (i = 0; i < pixm->num_planes; i++)
88056e3b29fSHelen Koike 			if (sizes[i] < pixm->plane_fmt[i].sizeimage)
88156e3b29fSHelen Koike 				return -EINVAL;
88256e3b29fSHelen Koike 	} else {
88356e3b29fSHelen Koike 		*num_planes = pixm->num_planes;
88456e3b29fSHelen Koike 		for (i = 0; i < pixm->num_planes; i++)
88556e3b29fSHelen Koike 			sizes[i] = pixm->plane_fmt[i].sizeimage;
88656e3b29fSHelen Koike 	}
88756e3b29fSHelen Koike 
88856e3b29fSHelen Koike 	return 0;
88956e3b29fSHelen Koike }
89056e3b29fSHelen Koike 
rkisp1_vb2_buf_init(struct vb2_buffer * vb)891f003d635SDafna Hirschfeld static int rkisp1_vb2_buf_init(struct vb2_buffer *vb)
89256e3b29fSHelen Koike {
89356e3b29fSHelen Koike 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
89456e3b29fSHelen Koike 	struct rkisp1_buffer *ispbuf =
89556e3b29fSHelen Koike 		container_of(vbuf, struct rkisp1_buffer, vb);
89656e3b29fSHelen Koike 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
89756e3b29fSHelen Koike 	const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt;
89856e3b29fSHelen Koike 	unsigned int i;
89956e3b29fSHelen Koike 
90056e3b29fSHelen Koike 	memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr));
90156e3b29fSHelen Koike 	for (i = 0; i < pixm->num_planes; i++)
90256e3b29fSHelen Koike 		ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
90356e3b29fSHelen Koike 
90456e3b29fSHelen Koike 	/* Convert to non-MPLANE */
90556e3b29fSHelen Koike 	if (pixm->num_planes == 1) {
90656e3b29fSHelen Koike 		ispbuf->buff_addr[RKISP1_PLANE_CB] =
90756e3b29fSHelen Koike 			ispbuf->buff_addr[RKISP1_PLANE_Y] +
90856e3b29fSHelen Koike 			rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y);
90956e3b29fSHelen Koike 		ispbuf->buff_addr[RKISP1_PLANE_CR] =
91056e3b29fSHelen Koike 			ispbuf->buff_addr[RKISP1_PLANE_CB] +
91156e3b29fSHelen Koike 			rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB);
91256e3b29fSHelen Koike 	}
91356e3b29fSHelen Koike 
914d0dd9278SDafna Hirschfeld 	/*
915d0dd9278SDafna Hirschfeld 	 * uv swap can be supported for planar formats by switching
916d0dd9278SDafna Hirschfeld 	 * the address of cb and cr
917d0dd9278SDafna Hirschfeld 	 */
918d0dd9278SDafna Hirschfeld 	if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap)
919d0dd9278SDafna Hirschfeld 		swap(ispbuf->buff_addr[RKISP1_PLANE_CR],
920d0dd9278SDafna Hirschfeld 		     ispbuf->buff_addr[RKISP1_PLANE_CB]);
921f003d635SDafna Hirschfeld 	return 0;
922f003d635SDafna Hirschfeld }
923f003d635SDafna Hirschfeld 
rkisp1_vb2_buf_queue(struct vb2_buffer * vb)924f003d635SDafna Hirschfeld static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb)
925f003d635SDafna Hirschfeld {
926f003d635SDafna Hirschfeld 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
927f003d635SDafna Hirschfeld 	struct rkisp1_buffer *ispbuf =
928f003d635SDafna Hirschfeld 		container_of(vbuf, struct rkisp1_buffer, vb);
929f003d635SDafna Hirschfeld 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
930d0dd9278SDafna Hirschfeld 
9311d509915SDafna Hirschfeld 	spin_lock_irq(&cap->buf.lock);
93256e3b29fSHelen Koike 	list_add_tail(&ispbuf->queue, &cap->buf.queue);
9331d509915SDafna Hirschfeld 	spin_unlock_irq(&cap->buf.lock);
93456e3b29fSHelen Koike }
93556e3b29fSHelen Koike 
rkisp1_vb2_buf_prepare(struct vb2_buffer * vb)93656e3b29fSHelen Koike static int rkisp1_vb2_buf_prepare(struct vb2_buffer *vb)
93756e3b29fSHelen Koike {
93856e3b29fSHelen Koike 	struct rkisp1_capture *cap = vb->vb2_queue->drv_priv;
93956e3b29fSHelen Koike 	unsigned int i;
94056e3b29fSHelen Koike 
94156e3b29fSHelen Koike 	for (i = 0; i < cap->pix.fmt.num_planes; i++) {
94256e3b29fSHelen Koike 		unsigned long size = cap->pix.fmt.plane_fmt[i].sizeimage;
94356e3b29fSHelen Koike 
94456e3b29fSHelen Koike 		if (vb2_plane_size(vb, i) < size) {
94556e3b29fSHelen Koike 			dev_err(cap->rkisp1->dev,
94656e3b29fSHelen Koike 				"User buffer too small (%ld < %ld)\n",
94756e3b29fSHelen Koike 				vb2_plane_size(vb, i), size);
94856e3b29fSHelen Koike 			return -EINVAL;
94956e3b29fSHelen Koike 		}
95056e3b29fSHelen Koike 		vb2_set_plane_payload(vb, i, size);
95156e3b29fSHelen Koike 	}
95256e3b29fSHelen Koike 
95356e3b29fSHelen Koike 	return 0;
95456e3b29fSHelen Koike }
95556e3b29fSHelen Koike 
rkisp1_return_all_buffers(struct rkisp1_capture * cap,enum vb2_buffer_state state)95656e3b29fSHelen Koike static void rkisp1_return_all_buffers(struct rkisp1_capture *cap,
95756e3b29fSHelen Koike 				      enum vb2_buffer_state state)
95856e3b29fSHelen Koike {
95956e3b29fSHelen Koike 	struct rkisp1_buffer *buf;
96056e3b29fSHelen Koike 
9611d509915SDafna Hirschfeld 	spin_lock_irq(&cap->buf.lock);
96256e3b29fSHelen Koike 	if (cap->buf.curr) {
96356e3b29fSHelen Koike 		vb2_buffer_done(&cap->buf.curr->vb.vb2_buf, state);
96456e3b29fSHelen Koike 		cap->buf.curr = NULL;
96556e3b29fSHelen Koike 	}
96656e3b29fSHelen Koike 	if (cap->buf.next) {
96756e3b29fSHelen Koike 		vb2_buffer_done(&cap->buf.next->vb.vb2_buf, state);
96856e3b29fSHelen Koike 		cap->buf.next = NULL;
96956e3b29fSHelen Koike 	}
97056e3b29fSHelen Koike 	while (!list_empty(&cap->buf.queue)) {
97156e3b29fSHelen Koike 		buf = list_first_entry(&cap->buf.queue,
97256e3b29fSHelen Koike 				       struct rkisp1_buffer, queue);
97356e3b29fSHelen Koike 		list_del(&buf->queue);
97456e3b29fSHelen Koike 		vb2_buffer_done(&buf->vb.vb2_buf, state);
97556e3b29fSHelen Koike 	}
9761d509915SDafna Hirschfeld 	spin_unlock_irq(&cap->buf.lock);
97756e3b29fSHelen Koike }
97856e3b29fSHelen Koike 
97956e3b29fSHelen Koike /*
98071c41518SSebastian Fricke  * Most registers inside the rockchip ISP1 have shadow register since
98171c41518SSebastian Fricke  * they must not be changed while processing a frame.
98256e3b29fSHelen Koike  * Usually, each sub-module updates its shadow register after
98356e3b29fSHelen Koike  * processing the last pixel of a frame.
98456e3b29fSHelen Koike  */
rkisp1_cap_stream_enable(struct rkisp1_capture * cap)985d51b5d9aSHelen Koike static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
98656e3b29fSHelen Koike {
98756e3b29fSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
98856e3b29fSHelen Koike 	struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1];
98982754080SPaul Elder 	bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH);
99056e3b29fSHelen Koike 
99156e3b29fSHelen Koike 	cap->ops->set_data_path(cap);
99256e3b29fSHelen Koike 	cap->ops->config(cap);
99356e3b29fSHelen Koike 
99456e3b29fSHelen Koike 	/* Setup a buffer for the next frame */
9957eba47abSDafna Hirschfeld 	spin_lock_irq(&cap->buf.lock);
99620698ed9SDafna Hirschfeld 	rkisp1_set_next_buf(cap);
99756e3b29fSHelen Koike 	cap->ops->enable(cap);
9986c144351SPaul Elder 
9996c144351SPaul Elder 	/*
10006c144351SPaul Elder 	 * It's safe to configure ACTIVE and SHADOW registers for the first
10016c144351SPaul Elder 	 * stream. While when the second is starting, do NOT force update
10026c144351SPaul Elder 	 * because it also updates the first one.
100356e3b29fSHelen Koike 	 *
10046c144351SPaul Elder 	 * The latter case would drop one more buffer(that is 2) since there's
10056c144351SPaul Elder 	 * no buffer in a shadow register when the second FE received. This's
10066c144351SPaul Elder 	 * also required because the second FE maybe corrupt especially when
10076c144351SPaul Elder 	 * run at 120fps.
100856e3b29fSHelen Koike 	 */
100982754080SPaul Elder 	if (!has_self_path || !other->is_streaming) {
10106c144351SPaul Elder 		u32 reg;
10116c144351SPaul Elder 
10126c144351SPaul Elder 		/*
10136c144351SPaul Elder 		 * Force cfg update.
10146c144351SPaul Elder 		 *
10156c144351SPaul Elder 		 * The ISP8000 (implementing the MAIN_STRIDE feature) as a
10166c144351SPaul Elder 		 * mp_output_format field in the CIF_MI_INIT register that must
10176c144351SPaul Elder 		 * be preserved. It can be read back, but it is not clear what
10186c144351SPaul Elder 		 * other register bits will return. Mask them out.
10196c144351SPaul Elder 		 *
10206c144351SPaul Elder 		 * On Rockchip platforms, the CIF_MI_INIT register is marked as
10216c144351SPaul Elder 		 * write-only and reads as zeros. We can skip reading it.
10226c144351SPaul Elder 		 */
10236c144351SPaul Elder 		if (rkisp1_has_feature(rkisp1, MAIN_STRIDE))
10246c144351SPaul Elder 			reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_INIT)
10256c144351SPaul Elder 			    & RKISP1_CIF_MI_INIT_MP_OUTPUT_MASK;
10266c144351SPaul Elder 		else
10276c144351SPaul Elder 			reg = 0;
10286c144351SPaul Elder 
10296c144351SPaul Elder 		reg |= RKISP1_CIF_MI_INIT_SOFT_UPD;
10306c144351SPaul Elder 		rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, reg);
10316c144351SPaul Elder 
103220698ed9SDafna Hirschfeld 		rkisp1_set_next_buf(cap);
103356e3b29fSHelen Koike 	}
10347eba47abSDafna Hirschfeld 	spin_unlock_irq(&cap->buf.lock);
103556e3b29fSHelen Koike 	cap->is_streaming = true;
103656e3b29fSHelen Koike }
103756e3b29fSHelen Koike 
rkisp1_cap_stream_disable(struct rkisp1_capture * cap)1038d51b5d9aSHelen Koike static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap)
1039d51b5d9aSHelen Koike {
1040d51b5d9aSHelen Koike 	int ret;
1041d51b5d9aSHelen Koike 
10426b94c09fSPeilin Ye 	/* Stream should stop in interrupt. If it doesn't, stop it by force. */
1043d51b5d9aSHelen Koike 	cap->is_stopping = true;
1044d51b5d9aSHelen Koike 	ret = wait_event_timeout(cap->done,
1045d51b5d9aSHelen Koike 				 !cap->is_streaming,
1046d51b5d9aSHelen Koike 				 msecs_to_jiffies(1000));
1047d51b5d9aSHelen Koike 	if (!ret) {
1048d51b5d9aSHelen Koike 		cap->rkisp1->debug.stop_timeout[cap->id]++;
1049d51b5d9aSHelen Koike 		cap->ops->stop(cap);
1050d51b5d9aSHelen Koike 		cap->is_stopping = false;
1051d51b5d9aSHelen Koike 		cap->is_streaming = false;
1052d51b5d9aSHelen Koike 	}
1053d51b5d9aSHelen Koike }
1054d51b5d9aSHelen Koike 
1055d51b5d9aSHelen Koike /*
1056d51b5d9aSHelen Koike  * rkisp1_pipeline_stream_disable - disable nodes in the pipeline
1057d51b5d9aSHelen Koike  *
1058d51b5d9aSHelen Koike  * Call s_stream(false) in the reverse order from
1059d51b5d9aSHelen Koike  * rkisp1_pipeline_stream_enable() and disable the DMA engine.
106012cecbf9STomi Valkeinen  * Should be called before video_device_pipeline_stop()
1061d51b5d9aSHelen Koike  */
rkisp1_pipeline_stream_disable(struct rkisp1_capture * cap)1062d51b5d9aSHelen Koike static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap)
1063d51b5d9aSHelen Koike 	__must_hold(&cap->rkisp1->stream_lock)
1064d51b5d9aSHelen Koike {
1065d51b5d9aSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
1066d51b5d9aSHelen Koike 
10679d28a76dSHelen Koike 	rkisp1_cap_stream_disable(cap);
10689d28a76dSHelen Koike 
1069d51b5d9aSHelen Koike 	/*
1070d51b5d9aSHelen Koike 	 * If the other capture is streaming, isp and sensor nodes shouldn't
1071d51b5d9aSHelen Koike 	 * be disabled, skip them.
1072d51b5d9aSHelen Koike 	 */
1073b7319e2bSTomi Valkeinen 	if (rkisp1->pipe.start_count < 2)
1074d51b5d9aSHelen Koike 		v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false);
1075d51b5d9aSHelen Koike 
1076d51b5d9aSHelen Koike 	v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
1077d51b5d9aSHelen Koike 			 false);
1078d51b5d9aSHelen Koike }
1079d51b5d9aSHelen Koike 
1080d51b5d9aSHelen Koike /*
1081d51b5d9aSHelen Koike  * rkisp1_pipeline_stream_enable - enable nodes in the pipeline
1082d51b5d9aSHelen Koike  *
1083d51b5d9aSHelen Koike  * Enable the DMA Engine and call s_stream(true) through the pipeline.
108412cecbf9STomi Valkeinen  * Should be called after video_device_pipeline_start()
1085d51b5d9aSHelen Koike  */
rkisp1_pipeline_stream_enable(struct rkisp1_capture * cap)1086d51b5d9aSHelen Koike static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap)
1087d51b5d9aSHelen Koike 	__must_hold(&cap->rkisp1->stream_lock)
1088d51b5d9aSHelen Koike {
1089d51b5d9aSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
1090d51b5d9aSHelen Koike 	int ret;
1091d51b5d9aSHelen Koike 
1092d51b5d9aSHelen Koike 	rkisp1_cap_stream_enable(cap);
1093d51b5d9aSHelen Koike 
1094d51b5d9aSHelen Koike 	ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video,
1095d51b5d9aSHelen Koike 			       s_stream, true);
1096d51b5d9aSHelen Koike 	if (ret)
1097d51b5d9aSHelen Koike 		goto err_disable_cap;
1098d51b5d9aSHelen Koike 
1099d51b5d9aSHelen Koike 	/*
1100d51b5d9aSHelen Koike 	 * If the other capture is streaming, isp and sensor nodes are already
1101d51b5d9aSHelen Koike 	 * enabled, skip them.
1102d51b5d9aSHelen Koike 	 */
1103b7319e2bSTomi Valkeinen 	if (rkisp1->pipe.start_count > 1)
1104d51b5d9aSHelen Koike 		return 0;
1105d51b5d9aSHelen Koike 
1106d51b5d9aSHelen Koike 	ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true);
1107d51b5d9aSHelen Koike 	if (ret)
1108d51b5d9aSHelen Koike 		goto err_disable_rsz;
1109d51b5d9aSHelen Koike 
1110d51b5d9aSHelen Koike 	return 0;
1111d51b5d9aSHelen Koike 
1112d51b5d9aSHelen Koike err_disable_rsz:
1113d51b5d9aSHelen Koike 	v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
1114d51b5d9aSHelen Koike 			 false);
1115d51b5d9aSHelen Koike err_disable_cap:
1116d51b5d9aSHelen Koike 	rkisp1_cap_stream_disable(cap);
1117d51b5d9aSHelen Koike 
1118d51b5d9aSHelen Koike 	return ret;
1119d51b5d9aSHelen Koike }
1120d51b5d9aSHelen Koike 
rkisp1_vb2_stop_streaming(struct vb2_queue * queue)1121d51b5d9aSHelen Koike static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue)
1122d51b5d9aSHelen Koike {
1123d51b5d9aSHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
1124d51b5d9aSHelen Koike 	struct rkisp1_vdev_node *node = &cap->vnode;
1125d51b5d9aSHelen Koike 	struct rkisp1_device *rkisp1 = cap->rkisp1;
1126d51b5d9aSHelen Koike 	int ret;
1127d51b5d9aSHelen Koike 
1128d51b5d9aSHelen Koike 	mutex_lock(&cap->rkisp1->stream_lock);
1129d51b5d9aSHelen Koike 
1130d51b5d9aSHelen Koike 	rkisp1_pipeline_stream_disable(cap);
1131d51b5d9aSHelen Koike 
1132d51b5d9aSHelen Koike 	rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR);
1133d51b5d9aSHelen Koike 
1134d51b5d9aSHelen Koike 	v4l2_pipeline_pm_put(&node->vdev.entity);
1135d51b5d9aSHelen Koike 	ret = pm_runtime_put(rkisp1->dev);
1136d51b5d9aSHelen Koike 	if (ret < 0)
1137d51b5d9aSHelen Koike 		dev_err(rkisp1->dev, "power down failed error:%d\n", ret);
1138d51b5d9aSHelen Koike 
1139d51b5d9aSHelen Koike 	rkisp1_dummy_buf_destroy(cap);
1140d51b5d9aSHelen Koike 
114112cecbf9STomi Valkeinen 	video_device_pipeline_stop(&node->vdev);
1142d51b5d9aSHelen Koike 
1143d51b5d9aSHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
1144d51b5d9aSHelen Koike }
1145d51b5d9aSHelen Koike 
114656e3b29fSHelen Koike static int
rkisp1_vb2_start_streaming(struct vb2_queue * queue,unsigned int count)114756e3b29fSHelen Koike rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
114856e3b29fSHelen Koike {
114956e3b29fSHelen Koike 	struct rkisp1_capture *cap = queue->drv_priv;
115056e3b29fSHelen Koike 	struct media_entity *entity = &cap->vnode.vdev.entity;
115156e3b29fSHelen Koike 	int ret;
115256e3b29fSHelen Koike 
1153e4b0326cSHelen Koike 	mutex_lock(&cap->rkisp1->stream_lock);
1154e4b0326cSHelen Koike 
115512cecbf9STomi Valkeinen 	ret = video_device_pipeline_start(&cap->vnode.vdev, &cap->rkisp1->pipe);
115635d1a7bbSDafna Hirschfeld 	if (ret) {
115735d1a7bbSDafna Hirschfeld 		dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret);
115835d1a7bbSDafna Hirschfeld 		goto err_ret_buffers;
115935d1a7bbSDafna Hirschfeld 	}
116035d1a7bbSDafna Hirschfeld 
116156e3b29fSHelen Koike 	ret = rkisp1_dummy_buf_create(cap);
116256e3b29fSHelen Koike 	if (ret)
116335d1a7bbSDafna Hirschfeld 		goto err_pipeline_stop;
116456e3b29fSHelen Koike 
11658102cf89SMauro Carvalho Chehab 	ret = pm_runtime_resume_and_get(cap->rkisp1->dev);
116660e91535SHelen Koike 	if (ret < 0) {
116756e3b29fSHelen Koike 		dev_err(cap->rkisp1->dev, "power up failed %d\n", ret);
116856e3b29fSHelen Koike 		goto err_destroy_dummy;
116956e3b29fSHelen Koike 	}
11708fd390b8SEzequiel Garcia 	ret = v4l2_pipeline_pm_get(entity);
117156e3b29fSHelen Koike 	if (ret) {
117256e3b29fSHelen Koike 		dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret);
117356e3b29fSHelen Koike 		goto err_pipe_pm_put;
117456e3b29fSHelen Koike 	}
117556e3b29fSHelen Koike 
1176d51b5d9aSHelen Koike 	ret = rkisp1_pipeline_stream_enable(cap);
117756e3b29fSHelen Koike 	if (ret)
1178d51b5d9aSHelen Koike 		goto err_v4l2_pm_put;
117956e3b29fSHelen Koike 
1180e4b0326cSHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
1181e4b0326cSHelen Koike 
118256e3b29fSHelen Koike 	return 0;
118356e3b29fSHelen Koike 
1184d51b5d9aSHelen Koike err_v4l2_pm_put:
11858fd390b8SEzequiel Garcia 	v4l2_pipeline_pm_put(entity);
118656e3b29fSHelen Koike err_pipe_pm_put:
118756e3b29fSHelen Koike 	pm_runtime_put(cap->rkisp1->dev);
118856e3b29fSHelen Koike err_destroy_dummy:
118956e3b29fSHelen Koike 	rkisp1_dummy_buf_destroy(cap);
119035d1a7bbSDafna Hirschfeld err_pipeline_stop:
119112cecbf9STomi Valkeinen 	video_device_pipeline_stop(&cap->vnode.vdev);
119256e3b29fSHelen Koike err_ret_buffers:
119356e3b29fSHelen Koike 	rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED);
1194e4b0326cSHelen Koike 	mutex_unlock(&cap->rkisp1->stream_lock);
119556e3b29fSHelen Koike 
119656e3b29fSHelen Koike 	return ret;
119756e3b29fSHelen Koike }
119856e3b29fSHelen Koike 
1199a109073bSRikard Falkeborn static const struct vb2_ops rkisp1_vb2_ops = {
120056e3b29fSHelen Koike 	.queue_setup = rkisp1_vb2_queue_setup,
1201f003d635SDafna Hirschfeld 	.buf_init = rkisp1_vb2_buf_init,
120256e3b29fSHelen Koike 	.buf_queue = rkisp1_vb2_buf_queue,
120356e3b29fSHelen Koike 	.buf_prepare = rkisp1_vb2_buf_prepare,
120456e3b29fSHelen Koike 	.stop_streaming = rkisp1_vb2_stop_streaming,
120556e3b29fSHelen Koike 	.start_streaming = rkisp1_vb2_start_streaming,
120656e3b29fSHelen Koike };
120756e3b29fSHelen Koike 
120856e3b29fSHelen Koike /* ----------------------------------------------------------------------------
120956e3b29fSHelen Koike  * IOCTLs operations
121056e3b29fSHelen Koike  */
121156e3b29fSHelen Koike 
121256e3b29fSHelen Koike static const struct v4l2_format_info *
rkisp1_fill_pixfmt(const struct rkisp1_capture * cap,struct v4l2_pix_format_mplane * pixm)1213bcb40cc1SPaul Elder rkisp1_fill_pixfmt(const struct rkisp1_capture *cap,
1214bcb40cc1SPaul Elder 		   struct v4l2_pix_format_mplane *pixm)
121556e3b29fSHelen Koike {
121656e3b29fSHelen Koike 	struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0];
121756e3b29fSHelen Koike 	const struct v4l2_format_info *info;
121856e3b29fSHelen Koike 	unsigned int i;
121956e3b29fSHelen Koike 	u32 stride;
122056e3b29fSHelen Koike 
12210ec314ffSDafna Hirschfeld 	memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt));
122256e3b29fSHelen Koike 	info = v4l2_format_info(pixm->pixelformat);
122356e3b29fSHelen Koike 	pixm->num_planes = info->mem_planes;
122456e3b29fSHelen Koike 
12255964c90aSLaurent Pinchart 	/*
12265964c90aSLaurent Pinchart 	 * The SP supports custom strides, expressed as a number of pixels for
1227bcb40cc1SPaul Elder 	 * the Y plane, and so does the MP in ISP versions that have the
1228bcb40cc1SPaul Elder 	 * MAIN_STRIDE feature. Clamp the stride to a reasonable value to avoid
1229bcb40cc1SPaul Elder 	 * integer overflows when calculating the bytesperline and sizeimage
1230bcb40cc1SPaul Elder 	 * values.
12315964c90aSLaurent Pinchart 	 */
1232bcb40cc1SPaul Elder 	if (cap->id == RKISP1_SELFPATH ||
1233bcb40cc1SPaul Elder 	    rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE))
12345964c90aSLaurent Pinchart 		stride = clamp(DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]),
12355964c90aSLaurent Pinchart 			       pixm->width, 65536U);
12365964c90aSLaurent Pinchart 	else
12375964c90aSLaurent Pinchart 		stride = pixm->width;
12385964c90aSLaurent Pinchart 
12395964c90aSLaurent Pinchart 	plane_y->bytesperline = stride * info->bpp[0];
12405964c90aSLaurent Pinchart 	plane_y->sizeimage = plane_y->bytesperline * pixm->height;
124156e3b29fSHelen Koike 
124256e3b29fSHelen Koike 	for (i = 1; i < info->comp_planes; i++) {
124356e3b29fSHelen Koike 		struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i];
124456e3b29fSHelen Koike 
124556e3b29fSHelen Koike 		/* bytesperline for other components derive from Y component */
124656e3b29fSHelen Koike 		plane->bytesperline = DIV_ROUND_UP(stride, info->hdiv) *
124756e3b29fSHelen Koike 				      info->bpp[i];
124856e3b29fSHelen Koike 		plane->sizeimage = plane->bytesperline *
124956e3b29fSHelen Koike 				   DIV_ROUND_UP(pixm->height, info->vdiv);
125056e3b29fSHelen Koike 	}
125156e3b29fSHelen Koike 
125256e3b29fSHelen Koike 	/*
125356e3b29fSHelen Koike 	 * If pixfmt is packed, then plane_fmt[0] should contain the total size
125456e3b29fSHelen Koike 	 * considering all components. plane_fmt[i] for i > 0 should be ignored
125556e3b29fSHelen Koike 	 * by userspace as mem_planes == 1, but we are keeping information there
125656e3b29fSHelen Koike 	 * for convenience.
125756e3b29fSHelen Koike 	 */
125856e3b29fSHelen Koike 	if (info->mem_planes == 1)
125956e3b29fSHelen Koike 		for (i = 1; i < info->comp_planes; i++)
126056e3b29fSHelen Koike 			plane_y->sizeimage += pixm->plane_fmt[i].sizeimage;
126156e3b29fSHelen Koike 
126256e3b29fSHelen Koike 	return info;
126356e3b29fSHelen Koike }
126456e3b29fSHelen Koike 
126556e3b29fSHelen Koike static const struct rkisp1_capture_fmt_cfg *
rkisp1_find_fmt_cfg(const struct rkisp1_capture * cap,const u32 pixelfmt)126656e3b29fSHelen Koike rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt)
126756e3b29fSHelen Koike {
1268fd62bd4eSPaul Elder 	bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE);
126956e3b29fSHelen Koike 	unsigned int i;
127056e3b29fSHelen Koike 
127156e3b29fSHelen Koike 	for (i = 0; i < cap->config->fmt_size; i++) {
1272fd62bd4eSPaul Elder 		const struct rkisp1_capture_fmt_cfg *fmt = &cap->config->fmts[i];
1273fd62bd4eSPaul Elder 
1274fd62bd4eSPaul Elder 		if (fmt->fourcc == pixelfmt &&
1275fd62bd4eSPaul Elder 		    (!fmt->yc_swap || yc_swap_support))
127656e3b29fSHelen Koike 			return &cap->config->fmts[i];
127756e3b29fSHelen Koike 	}
127856e3b29fSHelen Koike 	return NULL;
127956e3b29fSHelen Koike }
128056e3b29fSHelen 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)128156e3b29fSHelen Koike static void rkisp1_try_fmt(const struct rkisp1_capture *cap,
128256e3b29fSHelen Koike 			   struct v4l2_pix_format_mplane *pixm,
128356e3b29fSHelen Koike 			   const struct rkisp1_capture_fmt_cfg **fmt_cfg,
128456e3b29fSHelen Koike 			   const struct v4l2_format_info **fmt_info)
128556e3b29fSHelen Koike {
128656e3b29fSHelen Koike 	const struct rkisp1_capture_config *config = cap->config;
128756e3b29fSHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmt;
128856e3b29fSHelen Koike 	const struct v4l2_format_info *info;
12894ee8191cSColin Ian King 	static const unsigned int max_widths[] = {
12904ee8191cSColin Ian King 		RKISP1_RSZ_MP_SRC_MAX_WIDTH, RKISP1_RSZ_SP_SRC_MAX_WIDTH
12914ee8191cSColin Ian King 	};
12924ee8191cSColin Ian King 	static const unsigned int max_heights[] = {
12934ee8191cSColin Ian King 		RKISP1_RSZ_MP_SRC_MAX_HEIGHT, RKISP1_RSZ_SP_SRC_MAX_HEIGHT
12944ee8191cSColin Ian King 	};
129556e3b29fSHelen Koike 
129656e3b29fSHelen Koike 	fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat);
129756e3b29fSHelen Koike 	if (!fmt) {
129856e3b29fSHelen Koike 		fmt = config->fmts;
129956e3b29fSHelen Koike 		pixm->pixelformat = fmt->fourcc;
130056e3b29fSHelen Koike 	}
130156e3b29fSHelen Koike 
130256e3b29fSHelen Koike 	pixm->width = clamp_t(u32, pixm->width,
130356e3b29fSHelen Koike 			      RKISP1_RSZ_SRC_MIN_WIDTH, max_widths[cap->id]);
130456e3b29fSHelen Koike 	pixm->height = clamp_t(u32, pixm->height,
130556e3b29fSHelen Koike 			       RKISP1_RSZ_SRC_MIN_HEIGHT, max_heights[cap->id]);
130656e3b29fSHelen Koike 
130756e3b29fSHelen Koike 	pixm->field = V4L2_FIELD_NONE;
130856e3b29fSHelen Koike 	pixm->colorspace = V4L2_COLORSPACE_DEFAULT;
130956e3b29fSHelen Koike 	pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
1310f4aefc58SDafna Hirschfeld 	pixm->quantization = V4L2_QUANTIZATION_DEFAULT;
131156e3b29fSHelen Koike 
1312bcb40cc1SPaul Elder 	info = rkisp1_fill_pixfmt(cap, pixm);
131356e3b29fSHelen Koike 
131456e3b29fSHelen Koike 	if (fmt_cfg)
131556e3b29fSHelen Koike 		*fmt_cfg = fmt;
131656e3b29fSHelen Koike 	if (fmt_info)
131756e3b29fSHelen Koike 		*fmt_info = info;
131856e3b29fSHelen Koike }
131956e3b29fSHelen Koike 
rkisp1_set_fmt(struct rkisp1_capture * cap,struct v4l2_pix_format_mplane * pixm)132056e3b29fSHelen Koike static void rkisp1_set_fmt(struct rkisp1_capture *cap,
132156e3b29fSHelen Koike 			   struct v4l2_pix_format_mplane *pixm)
132256e3b29fSHelen Koike {
132356e3b29fSHelen Koike 	rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info);
132456e3b29fSHelen Koike 
1325bcb40cc1SPaul Elder 	cap->pix.fmt = *pixm;
1326bcb40cc1SPaul Elder 	cap->stride = pixm->plane_fmt[0].bytesperline / cap->pix.info->bpp[0];
132756e3b29fSHelen Koike }
132856e3b29fSHelen Koike 
rkisp1_try_fmt_vid_cap_mplane(struct file * file,void * fh,struct v4l2_format * f)132956e3b29fSHelen Koike static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh,
133056e3b29fSHelen Koike 					 struct v4l2_format *f)
133156e3b29fSHelen Koike {
133256e3b29fSHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
133356e3b29fSHelen Koike 
133456e3b29fSHelen Koike 	rkisp1_try_fmt(cap, &f->fmt.pix_mp, NULL, NULL);
133556e3b29fSHelen Koike 
133656e3b29fSHelen Koike 	return 0;
133756e3b29fSHelen Koike }
133856e3b29fSHelen Koike 
rkisp1_enum_fmt_vid_cap_mplane(struct file * file,void * priv,struct v4l2_fmtdesc * f)133956e3b29fSHelen Koike static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
134056e3b29fSHelen Koike 					  struct v4l2_fmtdesc *f)
134156e3b29fSHelen Koike {
134256e3b29fSHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
134356e3b29fSHelen Koike 	const struct rkisp1_capture_fmt_cfg *fmt = NULL;
1344fd62bd4eSPaul Elder 	bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE);
13455fc929aeSDafna Hirschfeld 	unsigned int i, n = 0;
134656e3b29fSHelen Koike 
134756e3b29fSHelen Koike 	if (f->index >= cap->config->fmt_size)
134856e3b29fSHelen Koike 		return -EINVAL;
134956e3b29fSHelen Koike 
1350fd62bd4eSPaul Elder 	if (!f->mbus_code && yc_swap_support) {
135156e3b29fSHelen Koike 		fmt = &cap->config->fmts[f->index];
135256e3b29fSHelen Koike 		f->pixelformat = fmt->fourcc;
135356e3b29fSHelen Koike 		return 0;
135456e3b29fSHelen Koike 	}
135556e3b29fSHelen Koike 
13565fc929aeSDafna Hirschfeld 	for (i = 0; i < cap->config->fmt_size; i++) {
1357fd62bd4eSPaul Elder 		fmt = &cap->config->fmts[i];
1358fd62bd4eSPaul Elder 
1359fd62bd4eSPaul Elder 		if (f->mbus_code && fmt->mbus != f->mbus_code)
1360fd62bd4eSPaul Elder 			continue;
1361fd62bd4eSPaul Elder 
1362fd62bd4eSPaul Elder 		if (!yc_swap_support && fmt->yc_swap)
13635fc929aeSDafna Hirschfeld 			continue;
13645fc929aeSDafna Hirschfeld 
13655fc929aeSDafna Hirschfeld 		if (n++ == f->index) {
1366fd62bd4eSPaul Elder 			f->pixelformat = fmt->fourcc;
13675fc929aeSDafna Hirschfeld 			return 0;
13685fc929aeSDafna Hirschfeld 		}
13695fc929aeSDafna Hirschfeld 	}
13705fc929aeSDafna Hirschfeld 	return -EINVAL;
13715fc929aeSDafna Hirschfeld }
13725fc929aeSDafna Hirschfeld 
rkisp1_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)13737cfb35d3SPaul Elder static int rkisp1_enum_framesizes(struct file *file, void *fh,
13747cfb35d3SPaul Elder 				  struct v4l2_frmsizeenum *fsize)
13757cfb35d3SPaul Elder {
13767cfb35d3SPaul Elder 	static const unsigned int max_widths[] = {
13777cfb35d3SPaul Elder 		RKISP1_RSZ_MP_SRC_MAX_WIDTH,
13787cfb35d3SPaul Elder 		RKISP1_RSZ_SP_SRC_MAX_WIDTH,
13797cfb35d3SPaul Elder 	};
13807cfb35d3SPaul Elder 	static const unsigned int max_heights[] = {
13817cfb35d3SPaul Elder 		RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
13827cfb35d3SPaul Elder 		RKISP1_RSZ_SP_SRC_MAX_HEIGHT,
13837cfb35d3SPaul Elder 	};
13847cfb35d3SPaul Elder 	struct rkisp1_capture *cap = video_drvdata(file);
13857cfb35d3SPaul Elder 
13867cfb35d3SPaul Elder 	if (fsize->index != 0)
13877cfb35d3SPaul Elder 		return -EINVAL;
13887cfb35d3SPaul Elder 
13897cfb35d3SPaul Elder 	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
13907cfb35d3SPaul Elder 
13917cfb35d3SPaul Elder 	fsize->stepwise.min_width = RKISP1_RSZ_SRC_MIN_WIDTH;
13927cfb35d3SPaul Elder 	fsize->stepwise.max_width = max_widths[cap->id];
13937cfb35d3SPaul Elder 	fsize->stepwise.step_width = 2;
13947cfb35d3SPaul Elder 
13957cfb35d3SPaul Elder 	fsize->stepwise.min_height = RKISP1_RSZ_SRC_MIN_HEIGHT;
13967cfb35d3SPaul Elder 	fsize->stepwise.max_height = max_heights[cap->id];
13977cfb35d3SPaul Elder 	fsize->stepwise.step_height = 2;
13987cfb35d3SPaul Elder 
13997cfb35d3SPaul Elder 	return 0;
14007cfb35d3SPaul Elder }
14017cfb35d3SPaul Elder 
rkisp1_s_fmt_vid_cap_mplane(struct file * file,void * priv,struct v4l2_format * f)140256e3b29fSHelen Koike static int rkisp1_s_fmt_vid_cap_mplane(struct file *file,
140356e3b29fSHelen Koike 				       void *priv, struct v4l2_format *f)
140456e3b29fSHelen Koike {
140556e3b29fSHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
140656e3b29fSHelen Koike 	struct rkisp1_vdev_node *node =
140756e3b29fSHelen Koike 				rkisp1_vdev_to_node(&cap->vnode.vdev);
140856e3b29fSHelen Koike 
140956e3b29fSHelen Koike 	if (vb2_is_busy(&node->buf_queue))
141056e3b29fSHelen Koike 		return -EBUSY;
141156e3b29fSHelen Koike 
141256e3b29fSHelen Koike 	rkisp1_set_fmt(cap, &f->fmt.pix_mp);
141356e3b29fSHelen Koike 
141456e3b29fSHelen Koike 	return 0;
141556e3b29fSHelen Koike }
141656e3b29fSHelen Koike 
rkisp1_g_fmt_vid_cap_mplane(struct file * file,void * fh,struct v4l2_format * f)141756e3b29fSHelen Koike static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh,
141856e3b29fSHelen Koike 				       struct v4l2_format *f)
141956e3b29fSHelen Koike {
142056e3b29fSHelen Koike 	struct rkisp1_capture *cap = video_drvdata(file);
142156e3b29fSHelen Koike 
142256e3b29fSHelen Koike 	f->fmt.pix_mp = cap->pix.fmt;
142356e3b29fSHelen Koike 
142456e3b29fSHelen Koike 	return 0;
142556e3b29fSHelen Koike }
142656e3b29fSHelen Koike 
142756e3b29fSHelen Koike static int
rkisp1_querycap(struct file * file,void * priv,struct v4l2_capability * cap)142856e3b29fSHelen Koike rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
142956e3b29fSHelen Koike {
14303d91b856SPaul Elder 	strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver));
14313d91b856SPaul Elder 	strscpy(cap->card, RKISP1_DRIVER_NAME, sizeof(cap->card));
143256e3b29fSHelen Koike 	strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info));
143356e3b29fSHelen Koike 
143456e3b29fSHelen Koike 	return 0;
143556e3b29fSHelen Koike }
143656e3b29fSHelen Koike 
143756e3b29fSHelen Koike static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = {
143856e3b29fSHelen Koike 	.vidioc_reqbufs = vb2_ioctl_reqbufs,
143956e3b29fSHelen Koike 	.vidioc_querybuf = vb2_ioctl_querybuf,
144056e3b29fSHelen Koike 	.vidioc_create_bufs = vb2_ioctl_create_bufs,
144156e3b29fSHelen Koike 	.vidioc_qbuf = vb2_ioctl_qbuf,
144256e3b29fSHelen Koike 	.vidioc_expbuf = vb2_ioctl_expbuf,
144356e3b29fSHelen Koike 	.vidioc_dqbuf = vb2_ioctl_dqbuf,
144456e3b29fSHelen Koike 	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
144556e3b29fSHelen Koike 	.vidioc_streamon = vb2_ioctl_streamon,
144656e3b29fSHelen Koike 	.vidioc_streamoff = vb2_ioctl_streamoff,
144756e3b29fSHelen Koike 	.vidioc_try_fmt_vid_cap_mplane = rkisp1_try_fmt_vid_cap_mplane,
144856e3b29fSHelen Koike 	.vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane,
144956e3b29fSHelen Koike 	.vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane,
145056e3b29fSHelen Koike 	.vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane,
14517cfb35d3SPaul Elder 	.vidioc_enum_framesizes = rkisp1_enum_framesizes,
145256e3b29fSHelen Koike 	.vidioc_querycap = rkisp1_querycap,
145356e3b29fSHelen Koike 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
145456e3b29fSHelen Koike 	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
145556e3b29fSHelen Koike };
145656e3b29fSHelen Koike 
rkisp1_capture_link_validate(struct media_link * link)145756e3b29fSHelen Koike static int rkisp1_capture_link_validate(struct media_link *link)
145856e3b29fSHelen Koike {
145956e3b29fSHelen Koike 	struct video_device *vdev =
146056e3b29fSHelen Koike 		media_entity_to_video_device(link->sink->entity);
146156e3b29fSHelen Koike 	struct v4l2_subdev *sd =
146256e3b29fSHelen Koike 		media_entity_to_v4l2_subdev(link->source->entity);
146356e3b29fSHelen Koike 	struct rkisp1_capture *cap = video_get_drvdata(vdev);
14646803a9e0SDafna Hirschfeld 	const struct rkisp1_capture_fmt_cfg *fmt =
14656803a9e0SDafna Hirschfeld 		rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat);
1466c53e3a04SLaurent Pinchart 	struct v4l2_subdev_format sd_fmt = {
1467c53e3a04SLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
1468c53e3a04SLaurent Pinchart 		.pad = link->source->index,
1469c53e3a04SLaurent Pinchart 	};
147056e3b29fSHelen Koike 	int ret;
147156e3b29fSHelen Koike 
147256e3b29fSHelen Koike 	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
147356e3b29fSHelen Koike 	if (ret)
147456e3b29fSHelen Koike 		return ret;
147556e3b29fSHelen Koike 
147656e3b29fSHelen Koike 	if (sd_fmt.format.height != cap->pix.fmt.height ||
14776803a9e0SDafna Hirschfeld 	    sd_fmt.format.width != cap->pix.fmt.width ||
1478fc890f00SLaurent Pinchart 	    sd_fmt.format.code != fmt->mbus) {
1479fc890f00SLaurent Pinchart 		dev_dbg(cap->rkisp1->dev,
1480fc890f00SLaurent Pinchart 			"link '%s':%u -> '%s':%u not valid: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
1481fc890f00SLaurent Pinchart 			link->source->entity->name, link->source->index,
1482fc890f00SLaurent Pinchart 			link->sink->entity->name, link->sink->index,
1483fc890f00SLaurent Pinchart 			sd_fmt.format.code, sd_fmt.format.width,
1484fc890f00SLaurent Pinchart 			sd_fmt.format.height, fmt->mbus, cap->pix.fmt.width,
1485fc890f00SLaurent Pinchart 			cap->pix.fmt.height);
148656e3b29fSHelen Koike 		return -EPIPE;
1487fc890f00SLaurent Pinchart 	}
148856e3b29fSHelen Koike 
148956e3b29fSHelen Koike 	return 0;
149056e3b29fSHelen Koike }
149156e3b29fSHelen Koike 
149256e3b29fSHelen Koike /* ----------------------------------------------------------------------------
149356e3b29fSHelen Koike  * core functions
149456e3b29fSHelen Koike  */
149556e3b29fSHelen Koike 
149656e3b29fSHelen Koike static const struct media_entity_operations rkisp1_media_ops = {
149756e3b29fSHelen Koike 	.link_validate = rkisp1_capture_link_validate,
149856e3b29fSHelen Koike };
149956e3b29fSHelen Koike 
150056e3b29fSHelen Koike static const struct v4l2_file_operations rkisp1_fops = {
150156e3b29fSHelen Koike 	.open = v4l2_fh_open,
150256e3b29fSHelen Koike 	.release = vb2_fop_release,
150356e3b29fSHelen Koike 	.unlocked_ioctl = video_ioctl2,
150456e3b29fSHelen Koike 	.poll = vb2_fop_poll,
150556e3b29fSHelen Koike 	.mmap = vb2_fop_mmap,
150656e3b29fSHelen Koike };
150756e3b29fSHelen Koike 
rkisp1_unregister_capture(struct rkisp1_capture * cap)150856e3b29fSHelen Koike static void rkisp1_unregister_capture(struct rkisp1_capture *cap)
150956e3b29fSHelen Koike {
151055fcb913SLaurent Pinchart 	if (!video_is_registered(&cap->vnode.vdev))
151155fcb913SLaurent Pinchart 		return;
151255fcb913SLaurent Pinchart 
151356e3b29fSHelen Koike 	media_entity_cleanup(&cap->vnode.vdev.entity);
15142dc73489SHans Verkuil 	vb2_video_unregister_device(&cap->vnode.vdev);
151555fcb913SLaurent Pinchart 	mutex_destroy(&cap->vnode.vlock);
151656e3b29fSHelen Koike }
151756e3b29fSHelen Koike 
rkisp1_capture_devs_unregister(struct rkisp1_device * rkisp1)151856e3b29fSHelen Koike void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1)
151956e3b29fSHelen Koike {
152056e3b29fSHelen Koike 	struct rkisp1_capture *mp = &rkisp1->capture_devs[RKISP1_MAINPATH];
152156e3b29fSHelen Koike 	struct rkisp1_capture *sp = &rkisp1->capture_devs[RKISP1_SELFPATH];
152256e3b29fSHelen Koike 
152356e3b29fSHelen Koike 	rkisp1_unregister_capture(mp);
152456e3b29fSHelen Koike 	rkisp1_unregister_capture(sp);
152556e3b29fSHelen Koike }
152656e3b29fSHelen Koike 
rkisp1_register_capture(struct rkisp1_capture * cap)152756e3b29fSHelen Koike static int rkisp1_register_capture(struct rkisp1_capture *cap)
152856e3b29fSHelen Koike {
15294ee8191cSColin Ian King 	static const char * const dev_names[] = {
15304ee8191cSColin Ian King 		RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME
15314ee8191cSColin Ian King 	};
153256e3b29fSHelen Koike 	struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev;
153356e3b29fSHelen Koike 	struct video_device *vdev = &cap->vnode.vdev;
153456e3b29fSHelen Koike 	struct rkisp1_vdev_node *node;
153556e3b29fSHelen Koike 	struct vb2_queue *q;
153656e3b29fSHelen Koike 	int ret;
153756e3b29fSHelen Koike 
153856e3b29fSHelen Koike 	strscpy(vdev->name, dev_names[cap->id], sizeof(vdev->name));
153956e3b29fSHelen Koike 	node = rkisp1_vdev_to_node(vdev);
154056e3b29fSHelen Koike 	mutex_init(&node->vlock);
154156e3b29fSHelen Koike 
154256e3b29fSHelen Koike 	vdev->ioctl_ops = &rkisp1_v4l2_ioctl_ops;
154356e3b29fSHelen Koike 	vdev->release = video_device_release_empty;
154456e3b29fSHelen Koike 	vdev->fops = &rkisp1_fops;
154556e3b29fSHelen Koike 	vdev->minor = -1;
154656e3b29fSHelen Koike 	vdev->v4l2_dev = v4l2_dev;
154756e3b29fSHelen Koike 	vdev->lock = &node->vlock;
154856e3b29fSHelen Koike 	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
15495fc929aeSDafna Hirschfeld 			    V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
155056e3b29fSHelen Koike 	vdev->entity.ops = &rkisp1_media_ops;
155156e3b29fSHelen Koike 	video_set_drvdata(vdev, cap);
155256e3b29fSHelen Koike 	vdev->vfl_dir = VFL_DIR_RX;
155356e3b29fSHelen Koike 	node->pad.flags = MEDIA_PAD_FL_SINK;
155456e3b29fSHelen Koike 
155556e3b29fSHelen Koike 	q = &node->buf_queue;
155656e3b29fSHelen Koike 	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
15575f028c51SDafna Hirschfeld 	q->io_modes = VB2_MMAP | VB2_DMABUF;
155856e3b29fSHelen Koike 	q->drv_priv = cap;
155956e3b29fSHelen Koike 	q->ops = &rkisp1_vb2_ops;
156056e3b29fSHelen Koike 	q->mem_ops = &vb2_dma_contig_memops;
156156e3b29fSHelen Koike 	q->buf_struct_size = sizeof(struct rkisp1_buffer);
1562*6c10d1adSJacopo Mondi 	q->min_queued_buffers = 1;
156356e3b29fSHelen Koike 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
156456e3b29fSHelen Koike 	q->lock = &node->vlock;
156556e3b29fSHelen Koike 	q->dev = cap->rkisp1->dev;
156656e3b29fSHelen Koike 	ret = vb2_queue_init(q);
156756e3b29fSHelen Koike 	if (ret) {
156856e3b29fSHelen Koike 		dev_err(cap->rkisp1->dev,
156956e3b29fSHelen Koike 			"vb2 queue init failed (err=%d)\n", ret);
157055fcb913SLaurent Pinchart 		goto error;
157156e3b29fSHelen Koike 	}
157256e3b29fSHelen Koike 
157356e3b29fSHelen Koike 	vdev->queue = q;
157456e3b29fSHelen Koike 
157556c8534eSLaurent Pinchart 	ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
157656c8534eSLaurent Pinchart 	if (ret)
157755fcb913SLaurent Pinchart 		goto error;
157856c8534eSLaurent Pinchart 
15790e17c50fSHans Verkuil 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
158056e3b29fSHelen Koike 	if (ret) {
158156e3b29fSHelen Koike 		dev_err(cap->rkisp1->dev,
158256e3b29fSHelen Koike 			"failed to register %s, ret=%d\n", vdev->name, ret);
158356c8534eSLaurent Pinchart 		goto error;
158456e3b29fSHelen Koike 	}
158556c8534eSLaurent Pinchart 
158656e3b29fSHelen Koike 	v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name,
158756e3b29fSHelen Koike 		  vdev->num);
158856e3b29fSHelen Koike 
158956e3b29fSHelen Koike 	return 0;
159056c8534eSLaurent Pinchart 
159156c8534eSLaurent Pinchart error:
159256c8534eSLaurent Pinchart 	media_entity_cleanup(&vdev->entity);
159355fcb913SLaurent Pinchart 	mutex_destroy(&node->vlock);
159456c8534eSLaurent Pinchart 	return ret;
159556e3b29fSHelen Koike }
159656e3b29fSHelen Koike 
159756e3b29fSHelen Koike static void
rkisp1_capture_init(struct rkisp1_device * rkisp1,enum rkisp1_stream_id id)159856e3b29fSHelen Koike rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id)
159956e3b29fSHelen Koike {
160056e3b29fSHelen Koike 	struct rkisp1_capture *cap = &rkisp1->capture_devs[id];
160156e3b29fSHelen Koike 	struct v4l2_pix_format_mplane pixm;
160256e3b29fSHelen Koike 
160356e3b29fSHelen Koike 	memset(cap, 0, sizeof(*cap));
160456e3b29fSHelen Koike 	cap->id = id;
160556e3b29fSHelen Koike 	cap->rkisp1 = rkisp1;
160656e3b29fSHelen Koike 
160756e3b29fSHelen Koike 	INIT_LIST_HEAD(&cap->buf.queue);
160856e3b29fSHelen Koike 	init_waitqueue_head(&cap->done);
160956e3b29fSHelen Koike 	spin_lock_init(&cap->buf.lock);
161056e3b29fSHelen Koike 	if (cap->id == RKISP1_SELFPATH) {
161156e3b29fSHelen Koike 		cap->ops = &rkisp1_capture_ops_sp;
161256e3b29fSHelen Koike 		cap->config = &rkisp1_capture_config_sp;
161356e3b29fSHelen Koike 	} else {
161456e3b29fSHelen Koike 		cap->ops = &rkisp1_capture_ops_mp;
161556e3b29fSHelen Koike 		cap->config = &rkisp1_capture_config_mp;
161656e3b29fSHelen Koike 	}
161756e3b29fSHelen Koike 
161856e3b29fSHelen Koike 	cap->is_streaming = false;
161956e3b29fSHelen Koike 
162056e3b29fSHelen Koike 	memset(&pixm, 0, sizeof(pixm));
162156e3b29fSHelen Koike 	pixm.pixelformat = V4L2_PIX_FMT_YUYV;
162256e3b29fSHelen Koike 	pixm.width = RKISP1_DEFAULT_WIDTH;
162356e3b29fSHelen Koike 	pixm.height = RKISP1_DEFAULT_HEIGHT;
162456e3b29fSHelen Koike 	rkisp1_set_fmt(cap, &pixm);
162556e3b29fSHelen Koike }
162656e3b29fSHelen Koike 
rkisp1_capture_devs_register(struct rkisp1_device * rkisp1)162756e3b29fSHelen Koike int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1)
162856e3b29fSHelen Koike {
162982754080SPaul Elder 	unsigned int dev_count = rkisp1_path_count(rkisp1);
163055fcb913SLaurent Pinchart 	unsigned int i;
163156e3b29fSHelen Koike 	int ret;
163256e3b29fSHelen Koike 
163382754080SPaul Elder 	for (i = 0; i < dev_count; i++) {
163455fcb913SLaurent Pinchart 		struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
163555fcb913SLaurent Pinchart 
163656e3b29fSHelen Koike 		rkisp1_capture_init(rkisp1, i);
163755fcb913SLaurent Pinchart 
163856e3b29fSHelen Koike 		ret = rkisp1_register_capture(cap);
163955fcb913SLaurent Pinchart 		if (ret) {
164055fcb913SLaurent Pinchart 			rkisp1_capture_devs_unregister(rkisp1);
164155fcb913SLaurent Pinchart 			return ret;
164255fcb913SLaurent Pinchart 		}
164356e3b29fSHelen Koike 	}
164456e3b29fSHelen Koike 
164556e3b29fSHelen Koike 	return 0;
164656e3b29fSHelen Koike 
164756e3b29fSHelen Koike }
1648