brintos

brintos / linux-shallow public Read only

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