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