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