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