GNU Linux-libre 4.14.265-gnu1
[releases.git] / drivers / staging / media / atomisp / pci / atomisp2 / css2400 / runtime / inputfifo / src / inputfifo.c
1 #ifndef ISP2401
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15 #else
16 /**
17 Support for Intel Camera Imaging ISP subsystem.
18 Copyright (c) 2010 - 2015, Intel Corporation.
19
20 This program is free software; you can redistribute it and/or modify it
21 under the terms and conditions of the GNU General Public License,
22 version 2, as published by the Free Software Foundation.
23
24 This program is distributed in the hope it will be useful, but WITHOUT
25 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
27 more details.
28 */
29 #endif
30
31 #include "platform_support.h"
32
33 #include "ia_css_inputfifo.h"
34
35 #include "device_access.h"
36
37 #define __INLINE_SP__
38 #include "sp.h"
39 #define __INLINE_ISP__
40 #include "isp.h"
41 #define __INLINE_IRQ__
42 #include "irq.h"
43 #define __INLINE_FIFO_MONITOR__
44 #include "fifo_monitor.h"
45
46 #define __INLINE_EVENT__
47 #include "event_fifo.h"
48 #define __INLINE_SP__
49
50 #if !defined(HAS_NO_INPUT_SYSTEM)
51 #include "input_system.h"       /* MIPI_PREDICTOR_NONE,... */
52 #endif
53
54 #include "assert_support.h"
55
56 /* System independent */
57 #include "sh_css_internal.h"
58 #if !defined(HAS_NO_INPUT_SYSTEM)
59 #include "ia_css_isys.h"
60 #endif
61
62 #define HBLANK_CYCLES (187)
63 #define MARKER_CYCLES (6)
64
65 #if !defined(HAS_NO_INPUT_SYSTEM)
66 #include <hive_isp_css_streaming_to_mipi_types_hrt.h>
67 #endif
68
69 /* The data type is used to send special cases:
70  * yuv420: odd lines (1, 3 etc) are twice as wide as even
71  *         lines (0, 2, 4 etc).
72  * rgb: for two pixels per clock, the R and B values are sent
73  *      to output_0 while only G is sent to output_1. This means
74  *      that output_1 only gets half the number of values of output_0.
75  *      WARNING: This type should also be used for Legacy YUV420.
76  * regular: used for all other data types (RAW, YUV422, etc)
77  */
78 enum inputfifo_mipi_data_type {
79         inputfifo_mipi_data_type_regular,
80         inputfifo_mipi_data_type_yuv420,
81         inputfifo_mipi_data_type_yuv420_legacy,
82         inputfifo_mipi_data_type_rgb,
83 };
84 #if !defined(HAS_NO_INPUT_SYSTEM)
85 static unsigned int inputfifo_curr_ch_id, inputfifo_curr_fmt_type;
86 #endif
87 struct inputfifo_instance {
88         unsigned int                            ch_id;
89         enum ia_css_stream_format       input_format;
90         bool                                            two_ppc;
91         bool                                            streaming;
92         unsigned int                            hblank_cycles;
93         unsigned int                            marker_cycles;
94         unsigned int                            fmt_type;
95         enum inputfifo_mipi_data_type   type;
96 };
97 #if !defined(HAS_NO_INPUT_SYSTEM)
98 /*
99  * Maintain a basic streaming to Mipi administration with ch_id as index
100  * ch_id maps on the "Mipi virtual channel ID" and can have value 0..3
101  */
102 #define INPUTFIFO_NR_OF_S2M_CHANNELS    (4)
103 static struct inputfifo_instance
104         inputfifo_inst_admin[INPUTFIFO_NR_OF_S2M_CHANNELS];
105
106 /* Streaming to MIPI */
107 static unsigned inputfifo_wrap_marker(
108 /* STORAGE_CLASS_INLINE unsigned inputfifo_wrap_marker( */
109         unsigned marker)
110 {
111         return marker |
112         (inputfifo_curr_ch_id << HIVE_STR_TO_MIPI_CH_ID_LSB) |
113         (inputfifo_curr_fmt_type << _HIVE_STR_TO_MIPI_FMT_TYPE_LSB);
114 }
115
116 STORAGE_CLASS_INLINE void
117 _sh_css_fifo_snd(unsigned token)
118 {
119         while (!can_event_send_token(STR2MIPI_EVENT_ID))
120                 hrt_sleep();
121         event_send_token(STR2MIPI_EVENT_ID, token);
122         return;
123 }
124
125 static void inputfifo_send_data_a(
126 /* STORAGE_CLASS_INLINE void inputfifo_send_data_a( */
127 unsigned int data)
128 {
129         unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_A_BIT) |
130                              (data << HIVE_STR_TO_MIPI_DATA_A_LSB);
131         _sh_css_fifo_snd(token);
132         return;
133 }
134
135
136
137 static void inputfifo_send_data_b(
138 /* STORAGE_CLASS_INLINE void inputfifo_send_data_b( */
139         unsigned int data)
140 {
141         unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) |
142                              (data << _HIVE_STR_TO_MIPI_DATA_B_LSB);
143         _sh_css_fifo_snd(token);
144         return;
145 }
146
147
148
149 static void inputfifo_send_data(
150 /* STORAGE_CLASS_INLINE void inputfifo_send_data( */
151         unsigned int a,
152         unsigned int b)
153 {
154         unsigned int token = ((1 << HIVE_STR_TO_MIPI_VALID_A_BIT) |
155                               (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) |
156                               (a << HIVE_STR_TO_MIPI_DATA_A_LSB) |
157                               (b << _HIVE_STR_TO_MIPI_DATA_B_LSB));
158         _sh_css_fifo_snd(token);
159         return;
160 }
161
162
163
164 static void inputfifo_send_sol(void)
165 /* STORAGE_CLASS_INLINE void inputfifo_send_sol(void) */
166 {
167         hrt_data        token = inputfifo_wrap_marker(
168                 1 << HIVE_STR_TO_MIPI_SOL_BIT);
169
170         _sh_css_fifo_snd(token);
171         return;
172 }
173
174
175
176 static void inputfifo_send_eol(void)
177 /* STORAGE_CLASS_INLINE void inputfifo_send_eol(void) */
178 {
179         hrt_data        token = inputfifo_wrap_marker(
180                 1 << HIVE_STR_TO_MIPI_EOL_BIT);
181         _sh_css_fifo_snd(token);
182         return;
183 }
184
185
186
187 static void inputfifo_send_sof(void)
188 /* STORAGE_CLASS_INLINE void inputfifo_send_sof(void) */
189 {
190         hrt_data        token = inputfifo_wrap_marker(
191                 1 << HIVE_STR_TO_MIPI_SOF_BIT);
192
193         _sh_css_fifo_snd(token);
194         return;
195 }
196
197
198
199 static void inputfifo_send_eof(void)
200 /* STORAGE_CLASS_INLINE void inputfifo_send_eof(void) */
201 {
202         hrt_data        token = inputfifo_wrap_marker(
203                 1 << HIVE_STR_TO_MIPI_EOF_BIT);
204         _sh_css_fifo_snd(token);
205         return;
206 }
207
208
209
210 #ifdef __ON__
211 static void inputfifo_send_ch_id(
212 /* STORAGE_CLASS_INLINE void inputfifo_send_ch_id( */
213         unsigned int ch_id)
214 {
215         hrt_data        token;
216         inputfifo_curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK;
217         /* we send an zero marker, this will wrap the ch_id and
218          * fmt_type automatically.
219          */
220         token = inputfifo_wrap_marker(0);
221         _sh_css_fifo_snd(token);
222         return;
223 }
224
225 static void inputfifo_send_fmt_type(
226 /* STORAGE_CLASS_INLINE void inputfifo_send_fmt_type( */
227         unsigned int fmt_type)
228 {
229         hrt_data        token;
230         inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK;
231         /* we send an zero marker, this will wrap the ch_id and
232          * fmt_type automatically.
233          */
234         token = inputfifo_wrap_marker(0);
235         _sh_css_fifo_snd(token);
236         return;
237 }
238 #endif /*  __ON__ */
239
240
241
242 static void inputfifo_send_ch_id_and_fmt_type(
243 /* STORAGE_CLASS_INLINE
244 void inputfifo_send_ch_id_and_fmt_type( */
245         unsigned int ch_id,
246         unsigned int fmt_type)
247 {
248         hrt_data        token;
249         inputfifo_curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK;
250         inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK;
251         /* we send an zero marker, this will wrap the ch_id and
252          * fmt_type automatically.
253          */
254         token = inputfifo_wrap_marker(0);
255         _sh_css_fifo_snd(token);
256         return;
257 }
258
259
260
261 static void inputfifo_send_empty_token(void)
262 /* STORAGE_CLASS_INLINE void inputfifo_send_empty_token(void) */
263 {
264         hrt_data        token = inputfifo_wrap_marker(0);
265         _sh_css_fifo_snd(token);
266         return;
267 }
268
269
270
271 static void inputfifo_start_frame(
272 /* STORAGE_CLASS_INLINE void inputfifo_start_frame( */
273         unsigned int ch_id,
274         unsigned int fmt_type)
275 {
276         inputfifo_send_ch_id_and_fmt_type(ch_id, fmt_type);
277         inputfifo_send_sof();
278         return;
279 }
280
281
282
283 static void inputfifo_end_frame(
284         unsigned int marker_cycles)
285 {
286         unsigned int i;
287         for (i = 0; i < marker_cycles; i++)
288                 inputfifo_send_empty_token();
289         inputfifo_send_eof();
290         return;
291 }
292
293
294
295 static void inputfifo_send_line2(
296         const unsigned short *data,
297         unsigned int width,
298         const unsigned short *data2,
299         unsigned int width2,
300         unsigned int hblank_cycles,
301         unsigned int marker_cycles,
302         unsigned int two_ppc,
303         enum inputfifo_mipi_data_type type)
304 {
305         unsigned int i, is_rgb = 0, is_legacy = 0;
306
307         assert(data != NULL);
308         assert((data2 != NULL) || (width2 == 0));
309         if (type == inputfifo_mipi_data_type_rgb)
310                 is_rgb = 1;
311
312         if (type == inputfifo_mipi_data_type_yuv420_legacy)
313                 is_legacy = 1;
314
315         for (i = 0; i < hblank_cycles; i++)
316                 inputfifo_send_empty_token();
317         inputfifo_send_sol();
318         for (i = 0; i < marker_cycles; i++)
319                 inputfifo_send_empty_token();
320         for (i = 0; i < width; i++, data++) {
321                 /* for RGB in two_ppc, we only actually send 2 pixels per
322                  * clock in the even pixels (0, 2 etc). In the other cycles,
323                  * we only send 1 pixel, to data[0].
324                  */
325                 unsigned int send_two_pixels = two_ppc;
326                 if ((is_rgb || is_legacy) && (i % 3 == 2))
327                         send_two_pixels = 0;
328                 if (send_two_pixels) {
329                         if (i + 1 == width) {
330                                 /* for jpg (binary) copy, this can occur
331                                  * if the file contains an odd number of bytes.
332                                  */
333                                 inputfifo_send_data(
334                                                         data[0], 0);
335                         } else {
336                                 inputfifo_send_data(
337                                                         data[0], data[1]);
338                         }
339                         /* Additional increment because we send 2 pixels */
340                         data++;
341                         i++;
342                 } else if (two_ppc && is_legacy) {
343                         inputfifo_send_data_b(data[0]);
344                 } else {
345                         inputfifo_send_data_a(data[0]);
346                 }
347         }
348
349         for (i = 0; i < width2; i++, data2++) {
350                 /* for RGB in two_ppc, we only actually send 2 pixels per
351                  * clock in the even pixels (0, 2 etc). In the other cycles,
352                  * we only send 1 pixel, to data2[0].
353                  */
354                 unsigned int send_two_pixels = two_ppc;
355                 if ((is_rgb || is_legacy) && (i % 3 == 2))
356                         send_two_pixels = 0;
357                 if (send_two_pixels) {
358                         if (i + 1 == width2) {
359                                 /* for jpg (binary) copy, this can occur
360                                  * if the file contains an odd number of bytes.
361                                  */
362                                 inputfifo_send_data(
363                                                         data2[0], 0);
364                         } else {
365                                 inputfifo_send_data(
366                                                         data2[0], data2[1]);
367                         }
368                         /* Additional increment because we send 2 pixels */
369                         data2++;
370                         i++;
371                 } else if (two_ppc && is_legacy) {
372                         inputfifo_send_data_b(data2[0]);
373                 } else {
374                         inputfifo_send_data_a(data2[0]);
375                 }
376         }
377         for (i = 0; i < hblank_cycles; i++)
378                 inputfifo_send_empty_token();
379         inputfifo_send_eol();
380         return;
381 }
382
383
384
385 static void
386 inputfifo_send_line(const unsigned short *data,
387                          unsigned int width,
388                          unsigned int hblank_cycles,
389                          unsigned int marker_cycles,
390                          unsigned int two_ppc,
391                          enum inputfifo_mipi_data_type type)
392 {
393         assert(data != NULL);
394         inputfifo_send_line2(data, width, NULL, 0,
395                                         hblank_cycles,
396                                         marker_cycles,
397                                         two_ppc,
398                                         type);
399 }
400
401
402 /* Send a frame of data into the input network via the GP FIFO.
403  *  Parameters:
404  *   - data: array of 16 bit values that contains all data for the frame.
405  *   - width: width of a line in number of subpixels, for yuv420 it is the
406  *            number of Y components per line.
407  *   - height: height of the frame in number of lines.
408  *   - ch_id: channel ID.
409  *   - fmt_type: format type.
410  *   - hblank_cycles: length of horizontal blanking in cycles.
411  *   - marker_cycles: number of empty cycles after start-of-line and before
412  *                    end-of-frame.
413  *   - two_ppc: boolean, describes whether to send one or two pixels per clock
414  *              cycle. In this mode, we sent pixels N and N+1 in the same cycle,
415  *              to IF_PRIM_A and IF_PRIM_B respectively. The caller must make
416  *              sure the input data has been formatted correctly for this.
417  *              For example, for RGB formats this means that unused values
418  *              must be inserted.
419  *   - yuv420: boolean, describes whether (non-legacy) yuv420 data is used. In
420  *             this mode, the odd lines (1,3,5 etc) are half as long as the
421  *             even lines (2,4,6 etc).
422  *             Note that the first line is odd (1) and the second line is even
423  *             (2).
424  *
425  * This function does not do any reordering of pixels, the caller must make
426  * sure the data is in the righ format. Please refer to the CSS receiver
427  * documentation for details on the data formats.
428  */
429
430 static void inputfifo_send_frame(
431         const unsigned short *data,
432         unsigned int width,
433         unsigned int height,
434         unsigned int ch_id,
435         unsigned int fmt_type,
436         unsigned int hblank_cycles,
437         unsigned int marker_cycles,
438         unsigned int two_ppc,
439         enum inputfifo_mipi_data_type type)
440 {
441         unsigned int i;
442
443         assert(data != NULL);
444         inputfifo_start_frame(ch_id, fmt_type);
445
446         for (i = 0; i < height; i++) {
447                 if ((type == inputfifo_mipi_data_type_yuv420) &&
448                     (i & 1) == 1) {
449                         inputfifo_send_line(data, 2 * width,
450                                                            hblank_cycles,
451                                                            marker_cycles,
452                                                            two_ppc, type);
453                         data += 2 * width;
454                 } else {
455                         inputfifo_send_line(data, width,
456                                                            hblank_cycles,
457                                                            marker_cycles,
458                                                            two_ppc, type);
459                         data += width;
460                 }
461         }
462         inputfifo_end_frame(marker_cycles);
463         return;
464 }
465
466
467
468 static enum inputfifo_mipi_data_type inputfifo_determine_type(
469         enum ia_css_stream_format input_format)
470 {
471         enum inputfifo_mipi_data_type type;
472
473         type = inputfifo_mipi_data_type_regular;
474         if (input_format == IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY) {
475                 type =
476                         inputfifo_mipi_data_type_yuv420_legacy;
477         } else if (input_format == IA_CSS_STREAM_FORMAT_YUV420_8  ||
478                    input_format == IA_CSS_STREAM_FORMAT_YUV420_10 ||
479                    input_format == IA_CSS_STREAM_FORMAT_YUV420_16) {
480                 type =
481                         inputfifo_mipi_data_type_yuv420;
482         } else if (input_format >= IA_CSS_STREAM_FORMAT_RGB_444 &&
483                    input_format <= IA_CSS_STREAM_FORMAT_RGB_888) {
484                 type =
485                         inputfifo_mipi_data_type_rgb;
486         }
487         return type;
488 }
489
490
491
492 static struct inputfifo_instance *inputfifo_get_inst(
493         unsigned int ch_id)
494 {
495         return &inputfifo_inst_admin[ch_id];
496 }
497
498 void ia_css_inputfifo_send_input_frame(
499         const unsigned short *data,
500         unsigned int width,
501         unsigned int height,
502         unsigned int ch_id,
503         enum ia_css_stream_format input_format,
504         bool two_ppc)
505 {
506         unsigned int fmt_type, hblank_cycles, marker_cycles;
507         enum inputfifo_mipi_data_type type;
508
509         assert(data != NULL);
510         hblank_cycles = HBLANK_CYCLES;
511         marker_cycles = MARKER_CYCLES;
512         ia_css_isys_convert_stream_format_to_mipi_format(input_format,
513                                  MIPI_PREDICTOR_NONE,
514                                  &fmt_type);
515
516         type = inputfifo_determine_type(input_format);
517
518         inputfifo_send_frame(data, width, height,
519                         ch_id, fmt_type, hblank_cycles, marker_cycles,
520                         two_ppc, type);
521 }
522
523
524
525 void ia_css_inputfifo_start_frame(
526         unsigned int ch_id,
527         enum ia_css_stream_format input_format,
528         bool two_ppc)
529 {
530         struct inputfifo_instance *s2mi;
531         s2mi = inputfifo_get_inst(ch_id);
532
533         s2mi->ch_id = ch_id;
534         ia_css_isys_convert_stream_format_to_mipi_format(input_format,
535                                 MIPI_PREDICTOR_NONE,
536                                 &s2mi->fmt_type);
537         s2mi->two_ppc = two_ppc;
538         s2mi->type = inputfifo_determine_type(input_format);
539         s2mi->hblank_cycles = HBLANK_CYCLES;
540         s2mi->marker_cycles = MARKER_CYCLES;
541         s2mi->streaming = true;
542
543         inputfifo_start_frame(ch_id, s2mi->fmt_type);
544         return;
545 }
546
547
548
549 void ia_css_inputfifo_send_line(
550         unsigned int ch_id,
551         const unsigned short *data,
552         unsigned int width,
553         const unsigned short *data2,
554         unsigned int width2)
555 {
556         struct inputfifo_instance *s2mi;
557
558         assert(data != NULL);
559         assert((data2 != NULL) || (width2 == 0));
560         s2mi = inputfifo_get_inst(ch_id);
561
562
563         /* Set global variables that indicate channel_id and format_type */
564         inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK;
565         inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK;
566
567         inputfifo_send_line2(data, width, data2, width2,
568                                         s2mi->hblank_cycles,
569                                         s2mi->marker_cycles,
570                                         s2mi->two_ppc,
571                                         s2mi->type);
572 }
573
574
575 void ia_css_inputfifo_send_embedded_line(
576         unsigned int    ch_id,
577         enum ia_css_stream_format       data_type,
578         const unsigned short    *data,
579         unsigned int    width)
580 {
581         struct inputfifo_instance *s2mi;
582         unsigned int fmt_type;
583
584         assert(data != NULL);
585         s2mi = inputfifo_get_inst(ch_id);
586         ia_css_isys_convert_stream_format_to_mipi_format(data_type,
587                         MIPI_PREDICTOR_NONE, &fmt_type);
588
589         /* Set format_type for metadata line. */
590         inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK;
591
592         inputfifo_send_line(data, width, s2mi->hblank_cycles, s2mi->marker_cycles,
593                         s2mi->two_ppc, inputfifo_mipi_data_type_regular);
594 }
595
596
597 void ia_css_inputfifo_end_frame(
598         unsigned int    ch_id)
599 {
600         struct inputfifo_instance *s2mi;
601         s2mi = inputfifo_get_inst(ch_id);
602
603         /* Set global variables that indicate channel_id and format_type */
604         inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK;
605         inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK;
606
607         /* Call existing HRT function */
608         inputfifo_end_frame(s2mi->marker_cycles);
609
610         s2mi->streaming = false;
611         return;
612 }
613 #endif /* #if !defined(HAS_NO_INPUT_SYSTEM) */