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