1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 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 "ia_css_mipi.h"
17 #include "sh_css_mipi.h"
18 #include <type_support.h>
19 #include "system_global.h"
20 #include "ia_css_err.h"
21 #include "ia_css_pipe.h"
22 #include "ia_css_stream_format.h"
23 #include "sh_css_stream_format.h"
24 #include "ia_css_stream_public.h"
25 #include "ia_css_frame_public.h"
26 #include "ia_css_input_port.h"
27 #include "ia_css_debug.h"
28 #include "sh_css_struct.h"
29 #include "sh_css_defs.h"
30 #include "sh_css_sp.h" /* sh_css_update_host2sp_mipi_frame sh_css_update_host2sp_num_mipi_frames ... */
31 #include "sw_event_global.h" /* IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY */
32 
33 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
34 static u32
35 ref_count_mipi_allocation[N_CSI_PORTS]; /* Initialized in mipi_init */
36 #endif
37 
38 int
39 ia_css_mipi_frame_specify(const unsigned int size_mem_words,
40 			  const bool contiguous) {
41 	int err = 0;
42 
43 	my_css.size_mem_words = size_mem_words;
44 	(void)contiguous;
45 
46 	return err;
47 }
48 
49 /*
50  * Check if a source port or TPG/PRBS ID is valid
51  */
52 static bool ia_css_mipi_is_source_port_valid(struct ia_css_pipe *pipe,
53 	unsigned int *pport)
54 {
55 	bool ret = true;
56 	unsigned int port = 0;
57 	unsigned int max_ports = 0;
58 
59 	switch (pipe->stream->config.mode) {
60 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
61 		port = (unsigned int)pipe->stream->config.source.port.port;
62 		max_ports = N_CSI_PORTS;
63 		break;
64 	case IA_CSS_INPUT_MODE_TPG:
65 		port = (unsigned int)pipe->stream->config.source.tpg.id;
66 		max_ports = N_CSS_TPG_IDS;
67 		break;
68 	case IA_CSS_INPUT_MODE_PRBS:
69 		port = (unsigned int)pipe->stream->config.source.prbs.id;
70 		max_ports = N_CSS_PRBS_IDS;
71 		break;
72 	default:
73 		assert(false);
74 		ret = false;
75 		break;
76 	}
77 
78 	if (ret) {
79 		assert(port < max_ports);
80 
81 		if (port >= max_ports)
82 			ret = false;
83 	}
84 
85 	*pport = port;
86 
87 	return ret;
88 }
89 
90 /* Assumptions:
91  *	- A line is multiple of 4 bytes = 1 word.
92  *	- Each frame has SOF and EOF (each 1 word).
93  *	- Each line has format header and optionally SOL and EOL (each 1 word).
94  *	- Odd and even lines of YUV420 format are different in bites per pixel size.
95  *	- Custom size of embedded data.
96  *  -- Interleaved frames are not taken into account.
97  *  -- Lines are multiples of 8B, and not necessary of (custom 3B, or 7B
98  *  etc.).
99  * Result is given in DDR mem words, 32B or 256 bits
100  */
101 int
102 ia_css_mipi_frame_calculate_size(const unsigned int width,
103 				 const unsigned int height,
104 				 const enum atomisp_input_format format,
105 				 const bool hasSOLandEOL,
106 				 const unsigned int embedded_data_size_words,
107 				 unsigned int *size_mem_words) {
108 	int err = 0;
109 
110 	unsigned int bits_per_pixel = 0;
111 	unsigned int even_line_bytes = 0;
112 	unsigned int odd_line_bytes = 0;
113 	unsigned int words_per_odd_line = 0;
114 	unsigned int words_for_first_line = 0;
115 	unsigned int words_per_even_line = 0;
116 	unsigned int mem_words_per_even_line = 0;
117 	unsigned int mem_words_per_odd_line = 0;
118 	unsigned int mem_words_for_first_line = 0;
119 	unsigned int mem_words_for_EOF = 0;
120 	unsigned int mem_words = 0;
121 	unsigned int width_padded = width;
122 
123 #if defined(USE_INPUT_SYSTEM_VERSION_2401)
124 	/* The changes will be reverted as soon as RAW
125 	 * Buffers are deployed by the 2401 Input System
126 	 * in the non-continuous use scenario.
127 	 */
128 	width_padded += (2 * ISP_VEC_NELEMS);
129 #endif
130 
131 	IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n",
132 		     width_padded, height, format, hasSOLandEOL, embedded_data_size_words);
133 
134 	switch (format)
135 	{
136 	case ATOMISP_INPUT_FORMAT_RAW_6:		/* 4p, 3B, 24bits */
137 		bits_per_pixel = 6;
138 		break;
139 	case ATOMISP_INPUT_FORMAT_RAW_7:		/* 8p, 7B, 56bits */
140 		bits_per_pixel = 7;
141 		break;
142 	case ATOMISP_INPUT_FORMAT_RAW_8:		/* 1p, 1B, 8bits */
143 	case ATOMISP_INPUT_FORMAT_BINARY_8:		/*  8bits, TODO: check. */
144 	case ATOMISP_INPUT_FORMAT_YUV420_8:		/* odd 2p, 2B, 16bits, even 2p, 4B, 32bits */
145 		bits_per_pixel = 8;
146 		break;
147 	case ATOMISP_INPUT_FORMAT_YUV420_10:		/* odd 4p, 5B, 40bits, even 4p, 10B, 80bits */
148 	case ATOMISP_INPUT_FORMAT_RAW_10:		/* 4p, 5B, 40bits */
149 #if !defined(HAS_NO_PACKED_RAW_PIXELS)
150 		/* The changes will be reverted as soon as RAW
151 		 * Buffers are deployed by the 2401 Input System
152 		 * in the non-continuous use scenario.
153 		 */
154 		bits_per_pixel = 10;
155 #else
156 		bits_per_pixel = 16;
157 #endif
158 		break;
159 	case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:	/* 2p, 3B, 24bits */
160 	case ATOMISP_INPUT_FORMAT_RAW_12:		/* 2p, 3B, 24bits */
161 		bits_per_pixel = 12;
162 		break;
163 	case ATOMISP_INPUT_FORMAT_RAW_14:		/* 4p, 7B, 56bits */
164 		bits_per_pixel = 14;
165 		break;
166 	case ATOMISP_INPUT_FORMAT_RGB_444:		/* 1p, 2B, 16bits */
167 	case ATOMISP_INPUT_FORMAT_RGB_555:		/* 1p, 2B, 16bits */
168 	case ATOMISP_INPUT_FORMAT_RGB_565:		/* 1p, 2B, 16bits */
169 	case ATOMISP_INPUT_FORMAT_YUV422_8:		/* 2p, 4B, 32bits */
170 		bits_per_pixel = 16;
171 		break;
172 	case ATOMISP_INPUT_FORMAT_RGB_666:		/* 4p, 9B, 72bits */
173 		bits_per_pixel = 18;
174 		break;
175 	case ATOMISP_INPUT_FORMAT_YUV422_10:		/* 2p, 5B, 40bits */
176 		bits_per_pixel = 20;
177 		break;
178 	case ATOMISP_INPUT_FORMAT_RGB_888:		/* 1p, 3B, 24bits */
179 		bits_per_pixel = 24;
180 		break;
181 
182 	case ATOMISP_INPUT_FORMAT_YUV420_16:		/* Not supported */
183 	case ATOMISP_INPUT_FORMAT_YUV422_16:		/* Not supported */
184 	case ATOMISP_INPUT_FORMAT_RAW_16:		/* TODO: not specified in MIPI SPEC, check */
185 	default:
186 		return -EINVAL;
187 	}
188 
189 	odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
190 
191 	/* Even lines for YUV420 formats are double in bits_per_pixel. */
192 	if (format == ATOMISP_INPUT_FORMAT_YUV420_8
193 	    || format == ATOMISP_INPUT_FORMAT_YUV420_10
194 	    || format == ATOMISP_INPUT_FORMAT_YUV420_16)
195 	{
196 		even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
197 			3; /* ceil ( bits per line / 8) */
198 	} else
199 	{
200 		even_line_bytes = odd_line_bytes;
201 	}
202 
203 	/*  a frame represented in memory:  ()- optional; data - payload words.
204 	*  addr		0	1	2	3	4	5	6	7:
205 	*  first	SOF	(SOL)	PACK_H	data	data	data	data	data
206 	*		data	data	data	data	data	data	data	data
207 	*		...
208 	*		data	data	0	0	0	0	0	0
209 	*  second	(EOL)	(SOL)	PACK_H	data	data	data	data	data
210 	*		data	data	data	data	data	data	data	data
211 	*		...
212 	*		data	data	0	0	0	0	0	0
213 	*  ...
214 	*  last		(EOL)	EOF	0	0	0	0	0	0
215 	*
216 	*  Embedded lines are regular lines stored before the first and after
217 	*  payload lines.
218 	*/
219 
220 	words_per_odd_line = (odd_line_bytes + 3) >> 2;
221 	/* ceil(odd_line_bytes/4); word = 4 bytes */
222 	words_per_even_line  = (even_line_bytes  + 3) >> 2;
223 	words_for_first_line = words_per_odd_line + 2 + (hasSOLandEOL ? 1 : 0);
224 	/* + SOF +packet header + optionally (SOL), but (EOL) is not in the first line */
225 	words_per_odd_line	+= (1 + (hasSOLandEOL ? 2 : 0));
226 	/* each non-first line has format header, and optionally (SOL) and (EOL). */
227 	words_per_even_line += (1 + (hasSOLandEOL ? 2 : 0));
228 
229 	mem_words_per_odd_line	 = (words_per_odd_line + 7) >> 3;
230 	/* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
231 	mem_words_for_first_line = (words_for_first_line + 7) >> 3;
232 	mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
233 	mem_words_for_EOF        = 1; /* last line consisit of the optional (EOL) and EOF */
234 
235 	mem_words = ((embedded_data_size_words + 7) >> 3) +
236 	mem_words_for_first_line +
237 	(((height + 1) >> 1) - 1) * mem_words_per_odd_line +
238 	/* ceil (height/2) - 1 (first line is calculated separatelly) */
239 	(height      >> 1) * mem_words_per_even_line + /* floor(height/2) */
240 	mem_words_for_EOF;
241 
242 	*size_mem_words = mem_words; /* ceil(words/8); mem word is 32B = 8words. */
243 	/* Check if the above is still needed. */
244 
245 	IA_CSS_LEAVE_ERR(err);
246 	return err;
247 }
248 
249 #if !defined(HAS_NO_INPUT_SYSTEM) && defined(USE_INPUT_SYSTEM_VERSION_2)
250 int
251 ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port,
252 				       const unsigned int	size_mem_words) {
253 	u32 idx;
254 
255 	int err = -EBUSY;
256 
257 	OP___assert(port < N_CSI_PORTS);
258 	OP___assert(size_mem_words != 0);
259 
260 	for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT &&
261 	     my_css.mipi_sizes_for_check[port][idx] != 0;
262 	     idx++)   /* do nothing */
263 	{
264 	}
265 	if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT)
266 	{
267 		my_css.mipi_sizes_for_check[port][idx] = size_mem_words;
268 		err = 0;
269 	}
270 
271 	return err;
272 }
273 #endif
274 
275 void
276 mipi_init(void)
277 {
278 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
279 	unsigned int i;
280 
281 	for (i = 0; i < N_CSI_PORTS; i++)
282 		ref_count_mipi_allocation[i] = 0;
283 #endif
284 }
285 
286 int
287 calculate_mipi_buff_size(
288     struct ia_css_stream_config *stream_cfg,
289     unsigned int *size_mem_words) {
290 #if !defined(USE_INPUT_SYSTEM_VERSION_2401)
291 	int err = -EINVAL;
292 	(void)stream_cfg;
293 	(void)size_mem_words;
294 #else
295 	unsigned int width;
296 	unsigned int height;
297 	enum atomisp_input_format format;
298 	bool pack_raw_pixels;
299 
300 	unsigned int width_padded;
301 	unsigned int bits_per_pixel = 0;
302 
303 	unsigned int even_line_bytes = 0;
304 	unsigned int odd_line_bytes = 0;
305 
306 	unsigned int words_per_odd_line = 0;
307 	unsigned int words_per_even_line = 0;
308 
309 	unsigned int mem_words_per_even_line = 0;
310 	unsigned int mem_words_per_odd_line = 0;
311 
312 	unsigned int mem_words_per_buff_line = 0;
313 	unsigned int mem_words_per_buff = 0;
314 	int err = 0;
315 
316 	/**
317 	 * zhengjie.lu@intel.com
318 	 *
319 	 * NOTE
320 	 * - In the struct "ia_css_stream_config", there
321 	 *   are two members: "input_config" and "isys_config".
322 	 *   Both of them provide the same information, e.g.
323 	 *   input_res and format.
324 	 *
325 	 *   Question here is that: which one shall be used?
326 	 */
327 	width = stream_cfg->input_config.input_res.width;
328 	height = stream_cfg->input_config.input_res.height;
329 	format = stream_cfg->input_config.format;
330 	pack_raw_pixels = stream_cfg->pack_raw_pixels;
331 	/* end of NOTE */
332 
333 	/**
334 	 * zhengjie.lu@intel.com
335 	 *
336 	 * NOTE
337 	 * - The following code is derived from the
338 	 *   existing code "ia_css_mipi_frame_calculate_size()".
339 	 *
340 	 *   Question here is: why adding "2 * ISP_VEC_NELEMS"
341 	 *   to "width_padded", but not making "width_padded"
342 	 *   aligned with "2 * ISP_VEC_NELEMS"?
343 	 */
344 	/* The changes will be reverted as soon as RAW
345 	 * Buffers are deployed by the 2401 Input System
346 	 * in the non-continuous use scenario.
347 	 */
348 	width_padded = width + (2 * ISP_VEC_NELEMS);
349 	/* end of NOTE */
350 
351 	IA_CSS_ENTER("padded_width=%d, height=%d, format=%d\n",
352 		     width_padded, height, format);
353 
354 	bits_per_pixel = sh_css_stream_format_2_bits_per_subpixel(format);
355 	bits_per_pixel =
356 	(format == ATOMISP_INPUT_FORMAT_RAW_10 && pack_raw_pixels) ? bits_per_pixel : 16;
357 	if (bits_per_pixel == 0)
358 		return -EINVAL;
359 
360 	odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
361 
362 	/* Even lines for YUV420 formats are double in bits_per_pixel. */
363 	if (format == ATOMISP_INPUT_FORMAT_YUV420_8
364 	    || format == ATOMISP_INPUT_FORMAT_YUV420_10)
365 	{
366 		even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
367 			3; /* ceil ( bits per line / 8) */
368 	} else
369 	{
370 		even_line_bytes = odd_line_bytes;
371 	}
372 
373 	words_per_odd_line	 = (odd_line_bytes   + 3) >> 2;
374 	/* ceil(odd_line_bytes/4); word = 4 bytes */
375 	words_per_even_line  = (even_line_bytes  + 3) >> 2;
376 
377 	mem_words_per_odd_line	 = (words_per_odd_line + 7) >> 3;
378 	/* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
379 	mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
380 
381 	mem_words_per_buff_line =
382 	(mem_words_per_odd_line > mem_words_per_even_line) ? mem_words_per_odd_line : mem_words_per_even_line;
383 	mem_words_per_buff = mem_words_per_buff_line * height;
384 
385 	*size_mem_words = mem_words_per_buff;
386 
387 	IA_CSS_LEAVE_ERR(err);
388 #endif
389 	return err;
390 }
391 
392 static bool buffers_needed(struct ia_css_pipe *pipe)
393 {
394 	if (!IS_ISP2401) {
395 		if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
396 			return false;
397 		else
398 			return true;
399 	}
400 
401 	if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR ||
402 	    pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
403 	    pipe->stream->config.mode == IA_CSS_INPUT_MODE_PRBS)
404 		return false;
405 
406 	return true;
407 }
408 
409 int
410 allocate_mipi_frames(struct ia_css_pipe *pipe,
411 		     struct ia_css_stream_info *info) {
412 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
413 	int err = -EINVAL;
414 	unsigned int port;
415 	struct ia_css_frame_info mipi_intermediate_info;
416 
417 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
418 			    "allocate_mipi_frames(%p) enter:\n", pipe);
419 
420 	assert(pipe);
421 	assert(pipe->stream);
422 	if ((!pipe) || (!pipe->stream))
423 	{
424 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
425 				    "allocate_mipi_frames(%p) exit: pipe or stream is null.\n",
426 				    pipe);
427 		return -EINVAL;
428 	}
429 
430 #ifdef USE_INPUT_SYSTEM_VERSION_2401
431 	if (pipe->stream->config.online)
432 	{
433 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
434 				    "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n",
435 				    pipe);
436 		return 0;
437 	}
438 
439 #endif
440 
441 	if (!buffers_needed(pipe)) {
442 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
443 				    "allocate_mipi_frames(%p) exit: no buffers needed for pipe mode.\n",
444 				    pipe);
445 		return 0; /* AM TODO: Check  */
446 	}
447 
448 	if (!IS_ISP2401)
449 		port = (unsigned int)pipe->stream->config.source.port.port;
450 	else
451 		err = ia_css_mipi_is_source_port_valid(pipe, &port);
452 
453 	assert(port < N_CSI_PORTS);
454 
455 	if (port >= N_CSI_PORTS || err) {
456 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
457 				    "allocate_mipi_frames(%p) exit: error: port is not correct (port=%d).\n",
458 				    pipe, port);
459 		return -EINVAL;
460 	}
461 
462 #ifdef USE_INPUT_SYSTEM_VERSION_2401
463 	err = calculate_mipi_buff_size(
464 	    &pipe->stream->config,
465 	    &my_css.mipi_frame_size[port]);
466 #endif
467 
468 #if defined(USE_INPUT_SYSTEM_VERSION_2)
469 	if (ref_count_mipi_allocation[port] != 0)
470 	{
471 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
472 				    "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n",
473 				    pipe, port);
474 		return 0;
475 	}
476 #else
477 	/* 2401 system allows multiple streams to use same physical port. This is not
478 	 * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
479 	 * TODO AM: Once that is changed (removed) this code should be removed as well.
480 	 * In that case only 2400 related code should remain.
481 	 */
482 	if (ref_count_mipi_allocation[port] != 0)
483 	{
484 		ref_count_mipi_allocation[port]++;
485 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
486 				    "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n",
487 				    pipe, port);
488 		return 0;
489 	}
490 #endif
491 
492 	ref_count_mipi_allocation[port]++;
493 
494 	/* TODO: Cleaning needed. */
495 	/* This code needs to modified to allocate the MIPI frames in the correct normal way
496 	  with an allocate from info, by justin */
497 	mipi_intermediate_info = pipe->pipe_settings.video.video_binary.internal_frame_info;
498 	mipi_intermediate_info.res.width = 0;
499 	mipi_intermediate_info.res.height = 0;
500 	/* To indicate it is not (yet) valid format. */
501 	mipi_intermediate_info.format = IA_CSS_FRAME_FORMAT_NUM;
502 	mipi_intermediate_info.padded_width = 0;
503 	mipi_intermediate_info.raw_bit_depth = 0;
504 
505 	/* AM TODO: mipi frames number should come from stream struct. */
506 	my_css.num_mipi_frames[port] = NUM_MIPI_FRAMES_PER_STREAM;
507 
508 	/* Incremental allocation (per stream), not for all streams at once. */
509 	{ /* limit the scope of i,j */
510 		unsigned int i, j;
511 
512 		for (i = 0; i < my_css.num_mipi_frames[port]; i++)
513 		{
514 			/* free previous frame */
515 			if (my_css.mipi_frames[port][i]) {
516 				ia_css_frame_free(my_css.mipi_frames[port][i]);
517 				my_css.mipi_frames[port][i] = NULL;
518 			}
519 			/* check if new frame is needed */
520 			if (i < my_css.num_mipi_frames[port]) {
521 				/* allocate new frame */
522 				err = ia_css_frame_allocate_with_buffer_size(
523 					  &my_css.mipi_frames[port][i],
524 					  my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES,
525 					  false);
526 				if (err) {
527 					for (j = 0; j < i; j++) {
528 						if (my_css.mipi_frames[port][j]) {
529 							ia_css_frame_free(my_css.mipi_frames[port][j]);
530 							my_css.mipi_frames[port][j] = NULL;
531 						}
532 					}
533 					ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
534 							    "allocate_mipi_frames(%p, %d) exit: error: allocation failed.\n",
535 							    pipe, port);
536 					return err;
537 				}
538 			}
539 			if (info->metadata_info.size > 0) {
540 				/* free previous metadata buffer */
541 				if (my_css.mipi_metadata[port][i]) {
542 					ia_css_metadata_free(my_css.mipi_metadata[port][i]);
543 					my_css.mipi_metadata[port][i] = NULL;
544 				}
545 				/* check if need to allocate a new metadata buffer */
546 				if (i < my_css.num_mipi_frames[port]) {
547 					/* allocate new metadata buffer */
548 					my_css.mipi_metadata[port][i] = ia_css_metadata_allocate(&info->metadata_info);
549 					if (!my_css.mipi_metadata[port][i]) {
550 						ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
551 								    "allocate_mipi_metadata(%p, %d) failed.\n",
552 								    pipe, port);
553 						return err;
554 					}
555 				}
556 			}
557 		}
558 	}
559 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
560 			    "allocate_mipi_frames(%p) exit:\n", pipe);
561 
562 	return err;
563 #else
564 	(void)pipe;
565 	(void)info;
566 	return 0;
567 #endif
568 }
569 
570 int
571 free_mipi_frames(struct ia_css_pipe *pipe) {
572 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
573 	int err = -EINVAL;
574 	unsigned int port;
575 
576 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
577 			    "free_mipi_frames(%p) enter:\n", pipe);
578 
579 	/* assert(pipe != NULL); TEMP: TODO: Should be assert only. */
580 	if (pipe)
581 	{
582 		assert(pipe->stream);
583 		if ((!pipe) || (!pipe->stream)) {
584 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
585 					    "free_mipi_frames(%p) exit: error: pipe or stream is null.\n",
586 					    pipe);
587 			return -EINVAL;
588 		}
589 
590 		if (!buffers_needed(pipe)) {
591 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
592 					    "free_mipi_frames(%p) exit: error: wrong mode.\n",
593 					    pipe);
594 			return err;
595 		}
596 
597 		if (!IS_ISP2401)
598 			port = (unsigned int)pipe->stream->config.source.port.port;
599 		else
600 			err = ia_css_mipi_is_source_port_valid(pipe, &port);
601 
602 		assert(port < N_CSI_PORTS);
603 
604 		if (port >= N_CSI_PORTS || err) {
605 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
606 					    "free_mipi_frames(%p, %d) exit: error: pipe port is not correct.\n",
607 					    pipe, port);
608 			return err;
609 		}
610 
611 		if (ref_count_mipi_allocation[port] > 0) {
612 #if defined(USE_INPUT_SYSTEM_VERSION_2)
613 			assert(ref_count_mipi_allocation[port] == 1);
614 			if (ref_count_mipi_allocation[port] != 1) {
615 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
616 						    "free_mipi_frames(%p) exit: error: wrong ref_count (ref_count=%d).\n",
617 						    pipe, ref_count_mipi_allocation[port]);
618 				return err;
619 			}
620 #endif
621 
622 			ref_count_mipi_allocation[port]--;
623 
624 			if (ref_count_mipi_allocation[port] == 0) {
625 				/* no streams are using this buffer, so free it */
626 				unsigned int i;
627 
628 				for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
629 					if (my_css.mipi_frames[port][i]) {
630 						ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
631 								    "free_mipi_frames(port=%d, num=%d).\n", port, i);
632 						ia_css_frame_free(my_css.mipi_frames[port][i]);
633 						my_css.mipi_frames[port][i] = NULL;
634 					}
635 					if (my_css.mipi_metadata[port][i]) {
636 						ia_css_metadata_free(my_css.mipi_metadata[port][i]);
637 						my_css.mipi_metadata[port][i] = NULL;
638 					}
639 				}
640 
641 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
642 						    "free_mipi_frames(%p) exit (deallocated).\n", pipe);
643 			}
644 #if defined(USE_INPUT_SYSTEM_VERSION_2401)
645 			else {
646 				/* 2401 system allows multiple streams to use same physical port. This is not
647 				 * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
648 				 * TODO AM: Once that is changed (removed) this code should be removed as well.
649 				 * In that case only 2400 related code should remain.
650 				 */
651 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
652 						    "free_mipi_frames(%p) leave: nothing to do, other streams still use this port (port=%d).\n",
653 						    pipe, port);
654 			}
655 #endif
656 		}
657 	} else   /* pipe ==NULL */
658 	{
659 		/* AM TEMP: free-ing all mipi buffers just like a legacy code. */
660 		for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) {
661 			unsigned int i;
662 
663 			for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
664 				if (my_css.mipi_frames[port][i]) {
665 					ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
666 							    "free_mipi_frames(port=%d, num=%d).\n", port, i);
667 					ia_css_frame_free(my_css.mipi_frames[port][i]);
668 					my_css.mipi_frames[port][i] = NULL;
669 				}
670 				if (my_css.mipi_metadata[port][i]) {
671 					ia_css_metadata_free(my_css.mipi_metadata[port][i]);
672 					my_css.mipi_metadata[port][i] = NULL;
673 				}
674 			}
675 			ref_count_mipi_allocation[port] = 0;
676 		}
677 	}
678 #else
679 	(void)pipe;
680 #endif
681 	return 0;
682 }
683 
684 int
685 send_mipi_frames(struct ia_css_pipe *pipe) {
686 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
687 	int err = -EINVAL;
688 	unsigned int i;
689 #ifndef ISP2401
690 	unsigned int port;
691 #else
692 	unsigned int port = 0;
693 #endif
694 
695 	IA_CSS_ENTER_PRIVATE("pipe=%p", pipe);
696 
697 	assert(pipe);
698 	assert(pipe->stream);
699 	if (!pipe || !pipe->stream)
700 	{
701 		IA_CSS_ERROR("pipe or stream is null");
702 		return -EINVAL;
703 	}
704 
705 	/* multi stream video needs mipi buffers */
706 	/* nothing to be done in other cases. */
707 	if (!buffers_needed(pipe)) {
708 		IA_CSS_LOG("nothing to be done for this mode");
709 		return 0;
710 		/* TODO: AM: maybe this should be returning an error. */
711 	}
712 
713 	if (!IS_ISP2401)
714 		port = (unsigned int)pipe->stream->config.source.port.port;
715 	else
716 		err = ia_css_mipi_is_source_port_valid(pipe, &port);
717 
718 	assert(port < N_CSI_PORTS);
719 
720 	if (port >= N_CSI_PORTS || err) {
721 		IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).\n",
722 			     pipe, port);
723 		return err;
724 	}
725 
726 	/* Hand-over the SP-internal mipi buffers */
727 	for (i = 0; i < my_css.num_mipi_frames[port]; i++)
728 	{
729 		/* Need to include the ofset for port. */
730 		sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i,
731 						 my_css.mipi_frames[port][i]);
732 		sh_css_update_host2sp_mipi_metadata(port * NUM_MIPI_FRAMES_PER_STREAM + i,
733 						    my_css.mipi_metadata[port][i]);
734 	}
735 	sh_css_update_host2sp_num_mipi_frames(my_css.num_mipi_frames[port]);
736 
737 	/**********************************
738 	 * Send an event to inform the SP
739 	 * that all MIPI frames are passed.
740 	 **********************************/
741 	if (!sh_css_sp_is_running())
742 	{
743 		/* SP is not running. The queues are not valid */
744 		IA_CSS_ERROR("sp is not running");
745 		return err;
746 	}
747 
748 	ia_css_bufq_enqueue_psys_event(
749 	    IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY,
750 	    (uint8_t)port,
751 	    (uint8_t)my_css.num_mipi_frames[port],
752 	    0 /* not used */);
753 	IA_CSS_LEAVE_ERR_PRIVATE(0);
754 #else
755 	(void)pipe;
756 #endif
757 	return 0;
758 }
759