1d64685e1SAlain Volmat // SPDX-License-Identifier: GPL-2.0 2d64685e1SAlain Volmat /* 3d64685e1SAlain Volmat * Driver for STM32 Digital Camera Memory Interface Pixel Processor 4d64685e1SAlain Volmat * 5d64685e1SAlain Volmat * Copyright (C) STMicroelectronics SA 2023 6d64685e1SAlain Volmat * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com> 7d64685e1SAlain Volmat * Alain Volmat <alain.volmat@foss.st.com> 8d64685e1SAlain Volmat * for STMicroelectronics. 9d64685e1SAlain Volmat */ 10d64685e1SAlain Volmat 11d64685e1SAlain Volmat #include <linux/v4l2-mediabus.h> 12*03abfb7bSAlain Volmat #include <media/mipi-csi2.h> 13d64685e1SAlain Volmat #include <media/v4l2-event.h> 14d64685e1SAlain Volmat #include <media/v4l2-subdev.h> 15d64685e1SAlain Volmat 16d64685e1SAlain Volmat #include "dcmipp-common.h" 17d64685e1SAlain Volmat 18d64685e1SAlain Volmat #define DCMIPP_PRCR 0x104 19d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_SHIFT 16 20d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_YUV422 0x1e 21d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_RGB565 0x22 22d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_RAW8 0x2a 23*03abfb7bSAlain Volmat #define DCMIPP_PRCR_FORMAT_RAW10 0x2b 24*03abfb7bSAlain Volmat #define DCMIPP_PRCR_FORMAT_RAW12 0x2c 25*03abfb7bSAlain Volmat #define DCMIPP_PRCR_FORMAT_RAW14 0x2d 26d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_G8 0x4a 27d64685e1SAlain Volmat #define DCMIPP_PRCR_FORMAT_BYTE_STREAM 0x5a 28d64685e1SAlain Volmat #define DCMIPP_PRCR_ESS BIT(4) 29d64685e1SAlain Volmat #define DCMIPP_PRCR_PCKPOL BIT(5) 30d64685e1SAlain Volmat #define DCMIPP_PRCR_HSPOL BIT(6) 31d64685e1SAlain Volmat #define DCMIPP_PRCR_VSPOL BIT(7) 32d64685e1SAlain Volmat #define DCMIPP_PRCR_ENABLE BIT(14) 33d64685e1SAlain Volmat #define DCMIPP_PRCR_SWAPCYCLES BIT(25) 34d64685e1SAlain Volmat 35d64685e1SAlain Volmat #define DCMIPP_PRESCR 0x108 36d64685e1SAlain Volmat #define DCMIPP_PRESUR 0x10c 37d64685e1SAlain Volmat 38*03abfb7bSAlain Volmat #define DCMIPP_CMCR 0x204 39*03abfb7bSAlain Volmat #define DCMIPP_CMCR_INSEL BIT(0) 40*03abfb7bSAlain Volmat 41*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR 0x404 42*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTMODE_MASK GENMASK(17, 16) 43*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTMODE_SHIFT 16 44*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTMODE_DTIDA 0x00 45*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTMODE_ALLDT 0x03 46*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTIDA_MASK GENMASK(5, 0) 47*03abfb7bSAlain Volmat #define DCMIPP_P0FSCR_DTIDA_SHIFT 0 48*03abfb7bSAlain Volmat 49d64685e1SAlain Volmat #define IS_SINK(pad) (!(pad)) 50d64685e1SAlain Volmat #define IS_SRC(pad) ((pad)) 51d64685e1SAlain Volmat 52d64685e1SAlain Volmat struct dcmipp_inp_pix_map { 53d64685e1SAlain Volmat unsigned int code_sink; 54d64685e1SAlain Volmat unsigned int code_src; 55*03abfb7bSAlain Volmat /* Parallel related information */ 56d64685e1SAlain Volmat u8 prcr_format; 57d64685e1SAlain Volmat u8 prcr_swapcycles; 58*03abfb7bSAlain Volmat /* CSI related information */ 59*03abfb7bSAlain Volmat unsigned int dt; 60d64685e1SAlain Volmat }; 61d64685e1SAlain Volmat 62*03abfb7bSAlain Volmat #define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap, data_type) \ 63d64685e1SAlain Volmat { \ 64d64685e1SAlain Volmat .code_sink = MEDIA_BUS_FMT_##sink, \ 65d64685e1SAlain Volmat .code_src = MEDIA_BUS_FMT_##src, \ 66d64685e1SAlain Volmat .prcr_format = DCMIPP_PRCR_FORMAT_##prcr, \ 67d64685e1SAlain Volmat .prcr_swapcycles = swap, \ 68*03abfb7bSAlain Volmat .dt = data_type, \ 69d64685e1SAlain Volmat } 70d64685e1SAlain Volmat static const struct dcmipp_inp_pix_map dcmipp_inp_pix_map_list[] = { 71d64685e1SAlain Volmat /* RGB565 */ 72*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1, MIPI_CSI2_DT_RGB565), 73*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0, MIPI_CSI2_DT_RGB565), 74*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_1X16, RGB565_1X16, RGB565, 0, MIPI_CSI2_DT_RGB565), 75d64685e1SAlain Volmat /* YUV422 */ 76*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 77*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_1X16, YUYV8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 78*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 79*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 80*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_1X16, UYVY8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 81*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 82*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 83*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_1X16, YVYU8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 84*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1, MIPI_CSI2_DT_YUV422_8B), 85*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_1X16, VYUY8_1X16, YUV422, 0, MIPI_CSI2_DT_YUV422_8B), 86d64685e1SAlain Volmat /* GREY */ 87*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0, MIPI_CSI2_DT_RAW8), 88d64685e1SAlain Volmat /* Raw Bayer */ 89*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 90*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 91*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 92*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0, MIPI_CSI2_DT_RAW8), 93*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR10_1X10, SBGGR10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 94*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG10_1X10, SGBRG10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 95*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG10_1X10, SGRBG10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 96*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB10_1X10, SRGGB10_1X10, RAW10, 0, MIPI_CSI2_DT_RAW10), 97*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR12_1X12, SBGGR12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 98*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG12_1X12, SGBRG12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 99*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG12_1X12, SGRBG12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 100*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB12_1X12, SRGGB12_1X12, RAW12, 0, MIPI_CSI2_DT_RAW12), 101*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR14_1X14, SBGGR14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 102*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG14_1X14, SGBRG14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 103*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG14_1X14, SGRBG14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 104*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB14_1X14, SRGGB14_1X14, RAW14, 0, MIPI_CSI2_DT_RAW14), 105d64685e1SAlain Volmat /* JPEG */ 106*03abfb7bSAlain Volmat PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0, 0), 107d64685e1SAlain Volmat }; 108d64685e1SAlain Volmat 109d64685e1SAlain Volmat /* 110d64685e1SAlain Volmat * Search through the pix_map table, skipping two consecutive entry with the 111d64685e1SAlain Volmat * same code 112d64685e1SAlain Volmat */ 113d64685e1SAlain Volmat static inline const struct dcmipp_inp_pix_map *dcmipp_inp_pix_map_by_index 114d64685e1SAlain Volmat (unsigned int index, 115d64685e1SAlain Volmat unsigned int pad) 116d64685e1SAlain Volmat { 117d64685e1SAlain Volmat unsigned int i = 0; 118d64685e1SAlain Volmat u32 prev_code = 0, cur_code; 119d64685e1SAlain Volmat 120d64685e1SAlain Volmat while (i < ARRAY_SIZE(dcmipp_inp_pix_map_list)) { 121d64685e1SAlain Volmat if (IS_SRC(pad)) 122d64685e1SAlain Volmat cur_code = dcmipp_inp_pix_map_list[i].code_src; 123d64685e1SAlain Volmat else 124d64685e1SAlain Volmat cur_code = dcmipp_inp_pix_map_list[i].code_sink; 125d64685e1SAlain Volmat 126d64685e1SAlain Volmat if (cur_code == prev_code) { 127d64685e1SAlain Volmat i++; 128d64685e1SAlain Volmat continue; 129d64685e1SAlain Volmat } 130d64685e1SAlain Volmat prev_code = cur_code; 131d64685e1SAlain Volmat 132d64685e1SAlain Volmat if (index == 0) 133d64685e1SAlain Volmat break; 134d64685e1SAlain Volmat i++; 135d64685e1SAlain Volmat index--; 136d64685e1SAlain Volmat } 137d64685e1SAlain Volmat 138d64685e1SAlain Volmat if (i >= ARRAY_SIZE(dcmipp_inp_pix_map_list)) 139d64685e1SAlain Volmat return NULL; 140d64685e1SAlain Volmat 141d64685e1SAlain Volmat return &dcmipp_inp_pix_map_list[i]; 142d64685e1SAlain Volmat } 143d64685e1SAlain Volmat 144d64685e1SAlain Volmat static inline const struct dcmipp_inp_pix_map *dcmipp_inp_pix_map_by_code 145d64685e1SAlain Volmat (u32 code_sink, u32 code_src) 146d64685e1SAlain Volmat { 147d64685e1SAlain Volmat unsigned int i; 148d64685e1SAlain Volmat 149d64685e1SAlain Volmat for (i = 0; i < ARRAY_SIZE(dcmipp_inp_pix_map_list); i++) { 150d64685e1SAlain Volmat if ((dcmipp_inp_pix_map_list[i].code_sink == code_sink && 151d64685e1SAlain Volmat dcmipp_inp_pix_map_list[i].code_src == code_src) || 152d64685e1SAlain Volmat (dcmipp_inp_pix_map_list[i].code_sink == code_src && 153d64685e1SAlain Volmat dcmipp_inp_pix_map_list[i].code_src == code_sink) || 154d64685e1SAlain Volmat (dcmipp_inp_pix_map_list[i].code_sink == code_sink && 155d64685e1SAlain Volmat code_src == 0) || 156d64685e1SAlain Volmat (code_sink == 0 && 157d64685e1SAlain Volmat dcmipp_inp_pix_map_list[i].code_src == code_src)) 158d64685e1SAlain Volmat return &dcmipp_inp_pix_map_list[i]; 159d64685e1SAlain Volmat } 160d64685e1SAlain Volmat return NULL; 161d64685e1SAlain Volmat } 162d64685e1SAlain Volmat 163d64685e1SAlain Volmat struct dcmipp_inp_device { 164d64685e1SAlain Volmat struct dcmipp_ent_device ved; 165d64685e1SAlain Volmat struct v4l2_subdev sd; 166d64685e1SAlain Volmat struct device *dev; 167d64685e1SAlain Volmat void __iomem *regs; 168d64685e1SAlain Volmat }; 169d64685e1SAlain Volmat 170d64685e1SAlain Volmat static const struct v4l2_mbus_framefmt fmt_default = { 171d64685e1SAlain Volmat .width = DCMIPP_FMT_WIDTH_DEFAULT, 172d64685e1SAlain Volmat .height = DCMIPP_FMT_HEIGHT_DEFAULT, 173d64685e1SAlain Volmat .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 174d64685e1SAlain Volmat .field = V4L2_FIELD_NONE, 175d64685e1SAlain Volmat .colorspace = DCMIPP_COLORSPACE_DEFAULT, 176d64685e1SAlain Volmat .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT, 177d64685e1SAlain Volmat .quantization = DCMIPP_QUANTIZATION_DEFAULT, 178d64685e1SAlain Volmat .xfer_func = DCMIPP_XFER_FUNC_DEFAULT, 179d64685e1SAlain Volmat }; 180d64685e1SAlain Volmat 181d64685e1SAlain Volmat static int dcmipp_inp_init_state(struct v4l2_subdev *sd, 182d64685e1SAlain Volmat struct v4l2_subdev_state *sd_state) 183d64685e1SAlain Volmat { 184d64685e1SAlain Volmat unsigned int i; 185d64685e1SAlain Volmat 186d64685e1SAlain Volmat for (i = 0; i < sd->entity.num_pads; i++) { 187d64685e1SAlain Volmat struct v4l2_mbus_framefmt *mf; 188d64685e1SAlain Volmat 189d64685e1SAlain Volmat mf = v4l2_subdev_state_get_format(sd_state, i); 190d64685e1SAlain Volmat *mf = fmt_default; 191d64685e1SAlain Volmat } 192d64685e1SAlain Volmat 193d64685e1SAlain Volmat return 0; 194d64685e1SAlain Volmat } 195d64685e1SAlain Volmat 196d64685e1SAlain Volmat static int dcmipp_inp_enum_mbus_code(struct v4l2_subdev *sd, 197d64685e1SAlain Volmat struct v4l2_subdev_state *sd_state, 198d64685e1SAlain Volmat struct v4l2_subdev_mbus_code_enum *code) 199d64685e1SAlain Volmat { 200d64685e1SAlain Volmat const struct dcmipp_inp_pix_map *vpix = 201d64685e1SAlain Volmat dcmipp_inp_pix_map_by_index(code->index, code->pad); 202d64685e1SAlain Volmat 203d64685e1SAlain Volmat if (!vpix) 204d64685e1SAlain Volmat return -EINVAL; 205d64685e1SAlain Volmat 206d64685e1SAlain Volmat code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink; 207d64685e1SAlain Volmat 208d64685e1SAlain Volmat return 0; 209d64685e1SAlain Volmat } 210d64685e1SAlain Volmat 211d64685e1SAlain Volmat static int dcmipp_inp_enum_frame_size(struct v4l2_subdev *sd, 212d64685e1SAlain Volmat struct v4l2_subdev_state *sd_state, 213d64685e1SAlain Volmat struct v4l2_subdev_frame_size_enum *fse) 214d64685e1SAlain Volmat { 215d64685e1SAlain Volmat const struct dcmipp_inp_pix_map *vpix; 216d64685e1SAlain Volmat 217d64685e1SAlain Volmat if (fse->index) 218d64685e1SAlain Volmat return -EINVAL; 219d64685e1SAlain Volmat 220d64685e1SAlain Volmat /* Only accept code in the pix map table */ 221d64685e1SAlain Volmat vpix = dcmipp_inp_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0, 222d64685e1SAlain Volmat IS_SRC(fse->pad) ? fse->code : 0); 223d64685e1SAlain Volmat if (!vpix) 224d64685e1SAlain Volmat return -EINVAL; 225d64685e1SAlain Volmat 226d64685e1SAlain Volmat fse->min_width = DCMIPP_FRAME_MIN_WIDTH; 227d64685e1SAlain Volmat fse->max_width = DCMIPP_FRAME_MAX_WIDTH; 228d64685e1SAlain Volmat fse->min_height = DCMIPP_FRAME_MIN_HEIGHT; 229d64685e1SAlain Volmat fse->max_height = DCMIPP_FRAME_MAX_HEIGHT; 230d64685e1SAlain Volmat 231d64685e1SAlain Volmat return 0; 232d64685e1SAlain Volmat } 233d64685e1SAlain Volmat 234d64685e1SAlain Volmat static void dcmipp_inp_adjust_fmt(struct dcmipp_inp_device *inp, 235d64685e1SAlain Volmat struct v4l2_mbus_framefmt *fmt, __u32 pad) 236d64685e1SAlain Volmat { 237d64685e1SAlain Volmat const struct dcmipp_inp_pix_map *vpix; 238d64685e1SAlain Volmat 239d64685e1SAlain Volmat /* Only accept code in the pix map table */ 240d64685e1SAlain Volmat vpix = dcmipp_inp_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0, 241d64685e1SAlain Volmat IS_SRC(pad) ? fmt->code : 0); 242d64685e1SAlain Volmat if (!vpix) 243d64685e1SAlain Volmat fmt->code = fmt_default.code; 244d64685e1SAlain Volmat 245d64685e1SAlain Volmat /* Exclude JPEG if BT656 bus is selected */ 246d64685e1SAlain Volmat if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 && 247d64685e1SAlain Volmat inp->ved.bus_type == V4L2_MBUS_BT656) 248d64685e1SAlain Volmat fmt->code = fmt_default.code; 249d64685e1SAlain Volmat 250d64685e1SAlain Volmat fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH, 251d64685e1SAlain Volmat DCMIPP_FRAME_MAX_WIDTH) & ~1; 252d64685e1SAlain Volmat fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT, 253d64685e1SAlain Volmat DCMIPP_FRAME_MAX_HEIGHT) & ~1; 254d64685e1SAlain Volmat 255d64685e1SAlain Volmat if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) 256d64685e1SAlain Volmat fmt->field = fmt_default.field; 257d64685e1SAlain Volmat 258d64685e1SAlain Volmat dcmipp_colorimetry_clamp(fmt); 259d64685e1SAlain Volmat } 260d64685e1SAlain Volmat 261d64685e1SAlain Volmat static int dcmipp_inp_set_fmt(struct v4l2_subdev *sd, 262d64685e1SAlain Volmat struct v4l2_subdev_state *sd_state, 263d64685e1SAlain Volmat struct v4l2_subdev_format *fmt) 264d64685e1SAlain Volmat { 265d64685e1SAlain Volmat struct dcmipp_inp_device *inp = v4l2_get_subdevdata(sd); 266d64685e1SAlain Volmat struct v4l2_mbus_framefmt *mf; 267d64685e1SAlain Volmat 268d64685e1SAlain Volmat if (v4l2_subdev_is_streaming(sd)) 269d64685e1SAlain Volmat return -EBUSY; 270d64685e1SAlain Volmat 271d64685e1SAlain Volmat mf = v4l2_subdev_state_get_format(sd_state, fmt->pad); 272d64685e1SAlain Volmat 273d64685e1SAlain Volmat /* Set the new format */ 274d64685e1SAlain Volmat dcmipp_inp_adjust_fmt(inp, &fmt->format, fmt->pad); 275d64685e1SAlain Volmat 276d64685e1SAlain Volmat dev_dbg(inp->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n", 277d64685e1SAlain Volmat inp->sd.name, 278d64685e1SAlain Volmat /* old */ 279d64685e1SAlain Volmat mf->width, mf->height, mf->code, 280d64685e1SAlain Volmat mf->colorspace, mf->quantization, 281d64685e1SAlain Volmat mf->xfer_func, mf->ycbcr_enc, 282d64685e1SAlain Volmat /* new */ 283d64685e1SAlain Volmat fmt->format.width, fmt->format.height, fmt->format.code, 284d64685e1SAlain Volmat fmt->format.colorspace, fmt->format.quantization, 285d64685e1SAlain Volmat fmt->format.xfer_func, fmt->format.ycbcr_enc); 286d64685e1SAlain Volmat 287d64685e1SAlain Volmat *mf = fmt->format; 288d64685e1SAlain Volmat 289d64685e1SAlain Volmat /* When setting the sink format, report that format on the src pad */ 290d64685e1SAlain Volmat if (IS_SINK(fmt->pad)) { 291d64685e1SAlain Volmat mf = v4l2_subdev_state_get_format(sd_state, 1); 292d64685e1SAlain Volmat *mf = fmt->format; 293d64685e1SAlain Volmat dcmipp_inp_adjust_fmt(inp, mf, 1); 294d64685e1SAlain Volmat } 295d64685e1SAlain Volmat 296d64685e1SAlain Volmat return 0; 297d64685e1SAlain Volmat } 298d64685e1SAlain Volmat 299*03abfb7bSAlain Volmat static int dcmipp_inp_configure_parallel(struct dcmipp_inp_device *inp, 300d64685e1SAlain Volmat struct v4l2_subdev_state *state) 301d64685e1SAlain Volmat { 302d64685e1SAlain Volmat u32 val = 0; 303d64685e1SAlain Volmat const struct dcmipp_inp_pix_map *vpix; 304d64685e1SAlain Volmat struct v4l2_mbus_framefmt *sink_fmt; 305d64685e1SAlain Volmat struct v4l2_mbus_framefmt *src_fmt; 306d64685e1SAlain Volmat 307d64685e1SAlain Volmat /* Set vertical synchronization polarity */ 308d64685e1SAlain Volmat if (inp->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 309d64685e1SAlain Volmat val |= DCMIPP_PRCR_VSPOL; 310d64685e1SAlain Volmat 311d64685e1SAlain Volmat /* Set horizontal synchronization polarity */ 312d64685e1SAlain Volmat if (inp->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 313d64685e1SAlain Volmat val |= DCMIPP_PRCR_HSPOL; 314d64685e1SAlain Volmat 315d64685e1SAlain Volmat /* Set pixel clock polarity */ 316d64685e1SAlain Volmat if (inp->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 317d64685e1SAlain Volmat val |= DCMIPP_PRCR_PCKPOL; 318d64685e1SAlain Volmat 319d64685e1SAlain Volmat /* 320d64685e1SAlain Volmat * BT656 embedded synchronisation bus mode. 321d64685e1SAlain Volmat * 322d64685e1SAlain Volmat * Default SAV/EAV mode is supported here with default codes 323d64685e1SAlain Volmat * SAV=0xff000080 & EAV=0xff00009d. 324d64685e1SAlain Volmat * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d. 325d64685e1SAlain Volmat */ 326d64685e1SAlain Volmat if (inp->ved.bus_type == V4L2_MBUS_BT656) { 327d64685e1SAlain Volmat val |= DCMIPP_PRCR_ESS; 328d64685e1SAlain Volmat 329d64685e1SAlain Volmat /* Unmask all codes */ 330d64685e1SAlain Volmat reg_write(inp, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ 331d64685e1SAlain Volmat 332d64685e1SAlain Volmat /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ 333d64685e1SAlain Volmat reg_write(inp, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ 334d64685e1SAlain Volmat } 335d64685e1SAlain Volmat 336d64685e1SAlain Volmat /* Set format */ 337d64685e1SAlain Volmat sink_fmt = v4l2_subdev_state_get_format(state, 0); 338d64685e1SAlain Volmat src_fmt = v4l2_subdev_state_get_format(state, 1); 339d64685e1SAlain Volmat 340d64685e1SAlain Volmat vpix = dcmipp_inp_pix_map_by_code(sink_fmt->code, src_fmt->code); 341d64685e1SAlain Volmat if (!vpix) { 342d64685e1SAlain Volmat dev_err(inp->dev, "Invalid sink/src format configuration\n"); 343d64685e1SAlain Volmat return -EINVAL; 344d64685e1SAlain Volmat } 345d64685e1SAlain Volmat 346d64685e1SAlain Volmat val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT; 347d64685e1SAlain Volmat 348d64685e1SAlain Volmat /* swap cycles */ 349d64685e1SAlain Volmat if (vpix->prcr_swapcycles) 350d64685e1SAlain Volmat val |= DCMIPP_PRCR_SWAPCYCLES; 351d64685e1SAlain Volmat 352d64685e1SAlain Volmat reg_write(inp, DCMIPP_PRCR, val); 353d64685e1SAlain Volmat 354*03abfb7bSAlain Volmat /* Select the DCMIPP parallel interface */ 355*03abfb7bSAlain Volmat reg_write(inp, DCMIPP_CMCR, 0); 356*03abfb7bSAlain Volmat 357*03abfb7bSAlain Volmat /* Enable parallel interface */ 358*03abfb7bSAlain Volmat reg_set(inp, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 359*03abfb7bSAlain Volmat 360*03abfb7bSAlain Volmat return 0; 361*03abfb7bSAlain Volmat } 362*03abfb7bSAlain Volmat 363*03abfb7bSAlain Volmat static int dcmipp_inp_configure_csi(struct dcmipp_inp_device *inp, 364*03abfb7bSAlain Volmat struct v4l2_subdev_state *state) 365*03abfb7bSAlain Volmat { 366*03abfb7bSAlain Volmat const struct dcmipp_inp_pix_map *vpix; 367*03abfb7bSAlain Volmat struct v4l2_mbus_framefmt *sink_fmt; 368*03abfb7bSAlain Volmat struct v4l2_mbus_framefmt *src_fmt; 369*03abfb7bSAlain Volmat 370*03abfb7bSAlain Volmat /* Get format information */ 371*03abfb7bSAlain Volmat sink_fmt = v4l2_subdev_state_get_format(state, 0); 372*03abfb7bSAlain Volmat src_fmt = v4l2_subdev_state_get_format(state, 1); 373*03abfb7bSAlain Volmat 374*03abfb7bSAlain Volmat vpix = dcmipp_inp_pix_map_by_code(sink_fmt->code, src_fmt->code); 375*03abfb7bSAlain Volmat if (!vpix) { 376*03abfb7bSAlain Volmat dev_err(inp->dev, "Invalid sink/src format configuration\n"); 377*03abfb7bSAlain Volmat return -EINVAL; 378*03abfb7bSAlain Volmat } 379*03abfb7bSAlain Volmat 380*03abfb7bSAlain Volmat /* Apply configuration on each input pipe */ 381*03abfb7bSAlain Volmat reg_clear(inp, DCMIPP_P0FSCR, 382*03abfb7bSAlain Volmat DCMIPP_P0FSCR_DTMODE_MASK | DCMIPP_P0FSCR_DTIDA_MASK); 383*03abfb7bSAlain Volmat 384*03abfb7bSAlain Volmat /* In case of JPEG we don't know the DT so we allow all data */ 385*03abfb7bSAlain Volmat /* 386*03abfb7bSAlain Volmat * TODO - check instead dt == 0 for the time being to allow other 387*03abfb7bSAlain Volmat * unknown data-type 388*03abfb7bSAlain Volmat */ 389*03abfb7bSAlain Volmat if (!vpix->dt) 390*03abfb7bSAlain Volmat reg_set(inp, DCMIPP_P0FSCR, 391*03abfb7bSAlain Volmat DCMIPP_P0FSCR_DTMODE_ALLDT << DCMIPP_P0FSCR_DTMODE_SHIFT); 392*03abfb7bSAlain Volmat else 393*03abfb7bSAlain Volmat reg_set(inp, DCMIPP_P0FSCR, 394*03abfb7bSAlain Volmat vpix->dt << DCMIPP_P0FSCR_DTIDA_SHIFT | 395*03abfb7bSAlain Volmat DCMIPP_P0FSCR_DTMODE_DTIDA); 396*03abfb7bSAlain Volmat 397*03abfb7bSAlain Volmat /* Select the DCMIPP CSI interface */ 398*03abfb7bSAlain Volmat reg_write(inp, DCMIPP_CMCR, DCMIPP_CMCR_INSEL); 399*03abfb7bSAlain Volmat 400d64685e1SAlain Volmat return 0; 401d64685e1SAlain Volmat } 402d64685e1SAlain Volmat 403d64685e1SAlain Volmat static int dcmipp_inp_enable_streams(struct v4l2_subdev *sd, 404d64685e1SAlain Volmat struct v4l2_subdev_state *state, 405d64685e1SAlain Volmat u32 pad, u64 streams_mask) 406d64685e1SAlain Volmat { 407d64685e1SAlain Volmat struct dcmipp_inp_device *inp = 408d64685e1SAlain Volmat container_of(sd, struct dcmipp_inp_device, sd); 409d64685e1SAlain Volmat struct v4l2_subdev *s_subdev; 410d64685e1SAlain Volmat struct media_pad *s_pad; 411*03abfb7bSAlain Volmat int ret = 0; 412d64685e1SAlain Volmat 413d64685e1SAlain Volmat /* Get source subdev */ 414d64685e1SAlain Volmat s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]); 415d64685e1SAlain Volmat if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity)) 416d64685e1SAlain Volmat return -EINVAL; 417d64685e1SAlain Volmat s_subdev = media_entity_to_v4l2_subdev(s_pad->entity); 418d64685e1SAlain Volmat 419*03abfb7bSAlain Volmat if (inp->ved.bus_type == V4L2_MBUS_PARALLEL || 420*03abfb7bSAlain Volmat inp->ved.bus_type == V4L2_MBUS_BT656) 421*03abfb7bSAlain Volmat ret = dcmipp_inp_configure_parallel(inp, state); 422*03abfb7bSAlain Volmat else if (inp->ved.bus_type == V4L2_MBUS_CSI2_DPHY) 423*03abfb7bSAlain Volmat ret = dcmipp_inp_configure_csi(inp, state); 424d64685e1SAlain Volmat if (ret) 425d64685e1SAlain Volmat return ret; 426d64685e1SAlain Volmat 427d64685e1SAlain Volmat ret = v4l2_subdev_enable_streams(s_subdev, s_pad->index, BIT_ULL(0)); 428d64685e1SAlain Volmat if (ret < 0) { 429d64685e1SAlain Volmat dev_err(inp->dev, 430d64685e1SAlain Volmat "failed to start source subdev streaming (%d)\n", ret); 431d64685e1SAlain Volmat return ret; 432d64685e1SAlain Volmat } 433d64685e1SAlain Volmat 434d64685e1SAlain Volmat return 0; 435d64685e1SAlain Volmat } 436d64685e1SAlain Volmat 437d64685e1SAlain Volmat static int dcmipp_inp_disable_streams(struct v4l2_subdev *sd, 438d64685e1SAlain Volmat struct v4l2_subdev_state *state, 439d64685e1SAlain Volmat u32 pad, u64 streams_mask) 440d64685e1SAlain Volmat { 441d64685e1SAlain Volmat struct dcmipp_inp_device *inp = 442d64685e1SAlain Volmat container_of(sd, struct dcmipp_inp_device, sd); 443d64685e1SAlain Volmat struct v4l2_subdev *s_subdev; 444d64685e1SAlain Volmat struct media_pad *s_pad; 445d64685e1SAlain Volmat int ret; 446d64685e1SAlain Volmat 447d64685e1SAlain Volmat /* Get source subdev */ 448d64685e1SAlain Volmat s_pad = media_pad_remote_pad_first(&sd->entity.pads[0]); 449d64685e1SAlain Volmat if (!s_pad || !is_media_entity_v4l2_subdev(s_pad->entity)) 450d64685e1SAlain Volmat return -EINVAL; 451d64685e1SAlain Volmat s_subdev = media_entity_to_v4l2_subdev(s_pad->entity); 452d64685e1SAlain Volmat 453d64685e1SAlain Volmat ret = v4l2_subdev_disable_streams(s_subdev, s_pad->index, BIT_ULL(0)); 454d64685e1SAlain Volmat if (ret < 0) { 455d64685e1SAlain Volmat dev_err(inp->dev, 456d64685e1SAlain Volmat "failed to stop source subdev streaming (%d)\n", ret); 457d64685e1SAlain Volmat return ret; 458d64685e1SAlain Volmat } 459d64685e1SAlain Volmat 460*03abfb7bSAlain Volmat if (inp->ved.bus_type == V4L2_MBUS_PARALLEL || 461*03abfb7bSAlain Volmat inp->ved.bus_type == V4L2_MBUS_BT656) { 462d64685e1SAlain Volmat /* Disable parallel interface */ 463d64685e1SAlain Volmat reg_clear(inp, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE); 464*03abfb7bSAlain Volmat } 465d64685e1SAlain Volmat 466d64685e1SAlain Volmat return 0; 467d64685e1SAlain Volmat } 468d64685e1SAlain Volmat 469d64685e1SAlain Volmat static const struct v4l2_subdev_pad_ops dcmipp_inp_pad_ops = { 470d64685e1SAlain Volmat .enum_mbus_code = dcmipp_inp_enum_mbus_code, 471d64685e1SAlain Volmat .enum_frame_size = dcmipp_inp_enum_frame_size, 472d64685e1SAlain Volmat .get_fmt = v4l2_subdev_get_fmt, 473d64685e1SAlain Volmat .set_fmt = dcmipp_inp_set_fmt, 474d64685e1SAlain Volmat .enable_streams = dcmipp_inp_enable_streams, 475d64685e1SAlain Volmat .disable_streams = dcmipp_inp_disable_streams, 476d64685e1SAlain Volmat }; 477d64685e1SAlain Volmat 478d64685e1SAlain Volmat static const struct v4l2_subdev_video_ops dcmipp_inp_video_ops = { 479d64685e1SAlain Volmat .s_stream = v4l2_subdev_s_stream_helper, 480d64685e1SAlain Volmat }; 481d64685e1SAlain Volmat 482d64685e1SAlain Volmat static const struct v4l2_subdev_ops dcmipp_inp_ops = { 483d64685e1SAlain Volmat .pad = &dcmipp_inp_pad_ops, 484d64685e1SAlain Volmat .video = &dcmipp_inp_video_ops, 485d64685e1SAlain Volmat }; 486d64685e1SAlain Volmat 487d64685e1SAlain Volmat static void dcmipp_inp_release(struct v4l2_subdev *sd) 488d64685e1SAlain Volmat { 489d64685e1SAlain Volmat struct dcmipp_inp_device *inp = 490d64685e1SAlain Volmat container_of(sd, struct dcmipp_inp_device, sd); 491d64685e1SAlain Volmat 492d64685e1SAlain Volmat kfree(inp); 493d64685e1SAlain Volmat } 494d64685e1SAlain Volmat 495d64685e1SAlain Volmat static const struct v4l2_subdev_internal_ops dcmipp_inp_int_ops = { 496d64685e1SAlain Volmat .init_state = dcmipp_inp_init_state, 497d64685e1SAlain Volmat .release = dcmipp_inp_release, 498d64685e1SAlain Volmat }; 499d64685e1SAlain Volmat 500d64685e1SAlain Volmat void dcmipp_inp_ent_release(struct dcmipp_ent_device *ved) 501d64685e1SAlain Volmat { 502d64685e1SAlain Volmat struct dcmipp_inp_device *inp = 503d64685e1SAlain Volmat container_of(ved, struct dcmipp_inp_device, ved); 504d64685e1SAlain Volmat 505d64685e1SAlain Volmat dcmipp_ent_sd_unregister(ved, &inp->sd); 506d64685e1SAlain Volmat } 507d64685e1SAlain Volmat 508d64685e1SAlain Volmat struct dcmipp_ent_device *dcmipp_inp_ent_init(struct device *dev, 509d64685e1SAlain Volmat const char *entity_name, 510d64685e1SAlain Volmat struct v4l2_device *v4l2_dev, 511d64685e1SAlain Volmat void __iomem *regs) 512d64685e1SAlain Volmat { 513d64685e1SAlain Volmat struct dcmipp_inp_device *inp; 514d64685e1SAlain Volmat const unsigned long pads_flag[] = { 515d64685e1SAlain Volmat MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, 516d64685e1SAlain Volmat }; 517d64685e1SAlain Volmat int ret; 518d64685e1SAlain Volmat 519d64685e1SAlain Volmat /* Allocate the inp struct */ 520d64685e1SAlain Volmat inp = kzalloc(sizeof(*inp), GFP_KERNEL); 521d64685e1SAlain Volmat if (!inp) 522d64685e1SAlain Volmat return ERR_PTR(-ENOMEM); 523d64685e1SAlain Volmat 524d64685e1SAlain Volmat inp->regs = regs; 525d64685e1SAlain Volmat 526d64685e1SAlain Volmat /* Initialize ved and sd */ 527d64685e1SAlain Volmat ret = dcmipp_ent_sd_register(&inp->ved, &inp->sd, v4l2_dev, 528d64685e1SAlain Volmat entity_name, MEDIA_ENT_F_VID_IF_BRIDGE, 529d64685e1SAlain Volmat ARRAY_SIZE(pads_flag), pads_flag, 530d64685e1SAlain Volmat &dcmipp_inp_int_ops, &dcmipp_inp_ops, 531d64685e1SAlain Volmat NULL, NULL); 532d64685e1SAlain Volmat if (ret) { 533d64685e1SAlain Volmat kfree(inp); 534d64685e1SAlain Volmat return ERR_PTR(ret); 535d64685e1SAlain Volmat } 536d64685e1SAlain Volmat 537d64685e1SAlain Volmat inp->dev = dev; 538d64685e1SAlain Volmat 539d64685e1SAlain Volmat return &inp->ved; 540d64685e1SAlain Volmat } 541