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) */
539