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 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 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 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 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 */ 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 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 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 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