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