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