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