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