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