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