Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] v4l: Add Renesas R-Car FDP1 Driver

The FDP1 driver performs advanced de-interlacing on a memory 2 memory
based video stream, and supports conversion from YCbCr/YUV
to RGB pixel formats

Signed-off-by: Kieran Bingham <kieran+renesas@bingham.xyz>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Kieran Bingham and committed by
Mauro Carvalho Chehab
4710b752 3547d32b

+2506
+1
Documentation/media/v4l-drivers/index.rst
··· 48 48 pvrusb2 49 49 pxa_camera 50 50 radiotrack 51 + rcar-fdp1 51 52 saa7134 52 53 sh_mobile_ceu_camera 53 54 si470x
+37
Documentation/media/v4l-drivers/rcar-fdp1.rst
··· 1 + Renesas R-Car Fine Display Processor (FDP1) Driver 2 + ================================================== 3 + 4 + The R-Car FDP1 driver implements driver-specific controls as follows. 5 + 6 + ``V4L2_CID_DEINTERLACING_MODE (menu)`` 7 + The video deinterlacing mode (such as Bob, Weave, ...). The R-Car FDP1 8 + driver implements the following modes. 9 + 10 + .. flat-table:: 11 + :header-rows: 0 12 + :stub-columns: 0 13 + :widths: 1 4 14 + 15 + * - ``"Progressive" (0)`` 16 + - The input image video stream is progressive (not interlaced). No 17 + deinterlacing is performed. Apart from (optional) format and encoding 18 + conversion output frames are identical to the input frames. 19 + * - ``"Adaptive 2D/3D" (1)`` 20 + - Motion adaptive version of 2D and 3D deinterlacing. Use 3D deinterlacing 21 + in the presence of fast motion and 2D deinterlacing with diagonal 22 + interpolation otherwise. 23 + * - ``"Fixed 2D" (2)`` 24 + - The current field is scaled vertically by averaging adjacent lines to 25 + recover missing lines. This method is also known as blending or Line 26 + Averaging (LAV). 27 + * - ``"Fixed 3D" (3)`` 28 + - The previous and next fields are averaged to recover lines missing from 29 + the current field. This method is also known as Field Averaging (FAV). 30 + * - ``"Previous field" (4)`` 31 + - The current field is weaved with the previous field, i.e. the previous 32 + field is used to fill missing lines from the current field. This method 33 + is also known as weave deinterlacing. 34 + * - ``"Next field" (5)`` 35 + - The current field is weaved with the next field, i.e. the next field is 36 + used to fill missing lines from the current field. This method is also 37 + known as weave deinterlacing.
+9
MAINTAINERS
··· 7712 7712 F: drivers/media/platform/rcar-fcp.c 7713 7713 F: include/media/rcar-fcp.h 7714 7714 7715 + MEDIA DRIVERS FOR RENESAS - FDP1 7716 + M: Kieran Bingham <kieran@bingham.xyz> 7717 + L: linux-media@vger.kernel.org 7718 + L: linux-renesas-soc@vger.kernel.org 7719 + T: git git://linuxtv.org/media_tree.git 7720 + S: Supported 7721 + F: Documentation/devicetree/bindings/media/renesas,fdp1.txt 7722 + F: drivers/media/platform/rcar_fdp1.c 7723 + 7715 7724 MEDIA DRIVERS FOR RENESAS - VIN 7716 7725 M: Niklas Söderlund <niklas.soderlund@ragnatech.se> 7717 7726 L: linux-media@vger.kernel.org
+13
drivers/media/platform/Kconfig
··· 307 307 Support for the Video Engine Unit (VEU) on SuperH and 308 308 SH-Mobile SoCs. 309 309 310 + config VIDEO_RENESAS_FDP1 311 + tristate "Renesas Fine Display Processor" 312 + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA 313 + depends on ARCH_SHMOBILE || COMPILE_TEST 314 + select VIDEOBUF2_DMA_CONTIG 315 + select V4L2_MEM2MEM_DEV 316 + ---help--- 317 + This is a V4L2 driver for the Renesas Fine Display Processor 318 + providing colour space conversion, and de-interlacing features. 319 + 320 + To compile this driver as a module, choose M here: the module 321 + will be called rcar_fdp1. 322 + 310 323 config VIDEO_RENESAS_JPU 311 324 tristate "Renesas JPEG Processing Unit" 312 325 depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+1
drivers/media/platform/Makefile
··· 48 48 obj-$(CONFIG_SOC_CAMERA) += soc_camera/ 49 49 50 50 obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o 51 + obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o 51 52 obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o 52 53 obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ 53 54
+2445
drivers/media/platform/rcar_fdp1.c
··· 1 + /* 2 + * Renesas RCar Fine Display Processor 3 + * 4 + * Video format converter and frame deinterlacer device. 5 + * 6 + * Author: Kieran Bingham, <kieran@bingham.xyz> 7 + * Copyright (c) 2016 Renesas Electronics Corporation. 8 + * 9 + * This code is developed and inspired from the vim2m, rcar_jpu, 10 + * m2m-deinterlace, and vsp1 drivers. 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License as published by the 14 + * Free Software Foundation; either version 2 of the 15 + * License, or (at your option) any later version 16 + */ 17 + 18 + #include <linux/clk.h> 19 + #include <linux/delay.h> 20 + #include <linux/dma-mapping.h> 21 + #include <linux/fs.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/module.h> 24 + #include <linux/of.h> 25 + #include <linux/of_device.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/pm_runtime.h> 28 + #include <linux/sched.h> 29 + #include <linux/slab.h> 30 + #include <linux/timer.h> 31 + #include <media/rcar-fcp.h> 32 + #include <media/v4l2-ctrls.h> 33 + #include <media/v4l2-device.h> 34 + #include <media/v4l2-event.h> 35 + #include <media/v4l2-ioctl.h> 36 + #include <media/v4l2-mem2mem.h> 37 + #include <media/videobuf2-dma-contig.h> 38 + 39 + static unsigned int debug; 40 + module_param(debug, uint, 0644); 41 + MODULE_PARM_DESC(debug, "activate debug info"); 42 + 43 + /* Minimum and maximum frame width/height */ 44 + #define FDP1_MIN_W 80U 45 + #define FDP1_MIN_H 80U 46 + 47 + #define FDP1_MAX_W 3840U 48 + #define FDP1_MAX_H 2160U 49 + 50 + #define FDP1_MAX_PLANES 3U 51 + #define FDP1_MAX_STRIDE 8190U 52 + 53 + /* Flags that indicate a format can be used for capture/output */ 54 + #define FDP1_CAPTURE BIT(0) 55 + #define FDP1_OUTPUT BIT(1) 56 + 57 + #define DRIVER_NAME "rcar_fdp1" 58 + 59 + /* Number of Job's to have available on the processing queue */ 60 + #define FDP1_NUMBER_JOBS 8 61 + 62 + #define dprintk(fdp1, fmt, arg...) \ 63 + v4l2_dbg(1, debug, &fdp1->v4l2_dev, "%s: " fmt, __func__, ## arg) 64 + 65 + /* 66 + * FDP1 registers and bits 67 + */ 68 + 69 + /* FDP1 start register - Imm */ 70 + #define FD1_CTL_CMD 0x0000 71 + #define FD1_CTL_CMD_STRCMD BIT(0) 72 + 73 + /* Sync generator register - Imm */ 74 + #define FD1_CTL_SGCMD 0x0004 75 + #define FD1_CTL_SGCMD_SGEN BIT(0) 76 + 77 + /* Register set end register - Imm */ 78 + #define FD1_CTL_REGEND 0x0008 79 + #define FD1_CTL_REGEND_REGEND BIT(0) 80 + 81 + /* Channel activation register - Vupdt */ 82 + #define FD1_CTL_CHACT 0x000c 83 + #define FD1_CTL_CHACT_SMW BIT(9) 84 + #define FD1_CTL_CHACT_WR BIT(8) 85 + #define FD1_CTL_CHACT_SMR BIT(3) 86 + #define FD1_CTL_CHACT_RD2 BIT(2) 87 + #define FD1_CTL_CHACT_RD1 BIT(1) 88 + #define FD1_CTL_CHACT_RD0 BIT(0) 89 + 90 + /* Operation Mode Register - Vupdt */ 91 + #define FD1_CTL_OPMODE 0x0010 92 + #define FD1_CTL_OPMODE_PRG BIT(4) 93 + #define FD1_CTL_OPMODE_VIMD_INTERRUPT (0 << 0) 94 + #define FD1_CTL_OPMODE_VIMD_BESTEFFORT (1 << 0) 95 + #define FD1_CTL_OPMODE_VIMD_NOINTERRUPT (2 << 0) 96 + 97 + #define FD1_CTL_VPERIOD 0x0014 98 + #define FD1_CTL_CLKCTRL 0x0018 99 + #define FD1_CTL_CLKCTRL_CSTP_N BIT(0) 100 + 101 + /* Software reset register */ 102 + #define FD1_CTL_SRESET 0x001c 103 + #define FD1_CTL_SRESET_SRST BIT(0) 104 + 105 + /* Control status register (V-update-status) */ 106 + #define FD1_CTL_STATUS 0x0024 107 + #define FD1_CTL_STATUS_VINT_CNT_MASK GENMASK(31, 16) 108 + #define FD1_CTL_STATUS_VINT_CNT_SHIFT 16 109 + #define FD1_CTL_STATUS_SGREGSET BIT(10) 110 + #define FD1_CTL_STATUS_SGVERR BIT(9) 111 + #define FD1_CTL_STATUS_SGFREND BIT(8) 112 + #define FD1_CTL_STATUS_BSY BIT(0) 113 + 114 + #define FD1_CTL_VCYCLE_STAT 0x0028 115 + 116 + /* Interrupt enable register */ 117 + #define FD1_CTL_IRQENB 0x0038 118 + /* Interrupt status register */ 119 + #define FD1_CTL_IRQSTA 0x003c 120 + /* Interrupt control register */ 121 + #define FD1_CTL_IRQFSET 0x0040 122 + 123 + /* Common IRQ Bit settings */ 124 + #define FD1_CTL_IRQ_VERE BIT(16) 125 + #define FD1_CTL_IRQ_VINTE BIT(4) 126 + #define FD1_CTL_IRQ_FREE BIT(0) 127 + #define FD1_CTL_IRQ_MASK (FD1_CTL_IRQ_VERE | \ 128 + FD1_CTL_IRQ_VINTE | \ 129 + FD1_CTL_IRQ_FREE) 130 + 131 + /* RPF */ 132 + #define FD1_RPF_SIZE 0x0060 133 + #define FD1_RPF_SIZE_MASK GENMASK(12, 0) 134 + #define FD1_RPF_SIZE_H_SHIFT 16 135 + #define FD1_RPF_SIZE_V_SHIFT 0 136 + 137 + #define FD1_RPF_FORMAT 0x0064 138 + #define FD1_RPF_FORMAT_CIPM BIT(16) 139 + #define FD1_RPF_FORMAT_RSPYCS BIT(13) 140 + #define FD1_RPF_FORMAT_RSPUVS BIT(12) 141 + #define FD1_RPF_FORMAT_CF BIT(8) 142 + 143 + #define FD1_RPF_PSTRIDE 0x0068 144 + #define FD1_RPF_PSTRIDE_Y_SHIFT 16 145 + #define FD1_RPF_PSTRIDE_C_SHIFT 0 146 + 147 + /* RPF0 Source Component Y Address register */ 148 + #define FD1_RPF0_ADDR_Y 0x006c 149 + 150 + /* RPF1 Current Picture Registers */ 151 + #define FD1_RPF1_ADDR_Y 0x0078 152 + #define FD1_RPF1_ADDR_C0 0x007c 153 + #define FD1_RPF1_ADDR_C1 0x0080 154 + 155 + /* RPF2 next picture register */ 156 + #define FD1_RPF2_ADDR_Y 0x0084 157 + 158 + #define FD1_RPF_SMSK_ADDR 0x0090 159 + #define FD1_RPF_SWAP 0x0094 160 + 161 + /* WPF */ 162 + #define FD1_WPF_FORMAT 0x00c0 163 + #define FD1_WPF_FORMAT_PDV_SHIFT 24 164 + #define FD1_WPF_FORMAT_FCNL BIT(20) 165 + #define FD1_WPF_FORMAT_WSPYCS BIT(15) 166 + #define FD1_WPF_FORMAT_WSPUVS BIT(14) 167 + #define FD1_WPF_FORMAT_WRTM_601_16 (0 << 9) 168 + #define FD1_WPF_FORMAT_WRTM_601_0 (1 << 9) 169 + #define FD1_WPF_FORMAT_WRTM_709_16 (2 << 9) 170 + #define FD1_WPF_FORMAT_CSC BIT(8) 171 + 172 + #define FD1_WPF_RNDCTL 0x00c4 173 + #define FD1_WPF_RNDCTL_CBRM BIT(28) 174 + #define FD1_WPF_RNDCTL_CLMD_NOCLIP (0 << 12) 175 + #define FD1_WPF_RNDCTL_CLMD_CLIP_16_235 (1 << 12) 176 + #define FD1_WPF_RNDCTL_CLMD_CLIP_1_254 (2 << 12) 177 + 178 + #define FD1_WPF_PSTRIDE 0x00c8 179 + #define FD1_WPF_PSTRIDE_Y_SHIFT 16 180 + #define FD1_WPF_PSTRIDE_C_SHIFT 0 181 + 182 + /* WPF Destination picture */ 183 + #define FD1_WPF_ADDR_Y 0x00cc 184 + #define FD1_WPF_ADDR_C0 0x00d0 185 + #define FD1_WPF_ADDR_C1 0x00d4 186 + #define FD1_WPF_SWAP 0x00d8 187 + #define FD1_WPF_SWAP_OSWAP_SHIFT 0 188 + #define FD1_WPF_SWAP_SSWAP_SHIFT 4 189 + 190 + /* WPF/RPF Common */ 191 + #define FD1_RWPF_SWAP_BYTE BIT(0) 192 + #define FD1_RWPF_SWAP_WORD BIT(1) 193 + #define FD1_RWPF_SWAP_LWRD BIT(2) 194 + #define FD1_RWPF_SWAP_LLWD BIT(3) 195 + 196 + /* IPC */ 197 + #define FD1_IPC_MODE 0x0100 198 + #define FD1_IPC_MODE_DLI BIT(8) 199 + #define FD1_IPC_MODE_DIM_ADAPT2D3D (0 << 0) 200 + #define FD1_IPC_MODE_DIM_FIXED2D (1 << 0) 201 + #define FD1_IPC_MODE_DIM_FIXED3D (2 << 0) 202 + #define FD1_IPC_MODE_DIM_PREVFIELD (3 << 0) 203 + #define FD1_IPC_MODE_DIM_NEXTFIELD (4 << 0) 204 + 205 + #define FD1_IPC_SMSK_THRESH 0x0104 206 + #define FD1_IPC_SMSK_THRESH_CONST 0x00010002 207 + 208 + #define FD1_IPC_COMB_DET 0x0108 209 + #define FD1_IPC_COMB_DET_CONST 0x00200040 210 + 211 + #define FD1_IPC_MOTDEC 0x010c 212 + #define FD1_IPC_MOTDEC_CONST 0x00008020 213 + 214 + /* DLI registers */ 215 + #define FD1_IPC_DLI_BLEND 0x0120 216 + #define FD1_IPC_DLI_BLEND_CONST 0x0080ff02 217 + 218 + #define FD1_IPC_DLI_HGAIN 0x0124 219 + #define FD1_IPC_DLI_HGAIN_CONST 0x001000ff 220 + 221 + #define FD1_IPC_DLI_SPRS 0x0128 222 + #define FD1_IPC_DLI_SPRS_CONST 0x009004ff 223 + 224 + #define FD1_IPC_DLI_ANGLE 0x012c 225 + #define FD1_IPC_DLI_ANGLE_CONST 0x0004080c 226 + 227 + #define FD1_IPC_DLI_ISOPIX0 0x0130 228 + #define FD1_IPC_DLI_ISOPIX0_CONST 0xff10ff10 229 + 230 + #define FD1_IPC_DLI_ISOPIX1 0x0134 231 + #define FD1_IPC_DLI_ISOPIX1_CONST 0x0000ff10 232 + 233 + /* Sensor registers */ 234 + #define FD1_IPC_SENSOR_TH0 0x0140 235 + #define FD1_IPC_SENSOR_TH0_CONST 0x20208080 236 + 237 + #define FD1_IPC_SENSOR_TH1 0x0144 238 + #define FD1_IPC_SENSOR_TH1_CONST 0 239 + 240 + #define FD1_IPC_SENSOR_CTL0 0x0170 241 + #define FD1_IPC_SENSOR_CTL0_CONST 0x00002201 242 + 243 + #define FD1_IPC_SENSOR_CTL1 0x0174 244 + #define FD1_IPC_SENSOR_CTL1_CONST 0 245 + 246 + #define FD1_IPC_SENSOR_CTL2 0x0178 247 + #define FD1_IPC_SENSOR_CTL2_X_SHIFT 16 248 + #define FD1_IPC_SENSOR_CTL2_Y_SHIFT 0 249 + 250 + #define FD1_IPC_SENSOR_CTL3 0x017c 251 + #define FD1_IPC_SENSOR_CTL3_0_SHIFT 16 252 + #define FD1_IPC_SENSOR_CTL3_1_SHIFT 0 253 + 254 + /* Line memory pixel number register */ 255 + #define FD1_IPC_LMEM 0x01e0 256 + #define FD1_IPC_LMEM_LINEAR 1024 257 + #define FD1_IPC_LMEM_TILE 960 258 + 259 + /* Internal Data (HW Version) */ 260 + #define FD1_IP_INTDATA 0x0800 261 + #define FD1_IP_H3 0x02010101 262 + #define FD1_IP_M3W 0x02010202 263 + 264 + /* LUTs */ 265 + #define FD1_LUT_DIF_ADJ 0x1000 266 + #define FD1_LUT_SAD_ADJ 0x1400 267 + #define FD1_LUT_BLD_GAIN 0x1800 268 + #define FD1_LUT_DIF_GAIN 0x1c00 269 + #define FD1_LUT_MDET 0x2000 270 + 271 + /** 272 + * struct fdp1_fmt - The FDP1 internal format data 273 + * @fourcc: the fourcc code, to match the V4L2 API 274 + * @bpp: bits per pixel per plane 275 + * @num_planes: number of planes 276 + * @hsub: horizontal subsampling factor 277 + * @vsub: vertical subsampling factor 278 + * @fmt: 7-bit format code for the fdp1 hardware 279 + * @swap_yc: the Y and C components are swapped (Y comes before C) 280 + * @swap_uv: the U and V components are swapped (V comes before U) 281 + * @swap: swap register control 282 + * @types: types of queue this format is applicable to 283 + */ 284 + struct fdp1_fmt { 285 + u32 fourcc; 286 + u8 bpp[3]; 287 + u8 num_planes; 288 + u8 hsub; 289 + u8 vsub; 290 + u8 fmt; 291 + bool swap_yc; 292 + bool swap_uv; 293 + u8 swap; 294 + u8 types; 295 + }; 296 + 297 + static const struct fdp1_fmt fdp1_formats[] = { 298 + /* RGB formats are only supported by the Write Pixel Formatter */ 299 + 300 + { V4L2_PIX_FMT_RGB332, { 8, 0, 0 }, 1, 1, 1, 0x00, false, false, 301 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 302 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 303 + FDP1_CAPTURE }, 304 + { V4L2_PIX_FMT_XRGB444, { 16, 0, 0 }, 1, 1, 1, 0x01, false, false, 305 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 306 + FD1_RWPF_SWAP_WORD, 307 + FDP1_CAPTURE }, 308 + { V4L2_PIX_FMT_XRGB555, { 16, 0, 0 }, 1, 1, 1, 0x04, false, false, 309 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 310 + FD1_RWPF_SWAP_WORD, 311 + FDP1_CAPTURE }, 312 + { V4L2_PIX_FMT_RGB565, { 16, 0, 0 }, 1, 1, 1, 0x06, false, false, 313 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 314 + FD1_RWPF_SWAP_WORD, 315 + FDP1_CAPTURE }, 316 + { V4L2_PIX_FMT_ABGR32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, 317 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD, 318 + FDP1_CAPTURE }, 319 + { V4L2_PIX_FMT_XBGR32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, 320 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD, 321 + FDP1_CAPTURE }, 322 + { V4L2_PIX_FMT_ARGB32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, 323 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 324 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 325 + FDP1_CAPTURE }, 326 + { V4L2_PIX_FMT_XRGB32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, 327 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 328 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 329 + FDP1_CAPTURE }, 330 + { V4L2_PIX_FMT_RGB24, { 24, 0, 0 }, 1, 1, 1, 0x15, false, false, 331 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 332 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 333 + FDP1_CAPTURE }, 334 + { V4L2_PIX_FMT_BGR24, { 24, 0, 0 }, 1, 1, 1, 0x18, false, false, 335 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 336 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 337 + FDP1_CAPTURE }, 338 + { V4L2_PIX_FMT_ARGB444, { 16, 0, 0 }, 1, 1, 1, 0x19, false, false, 339 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 340 + FD1_RWPF_SWAP_WORD, 341 + FDP1_CAPTURE }, 342 + { V4L2_PIX_FMT_ARGB555, { 16, 0, 0 }, 1, 1, 1, 0x1b, false, false, 343 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 344 + FD1_RWPF_SWAP_WORD, 345 + FDP1_CAPTURE }, 346 + 347 + /* YUV Formats are supported by Read and Write Pixel Formatters */ 348 + 349 + { V4L2_PIX_FMT_NV16M, { 8, 16, 0 }, 2, 2, 1, 0x41, false, false, 350 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 351 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 352 + FDP1_CAPTURE | FDP1_OUTPUT }, 353 + { V4L2_PIX_FMT_NV61M, { 8, 16, 0 }, 2, 2, 1, 0x41, false, true, 354 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 355 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 356 + FDP1_CAPTURE | FDP1_OUTPUT }, 357 + { V4L2_PIX_FMT_NV12M, { 8, 16, 0 }, 2, 2, 2, 0x42, false, false, 358 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 359 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 360 + FDP1_CAPTURE | FDP1_OUTPUT }, 361 + { V4L2_PIX_FMT_NV21M, { 8, 16, 0 }, 2, 2, 2, 0x42, false, true, 362 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 363 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 364 + FDP1_CAPTURE | FDP1_OUTPUT }, 365 + { V4L2_PIX_FMT_UYVY, { 16, 0, 0 }, 1, 2, 1, 0x47, false, false, 366 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 367 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 368 + FDP1_CAPTURE | FDP1_OUTPUT }, 369 + { V4L2_PIX_FMT_VYUY, { 16, 0, 0 }, 1, 2, 1, 0x47, false, true, 370 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 371 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 372 + FDP1_CAPTURE | FDP1_OUTPUT }, 373 + { V4L2_PIX_FMT_YUYV, { 16, 0, 0 }, 1, 2, 1, 0x47, true, false, 374 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 375 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 376 + FDP1_CAPTURE | FDP1_OUTPUT }, 377 + { V4L2_PIX_FMT_YVYU, { 16, 0, 0 }, 1, 2, 1, 0x47, true, true, 378 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 379 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 380 + FDP1_CAPTURE | FDP1_OUTPUT }, 381 + { V4L2_PIX_FMT_YUV444M, { 8, 8, 8 }, 3, 1, 1, 0x4a, false, false, 382 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 383 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 384 + FDP1_CAPTURE | FDP1_OUTPUT }, 385 + { V4L2_PIX_FMT_YVU444M, { 8, 8, 8 }, 3, 1, 1, 0x4a, false, true, 386 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 387 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 388 + FDP1_CAPTURE | FDP1_OUTPUT }, 389 + { V4L2_PIX_FMT_YUV422M, { 8, 8, 8 }, 3, 2, 1, 0x4b, false, false, 390 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 391 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 392 + FDP1_CAPTURE | FDP1_OUTPUT }, 393 + { V4L2_PIX_FMT_YVU422M, { 8, 8, 8 }, 3, 2, 1, 0x4b, false, true, 394 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 395 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 396 + FDP1_CAPTURE | FDP1_OUTPUT }, 397 + { V4L2_PIX_FMT_YUV420M, { 8, 8, 8 }, 3, 2, 2, 0x4c, false, false, 398 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 399 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 400 + FDP1_CAPTURE | FDP1_OUTPUT }, 401 + { V4L2_PIX_FMT_YVU420M, { 8, 8, 8 }, 3, 2, 2, 0x4c, false, true, 402 + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | 403 + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, 404 + FDP1_CAPTURE | FDP1_OUTPUT }, 405 + }; 406 + 407 + static int fdp1_fmt_is_rgb(const struct fdp1_fmt *fmt) 408 + { 409 + return fmt->fmt <= 0x1b; /* Last RGB code */ 410 + } 411 + 412 + /* 413 + * FDP1 Lookup tables range from 0...255 only 414 + * 415 + * Each table must be less than 256 entries, and all tables 416 + * are padded out to 256 entries by duplicating the last value. 417 + */ 418 + static const u8 fdp1_diff_adj[] = { 419 + 0x00, 0x24, 0x43, 0x5e, 0x76, 0x8c, 0x9e, 0xaf, 420 + 0xbd, 0xc9, 0xd4, 0xdd, 0xe4, 0xea, 0xef, 0xf3, 421 + 0xf6, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 422 + }; 423 + 424 + static const u8 fdp1_sad_adj[] = { 425 + 0x00, 0x24, 0x43, 0x5e, 0x76, 0x8c, 0x9e, 0xaf, 426 + 0xbd, 0xc9, 0xd4, 0xdd, 0xe4, 0xea, 0xef, 0xf3, 427 + 0xf6, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 428 + }; 429 + 430 + static const u8 fdp1_bld_gain[] = { 431 + 0x80, 432 + }; 433 + 434 + static const u8 fdp1_dif_gain[] = { 435 + 0x80, 436 + }; 437 + 438 + static const u8 fdp1_mdet[] = { 439 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 440 + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 441 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 442 + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 443 + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 444 + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 445 + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 446 + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 447 + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 448 + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 449 + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 450 + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 451 + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 452 + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 453 + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 454 + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 455 + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 456 + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 457 + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 458 + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 459 + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 460 + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 461 + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 462 + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 463 + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 464 + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 465 + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 466 + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 467 + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 468 + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 469 + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 470 + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 471 + }; 472 + 473 + /* Per-queue, driver-specific private data */ 474 + struct fdp1_q_data { 475 + const struct fdp1_fmt *fmt; 476 + struct v4l2_pix_format_mplane format; 477 + 478 + unsigned int vsize; 479 + unsigned int stride_y; 480 + unsigned int stride_c; 481 + }; 482 + 483 + static const struct fdp1_fmt *fdp1_find_format(u32 pixelformat) 484 + { 485 + const struct fdp1_fmt *fmt; 486 + unsigned int i; 487 + 488 + for (i = 0; i < ARRAY_SIZE(fdp1_formats); i++) { 489 + fmt = &fdp1_formats[i]; 490 + if (fmt->fourcc == pixelformat) 491 + return fmt; 492 + } 493 + 494 + return NULL; 495 + } 496 + 497 + enum fdp1_deint_mode { 498 + FDP1_PROGRESSIVE = 0, /* Must be zero when !deinterlacing */ 499 + FDP1_ADAPT2D3D, 500 + FDP1_FIXED2D, 501 + FDP1_FIXED3D, 502 + FDP1_PREVFIELD, 503 + FDP1_NEXTFIELD, 504 + }; 505 + 506 + #define FDP1_DEINT_MODE_USES_NEXT(mode) \ 507 + (mode == FDP1_ADAPT2D3D || \ 508 + mode == FDP1_FIXED3D || \ 509 + mode == FDP1_NEXTFIELD) 510 + 511 + #define FDP1_DEINT_MODE_USES_PREV(mode) \ 512 + (mode == FDP1_ADAPT2D3D || \ 513 + mode == FDP1_FIXED3D || \ 514 + mode == FDP1_PREVFIELD) 515 + 516 + /* 517 + * FDP1 operates on potentially 3 fields, which are tracked 518 + * from the VB buffers using this context structure. 519 + * Will always be a field or a full frame, never two fields. 520 + */ 521 + struct fdp1_field_buffer { 522 + struct vb2_v4l2_buffer *vb; 523 + dma_addr_t addrs[3]; 524 + 525 + /* Should be NONE:TOP:BOTTOM only */ 526 + enum v4l2_field field; 527 + 528 + /* Flag to indicate this is the last field in the vb */ 529 + bool last_field; 530 + 531 + /* Buffer queue lists */ 532 + struct list_head list; 533 + }; 534 + 535 + struct fdp1_buffer { 536 + struct v4l2_m2m_buffer m2m_buf; 537 + struct fdp1_field_buffer fields[2]; 538 + unsigned int num_fields; 539 + }; 540 + 541 + static inline struct fdp1_buffer *to_fdp1_buffer(struct vb2_v4l2_buffer *vb) 542 + { 543 + return container_of(vb, struct fdp1_buffer, m2m_buf.vb); 544 + } 545 + 546 + struct fdp1_job { 547 + struct fdp1_field_buffer *previous; 548 + struct fdp1_field_buffer *active; 549 + struct fdp1_field_buffer *next; 550 + struct fdp1_field_buffer *dst; 551 + 552 + /* A job can only be on one list at a time */ 553 + struct list_head list; 554 + }; 555 + 556 + struct fdp1_dev { 557 + struct v4l2_device v4l2_dev; 558 + struct video_device vfd; 559 + 560 + struct mutex dev_mutex; 561 + spinlock_t irqlock; 562 + spinlock_t device_process_lock; 563 + 564 + void __iomem *regs; 565 + unsigned int irq; 566 + struct device *dev; 567 + 568 + /* Job Queues */ 569 + struct fdp1_job jobs[FDP1_NUMBER_JOBS]; 570 + struct list_head free_job_list; 571 + struct list_head queued_job_list; 572 + struct list_head hw_job_list; 573 + 574 + unsigned int clk_rate; 575 + 576 + struct rcar_fcp_device *fcp; 577 + struct v4l2_m2m_dev *m2m_dev; 578 + }; 579 + 580 + struct fdp1_ctx { 581 + struct v4l2_fh fh; 582 + struct fdp1_dev *fdp1; 583 + 584 + struct v4l2_ctrl_handler hdl; 585 + unsigned int sequence; 586 + 587 + /* Processed buffers in this transaction */ 588 + u8 num_processed; 589 + 590 + /* Transaction length (i.e. how many buffers per transaction) */ 591 + u32 translen; 592 + 593 + /* Abort requested by m2m */ 594 + int aborting; 595 + 596 + /* Deinterlace processing mode */ 597 + enum fdp1_deint_mode deint_mode; 598 + 599 + /* 600 + * Adaptive 2D/3D mode uses a shared mask 601 + * This is allocated at streamon, if the ADAPT2D3D mode 602 + * is requested 603 + */ 604 + unsigned int smsk_size; 605 + dma_addr_t smsk_addr[2]; 606 + void *smsk_cpu; 607 + 608 + /* Capture pipeline, can specify an alpha value 609 + * for supported formats. 0-255 only 610 + */ 611 + unsigned char alpha; 612 + 613 + /* Source and destination queue data */ 614 + struct fdp1_q_data out_q; /* HW Source */ 615 + struct fdp1_q_data cap_q; /* HW Destination */ 616 + 617 + /* 618 + * Field Queues 619 + * Interlaced fields are used on 3 occasions, and tracked in this list. 620 + * 621 + * V4L2 Buffers are tracked inside the fdp1_buffer 622 + * and released when the last 'field' completes 623 + */ 624 + struct list_head fields_queue; 625 + unsigned int buffers_queued; 626 + 627 + /* 628 + * For de-interlacing we need to track our previous buffer 629 + * while preparing our job lists. 630 + */ 631 + struct fdp1_field_buffer *previous; 632 + }; 633 + 634 + static inline struct fdp1_ctx *fh_to_ctx(struct v4l2_fh *fh) 635 + { 636 + return container_of(fh, struct fdp1_ctx, fh); 637 + } 638 + 639 + static struct fdp1_q_data *get_q_data(struct fdp1_ctx *ctx, 640 + enum v4l2_buf_type type) 641 + { 642 + if (V4L2_TYPE_IS_OUTPUT(type)) 643 + return &ctx->out_q; 644 + else 645 + return &ctx->cap_q; 646 + } 647 + 648 + /* 649 + * list_remove_job: Take the first item off the specified job list 650 + * 651 + * Returns: pointer to a job, or NULL if the list is empty. 652 + */ 653 + static struct fdp1_job *list_remove_job(struct fdp1_dev *fdp1, 654 + struct list_head *list) 655 + { 656 + struct fdp1_job *job; 657 + unsigned long flags; 658 + 659 + spin_lock_irqsave(&fdp1->irqlock, flags); 660 + job = list_first_entry_or_null(list, struct fdp1_job, list); 661 + if (job) 662 + list_del(&job->list); 663 + spin_unlock_irqrestore(&fdp1->irqlock, flags); 664 + 665 + return job; 666 + } 667 + 668 + /* 669 + * list_add_job: Add a job to the specified job list 670 + * 671 + * Returns: void - always succeeds 672 + */ 673 + static void list_add_job(struct fdp1_dev *fdp1, 674 + struct list_head *list, 675 + struct fdp1_job *job) 676 + { 677 + unsigned long flags; 678 + 679 + spin_lock_irqsave(&fdp1->irqlock, flags); 680 + list_add_tail(&job->list, list); 681 + spin_unlock_irqrestore(&fdp1->irqlock, flags); 682 + } 683 + 684 + static struct fdp1_job *fdp1_job_alloc(struct fdp1_dev *fdp1) 685 + { 686 + return list_remove_job(fdp1, &fdp1->free_job_list); 687 + } 688 + 689 + static void fdp1_job_free(struct fdp1_dev *fdp1, struct fdp1_job *job) 690 + { 691 + /* Ensure that all residue from previous jobs is gone */ 692 + memset(job, 0, sizeof(struct fdp1_job)); 693 + 694 + list_add_job(fdp1, &fdp1->free_job_list, job); 695 + } 696 + 697 + static void queue_job(struct fdp1_dev *fdp1, struct fdp1_job *job) 698 + { 699 + list_add_job(fdp1, &fdp1->queued_job_list, job); 700 + } 701 + 702 + static struct fdp1_job *get_queued_job(struct fdp1_dev *fdp1) 703 + { 704 + return list_remove_job(fdp1, &fdp1->queued_job_list); 705 + } 706 + 707 + static void queue_hw_job(struct fdp1_dev *fdp1, struct fdp1_job *job) 708 + { 709 + list_add_job(fdp1, &fdp1->hw_job_list, job); 710 + } 711 + 712 + static struct fdp1_job *get_hw_queued_job(struct fdp1_dev *fdp1) 713 + { 714 + return list_remove_job(fdp1, &fdp1->hw_job_list); 715 + } 716 + 717 + /* 718 + * Buffer lists handling 719 + */ 720 + static void fdp1_field_complete(struct fdp1_ctx *ctx, 721 + struct fdp1_field_buffer *fbuf) 722 + { 723 + /* job->previous may be on the first field */ 724 + if (!fbuf) 725 + return; 726 + 727 + if (fbuf->last_field) 728 + v4l2_m2m_buf_done(fbuf->vb, VB2_BUF_STATE_DONE); 729 + } 730 + 731 + static void fdp1_queue_field(struct fdp1_ctx *ctx, 732 + struct fdp1_field_buffer *fbuf) 733 + { 734 + unsigned long flags; 735 + 736 + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); 737 + list_add_tail(&fbuf->list, &ctx->fields_queue); 738 + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); 739 + 740 + ctx->buffers_queued++; 741 + } 742 + 743 + static struct fdp1_field_buffer *fdp1_dequeue_field(struct fdp1_ctx *ctx) 744 + { 745 + struct fdp1_field_buffer *fbuf; 746 + unsigned long flags; 747 + 748 + ctx->buffers_queued--; 749 + 750 + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); 751 + fbuf = list_first_entry_or_null(&ctx->fields_queue, 752 + struct fdp1_field_buffer, list); 753 + if (fbuf) 754 + list_del(&fbuf->list); 755 + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); 756 + 757 + return fbuf; 758 + } 759 + 760 + /* 761 + * Return the next field in the queue - or NULL, 762 + * without removing the item from the list 763 + */ 764 + static struct fdp1_field_buffer *fdp1_peek_queued_field(struct fdp1_ctx *ctx) 765 + { 766 + struct fdp1_field_buffer *fbuf; 767 + unsigned long flags; 768 + 769 + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); 770 + fbuf = list_first_entry_or_null(&ctx->fields_queue, 771 + struct fdp1_field_buffer, list); 772 + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); 773 + 774 + return fbuf; 775 + } 776 + 777 + static u32 fdp1_read(struct fdp1_dev *fdp1, unsigned int reg) 778 + { 779 + u32 value = ioread32(fdp1->regs + reg); 780 + 781 + if (debug >= 2) 782 + dprintk(fdp1, "Read 0x%08x from 0x%04x\n", value, reg); 783 + 784 + return value; 785 + } 786 + 787 + static void fdp1_write(struct fdp1_dev *fdp1, u32 val, unsigned int reg) 788 + { 789 + if (debug >= 2) 790 + dprintk(fdp1, "Write 0x%08x to 0x%04x\n", val, reg); 791 + 792 + iowrite32(val, fdp1->regs + reg); 793 + } 794 + 795 + /* IPC registers are to be programmed with constant values */ 796 + static void fdp1_set_ipc_dli(struct fdp1_ctx *ctx) 797 + { 798 + struct fdp1_dev *fdp1 = ctx->fdp1; 799 + 800 + fdp1_write(fdp1, FD1_IPC_SMSK_THRESH_CONST, FD1_IPC_SMSK_THRESH); 801 + fdp1_write(fdp1, FD1_IPC_COMB_DET_CONST, FD1_IPC_COMB_DET); 802 + fdp1_write(fdp1, FD1_IPC_MOTDEC_CONST, FD1_IPC_MOTDEC); 803 + 804 + fdp1_write(fdp1, FD1_IPC_DLI_BLEND_CONST, FD1_IPC_DLI_BLEND); 805 + fdp1_write(fdp1, FD1_IPC_DLI_HGAIN_CONST, FD1_IPC_DLI_HGAIN); 806 + fdp1_write(fdp1, FD1_IPC_DLI_SPRS_CONST, FD1_IPC_DLI_SPRS); 807 + fdp1_write(fdp1, FD1_IPC_DLI_ANGLE_CONST, FD1_IPC_DLI_ANGLE); 808 + fdp1_write(fdp1, FD1_IPC_DLI_ISOPIX0_CONST, FD1_IPC_DLI_ISOPIX0); 809 + fdp1_write(fdp1, FD1_IPC_DLI_ISOPIX1_CONST, FD1_IPC_DLI_ISOPIX1); 810 + } 811 + 812 + 813 + static void fdp1_set_ipc_sensor(struct fdp1_ctx *ctx) 814 + { 815 + struct fdp1_dev *fdp1 = ctx->fdp1; 816 + struct fdp1_q_data *src_q_data = &ctx->out_q; 817 + unsigned int x0, x1; 818 + unsigned int hsize = src_q_data->format.width; 819 + unsigned int vsize = src_q_data->format.height; 820 + 821 + x0 = hsize / 3; 822 + x1 = 2 * hsize / 3; 823 + 824 + fdp1_write(fdp1, FD1_IPC_SENSOR_TH0_CONST, FD1_IPC_SENSOR_TH0); 825 + fdp1_write(fdp1, FD1_IPC_SENSOR_TH1_CONST, FD1_IPC_SENSOR_TH1); 826 + fdp1_write(fdp1, FD1_IPC_SENSOR_CTL0_CONST, FD1_IPC_SENSOR_CTL0); 827 + fdp1_write(fdp1, FD1_IPC_SENSOR_CTL1_CONST, FD1_IPC_SENSOR_CTL1); 828 + 829 + fdp1_write(fdp1, ((hsize - 1) << FD1_IPC_SENSOR_CTL2_X_SHIFT) | 830 + ((vsize - 1) << FD1_IPC_SENSOR_CTL2_Y_SHIFT), 831 + FD1_IPC_SENSOR_CTL2); 832 + 833 + fdp1_write(fdp1, (x0 << FD1_IPC_SENSOR_CTL3_0_SHIFT) | 834 + (x1 << FD1_IPC_SENSOR_CTL3_1_SHIFT), 835 + FD1_IPC_SENSOR_CTL3); 836 + } 837 + 838 + /* 839 + * fdp1_write_lut: Write a padded LUT to the hw 840 + * 841 + * FDP1 uses constant data for de-interlacing processing, 842 + * with large tables. These hardware tables are all 256 bytes 843 + * long, however they often contain repeated data at the end. 844 + * 845 + * The last byte of the table is written to all remaining entries. 846 + */ 847 + static void fdp1_write_lut(struct fdp1_dev *fdp1, const u8 *lut, 848 + unsigned int len, unsigned int base) 849 + { 850 + unsigned int i; 851 + u8 pad; 852 + 853 + /* Tables larger than the hw are clipped */ 854 + len = min(len, 256u); 855 + 856 + for (i = 0; i < len; i++) 857 + fdp1_write(fdp1, lut[i], base + (i*4)); 858 + 859 + /* Tables are padded with the last entry */ 860 + pad = lut[i-1]; 861 + 862 + for (; i < 256; i++) 863 + fdp1_write(fdp1, pad, base + (i*4)); 864 + } 865 + 866 + static void fdp1_set_lut(struct fdp1_dev *fdp1) 867 + { 868 + fdp1_write_lut(fdp1, fdp1_diff_adj, ARRAY_SIZE(fdp1_diff_adj), 869 + FD1_LUT_DIF_ADJ); 870 + fdp1_write_lut(fdp1, fdp1_sad_adj, ARRAY_SIZE(fdp1_sad_adj), 871 + FD1_LUT_SAD_ADJ); 872 + fdp1_write_lut(fdp1, fdp1_bld_gain, ARRAY_SIZE(fdp1_bld_gain), 873 + FD1_LUT_BLD_GAIN); 874 + fdp1_write_lut(fdp1, fdp1_dif_gain, ARRAY_SIZE(fdp1_dif_gain), 875 + FD1_LUT_DIF_GAIN); 876 + fdp1_write_lut(fdp1, fdp1_mdet, ARRAY_SIZE(fdp1_mdet), 877 + FD1_LUT_MDET); 878 + } 879 + 880 + static void fdp1_configure_rpf(struct fdp1_ctx *ctx, 881 + struct fdp1_job *job) 882 + { 883 + struct fdp1_dev *fdp1 = ctx->fdp1; 884 + u32 picture_size; 885 + u32 pstride; 886 + u32 format; 887 + u32 smsk_addr; 888 + 889 + struct fdp1_q_data *q_data = &ctx->out_q; 890 + 891 + /* Picture size is common to Source and Destination frames */ 892 + picture_size = (q_data->format.width << FD1_RPF_SIZE_H_SHIFT) 893 + | (q_data->vsize << FD1_RPF_SIZE_V_SHIFT); 894 + 895 + /* Strides */ 896 + pstride = q_data->stride_y << FD1_RPF_PSTRIDE_Y_SHIFT; 897 + if (q_data->format.num_planes > 1) 898 + pstride |= q_data->stride_c << FD1_RPF_PSTRIDE_C_SHIFT; 899 + 900 + /* Format control */ 901 + format = q_data->fmt->fmt; 902 + if (q_data->fmt->swap_yc) 903 + format |= FD1_RPF_FORMAT_RSPYCS; 904 + 905 + if (q_data->fmt->swap_uv) 906 + format |= FD1_RPF_FORMAT_RSPUVS; 907 + 908 + if (job->active->field == V4L2_FIELD_BOTTOM) { 909 + format |= FD1_RPF_FORMAT_CF; /* Set for Bottom field */ 910 + smsk_addr = ctx->smsk_addr[0]; 911 + } else { 912 + smsk_addr = ctx->smsk_addr[1]; 913 + } 914 + 915 + /* Deint mode is non-zero when deinterlacing */ 916 + if (ctx->deint_mode) 917 + format |= FD1_RPF_FORMAT_CIPM; 918 + 919 + fdp1_write(fdp1, format, FD1_RPF_FORMAT); 920 + fdp1_write(fdp1, q_data->fmt->swap, FD1_RPF_SWAP); 921 + fdp1_write(fdp1, picture_size, FD1_RPF_SIZE); 922 + fdp1_write(fdp1, pstride, FD1_RPF_PSTRIDE); 923 + fdp1_write(fdp1, smsk_addr, FD1_RPF_SMSK_ADDR); 924 + 925 + /* Previous Field Channel (CH0) */ 926 + if (job->previous) 927 + fdp1_write(fdp1, job->previous->addrs[0], FD1_RPF0_ADDR_Y); 928 + 929 + /* Current Field Channel (CH1) */ 930 + fdp1_write(fdp1, job->active->addrs[0], FD1_RPF1_ADDR_Y); 931 + fdp1_write(fdp1, job->active->addrs[1], FD1_RPF1_ADDR_C0); 932 + fdp1_write(fdp1, job->active->addrs[2], FD1_RPF1_ADDR_C1); 933 + 934 + /* Next Field Channel (CH2) */ 935 + if (job->next) 936 + fdp1_write(fdp1, job->next->addrs[0], FD1_RPF2_ADDR_Y); 937 + } 938 + 939 + static void fdp1_configure_wpf(struct fdp1_ctx *ctx, 940 + struct fdp1_job *job) 941 + { 942 + struct fdp1_dev *fdp1 = ctx->fdp1; 943 + struct fdp1_q_data *src_q_data = &ctx->out_q; 944 + struct fdp1_q_data *q_data = &ctx->cap_q; 945 + u32 pstride; 946 + u32 format; 947 + u32 swap; 948 + u32 rndctl; 949 + 950 + pstride = q_data->format.plane_fmt[0].bytesperline 951 + << FD1_WPF_PSTRIDE_Y_SHIFT; 952 + 953 + if (q_data->format.num_planes > 1) 954 + pstride |= q_data->format.plane_fmt[1].bytesperline 955 + << FD1_WPF_PSTRIDE_C_SHIFT; 956 + 957 + format = q_data->fmt->fmt; /* Output Format Code */ 958 + 959 + if (q_data->fmt->swap_yc) 960 + format |= FD1_WPF_FORMAT_WSPYCS; 961 + 962 + if (q_data->fmt->swap_uv) 963 + format |= FD1_WPF_FORMAT_WSPUVS; 964 + 965 + if (fdp1_fmt_is_rgb(q_data->fmt)) { 966 + /* Enable Colour Space conversion */ 967 + format |= FD1_WPF_FORMAT_CSC; 968 + 969 + /* Set WRTM */ 970 + if (src_q_data->format.ycbcr_enc == V4L2_YCBCR_ENC_709) 971 + format |= FD1_WPF_FORMAT_WRTM_709_16; 972 + else if (src_q_data->format.quantization == 973 + V4L2_QUANTIZATION_FULL_RANGE) 974 + format |= FD1_WPF_FORMAT_WRTM_601_0; 975 + else 976 + format |= FD1_WPF_FORMAT_WRTM_601_16; 977 + } 978 + 979 + /* Set an alpha value into the Pad Value */ 980 + format |= ctx->alpha << FD1_WPF_FORMAT_PDV_SHIFT; 981 + 982 + /* Determine picture rounding and clipping */ 983 + rndctl = FD1_WPF_RNDCTL_CBRM; /* Rounding Off */ 984 + rndctl |= FD1_WPF_RNDCTL_CLMD_NOCLIP; 985 + 986 + /* WPF Swap needs both ISWAP and OSWAP setting */ 987 + swap = q_data->fmt->swap << FD1_WPF_SWAP_OSWAP_SHIFT; 988 + swap |= src_q_data->fmt->swap << FD1_WPF_SWAP_SSWAP_SHIFT; 989 + 990 + fdp1_write(fdp1, format, FD1_WPF_FORMAT); 991 + fdp1_write(fdp1, rndctl, FD1_WPF_RNDCTL); 992 + fdp1_write(fdp1, swap, FD1_WPF_SWAP); 993 + fdp1_write(fdp1, pstride, FD1_WPF_PSTRIDE); 994 + 995 + fdp1_write(fdp1, job->dst->addrs[0], FD1_WPF_ADDR_Y); 996 + fdp1_write(fdp1, job->dst->addrs[1], FD1_WPF_ADDR_C0); 997 + fdp1_write(fdp1, job->dst->addrs[2], FD1_WPF_ADDR_C1); 998 + } 999 + 1000 + static void fdp1_configure_deint_mode(struct fdp1_ctx *ctx, 1001 + struct fdp1_job *job) 1002 + { 1003 + struct fdp1_dev *fdp1 = ctx->fdp1; 1004 + u32 opmode = FD1_CTL_OPMODE_VIMD_NOINTERRUPT; 1005 + u32 ipcmode = FD1_IPC_MODE_DLI; /* Always set */ 1006 + u32 channels = FD1_CTL_CHACT_WR | FD1_CTL_CHACT_RD1; /* Always on */ 1007 + 1008 + /* De-interlacing Mode */ 1009 + switch (ctx->deint_mode) { 1010 + default: 1011 + case FDP1_PROGRESSIVE: 1012 + dprintk(fdp1, "Progressive Mode\n"); 1013 + opmode |= FD1_CTL_OPMODE_PRG; 1014 + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; 1015 + break; 1016 + case FDP1_ADAPT2D3D: 1017 + dprintk(fdp1, "Adapt2D3D Mode\n"); 1018 + if (ctx->sequence == 0 || ctx->aborting) 1019 + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; 1020 + else 1021 + ipcmode |= FD1_IPC_MODE_DIM_ADAPT2D3D; 1022 + 1023 + if (ctx->sequence > 1) { 1024 + channels |= FD1_CTL_CHACT_SMW; 1025 + channels |= FD1_CTL_CHACT_RD0 | FD1_CTL_CHACT_RD2; 1026 + } 1027 + 1028 + if (ctx->sequence > 2) 1029 + channels |= FD1_CTL_CHACT_SMR; 1030 + 1031 + break; 1032 + case FDP1_FIXED3D: 1033 + dprintk(fdp1, "Fixed 3D Mode\n"); 1034 + ipcmode |= FD1_IPC_MODE_DIM_FIXED3D; 1035 + /* Except for first and last frame, enable all channels */ 1036 + if (!(ctx->sequence == 0 || ctx->aborting)) 1037 + channels |= FD1_CTL_CHACT_RD0 | FD1_CTL_CHACT_RD2; 1038 + break; 1039 + case FDP1_FIXED2D: 1040 + dprintk(fdp1, "Fixed 2D Mode\n"); 1041 + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; 1042 + /* No extra channels enabled */ 1043 + break; 1044 + case FDP1_PREVFIELD: 1045 + dprintk(fdp1, "Previous Field Mode\n"); 1046 + ipcmode |= FD1_IPC_MODE_DIM_PREVFIELD; 1047 + channels |= FD1_CTL_CHACT_RD0; /* Previous */ 1048 + break; 1049 + case FDP1_NEXTFIELD: 1050 + dprintk(fdp1, "Next Field Mode\n"); 1051 + ipcmode |= FD1_IPC_MODE_DIM_NEXTFIELD; 1052 + channels |= FD1_CTL_CHACT_RD2; /* Next */ 1053 + break; 1054 + } 1055 + 1056 + fdp1_write(fdp1, channels, FD1_CTL_CHACT); 1057 + fdp1_write(fdp1, opmode, FD1_CTL_OPMODE); 1058 + fdp1_write(fdp1, ipcmode, FD1_IPC_MODE); 1059 + } 1060 + 1061 + /* 1062 + * fdp1_device_process() - Run the hardware 1063 + * 1064 + * Configure and start the hardware to generate a single frame 1065 + * of output given our input parameters. 1066 + */ 1067 + static int fdp1_device_process(struct fdp1_ctx *ctx) 1068 + 1069 + { 1070 + struct fdp1_dev *fdp1 = ctx->fdp1; 1071 + struct fdp1_job *job; 1072 + unsigned long flags; 1073 + 1074 + spin_lock_irqsave(&fdp1->device_process_lock, flags); 1075 + 1076 + /* Get a job to process */ 1077 + job = get_queued_job(fdp1); 1078 + if (!job) { 1079 + /* 1080 + * VINT can call us to see if we can queue another job. 1081 + * If we have no work to do, we simply return. 1082 + */ 1083 + spin_unlock_irqrestore(&fdp1->device_process_lock, flags); 1084 + return 0; 1085 + } 1086 + 1087 + /* First Frame only? ... */ 1088 + fdp1_write(fdp1, FD1_CTL_CLKCTRL_CSTP_N, FD1_CTL_CLKCTRL); 1089 + 1090 + /* Set the mode, and configuration */ 1091 + fdp1_configure_deint_mode(ctx, job); 1092 + 1093 + /* DLI Static Configuration */ 1094 + fdp1_set_ipc_dli(ctx); 1095 + 1096 + /* Sensor Configuration */ 1097 + fdp1_set_ipc_sensor(ctx); 1098 + 1099 + /* Setup the source picture */ 1100 + fdp1_configure_rpf(ctx, job); 1101 + 1102 + /* Setup the destination picture */ 1103 + fdp1_configure_wpf(ctx, job); 1104 + 1105 + /* Line Memory Pixel Number Register for linear access */ 1106 + fdp1_write(fdp1, FD1_IPC_LMEM_LINEAR, FD1_IPC_LMEM); 1107 + 1108 + /* Enable Interrupts */ 1109 + fdp1_write(fdp1, FD1_CTL_IRQ_MASK, FD1_CTL_IRQENB); 1110 + 1111 + /* Finally, the Immediate Registers */ 1112 + 1113 + /* This job is now in the HW queue */ 1114 + queue_hw_job(fdp1, job); 1115 + 1116 + /* Start the command */ 1117 + fdp1_write(fdp1, FD1_CTL_CMD_STRCMD, FD1_CTL_CMD); 1118 + 1119 + /* Registers will update to HW at next VINT */ 1120 + fdp1_write(fdp1, FD1_CTL_REGEND_REGEND, FD1_CTL_REGEND); 1121 + 1122 + /* Enable VINT Generator */ 1123 + fdp1_write(fdp1, FD1_CTL_SGCMD_SGEN, FD1_CTL_SGCMD); 1124 + 1125 + spin_unlock_irqrestore(&fdp1->device_process_lock, flags); 1126 + 1127 + return 0; 1128 + } 1129 + 1130 + /* 1131 + * mem2mem callbacks 1132 + */ 1133 + 1134 + /** 1135 + * job_ready() - check whether an instance is ready to be scheduled to run 1136 + */ 1137 + static int fdp1_m2m_job_ready(void *priv) 1138 + { 1139 + struct fdp1_ctx *ctx = priv; 1140 + struct fdp1_q_data *src_q_data = &ctx->out_q; 1141 + int srcbufs = 1; 1142 + int dstbufs = 1; 1143 + 1144 + dprintk(ctx->fdp1, "+ Src: %d : Dst: %d\n", 1145 + v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), 1146 + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); 1147 + 1148 + /* One output buffer is required for each field */ 1149 + if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) 1150 + dstbufs = 2; 1151 + 1152 + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < srcbufs 1153 + || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < dstbufs) { 1154 + dprintk(ctx->fdp1, "Not enough buffers available\n"); 1155 + return 0; 1156 + } 1157 + 1158 + return 1; 1159 + } 1160 + 1161 + static void fdp1_m2m_job_abort(void *priv) 1162 + { 1163 + struct fdp1_ctx *ctx = priv; 1164 + 1165 + dprintk(ctx->fdp1, "+\n"); 1166 + 1167 + /* Will cancel the transaction in the next interrupt handler */ 1168 + ctx->aborting = 1; 1169 + 1170 + /* Immediate abort sequence */ 1171 + fdp1_write(ctx->fdp1, 0, FD1_CTL_SGCMD); 1172 + fdp1_write(ctx->fdp1, FD1_CTL_SRESET_SRST, FD1_CTL_SRESET); 1173 + } 1174 + 1175 + /* 1176 + * fdp1_prepare_job: Prepare and queue a new job for a single action of work 1177 + * 1178 + * Prepare the next field, (or frame in progressive) and an output 1179 + * buffer for the hardware to perform a single operation. 1180 + */ 1181 + static struct fdp1_job *fdp1_prepare_job(struct fdp1_ctx *ctx) 1182 + { 1183 + struct vb2_v4l2_buffer *vbuf; 1184 + struct fdp1_buffer *fbuf; 1185 + struct fdp1_dev *fdp1 = ctx->fdp1; 1186 + struct fdp1_job *job; 1187 + unsigned int buffers_required = 1; 1188 + 1189 + dprintk(fdp1, "+\n"); 1190 + 1191 + if (FDP1_DEINT_MODE_USES_NEXT(ctx->deint_mode)) 1192 + buffers_required = 2; 1193 + 1194 + if (ctx->buffers_queued < buffers_required) 1195 + return NULL; 1196 + 1197 + job = fdp1_job_alloc(fdp1); 1198 + if (!job) { 1199 + dprintk(fdp1, "No free jobs currently available\n"); 1200 + return NULL; 1201 + } 1202 + 1203 + job->active = fdp1_dequeue_field(ctx); 1204 + if (!job->active) { 1205 + /* Buffer check should prevent this ever happening */ 1206 + dprintk(fdp1, "No input buffers currently available\n"); 1207 + 1208 + fdp1_job_free(fdp1, job); 1209 + return NULL; 1210 + } 1211 + 1212 + dprintk(fdp1, "+ Buffer en-route...\n"); 1213 + 1214 + /* Source buffers have been prepared on our buffer_queue 1215 + * Prepare our Output buffer 1216 + */ 1217 + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 1218 + fbuf = to_fdp1_buffer(vbuf); 1219 + job->dst = &fbuf->fields[0]; 1220 + 1221 + job->active->vb->sequence = ctx->sequence; 1222 + job->dst->vb->sequence = ctx->sequence; 1223 + ctx->sequence++; 1224 + 1225 + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) { 1226 + job->previous = ctx->previous; 1227 + 1228 + /* Active buffer becomes the next job's previous buffer */ 1229 + ctx->previous = job->active; 1230 + } 1231 + 1232 + if (FDP1_DEINT_MODE_USES_NEXT(ctx->deint_mode)) { 1233 + /* Must be called after 'active' is dequeued */ 1234 + job->next = fdp1_peek_queued_field(ctx); 1235 + } 1236 + 1237 + /* Transfer timestamps and flags from src->dst */ 1238 + 1239 + job->dst->vb->vb2_buf.timestamp = job->active->vb->vb2_buf.timestamp; 1240 + 1241 + job->dst->vb->flags = job->active->vb->flags & 1242 + V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 1243 + 1244 + /* Ideally, the frame-end function will just 'check' to see 1245 + * if there are more jobs instead 1246 + */ 1247 + ctx->translen++; 1248 + 1249 + /* Finally, Put this job on the processing queue */ 1250 + queue_job(fdp1, job); 1251 + 1252 + dprintk(fdp1, "Job Queued translen = %d\n", ctx->translen); 1253 + 1254 + return job; 1255 + } 1256 + 1257 + /* fdp1_m2m_device_run() - prepares and starts the device for an M2M task 1258 + * 1259 + * A single input buffer is taken and serialised into our fdp1_buffer 1260 + * queue. The queue is then processed to create as many jobs as possible 1261 + * from our available input. 1262 + */ 1263 + static void fdp1_m2m_device_run(void *priv) 1264 + { 1265 + struct fdp1_ctx *ctx = priv; 1266 + struct fdp1_dev *fdp1 = ctx->fdp1; 1267 + struct vb2_v4l2_buffer *src_vb; 1268 + struct fdp1_buffer *buf; 1269 + unsigned int i; 1270 + 1271 + dprintk(fdp1, "+\n"); 1272 + 1273 + ctx->translen = 0; 1274 + 1275 + /* Get our incoming buffer of either one or two fields, or one frame */ 1276 + src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 1277 + buf = to_fdp1_buffer(src_vb); 1278 + 1279 + for (i = 0; i < buf->num_fields; i++) { 1280 + struct fdp1_field_buffer *fbuf = &buf->fields[i]; 1281 + 1282 + fdp1_queue_field(ctx, fbuf); 1283 + dprintk(fdp1, "Queued Buffer [%d] last_field:%d\n", 1284 + i, fbuf->last_field); 1285 + } 1286 + 1287 + /* Queue as many jobs as our data provides for */ 1288 + while (fdp1_prepare_job(ctx)) 1289 + ; 1290 + 1291 + if (ctx->translen == 0) { 1292 + dprintk(fdp1, "No jobs were processed. M2M action complete\n"); 1293 + v4l2_m2m_job_finish(fdp1->m2m_dev, ctx->fh.m2m_ctx); 1294 + return; 1295 + } 1296 + 1297 + /* Kick the job processing action */ 1298 + fdp1_device_process(ctx); 1299 + } 1300 + 1301 + /* 1302 + * device_frame_end: 1303 + * 1304 + * Handles the M2M level after a buffer completion event. 1305 + */ 1306 + static void device_frame_end(struct fdp1_dev *fdp1, 1307 + enum vb2_buffer_state state) 1308 + { 1309 + struct fdp1_ctx *ctx; 1310 + unsigned long flags; 1311 + struct fdp1_job *job = get_hw_queued_job(fdp1); 1312 + 1313 + dprintk(fdp1, "+\n"); 1314 + 1315 + ctx = v4l2_m2m_get_curr_priv(fdp1->m2m_dev); 1316 + 1317 + if (ctx == NULL) { 1318 + v4l2_err(&fdp1->v4l2_dev, 1319 + "Instance released before the end of transaction\n"); 1320 + return; 1321 + } 1322 + 1323 + ctx->num_processed++; 1324 + 1325 + /* 1326 + * fdp1_field_complete will call buf_done only when the last vb2_buffer 1327 + * reference is complete 1328 + */ 1329 + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) 1330 + fdp1_field_complete(ctx, job->previous); 1331 + else 1332 + fdp1_field_complete(ctx, job->active); 1333 + 1334 + spin_lock_irqsave(&fdp1->irqlock, flags); 1335 + v4l2_m2m_buf_done(job->dst->vb, state); 1336 + job->dst = NULL; 1337 + spin_unlock_irqrestore(&fdp1->irqlock, flags); 1338 + 1339 + /* Move this job back to the free job list */ 1340 + fdp1_job_free(fdp1, job); 1341 + 1342 + dprintk(fdp1, "curr_ctx->num_processed %d curr_ctx->translen %d\n", 1343 + ctx->num_processed, ctx->translen); 1344 + 1345 + if (ctx->num_processed == ctx->translen || 1346 + ctx->aborting) { 1347 + dprintk(ctx->fdp1, "Finishing transaction\n"); 1348 + ctx->num_processed = 0; 1349 + v4l2_m2m_job_finish(fdp1->m2m_dev, ctx->fh.m2m_ctx); 1350 + } else { 1351 + /* 1352 + * For pipelined performance support, this would 1353 + * be called from a VINT handler 1354 + */ 1355 + fdp1_device_process(ctx); 1356 + } 1357 + } 1358 + 1359 + /* 1360 + * video ioctls 1361 + */ 1362 + static int fdp1_vidioc_querycap(struct file *file, void *priv, 1363 + struct v4l2_capability *cap) 1364 + { 1365 + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); 1366 + strlcpy(cap->card, DRIVER_NAME, sizeof(cap->card)); 1367 + snprintf(cap->bus_info, sizeof(cap->bus_info), 1368 + "platform:%s", DRIVER_NAME); 1369 + return 0; 1370 + } 1371 + 1372 + static int fdp1_enum_fmt(struct v4l2_fmtdesc *f, u32 type) 1373 + { 1374 + unsigned int i, num; 1375 + 1376 + num = 0; 1377 + 1378 + for (i = 0; i < ARRAY_SIZE(fdp1_formats); ++i) { 1379 + if (fdp1_formats[i].types & type) { 1380 + if (num == f->index) 1381 + break; 1382 + ++num; 1383 + } 1384 + } 1385 + 1386 + /* Format not found */ 1387 + if (i >= ARRAY_SIZE(fdp1_formats)) 1388 + return -EINVAL; 1389 + 1390 + /* Format found */ 1391 + f->pixelformat = fdp1_formats[i].fourcc; 1392 + 1393 + return 0; 1394 + } 1395 + 1396 + static int fdp1_enum_fmt_vid_cap(struct file *file, void *priv, 1397 + struct v4l2_fmtdesc *f) 1398 + { 1399 + return fdp1_enum_fmt(f, FDP1_CAPTURE); 1400 + } 1401 + 1402 + static int fdp1_enum_fmt_vid_out(struct file *file, void *priv, 1403 + struct v4l2_fmtdesc *f) 1404 + { 1405 + return fdp1_enum_fmt(f, FDP1_OUTPUT); 1406 + } 1407 + 1408 + static int fdp1_g_fmt(struct file *file, void *priv, struct v4l2_format *f) 1409 + { 1410 + struct fdp1_q_data *q_data; 1411 + struct fdp1_ctx *ctx = fh_to_ctx(priv); 1412 + 1413 + if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) 1414 + return -EINVAL; 1415 + 1416 + q_data = get_q_data(ctx, f->type); 1417 + f->fmt.pix_mp = q_data->format; 1418 + 1419 + return 0; 1420 + } 1421 + 1422 + static void fdp1_compute_stride(struct v4l2_pix_format_mplane *pix, 1423 + const struct fdp1_fmt *fmt) 1424 + { 1425 + unsigned int i; 1426 + 1427 + /* Compute and clamp the stride and image size. */ 1428 + for (i = 0; i < min_t(unsigned int, fmt->num_planes, 2U); ++i) { 1429 + unsigned int hsub = i > 0 ? fmt->hsub : 1; 1430 + unsigned int vsub = i > 0 ? fmt->vsub : 1; 1431 + /* From VSP : TODO: Confirm alignment limits for FDP1 */ 1432 + unsigned int align = 128; 1433 + unsigned int bpl; 1434 + 1435 + bpl = clamp_t(unsigned int, pix->plane_fmt[i].bytesperline, 1436 + pix->width / hsub * fmt->bpp[i] / 8, 1437 + round_down(FDP1_MAX_STRIDE, align)); 1438 + 1439 + pix->plane_fmt[i].bytesperline = round_up(bpl, align); 1440 + pix->plane_fmt[i].sizeimage = pix->plane_fmt[i].bytesperline 1441 + * pix->height / vsub; 1442 + 1443 + memset(pix->plane_fmt[i].reserved, 0, 1444 + sizeof(pix->plane_fmt[i].reserved)); 1445 + } 1446 + 1447 + if (fmt->num_planes == 3) { 1448 + /* The two chroma planes must have the same stride. */ 1449 + pix->plane_fmt[2].bytesperline = pix->plane_fmt[1].bytesperline; 1450 + pix->plane_fmt[2].sizeimage = pix->plane_fmt[1].sizeimage; 1451 + 1452 + memset(pix->plane_fmt[2].reserved, 0, 1453 + sizeof(pix->plane_fmt[2].reserved)); 1454 + } 1455 + } 1456 + 1457 + static void fdp1_try_fmt_output(struct fdp1_ctx *ctx, 1458 + const struct fdp1_fmt **fmtinfo, 1459 + struct v4l2_pix_format_mplane *pix) 1460 + { 1461 + const struct fdp1_fmt *fmt; 1462 + unsigned int width; 1463 + unsigned int height; 1464 + 1465 + /* Validate the pixel format to ensure the output queue supports it. */ 1466 + fmt = fdp1_find_format(pix->pixelformat); 1467 + if (!fmt || !(fmt->types & FDP1_OUTPUT)) 1468 + fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV); 1469 + 1470 + if (fmtinfo) 1471 + *fmtinfo = fmt; 1472 + 1473 + pix->pixelformat = fmt->fourcc; 1474 + pix->num_planes = fmt->num_planes; 1475 + 1476 + /* 1477 + * Progressive video and all interlaced field orders are acceptable. 1478 + * Default to V4L2_FIELD_INTERLACED. 1479 + */ 1480 + if (pix->field != V4L2_FIELD_NONE && 1481 + pix->field != V4L2_FIELD_ALTERNATE && 1482 + !V4L2_FIELD_HAS_BOTH(pix->field)) 1483 + pix->field = V4L2_FIELD_INTERLACED; 1484 + 1485 + /* 1486 + * The deinterlacer doesn't care about the colorspace, accept all values 1487 + * and default to V4L2_COLORSPACE_SMPTE170M. The YUV to RGB conversion 1488 + * at the output of the deinterlacer supports a subset of encodings and 1489 + * quantization methods and will only be available when the colorspace 1490 + * allows it. 1491 + */ 1492 + if (pix->colorspace == V4L2_COLORSPACE_DEFAULT) 1493 + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; 1494 + 1495 + /* 1496 + * Align the width and height for YUV 4:2:2 and 4:2:0 formats and clamp 1497 + * them to the supported frame size range. The height boundary are 1498 + * related to the full frame, divide them by two when the format passes 1499 + * fields in separate buffers. 1500 + */ 1501 + width = round_down(pix->width, fmt->hsub); 1502 + pix->width = clamp(width, FDP1_MIN_W, FDP1_MAX_W); 1503 + 1504 + height = round_down(pix->height, fmt->vsub); 1505 + if (pix->field == V4L2_FIELD_ALTERNATE) 1506 + pix->height = clamp(height, FDP1_MIN_H / 2, FDP1_MAX_H / 2); 1507 + else 1508 + pix->height = clamp(height, FDP1_MIN_H, FDP1_MAX_H); 1509 + 1510 + fdp1_compute_stride(pix, fmt); 1511 + } 1512 + 1513 + static void fdp1_try_fmt_capture(struct fdp1_ctx *ctx, 1514 + const struct fdp1_fmt **fmtinfo, 1515 + struct v4l2_pix_format_mplane *pix) 1516 + { 1517 + struct fdp1_q_data *src_data = &ctx->out_q; 1518 + enum v4l2_colorspace colorspace; 1519 + enum v4l2_ycbcr_encoding ycbcr_enc; 1520 + enum v4l2_quantization quantization; 1521 + const struct fdp1_fmt *fmt; 1522 + bool allow_rgb; 1523 + 1524 + /* 1525 + * Validate the pixel format. We can only accept RGB output formats if 1526 + * the input encoding and quantization are compatible with the format 1527 + * conversions supported by the hardware. The supported combinations are 1528 + * 1529 + * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_LIM_RANGE 1530 + * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_FULL_RANGE 1531 + * V4L2_YCBCR_ENC_709 + V4L2_QUANTIZATION_LIM_RANGE 1532 + */ 1533 + colorspace = src_data->format.colorspace; 1534 + 1535 + ycbcr_enc = src_data->format.ycbcr_enc; 1536 + if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) 1537 + ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace); 1538 + 1539 + quantization = src_data->format.quantization; 1540 + if (quantization == V4L2_QUANTIZATION_DEFAULT) 1541 + quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false, colorspace, 1542 + ycbcr_enc); 1543 + 1544 + allow_rgb = ycbcr_enc == V4L2_YCBCR_ENC_601 || 1545 + (ycbcr_enc == V4L2_YCBCR_ENC_709 && 1546 + quantization == V4L2_QUANTIZATION_LIM_RANGE); 1547 + 1548 + fmt = fdp1_find_format(pix->pixelformat); 1549 + if (!fmt || (!allow_rgb && fdp1_fmt_is_rgb(fmt))) 1550 + fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV); 1551 + 1552 + if (fmtinfo) 1553 + *fmtinfo = fmt; 1554 + 1555 + pix->pixelformat = fmt->fourcc; 1556 + pix->num_planes = fmt->num_planes; 1557 + pix->field = V4L2_FIELD_NONE; 1558 + 1559 + /* 1560 + * The colorspace on the capture queue is copied from the output queue 1561 + * as the hardware can't change the colorspace. It can convert YCbCr to 1562 + * RGB though, in which case the encoding and quantization are set to 1563 + * default values as anything else wouldn't make sense. 1564 + */ 1565 + pix->colorspace = src_data->format.colorspace; 1566 + pix->xfer_func = src_data->format.xfer_func; 1567 + 1568 + if (fdp1_fmt_is_rgb(fmt)) { 1569 + pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 1570 + pix->quantization = V4L2_QUANTIZATION_DEFAULT; 1571 + } else { 1572 + pix->ycbcr_enc = src_data->format.ycbcr_enc; 1573 + pix->quantization = src_data->format.quantization; 1574 + } 1575 + 1576 + /* 1577 + * The frame width is identical to the output queue, and the height is 1578 + * either doubled or identical depending on whether the output queue 1579 + * field order contains one or two fields per frame. 1580 + */ 1581 + pix->width = src_data->format.width; 1582 + if (src_data->format.field == V4L2_FIELD_ALTERNATE) 1583 + pix->height = 2 * src_data->format.height; 1584 + else 1585 + pix->height = src_data->format.height; 1586 + 1587 + fdp1_compute_stride(pix, fmt); 1588 + } 1589 + 1590 + static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f) 1591 + { 1592 + struct fdp1_ctx *ctx = fh_to_ctx(priv); 1593 + 1594 + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 1595 + fdp1_try_fmt_output(ctx, NULL, &f->fmt.pix_mp); 1596 + else 1597 + fdp1_try_fmt_capture(ctx, NULL, &f->fmt.pix_mp); 1598 + 1599 + dprintk(ctx->fdp1, "Try %s format: %4s (0x%08x) %ux%u field %u\n", 1600 + V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture", 1601 + (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat, 1602 + f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field); 1603 + 1604 + return 0; 1605 + } 1606 + 1607 + static void fdp1_set_format(struct fdp1_ctx *ctx, 1608 + struct v4l2_pix_format_mplane *pix, 1609 + enum v4l2_buf_type type) 1610 + { 1611 + struct fdp1_q_data *q_data = get_q_data(ctx, type); 1612 + const struct fdp1_fmt *fmtinfo; 1613 + 1614 + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 1615 + fdp1_try_fmt_output(ctx, &fmtinfo, pix); 1616 + else 1617 + fdp1_try_fmt_capture(ctx, &fmtinfo, pix); 1618 + 1619 + q_data->fmt = fmtinfo; 1620 + q_data->format = *pix; 1621 + 1622 + q_data->vsize = pix->height; 1623 + if (pix->field != V4L2_FIELD_NONE) 1624 + q_data->vsize /= 2; 1625 + 1626 + q_data->stride_y = pix->plane_fmt[0].bytesperline; 1627 + q_data->stride_c = pix->plane_fmt[1].bytesperline; 1628 + 1629 + /* Adjust strides for interleaved buffers */ 1630 + if (pix->field == V4L2_FIELD_INTERLACED || 1631 + pix->field == V4L2_FIELD_INTERLACED_TB || 1632 + pix->field == V4L2_FIELD_INTERLACED_BT) { 1633 + q_data->stride_y *= 2; 1634 + q_data->stride_c *= 2; 1635 + } 1636 + 1637 + /* Propagate the format from the output node to the capture node. */ 1638 + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 1639 + struct fdp1_q_data *dst_data = &ctx->cap_q; 1640 + 1641 + /* 1642 + * Copy the format, clear the per-plane bytes per line and image 1643 + * size, override the field and double the height if needed. 1644 + */ 1645 + dst_data->format = q_data->format; 1646 + memset(dst_data->format.plane_fmt, 0, 1647 + sizeof(dst_data->format.plane_fmt)); 1648 + 1649 + dst_data->format.field = V4L2_FIELD_NONE; 1650 + if (pix->field == V4L2_FIELD_ALTERNATE) 1651 + dst_data->format.height *= 2; 1652 + 1653 + fdp1_try_fmt_capture(ctx, &dst_data->fmt, &dst_data->format); 1654 + 1655 + dst_data->vsize = dst_data->format.height; 1656 + dst_data->stride_y = dst_data->format.plane_fmt[0].bytesperline; 1657 + dst_data->stride_c = dst_data->format.plane_fmt[1].bytesperline; 1658 + } 1659 + } 1660 + 1661 + static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f) 1662 + { 1663 + struct fdp1_ctx *ctx = fh_to_ctx(priv); 1664 + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; 1665 + struct vb2_queue *vq = v4l2_m2m_get_vq(m2m_ctx, f->type); 1666 + 1667 + if (vb2_is_busy(vq)) { 1668 + v4l2_err(&ctx->fdp1->v4l2_dev, "%s queue busy\n", __func__); 1669 + return -EBUSY; 1670 + } 1671 + 1672 + fdp1_set_format(ctx, &f->fmt.pix_mp, f->type); 1673 + 1674 + dprintk(ctx->fdp1, "Set %s format: %4s (0x%08x) %ux%u field %u\n", 1675 + V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture", 1676 + (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat, 1677 + f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field); 1678 + 1679 + return 0; 1680 + } 1681 + 1682 + static int fdp1_g_ctrl(struct v4l2_ctrl *ctrl) 1683 + { 1684 + struct fdp1_ctx *ctx = 1685 + container_of(ctrl->handler, struct fdp1_ctx, hdl); 1686 + struct fdp1_q_data *src_q_data = &ctx->out_q; 1687 + 1688 + switch (ctrl->id) { 1689 + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: 1690 + if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) 1691 + ctrl->val = 2; 1692 + else 1693 + ctrl->val = 1; 1694 + return 0; 1695 + } 1696 + 1697 + return 1; 1698 + } 1699 + 1700 + static int fdp1_s_ctrl(struct v4l2_ctrl *ctrl) 1701 + { 1702 + struct fdp1_ctx *ctx = 1703 + container_of(ctrl->handler, struct fdp1_ctx, hdl); 1704 + 1705 + switch (ctrl->id) { 1706 + case V4L2_CID_ALPHA_COMPONENT: 1707 + ctx->alpha = ctrl->val; 1708 + break; 1709 + 1710 + case V4L2_CID_DEINTERLACING_MODE: 1711 + ctx->deint_mode = ctrl->val; 1712 + break; 1713 + } 1714 + 1715 + return 0; 1716 + } 1717 + 1718 + static const struct v4l2_ctrl_ops fdp1_ctrl_ops = { 1719 + .s_ctrl = fdp1_s_ctrl, 1720 + .g_volatile_ctrl = fdp1_g_ctrl, 1721 + }; 1722 + 1723 + static const char * const fdp1_ctrl_deint_menu[] = { 1724 + "Progressive", 1725 + "Adaptive 2D/3D", 1726 + "Fixed 2D", 1727 + "Fixed 3D", 1728 + "Previous field", 1729 + "Next field", 1730 + NULL 1731 + }; 1732 + 1733 + static const struct v4l2_ioctl_ops fdp1_ioctl_ops = { 1734 + .vidioc_querycap = fdp1_vidioc_querycap, 1735 + 1736 + .vidioc_enum_fmt_vid_cap_mplane = fdp1_enum_fmt_vid_cap, 1737 + .vidioc_enum_fmt_vid_out_mplane = fdp1_enum_fmt_vid_out, 1738 + .vidioc_g_fmt_vid_cap_mplane = fdp1_g_fmt, 1739 + .vidioc_g_fmt_vid_out_mplane = fdp1_g_fmt, 1740 + .vidioc_try_fmt_vid_cap_mplane = fdp1_try_fmt, 1741 + .vidioc_try_fmt_vid_out_mplane = fdp1_try_fmt, 1742 + .vidioc_s_fmt_vid_cap_mplane = fdp1_s_fmt, 1743 + .vidioc_s_fmt_vid_out_mplane = fdp1_s_fmt, 1744 + 1745 + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 1746 + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 1747 + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 1748 + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 1749 + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 1750 + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 1751 + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 1752 + 1753 + .vidioc_streamon = v4l2_m2m_ioctl_streamon, 1754 + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 1755 + 1756 + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1757 + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1758 + }; 1759 + 1760 + /* 1761 + * Queue operations 1762 + */ 1763 + 1764 + static int fdp1_queue_setup(struct vb2_queue *vq, 1765 + unsigned int *nbuffers, unsigned int *nplanes, 1766 + unsigned int sizes[], 1767 + struct device *alloc_ctxs[]) 1768 + { 1769 + struct fdp1_ctx *ctx = vb2_get_drv_priv(vq); 1770 + struct fdp1_q_data *q_data; 1771 + unsigned int i; 1772 + 1773 + q_data = get_q_data(ctx, vq->type); 1774 + 1775 + if (*nplanes) { 1776 + if (*nplanes > FDP1_MAX_PLANES) 1777 + return -EINVAL; 1778 + 1779 + return 0; 1780 + } 1781 + 1782 + *nplanes = q_data->format.num_planes; 1783 + 1784 + for (i = 0; i < *nplanes; i++) 1785 + sizes[i] = q_data->format.plane_fmt[i].sizeimage; 1786 + 1787 + return 0; 1788 + } 1789 + 1790 + static void fdp1_buf_prepare_field(struct fdp1_q_data *q_data, 1791 + struct vb2_v4l2_buffer *vbuf, 1792 + unsigned int field_num) 1793 + { 1794 + struct fdp1_buffer *buf = to_fdp1_buffer(vbuf); 1795 + struct fdp1_field_buffer *fbuf = &buf->fields[field_num]; 1796 + unsigned int num_fields; 1797 + unsigned int i; 1798 + 1799 + num_fields = V4L2_FIELD_HAS_BOTH(vbuf->field) ? 2 : 1; 1800 + 1801 + fbuf->vb = vbuf; 1802 + fbuf->last_field = (field_num + 1) == num_fields; 1803 + 1804 + for (i = 0; i < vbuf->vb2_buf.num_planes; ++i) 1805 + fbuf->addrs[i] = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, i); 1806 + 1807 + switch (vbuf->field) { 1808 + case V4L2_FIELD_INTERLACED: 1809 + /* 1810 + * Interlaced means bottom-top for 60Hz TV standards (NTSC) and 1811 + * top-bottom for 50Hz. As TV standards are not applicable to 1812 + * the mem-to-mem API, use the height as a heuristic. 1813 + */ 1814 + fbuf->field = (q_data->format.height < 576) == field_num 1815 + ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; 1816 + break; 1817 + case V4L2_FIELD_INTERLACED_TB: 1818 + case V4L2_FIELD_SEQ_TB: 1819 + fbuf->field = field_num ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; 1820 + break; 1821 + case V4L2_FIELD_INTERLACED_BT: 1822 + case V4L2_FIELD_SEQ_BT: 1823 + fbuf->field = field_num ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; 1824 + break; 1825 + default: 1826 + fbuf->field = vbuf->field; 1827 + break; 1828 + } 1829 + 1830 + /* Buffer is completed */ 1831 + if (!field_num) 1832 + return; 1833 + 1834 + /* Adjust buffer addresses for second field */ 1835 + switch (vbuf->field) { 1836 + case V4L2_FIELD_INTERLACED: 1837 + case V4L2_FIELD_INTERLACED_TB: 1838 + case V4L2_FIELD_INTERLACED_BT: 1839 + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) 1840 + fbuf->addrs[i] += 1841 + (i == 0 ? q_data->stride_y : q_data->stride_c); 1842 + break; 1843 + case V4L2_FIELD_SEQ_TB: 1844 + case V4L2_FIELD_SEQ_BT: 1845 + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) 1846 + fbuf->addrs[i] += q_data->vsize * 1847 + (i == 0 ? q_data->stride_y : q_data->stride_c); 1848 + break; 1849 + } 1850 + } 1851 + 1852 + static int fdp1_buf_prepare(struct vb2_buffer *vb) 1853 + { 1854 + struct fdp1_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1855 + struct fdp1_q_data *q_data = get_q_data(ctx, vb->vb2_queue->type); 1856 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1857 + struct fdp1_buffer *buf = to_fdp1_buffer(vbuf); 1858 + unsigned int i; 1859 + 1860 + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 1861 + bool field_valid = true; 1862 + 1863 + /* Validate the buffer field. */ 1864 + switch (q_data->format.field) { 1865 + case V4L2_FIELD_NONE: 1866 + if (vbuf->field != V4L2_FIELD_NONE) 1867 + field_valid = false; 1868 + break; 1869 + 1870 + case V4L2_FIELD_ALTERNATE: 1871 + if (vbuf->field != V4L2_FIELD_TOP && 1872 + vbuf->field != V4L2_FIELD_BOTTOM) 1873 + field_valid = false; 1874 + break; 1875 + 1876 + case V4L2_FIELD_INTERLACED: 1877 + case V4L2_FIELD_SEQ_TB: 1878 + case V4L2_FIELD_SEQ_BT: 1879 + case V4L2_FIELD_INTERLACED_TB: 1880 + case V4L2_FIELD_INTERLACED_BT: 1881 + if (vbuf->field != q_data->format.field) 1882 + field_valid = false; 1883 + break; 1884 + } 1885 + 1886 + if (!field_valid) { 1887 + dprintk(ctx->fdp1, 1888 + "buffer field %u invalid for format field %u\n", 1889 + vbuf->field, q_data->format.field); 1890 + return -EINVAL; 1891 + } 1892 + } else { 1893 + vbuf->field = V4L2_FIELD_NONE; 1894 + } 1895 + 1896 + /* Validate the planes sizes. */ 1897 + for (i = 0; i < q_data->format.num_planes; i++) { 1898 + unsigned long size = q_data->format.plane_fmt[i].sizeimage; 1899 + 1900 + if (vb2_plane_size(vb, i) < size) { 1901 + dprintk(ctx->fdp1, 1902 + "data will not fit into plane [%u/%u] (%lu < %lu)\n", 1903 + i, q_data->format.num_planes, 1904 + vb2_plane_size(vb, i), size); 1905 + return -EINVAL; 1906 + } 1907 + 1908 + /* We have known size formats all around */ 1909 + vb2_set_plane_payload(vb, i, size); 1910 + } 1911 + 1912 + buf->num_fields = V4L2_FIELD_HAS_BOTH(vbuf->field) ? 2 : 1; 1913 + for (i = 0; i < buf->num_fields; ++i) 1914 + fdp1_buf_prepare_field(q_data, vbuf, i); 1915 + 1916 + return 0; 1917 + } 1918 + 1919 + static void fdp1_buf_queue(struct vb2_buffer *vb) 1920 + { 1921 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1922 + struct fdp1_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1923 + 1924 + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 1925 + } 1926 + 1927 + static int fdp1_start_streaming(struct vb2_queue *q, unsigned int count) 1928 + { 1929 + struct fdp1_ctx *ctx = vb2_get_drv_priv(q); 1930 + struct fdp1_q_data *q_data = get_q_data(ctx, q->type); 1931 + 1932 + if (V4L2_TYPE_IS_OUTPUT(q->type)) { 1933 + /* 1934 + * Force our deint_mode when we are progressive, 1935 + * ignoring any setting on the device from the user, 1936 + * Otherwise, lock in the requested de-interlace mode. 1937 + */ 1938 + if (q_data->format.field == V4L2_FIELD_NONE) 1939 + ctx->deint_mode = FDP1_PROGRESSIVE; 1940 + 1941 + if (ctx->deint_mode == FDP1_ADAPT2D3D) { 1942 + u32 stride; 1943 + dma_addr_t smsk_base; 1944 + const u32 bpp = 2; /* bytes per pixel */ 1945 + 1946 + stride = round_up(q_data->format.width, 8); 1947 + 1948 + ctx->smsk_size = bpp * stride * q_data->vsize; 1949 + 1950 + ctx->smsk_cpu = dma_alloc_coherent(ctx->fdp1->dev, 1951 + ctx->smsk_size, &smsk_base, GFP_KERNEL); 1952 + 1953 + if (ctx->smsk_cpu == NULL) { 1954 + dprintk(ctx->fdp1, "Failed to alloc smsk\n"); 1955 + return -ENOMEM; 1956 + } 1957 + 1958 + ctx->smsk_addr[0] = smsk_base; 1959 + ctx->smsk_addr[1] = smsk_base + (ctx->smsk_size/2); 1960 + } 1961 + } 1962 + 1963 + return 0; 1964 + } 1965 + 1966 + static void fdp1_stop_streaming(struct vb2_queue *q) 1967 + { 1968 + struct fdp1_ctx *ctx = vb2_get_drv_priv(q); 1969 + struct vb2_v4l2_buffer *vbuf; 1970 + unsigned long flags; 1971 + 1972 + while (1) { 1973 + if (V4L2_TYPE_IS_OUTPUT(q->type)) 1974 + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 1975 + else 1976 + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 1977 + if (vbuf == NULL) 1978 + break; 1979 + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); 1980 + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); 1981 + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); 1982 + } 1983 + 1984 + /* Empty Output queues */ 1985 + if (V4L2_TYPE_IS_OUTPUT(q->type)) { 1986 + /* Empty our internal queues */ 1987 + struct fdp1_field_buffer *fbuf; 1988 + 1989 + /* Free any queued buffers */ 1990 + fbuf = fdp1_dequeue_field(ctx); 1991 + while (fbuf != NULL) { 1992 + fdp1_field_complete(ctx, fbuf); 1993 + fbuf = fdp1_dequeue_field(ctx); 1994 + } 1995 + 1996 + /* Free smsk_data */ 1997 + if (ctx->smsk_cpu) { 1998 + dma_free_coherent(ctx->fdp1->dev, ctx->smsk_size, 1999 + ctx->smsk_cpu, ctx->smsk_addr[0]); 2000 + ctx->smsk_addr[0] = ctx->smsk_addr[1] = 0; 2001 + ctx->smsk_cpu = NULL; 2002 + } 2003 + 2004 + WARN(!list_empty(&ctx->fields_queue), 2005 + "Buffer queue not empty"); 2006 + } else { 2007 + /* Empty Capture queues (Jobs) */ 2008 + struct fdp1_job *job; 2009 + 2010 + job = get_queued_job(ctx->fdp1); 2011 + while (job) { 2012 + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) 2013 + fdp1_field_complete(ctx, job->previous); 2014 + else 2015 + fdp1_field_complete(ctx, job->active); 2016 + 2017 + v4l2_m2m_buf_done(job->dst->vb, VB2_BUF_STATE_ERROR); 2018 + job->dst = NULL; 2019 + 2020 + job = get_queued_job(ctx->fdp1); 2021 + } 2022 + 2023 + /* Free any held buffer in the ctx */ 2024 + fdp1_field_complete(ctx, ctx->previous); 2025 + 2026 + WARN(!list_empty(&ctx->fdp1->queued_job_list), 2027 + "Queued Job List not empty"); 2028 + 2029 + WARN(!list_empty(&ctx->fdp1->hw_job_list), 2030 + "HW Job list not empty"); 2031 + } 2032 + } 2033 + 2034 + static struct vb2_ops fdp1_qops = { 2035 + .queue_setup = fdp1_queue_setup, 2036 + .buf_prepare = fdp1_buf_prepare, 2037 + .buf_queue = fdp1_buf_queue, 2038 + .start_streaming = fdp1_start_streaming, 2039 + .stop_streaming = fdp1_stop_streaming, 2040 + .wait_prepare = vb2_ops_wait_prepare, 2041 + .wait_finish = vb2_ops_wait_finish, 2042 + }; 2043 + 2044 + static int queue_init(void *priv, struct vb2_queue *src_vq, 2045 + struct vb2_queue *dst_vq) 2046 + { 2047 + struct fdp1_ctx *ctx = priv; 2048 + int ret; 2049 + 2050 + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 2051 + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 2052 + src_vq->drv_priv = ctx; 2053 + src_vq->buf_struct_size = sizeof(struct fdp1_buffer); 2054 + src_vq->ops = &fdp1_qops; 2055 + src_vq->mem_ops = &vb2_dma_contig_memops; 2056 + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 2057 + src_vq->lock = &ctx->fdp1->dev_mutex; 2058 + src_vq->dev = ctx->fdp1->dev; 2059 + 2060 + ret = vb2_queue_init(src_vq); 2061 + if (ret) 2062 + return ret; 2063 + 2064 + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 2065 + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 2066 + dst_vq->drv_priv = ctx; 2067 + dst_vq->buf_struct_size = sizeof(struct fdp1_buffer); 2068 + dst_vq->ops = &fdp1_qops; 2069 + dst_vq->mem_ops = &vb2_dma_contig_memops; 2070 + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 2071 + dst_vq->lock = &ctx->fdp1->dev_mutex; 2072 + dst_vq->dev = ctx->fdp1->dev; 2073 + 2074 + return vb2_queue_init(dst_vq); 2075 + } 2076 + 2077 + /* 2078 + * File operations 2079 + */ 2080 + static int fdp1_open(struct file *file) 2081 + { 2082 + struct fdp1_dev *fdp1 = video_drvdata(file); 2083 + struct v4l2_pix_format_mplane format; 2084 + struct fdp1_ctx *ctx = NULL; 2085 + struct v4l2_ctrl *ctrl; 2086 + int ret = 0; 2087 + 2088 + if (mutex_lock_interruptible(&fdp1->dev_mutex)) 2089 + return -ERESTARTSYS; 2090 + 2091 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 2092 + if (!ctx) { 2093 + ret = -ENOMEM; 2094 + goto done; 2095 + } 2096 + 2097 + v4l2_fh_init(&ctx->fh, video_devdata(file)); 2098 + file->private_data = &ctx->fh; 2099 + ctx->fdp1 = fdp1; 2100 + 2101 + /* Initialise Queues */ 2102 + INIT_LIST_HEAD(&ctx->fields_queue); 2103 + 2104 + ctx->translen = 1; 2105 + ctx->sequence = 0; 2106 + 2107 + /* Initialise controls */ 2108 + 2109 + v4l2_ctrl_handler_init(&ctx->hdl, 3); 2110 + v4l2_ctrl_new_std_menu_items(&ctx->hdl, &fdp1_ctrl_ops, 2111 + V4L2_CID_DEINTERLACING_MODE, 2112 + FDP1_NEXTFIELD, BIT(0), FDP1_FIXED3D, 2113 + fdp1_ctrl_deint_menu); 2114 + 2115 + ctrl = v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, 2116 + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); 2117 + if (ctrl) 2118 + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; 2119 + 2120 + v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, 2121 + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); 2122 + 2123 + if (ctx->hdl.error) { 2124 + ret = ctx->hdl.error; 2125 + v4l2_ctrl_handler_free(&ctx->hdl); 2126 + goto done; 2127 + } 2128 + 2129 + ctx->fh.ctrl_handler = &ctx->hdl; 2130 + v4l2_ctrl_handler_setup(&ctx->hdl); 2131 + 2132 + /* Configure default parameters. */ 2133 + memset(&format, 0, sizeof(format)); 2134 + fdp1_set_format(ctx, &format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 2135 + 2136 + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fdp1->m2m_dev, ctx, &queue_init); 2137 + 2138 + if (IS_ERR(ctx->fh.m2m_ctx)) { 2139 + ret = PTR_ERR(ctx->fh.m2m_ctx); 2140 + 2141 + v4l2_ctrl_handler_free(&ctx->hdl); 2142 + kfree(ctx); 2143 + goto done; 2144 + } 2145 + 2146 + /* Perform any power management required */ 2147 + pm_runtime_get_sync(fdp1->dev); 2148 + 2149 + v4l2_fh_add(&ctx->fh); 2150 + 2151 + dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n", 2152 + ctx, ctx->fh.m2m_ctx); 2153 + 2154 + done: 2155 + mutex_unlock(&fdp1->dev_mutex); 2156 + return ret; 2157 + } 2158 + 2159 + static int fdp1_release(struct file *file) 2160 + { 2161 + struct fdp1_dev *fdp1 = video_drvdata(file); 2162 + struct fdp1_ctx *ctx = fh_to_ctx(file->private_data); 2163 + 2164 + dprintk(fdp1, "Releasing instance %p\n", ctx); 2165 + 2166 + v4l2_fh_del(&ctx->fh); 2167 + v4l2_fh_exit(&ctx->fh); 2168 + v4l2_ctrl_handler_free(&ctx->hdl); 2169 + mutex_lock(&fdp1->dev_mutex); 2170 + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 2171 + mutex_unlock(&fdp1->dev_mutex); 2172 + kfree(ctx); 2173 + 2174 + pm_runtime_put(fdp1->dev); 2175 + 2176 + return 0; 2177 + } 2178 + 2179 + static const struct v4l2_file_operations fdp1_fops = { 2180 + .owner = THIS_MODULE, 2181 + .open = fdp1_open, 2182 + .release = fdp1_release, 2183 + .poll = v4l2_m2m_fop_poll, 2184 + .unlocked_ioctl = video_ioctl2, 2185 + .mmap = v4l2_m2m_fop_mmap, 2186 + }; 2187 + 2188 + static const struct video_device fdp1_videodev = { 2189 + .name = DRIVER_NAME, 2190 + .vfl_dir = VFL_DIR_M2M, 2191 + .fops = &fdp1_fops, 2192 + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, 2193 + .ioctl_ops = &fdp1_ioctl_ops, 2194 + .minor = -1, 2195 + .release = video_device_release_empty, 2196 + }; 2197 + 2198 + static const struct v4l2_m2m_ops m2m_ops = { 2199 + .device_run = fdp1_m2m_device_run, 2200 + .job_ready = fdp1_m2m_job_ready, 2201 + .job_abort = fdp1_m2m_job_abort, 2202 + }; 2203 + 2204 + static irqreturn_t fdp1_irq_handler(int irq, void *dev_id) 2205 + { 2206 + struct fdp1_dev *fdp1 = dev_id; 2207 + u32 int_status; 2208 + u32 ctl_status; 2209 + u32 vint_cnt; 2210 + u32 cycles; 2211 + 2212 + int_status = fdp1_read(fdp1, FD1_CTL_IRQSTA); 2213 + cycles = fdp1_read(fdp1, FD1_CTL_VCYCLE_STAT); 2214 + ctl_status = fdp1_read(fdp1, FD1_CTL_STATUS); 2215 + vint_cnt = (ctl_status & FD1_CTL_STATUS_VINT_CNT_MASK) >> 2216 + FD1_CTL_STATUS_VINT_CNT_SHIFT; 2217 + 2218 + /* Clear interrupts */ 2219 + fdp1_write(fdp1, ~(int_status) & FD1_CTL_IRQ_MASK, FD1_CTL_IRQSTA); 2220 + 2221 + if (debug >= 2) { 2222 + dprintk(fdp1, "IRQ: 0x%x %s%s%s\n", int_status, 2223 + int_status & FD1_CTL_IRQ_VERE ? "[Error]" : "[!E]", 2224 + int_status & FD1_CTL_IRQ_VINTE ? "[VSync]" : "[!V]", 2225 + int_status & FD1_CTL_IRQ_FREE ? "[FrameEnd]" : "[!F]"); 2226 + 2227 + dprintk(fdp1, "CycleStatus = %d (%dms)\n", 2228 + cycles, cycles/(fdp1->clk_rate/1000)); 2229 + 2230 + dprintk(fdp1, 2231 + "Control Status = 0x%08x : VINT_CNT = %d %s:%s:%s:%s\n", 2232 + ctl_status, vint_cnt, 2233 + ctl_status & FD1_CTL_STATUS_SGREGSET ? "RegSet" : "", 2234 + ctl_status & FD1_CTL_STATUS_SGVERR ? "Vsync Error" : "", 2235 + ctl_status & FD1_CTL_STATUS_SGFREND ? "FrameEnd" : "", 2236 + ctl_status & FD1_CTL_STATUS_BSY ? "Busy" : ""); 2237 + dprintk(fdp1, "***********************************\n"); 2238 + } 2239 + 2240 + /* Spurious interrupt */ 2241 + if (!(FD1_CTL_IRQ_MASK & int_status)) 2242 + return IRQ_NONE; 2243 + 2244 + /* Work completed, release the frame */ 2245 + if (FD1_CTL_IRQ_VERE & int_status) 2246 + device_frame_end(fdp1, VB2_BUF_STATE_ERROR); 2247 + else if (FD1_CTL_IRQ_FREE & int_status) 2248 + device_frame_end(fdp1, VB2_BUF_STATE_DONE); 2249 + 2250 + return IRQ_HANDLED; 2251 + } 2252 + 2253 + static int fdp1_probe(struct platform_device *pdev) 2254 + { 2255 + struct fdp1_dev *fdp1; 2256 + struct video_device *vfd; 2257 + struct device_node *fcp_node; 2258 + struct resource *res; 2259 + struct clk *clk; 2260 + unsigned int i; 2261 + 2262 + int ret; 2263 + int hw_version; 2264 + 2265 + fdp1 = devm_kzalloc(&pdev->dev, sizeof(*fdp1), GFP_KERNEL); 2266 + if (!fdp1) 2267 + return -ENOMEM; 2268 + 2269 + INIT_LIST_HEAD(&fdp1->free_job_list); 2270 + INIT_LIST_HEAD(&fdp1->queued_job_list); 2271 + INIT_LIST_HEAD(&fdp1->hw_job_list); 2272 + 2273 + /* Initialise the jobs on the free list */ 2274 + for (i = 0; i < ARRAY_SIZE(fdp1->jobs); i++) 2275 + list_add(&fdp1->jobs[i].list, &fdp1->free_job_list); 2276 + 2277 + mutex_init(&fdp1->dev_mutex); 2278 + 2279 + spin_lock_init(&fdp1->irqlock); 2280 + spin_lock_init(&fdp1->device_process_lock); 2281 + fdp1->dev = &pdev->dev; 2282 + platform_set_drvdata(pdev, fdp1); 2283 + 2284 + /* Memory-mapped registers */ 2285 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2286 + fdp1->regs = devm_ioremap_resource(&pdev->dev, res); 2287 + if (IS_ERR(fdp1->regs)) 2288 + return PTR_ERR(fdp1->regs); 2289 + 2290 + /* Interrupt service routine registration */ 2291 + fdp1->irq = ret = platform_get_irq(pdev, 0); 2292 + if (ret < 0) { 2293 + dev_err(&pdev->dev, "cannot find IRQ\n"); 2294 + return ret; 2295 + } 2296 + 2297 + ret = devm_request_irq(&pdev->dev, fdp1->irq, fdp1_irq_handler, 0, 2298 + dev_name(&pdev->dev), fdp1); 2299 + if (ret) { 2300 + dev_err(&pdev->dev, "cannot claim IRQ %d\n", fdp1->irq); 2301 + return ret; 2302 + } 2303 + 2304 + /* FCP */ 2305 + fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); 2306 + if (fcp_node) { 2307 + fdp1->fcp = rcar_fcp_get(fcp_node); 2308 + of_node_put(fcp_node); 2309 + if (IS_ERR(fdp1->fcp)) { 2310 + dev_err(&pdev->dev, "FCP not found (%ld)\n", 2311 + PTR_ERR(fdp1->fcp)); 2312 + return PTR_ERR(fdp1->fcp); 2313 + } 2314 + } 2315 + 2316 + /* Determine our clock rate */ 2317 + clk = clk_get(&pdev->dev, NULL); 2318 + if (IS_ERR(clk)) 2319 + return PTR_ERR(clk); 2320 + 2321 + fdp1->clk_rate = clk_get_rate(clk); 2322 + clk_put(clk); 2323 + 2324 + /* V4L2 device registration */ 2325 + ret = v4l2_device_register(&pdev->dev, &fdp1->v4l2_dev); 2326 + if (ret) { 2327 + v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n"); 2328 + return ret; 2329 + } 2330 + 2331 + /* M2M registration */ 2332 + fdp1->m2m_dev = v4l2_m2m_init(&m2m_ops); 2333 + if (IS_ERR(fdp1->m2m_dev)) { 2334 + v4l2_err(&fdp1->v4l2_dev, "Failed to init mem2mem device\n"); 2335 + ret = PTR_ERR(fdp1->m2m_dev); 2336 + goto unreg_dev; 2337 + } 2338 + 2339 + /* Video registration */ 2340 + fdp1->vfd = fdp1_videodev; 2341 + vfd = &fdp1->vfd; 2342 + vfd->lock = &fdp1->dev_mutex; 2343 + vfd->v4l2_dev = &fdp1->v4l2_dev; 2344 + video_set_drvdata(vfd, fdp1); 2345 + strlcpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name)); 2346 + 2347 + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); 2348 + if (ret) { 2349 + v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n"); 2350 + goto release_m2m; 2351 + } 2352 + 2353 + v4l2_info(&fdp1->v4l2_dev, 2354 + "Device registered as /dev/video%d\n", vfd->num); 2355 + 2356 + /* Power up the cells to read HW */ 2357 + pm_runtime_enable(&pdev->dev); 2358 + pm_runtime_get_sync(fdp1->dev); 2359 + 2360 + hw_version = fdp1_read(fdp1, FD1_IP_INTDATA); 2361 + switch (hw_version) { 2362 + case FD1_IP_H3: 2363 + dprintk(fdp1, "FDP1 Version R-Car H3\n"); 2364 + break; 2365 + case FD1_IP_M3W: 2366 + dprintk(fdp1, "FDP1 Version R-Car M3-W\n"); 2367 + break; 2368 + default: 2369 + dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", 2370 + hw_version); 2371 + } 2372 + 2373 + /* Allow the hw to sleep until an open call puts it to use */ 2374 + pm_runtime_put(fdp1->dev); 2375 + 2376 + return 0; 2377 + 2378 + release_m2m: 2379 + v4l2_m2m_release(fdp1->m2m_dev); 2380 + 2381 + unreg_dev: 2382 + v4l2_device_unregister(&fdp1->v4l2_dev); 2383 + 2384 + return ret; 2385 + } 2386 + 2387 + static int fdp1_remove(struct platform_device *pdev) 2388 + { 2389 + struct fdp1_dev *fdp1 = platform_get_drvdata(pdev); 2390 + 2391 + v4l2_m2m_release(fdp1->m2m_dev); 2392 + video_unregister_device(&fdp1->vfd); 2393 + v4l2_device_unregister(&fdp1->v4l2_dev); 2394 + pm_runtime_disable(&pdev->dev); 2395 + 2396 + return 0; 2397 + } 2398 + 2399 + static int fdp1_pm_runtime_suspend(struct device *dev) 2400 + { 2401 + struct fdp1_dev *fdp1 = dev_get_drvdata(dev); 2402 + 2403 + rcar_fcp_disable(fdp1->fcp); 2404 + 2405 + return 0; 2406 + } 2407 + 2408 + static int fdp1_pm_runtime_resume(struct device *dev) 2409 + { 2410 + struct fdp1_dev *fdp1 = dev_get_drvdata(dev); 2411 + 2412 + /* Program in the static LUTs */ 2413 + fdp1_set_lut(fdp1); 2414 + 2415 + return rcar_fcp_enable(fdp1->fcp); 2416 + } 2417 + 2418 + static const struct dev_pm_ops fdp1_pm_ops = { 2419 + SET_RUNTIME_PM_OPS(fdp1_pm_runtime_suspend, 2420 + fdp1_pm_runtime_resume, 2421 + NULL) 2422 + }; 2423 + 2424 + static const struct of_device_id fdp1_dt_ids[] = { 2425 + { .compatible = "renesas,fdp1" }, 2426 + { }, 2427 + }; 2428 + MODULE_DEVICE_TABLE(of, fdp1_dt_ids); 2429 + 2430 + static struct platform_driver fdp1_pdrv = { 2431 + .probe = fdp1_probe, 2432 + .remove = fdp1_remove, 2433 + .driver = { 2434 + .name = DRIVER_NAME, 2435 + .of_match_table = fdp1_dt_ids, 2436 + .pm = &fdp1_pm_ops, 2437 + }, 2438 + }; 2439 + 2440 + module_platform_driver(fdp1_pdrv); 2441 + 2442 + MODULE_DESCRIPTION("Renesas R-Car Fine Display Processor Driver"); 2443 + MODULE_AUTHOR("Kieran Bingham <kieran@bingham.xyz>"); 2444 + MODULE_LICENSE("GPL"); 2445 + MODULE_ALIAS("platform:" DRIVER_NAME);