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