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 */
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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
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 
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 
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 
414 static struct inputfifo_instance *inputfifo_get_inst(
415     unsigned int ch_id)
416 {
417 	return &inputfifo_inst_admin[ch_id];
418 }
419 
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 
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 
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 
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 
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