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