sh_eth: fix EESIPR values for SH77{34|63}
[linux/fpc-iii.git] / drivers / media / platform / rcar-vin / rcar-dma.c
blob9ccd5ff55e19251440038b514e258265af282212
1 /*
2 * Driver for Renesas R-Car VIN
4 * Copyright (C) 2016 Renesas Electronics Corp.
5 * Copyright (C) 2011-2013 Renesas Solutions Corp.
6 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
7 * Copyright (C) 2008 Magnus Damm
9 * Based on the soc-camera rcar_vin driver
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
17 #include <linux/delay.h>
18 #include <linux/interrupt.h>
20 #include <media/videobuf2-dma-contig.h>
22 #include "rcar-vin.h"
24 /* -----------------------------------------------------------------------------
25 * HW Functions
28 /* Register offsets for R-Car VIN */
29 #define VNMC_REG 0x00 /* Video n Main Control Register */
30 #define VNMS_REG 0x04 /* Video n Module Status Register */
31 #define VNFC_REG 0x08 /* Video n Frame Capture Register */
32 #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */
33 #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */
34 #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */
35 #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */
36 #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */
37 #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */
38 #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */
39 #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */
40 #define VNIS_REG 0x2C /* Video n Image Stride Register */
41 #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */
42 #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */
43 #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */
44 #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */
45 #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */
46 #define VNYS_REG 0x50 /* Video n Y Scale Register */
47 #define VNXS_REG 0x54 /* Video n X Scale Register */
48 #define VNDMR_REG 0x58 /* Video n Data Mode Register */
49 #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */
50 #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */
51 #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */
52 #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */
53 #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */
54 #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */
55 #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */
56 #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */
57 #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */
58 #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */
59 #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */
60 #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */
61 #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */
62 #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */
63 #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */
64 #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */
65 #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */
66 #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */
67 #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */
68 #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */
69 #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */
70 #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */
71 #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */
72 #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */
73 #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */
74 #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */
77 /* Register bit fields for R-Car VIN */
78 /* Video n Main Control Register bits */
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)
95 /* Video n Module Status Register bits */
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)
102 /* Video n Frame Capture Register bits */
103 #define VNFC_C_FRAME (1 << 1)
104 #define VNFC_S_FRAME (1 << 0)
106 /* Video n Interrupt Enable Register bits */
107 #define VNIE_FIE (1 << 4)
108 #define VNIE_EFE (1 << 1)
110 /* Video n Data Mode Register bits */
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)
116 /* Video n Data Mode Register 2 bits */
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)
122 static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset)
124 iowrite32(value, vin->base + offset);
127 static u32 rvin_read(struct rvin_dev *vin, u32 offset)
129 return ioread32(vin->base + offset);
132 static int rvin_setup(struct rvin_dev *vin)
134 u32 vnmc, dmr, dmr2, interrupts;
135 v4l2_std_id std;
136 bool progressive = false, output_is_yuv = false, input_is_yuv = false;
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 /* Default to TB */
147 vnmc = VNMC_IM_FULL;
148 /* Use BT if video standard can be read and is 60 Hz format */
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;
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;
168 break;
169 default:
170 vnmc = VNMC_IM_ODD;
171 break;
175 * Input interface
177 switch (vin->digital.code) {
178 case MEDIA_BUS_FMT_YUYV8_1X16:
179 /* BT.601/BT.1358 16bit YCbCr422 */
180 vnmc |= VNMC_INF_YUV16;
181 input_is_yuv = true;
182 break;
183 case MEDIA_BUS_FMT_UYVY8_2X8:
184 /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
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 /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
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;
202 /* Enable VSYNC Field Toogle mode after one VSYNC input */
203 dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
205 /* Hsync Signal Polarity Select */
206 if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
207 dmr2 |= VNDMR2_HPS;
209 /* Vsync Signal Polarity Select */
210 if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
211 dmr2 |= VNDMR2_VPS;
214 * Output format
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 /* Note: not supported on M1 */
240 dmr = VNDMR_EXRGB;
241 break;
242 default:
243 vin_err(vin, "Invalid pixelformat (0x%x)\n",
244 vin->format.pixelformat);
245 return -EINVAL;
248 /* Always update on field change */
249 vnmc |= VNMC_VUP;
251 /* If input and output use the same colorspace, use bypass mode */
252 if (input_is_yuv == output_is_yuv)
253 vnmc |= VNMC_BPS;
255 /* Progressive or interlaced mode */
256 interrupts = progressive ? VNIE_FIE : VNIE_EFE;
258 /* Ack interrupts */
259 rvin_write(vin, interrupts, VNINTS_REG);
260 /* Enable interrupts */
261 rvin_write(vin, interrupts, VNIE_REG);
262 /* Start capturing */
263 rvin_write(vin, dmr, VNDMR_REG);
264 rvin_write(vin, dmr2, VNDMR2_REG);
266 /* Enable module */
267 rvin_write(vin, vnmc | VNMC_ME, VNMC_REG);
269 return 0;
272 static void rvin_capture_on(struct rvin_dev *vin)
274 vin_dbg(vin, "Capture on in %s mode\n",
275 vin->continuous ? "continuous" : "single");
277 if (vin->continuous)
278 /* Continuous Frame Capture Mode */
279 rvin_write(vin, VNFC_C_FRAME, VNFC_REG);
280 else
281 /* Single Frame Capture Mode */
282 rvin_write(vin, VNFC_S_FRAME, VNFC_REG);
285 static void rvin_capture_off(struct rvin_dev *vin)
287 /* Set continuous & single transfer off */
288 rvin_write(vin, 0, VNFC_REG);
291 static int rvin_capture_start(struct rvin_dev *vin)
293 int ret;
295 rvin_crop_scale_comp(vin);
297 ret = rvin_setup(vin);
298 if (ret)
299 return ret;
301 rvin_capture_on(vin);
303 return 0;
306 static void rvin_capture_stop(struct rvin_dev *vin)
308 rvin_capture_off(vin);
310 /* Disable module */
311 rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG);
314 static void rvin_disable_interrupts(struct rvin_dev *vin)
316 rvin_write(vin, 0, VNIE_REG);
319 static u32 rvin_get_interrupt_status(struct rvin_dev *vin)
321 return rvin_read(vin, VNINTS_REG);
324 static void rvin_ack_interrupt(struct rvin_dev *vin)
326 rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG);
329 static bool rvin_capture_active(struct rvin_dev *vin)
331 return rvin_read(vin, VNMS_REG) & VNMS_CA;
334 static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms)
336 if (vin->continuous)
337 return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT;
339 return 0;
342 static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
344 if (vin->format.field == V4L2_FIELD_ALTERNATE) {
345 /* If FS is set it's a Even field */
346 if (vnms & VNMS_FS)
347 return V4L2_FIELD_BOTTOM;
348 return V4L2_FIELD_TOP;
351 return vin->format.field;
354 static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
356 const struct rvin_video_format *fmt;
357 int offsetx, offsety;
358 dma_addr_t offset;
360 fmt = rvin_format_from_pixel(vin->format.pixelformat);
363 * There is no HW support for composition do the beast we can
364 * by modifying the buffer offset
366 offsetx = vin->compose.left * fmt->bpp;
367 offsety = vin->compose.top * vin->format.bytesperline;
368 offset = addr + offsetx + offsety;
371 * The address needs to be 128 bytes aligned. Driver should never accept
372 * settings that do not satisfy this in the first place...
374 if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK))
375 return;
377 rvin_write(vin, offset, VNMB_REG(slot));
380 /* -----------------------------------------------------------------------------
381 * Crop and Scaling Gen2
384 struct vin_coeff {
385 unsigned short xs_value;
386 u32 coeff_set[24];
389 static 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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
702 static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
704 int i;
705 const struct vin_coeff *p_prev_set = NULL;
706 const struct vin_coeff *p_set = NULL;
708 /* Look for suitable coefficient values */
709 for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) {
710 p_prev_set = p_set;
711 p_set = &vin_coeff_set[i];
713 if (xs < p_set->xs_value)
714 break;
717 /* Use previous value if its XS value is closer */
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;
722 /* Set coefficient registers */
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);
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);
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);
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);
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);
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);
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);
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);
756 void rvin_crop_scale_comp(struct rvin_dev *vin)
758 u32 xs, ys;
760 /* Set Start/End Pixel/Line Pre-Clip */
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;
778 /* Set scaling coefficient */
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);
784 xs = 0;
785 if (vin->crop.width != vin->compose.width)
786 xs = (4096 * vin->crop.width) / vin->compose.width;
788 /* Horizontal upscaling is up to double size */
789 if (xs > 0 && xs < 2048)
790 xs = 2048;
792 rvin_write(vin, xs, VNXS_REG);
794 /* Horizontal upscaling is done out by scaling down from double size */
795 if (xs < 4096)
796 xs *= 2;
798 rvin_set_coeff(vin, xs);
800 /* Set Start/End Pixel/Line Post-Clip */
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;
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);
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);
827 void rvin_scale_try(struct rvin_dev *vin, struct v4l2_pix_format *pix,
828 u32 width, u32 height)
830 /* All VIN channels on Gen2 have scalers */
831 pix->width = width;
832 pix->height = height;
835 /* -----------------------------------------------------------------------------
836 * DMA Functions
839 #define RVIN_TIMEOUT_MS 100
840 #define RVIN_RETRIES 10
842 struct rvin_buffer {
843 struct vb2_v4l2_buffer vb;
844 struct list_head list;
847 #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \
848 struct rvin_buffer, \
849 vb)->list)
851 /* Moves a buffer from the queue to the HW slots */
852 static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
854 struct rvin_buffer *buf;
855 struct vb2_v4l2_buffer *vbuf;
856 dma_addr_t phys_addr_top;
858 if (vin->queue_buf[slot] != NULL)
859 return true;
861 if (list_empty(&vin->buf_list))
862 return false;
864 vin_dbg(vin, "Filling HW slot: %d\n", slot);
866 /* Keep track of buffer we give to HW */
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;
872 /* Setup DMA */
873 phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
874 rvin_set_slot_addr(vin, slot, phys_addr_top);
876 return true;
879 static bool rvin_fill_hw(struct rvin_dev *vin)
881 int slot, limit;
883 limit = vin->continuous ? HW_BUFFER_NUM : 1;
885 for (slot = 0; slot < limit; slot++)
886 if (!rvin_fill_hw_slot(vin, slot))
887 return false;
888 return true;
891 static irqreturn_t rvin_irq(int irq, void *data)
893 struct rvin_dev *vin = data;
894 u32 int_status, vnms;
895 int slot;
896 unsigned int sequence, handled = 0;
897 unsigned long flags;
899 spin_lock_irqsave(&vin->qlock, flags);
901 int_status = rvin_get_interrupt_status(vin);
902 if (!int_status)
903 goto done;
905 rvin_ack_interrupt(vin);
906 handled = 1;
908 /* Nothing to do if capture status is 'STOPPED' */
909 if (vin->state == STOPPED) {
910 vin_dbg(vin, "IRQ while state stopped\n");
911 goto done;
914 /* Nothing to do if capture status is 'STOPPING' */
915 if (vin->state == STOPPING) {
916 vin_dbg(vin, "IRQ while state stopping\n");
917 goto done;
920 /* Prepare for capture and update state */
921 vnms = rvin_read(vin, VNMS_REG);
922 slot = rvin_get_active_slot(vin, vnms);
923 sequence = vin->sequence++;
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));
932 /* HW have written to a slot that is not prepared we are in trouble */
933 if (WARN_ON((vin->queue_buf[slot] == NULL)))
934 goto done;
936 /* Capture frame */
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;
943 /* Prepare for next frame */
944 if (!rvin_fill_hw(vin)) {
947 * Can't supply HW with new buffers fast enough. Halt
948 * capture until more buffers are available.
950 vin->state = STALLED;
953 * The continuous capturing requires an explicit stop
954 * operation when there is no buffer to be set into
955 * the VnMBm registers.
957 if (vin->continuous) {
958 rvin_capture_off(vin);
959 vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence);
961 } else {
963 * The single capturing requires an explicit capture
964 * operation to fetch the next frame.
966 if (!vin->continuous)
967 rvin_capture_on(vin);
969 done:
970 spin_unlock_irqrestore(&vin->qlock, flags);
972 return IRQ_RETVAL(handled);
975 /* Need to hold qlock before calling */
976 static void return_all_buffers(struct rvin_dev *vin,
977 enum vb2_buffer_state state)
979 struct rvin_buffer *buf, *node;
980 int i;
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;
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);
996 static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
997 unsigned int *nplanes, unsigned int sizes[],
998 struct device *alloc_devs[])
1001 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1003 /* Make sure the image size is large enough. */
1004 if (*nplanes)
1005 return sizes[0] < vin->format.sizeimage ? -EINVAL : 0;
1007 *nplanes = 1;
1008 sizes[0] = vin->format.sizeimage;
1010 return 0;
1013 static int rvin_buffer_prepare(struct vb2_buffer *vb)
1015 struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue);
1016 unsigned long size = vin->format.sizeimage;
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;
1024 vb2_set_plane_payload(vb, 0, size);
1026 return 0;
1029 static void rvin_buffer_queue(struct vb2_buffer *vb)
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;
1035 spin_lock_irqsave(&vin->qlock, flags);
1037 list_add_tail(to_buf_list(vbuf), &vin->buf_list);
1040 * If capture is stalled add buffer to HW and restart
1041 * capturing if HW is ready to continue.
1043 if (vin->state == STALLED)
1044 if (rvin_fill_hw(vin))
1045 rvin_capture_on(vin);
1047 spin_unlock_irqrestore(&vin->qlock, flags);
1050 static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count)
1052 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1053 struct v4l2_subdev *sd;
1054 unsigned long flags;
1055 int ret;
1057 sd = vin_to_source(vin);
1058 v4l2_subdev_call(sd, video, s_stream, 1);
1060 spin_lock_irqsave(&vin->qlock, flags);
1062 vin->state = RUNNING;
1063 vin->sequence = 0;
1065 /* Continuous capture requires more buffers then there are HW slots */
1066 vin->continuous = count > HW_BUFFER_NUM;
1069 * This should never happen but if we don't have enough
1070 * buffers for HW bail out
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;
1078 ret = rvin_capture_start(vin);
1079 out:
1080 /* Return all buffers if something went wrong */
1081 if (ret) {
1082 return_all_buffers(vin, VB2_BUF_STATE_QUEUED);
1083 v4l2_subdev_call(sd, video, s_stream, 0);
1086 spin_unlock_irqrestore(&vin->qlock, flags);
1088 return ret;
1091 static void rvin_stop_streaming(struct vb2_queue *vq)
1093 struct rvin_dev *vin = vb2_get_drv_priv(vq);
1094 struct v4l2_subdev *sd;
1095 unsigned long flags;
1096 int retries = 0;
1098 spin_lock_irqsave(&vin->qlock, flags);
1100 vin->state = STOPPING;
1102 /* Wait for streaming to stop */
1103 while (retries++ < RVIN_RETRIES) {
1105 rvin_capture_stop(vin);
1107 /* Check if HW is stopped */
1108 if (!rvin_capture_active(vin)) {
1109 vin->state = STOPPED;
1110 break;
1113 spin_unlock_irqrestore(&vin->qlock, flags);
1114 msleep(RVIN_TIMEOUT_MS);
1115 spin_lock_irqsave(&vin->qlock, flags);
1118 if (vin->state != STOPPED) {
1120 * If this happens something have gone horribly wrong.
1121 * Set state to stopped to prevent the interrupt handler
1122 * to make things worse...
1124 vin_err(vin, "Failed stop HW, something is seriously broken\n");
1125 vin->state = STOPPED;
1128 /* Release all active buffers */
1129 return_all_buffers(vin, VB2_BUF_STATE_ERROR);
1131 spin_unlock_irqrestore(&vin->qlock, flags);
1133 sd = vin_to_source(vin);
1134 v4l2_subdev_call(sd, video, s_stream, 0);
1136 /* disable interrupts */
1137 rvin_disable_interrupts(vin);
1140 static 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,
1150 void rvin_dma_remove(struct rvin_dev *vin)
1152 mutex_destroy(&vin->lock);
1154 v4l2_device_unregister(&vin->v4l2_dev);
1157 int rvin_dma_probe(struct rvin_dev *vin, int irq)
1159 struct vb2_queue *q = &vin->queue;
1160 int i, ret;
1162 /* Initialize the top-level structure */
1163 ret = v4l2_device_register(vin->dev, &vin->v4l2_dev);
1164 if (ret)
1165 return ret;
1167 mutex_init(&vin->lock);
1168 INIT_LIST_HEAD(&vin->buf_list);
1170 spin_lock_init(&vin->qlock);
1172 vin->state = STOPPED;
1174 for (i = 0; i < HW_BUFFER_NUM; i++)
1175 vin->queue_buf[i] = NULL;
1177 /* buffer queue */
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;
1189 ret = vb2_queue_init(q);
1190 if (ret < 0) {
1191 vin_err(vin, "failed to initialize VB2 queue\n");
1192 goto error;
1195 /* irq */
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;
1203 return 0;
1204 error:
1205 rvin_dma_remove(vin);
1207 return ret;