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