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