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