1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/delay.h>
18#include <linux/interrupt.h>
19
20#include <media/videobuf2-dma-contig.h>
21
22#include "rcar-vin.h"
23
24
25
26
27
28
29#define VNMC_REG 0x00
30#define VNMS_REG 0x04
31#define VNFC_REG 0x08
32#define VNSLPRC_REG 0x0C
33#define VNELPRC_REG 0x10
34#define VNSPPRC_REG 0x14
35#define VNEPPRC_REG 0x18
36#define VNSLPOC_REG 0x1C
37#define VNELPOC_REG 0x20
38#define VNSPPOC_REG 0x24
39#define VNEPPOC_REG 0x28
40#define VNIS_REG 0x2C
41#define VNMB_REG(m) (0x30 + ((m) << 2))
42#define VNIE_REG 0x40
43#define VNINTS_REG 0x44
44#define VNSI_REG 0x48
45#define VNMTC_REG 0x4C
46#define VNYS_REG 0x50
47#define VNXS_REG 0x54
48#define VNDMR_REG 0x58
49#define VNDMR2_REG 0x5C
50#define VNUVAOF_REG 0x60
51#define VNC1A_REG 0x80
52#define VNC1B_REG 0x84
53#define VNC1C_REG 0x88
54#define VNC2A_REG 0x90
55#define VNC2B_REG 0x94
56#define VNC2C_REG 0x98
57#define VNC3A_REG 0xA0
58#define VNC3B_REG 0xA4
59#define VNC3C_REG 0xA8
60#define VNC4A_REG 0xB0
61#define VNC4B_REG 0xB4
62#define VNC4C_REG 0xB8
63#define VNC5A_REG 0xC0
64#define VNC5B_REG 0xC4
65#define VNC5C_REG 0xC8
66#define VNC6A_REG 0xD0
67#define VNC6B_REG 0xD4
68#define VNC6C_REG 0xD8
69#define VNC7A_REG 0xE0
70#define VNC7B_REG 0xE4
71#define VNC7C_REG 0xE8
72#define VNC8A_REG 0xF0
73#define VNC8B_REG 0xF4
74#define VNC8C_REG 0xF8
75
76
77
78
79#define VNMC_FOC (1 << 21)
80#define VNMC_YCAL (1 << 19)
81#define VNMC_INF_YUV8_BT656 (0 << 16)
82#define VNMC_INF_YUV8_BT601 (1 << 16)
83#define VNMC_INF_YUV10_BT656 (2 << 16)
84#define VNMC_INF_YUV10_BT601 (3 << 16)
85#define VNMC_INF_YUV16 (5 << 16)
86#define VNMC_INF_RGB888 (6 << 16)
87#define VNMC_VUP (1 << 10)
88#define VNMC_IM_ODD (0 << 3)
89#define VNMC_IM_ODD_EVEN (1 << 3)
90#define VNMC_IM_EVEN (2 << 3)
91#define VNMC_IM_FULL (3 << 3)
92#define VNMC_BPS (1 << 1)
93#define VNMC_ME (1 << 0)
94
95
96#define VNMS_FBS_MASK (3 << 3)
97#define VNMS_FBS_SHIFT 3
98#define VNMS_FS (1 << 2)
99#define VNMS_AV (1 << 1)
100#define VNMS_CA (1 << 0)
101
102
103#define VNFC_C_FRAME (1 << 1)
104#define VNFC_S_FRAME (1 << 0)
105
106
107#define VNIE_FIE (1 << 4)
108#define VNIE_EFE (1 << 1)
109
110
111#define VNDMR_EXRGB (1 << 8)
112#define VNDMR_BPSM (1 << 4)
113#define VNDMR_DTMD_YCSEP (1 << 1)
114#define VNDMR_DTMD_ARGB1555 (1 << 0)
115
116
117#define VNDMR2_VPS (1 << 30)
118#define VNDMR2_HPS (1 << 29)
119#define VNDMR2_FTEV (1 << 17)
120#define VNDMR2_VLV(n) ((n & 0xf) << 12)
121
122static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
123{
124 iowrite32(value, vin->base + offset);
125}
126
127static u32 rvin_read(struct rvin_dev *vin, u32 offset)
128{
129 return ioread32(vin->base + offset);
130}
131
132static int rvin_setup(struct rvin_dev *vin)
133{
134 u32 vnmc, dmr, dmr2, interrupts;
135 v4l2_std_id std;
136 bool progressive = false, output_is_yuv = false, input_is_yuv = false;
137
138 switch (vin->format.field) {
139 case V4L2_FIELD_TOP:
140 vnmc = VNMC_IM_ODD;
141 break;
142 case V4L2_FIELD_BOTTOM:
143 vnmc = VNMC_IM_EVEN;
144 break;
145 case V4L2_FIELD_INTERLACED:
146
147 vnmc = VNMC_IM_FULL;
148
149 if (!v4l2_subdev_call(vin_to_source(vin), video, g_std, &std)) {
150 if (std & V4L2_STD_525_60)
151 vnmc = VNMC_IM_FULL | VNMC_FOC;
152 }
153 break;
154 case V4L2_FIELD_INTERLACED_TB:
155 vnmc = VNMC_IM_FULL;
156 break;
157 case V4L2_FIELD_INTERLACED_BT:
158 vnmc = VNMC_IM_FULL | VNMC_FOC;
159 break;
160 case V4L2_FIELD_ALTERNATE:
161 case V4L2_FIELD_NONE:
162 if (vin->continuous) {
163 vnmc = VNMC_IM_ODD_EVEN;
164 progressive = true;
165 } else {
166 vnmc = VNMC_IM_ODD;
167 }
168 break;
169 default:
170 vnmc = VNMC_IM_ODD;
171 break;
172 }
173
174
175
176
177 switch (vin->digital.code) {
178 case MEDIA_BUS_FMT_YUYV8_1X16:
179
180 vnmc |= VNMC_INF_YUV16;
181 input_is_yuv = true;
182 break;
183 case MEDIA_BUS_FMT_UYVY8_2X8:
184
185 vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
186 VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
187 input_is_yuv = true;
188 break;
189 case MEDIA_BUS_FMT_RGB888_1X24:
190 vnmc |= VNMC_INF_RGB888;
191 break;
192 case MEDIA_BUS_FMT_UYVY10_2X10:
193
194 vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
195 VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
196 input_is_yuv = true;
197 break;
198 default:
199 break;
200 }
201
202
203 dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
204
205
206 if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
207 dmr2 |= VNDMR2_HPS;
208
209
210 if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
211 dmr2 |= VNDMR2_VPS;
212
213
214
215
216 switch (vin->format.pixelformat) {
217 case V4L2_PIX_FMT_NV16:
218 rvin_write(vin,
219 ALIGN(vin->format.width * vin->format.height, 0x80),
220 VNUVAOF_REG);
221 dmr = VNDMR_DTMD_YCSEP;
222 output_is_yuv = true;
223 break;
224 case V4L2_PIX_FMT_YUYV:
225 dmr = VNDMR_BPSM;
226 output_is_yuv = true;
227 break;
228 case V4L2_PIX_FMT_UYVY:
229 dmr = 0;
230 output_is_yuv = true;
231 break;
232 case V4L2_PIX_FMT_XRGB555:
233 dmr = VNDMR_DTMD_ARGB1555;
234 break;
235 case V4L2_PIX_FMT_RGB565:
236 dmr = 0;
237 break;
238 case V4L2_PIX_FMT_XBGR32:
239
240 dmr = VNDMR_EXRGB;
241 break;
242 default:
243 vin_err(vin, "Invalid pixelformat (0x%x)\n",
244 vin->format.pixelformat);
245 return -EINVAL;
246 }
247
248
249 vnmc |= VNMC_VUP;
250
251
252 if (input_is_yuv == output_is_yuv)
253 vnmc |= VNMC_BPS;
254
255
256 interrupts = progressive ? VNIE_FIE : VNIE_EFE;
257
258
259 rvin_write(vin, interrupts, VNINTS_REG);
260
261 rvin_write(vin, interrupts, VNIE_REG);
262
263 rvin_write(vin, dmr, VNDMR_REG);
264 rvin_write(vin, dmr2, VNDMR2_REG);
265
266
267 rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
268
269 return 0;
270}
271
272static void rvin_capture_on(struct rvin_dev *vin)
273{
274 vin_dbg(vin, "Capture on in %s mode\n",
275 vin->continuous ? "continuous" : "single");
276
277 if (vin->continuous)
278
279 rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
280 else
281
282 rvin_write(vin, VNFC_S_FRAME, VNFC_REG);
283}
284
285static void rvin_capture_off(struct rvin_dev *vin)
286{
287
288 rvin_write(vin, 0, VNFC_REG);
289}
290
291static int rvin_capture_start(struct rvin_dev *vin)
292{
293 int ret;
294
295 rvin_crop_scale_comp(vin);
296
297 ret = rvin_setup(vin);
298 if (ret)
299 return ret;
300
301 rvin_capture_on(vin);
302
303 return 0;
304}
305
306static void rvin_capture_stop(struct rvin_dev *vin)
307{
308 rvin_capture_off(vin);
309
310
311 rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
312}
313
314static void rvin_disable_interrupts(struct rvin_dev *vin)
315{
316 rvin_write(vin, 0, VNIE_REG);
317}
318
319static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
320{
321 return rvin_read(vin, VNINTS_REG);
322}
323
324static void rvin_ack_interrupt(struct rvin_dev *vin)
325{
326 rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
327}
328
329static bool rvin_capture_active(struct rvin_dev *vin)
330{
331 return rvin_read(vin, VNMS_REG) & VNMS_CA;
332}
333
334static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms)
335{
336 if (vin->continuous)
337 return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
338
339 return 0;
340}
341
342static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
343{
344 if (vin->format.field == V4L2_FIELD_ALTERNATE) {
345
346 if (vnms & VNMS_FS)
347 return V4L2_FIELD_BOTTOM;
348 return V4L2_FIELD_TOP;
349 }
350
351 return vin->format.field;
352}
353
354static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
355{
356 const struct rvin_video_format *fmt;
357 int offsetx, offsety;
358 dma_addr_t offset;
359
360 fmt = rvin_format_from_pixel(vin->format.pixelformat);
361
362
363
364
365
366 offsetx = vin->compose.left * fmt->bpp;
367 offsety = vin->compose.top * vin->format.bytesperline;
368 offset = addr + offsetx + offsety;
369
370
371
372
373
374 if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
375 return;
376
377 rvin_write(vin, offset, VNMB_REG(slot));
378}
379
380
381
382
383
384struct vin_coeff {
385 unsigned short xs_value;
386 u32 coeff_set[24];
387};
388
389static const struct vin_coeff vin_coeff_set[] = {
390 { 0x0000, {
391 0x00000000, 0x00000000, 0x00000000,
392 0x00000000, 0x00000000, 0x00000000,
393 0x00000000, 0x00000000, 0x00000000,
394 0x00000000, 0x00000000, 0x00000000,
395 0x00000000, 0x00000000, 0x00000000,
396 0x00000000, 0x00000000, 0x00000000,
397 0x00000000, 0x00000000, 0x00000000,
398 0x00000000, 0x00000000, 0x00000000 },
399 },
400 { 0x1000, {
401 0x000fa400, 0x000fa400, 0x09625902,
402 0x000003f8, 0x00000403, 0x3de0d9f0,
403 0x001fffed, 0x00000804, 0x3cc1f9c3,
404 0x001003de, 0x00000c01, 0x3cb34d7f,
405 0x002003d2, 0x00000c00, 0x3d24a92d,
406 0x00200bca, 0x00000bff, 0x3df600d2,
407 0x002013cc, 0x000007ff, 0x3ed70c7e,
408 0x00100fde, 0x00000000, 0x3f87c036 },
409 },
410 { 0x1200, {
411 0x002ffff1, 0x002ffff1, 0x02a0a9c8,
412 0x002003e7, 0x001ffffa, 0x000185bc,
413 0x002007dc, 0x000003ff, 0x3e52859c,
414 0x00200bd4, 0x00000002, 0x3d53996b,
415 0x00100fd0, 0x00000403, 0x3d04ad2d,
416 0x00000bd5, 0x00000403, 0x3d35ace7,
417 0x3ff003e4, 0x00000801, 0x3dc674a1,
418 0x3fffe800, 0x00000800, 0x3e76f461 },
419 },
420 { 0x1400, {
421 0x00100be3, 0x00100be3, 0x04d1359a,
422 0x00000fdb, 0x002003ed, 0x0211fd93,
423 0x00000fd6, 0x002003f4, 0x0002d97b,
424 0x000007d6, 0x002ffffb, 0x3e93b956,
425 0x3ff003da, 0x001003ff, 0x3db49926,
426 0x3fffefe9, 0x00100001, 0x3d655cee,
427 0x3fffd400, 0x00000003, 0x3d65f4b6,
428 0x000fb421, 0x00000402, 0x3dc6547e },
429 },
430 { 0x1600, {
431 0x00000bdd, 0x00000bdd, 0x06519578,
432 0x3ff007da, 0x00000be3, 0x03c24973,
433 0x3ff003d9, 0x00000be9, 0x01b30d5f,
434 0x3ffff7df, 0x001003f1, 0x0003c542,
435 0x000fdfec, 0x001003f7, 0x3ec4711d,
436 0x000fc400, 0x002ffffd, 0x3df504f1,
437 0x001fa81a, 0x002ffc00, 0x3d957cc2,
438 0x002f8c3c, 0x00100000, 0x3db5c891 },
439 },
440 { 0x1800, {
441 0x3ff003dc, 0x3ff003dc, 0x0791e558,
442 0x000ff7dd, 0x3ff007de, 0x05328554,
443 0x000fe7e3, 0x3ff00be2, 0x03232546,
444 0x000fd7ee, 0x000007e9, 0x0143bd30,
445 0x001fb800, 0x000007ee, 0x00044511,
446 0x002fa015, 0x000007f4, 0x3ef4bcee,
447 0x002f8832, 0x001003f9, 0x3e4514c7,
448 0x001f7853, 0x001003fd, 0x3de54c9f },
449 },
450 { 0x1a00, {
451 0x000fefe0, 0x000fefe0, 0x08721d3c,
452 0x001fdbe7, 0x000ffbde, 0x0652a139,
453 0x001fcbf0, 0x000003df, 0x0463292e,
454 0x002fb3ff, 0x3ff007e3, 0x0293a91d,
455 0x002f9c12, 0x3ff00be7, 0x01241905,
456 0x001f8c29, 0x000007ed, 0x3fe470eb,
457 0x000f7c46, 0x000007f2, 0x3f04b8ca,
458 0x3fef7865, 0x000007f6, 0x3e74e4a8 },
459 },
460 { 0x1c00, {
461 0x001fd3e9, 0x001fd3e9, 0x08f23d26,
462 0x002fbff3, 0x001fe3e4, 0x0712ad23,
463 0x002fa800, 0x000ff3e0, 0x05631d1b,
464 0x001f9810, 0x000ffbe1, 0x03b3890d,
465 0x000f8c23, 0x000003e3, 0x0233e8fa,
466 0x3fef843b, 0x000003e7, 0x00f430e4,
467 0x3fbf8456, 0x3ff00bea, 0x00046cc8,
468 0x3f8f8c72, 0x3ff00bef, 0x3f3490ac },
469 },
470 { 0x1e00, {
471 0x001fbbf4, 0x001fbbf4, 0x09425112,
472 0x001fa800, 0x002fc7ed, 0x0792b110,
473 0x000f980e, 0x001fdbe6, 0x0613110a,
474 0x3fff8c20, 0x001fe7e3, 0x04a368fd,
475 0x3fcf8c33, 0x000ff7e2, 0x0343b8ed,
476 0x3f9f8c4a, 0x000fffe3, 0x0203f8da,
477 0x3f5f9c61, 0x000003e6, 0x00e428c5,
478 0x3f1fb07b, 0x000003eb, 0x3fe440af },
479 },
480 { 0x2000, {
481 0x000fa400, 0x000fa400, 0x09625902,
482 0x3fff980c, 0x001fb7f5, 0x0812b0ff,
483 0x3fdf901c, 0x001fc7ed, 0x06b2fcfa,
484 0x3faf902d, 0x001fd3e8, 0x055348f1,
485 0x3f7f983f, 0x001fe3e5, 0x04038ce3,
486 0x3f3fa454, 0x001fefe3, 0x02e3c8d1,
487 0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0,
488 0x3ecfd880, 0x000fffe6, 0x00c404ac },
489 },
490 { 0x2200, {
491 0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4,
492 0x3fbf9818, 0x3fffa400, 0x0842a8f1,
493 0x3f8f9827, 0x000fb3f7, 0x0702f0ec,
494 0x3f5fa037, 0x000fc3ef, 0x05d330e4,
495 0x3f2fac49, 0x001fcfea, 0x04a364d9,
496 0x3effc05c, 0x001fdbe7, 0x038394ca,
497 0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb,
498 0x3ea00083, 0x001fefe6, 0x0183c0a9 },
499 },
500 { 0x2400, {
501 0x3f9fa014, 0x3f9fa014, 0x098260e6,
502 0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5,
503 0x3f4fa431, 0x3fefa400, 0x0742d8e1,
504 0x3f1fb440, 0x3fffb3f8, 0x062310d9,
505 0x3eefc850, 0x000fbbf2, 0x050340d0,
506 0x3ecfe062, 0x000fcbec, 0x041364c2,
507 0x3ea00073, 0x001fd3ea, 0x03037cb5,
508 0x3e902086, 0x001fdfe8, 0x022388a5 },
509 },
510 { 0x2600, {
511 0x3f5fa81e, 0x3f5fa81e, 0x096258da,
512 0x3f3fac2b, 0x3f8fa412, 0x088290d8,
513 0x3f0fbc38, 0x3fafa408, 0x0772c8d5,
514 0x3eefcc47, 0x3fcfa800, 0x0672f4ce,
515 0x3ecfe456, 0x3fefaffa, 0x05531cc6,
516 0x3eb00066, 0x3fffbbf3, 0x047334bb,
517 0x3ea01c77, 0x000fc7ee, 0x039348ae,
518 0x3ea04486, 0x000fd3eb, 0x02b350a1 },
519 },
520 { 0x2800, {
521 0x3f2fb426, 0x3f2fb426, 0x094250ce,
522 0x3f0fc032, 0x3f4fac1b, 0x086284cd,
523 0x3eefd040, 0x3f7fa811, 0x0782acc9,
524 0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4,
525 0x3eb0005b, 0x3fbfac00, 0x05b2f4bc,
526 0x3eb0186a, 0x3fdfb3fa, 0x04c308b4,
527 0x3eb04077, 0x3fefbbf4, 0x03f31ca8,
528 0x3ec06884, 0x000fbff2, 0x03031c9e },
529 },
530 { 0x2a00, {
531 0x3f0fc42d, 0x3f0fc42d, 0x090240c4,
532 0x3eefd439, 0x3f2fb822, 0x08526cc2,
533 0x3edfe845, 0x3f4fb018, 0x078294bf,
534 0x3ec00051, 0x3f6fac0f, 0x06b2b4bb,
535 0x3ec0185f, 0x3f8fac07, 0x05e2ccb4,
536 0x3ec0386b, 0x3fafac00, 0x0502e8ac,
537 0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3,
538 0x3ef08482, 0x3fdfbbf6, 0x0372f898 },
539 },
540 { 0x2c00, {
541 0x3eefdc31, 0x3eefdc31, 0x08e238b8,
542 0x3edfec3d, 0x3f0fc828, 0x082258b9,
543 0x3ed00049, 0x3f1fc01e, 0x077278b6,
544 0x3ed01455, 0x3f3fb815, 0x06c294b2,
545 0x3ed03460, 0x3f5fb40d, 0x0602acac,
546 0x3ef0506c, 0x3f7fb006, 0x0542c0a4,
547 0x3f107476, 0x3f9fb400, 0x0472c89d,
548 0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 },
549 },
550 { 0x2e00, {
551 0x3eefec37, 0x3eefec37, 0x088220b0,
552 0x3ee00041, 0x3effdc2d, 0x07f244ae,
553 0x3ee0144c, 0x3f0fd023, 0x07625cad,
554 0x3ef02c57, 0x3f1fc81a, 0x06c274a9,
555 0x3f004861, 0x3f3fbc13, 0x060288a6,
556 0x3f20686b, 0x3f5fb80c, 0x05529c9e,
557 0x3f408c74, 0x3f6fb805, 0x04b2ac96,
558 0x3f80ac7e, 0x3f8fb800, 0x0402ac8e },
559 },
560 { 0x3000, {
561 0x3ef0003a, 0x3ef0003a, 0x084210a6,
562 0x3ef01045, 0x3effec32, 0x07b228a7,
563 0x3f00284e, 0x3f0fdc29, 0x073244a4,
564 0x3f104058, 0x3f0fd420, 0x06a258a2,
565 0x3f305c62, 0x3f2fc818, 0x0612689d,
566 0x3f508069, 0x3f3fc011, 0x05728496,
567 0x3f80a072, 0x3f4fc00a, 0x04d28c90,
568 0x3fc0c07b, 0x3f6fbc04, 0x04429088 },
569 },
570 { 0x3200, {
571 0x3f00103e, 0x3f00103e, 0x07f1fc9e,
572 0x3f102447, 0x3f000035, 0x0782149d,
573 0x3f203c4f, 0x3f0ff02c, 0x07122c9c,
574 0x3f405458, 0x3f0fe424, 0x06924099,
575 0x3f607061, 0x3f1fd41d, 0x06024c97,
576 0x3f909068, 0x3f2fcc16, 0x05726490,
577 0x3fc0b070, 0x3f3fc80f, 0x04f26c8a,
578 0x0000d077, 0x3f4fc409, 0x04627484 },
579 },
580 { 0x3400, {
581 0x3f202040, 0x3f202040, 0x07a1e898,
582 0x3f303449, 0x3f100c38, 0x0741fc98,
583 0x3f504c50, 0x3f10002f, 0x06e21495,
584 0x3f706459, 0x3f1ff028, 0x06722492,
585 0x3fa08060, 0x3f1fe421, 0x05f2348f,
586 0x3fd09c67, 0x3f1fdc19, 0x05824c89,
587 0x0000bc6e, 0x3f2fd014, 0x04f25086,
588 0x0040dc74, 0x3f3fcc0d, 0x04825c7f },
589 },
590 { 0x3600, {
591 0x3f403042, 0x3f403042, 0x0761d890,
592 0x3f504848, 0x3f301c3b, 0x0701f090,
593 0x3f805c50, 0x3f200c33, 0x06a2008f,
594 0x3fa07458, 0x3f10002b, 0x06520c8d,
595 0x3fd0905e, 0x3f1ff424, 0x05e22089,
596 0x0000ac65, 0x3f1fe81d, 0x05823483,
597 0x0030cc6a, 0x3f2fdc18, 0x04f23c81,
598 0x0080e871, 0x3f2fd412, 0x0482407c },
599 },
600 { 0x3800, {
601 0x3f604043, 0x3f604043, 0x0721c88a,
602 0x3f80544a, 0x3f502c3c, 0x06d1d88a,
603 0x3fb06851, 0x3f301c35, 0x0681e889,
604 0x3fd08456, 0x3f30082f, 0x0611fc88,
605 0x00009c5d, 0x3f200027, 0x05d20884,
606 0x0030b863, 0x3f2ff421, 0x05621880,
607 0x0070d468, 0x3f2fe81b, 0x0502247c,
608 0x00c0ec6f, 0x3f2fe015, 0x04a22877 },
609 },
610 { 0x3a00, {
611 0x3f904c44, 0x3f904c44, 0x06e1b884,
612 0x3fb0604a, 0x3f70383e, 0x0691c885,
613 0x3fe07451, 0x3f502c36, 0x0661d483,
614 0x00009055, 0x3f401831, 0x0601ec81,
615 0x0030a85b, 0x3f300c2a, 0x05b1f480,
616 0x0070c061, 0x3f300024, 0x0562047a,
617 0x00b0d867, 0x3f3ff41e, 0x05020c77,
618 0x00f0f46b, 0x3f2fec19, 0x04a21474 },
619 },
620 { 0x3c00, {
621 0x3fb05c43, 0x3fb05c43, 0x06c1b07e,
622 0x3fe06c4b, 0x3f902c3f, 0x0681c081,
623 0x0000844f, 0x3f703838, 0x0631cc7d,
624 0x00309855, 0x3f602433, 0x05d1d47e,
625 0x0060b459, 0x3f50142e, 0x0581e47b,
626 0x00a0c85f, 0x3f400828, 0x0531f078,
627 0x00e0e064, 0x3f300021, 0x0501fc73,
628 0x00b0fc6a, 0x3f3ff41d, 0x04a20873 },
629 },
630 { 0x3e00, {
631 0x3fe06444, 0x3fe06444, 0x0681a07a,
632 0x00007849, 0x3fc0503f, 0x0641b07a,
633 0x0020904d, 0x3fa0403a, 0x05f1c07a,
634 0x0060a453, 0x3f803034, 0x05c1c878,
635 0x0090b858, 0x3f70202f, 0x0571d477,
636 0x00d0d05d, 0x3f501829, 0x0531e073,
637 0x0110e462, 0x3f500825, 0x04e1e471,
638 0x01510065, 0x3f40001f, 0x04a1f06d },
639 },
640 { 0x4000, {
641 0x00007044, 0x00007044, 0x06519476,
642 0x00208448, 0x3fe05c3f, 0x0621a476,
643 0x0050984d, 0x3fc04c3a, 0x05e1b075,
644 0x0080ac52, 0x3fa03c35, 0x05a1b875,
645 0x00c0c056, 0x3f803030, 0x0561c473,
646 0x0100d45b, 0x3f70202b, 0x0521d46f,
647 0x0140e860, 0x3f601427, 0x04d1d46e,
648 0x01810064, 0x3f500822, 0x0491dc6b },
649 },
650 { 0x5000, {
651 0x0110a442, 0x0110a442, 0x0551545e,
652 0x0140b045, 0x00e0983f, 0x0531585f,
653 0x0160c047, 0x00c08c3c, 0x0511645e,
654 0x0190cc4a, 0x00908039, 0x04f1685f,
655 0x01c0dc4c, 0x00707436, 0x04d1705e,
656 0x0200e850, 0x00506833, 0x04b1785b,
657 0x0230f453, 0x00305c30, 0x0491805a,
658 0x02710056, 0x0010542d, 0x04718059 },
659 },
660 { 0x6000, {
661 0x01c0bc40, 0x01c0bc40, 0x04c13052,
662 0x01e0c841, 0x01a0b43d, 0x04c13851,
663 0x0210cc44, 0x0180a83c, 0x04a13453,
664 0x0230d845, 0x0160a03a, 0x04913c52,
665 0x0260e047, 0x01409838, 0x04714052,
666 0x0280ec49, 0x01208c37, 0x04514c50,
667 0x02b0f44b, 0x01008435, 0x04414c50,
668 0x02d1004c, 0x00e07c33, 0x0431544f },
669 },
670 { 0x7000, {
671 0x0230c83e, 0x0230c83e, 0x04711c4c,
672 0x0250d03f, 0x0210c43c, 0x0471204b,
673 0x0270d840, 0x0200b83c, 0x0451244b,
674 0x0290dc42, 0x01e0b43a, 0x0441244c,
675 0x02b0e443, 0x01c0b038, 0x0441284b,
676 0x02d0ec44, 0x01b0a438, 0x0421304a,
677 0x02f0f445, 0x0190a036, 0x04213449,
678 0x0310f847, 0x01709c34, 0x04213848 },
679 },
680 { 0x8000, {
681 0x0280d03d, 0x0280d03d, 0x04310c48,
682 0x02a0d43e, 0x0270c83c, 0x04311047,
683 0x02b0dc3e, 0x0250c83a, 0x04311447,
684 0x02d0e040, 0x0240c03a, 0x04211446,
685 0x02e0e840, 0x0220bc39, 0x04111847,
686 0x0300e842, 0x0210b438, 0x04012445,
687 0x0310f043, 0x0200b037, 0x04012045,
688 0x0330f444, 0x01e0ac36, 0x03f12445 },
689 },
690 { 0xefff, {
691 0x0340dc3a, 0x0340dc3a, 0x03b0ec40,
692 0x0340e03a, 0x0330e039, 0x03c0f03e,
693 0x0350e03b, 0x0330dc39, 0x03c0ec3e,
694 0x0350e43a, 0x0320dc38, 0x03c0f43e,
695 0x0360e43b, 0x0320d839, 0x03b0f03e,
696 0x0360e83b, 0x0310d838, 0x03c0fc3b,
697 0x0370e83b, 0x0310d439, 0x03a0f83d,
698 0x0370e83c, 0x0300d438, 0x03b0fc3c },
699 }
700};
701
702static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
703{
704 int i;
705 const struct vin_coeff *p_prev_set = NULL;
706 const struct vin_coeff *p_set = NULL;
707
708
709 for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
710 p_prev_set = p_set;
711 p_set = &vin_coeff_set[i];
712
713 if (xs < p_set->xs_value)
714 break;
715 }
716
717
718 if (p_prev_set && p_set &&
719 xs - p_prev_set->xs_value < p_set->xs_value - xs)
720 p_set = p_prev_set;
721
722
723 rvin_write(vin, p_set->coeff_set[0], VNC1A_REG);
724 rvin_write(vin, p_set->coeff_set[1], VNC1B_REG);
725 rvin_write(vin, p_set->coeff_set[2], VNC1C_REG);
726
727 rvin_write(vin, p_set->coeff_set[3], VNC2A_REG);
728 rvin_write(vin, p_set->coeff_set[4], VNC2B_REG);
729 rvin_write(vin, p_set->coeff_set[5], VNC2C_REG);
730
731 rvin_write(vin, p_set->coeff_set[6], VNC3A_REG);
732 rvin_write(vin, p_set->coeff_set[7], VNC3B_REG);
733 rvin_write(vin, p_set->coeff_set[8], VNC3C_REG);
734
735 rvin_write(vin, p_set->coeff_set[9], VNC4A_REG);
736 rvin_write(vin, p_set->coeff_set[10], VNC4B_REG);
737 rvin_write(vin, p_set->coeff_set[11], VNC4C_REG);
738
739 rvin_write(vin, p_set->coeff_set[12], VNC5A_REG);
740 rvin_write(vin, p_set->coeff_set[13], VNC5B_REG);
741 rvin_write(vin, p_set->coeff_set[14], VNC5C_REG);
742
743 rvin_write(vin, p_set->coeff_set[15], VNC6A_REG);
744 rvin_write(vin, p_set->coeff_set[16], VNC6B_REG);
745 rvin_write(vin, p_set->coeff_set[17], VNC6C_REG);
746
747 rvin_write(vin, p_set->coeff_set[18], VNC7A_REG);
748 rvin_write(vin, p_set->coeff_set[19], VNC7B_REG);
749 rvin_write(vin, p_set->coeff_set[20], VNC7C_REG);
750
751 rvin_write(vin, p_set->coeff_set[21], VNC8A_REG);
752 rvin_write(vin, p_set->coeff_set[22], VNC8B_REG);
753 rvin_write(vin, p_set->coeff_set[23], VNC8C_REG);
754}
755
756void rvin_crop_scale_comp(struct rvin_dev *vin)
757{
758 u32 xs, ys;
759
760
761 rvin_write(vin, vin->crop.left, VNSPPRC_REG);
762 rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
763 switch (vin->format.field) {
764 case V4L2_FIELD_INTERLACED:
765 case V4L2_FIELD_INTERLACED_TB:
766 case V4L2_FIELD_INTERLACED_BT:
767 rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG);
768 rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1,
769 VNELPRC_REG);
770 break;
771 default:
772 rvin_write(vin, vin->crop.top, VNSLPRC_REG);
773 rvin_write(vin, vin->crop.top + vin->crop.height - 1,
774 VNELPRC_REG);
775 break;
776 }
777
778
779 ys = 0;
780 if (vin->crop.height != vin->compose.height)
781 ys = (4096 * vin->crop.height) / vin->compose.height;
782 rvin_write(vin, ys, VNYS_REG);
783
784 xs = 0;
785 if (vin->crop.width != vin->compose.width)
786 xs = (4096 * vin->crop.width) / vin->compose.width;
787
788
789 if (xs > 0 && xs < 2048)
790 xs = 2048;
791
792 rvin_write(vin, xs, VNXS_REG);
793
794
795 if (xs < 4096)
796 xs *= 2;
797
798 rvin_set_coeff(vin, xs);
799
800
801 rvin_write(vin, 0, VNSPPOC_REG);
802 rvin_write(vin, 0, VNSLPOC_REG);
803 rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
804 switch (vin->format.field) {
805 case V4L2_FIELD_INTERLACED:
806 case V4L2_FIELD_INTERLACED_TB:
807 case V4L2_FIELD_INTERLACED_BT:
808 rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
809 break;
810 default:
811 rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
812 break;
813 }
814
815 if (vin->format.pixelformat == V4L2_PIX_FMT_NV16)
816 rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG);
817 else
818 rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG);
819
820 vin_dbg(vin,
821 "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
822 vin->crop.width, vin->crop.height, vin->crop.left,
823 vin->crop.top, ys, xs, vin->format.width, vin->format.height,
824 0, 0);
825}
826
827void rvin_scale_try(struct rvin_dev *vin, struct v4l2_pix_format *pix,
828 u32 width, u32 height)
829{
830
831 pix->width = width;
832 pix->height = height;
833}
834
835
836
837
838
839#define RVIN_TIMEOUT_MS 100
840#define RVIN_RETRIES 10
841
842struct rvin_buffer {
843 struct vb2_v4l2_buffer vb;
844 struct list_head list;
845};
846
847#define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
848 struct rvin_buffer, \
849 vb)->list)
850
851
852static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
853{
854 struct rvin_buffer *buf;
855 struct vb2_v4l2_buffer *vbuf;
856 dma_addr_t phys_addr_top;
857
858 if (vin->queue_buf[slot] != NULL)
859 return true;
860
861 if (list_empty(&vin->buf_list))
862 return false;
863
864 vin_dbg(vin, "Filling HW slot: %d\n", slot);
865
866
867 buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
868 vbuf = &buf->vb;
869 list_del_init(to_buf_list(vbuf));
870 vin->queue_buf[slot] = vbuf;
871
872
873 phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
874 rvin_set_slot_addr(vin, slot, phys_addr_top);
875
876 return true;
877}
878
879static bool rvin_fill_hw(struct rvin_dev *vin)
880{
881 int slot, limit;
882
883 limit = vin->continuous ? HW_BUFFER_NUM : 1;
884
885 for (slot = 0; slot < limit; slot++)
886 if (!rvin_fill_hw_slot(vin, slot))
887 return false;
888 return true;
889}
890
891static irqreturn_t rvin_irq(int irq, void *data)
892{
893 struct rvin_dev *vin = data;
894 u32 int_status, vnms;
895 int slot;
896 unsigned int sequence, handled = 0;
897 unsigned long flags;
898
899 spin_lock_irqsave(&vin->qlock, flags);
900
901 int_status = rvin_get_interrupt_status(vin);
902 if (!int_status)
903 goto done;
904
905 rvin_ack_interrupt(vin);
906 handled = 1;
907
908
909 if (vin->state == STOPPED) {
910 vin_dbg(vin, "IRQ while state stopped\n");
911 goto done;
912 }
913
914
915 if (vin->state == STOPPING) {
916 vin_dbg(vin, "IRQ while state stopping\n");
917 goto done;
918 }
919
920
921 vnms = rvin_read(vin, VNMS_REG);
922 slot = rvin_get_active_slot(vin, vnms);
923 sequence = vin->sequence++;
924
925 vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n",
926 sequence, slot,
927 slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0',
928 slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0',
929 slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0',
930 !list_empty(&vin->buf_list));
931
932
933 if (WARN_ON((vin->queue_buf[slot] == NULL)))
934 goto done;
935
936
937 vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
938 vin->queue_buf[slot]->sequence = sequence;
939 vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
940 vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE);
941 vin->queue_buf[slot] = NULL;
942
943
944 if (!rvin_fill_hw(vin)) {
945
946
947
948
949
950 vin->state = STALLED;
951
952
953
954
955
956
957 if (vin->continuous) {
958 rvin_capture_off(vin);
959 vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence);
960 }
961 } else {
962
963
964
965
966 if (!vin->continuous)
967 rvin_capture_on(vin);
968 }
969done:
970 spin_unlock_irqrestore(&vin->qlock, flags);
971
972 return IRQ_RETVAL(handled);
973}
974
975
976static void return_all_buffers(struct rvin_dev *vin,
977 enum vb2_buffer_state state)
978{
979 struct rvin_buffer *buf, *node;
980 int i;
981
982 for (i = 0; i < HW_BUFFER_NUM; i++) {
983 if (vin->queue_buf[i]) {
984 vb2_buffer_done(&vin->queue_buf[i]->vb2_buf,
985 state);
986 vin->queue_buf[i] = NULL;
987 }
988 }
989
990 list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
991 vb2_buffer_done(&buf->vb.vb2_buf, state);
992 list_del(&buf->list);
993 }
994}
995
996static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
997 unsigned int *nplanes, unsigned int sizes[],
998 struct device *alloc_devs[])
999
1000{
1001 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1002
1003
1004 if (*nplanes)
1005 return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1006
1007 *nplanes = 1;
1008 sizes[0] = vin->format.sizeimage;
1009
1010 return 0;
1011};
1012
1013static int rvin_buffer_prepare(struct vb2_buffer *vb)
1014{
1015 struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1016 unsigned long size = vin->format.sizeimage;
1017
1018 if (vb2_plane_size(vb, 0) < size) {
1019 vin_err(vin, "buffer too small (%lu < %lu)\n",
1020 vb2_plane_size(vb, 0), size);
1021 return -EINVAL;
1022 }
1023
1024 vb2_set_plane_payload(vb, 0, size);
1025
1026 return 0;
1027}
1028
1029static void rvin_buffer_queue(struct vb2_buffer *vb)
1030{
1031 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1032 struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1033 unsigned long flags;
1034
1035 spin_lock_irqsave(&vin->qlock, flags);
1036
1037 list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1038
1039
1040
1041
1042
1043 if (vin->state == STALLED)
1044 if (rvin_fill_hw(vin))
1045 rvin_capture_on(vin);
1046
1047 spin_unlock_irqrestore(&vin->qlock, flags);
1048}
1049
1050static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
1051{
1052 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1053 struct v4l2_subdev *sd;
1054 unsigned long flags;
1055 int ret;
1056
1057 sd = vin_to_source(vin);
1058 v4l2_subdev_call(sd, video, s_stream, 1);
1059
1060 spin_lock_irqsave(&vin->qlock, flags);
1061
1062 vin->state = RUNNING;
1063 vin->sequence = 0;
1064
1065
1066 vin->continuous = count > HW_BUFFER_NUM;
1067
1068
1069
1070
1071
1072 if (!rvin_fill_hw(vin)) {
1073 vin_err(vin, "HW not ready to start, not enough buffers available\n");
1074 ret = -EINVAL;
1075 goto out;
1076 }
1077
1078 ret = rvin_capture_start(vin);
1079out:
1080
1081 if (ret) {
1082 return_all_buffers(vin, VB2_BUF_STATE_QUEUED);
1083 v4l2_subdev_call(sd, video, s_stream, 0);
1084 }
1085
1086 spin_unlock_irqrestore(&vin->qlock, flags);
1087
1088 return ret;
1089}
1090
1091static void rvin_stop_streaming(struct vb2_queue *vq)
1092{
1093 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1094 struct v4l2_subdev *sd;
1095 unsigned long flags;
1096 int retries = 0;
1097
1098 spin_lock_irqsave(&vin->qlock, flags);
1099
1100 vin->state = STOPPING;
1101
1102
1103 while (retries++ < RVIN_RETRIES) {
1104
1105 rvin_capture_stop(vin);
1106
1107
1108 if (!rvin_capture_active(vin)) {
1109 vin->state = STOPPED;
1110 break;
1111 }
1112
1113 spin_unlock_irqrestore(&vin->qlock, flags);
1114 msleep(RVIN_TIMEOUT_MS);
1115 spin_lock_irqsave(&vin->qlock, flags);
1116 }
1117
1118 if (vin->state != STOPPED) {
1119
1120
1121
1122
1123
1124 vin_err(vin, "Failed stop HW, something is seriously broken\n");
1125 vin->state = STOPPED;
1126 }
1127
1128
1129 return_all_buffers(vin, VB2_BUF_STATE_ERROR);
1130
1131 spin_unlock_irqrestore(&vin->qlock, flags);
1132
1133 sd = vin_to_source(vin);
1134 v4l2_subdev_call(sd, video, s_stream, 0);
1135
1136
1137 rvin_disable_interrupts(vin);
1138}
1139
1140static const struct vb2_ops rvin_qops = {
1141 .queue_setup = rvin_queue_setup,
1142 .buf_prepare = rvin_buffer_prepare,
1143 .buf_queue = rvin_buffer_queue,
1144 .start_streaming = rvin_start_streaming,
1145 .stop_streaming = rvin_stop_streaming,
1146 .wait_prepare = vb2_ops_wait_prepare,
1147 .wait_finish = vb2_ops_wait_finish,
1148};
1149
1150void rvin_dma_remove(struct rvin_dev *vin)
1151{
1152 mutex_destroy(&vin->lock);
1153
1154 v4l2_device_unregister(&vin->v4l2_dev);
1155}
1156
1157int rvin_dma_probe(struct rvin_dev *vin, int irq)
1158{
1159 struct vb2_queue *q = &vin->queue;
1160 int i, ret;
1161
1162
1163 ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1164 if (ret)
1165 return ret;
1166
1167 mutex_init(&vin->lock);
1168 INIT_LIST_HEAD(&vin->buf_list);
1169
1170 spin_lock_init(&vin->qlock);
1171
1172 vin->state = STOPPED;
1173
1174 for (i = 0; i < HW_BUFFER_NUM; i++)
1175 vin->queue_buf[i] = NULL;
1176
1177
1178 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1179 q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
1180 q->lock = &vin->lock;
1181 q->drv_priv = vin;
1182 q->buf_struct_size = sizeof(struct rvin_buffer);
1183 q->ops = &rvin_qops;
1184 q->mem_ops = &vb2_dma_contig_memops;
1185 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1186 q->min_buffers_needed = 2;
1187 q->dev = vin->dev;
1188
1189 ret = vb2_queue_init(q);
1190 if (ret < 0) {
1191 vin_err(vin, "failed to initialize VB2 queue\n");
1192 goto error;
1193 }
1194
1195
1196 ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED,
1197 KBUILD_MODNAME, vin);
1198 if (ret) {
1199 vin_err(vin, "failed to request irq\n");
1200 goto error;
1201 }
1202
1203 return 0;
1204error:
1205 rvin_dma_remove(vin);
1206
1207 return ret;
1208}
1209