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