GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / staging / media / tegra-video / tegra20.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Tegra20-specific VI implementation
4  *
5  * Copyright (C) 2023 SKIDATA GmbH
6  * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
7  */
8
9 /*
10  * This source file contains Tegra20 supported video formats,
11  * VI and VIP SoC specific data, operations and registers accessors.
12  */
13
14 #include <linux/bitfield.h>
15 #include <linux/delay.h>
16 #include <linux/host1x.h>
17 #include <linux/kernel.h>
18 #include <linux/kthread.h>
19 #include <linux/v4l2-mediabus.h>
20
21 #include "vip.h"
22 #include "vi.h"
23
24 #define TEGRA_VI_SYNCPT_WAIT_TIMEOUT                    msecs_to_jiffies(200)
25
26 /* This are just good-sense numbers. The actual min/max is not documented. */
27 #define TEGRA20_MIN_WIDTH       32U
28 #define TEGRA20_MIN_HEIGHT      32U
29 #define TEGRA20_MAX_WIDTH       2048U
30 #define TEGRA20_MAX_HEIGHT      2048U
31
32 /* --------------------------------------------------------------------------
33  * Registers
34  */
35
36 #define TEGRA_VI_CONT_SYNCPT_OUT_1                      0x0060
37 #define       VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT    BIT(8)
38 #define       VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT       0
39
40 #define TEGRA_VI_VI_INPUT_CONTROL                       0x0088
41 #define       VI_INPUT_FIELD_DETECT                     BIT(27)
42 #define       VI_INPUT_BT656                            BIT(25)
43 #define       VI_INPUT_YUV_INPUT_FORMAT_SFT             8  /* bits [9:8] */
44 #define       VI_INPUT_YUV_INPUT_FORMAT_UYVY            (0 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
45 #define       VI_INPUT_YUV_INPUT_FORMAT_VYUY            (1 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
46 #define       VI_INPUT_YUV_INPUT_FORMAT_YUYV            (2 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
47 #define       VI_INPUT_YUV_INPUT_FORMAT_YVYU            (3 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
48 #define       VI_INPUT_INPUT_FORMAT_SFT                 2  /* bits [5:2] */
49 #define       VI_INPUT_INPUT_FORMAT_YUV422              (0 << VI_INPUT_INPUT_FORMAT_SFT)
50 #define       VI_INPUT_VIP_INPUT_ENABLE                 BIT(1)
51
52 #define TEGRA_VI_VI_CORE_CONTROL                        0x008c
53 #define       VI_VI_CORE_CONTROL_PLANAR_CONV_IN_SEL_EXT BIT(31)
54 #define       VI_VI_CORE_CONTROL_CSC_INPUT_SEL_EXT      BIT(30)
55 #define       VI_VI_CORE_CONTROL_INPUT_TO_ALT_MUX_SFT   27
56 #define       VI_VI_CORE_CONTROL_INPUT_TO_CORE_EXT_SFT  24
57 #define       VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_EXT_SFT  21
58 #define       VI_VI_CORE_CONTROL_ISP_HOST_STALL_OFF     BIT(20)
59 #define       VI_VI_CORE_CONTROL_V_DOWNSCALING          BIT(19)
60 #define       VI_VI_CORE_CONTROL_V_AVERAGING            BIT(18)
61 #define       VI_VI_CORE_CONTROL_H_DOWNSCALING          BIT(17)
62 #define       VI_VI_CORE_CONTROL_H_AVERAGING            BIT(16)
63 #define       VI_VI_CORE_CONTROL_CSC_INPUT_SEL          BIT(11)
64 #define       VI_VI_CORE_CONTROL_PLANAR_CONV_INPUT_SEL  BIT(10)
65 #define       VI_VI_CORE_CONTROL_INPUT_TO_CORE_SFT      8
66 #define       VI_VI_CORE_CONTROL_ISP_DOWNSAMPLE_SFT     5
67 #define       VI_VI_CORE_CONTROL_OUTPUT_TO_EPP_SFT      2
68 #define       VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_SFT      0
69
70 #define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL                0x0090
71 #define       VI_OUTPUT_FORMAT_EXT                      BIT(22)
72 #define       VI_OUTPUT_V_DIRECTION                     BIT(20)
73 #define       VI_OUTPUT_H_DIRECTION                     BIT(19)
74 #define       VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT           17
75 #define       VI_OUTPUT_YUV_OUTPUT_FORMAT_UYVY          (0 << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT)
76 #define       VI_OUTPUT_YUV_OUTPUT_FORMAT_VYUY          (1 << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT)
77 #define       VI_OUTPUT_YUV_OUTPUT_FORMAT_YUYV          (2 << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT)
78 #define       VI_OUTPUT_YUV_OUTPUT_FORMAT_YVYU          (3 << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT)
79 #define       VI_OUTPUT_OUTPUT_BYTE_SWAP                BIT(16)
80 #define       VI_OUTPUT_LAST_PIXEL_DUPLICATION          BIT(8)
81 #define       VI_OUTPUT_OUTPUT_FORMAT_SFT               0
82 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST        (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
83 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR      (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
84
85 #define TEGRA_VI_VIP_H_ACTIVE                           0x00a4
86 #define       VI_VIP_H_ACTIVE_PERIOD_SFT                16 /* active pixels/line, must be even */
87 #define       VI_VIP_H_ACTIVE_START_SFT                 0
88
89 #define TEGRA_VI_VIP_V_ACTIVE                           0x00a8
90 #define       VI_VIP_V_ACTIVE_PERIOD_SFT                16 /* active lines */
91 #define       VI_VIP_V_ACTIVE_START_SFT                 0
92
93 #define TEGRA_VI_VB0_START_ADDRESS_FIRST                0x00c4
94 #define TEGRA_VI_VB0_BASE_ADDRESS_FIRST                 0x00c8
95 #define TEGRA_VI_VB0_START_ADDRESS_U                    0x00cc
96 #define TEGRA_VI_VB0_BASE_ADDRESS_U                     0x00d0
97 #define TEGRA_VI_VB0_START_ADDRESS_V                    0x00d4
98 #define TEGRA_VI_VB0_BASE_ADDRESS_V                     0x00d8
99
100 #define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE                0x00e0
101 #define       VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT          16
102 #define       VI_FIRST_OUTPUT_FRAME_WIDTH_SFT           0
103
104 #define TEGRA_VI_VB0_COUNT_FIRST                        0x00e4
105
106 #define TEGRA_VI_VB0_SIZE_FIRST                         0x00e8
107 #define       VI_VB0_SIZE_FIRST_V_SFT                   16
108 #define       VI_VB0_SIZE_FIRST_H_SFT                   0
109
110 #define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST                0x00ec
111 #define       VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT     30
112 #define       VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT       0
113
114 #define TEGRA_VI_H_LPF_CONTROL                          0x0108
115 #define       VI_H_LPF_CONTROL_CHROMA_SFT               16
116 #define       VI_H_LPF_CONTROL_LUMA_SFT                 0
117
118 #define TEGRA_VI_H_DOWNSCALE_CONTROL                    0x010c
119 #define TEGRA_VI_V_DOWNSCALE_CONTROL                    0x0110
120
121 #define TEGRA_VI_VIP_INPUT_STATUS                       0x0144
122
123 #define TEGRA_VI_VI_DATA_INPUT_CONTROL                  0x0168
124 #define       VI_DATA_INPUT_SFT                         0 /* [11:0] = mask pin inputs to VI core */
125
126 #define TEGRA_VI_PIN_INPUT_ENABLE                       0x016c
127 #define       VI_PIN_INPUT_VSYNC                        BIT(14)
128 #define       VI_PIN_INPUT_HSYNC                        BIT(13)
129 #define       VI_PIN_INPUT_VD_SFT                       0 /* [11:0] = data bin N input enable */
130
131 #define TEGRA_VI_PIN_INVERSION                          0x0174
132 #define       VI_PIN_INVERSION_VSYNC_ACTIVE_HIGH        BIT(1)
133 #define       VI_PIN_INVERSION_HSYNC_ACTIVE_HIGH        BIT(0)
134
135 #define TEGRA_VI_CAMERA_CONTROL                         0x01a0
136 #define       VI_CAMERA_CONTROL_STOP_CAPTURE            BIT(2)
137 #define       VI_CAMERA_CONTROL_TEST_MODE               BIT(1)
138 #define       VI_CAMERA_CONTROL_VIP_ENABLE              BIT(0)
139
140 #define TEGRA_VI_VI_ENABLE                              0x01a4
141 #define       VI_VI_ENABLE_SW_FLOW_CONTROL_OUT1         BIT(1)
142 #define       VI_VI_ENABLE_FIRST_OUTPUT_TO_MEM_DISABLE  BIT(0)
143
144 #define TEGRA_VI_VI_RAISE                               0x01ac
145 #define       VI_VI_RAISE_ON_EDGE                       BIT(0)
146
147 /* --------------------------------------------------------------------------
148  * VI
149  */
150
151 static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
152 {
153         writel(val, chan->vi->iomem + addr);
154 }
155
156 /*
157  * Get the main input format (YUV/RGB...) and the YUV variant as values to
158  * be written into registers for the current VI input mbus code.
159  */
160 static void tegra20_vi_get_input_formats(struct tegra_vi_channel *chan,
161                                          unsigned int *main_input_format,
162                                          unsigned int *yuv_input_format)
163 {
164         unsigned int input_mbus_code = chan->fmtinfo->code;
165
166         (*main_input_format) = VI_INPUT_INPUT_FORMAT_YUV422;
167
168         switch (input_mbus_code) {
169         case MEDIA_BUS_FMT_UYVY8_2X8:
170                 (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_UYVY;
171                 break;
172         case MEDIA_BUS_FMT_VYUY8_2X8:
173                 (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_VYUY;
174                 break;
175         case MEDIA_BUS_FMT_YUYV8_2X8:
176                 (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YUYV;
177                 break;
178         case MEDIA_BUS_FMT_YVYU8_2X8:
179                 (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
180                 break;
181         }
182 }
183
184 /*
185  * Get the main output format (YUV/RGB...) and the YUV variant as values to
186  * be written into registers for the current VI output pixel format.
187  */
188 static void tegra20_vi_get_output_formats(struct tegra_vi_channel *chan,
189                                           unsigned int *main_output_format,
190                                           unsigned int *yuv_output_format)
191 {
192         u32 output_fourcc = chan->format.pixelformat;
193
194         /* Default to YUV422 non-planar (U8Y8V8Y8) after downscaling */
195         (*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_YUV422POST;
196         (*yuv_output_format) = VI_OUTPUT_YUV_OUTPUT_FORMAT_UYVY;
197
198         switch (output_fourcc) {
199         case V4L2_PIX_FMT_UYVY:
200                 (*yuv_output_format) = VI_OUTPUT_YUV_OUTPUT_FORMAT_UYVY;
201                 break;
202         case V4L2_PIX_FMT_VYUY:
203                 (*yuv_output_format) = VI_OUTPUT_YUV_OUTPUT_FORMAT_VYUY;
204                 break;
205         case V4L2_PIX_FMT_YUYV:
206                 (*yuv_output_format) = VI_OUTPUT_YUV_OUTPUT_FORMAT_YUYV;
207                 break;
208         case V4L2_PIX_FMT_YVYU:
209                 (*yuv_output_format) = VI_OUTPUT_YUV_OUTPUT_FORMAT_YVYU;
210                 break;
211         case V4L2_PIX_FMT_YUV420:
212         case V4L2_PIX_FMT_YVU420:
213                 (*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
214                 break;
215         }
216 }
217
218 /*
219  * Make the VI accessible (needed on Tegra20).
220  *
221  * This function writes an unknown bit into an unknown register. The code
222  * comes from a downstream 3.1 kernel that has a working VIP driver for
223  * Tegra20, and removing it makes the VI completely unaccessible. It should
224  * be rewritten and possibly moved elsewhere, but the appropriate location
225  * and implementation is unknown due to a total lack of documentation.
226  */
227 static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
228 {
229         /* from arch/arm/mach-tegra/iomap.h */
230         const phys_addr_t TEGRA_APB_MISC_BASE = 0x70000000;
231         const unsigned long reg_offset = 0x42c;
232         void __iomem *apb_misc;
233         u32 val;
234
235         apb_misc = ioremap(TEGRA_APB_MISC_BASE, PAGE_SIZE);
236         if (!apb_misc)
237                 apb_misc = ERR_PTR(-ENOENT);
238         if (IS_ERR(apb_misc))
239                 return dev_err_probe(vi->dev, PTR_ERR(apb_misc), "cannot access APB_MISC");
240
241         val = readl(apb_misc + reg_offset);
242         val &= ~BIT(0);
243         val |= on ? BIT(0) : 0;
244         writel(val, apb_misc + reg_offset);
245         iounmap(apb_misc);
246
247         return 0;
248 }
249
250 static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
251 {
252         struct tegra_vi *vi = chan->vi;
253         struct host1x_syncpt *out_sp;
254
255         out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
256         if (!out_sp)
257                 return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
258
259         chan->mw_ack_sp[0] = out_sp;
260
261         return 0;
262 }
263
264 static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
265 {
266         host1x_syncpt_put(chan->mw_ack_sp[0]);
267 }
268
269 static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
270 {
271         pix->width  = clamp(pix->width,  TEGRA20_MIN_WIDTH,  TEGRA20_MAX_WIDTH);
272         pix->height = clamp(pix->height, TEGRA20_MIN_HEIGHT, TEGRA20_MAX_HEIGHT);
273
274         switch (pix->pixelformat) {
275         case V4L2_PIX_FMT_UYVY:
276         case V4L2_PIX_FMT_VYUY:
277         case V4L2_PIX_FMT_YUYV:
278         case V4L2_PIX_FMT_YVYU:
279                 pix->bytesperline = roundup(pix->width, 2) * 2;
280                 pix->sizeimage = roundup(pix->width, 2) * 2 * pix->height;
281                 break;
282         case V4L2_PIX_FMT_YUV420:
283         case V4L2_PIX_FMT_YVU420:
284                 pix->bytesperline = roundup(pix->width, 8);
285                 pix->sizeimage = roundup(pix->width, 8) * pix->height * 3 / 2;
286                 break;
287         }
288 }
289
290 /*
291  * Compute buffer offsets once per stream so that
292  * tegra20_channel_vi_buffer_setup() only has to do very simple maths for
293  * each buffer.
294  */
295 static void tegra20_channel_queue_setup(struct tegra_vi_channel *chan)
296 {
297         unsigned int stride = chan->format.bytesperline;
298         unsigned int height = chan->format.height;
299
300         chan->start_offset = 0;
301
302         switch (chan->format.pixelformat) {
303         case V4L2_PIX_FMT_UYVY:
304         case V4L2_PIX_FMT_VYUY:
305         case V4L2_PIX_FMT_YUYV:
306         case V4L2_PIX_FMT_YVYU:
307                 if (chan->vflip)
308                         chan->start_offset += stride * (height - 1);
309                 if (chan->hflip)
310                         chan->start_offset += stride - 1;
311                 break;
312
313         case V4L2_PIX_FMT_YUV420:
314         case V4L2_PIX_FMT_YVU420:
315                 chan->addr_offset_u = stride * height;
316                 chan->addr_offset_v = chan->addr_offset_u + stride * height / 4;
317
318                 /* For YVU420, we swap the locations of the U and V planes. */
319                 if (chan->format.pixelformat == V4L2_PIX_FMT_YVU420) {
320                         unsigned long temp;
321
322                         temp = chan->addr_offset_u;
323                         chan->addr_offset_u = chan->addr_offset_v;
324                         chan->addr_offset_v = temp;
325                 }
326
327                 chan->start_offset_u = chan->addr_offset_u;
328                 chan->start_offset_v = chan->addr_offset_v;
329
330                 if (chan->vflip) {
331                         chan->start_offset   += stride * (height - 1);
332                         chan->start_offset_u += (stride / 2) * ((height / 2) - 1);
333                         chan->start_offset_v += (stride / 2) * ((height / 2) - 1);
334                 }
335                 if (chan->hflip) {
336                         chan->start_offset   += stride - 1;
337                         chan->start_offset_u += (stride / 2) - 1;
338                         chan->start_offset_v += (stride / 2) - 1;
339                 }
340                 break;
341         }
342 }
343
344 static void release_buffer(struct tegra_vi_channel *chan,
345                            struct tegra_channel_buffer *buf,
346                            enum vb2_buffer_state state)
347 {
348         struct vb2_v4l2_buffer *vb = &buf->buf;
349
350         vb->sequence = chan->sequence++;
351         vb->field = V4L2_FIELD_NONE;
352         vb->vb2_buf.timestamp = ktime_get_ns();
353         vb2_buffer_done(&vb->vb2_buf, state);
354 }
355
356 static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
357                                             struct tegra_channel_buffer *buf)
358 {
359         dma_addr_t base = buf->addr;
360
361         switch (chan->fmtinfo->fourcc) {
362         case V4L2_PIX_FMT_YUV420:
363         case V4L2_PIX_FMT_YVU420:
364                 tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_U,  base + chan->addr_offset_u);
365                 tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_U, base + chan->start_offset_u);
366                 tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_V,  base + chan->addr_offset_v);
367                 tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_V, base + chan->start_offset_v);
368                 fallthrough;
369
370         case V4L2_PIX_FMT_UYVY:
371         case V4L2_PIX_FMT_VYUY:
372         case V4L2_PIX_FMT_YUYV:
373         case V4L2_PIX_FMT_YVYU:
374                 tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,  base);
375                 tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_FIRST, base + chan->start_offset);
376                 break;
377         }
378 }
379
380 static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
381                                          struct tegra_channel_buffer *buf)
382 {
383         int err;
384
385         chan->next_out_sp_idx++;
386
387         tegra20_channel_vi_buffer_setup(chan, buf);
388
389         tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
390
391         /* Wait for syncpt counter to reach frame start event threshold */
392         err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
393                                  TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
394         if (err) {
395                 host1x_syncpt_incr(chan->mw_ack_sp[0]);
396                 dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
397                 release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
398                 return err;
399         }
400
401         tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
402                          VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
403
404         release_buffer(chan, buf, VB2_BUF_STATE_DONE);
405
406         return 0;
407 }
408
409 static int tegra20_chan_capture_kthread_start(void *data)
410 {
411         struct tegra_vi_channel *chan = data;
412         struct tegra_channel_buffer *buf;
413         unsigned int retries = 0;
414         int err = 0;
415
416         while (1) {
417                 /*
418                  * Source is not streaming if error is non-zero.
419                  * So, do not dequeue buffers on error and let the thread sleep
420                  * till kthread stop signal is received.
421                  */
422                 wait_event_interruptible(chan->start_wait,
423                                          kthread_should_stop() ||
424                                          (!list_empty(&chan->capture) && !err));
425
426                 if (kthread_should_stop())
427                         break;
428
429                 /* dequeue the buffer and start capture */
430                 spin_lock(&chan->start_lock);
431                 if (list_empty(&chan->capture)) {
432                         spin_unlock(&chan->start_lock);
433                         continue;
434                 }
435
436                 buf = list_first_entry(&chan->capture, struct tegra_channel_buffer, queue);
437                 list_del_init(&buf->queue);
438                 spin_unlock(&chan->start_lock);
439
440                 err = tegra20_channel_capture_frame(chan, buf);
441                 if (!err) {
442                         retries = 0;
443                         continue;
444                 }
445
446                 if (retries++ > chan->syncpt_timeout_retry)
447                         vb2_queue_error(&chan->queue);
448                 else
449                         err = 0;
450         }
451
452         return 0;
453 }
454
455 static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
456 {
457         u32 output_fourcc = chan->format.pixelformat;
458         int width  = chan->format.width;
459         int height = chan->format.height;
460         int stride_l = chan->format.bytesperline;
461         int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
462                         output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
463         int main_output_format;
464         int yuv_output_format;
465
466         tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
467
468         /*
469          * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
470          * for luminance, which is the default and means not to touch
471          * anything.
472          */
473         tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
474                          0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
475                          0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
476
477         /* Set up raise-on-edge, so we get an interrupt on end of frame. */
478         tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
479
480         tegra20_vi_write(chan, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
481                          (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
482                          (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
483                          yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
484                          main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
485
486         /* Set up frame size */
487         tegra20_vi_write(chan, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
488                          height << VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT |
489                          width  << VI_FIRST_OUTPUT_FRAME_WIDTH_SFT);
490
491         /* First output memory enabled */
492         tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
493
494         /* Set the number of frames in the buffer */
495         tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT_FIRST, 1);
496
497         /* Set up buffer frame size */
498         tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE_FIRST,
499                          height << VI_VB0_SIZE_FIRST_V_SFT |
500                          width  << VI_VB0_SIZE_FIRST_H_SFT);
501
502         tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
503                          stride_l << VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT |
504                          stride_c << VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT);
505
506         tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
507 }
508
509 static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
510 {
511         struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
512         struct media_pipeline *pipe = &chan->video.pipe;
513         int err;
514
515         chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
516
517         err = video_device_pipeline_start(&chan->video, pipe);
518         if (err)
519                 goto error_pipeline_start;
520
521         tegra20_camera_capture_setup(chan);
522
523         err = tegra_channel_set_stream(chan, true);
524         if (err)
525                 goto error_set_stream;
526
527         chan->sequence = 0;
528
529         chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
530                                                   chan, "%s:0", chan->video.name);
531         if (IS_ERR(chan->kthread_start_capture)) {
532                 err = PTR_ERR(chan->kthread_start_capture);
533                 chan->kthread_start_capture = NULL;
534                 dev_err_probe(&chan->video.dev, err, "failed to run capture kthread\n");
535                 goto error_kthread_start;
536         }
537
538         return 0;
539
540 error_kthread_start:
541         tegra_channel_set_stream(chan, false);
542 error_set_stream:
543         video_device_pipeline_stop(&chan->video);
544 error_pipeline_start:
545         tegra_channel_release_buffers(chan, VB2_BUF_STATE_QUEUED);
546
547         return err;
548 }
549
550 static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
551 {
552         struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
553
554         if (chan->kthread_start_capture) {
555                 kthread_stop(chan->kthread_start_capture);
556                 chan->kthread_start_capture = NULL;
557         }
558
559         tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
560         tegra_channel_set_stream(chan, false);
561         video_device_pipeline_stop(&chan->video);
562 }
563
564 static const struct tegra_vi_ops tegra20_vi_ops = {
565         .vi_enable = tegra20_vi_enable,
566         .channel_host1x_syncpt_init = tegra20_channel_host1x_syncpt_init,
567         .channel_host1x_syncpt_free = tegra20_channel_host1x_syncpt_free,
568         .vi_fmt_align = tegra20_fmt_align,
569         .channel_queue_setup = tegra20_channel_queue_setup,
570         .vi_start_streaming = tegra20_vi_start_streaming,
571         .vi_stop_streaming = tegra20_vi_stop_streaming,
572 };
573
574 #define TEGRA20_VIDEO_FMT(MBUS_CODE, BPP, FOURCC)       \
575 {                                                       \
576         .code    = MEDIA_BUS_FMT_##MBUS_CODE,           \
577         .bpp     = BPP,                                 \
578         .fourcc  = V4L2_PIX_FMT_##FOURCC,               \
579 }
580
581 static const struct tegra_video_format tegra20_video_formats[] = {
582         TEGRA20_VIDEO_FMT(UYVY8_2X8, 2, UYVY),
583         TEGRA20_VIDEO_FMT(VYUY8_2X8, 2, VYUY),
584         TEGRA20_VIDEO_FMT(YUYV8_2X8, 2, YUYV),
585         TEGRA20_VIDEO_FMT(YVYU8_2X8, 2, YVYU),
586         TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YUV420),
587         TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YVU420),
588 };
589
590 const struct tegra_vi_soc tegra20_vi_soc = {
591         .video_formats = tegra20_video_formats,
592         .nformats = ARRAY_SIZE(tegra20_video_formats),
593         .default_video_format = &tegra20_video_formats[0],
594         .ops = &tegra20_vi_ops,
595         .vi_max_channels = 1, /* parallel input (VIP) */
596         .vi_max_clk_hz = 150000000,
597         .has_h_v_flip = true,
598 };
599
600 /* --------------------------------------------------------------------------
601  * VIP
602  */
603
604 /*
605  * VIP-specific configuration for stream start.
606  *
607  * Whatever is common among VIP and CSI is done by the VI component (see
608  * tegra20_vi_start_streaming()). Here we do what is VIP-specific.
609  */
610 static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
611 {
612         struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&vip_chan->subdev);
613         int width  = vi_chan->format.width;
614         int height = vi_chan->format.height;
615
616         unsigned int main_input_format;
617         unsigned int yuv_input_format;
618
619         tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
620
621         tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
622
623         tegra20_vi_write(vi_chan, TEGRA_VI_VI_INPUT_CONTROL,
624                          VI_INPUT_VIP_INPUT_ENABLE | main_input_format | yuv_input_format);
625
626         tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, 0);
627         tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, 0);
628
629         tegra20_vi_write(vi_chan, TEGRA_VI_VIP_V_ACTIVE, height << VI_VIP_V_ACTIVE_PERIOD_SFT);
630         tegra20_vi_write(vi_chan, TEGRA_VI_VIP_H_ACTIVE,
631                          roundup(width, 2) << VI_VIP_H_ACTIVE_PERIOD_SFT);
632
633         /*
634          * For VIP, D9..D2 is mapped to the video decoder's P7..P0.
635          * Disable/mask out the other Dn wires. When not in BT656
636          * mode we also need the V/H sync.
637          */
638         tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INPUT_ENABLE,
639                          GENMASK(9, 2) << VI_PIN_INPUT_VD_SFT |
640                          VI_PIN_INPUT_HSYNC | VI_PIN_INPUT_VSYNC);
641         tegra20_vi_write(vi_chan, TEGRA_VI_VI_DATA_INPUT_CONTROL,
642                          GENMASK(9, 2) << VI_DATA_INPUT_SFT);
643         tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INVERSION, 0);
644
645         tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT_1,
646                          VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT |
647                          host1x_syncpt_id(vi_chan->mw_ack_sp[0])
648                          << VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT);
649
650         tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
651
652         return 0;
653 }
654
655 static const struct tegra_vip_ops tegra20_vip_ops = {
656         .vip_start_streaming = tegra20_vip_start_streaming,
657 };
658
659 const struct tegra_vip_soc tegra20_vip_soc = {
660         .ops = &tegra20_vip_ops,
661 };