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