2 * Support for Intel Camera Imaging ISP subsystem.
3 * Copyright (c) 2010 - 2015, Intel Corporation.
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.
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
15 #include "platform_support.h"
17 #include "ia_css_inputfifo.h"
19 #include "device_access.h"
23 #define __INLINE_ISP__
25 #define __INLINE_IRQ__
27 #define __INLINE_FIFO_MONITOR__
28 #include "fifo_monitor.h"
30 #define __INLINE_EVENT__
31 #include "event_fifo.h"
34 #if !defined(HAS_NO_INPUT_SYSTEM)
35 #include "input_system.h" /* MIPI_PREDICTOR_NONE,... */
38 #include "assert_support.h"
40 /* System independent */
41 #include "sh_css_internal.h"
42 #if !defined(HAS_NO_INPUT_SYSTEM)
43 #include "ia_css_isys.h"
46 #define HBLANK_CYCLES (187)
47 #define MARKER_CYCLES (6)
49 #if !defined(HAS_NO_INPUT_SYSTEM)
50 #include <hive_isp_css_streaming_to_mipi_types_hrt.h>
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)
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,
69 #if !defined(HAS_NO_INPUT_SYSTEM)
70 static unsigned int inputfifo_curr_ch_id, inputfifo_curr_fmt_type;
72 struct inputfifo_instance {
74 enum atomisp_input_format input_format;
77 unsigned int hblank_cycles;
78 unsigned int marker_cycles;
79 unsigned int fmt_type;
80 enum inputfifo_mipi_data_type type;
83 #if !defined(HAS_NO_INPUT_SYSTEM)
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
88 #define INPUTFIFO_NR_OF_S2M_CHANNELS (4)
89 static struct inputfifo_instance
90 inputfifo_inst_admin[INPUTFIFO_NR_OF_S2M_CHANNELS];
92 /* Streaming to MIPI */
93 static unsigned int inputfifo_wrap_marker(
94 /* static inline unsigned inputfifo_wrap_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);
103 _sh_css_fifo_snd(unsigned int token)
105 while (!can_event_send_token(STR2MIPI_EVENT_ID))
107 event_send_token(STR2MIPI_EVENT_ID, token);
111 static void inputfifo_send_data_a(
112 /* static inline void inputfifo_send_data_a( */
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);
121 static void inputfifo_send_data_b(
122 /* static inline void inputfifo_send_data_b( */
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);
131 static void inputfifo_send_data(
132 /* static inline void inputfifo_send_data( */
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);
144 static void inputfifo_send_sol(void)
145 /* static inline void inputfifo_send_sol(void) */
147 hrt_data token = inputfifo_wrap_marker(
148 1 << HIVE_STR_TO_MIPI_SOL_BIT);
150 _sh_css_fifo_snd(token);
154 static void inputfifo_send_eol(void)
155 /* static inline void inputfifo_send_eol(void) */
157 hrt_data token = inputfifo_wrap_marker(
158 1 << HIVE_STR_TO_MIPI_EOL_BIT);
159 _sh_css_fifo_snd(token);
163 static void inputfifo_send_sof(void)
164 /* static inline void inputfifo_send_sof(void) */
166 hrt_data token = inputfifo_wrap_marker(
167 1 << HIVE_STR_TO_MIPI_SOF_BIT);
169 _sh_css_fifo_snd(token);
173 static void inputfifo_send_eof(void)
174 /* static inline void inputfifo_send_eof(void) */
176 hrt_data token = inputfifo_wrap_marker(
177 1 << HIVE_STR_TO_MIPI_EOF_BIT);
178 _sh_css_fifo_snd(token);
182 static void inputfifo_send_ch_id_and_fmt_type(
184 void inputfifo_send_ch_id_and_fmt_type( */
186 unsigned int fmt_type)
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.
195 token = inputfifo_wrap_marker(0);
196 _sh_css_fifo_snd(token);
200 static void inputfifo_send_empty_token(void)
201 /* static inline void inputfifo_send_empty_token(void) */
203 hrt_data token = inputfifo_wrap_marker(0);
205 _sh_css_fifo_snd(token);
209 static void inputfifo_start_frame(
210 /* static inline void inputfifo_start_frame( */
212 unsigned int fmt_type)
214 inputfifo_send_ch_id_and_fmt_type(ch_id, fmt_type);
215 inputfifo_send_sof();
219 static void inputfifo_end_frame(
220 unsigned int marker_cycles)
224 for (i = 0; i < marker_cycles; i++)
225 inputfifo_send_empty_token();
226 inputfifo_send_eof();
230 static void inputfifo_send_line2(
231 const unsigned short *data,
233 const unsigned short *data2,
235 unsigned int hblank_cycles,
236 unsigned int marker_cycles,
237 unsigned int two_ppc,
238 enum inputfifo_mipi_data_type type)
240 unsigned int i, is_rgb = 0, is_legacy = 0;
243 assert((data2) || (width2 == 0));
244 if (type == inputfifo_mipi_data_type_rgb)
247 if (type == inputfifo_mipi_data_type_yuv420_legacy)
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].
260 unsigned int send_two_pixels = two_ppc;
262 if ((is_rgb || is_legacy) && (i % 3 == 2))
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.
275 /* Additional increment because we send 2 pixels */
278 } else if (two_ppc && is_legacy) {
279 inputfifo_send_data_b(data[0]);
281 inputfifo_send_data_a(data[0]);
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].
290 unsigned int send_two_pixels = two_ppc;
292 if ((is_rgb || is_legacy) && (i % 3 == 2))
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.
305 /* Additional increment because we send 2 pixels */
308 } else if (two_ppc && is_legacy) {
309 inputfifo_send_data_b(data2[0]);
311 inputfifo_send_data_a(data2[0]);
314 for (i = 0; i < hblank_cycles; i++)
315 inputfifo_send_empty_token();
316 inputfifo_send_eol();
321 inputfifo_send_line(const unsigned short *data,
323 unsigned int hblank_cycles,
324 unsigned int marker_cycles,
325 unsigned int two_ppc,
326 enum inputfifo_mipi_data_type type)
329 inputfifo_send_line2(data, width, NULL, 0,
336 /* Send a frame of data into the input network via the GP FIFO.
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
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
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
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.
364 static void inputfifo_send_frame(
365 const unsigned short *data,
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)
378 inputfifo_start_frame(ch_id, fmt_type);
380 for (i = 0; i < height; i++) {
381 if ((type == inputfifo_mipi_data_type_yuv420) &&
383 inputfifo_send_line(data, 2 * width,
389 inputfifo_send_line(data, width,
396 inputfifo_end_frame(marker_cycles);
400 static enum inputfifo_mipi_data_type inputfifo_determine_type(
401 enum atomisp_input_format input_format)
403 enum inputfifo_mipi_data_type type;
405 type = inputfifo_mipi_data_type_regular;
406 if (input_format == ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) {
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) {
413 inputfifo_mipi_data_type_yuv420;
414 } else if (input_format >= ATOMISP_INPUT_FORMAT_RGB_444 &&
415 input_format <= ATOMISP_INPUT_FORMAT_RGB_888) {
417 inputfifo_mipi_data_type_rgb;
422 static struct inputfifo_instance *inputfifo_get_inst(
425 return &inputfifo_inst_admin[ch_id];
428 void ia_css_inputfifo_send_input_frame(
429 const unsigned short *data,
433 enum atomisp_input_format input_format,
436 unsigned int fmt_type, hblank_cycles, marker_cycles;
437 enum inputfifo_mipi_data_type type;
440 hblank_cycles = HBLANK_CYCLES;
441 marker_cycles = MARKER_CYCLES;
442 ia_css_isys_convert_stream_format_to_mipi_format(input_format,
446 type = inputfifo_determine_type(input_format);
448 inputfifo_send_frame(data, width, height,
449 ch_id, fmt_type, hblank_cycles, marker_cycles,
453 void ia_css_inputfifo_start_frame(
455 enum atomisp_input_format input_format,
458 struct inputfifo_instance *s2mi;
460 s2mi = inputfifo_get_inst(ch_id);
463 ia_css_isys_convert_stream_format_to_mipi_format(input_format,
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;
472 inputfifo_start_frame(ch_id, s2mi->fmt_type);
476 void ia_css_inputfifo_send_line(
478 const unsigned short *data,
480 const unsigned short *data2,
483 struct inputfifo_instance *s2mi;
486 assert((data2) || (width2 == 0));
487 s2mi = inputfifo_get_inst(ch_id);
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;
493 inputfifo_send_line2(data, width, data2, width2,
500 void ia_css_inputfifo_send_embedded_line(
502 enum atomisp_input_format data_type,
503 const unsigned short *data,
506 struct inputfifo_instance *s2mi;
507 unsigned int fmt_type;
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);
514 /* Set format_type for metadata line. */
515 inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK;
517 inputfifo_send_line(data, width, s2mi->hblank_cycles, s2mi->marker_cycles,
518 s2mi->two_ppc, inputfifo_mipi_data_type_regular);
521 void ia_css_inputfifo_end_frame(
524 struct inputfifo_instance *s2mi;
526 s2mi = inputfifo_get_inst(ch_id);
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;
532 /* Call existing HRT function */
533 inputfifo_end_frame(s2mi->marker_cycles);
535 s2mi->streaming = false;
538 #endif /* #if !defined(HAS_NO_INPUT_SYSTEM) */