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 /*! \file */ 17 #include <linux/mm.h> 18 #include <linux/slab.h> 19 #include <linux/vmalloc.h> 20 21 #include "hmm.h" 22 23 #include "atomisp_internal.h" 24 25 #include "ia_css.h" 26 #include "sh_css_hrt.h" /* only for file 2 MIPI */ 27 #include "ia_css_buffer.h" 28 #include "ia_css_binary.h" 29 #include "sh_css_internal.h" 30 #include "sh_css_mipi.h" 31 #include "sh_css_sp.h" /* sh_css_sp_group */ 32 #include "ia_css_isys.h" 33 #include "ia_css_frame.h" 34 #include "sh_css_defs.h" 35 #include "sh_css_firmware.h" 36 #include "sh_css_params.h" 37 #include "sh_css_params_internal.h" 38 #include "sh_css_param_shading.h" 39 #include "ia_css_refcount.h" 40 #include "ia_css_rmgr.h" 41 #include "ia_css_debug.h" 42 #include "ia_css_debug_pipe.h" 43 #include "ia_css_device_access.h" 44 #include "device_access.h" 45 #include "sh_css_legacy.h" 46 #include "ia_css_pipeline.h" 47 #include "ia_css_stream.h" 48 #include "sh_css_stream_format.h" 49 #include "ia_css_pipe.h" 50 #include "ia_css_util.h" 51 #include "ia_css_pipe_util.h" 52 #include "ia_css_pipe_binarydesc.h" 53 #include "ia_css_pipe_stagedesc.h" 54 55 #include "tag.h" 56 #include "assert_support.h" 57 #include "math_support.h" 58 #include "sw_event_global.h" /* Event IDs.*/ 59 #include "ia_css_ifmtr.h" 60 #include "input_system.h" 61 #include "mmu_device.h" /* mmu_set_page_table_base_index(), ... */ 62 #include "ia_css_mmu_private.h" /* sh_css_mmu_set_page_table_base_index() */ 63 #include "gdc_device.h" /* HRT_GDC_N */ 64 #include "dma.h" /* dma_set_max_burst_size() */ 65 #include "irq.h" /* virq */ 66 #include "sp.h" /* cnd_sp_irq_enable() */ 67 #include "isp.h" /* cnd_isp_irq_enable, ISP_VEC_NELEMS */ 68 #include "gp_device.h" /* gp_device_reg_store() */ 69 #define __INLINE_GPIO__ 70 #include "gpio.h" 71 #include "timed_ctrl.h" 72 #include "ia_css_inputfifo.h" 73 #define WITH_PC_MONITORING 0 74 75 #define SH_CSS_VIDEO_BUFFER_ALIGNMENT 0 76 77 78 #include "ia_css_spctrl.h" 79 #include "ia_css_version_data.h" 80 #include "sh_css_struct.h" 81 #include "ia_css_bufq.h" 82 #include "ia_css_timer.h" /* clock_value_t */ 83 84 #include "isp/modes/interface/input_buf.isp.h" 85 86 /* Name of the sp program: should not be built-in */ 87 #define SP_PROG_NAME "sp" 88 /* Size of Refcount List */ 89 #define REFCOUNT_SIZE 1000 90 91 /* 92 * for JPEG, we don't know the length of the image upfront, 93 * but since we support sensor up to 16MP, we take this as 94 * upper limit. 95 */ 96 #define JPEG_BYTES (16 * 1024 * 1024) 97 98 struct sh_css my_css; 99 100 int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL; 101 102 /* 103 * modes of work: stream_create and stream_destroy will update the save/restore 104 * data only when in working mode, not suspend/resume 105 */ 106 enum ia_sh_css_modes { 107 sh_css_mode_none = 0, 108 sh_css_mode_working, 109 sh_css_mode_suspend, 110 sh_css_mode_resume 111 }; 112 113 /** 114 * struct sh_css_stream_seed - a stream seed, to save and restore the 115 * stream data. 116 * 117 * @orig_stream: pointer to restore the original handle 118 * @stream: handle, used as ID too. 119 * @stream_config: stream config struct 120 * @num_pipes: number of pipes 121 * @pipes: pipe handles 122 * @orig_pipes: pointer to restore original handle 123 * @pipe_config: pipe config structs 124 * 125 * the stream seed contains all the data required to "grow" the seed again 126 * after it was closed. 127 */ 128 struct sh_css_stream_seed { 129 struct ia_css_stream **orig_stream; 130 struct ia_css_stream *stream; 131 struct ia_css_stream_config stream_config; 132 int num_pipes; 133 struct ia_css_pipe *pipes[IA_CSS_PIPE_ID_NUM]; 134 struct ia_css_pipe **orig_pipes[IA_CSS_PIPE_ID_NUM]; 135 struct ia_css_pipe_config pipe_config[IA_CSS_PIPE_ID_NUM]; 136 }; 137 138 #define MAX_ACTIVE_STREAMS 5 139 /* 140 * A global struct for save/restore to hold all the data that should 141 * sustain power-down: MMU base, IRQ type, env for routines, binary loaded FW 142 * and the stream seeds. 143 */ 144 struct sh_css_save { 145 enum ia_sh_css_modes mode; 146 u32 mmu_base; /* the last mmu_base */ 147 enum ia_css_irq_type irq_type; 148 struct sh_css_stream_seed stream_seeds[MAX_ACTIVE_STREAMS]; 149 struct ia_css_fw *loaded_fw; /* fw struct previously loaded */ 150 struct ia_css_env driver_env; /* driver-supplied env copy */ 151 }; 152 153 static bool my_css_save_initialized; /* if my_css_save was initialized */ 154 static struct sh_css_save my_css_save; 155 156 /* 157 * pqiao NOTICE: this is for css internal buffer recycling when stopping 158 * pipeline, 159 * this array is temporary and will be replaced by resource manager 160 */ 161 162 /* Taking the biggest Size for number of Elements */ 163 #define MAX_HMM_BUFFER_NUM \ 164 (SH_CSS_MAX_NUM_QUEUES * (IA_CSS_NUM_ELEMS_SP2HOST_BUFFER_QUEUE + 2)) 165 166 struct sh_css_hmm_buffer_record { 167 bool in_use; 168 enum ia_css_buffer_type type; 169 struct ia_css_rmgr_vbuf_handle *h_vbuf; 170 hrt_address kernel_ptr; 171 }; 172 173 static struct sh_css_hmm_buffer_record hmm_buffer_record[MAX_HMM_BUFFER_NUM]; 174 175 #define GPIO_FLASH_PIN_MASK BIT(HIVE_GPIO_STROBE_TRIGGER_PIN) 176 177 static bool fw_explicitly_loaded; 178 179 /* 180 * Local prototypes 181 */ 182 183 static int 184 allocate_delay_frames(struct ia_css_pipe *pipe); 185 186 static int 187 sh_css_pipe_start(struct ia_css_stream *stream); 188 189 /* 190 * @brief Check if all "ia_css_pipe" instances in the target 191 * "ia_css_stream" instance have stopped. 192 * 193 * @param[in] stream Point to the target "ia_css_stream" instance. 194 * 195 * @return 196 * - true, if all "ia_css_pipe" instances in the target "ia_css_stream" 197 * instance have ben stopped. 198 * - false, otherwise. 199 */ 200 201 /* ISP 2401 */ 202 static int 203 ia_css_pipe_check_format(struct ia_css_pipe *pipe, 204 enum ia_css_frame_format format); 205 206 /* ISP 2401 */ 207 static void 208 ia_css_reset_defaults(struct sh_css *css); 209 210 static void 211 sh_css_init_host_sp_control_vars(void); 212 213 static int 214 set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version); 215 216 static bool 217 need_capture_pp(const struct ia_css_pipe *pipe); 218 219 static bool 220 need_yuv_scaler_stage(const struct ia_css_pipe *pipe); 221 222 static int ia_css_pipe_create_cas_scaler_desc_single_output( 223 struct ia_css_frame_info *cas_scaler_in_info, 224 struct ia_css_frame_info *cas_scaler_out_info, 225 struct ia_css_frame_info *cas_scaler_vf_info, 226 struct ia_css_cas_binary_descr *descr); 227 228 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr 229 *descr); 230 231 static bool 232 need_downscaling(const struct ia_css_resolution in_res, 233 const struct ia_css_resolution out_res); 234 235 static bool need_capt_ldc(const struct ia_css_pipe *pipe); 236 237 static int 238 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe); 239 240 static 241 int sh_css_pipe_get_viewfinder_frame_info( 242 struct ia_css_pipe *pipe, 243 struct ia_css_frame_info *info, 244 unsigned int idx); 245 246 static int 247 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, 248 struct ia_css_frame_info *info, 249 unsigned int idx); 250 251 static int 252 capture_start(struct ia_css_pipe *pipe); 253 254 static int 255 video_start(struct ia_css_pipe *pipe); 256 257 static int 258 preview_start(struct ia_css_pipe *pipe); 259 260 static int 261 yuvpp_start(struct ia_css_pipe *pipe); 262 263 static bool copy_on_sp(struct ia_css_pipe *pipe); 264 265 static int 266 init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, 267 struct ia_css_frame *vf_frame, unsigned int idx); 268 269 static int 270 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, 271 struct ia_css_frame *frame, enum ia_css_frame_format format); 272 273 static int 274 init_out_frameinfo_defaults(struct ia_css_pipe *pipe, 275 struct ia_css_frame *out_frame, unsigned int idx); 276 277 static int 278 alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time); 279 280 static void 281 pipe_global_init(void); 282 283 static int 284 pipe_generate_pipe_num(const struct ia_css_pipe *pipe, 285 unsigned int *pipe_number); 286 287 static void 288 pipe_release_pipe_num(unsigned int pipe_num); 289 290 static int 291 create_host_pipeline_structure(struct ia_css_stream *stream); 292 293 static int 294 create_host_pipeline(struct ia_css_stream *stream); 295 296 static int 297 create_host_preview_pipeline(struct ia_css_pipe *pipe); 298 299 static int 300 create_host_video_pipeline(struct ia_css_pipe *pipe); 301 302 static int 303 create_host_copy_pipeline(struct ia_css_pipe *pipe, 304 unsigned int max_input_width, 305 struct ia_css_frame *out_frame); 306 307 static int 308 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe); 309 310 static int 311 create_host_capture_pipeline(struct ia_css_pipe *pipe); 312 313 static int 314 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe); 315 316 static unsigned int 317 sh_css_get_sw_interrupt_value(unsigned int irq); 318 319 static struct ia_css_binary *ia_css_pipe_get_shading_correction_binary( 320 const struct ia_css_pipe *pipe); 321 322 static struct ia_css_binary * 323 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe); 324 325 static struct ia_css_binary * 326 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe); 327 328 static void 329 sh_css_hmm_buffer_record_init(void); 330 331 static void 332 sh_css_hmm_buffer_record_uninit(void); 333 334 static void 335 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record); 336 337 static struct sh_css_hmm_buffer_record 338 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf, 339 enum ia_css_buffer_type type, 340 hrt_address kernel_ptr); 341 342 static struct sh_css_hmm_buffer_record 343 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr, 344 enum ia_css_buffer_type type); 345 346 static unsigned int get_crop_lines_for_bayer_order(const struct 347 ia_css_stream_config *config); 348 static unsigned int get_crop_columns_for_bayer_order(const struct 349 ia_css_stream_config *config); 350 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe, 351 unsigned int *extra_row, unsigned int *extra_column); 352 353 static void 354 sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe) 355 { 356 if (!pipe) { 357 IA_CSS_ERROR("NULL input parameter"); 358 return; 359 } 360 361 if (pipe->shading_table) 362 ia_css_shading_table_free(pipe->shading_table); 363 pipe->shading_table = NULL; 364 } 365 366 static enum ia_css_frame_format yuv420_copy_formats[] = { 367 IA_CSS_FRAME_FORMAT_NV12, 368 IA_CSS_FRAME_FORMAT_NV21, 369 IA_CSS_FRAME_FORMAT_YV12, 370 IA_CSS_FRAME_FORMAT_YUV420, 371 IA_CSS_FRAME_FORMAT_YUV420_16, 372 IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8, 373 IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8 374 }; 375 376 static enum ia_css_frame_format yuv422_copy_formats[] = { 377 IA_CSS_FRAME_FORMAT_NV12, 378 IA_CSS_FRAME_FORMAT_NV16, 379 IA_CSS_FRAME_FORMAT_NV21, 380 IA_CSS_FRAME_FORMAT_NV61, 381 IA_CSS_FRAME_FORMAT_YV12, 382 IA_CSS_FRAME_FORMAT_YV16, 383 IA_CSS_FRAME_FORMAT_YUV420, 384 IA_CSS_FRAME_FORMAT_YUV420_16, 385 IA_CSS_FRAME_FORMAT_YUV422, 386 IA_CSS_FRAME_FORMAT_YUV422_16, 387 IA_CSS_FRAME_FORMAT_UYVY, 388 IA_CSS_FRAME_FORMAT_YUYV 389 }; 390 391 /* 392 * Verify whether the selected output format is can be produced 393 * by the copy binary given the stream format. 394 */ 395 static int 396 verify_copy_out_frame_format(struct ia_css_pipe *pipe) 397 { 398 enum ia_css_frame_format out_fmt = pipe->output_info[0].format; 399 unsigned int i, found = 0; 400 401 assert(pipe); 402 assert(pipe->stream); 403 404 switch (pipe->stream->config.input_config.format) { 405 case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: 406 case ATOMISP_INPUT_FORMAT_YUV420_8: 407 for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++) 408 found = (out_fmt == yuv420_copy_formats[i]); 409 break; 410 case ATOMISP_INPUT_FORMAT_YUV420_10: 411 case ATOMISP_INPUT_FORMAT_YUV420_16: 412 found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16); 413 break; 414 case ATOMISP_INPUT_FORMAT_YUV422_8: 415 for (i = 0; i < ARRAY_SIZE(yuv422_copy_formats) && !found; i++) 416 found = (out_fmt == yuv422_copy_formats[i]); 417 break; 418 case ATOMISP_INPUT_FORMAT_YUV422_10: 419 case ATOMISP_INPUT_FORMAT_YUV422_16: 420 found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV422_16 || 421 out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16); 422 break; 423 case ATOMISP_INPUT_FORMAT_RGB_444: 424 case ATOMISP_INPUT_FORMAT_RGB_555: 425 case ATOMISP_INPUT_FORMAT_RGB_565: 426 found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 || 427 out_fmt == IA_CSS_FRAME_FORMAT_RGB565); 428 break; 429 case ATOMISP_INPUT_FORMAT_RGB_666: 430 case ATOMISP_INPUT_FORMAT_RGB_888: 431 found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 || 432 out_fmt == IA_CSS_FRAME_FORMAT_YUV420); 433 break; 434 case ATOMISP_INPUT_FORMAT_RAW_6: 435 case ATOMISP_INPUT_FORMAT_RAW_7: 436 case ATOMISP_INPUT_FORMAT_RAW_8: 437 case ATOMISP_INPUT_FORMAT_RAW_10: 438 case ATOMISP_INPUT_FORMAT_RAW_12: 439 case ATOMISP_INPUT_FORMAT_RAW_14: 440 case ATOMISP_INPUT_FORMAT_RAW_16: 441 found = (out_fmt == IA_CSS_FRAME_FORMAT_RAW) || 442 (out_fmt == IA_CSS_FRAME_FORMAT_RAW_PACKED); 443 break; 444 case ATOMISP_INPUT_FORMAT_BINARY_8: 445 found = (out_fmt == IA_CSS_FRAME_FORMAT_BINARY_8); 446 break; 447 default: 448 break; 449 } 450 if (!found) 451 return -EINVAL; 452 return 0; 453 } 454 455 unsigned int 456 ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream) 457 { 458 int bpp = 0; 459 460 if (stream) 461 bpp = ia_css_util_input_format_bpp(stream->config.input_config.format, 462 stream->config.pixels_per_clock == 2); 463 464 return bpp; 465 } 466 467 /* TODO: move define to proper file in tools */ 468 #define GP_ISEL_TPG_MODE 0x90058 469 470 static int 471 sh_css_config_input_network_2400(struct ia_css_stream *stream) 472 { 473 unsigned int fmt_type; 474 struct ia_css_pipe *pipe = stream->last_pipe; 475 struct ia_css_binary *binary = NULL; 476 int err = 0; 477 478 assert(stream); 479 assert(pipe); 480 481 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 482 "sh_css_config_input_network() enter:\n"); 483 484 if (pipe->pipeline.stages) 485 binary = pipe->pipeline.stages->binary; 486 487 err = ia_css_isys_convert_stream_format_to_mipi_format( 488 stream->config.input_config.format, 489 stream->csi_rx_config.comp, 490 &fmt_type); 491 if (err) 492 return err; 493 sh_css_sp_program_input_circuit(fmt_type, 494 stream->config.channel_id, 495 stream->config.mode); 496 497 if ((binary && (binary->online || stream->config.continuous)) || 498 pipe->config.mode == IA_CSS_PIPE_MODE_COPY) { 499 err = ia_css_ifmtr_configure(&stream->config, 500 binary); 501 if (err) 502 return err; 503 } 504 505 if (stream->config.mode == IA_CSS_INPUT_MODE_TPG || 506 stream->config.mode == IA_CSS_INPUT_MODE_PRBS) { 507 unsigned int hblank_cycles = 100, 508 vblank_lines = 6, 509 width, 510 height, 511 vblank_cycles; 512 width = (stream->config.input_config.input_res.width) / (1 + 513 (stream->config.pixels_per_clock == 2)); 514 height = stream->config.input_config.input_res.height; 515 vblank_cycles = vblank_lines * (width + hblank_cycles); 516 sh_css_sp_configure_sync_gen(width, height, hblank_cycles, 517 vblank_cycles); 518 if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG) 519 ia_css_device_store_uint32(GP_ISEL_TPG_MODE, 0); 520 } 521 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 522 "sh_css_config_input_network() leave:\n"); 523 return 0; 524 } 525 526 static unsigned int csi2_protocol_calculate_max_subpixels_per_line( 527 enum atomisp_input_format format, 528 unsigned int pixels_per_line) 529 { 530 unsigned int rval; 531 532 switch (format) { 533 case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: 534 /* 535 * The frame format layout is shown below. 536 * 537 * Line 0: UYY0 UYY0 ... UYY0 538 * Line 1: VYY0 VYY0 ... VYY0 539 * Line 2: UYY0 UYY0 ... UYY0 540 * Line 3: VYY0 VYY0 ... VYY0 541 * ... 542 * Line (n-2): UYY0 UYY0 ... UYY0 543 * Line (n-1): VYY0 VYY0 ... VYY0 544 * 545 * In this frame format, the even-line is 546 * as wide as the odd-line. 547 * The 0 is introduced by the input system 548 * (mipi backend). 549 */ 550 rval = pixels_per_line * 2; 551 break; 552 case ATOMISP_INPUT_FORMAT_YUV420_8: 553 case ATOMISP_INPUT_FORMAT_YUV420_10: 554 case ATOMISP_INPUT_FORMAT_YUV420_16: 555 /* 556 * The frame format layout is shown below. 557 * 558 * Line 0: YYYY YYYY ... YYYY 559 * Line 1: UYVY UYVY ... UYVY UYVY 560 * Line 2: YYYY YYYY ... YYYY 561 * Line 3: UYVY UYVY ... UYVY UYVY 562 * ... 563 * Line (n-2): YYYY YYYY ... YYYY 564 * Line (n-1): UYVY UYVY ... UYVY UYVY 565 * 566 * In this frame format, the odd-line is twice 567 * wider than the even-line. 568 */ 569 rval = pixels_per_line * 2; 570 break; 571 case ATOMISP_INPUT_FORMAT_YUV422_8: 572 case ATOMISP_INPUT_FORMAT_YUV422_10: 573 case ATOMISP_INPUT_FORMAT_YUV422_16: 574 /* 575 * The frame format layout is shown below. 576 * 577 * Line 0: UYVY UYVY ... UYVY 578 * Line 1: UYVY UYVY ... UYVY 579 * Line 2: UYVY UYVY ... UYVY 580 * Line 3: UYVY UYVY ... UYVY 581 * ... 582 * Line (n-2): UYVY UYVY ... UYVY 583 * Line (n-1): UYVY UYVY ... UYVY 584 * 585 * In this frame format, the even-line is 586 * as wide as the odd-line. 587 */ 588 rval = pixels_per_line * 2; 589 break; 590 case ATOMISP_INPUT_FORMAT_RGB_444: 591 case ATOMISP_INPUT_FORMAT_RGB_555: 592 case ATOMISP_INPUT_FORMAT_RGB_565: 593 case ATOMISP_INPUT_FORMAT_RGB_666: 594 case ATOMISP_INPUT_FORMAT_RGB_888: 595 /* 596 * The frame format layout is shown below. 597 * 598 * Line 0: ABGR ABGR ... ABGR 599 * Line 1: ABGR ABGR ... ABGR 600 * Line 2: ABGR ABGR ... ABGR 601 * Line 3: ABGR ABGR ... ABGR 602 * ... 603 * Line (n-2): ABGR ABGR ... ABGR 604 * Line (n-1): ABGR ABGR ... ABGR 605 * 606 * In this frame format, the even-line is 607 * as wide as the odd-line. 608 */ 609 rval = pixels_per_line * 4; 610 break; 611 case ATOMISP_INPUT_FORMAT_RAW_6: 612 case ATOMISP_INPUT_FORMAT_RAW_7: 613 case ATOMISP_INPUT_FORMAT_RAW_8: 614 case ATOMISP_INPUT_FORMAT_RAW_10: 615 case ATOMISP_INPUT_FORMAT_RAW_12: 616 case ATOMISP_INPUT_FORMAT_RAW_14: 617 case ATOMISP_INPUT_FORMAT_RAW_16: 618 case ATOMISP_INPUT_FORMAT_BINARY_8: 619 case ATOMISP_INPUT_FORMAT_USER_DEF1: 620 case ATOMISP_INPUT_FORMAT_USER_DEF2: 621 case ATOMISP_INPUT_FORMAT_USER_DEF3: 622 case ATOMISP_INPUT_FORMAT_USER_DEF4: 623 case ATOMISP_INPUT_FORMAT_USER_DEF5: 624 case ATOMISP_INPUT_FORMAT_USER_DEF6: 625 case ATOMISP_INPUT_FORMAT_USER_DEF7: 626 case ATOMISP_INPUT_FORMAT_USER_DEF8: 627 /* 628 * The frame format layout is shown below. 629 * 630 * Line 0: Pixel ... Pixel 631 * Line 1: Pixel ... Pixel 632 * Line 2: Pixel ... Pixel 633 * Line 3: Pixel ... Pixel 634 * ... 635 * Line (n-2): Pixel ... Pixel 636 * Line (n-1): Pixel ... Pixel 637 * 638 * In this frame format, the even-line is 639 * as wide as the odd-line. 640 */ 641 rval = pixels_per_line; 642 break; 643 default: 644 rval = 0; 645 break; 646 } 647 648 return rval; 649 } 650 651 static bool sh_css_translate_stream_cfg_to_input_system_input_port_id( 652 struct ia_css_stream_config *stream_cfg, 653 ia_css_isys_descr_t *isys_stream_descr) 654 { 655 bool rc; 656 657 rc = true; 658 switch (stream_cfg->mode) { 659 case IA_CSS_INPUT_MODE_TPG: 660 661 if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0) 662 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID; 663 else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1) 664 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID; 665 else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2) 666 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID; 667 668 break; 669 case IA_CSS_INPUT_MODE_PRBS: 670 671 if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0) 672 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID; 673 else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1) 674 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID; 675 else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2) 676 isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID; 677 678 break; 679 case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: 680 681 if (stream_cfg->source.port.port == MIPI_PORT0_ID) 682 isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID; 683 else if (stream_cfg->source.port.port == MIPI_PORT1_ID) 684 isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID; 685 else if (stream_cfg->source.port.port == MIPI_PORT2_ID) 686 isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID; 687 688 break; 689 default: 690 rc = false; 691 break; 692 } 693 694 return rc; 695 } 696 697 static bool sh_css_translate_stream_cfg_to_input_system_input_port_type( 698 struct ia_css_stream_config *stream_cfg, 699 ia_css_isys_descr_t *isys_stream_descr) 700 { 701 bool rc; 702 703 rc = true; 704 switch (stream_cfg->mode) { 705 case IA_CSS_INPUT_MODE_TPG: 706 707 isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_TPG; 708 709 break; 710 case IA_CSS_INPUT_MODE_PRBS: 711 712 isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_PRBS; 713 714 break; 715 case IA_CSS_INPUT_MODE_SENSOR: 716 case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: 717 718 isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_SENSOR; 719 break; 720 721 default: 722 rc = false; 723 break; 724 } 725 726 return rc; 727 } 728 729 static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr( 730 struct ia_css_stream_config *stream_cfg, 731 ia_css_isys_descr_t *isys_stream_descr, 732 int isys_stream_idx) 733 { 734 bool rc; 735 736 rc = true; 737 switch (stream_cfg->mode) { 738 case IA_CSS_INPUT_MODE_TPG: 739 if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP) 740 isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP; 741 else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD) 742 isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO; 743 else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO) 744 isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO; 745 else 746 rc = false; 747 748 /* 749 * TODO 750 * - Make "color_cfg" as part of "ia_css_tpg_config". 751 */ 752 isys_stream_descr->tpg_port_attr.color_cfg.R1 = 51; 753 isys_stream_descr->tpg_port_attr.color_cfg.G1 = 102; 754 isys_stream_descr->tpg_port_attr.color_cfg.B1 = 255; 755 isys_stream_descr->tpg_port_attr.color_cfg.R2 = 0; 756 isys_stream_descr->tpg_port_attr.color_cfg.G2 = 100; 757 isys_stream_descr->tpg_port_attr.color_cfg.B2 = 160; 758 759 isys_stream_descr->tpg_port_attr.mask_cfg.h_mask = 760 stream_cfg->source.tpg.x_mask; 761 isys_stream_descr->tpg_port_attr.mask_cfg.v_mask = 762 stream_cfg->source.tpg.y_mask; 763 isys_stream_descr->tpg_port_attr.mask_cfg.hv_mask = 764 stream_cfg->source.tpg.xy_mask; 765 766 isys_stream_descr->tpg_port_attr.delta_cfg.h_delta = 767 stream_cfg->source.tpg.x_delta; 768 isys_stream_descr->tpg_port_attr.delta_cfg.v_delta = 769 stream_cfg->source.tpg.y_delta; 770 771 /* 772 * TODO 773 * - Make "sync_gen_cfg" as part of "ia_css_tpg_config". 774 */ 775 isys_stream_descr->tpg_port_attr.sync_gen_cfg.hblank_cycles = 100; 776 isys_stream_descr->tpg_port_attr.sync_gen_cfg.vblank_cycles = 100; 777 isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_clock = 778 stream_cfg->pixels_per_clock; 779 isys_stream_descr->tpg_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0); 780 isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_line = 781 stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width; 782 isys_stream_descr->tpg_port_attr.sync_gen_cfg.lines_per_frame = 783 stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height; 784 785 break; 786 case IA_CSS_INPUT_MODE_PRBS: 787 788 isys_stream_descr->prbs_port_attr.seed0 = stream_cfg->source.prbs.seed; 789 isys_stream_descr->prbs_port_attr.seed1 = stream_cfg->source.prbs.seed1; 790 791 /* 792 * TODO 793 * - Make "sync_gen_cfg" as part of "ia_css_prbs_config". 794 */ 795 isys_stream_descr->prbs_port_attr.sync_gen_cfg.hblank_cycles = 100; 796 isys_stream_descr->prbs_port_attr.sync_gen_cfg.vblank_cycles = 100; 797 isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_clock = 798 stream_cfg->pixels_per_clock; 799 isys_stream_descr->prbs_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0); 800 isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_line = 801 stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width; 802 isys_stream_descr->prbs_port_attr.sync_gen_cfg.lines_per_frame = 803 stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height; 804 805 break; 806 case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: { 807 int err; 808 unsigned int fmt_type; 809 810 err = ia_css_isys_convert_stream_format_to_mipi_format( 811 stream_cfg->isys_config[isys_stream_idx].format, 812 MIPI_PREDICTOR_NONE, 813 &fmt_type); 814 if (err) 815 rc = false; 816 817 isys_stream_descr->csi_port_attr.active_lanes = 818 stream_cfg->source.port.num_lanes; 819 isys_stream_descr->csi_port_attr.fmt_type = fmt_type; 820 isys_stream_descr->csi_port_attr.ch_id = stream_cfg->channel_id; 821 822 if (IS_ISP2401) 823 isys_stream_descr->online = stream_cfg->online; 824 825 err |= ia_css_isys_convert_compressed_format( 826 &stream_cfg->source.port.compression, 827 isys_stream_descr); 828 if (err) 829 rc = false; 830 831 /* metadata */ 832 isys_stream_descr->metadata.enable = false; 833 if (stream_cfg->metadata_config.resolution.height > 0) { 834 err = ia_css_isys_convert_stream_format_to_mipi_format( 835 stream_cfg->metadata_config.data_type, 836 MIPI_PREDICTOR_NONE, 837 &fmt_type); 838 if (err) 839 rc = false; 840 isys_stream_descr->metadata.fmt_type = fmt_type; 841 isys_stream_descr->metadata.bits_per_pixel = 842 ia_css_util_input_format_bpp(stream_cfg->metadata_config.data_type, true); 843 isys_stream_descr->metadata.pixels_per_line = 844 stream_cfg->metadata_config.resolution.width; 845 isys_stream_descr->metadata.lines_per_frame = 846 stream_cfg->metadata_config.resolution.height; 847 848 /* 849 * For new input system, number of str2mmio requests must be even. 850 * So we round up number of metadata lines to be even. 851 */ 852 if (IS_ISP2401 && isys_stream_descr->metadata.lines_per_frame > 0) 853 isys_stream_descr->metadata.lines_per_frame += 854 (isys_stream_descr->metadata.lines_per_frame & 1); 855 856 isys_stream_descr->metadata.align_req_in_bytes = 857 ia_css_csi2_calculate_input_system_alignment( 858 stream_cfg->metadata_config.data_type); 859 isys_stream_descr->metadata.enable = true; 860 } 861 862 break; 863 } 864 default: 865 rc = false; 866 break; 867 } 868 869 return rc; 870 } 871 872 static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution( 873 struct ia_css_stream_config *stream_cfg, 874 ia_css_isys_descr_t *isys_stream_descr, 875 int isys_stream_idx) 876 { 877 unsigned int bits_per_subpixel; 878 unsigned int max_subpixels_per_line; 879 unsigned int lines_per_frame; 880 unsigned int align_req_in_bytes; 881 enum atomisp_input_format fmt_type; 882 883 fmt_type = stream_cfg->isys_config[isys_stream_idx].format; 884 if ((stream_cfg->mode == IA_CSS_INPUT_MODE_SENSOR || 885 stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) && 886 stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) { 887 if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel == 888 UNCOMPRESSED_BITS_PER_PIXEL_10) 889 fmt_type = ATOMISP_INPUT_FORMAT_RAW_10; 890 else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel == 891 UNCOMPRESSED_BITS_PER_PIXEL_12) 892 fmt_type = ATOMISP_INPUT_FORMAT_RAW_12; 893 else 894 return false; 895 } 896 897 bits_per_subpixel = 898 sh_css_stream_format_2_bits_per_subpixel(fmt_type); 899 if (bits_per_subpixel == 0) 900 return false; 901 902 max_subpixels_per_line = 903 csi2_protocol_calculate_max_subpixels_per_line(fmt_type, 904 stream_cfg->isys_config[isys_stream_idx].input_res.width); 905 if (max_subpixels_per_line == 0) 906 return false; 907 908 lines_per_frame = stream_cfg->isys_config[isys_stream_idx].input_res.height; 909 if (lines_per_frame == 0) 910 return false; 911 912 align_req_in_bytes = ia_css_csi2_calculate_input_system_alignment(fmt_type); 913 914 /* HW needs subpixel info for their settings */ 915 isys_stream_descr->input_port_resolution.bits_per_pixel = bits_per_subpixel; 916 isys_stream_descr->input_port_resolution.pixels_per_line = 917 max_subpixels_per_line; 918 isys_stream_descr->input_port_resolution.lines_per_frame = lines_per_frame; 919 isys_stream_descr->input_port_resolution.align_req_in_bytes = 920 align_req_in_bytes; 921 922 return true; 923 } 924 925 static bool sh_css_translate_stream_cfg_to_isys_stream_descr( 926 struct ia_css_stream_config *stream_cfg, 927 bool early_polling, 928 ia_css_isys_descr_t *isys_stream_descr, 929 int isys_stream_idx) 930 { 931 bool rc; 932 933 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 934 "sh_css_translate_stream_cfg_to_isys_stream_descr() enter:\n"); 935 rc = sh_css_translate_stream_cfg_to_input_system_input_port_id(stream_cfg, 936 isys_stream_descr); 937 rc &= sh_css_translate_stream_cfg_to_input_system_input_port_type(stream_cfg, 938 isys_stream_descr); 939 rc &= sh_css_translate_stream_cfg_to_input_system_input_port_attr(stream_cfg, 940 isys_stream_descr, isys_stream_idx); 941 rc &= sh_css_translate_stream_cfg_to_input_system_input_port_resolution( 942 stream_cfg, isys_stream_descr, isys_stream_idx); 943 944 isys_stream_descr->raw_packed = stream_cfg->pack_raw_pixels; 945 isys_stream_descr->linked_isys_stream_id = (int8_t) 946 stream_cfg->isys_config[isys_stream_idx].linked_isys_stream_id; 947 948 if (IS_ISP2401) 949 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 950 "sh_css_translate_stream_cfg_to_isys_stream_descr() leave:\n"); 951 952 return rc; 953 } 954 955 static bool sh_css_translate_binary_info_to_input_system_output_port_attr( 956 struct ia_css_binary *binary, 957 ia_css_isys_descr_t *isys_stream_descr) 958 { 959 if (!binary) 960 return false; 961 962 isys_stream_descr->output_port_attr.left_padding = binary->left_padding; 963 isys_stream_descr->output_port_attr.max_isp_input_width = 964 binary->info->sp.input.max_width; 965 966 return true; 967 } 968 969 static int 970 sh_css_config_input_network_2401(struct ia_css_stream *stream) 971 { 972 bool rc; 973 ia_css_isys_descr_t isys_stream_descr; 974 unsigned int sp_thread_id; 975 struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal; 976 struct ia_css_pipe *pipe = NULL; 977 struct ia_css_binary *binary = NULL; 978 int i; 979 u32 isys_stream_id; 980 bool early_polling = false; 981 982 assert(stream); 983 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 984 "sh_css_config_input_network() enter 0x%p:\n", stream); 985 986 if (stream->config.continuous) { 987 if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) 988 pipe = stream->last_pipe; 989 else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP) 990 pipe = stream->last_pipe; 991 else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) 992 pipe = stream->last_pipe->pipe_settings.preview.copy_pipe; 993 else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) 994 pipe = stream->last_pipe->pipe_settings.video.copy_pipe; 995 } else { 996 pipe = stream->last_pipe; 997 } 998 999 if (!pipe) 1000 return -EINVAL; 1001 1002 if (pipe->pipeline.stages) 1003 if (pipe->pipeline.stages->binary) 1004 binary = pipe->pipeline.stages->binary; 1005 1006 if (binary) { 1007 /* 1008 * this was being done in ifmtr in 2400. 1009 * online and cont bypass the init_in_frameinfo_memory_defaults 1010 * so need to do it here 1011 */ 1012 ia_css_get_crop_offsets(pipe, &binary->in_frame_info); 1013 } 1014 1015 /* get the SP thread id */ 1016 rc = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &sp_thread_id); 1017 if (!rc) 1018 return -EINVAL; 1019 /* get the target input terminal */ 1020 sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input; 1021 1022 for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { 1023 /* initialization */ 1024 memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t)); 1025 sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0; 1026 sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i].valid = 0; 1027 1028 if (!stream->config.isys_config[i].valid) 1029 continue; 1030 1031 /* translate the stream configuration to the Input System (2401) configuration */ 1032 rc = sh_css_translate_stream_cfg_to_isys_stream_descr( 1033 &stream->config, 1034 early_polling, 1035 &(isys_stream_descr), i); 1036 1037 if (stream->config.online) { 1038 rc &= sh_css_translate_binary_info_to_input_system_output_port_attr( 1039 binary, 1040 &(isys_stream_descr)); 1041 } 1042 1043 if (!rc) 1044 return -EINVAL; 1045 1046 isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, i); 1047 1048 /* create the virtual Input System (2401) */ 1049 rc = ia_css_isys_stream_create( 1050 &(isys_stream_descr), 1051 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i], 1052 isys_stream_id); 1053 if (!rc) 1054 return -EINVAL; 1055 1056 /* calculate the configuration of the virtual Input System (2401) */ 1057 rc = ia_css_isys_stream_calculate_cfg( 1058 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i], 1059 &(isys_stream_descr), 1060 &sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i]); 1061 if (!rc) { 1062 ia_css_isys_stream_destroy( 1063 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]); 1064 return -EINVAL; 1065 } 1066 } 1067 1068 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 1069 "sh_css_config_input_network() leave:\n"); 1070 1071 return 0; 1072 } 1073 1074 static inline struct ia_css_pipe *stream_get_last_pipe( 1075 struct ia_css_stream *stream) 1076 { 1077 struct ia_css_pipe *last_pipe = NULL; 1078 1079 if (stream) 1080 last_pipe = stream->last_pipe; 1081 1082 return last_pipe; 1083 } 1084 1085 static inline struct ia_css_pipe *stream_get_copy_pipe( 1086 struct ia_css_stream *stream) 1087 { 1088 struct ia_css_pipe *copy_pipe = NULL; 1089 struct ia_css_pipe *last_pipe = NULL; 1090 enum ia_css_pipe_id pipe_id; 1091 1092 last_pipe = stream_get_last_pipe(stream); 1093 1094 if ((stream) && 1095 (last_pipe) && 1096 (stream->config.continuous)) { 1097 pipe_id = last_pipe->mode; 1098 switch (pipe_id) { 1099 case IA_CSS_PIPE_ID_PREVIEW: 1100 copy_pipe = last_pipe->pipe_settings.preview.copy_pipe; 1101 break; 1102 case IA_CSS_PIPE_ID_VIDEO: 1103 copy_pipe = last_pipe->pipe_settings.video.copy_pipe; 1104 break; 1105 default: 1106 copy_pipe = NULL; 1107 break; 1108 } 1109 } 1110 1111 return copy_pipe; 1112 } 1113 1114 static inline struct ia_css_pipe *stream_get_target_pipe( 1115 struct ia_css_stream *stream) 1116 { 1117 struct ia_css_pipe *target_pipe; 1118 1119 /* get the pipe that consumes the stream */ 1120 if (stream->config.continuous) 1121 target_pipe = stream_get_copy_pipe(stream); 1122 else 1123 target_pipe = stream_get_last_pipe(stream); 1124 1125 return target_pipe; 1126 } 1127 1128 static int stream_csi_rx_helper( 1129 struct ia_css_stream *stream, 1130 int (*func)(enum mipi_port_id, uint32_t)) 1131 { 1132 int retval = -EINVAL; 1133 u32 sp_thread_id, stream_id; 1134 bool rc; 1135 struct ia_css_pipe *target_pipe = NULL; 1136 1137 if ((!stream) || (stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR)) 1138 goto exit; 1139 1140 target_pipe = stream_get_target_pipe(stream); 1141 1142 if (!target_pipe) 1143 goto exit; 1144 1145 rc = ia_css_pipeline_get_sp_thread_id( 1146 ia_css_pipe_get_pipe_num(target_pipe), 1147 &sp_thread_id); 1148 1149 if (!rc) 1150 goto exit; 1151 1152 /* (un)register all valid "virtual isys streams" within the ia_css_stream */ 1153 stream_id = 0; 1154 do { 1155 if (stream->config.isys_config[stream_id].valid) { 1156 u32 isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, stream_id); 1157 1158 retval = func(stream->config.source.port.port, isys_stream_id); 1159 } 1160 stream_id++; 1161 } while ((retval == 0) && 1162 (stream_id < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH)); 1163 1164 exit: 1165 return retval; 1166 } 1167 1168 static inline int stream_register_with_csi_rx( 1169 struct ia_css_stream *stream) 1170 { 1171 return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_register_stream); 1172 } 1173 1174 static inline int stream_unregister_with_csi_rx( 1175 struct ia_css_stream *stream) 1176 { 1177 return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_unregister_stream); 1178 } 1179 1180 1181 static void 1182 start_binary(struct ia_css_pipe *pipe, 1183 struct ia_css_binary *binary) 1184 { 1185 assert(pipe); 1186 /* Acceleration uses firmware, the binary thus can be NULL */ 1187 1188 if (binary) 1189 sh_css_metrics_start_binary(&binary->metrics); 1190 1191 if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) { 1192 ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, 1193 pipe->stream->config.mode); 1194 pipe->stream->reconfigure_css_rx = false; 1195 } 1196 } 1197 1198 /* start the copy function on the SP */ 1199 static int 1200 start_copy_on_sp(struct ia_css_pipe *pipe, 1201 struct ia_css_frame *out_frame) 1202 { 1203 (void)out_frame; 1204 1205 if ((!pipe) || (!pipe->stream)) 1206 return -EINVAL; 1207 1208 if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) 1209 ia_css_isys_rx_disable(); 1210 1211 if (pipe->stream->config.input_config.format != ATOMISP_INPUT_FORMAT_BINARY_8) 1212 return -EINVAL; 1213 sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2); 1214 1215 if (!IS_ISP2401 && pipe->stream->reconfigure_css_rx) { 1216 ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, 1217 pipe->stream->config.mode); 1218 pipe->stream->reconfigure_css_rx = false; 1219 } 1220 1221 return 0; 1222 } 1223 1224 void sh_css_binary_args_reset(struct sh_css_binary_args *args) 1225 { 1226 unsigned int i; 1227 1228 for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) 1229 args->tnr_frames[i] = NULL; 1230 for (i = 0; i < MAX_NUM_VIDEO_DELAY_FRAMES; i++) 1231 args->delay_frames[i] = NULL; 1232 args->in_frame = NULL; 1233 for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) 1234 args->out_frame[i] = NULL; 1235 args->out_vf_frame = NULL; 1236 args->copy_vf = false; 1237 args->copy_output = true; 1238 args->vf_downscale_log2 = 0; 1239 } 1240 1241 static void start_pipe( 1242 struct ia_css_pipe *me, 1243 enum sh_css_pipe_config_override copy_ovrd, 1244 enum ia_css_input_mode input_mode) 1245 { 1246 IA_CSS_ENTER_PRIVATE("me = %p, copy_ovrd = %d, input_mode = %d", 1247 me, copy_ovrd, input_mode); 1248 1249 assert(me); /* all callers are in this file and call with non null argument */ 1250 1251 sh_css_sp_init_pipeline(&me->pipeline, 1252 me->mode, 1253 (uint8_t)ia_css_pipe_get_pipe_num(me), 1254 me->config.default_capture_config.enable_xnr != 0, 1255 me->stream->config.pixels_per_clock == 2, 1256 me->stream->config.continuous, 1257 false, 1258 me->required_bds_factor, 1259 copy_ovrd, 1260 input_mode, 1261 &me->stream->config.metadata_config, 1262 &me->stream->info.metadata_info 1263 , (input_mode == IA_CSS_INPUT_MODE_MEMORY) ? 1264 (enum mipi_port_id)0 : 1265 me->stream->config.source.port.port); 1266 1267 if (me->config.mode != IA_CSS_PIPE_MODE_COPY) { 1268 struct ia_css_pipeline_stage *stage; 1269 1270 stage = me->pipeline.stages; 1271 if (stage) { 1272 me->pipeline.current_stage = stage; 1273 start_binary(me, stage->binary); 1274 } 1275 } 1276 IA_CSS_LEAVE_PRIVATE("void"); 1277 } 1278 1279 void 1280 sh_css_invalidate_shading_tables(struct ia_css_stream *stream) 1281 { 1282 int i; 1283 1284 assert(stream); 1285 1286 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 1287 "sh_css_invalidate_shading_tables() enter:\n"); 1288 1289 for (i = 0; i < stream->num_pipes; i++) { 1290 assert(stream->pipes[i]); 1291 sh_css_pipe_free_shading_table(stream->pipes[i]); 1292 } 1293 1294 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 1295 "sh_css_invalidate_shading_tables() leave: return_void\n"); 1296 } 1297 1298 static void 1299 enable_interrupts(enum ia_css_irq_type irq_type) 1300 { 1301 enum mipi_port_id port; 1302 bool enable_pulse = irq_type != IA_CSS_IRQ_TYPE_EDGE; 1303 1304 IA_CSS_ENTER_PRIVATE(""); 1305 /* Enable IRQ on the SP which signals that SP goes to idle 1306 * (aka ready state) */ 1307 cnd_sp_irq_enable(SP0_ID, true); 1308 /* Set the IRQ device 0 to either level or pulse */ 1309 irq_enable_pulse(IRQ0_ID, enable_pulse); 1310 1311 cnd_virq_enable_channel(virq_sp, true); 1312 1313 /* Enable SW interrupt 0, this is used to signal ISYS events */ 1314 cnd_virq_enable_channel( 1315 (enum virq_id)(IRQ_SW_CHANNEL0_ID + IRQ_SW_CHANNEL_OFFSET), 1316 true); 1317 /* Enable SW interrupt 1, this is used to signal PSYS events */ 1318 cnd_virq_enable_channel( 1319 (enum virq_id)(IRQ_SW_CHANNEL1_ID + IRQ_SW_CHANNEL_OFFSET), 1320 true); 1321 1322 if (!IS_ISP2401) { 1323 for (port = 0; port < N_MIPI_PORT_ID; port++) 1324 ia_css_isys_rx_enable_all_interrupts(port); 1325 } 1326 1327 IA_CSS_LEAVE_PRIVATE(""); 1328 } 1329 1330 static bool sh_css_setup_spctrl_config(const struct ia_css_fw_info *fw, 1331 const char *program, 1332 ia_css_spctrl_cfg *spctrl_cfg) 1333 { 1334 if ((!fw) || (!spctrl_cfg)) 1335 return false; 1336 spctrl_cfg->sp_entry = 0; 1337 spctrl_cfg->program_name = (char *)(program); 1338 1339 spctrl_cfg->ddr_data_offset = fw->blob.data_source; 1340 spctrl_cfg->dmem_data_addr = fw->blob.data_target; 1341 spctrl_cfg->dmem_bss_addr = fw->blob.bss_target; 1342 spctrl_cfg->data_size = fw->blob.data_size; 1343 spctrl_cfg->bss_size = fw->blob.bss_size; 1344 1345 spctrl_cfg->spctrl_config_dmem_addr = fw->info.sp.init_dmem_data; 1346 spctrl_cfg->spctrl_state_dmem_addr = fw->info.sp.sw_state; 1347 1348 spctrl_cfg->code_size = fw->blob.size; 1349 spctrl_cfg->code = fw->blob.code; 1350 spctrl_cfg->sp_entry = fw->info.sp.sp_entry; /* entry function ptr on SP */ 1351 1352 return true; 1353 } 1354 1355 void 1356 ia_css_unload_firmware(void) 1357 { 1358 if (sh_css_num_binaries) { 1359 /* we have already loaded before so get rid of the old stuff */ 1360 ia_css_binary_uninit(); 1361 sh_css_unload_firmware(); 1362 } 1363 fw_explicitly_loaded = false; 1364 } 1365 1366 static void 1367 ia_css_reset_defaults(struct sh_css *css) 1368 { 1369 struct sh_css default_css; 1370 1371 /* Reset everything to zero */ 1372 memset(&default_css, 0, sizeof(default_css)); 1373 1374 /* Initialize the non zero values */ 1375 default_css.check_system_idle = true; 1376 default_css.num_cont_raw_frames = NUM_CONTINUOUS_FRAMES; 1377 1378 /* 1379 * All should be 0: but memset does it already. 1380 * default_css.num_mipi_frames[N_CSI_PORTS] = 0; 1381 */ 1382 1383 default_css.irq_type = IA_CSS_IRQ_TYPE_EDGE; 1384 1385 /* Set the defaults to the output */ 1386 *css = default_css; 1387 } 1388 1389 int 1390 ia_css_load_firmware(struct device *dev, const struct ia_css_env *env, 1391 const struct ia_css_fw *fw) 1392 { 1393 int err; 1394 1395 if (!env) 1396 return -EINVAL; 1397 if (!fw) 1398 return -EINVAL; 1399 1400 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n"); 1401 1402 /* make sure we initialize my_css */ 1403 if (my_css.flush != env->cpu_mem_env.flush) { 1404 ia_css_reset_defaults(&my_css); 1405 my_css.flush = env->cpu_mem_env.flush; 1406 } 1407 1408 ia_css_unload_firmware(); /* in case we are called twice */ 1409 err = sh_css_load_firmware(dev, fw->data, fw->bytes); 1410 if (!err) { 1411 err = ia_css_binary_init_infos(); 1412 if (!err) 1413 fw_explicitly_loaded = true; 1414 } 1415 1416 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() leave\n"); 1417 return err; 1418 } 1419 1420 int 1421 ia_css_init(struct device *dev, const struct ia_css_env *env, 1422 const struct ia_css_fw *fw, 1423 u32 mmu_l1_base, 1424 enum ia_css_irq_type irq_type) 1425 { 1426 int err; 1427 ia_css_spctrl_cfg spctrl_cfg; 1428 1429 void (*flush_func)(struct ia_css_acc_fw *fw); 1430 hrt_data select, enable; 1431 1432 /* 1433 * The C99 standard does not specify the exact object representation of structs; 1434 * the representation is compiler dependent. 1435 * 1436 * The structs that are communicated between host and SP/ISP should have the 1437 * exact same object representation. The compiler that is used to compile the 1438 * firmware is hivecc. 1439 * 1440 * To check if a different compiler, used to compile a host application, uses 1441 * another object representation, macros are defined specifying the size of 1442 * the structs as expected by the firmware. 1443 * 1444 * A host application shall verify that a sizeof( ) of the struct is equal to 1445 * the SIZE_OF_XXX macro of the corresponding struct. If they are not 1446 * equal, functionality will break. 1447 */ 1448 1449 /* Check struct sh_css_ddr_address_map */ 1450 COMPILATION_ERROR_IF(sizeof(struct sh_css_ddr_address_map) != SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT); 1451 /* Check struct host_sp_queues */ 1452 COMPILATION_ERROR_IF(sizeof(struct host_sp_queues) != SIZE_OF_HOST_SP_QUEUES_STRUCT); 1453 COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_desc_s) != SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT); 1454 COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_elem_s) != SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT); 1455 1456 /* Check struct host_sp_communication */ 1457 COMPILATION_ERROR_IF(sizeof(struct host_sp_communication) != SIZE_OF_HOST_SP_COMMUNICATION_STRUCT); 1458 COMPILATION_ERROR_IF(sizeof(struct sh_css_event_irq_mask) != SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT); 1459 1460 /* Check struct sh_css_hmm_buffer */ 1461 COMPILATION_ERROR_IF(sizeof(struct sh_css_hmm_buffer) != SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT); 1462 COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_3a_statistics) != SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT); 1463 COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_dvs_statistics) != SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT); 1464 COMPILATION_ERROR_IF(sizeof(struct ia_css_metadata) != SIZE_OF_IA_CSS_METADATA_STRUCT); 1465 1466 /* Check struct ia_css_init_dmem_cfg */ 1467 COMPILATION_ERROR_IF(sizeof(struct ia_css_sp_init_dmem_cfg) != SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT); 1468 1469 if (!fw && !fw_explicitly_loaded) 1470 return -EINVAL; 1471 if (!env) 1472 return -EINVAL; 1473 1474 sh_css_printf = env->print_env.debug_print; 1475 1476 IA_CSS_ENTER("void"); 1477 1478 flush_func = env->cpu_mem_env.flush; 1479 1480 pipe_global_init(); 1481 ia_css_pipeline_init(); 1482 ia_css_queue_map_init(); 1483 1484 ia_css_device_access_init(&env->hw_access_env); 1485 1486 select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select) 1487 & (~GPIO_FLASH_PIN_MASK); 1488 enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e) 1489 | GPIO_FLASH_PIN_MASK; 1490 sh_css_mmu_set_page_table_base_index(mmu_l1_base); 1491 1492 my_css_save.mmu_base = mmu_l1_base; 1493 1494 ia_css_reset_defaults(&my_css); 1495 1496 my_css_save.driver_env = *env; 1497 my_css.flush = flush_func; 1498 1499 err = ia_css_rmgr_init(); 1500 if (err) { 1501 IA_CSS_LEAVE_ERR(err); 1502 return err; 1503 } 1504 1505 IA_CSS_LOG("init: %d", my_css_save_initialized); 1506 1507 if (!my_css_save_initialized) { 1508 my_css_save_initialized = true; 1509 my_css_save.mode = sh_css_mode_working; 1510 memset(my_css_save.stream_seeds, 0, 1511 sizeof(struct sh_css_stream_seed) * MAX_ACTIVE_STREAMS); 1512 IA_CSS_LOG("init: %d mode=%d", my_css_save_initialized, my_css_save.mode); 1513 } 1514 1515 mipi_init(); 1516 1517 /* 1518 * In case this has been programmed already, update internal 1519 * data structure ... 1520 * DEPRECATED 1521 */ 1522 if (!IS_ISP2401) 1523 my_css.page_table_base_index = mmu_get_page_table_base_index(MMU0_ID); 1524 1525 my_css.irq_type = irq_type; 1526 1527 my_css_save.irq_type = irq_type; 1528 1529 enable_interrupts(my_css.irq_type); 1530 1531 /* configure GPIO to output mode */ 1532 gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_select, select); 1533 gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_e, enable); 1534 gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0); 1535 1536 err = ia_css_refcount_init(REFCOUNT_SIZE); 1537 if (err) { 1538 IA_CSS_LEAVE_ERR(err); 1539 return err; 1540 } 1541 err = sh_css_params_init(); 1542 if (err) { 1543 IA_CSS_LEAVE_ERR(err); 1544 return err; 1545 } 1546 if (fw) { 1547 ia_css_unload_firmware(); /* in case we already had firmware loaded */ 1548 err = sh_css_load_firmware(dev, fw->data, fw->bytes); 1549 if (err) { 1550 IA_CSS_LEAVE_ERR(err); 1551 return err; 1552 } 1553 err = ia_css_binary_init_infos(); 1554 if (err) { 1555 IA_CSS_LEAVE_ERR(err); 1556 return err; 1557 } 1558 fw_explicitly_loaded = false; 1559 1560 my_css_save.loaded_fw = (struct ia_css_fw *)fw; 1561 } 1562 if (!sh_css_setup_spctrl_config(&sh_css_sp_fw, SP_PROG_NAME, &spctrl_cfg)) 1563 return -EINVAL; 1564 1565 err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg); 1566 if (err) { 1567 IA_CSS_LEAVE_ERR(err); 1568 return err; 1569 } 1570 1571 if (!sh_css_hrt_system_is_idle()) { 1572 IA_CSS_LEAVE_ERR(-EBUSY); 1573 return -EBUSY; 1574 } 1575 /* 1576 * can be called here, queuing works, but: 1577 * - when sp is started later, it will wipe queued items 1578 * so for now we leave it for later and make sure 1579 * updates are not called to frequently. 1580 * sh_css_init_buffer_queues(); 1581 */ 1582 1583 if (IS_ISP2401) 1584 gp_device_reg_store(GP_DEVICE0_ID, _REG_GP_SWITCH_ISYS2401_ADDR, 1); 1585 1586 if (!IS_ISP2401) 1587 dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN, 1588 ISP2400_DMA_MAX_BURST_LENGTH); 1589 else 1590 dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN, 1591 ISP2401_DMA_MAX_BURST_LENGTH); 1592 1593 if (ia_css_isys_init() != INPUT_SYSTEM_ERR_NO_ERROR) 1594 err = -EINVAL; 1595 1596 sh_css_params_map_and_store_default_gdc_lut(); 1597 1598 IA_CSS_LEAVE_ERR(err); 1599 return err; 1600 } 1601 1602 int 1603 ia_css_enable_isys_event_queue(bool enable) 1604 { 1605 if (sh_css_sp_is_running()) 1606 return -EBUSY; 1607 sh_css_sp_enable_isys_event_queue(enable); 1608 return 0; 1609 } 1610 1611 /* 1612 * Mapping sp threads. Currently, this is done when a stream is created and 1613 * pipelines are ready to be converted to sp pipelines. Be careful if you are 1614 * doing it from stream_create since we could run out of sp threads due to 1615 * allocation on inactive pipelines. 1616 */ 1617 static int 1618 map_sp_threads(struct ia_css_stream *stream, bool map) 1619 { 1620 struct ia_css_pipe *main_pipe = NULL; 1621 struct ia_css_pipe *copy_pipe = NULL; 1622 struct ia_css_pipe *capture_pipe = NULL; 1623 int err = 0; 1624 enum ia_css_pipe_id pipe_id; 1625 1626 IA_CSS_ENTER_PRIVATE("stream = %p, map = %s", 1627 stream, map ? "true" : "false"); 1628 1629 if (!stream) { 1630 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 1631 return -EINVAL; 1632 } 1633 1634 main_pipe = stream->last_pipe; 1635 pipe_id = main_pipe->mode; 1636 1637 ia_css_pipeline_map(main_pipe->pipe_num, map); 1638 1639 switch (pipe_id) { 1640 case IA_CSS_PIPE_ID_PREVIEW: 1641 copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; 1642 capture_pipe = main_pipe->pipe_settings.preview.capture_pipe; 1643 break; 1644 1645 case IA_CSS_PIPE_ID_VIDEO: 1646 copy_pipe = main_pipe->pipe_settings.video.copy_pipe; 1647 capture_pipe = main_pipe->pipe_settings.video.capture_pipe; 1648 break; 1649 1650 case IA_CSS_PIPE_ID_CAPTURE: 1651 default: 1652 break; 1653 } 1654 1655 if (capture_pipe) 1656 ia_css_pipeline_map(capture_pipe->pipe_num, map); 1657 1658 /* Firmware expects copy pipe to be the last pipe mapped. (if needed) */ 1659 if (copy_pipe) 1660 ia_css_pipeline_map(copy_pipe->pipe_num, map); 1661 1662 /* DH regular multi pipe - not continuous mode: map the next pipes too */ 1663 if (!stream->config.continuous) { 1664 int i; 1665 1666 for (i = 1; i < stream->num_pipes; i++) 1667 ia_css_pipeline_map(stream->pipes[i]->pipe_num, map); 1668 } 1669 1670 IA_CSS_LEAVE_ERR_PRIVATE(err); 1671 return err; 1672 } 1673 1674 /* 1675 * creates a host pipeline skeleton for all pipes in a stream. Called during 1676 * stream_create. 1677 */ 1678 static int 1679 create_host_pipeline_structure(struct ia_css_stream *stream) 1680 { 1681 struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL; 1682 enum ia_css_pipe_id pipe_id; 1683 struct ia_css_pipe *main_pipe = NULL; 1684 int err = 0; 1685 unsigned int copy_pipe_delay = 0, 1686 capture_pipe_delay = 0; 1687 1688 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 1689 1690 if (!stream) { 1691 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 1692 return -EINVAL; 1693 } 1694 1695 main_pipe = stream->last_pipe; 1696 if (!main_pipe) { 1697 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 1698 return -EINVAL; 1699 } 1700 1701 pipe_id = main_pipe->mode; 1702 1703 switch (pipe_id) { 1704 case IA_CSS_PIPE_ID_PREVIEW: 1705 copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; 1706 copy_pipe_delay = main_pipe->dvs_frame_delay; 1707 capture_pipe = main_pipe->pipe_settings.preview.capture_pipe; 1708 capture_pipe_delay = IA_CSS_FRAME_DELAY_0; 1709 err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode, 1710 main_pipe->pipe_num, main_pipe->dvs_frame_delay); 1711 break; 1712 1713 case IA_CSS_PIPE_ID_VIDEO: 1714 copy_pipe = main_pipe->pipe_settings.video.copy_pipe; 1715 copy_pipe_delay = main_pipe->dvs_frame_delay; 1716 capture_pipe = main_pipe->pipe_settings.video.capture_pipe; 1717 capture_pipe_delay = IA_CSS_FRAME_DELAY_0; 1718 err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode, 1719 main_pipe->pipe_num, main_pipe->dvs_frame_delay); 1720 break; 1721 1722 case IA_CSS_PIPE_ID_CAPTURE: 1723 capture_pipe = main_pipe; 1724 capture_pipe_delay = main_pipe->dvs_frame_delay; 1725 break; 1726 1727 case IA_CSS_PIPE_ID_YUVPP: 1728 err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode, 1729 main_pipe->pipe_num, main_pipe->dvs_frame_delay); 1730 break; 1731 1732 default: 1733 err = -EINVAL; 1734 } 1735 1736 if (!(err) && copy_pipe) 1737 err = ia_css_pipeline_create(©_pipe->pipeline, 1738 copy_pipe->mode, 1739 copy_pipe->pipe_num, 1740 copy_pipe_delay); 1741 1742 if (!(err) && capture_pipe) 1743 err = ia_css_pipeline_create(&capture_pipe->pipeline, 1744 capture_pipe->mode, 1745 capture_pipe->pipe_num, 1746 capture_pipe_delay); 1747 1748 /* DH regular multi pipe - not continuous mode: create the next pipelines too */ 1749 if (!stream->config.continuous) { 1750 int i; 1751 1752 for (i = 1; i < stream->num_pipes && 0 == err; i++) { 1753 main_pipe = stream->pipes[i]; 1754 err = ia_css_pipeline_create(&main_pipe->pipeline, 1755 main_pipe->mode, 1756 main_pipe->pipe_num, 1757 main_pipe->dvs_frame_delay); 1758 } 1759 } 1760 1761 IA_CSS_LEAVE_ERR_PRIVATE(err); 1762 return err; 1763 } 1764 1765 /* 1766 * creates a host pipeline for all pipes in a stream. Called during 1767 * stream_start. 1768 */ 1769 static int 1770 create_host_pipeline(struct ia_css_stream *stream) 1771 { 1772 struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL; 1773 enum ia_css_pipe_id pipe_id; 1774 struct ia_css_pipe *main_pipe = NULL; 1775 int err = 0; 1776 unsigned int max_input_width = 0; 1777 1778 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 1779 if (!stream) { 1780 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 1781 return -EINVAL; 1782 } 1783 1784 main_pipe = stream->last_pipe; 1785 pipe_id = main_pipe->mode; 1786 1787 /* 1788 * No continuous frame allocation for capture pipe. It uses the 1789 * "main" pipe's frames. 1790 */ 1791 if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) || 1792 (pipe_id == IA_CSS_PIPE_ID_VIDEO)) { 1793 /* 1794 * About 1795 * pipe_id == IA_CSS_PIPE_ID_PREVIEW && 1796 * stream->config.mode != IA_CSS_INPUT_MODE_MEMORY: 1797 * 1798 * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is 1799 * too strong. E.g. in SkyCam (with memory based input frames) 1800 * there is no continuous mode and thus no need for allocated 1801 * continuous frames. 1802 * This is not only for SkyCam but for all preview cases that 1803 * use DDR based input frames. For this reason the 1804 * stream->config.mode != IA_CSS_INPUT_MODE_MEMORY has beed 1805 * added. 1806 */ 1807 if (stream->config.continuous || 1808 (pipe_id == IA_CSS_PIPE_ID_PREVIEW && 1809 stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)) { 1810 err = alloc_continuous_frames(main_pipe, true); 1811 if (err) 1812 goto ERR; 1813 } 1814 } 1815 1816 /* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */ 1817 if (!IS_ISP2401 || main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY) { 1818 err = allocate_mipi_frames(main_pipe, &stream->info); 1819 if (err) 1820 goto ERR; 1821 } 1822 1823 switch (pipe_id) { 1824 case IA_CSS_PIPE_ID_PREVIEW: 1825 copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; 1826 capture_pipe = main_pipe->pipe_settings.preview.capture_pipe; 1827 max_input_width = 1828 main_pipe->pipe_settings.preview.preview_binary.info->sp.input.max_width; 1829 1830 err = create_host_preview_pipeline(main_pipe); 1831 if (err) 1832 goto ERR; 1833 1834 break; 1835 1836 case IA_CSS_PIPE_ID_VIDEO: 1837 copy_pipe = main_pipe->pipe_settings.video.copy_pipe; 1838 capture_pipe = main_pipe->pipe_settings.video.capture_pipe; 1839 max_input_width = 1840 main_pipe->pipe_settings.video.video_binary.info->sp.input.max_width; 1841 1842 err = create_host_video_pipeline(main_pipe); 1843 if (err) 1844 goto ERR; 1845 1846 break; 1847 1848 case IA_CSS_PIPE_ID_CAPTURE: 1849 capture_pipe = main_pipe; 1850 1851 break; 1852 1853 case IA_CSS_PIPE_ID_YUVPP: 1854 err = create_host_yuvpp_pipeline(main_pipe); 1855 if (err) 1856 goto ERR; 1857 1858 break; 1859 1860 default: 1861 err = -EINVAL; 1862 } 1863 if (err) 1864 goto ERR; 1865 1866 if (copy_pipe) { 1867 err = create_host_copy_pipeline(copy_pipe, max_input_width, 1868 main_pipe->continuous_frames[0]); 1869 if (err) 1870 goto ERR; 1871 } 1872 1873 if (capture_pipe) { 1874 err = create_host_capture_pipeline(capture_pipe); 1875 if (err) 1876 goto ERR; 1877 } 1878 1879 /* DH regular multi pipe - not continuous mode: create the next pipelines too */ 1880 if (!stream->config.continuous) { 1881 int i; 1882 1883 for (i = 1; i < stream->num_pipes && 0 == err; i++) { 1884 switch (stream->pipes[i]->mode) { 1885 case IA_CSS_PIPE_ID_PREVIEW: 1886 err = create_host_preview_pipeline(stream->pipes[i]); 1887 break; 1888 case IA_CSS_PIPE_ID_VIDEO: 1889 err = create_host_video_pipeline(stream->pipes[i]); 1890 break; 1891 case IA_CSS_PIPE_ID_CAPTURE: 1892 err = create_host_capture_pipeline(stream->pipes[i]); 1893 break; 1894 case IA_CSS_PIPE_ID_YUVPP: 1895 err = create_host_yuvpp_pipeline(stream->pipes[i]); 1896 break; 1897 default: 1898 err = -EINVAL; 1899 } 1900 if (err) 1901 goto ERR; 1902 } 1903 } 1904 1905 ERR: 1906 IA_CSS_LEAVE_ERR_PRIVATE(err); 1907 return err; 1908 } 1909 1910 static const struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE; 1911 static const struct ia_css_preview_settings preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS; 1912 static const struct ia_css_capture_settings capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS; 1913 static const struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS; 1914 static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS; 1915 1916 static int 1917 init_pipe_defaults(enum ia_css_pipe_mode mode, 1918 struct ia_css_pipe *pipe, 1919 bool copy_pipe) 1920 { 1921 if (!pipe) { 1922 IA_CSS_ERROR("NULL pipe parameter"); 1923 return -EINVAL; 1924 } 1925 1926 /* Initialize pipe to pre-defined defaults */ 1927 memcpy(pipe, &default_pipe, sizeof(default_pipe)); 1928 1929 /* TODO: JB should not be needed, but temporary backward reference */ 1930 switch (mode) { 1931 case IA_CSS_PIPE_MODE_PREVIEW: 1932 pipe->mode = IA_CSS_PIPE_ID_PREVIEW; 1933 memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview)); 1934 break; 1935 case IA_CSS_PIPE_MODE_CAPTURE: 1936 if (copy_pipe) 1937 pipe->mode = IA_CSS_PIPE_ID_COPY; 1938 else 1939 pipe->mode = IA_CSS_PIPE_ID_CAPTURE; 1940 1941 memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture)); 1942 break; 1943 case IA_CSS_PIPE_MODE_VIDEO: 1944 pipe->mode = IA_CSS_PIPE_ID_VIDEO; 1945 memcpy(&pipe->pipe_settings.video, &video, sizeof(video)); 1946 break; 1947 case IA_CSS_PIPE_MODE_COPY: 1948 pipe->mode = IA_CSS_PIPE_ID_CAPTURE; 1949 break; 1950 case IA_CSS_PIPE_MODE_YUVPP: 1951 pipe->mode = IA_CSS_PIPE_ID_YUVPP; 1952 memcpy(&pipe->pipe_settings.yuvpp, &yuvpp, sizeof(yuvpp)); 1953 break; 1954 default: 1955 return -EINVAL; 1956 } 1957 1958 return 0; 1959 } 1960 1961 static void 1962 pipe_global_init(void) 1963 { 1964 u8 i; 1965 1966 my_css.pipe_counter = 0; 1967 for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) 1968 my_css.all_pipes[i] = NULL; 1969 } 1970 1971 static int 1972 pipe_generate_pipe_num(const struct ia_css_pipe *pipe, 1973 unsigned int *pipe_number) 1974 { 1975 const u8 INVALID_PIPE_NUM = (uint8_t)~(0); 1976 u8 pipe_num = INVALID_PIPE_NUM; 1977 u8 i; 1978 1979 if (!pipe) { 1980 IA_CSS_ERROR("NULL pipe parameter"); 1981 return -EINVAL; 1982 } 1983 1984 /* Assign a new pipe_num .... search for empty place */ 1985 for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) { 1986 if (!my_css.all_pipes[i]) { 1987 /* position is reserved */ 1988 my_css.all_pipes[i] = (struct ia_css_pipe *)pipe; 1989 pipe_num = i; 1990 break; 1991 } 1992 } 1993 if (pipe_num == INVALID_PIPE_NUM) { 1994 /* Max number of pipes already allocated */ 1995 IA_CSS_ERROR("Max number of pipes already created"); 1996 return -ENOSPC; 1997 } 1998 1999 my_css.pipe_counter++; 2000 2001 IA_CSS_LOG("pipe_num (%d)", pipe_num); 2002 2003 *pipe_number = pipe_num; 2004 return 0; 2005 } 2006 2007 static void 2008 pipe_release_pipe_num(unsigned int pipe_num) 2009 { 2010 my_css.all_pipes[pipe_num] = NULL; 2011 my_css.pipe_counter--; 2012 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2013 "pipe_release_pipe_num (%d)\n", pipe_num); 2014 } 2015 2016 static int 2017 create_pipe(enum ia_css_pipe_mode mode, 2018 struct ia_css_pipe **pipe, 2019 bool copy_pipe) 2020 { 2021 int err = 0; 2022 struct ia_css_pipe *me; 2023 2024 if (!pipe) { 2025 IA_CSS_ERROR("NULL pipe parameter"); 2026 return -EINVAL; 2027 } 2028 2029 me = kmalloc(sizeof(*me), GFP_KERNEL); 2030 if (!me) 2031 return -ENOMEM; 2032 2033 err = init_pipe_defaults(mode, me, copy_pipe); 2034 if (err) { 2035 kfree(me); 2036 return err; 2037 } 2038 2039 err = pipe_generate_pipe_num(me, &me->pipe_num); 2040 if (err) { 2041 kfree(me); 2042 return err; 2043 } 2044 2045 *pipe = me; 2046 return 0; 2047 } 2048 2049 struct ia_css_pipe * 2050 find_pipe_by_num(uint32_t pipe_num) 2051 { 2052 unsigned int i; 2053 2054 for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) { 2055 if (my_css.all_pipes[i] && 2056 ia_css_pipe_get_pipe_num(my_css.all_pipes[i]) == pipe_num) { 2057 return my_css.all_pipes[i]; 2058 } 2059 } 2060 return NULL; 2061 } 2062 2063 int 2064 ia_css_pipe_destroy(struct ia_css_pipe *pipe) 2065 { 2066 int err = 0; 2067 2068 IA_CSS_ENTER("pipe = %p", pipe); 2069 2070 if (!pipe) { 2071 IA_CSS_LEAVE_ERR(-EINVAL); 2072 return -EINVAL; 2073 } 2074 2075 if (pipe->stream) { 2076 IA_CSS_LOG("ia_css_stream_destroy not called!"); 2077 IA_CSS_LEAVE_ERR(-EINVAL); 2078 return -EINVAL; 2079 } 2080 2081 switch (pipe->config.mode) { 2082 case IA_CSS_PIPE_MODE_PREVIEW: 2083 /* 2084 * need to take into account that this function is also called 2085 * on the internal copy pipe 2086 */ 2087 if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) { 2088 ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES, 2089 pipe->continuous_frames); 2090 ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES, 2091 pipe->cont_md_buffers); 2092 if (pipe->pipe_settings.preview.copy_pipe) { 2093 err = ia_css_pipe_destroy(pipe->pipe_settings.preview.copy_pipe); 2094 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2095 "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n", 2096 err); 2097 } 2098 } 2099 break; 2100 case IA_CSS_PIPE_MODE_VIDEO: 2101 if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) { 2102 ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES, 2103 pipe->continuous_frames); 2104 ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES, 2105 pipe->cont_md_buffers); 2106 if (pipe->pipe_settings.video.copy_pipe) { 2107 err = ia_css_pipe_destroy(pipe->pipe_settings.video.copy_pipe); 2108 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2109 "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n", 2110 err); 2111 } 2112 } 2113 ia_css_frame_free_multiple(NUM_VIDEO_TNR_FRAMES, 2114 pipe->pipe_settings.video.tnr_frames); 2115 ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES, 2116 pipe->pipe_settings.video.delay_frames); 2117 break; 2118 case IA_CSS_PIPE_MODE_CAPTURE: 2119 ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES, 2120 pipe->pipe_settings.capture.delay_frames); 2121 break; 2122 case IA_CSS_PIPE_MODE_COPY: 2123 break; 2124 case IA_CSS_PIPE_MODE_YUVPP: 2125 break; 2126 } 2127 2128 if (pipe->scaler_pp_lut != mmgr_NULL) { 2129 hmm_free(pipe->scaler_pp_lut); 2130 pipe->scaler_pp_lut = mmgr_NULL; 2131 } 2132 2133 my_css.active_pipes[ia_css_pipe_get_pipe_num(pipe)] = NULL; 2134 sh_css_pipe_free_shading_table(pipe); 2135 2136 ia_css_pipeline_destroy(&pipe->pipeline); 2137 pipe_release_pipe_num(ia_css_pipe_get_pipe_num(pipe)); 2138 2139 kfree(pipe); 2140 IA_CSS_LEAVE("err = %d", err); 2141 return err; 2142 } 2143 2144 void 2145 ia_css_uninit(void) 2146 { 2147 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() enter: void\n"); 2148 2149 sh_css_params_free_default_gdc_lut(); 2150 2151 /* TODO: JB: implement decent check and handling of freeing mipi frames */ 2152 if (!mipi_is_free()) 2153 dev_warn(atomisp_dev, "mipi frames are not freed.\n"); 2154 2155 /* cleanup generic data */ 2156 sh_css_params_uninit(); 2157 ia_css_refcount_uninit(); 2158 2159 ia_css_rmgr_uninit(); 2160 2161 if (!IS_ISP2401) { 2162 /* needed for reprogramming the inputformatter after power cycle of css */ 2163 ifmtr_set_if_blocking_mode_reset = true; 2164 } 2165 2166 if (!fw_explicitly_loaded) 2167 ia_css_unload_firmware(); 2168 2169 ia_css_spctrl_unload_fw(SP0_ID); 2170 sh_css_sp_set_sp_running(false); 2171 /* check and free any remaining mipi frames */ 2172 free_mipi_frames(NULL); 2173 2174 sh_css_sp_reset_global_vars(); 2175 2176 ia_css_isys_uninit(); 2177 2178 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() leave: return_void\n"); 2179 } 2180 2181 int ia_css_irq_translate( 2182 unsigned int *irq_infos) 2183 { 2184 enum virq_id irq; 2185 enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_more_irqs; 2186 unsigned int infos = 0; 2187 2188 /* irq_infos can be NULL, but that would make the function useless */ 2189 /* assert(irq_infos != NULL); */ 2190 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2191 "ia_css_irq_translate() enter: irq_infos=%p\n", irq_infos); 2192 2193 while (status == hrt_isp_css_irq_status_more_irqs) { 2194 status = virq_get_channel_id(&irq); 2195 if (status == hrt_isp_css_irq_status_error) 2196 return -EINVAL; 2197 2198 2199 switch (irq) { 2200 case virq_sp: 2201 /* 2202 * When SP goes to idle, info is available in the 2203 * event queue. 2204 */ 2205 infos |= IA_CSS_IRQ_INFO_EVENTS_READY; 2206 break; 2207 case virq_isp: 2208 break; 2209 case virq_isys_sof: 2210 infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF; 2211 break; 2212 case virq_isys_eof: 2213 infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF; 2214 break; 2215 case virq_isys_csi: 2216 infos |= IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR; 2217 break; 2218 case virq_ifmt0_id: 2219 if (!IS_ISP2401) 2220 infos |= IA_CSS_IRQ_INFO_IF_ERROR; 2221 break; 2222 case virq_dma: 2223 infos |= IA_CSS_IRQ_INFO_DMA_ERROR; 2224 break; 2225 case virq_sw_pin_0: 2226 infos |= sh_css_get_sw_interrupt_value(0); 2227 break; 2228 case virq_sw_pin_1: 2229 infos |= sh_css_get_sw_interrupt_value(1); 2230 /* pqiao TODO: also assumption here */ 2231 break; 2232 default: 2233 break; 2234 } 2235 } 2236 2237 if (irq_infos) 2238 *irq_infos = infos; 2239 2240 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2241 "ia_css_irq_translate() leave: irq_infos=%u\n", 2242 infos); 2243 2244 return 0; 2245 } 2246 2247 int ia_css_irq_enable( 2248 enum ia_css_irq_info info, 2249 bool enable) 2250 { 2251 enum virq_id irq = N_virq_id; 2252 2253 IA_CSS_ENTER("info=%d, enable=%d", info, enable); 2254 2255 switch (info) { 2256 case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF: 2257 if (IS_ISP2401) 2258 /* Just ignore those unused IRQs without printing errors */ 2259 return 0; 2260 2261 irq = virq_isys_sof; 2262 break; 2263 case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF: 2264 if (IS_ISP2401) 2265 /* Just ignore those unused IRQs without printing errors */ 2266 return 0; 2267 2268 irq = virq_isys_eof; 2269 break; 2270 case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR: 2271 if (IS_ISP2401) 2272 /* Just ignore those unused IRQs without printing errors */ 2273 return 0; 2274 2275 irq = virq_isys_csi; 2276 break; 2277 case IA_CSS_IRQ_INFO_IF_ERROR: 2278 if (IS_ISP2401) 2279 /* Just ignore those unused IRQs without printing errors */ 2280 return 0; 2281 2282 irq = virq_ifmt0_id; 2283 break; 2284 case IA_CSS_IRQ_INFO_DMA_ERROR: 2285 irq = virq_dma; 2286 break; 2287 case IA_CSS_IRQ_INFO_SW_0: 2288 irq = virq_sw_pin_0; 2289 break; 2290 case IA_CSS_IRQ_INFO_SW_1: 2291 irq = virq_sw_pin_1; 2292 break; 2293 default: 2294 IA_CSS_LEAVE_ERR(-EINVAL); 2295 return -EINVAL; 2296 } 2297 2298 cnd_virq_enable_channel(irq, enable); 2299 2300 IA_CSS_LEAVE_ERR(0); 2301 return 0; 2302 } 2303 2304 2305 static unsigned int 2306 sh_css_get_sw_interrupt_value(unsigned int irq) 2307 { 2308 unsigned int irq_value; 2309 2310 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2311 "sh_css_get_sw_interrupt_value() enter: irq=%d\n", irq); 2312 irq_value = sh_css_sp_get_sw_interrupt_value(irq); 2313 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 2314 "sh_css_get_sw_interrupt_value() leave: irq_value=%d\n", irq_value); 2315 return irq_value; 2316 } 2317 2318 /* 2319 * configure and load the copy binary, the next binary is used to 2320 * determine whether the copy binary needs to do left padding. 2321 */ 2322 static int load_copy_binary( 2323 struct ia_css_pipe *pipe, 2324 struct ia_css_binary *copy_binary, 2325 struct ia_css_binary *next_binary) 2326 { 2327 struct ia_css_frame_info copy_out_info, copy_in_info, copy_vf_info; 2328 unsigned int left_padding; 2329 int err; 2330 struct ia_css_binary_descr copy_descr; 2331 2332 /* next_binary can be NULL */ 2333 assert(pipe); 2334 assert(copy_binary); 2335 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2336 "load_copy_binary() enter:\n"); 2337 2338 if (next_binary) { 2339 copy_out_info = next_binary->in_frame_info; 2340 left_padding = next_binary->left_padding; 2341 } else { 2342 copy_out_info = pipe->output_info[0]; 2343 copy_vf_info = pipe->vf_output_info[0]; 2344 ia_css_frame_info_set_format(©_vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE); 2345 left_padding = 0; 2346 } 2347 2348 ia_css_pipe_get_copy_binarydesc(pipe, ©_descr, 2349 ©_in_info, ©_out_info, 2350 (next_binary) ? NULL : NULL/*TODO: ©_vf_info*/); 2351 err = ia_css_binary_find(©_descr, copy_binary); 2352 if (err) 2353 return err; 2354 copy_binary->left_padding = left_padding; 2355 return 0; 2356 } 2357 2358 static int 2359 alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time) 2360 { 2361 int err = 0; 2362 struct ia_css_frame_info ref_info; 2363 enum ia_css_pipe_id pipe_id; 2364 bool continuous; 2365 unsigned int i, idx; 2366 unsigned int num_frames; 2367 2368 IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time); 2369 2370 if ((!pipe) || (!pipe->stream)) { 2371 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 2372 return -EINVAL; 2373 } 2374 2375 pipe_id = pipe->mode; 2376 continuous = pipe->stream->config.continuous; 2377 2378 if (continuous) { 2379 if (init_time) { 2380 num_frames = pipe->stream->config.init_num_cont_raw_buf; 2381 pipe->stream->continuous_pipe = pipe; 2382 } else { 2383 num_frames = pipe->stream->config.target_num_cont_raw_buf; 2384 } 2385 } else { 2386 num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES; 2387 } 2388 2389 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) { 2390 ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info; 2391 } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) { 2392 ref_info = pipe->pipe_settings.video.video_binary.in_frame_info; 2393 } else { 2394 /* should not happen */ 2395 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 2396 return -EINVAL; 2397 } 2398 2399 if (IS_ISP2401) { 2400 /* For CSI2+, the continuous frame will hold the full input frame */ 2401 ref_info.res.width = pipe->stream->config.input_config.input_res.width; 2402 ref_info.res.height = pipe->stream->config.input_config.input_res.height; 2403 2404 /* Ensure padded width is aligned for 2401 */ 2405 ref_info.padded_width = CEIL_MUL(ref_info.res.width, 2 * ISP_VEC_NELEMS); 2406 } 2407 2408 if (pipe->stream->config.pack_raw_pixels) { 2409 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2410 "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n"); 2411 ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED; 2412 } else 2413 { 2414 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2415 "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW\n"); 2416 ref_info.format = IA_CSS_FRAME_FORMAT_RAW; 2417 } 2418 2419 /* Write format back to binary */ 2420 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) { 2421 pipe->pipe_settings.preview.preview_binary.in_frame_info.format = 2422 ref_info.format; 2423 } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) { 2424 pipe->pipe_settings.video.video_binary.in_frame_info.format = ref_info.format; 2425 } else { 2426 /* should not happen */ 2427 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 2428 return -EINVAL; 2429 } 2430 2431 if (init_time) 2432 idx = 0; 2433 else 2434 idx = pipe->stream->config.init_num_cont_raw_buf; 2435 2436 for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) { 2437 /* free previous frame */ 2438 if (pipe->continuous_frames[i]) { 2439 ia_css_frame_free(pipe->continuous_frames[i]); 2440 pipe->continuous_frames[i] = NULL; 2441 } 2442 /* free previous metadata buffer */ 2443 ia_css_metadata_free(pipe->cont_md_buffers[i]); 2444 pipe->cont_md_buffers[i] = NULL; 2445 2446 /* check if new frame needed */ 2447 if (i < num_frames) { 2448 /* allocate new frame */ 2449 err = ia_css_frame_allocate_from_info( 2450 &pipe->continuous_frames[i], 2451 &ref_info); 2452 if (err) { 2453 IA_CSS_LEAVE_ERR_PRIVATE(err); 2454 return err; 2455 } 2456 /* allocate metadata buffer */ 2457 pipe->cont_md_buffers[i] = ia_css_metadata_allocate( 2458 &pipe->stream->info.metadata_info); 2459 } 2460 } 2461 IA_CSS_LEAVE_ERR_PRIVATE(0); 2462 return 0; 2463 } 2464 2465 int 2466 ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream) 2467 { 2468 if (!stream) 2469 return -EINVAL; 2470 return alloc_continuous_frames(stream->continuous_pipe, false); 2471 } 2472 2473 static int 2474 load_preview_binaries(struct ia_css_pipe *pipe) 2475 { 2476 struct ia_css_frame_info prev_in_info, 2477 prev_bds_out_info, 2478 prev_out_info, 2479 prev_vf_info; 2480 struct ia_css_binary_descr preview_descr; 2481 bool online; 2482 int err = 0; 2483 bool need_vf_pp = false; 2484 bool need_isp_copy_binary = false; 2485 bool sensor = false; 2486 bool continuous; 2487 2488 /* preview only have 1 output pin now */ 2489 struct ia_css_frame_info *pipe_out_info = &pipe->output_info[0]; 2490 struct ia_css_preview_settings *mycs = &pipe->pipe_settings.preview; 2491 2492 IA_CSS_ENTER_PRIVATE(""); 2493 assert(pipe); 2494 assert(pipe->stream); 2495 assert(pipe->mode == IA_CSS_PIPE_ID_PREVIEW); 2496 2497 online = pipe->stream->config.online; 2498 2499 sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 2500 continuous = pipe->stream->config.continuous; 2501 2502 if (mycs->preview_binary.info) 2503 return 0; 2504 2505 err = ia_css_util_check_input(&pipe->stream->config, false, false); 2506 if (err) 2507 return err; 2508 err = ia_css_frame_check_info(pipe_out_info); 2509 if (err) 2510 return err; 2511 2512 /* 2513 * Note: the current selection of vf_pp binary and 2514 * parameterization of the preview binary contains a few pieces 2515 * of hardcoded knowledge. This needs to be cleaned up such that 2516 * the binary selection becomes more generic. 2517 * The vf_pp binary is needed if one or more of the following features 2518 * are required: 2519 * 1. YUV downscaling. 2520 * 2. Digital zoom. 2521 * 3. An output format that is not supported by the preview binary. 2522 * In practice this means something other than yuv_line or nv12. 2523 * The decision if the vf_pp binary is needed for YUV downscaling is 2524 * made after the preview binary selection, since some preview binaries 2525 * can perform the requested YUV downscaling. 2526 */ 2527 need_vf_pp = pipe->config.enable_dz; 2528 need_vf_pp |= pipe_out_info->format != IA_CSS_FRAME_FORMAT_YUV_LINE && 2529 !(pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12 || 2530 pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_16 || 2531 pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY); 2532 2533 /* Preview step 1 */ 2534 if (pipe->vf_yuv_ds_input_info.res.width) 2535 prev_vf_info = pipe->vf_yuv_ds_input_info; 2536 else 2537 prev_vf_info = *pipe_out_info; 2538 /* 2539 * If vf_pp is needed, then preview must output yuv_line. 2540 * The exception is when vf_pp is manually disabled, that is only 2541 * used in combination with a pipeline extension that requires 2542 * yuv_line as input. 2543 */ 2544 if (need_vf_pp) 2545 ia_css_frame_info_set_format(&prev_vf_info, 2546 IA_CSS_FRAME_FORMAT_YUV_LINE); 2547 2548 err = ia_css_pipe_get_preview_binarydesc( 2549 pipe, 2550 &preview_descr, 2551 &prev_in_info, 2552 &prev_bds_out_info, 2553 &prev_out_info, 2554 &prev_vf_info); 2555 if (err) 2556 return err; 2557 err = ia_css_binary_find(&preview_descr, &mycs->preview_binary); 2558 if (err) 2559 return err; 2560 2561 /* The vf_pp binary is needed when (further) YUV downscaling is required */ 2562 need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.width != pipe_out_info->res.width; 2563 need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.height != pipe_out_info->res.height; 2564 2565 /* 2566 * When vf_pp is needed, then the output format of the selected 2567 * preview binary must be yuv_line. If this is not the case, 2568 * then the preview binary selection is done again. 2569 */ 2570 if (need_vf_pp && 2571 (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) { 2572 /* Preview step 2 */ 2573 if (pipe->vf_yuv_ds_input_info.res.width) 2574 prev_vf_info = pipe->vf_yuv_ds_input_info; 2575 else 2576 prev_vf_info = *pipe_out_info; 2577 2578 ia_css_frame_info_set_format(&prev_vf_info, 2579 IA_CSS_FRAME_FORMAT_YUV_LINE); 2580 2581 err = ia_css_pipe_get_preview_binarydesc( 2582 pipe, 2583 &preview_descr, 2584 &prev_in_info, 2585 &prev_bds_out_info, 2586 &prev_out_info, 2587 &prev_vf_info); 2588 if (err) 2589 return err; 2590 err = ia_css_binary_find(&preview_descr, 2591 &mycs->preview_binary); 2592 if (err) 2593 return err; 2594 } 2595 2596 if (need_vf_pp) { 2597 struct ia_css_binary_descr vf_pp_descr; 2598 2599 /* Viewfinder post-processing */ 2600 ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, 2601 &mycs->preview_binary.out_frame_info[0], 2602 pipe_out_info); 2603 err = ia_css_binary_find(&vf_pp_descr, 2604 &mycs->vf_pp_binary); 2605 if (err) 2606 return err; 2607 } 2608 2609 if (IS_ISP2401) { 2610 /* 2611 * When the input system is 2401, only the Direct Sensor Mode 2612 * Offline Preview uses the ISP copy binary. 2613 */ 2614 need_isp_copy_binary = !online && sensor; 2615 } else { 2616 /* 2617 * About pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY: 2618 * This is typical the case with SkyCam (which has no input system) but it also 2619 * applies to all cases where the driver chooses for memory based input frames. 2620 * In these cases, a copy binary (which typical copies sensor data to DDR) does 2621 * not have much use. 2622 */ 2623 need_isp_copy_binary = !online && !continuous; 2624 } 2625 2626 /* Copy */ 2627 if (need_isp_copy_binary) { 2628 err = load_copy_binary(pipe, 2629 &mycs->copy_binary, 2630 &mycs->preview_binary); 2631 if (err) 2632 return err; 2633 } 2634 2635 if (pipe->shading_table) { 2636 ia_css_shading_table_free(pipe->shading_table); 2637 pipe->shading_table = NULL; 2638 } 2639 2640 return 0; 2641 } 2642 2643 static void 2644 ia_css_binary_unload(struct ia_css_binary *binary) 2645 { 2646 ia_css_binary_destroy_isp_parameters(binary); 2647 } 2648 2649 static int 2650 unload_preview_binaries(struct ia_css_pipe *pipe) 2651 { 2652 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 2653 2654 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { 2655 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 2656 return -EINVAL; 2657 } 2658 ia_css_binary_unload(&pipe->pipe_settings.preview.copy_binary); 2659 ia_css_binary_unload(&pipe->pipe_settings.preview.preview_binary); 2660 ia_css_binary_unload(&pipe->pipe_settings.preview.vf_pp_binary); 2661 2662 IA_CSS_LEAVE_ERR_PRIVATE(0); 2663 return 0; 2664 } 2665 2666 static const struct ia_css_fw_info *last_output_firmware( 2667 const struct ia_css_fw_info *fw) 2668 { 2669 const struct ia_css_fw_info *last_fw = NULL; 2670 /* fw can be NULL */ 2671 IA_CSS_ENTER_LEAVE_PRIVATE(""); 2672 2673 for (; fw; fw = fw->next) { 2674 const struct ia_css_fw_info *info = fw; 2675 2676 if (info->info.isp.sp.enable.output) 2677 last_fw = fw; 2678 } 2679 return last_fw; 2680 } 2681 2682 static int add_firmwares( 2683 struct ia_css_pipeline *me, 2684 struct ia_css_binary *binary, 2685 const struct ia_css_fw_info *fw, 2686 const struct ia_css_fw_info *last_fw, 2687 unsigned int binary_mode, 2688 struct ia_css_frame *in_frame, 2689 struct ia_css_frame *out_frame, 2690 struct ia_css_frame *vf_frame, 2691 struct ia_css_pipeline_stage **my_stage, 2692 struct ia_css_pipeline_stage **vf_stage) 2693 { 2694 int err = 0; 2695 struct ia_css_pipeline_stage *extra_stage = NULL; 2696 struct ia_css_pipeline_stage_desc stage_desc; 2697 2698 /* all args can be NULL ??? */ 2699 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2700 "add_firmwares() enter:\n"); 2701 2702 for (; fw; fw = fw->next) { 2703 struct ia_css_frame *out[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL}; 2704 struct ia_css_frame *in = NULL; 2705 struct ia_css_frame *vf = NULL; 2706 2707 if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame != 0)) 2708 out[0] = out_frame; 2709 2710 if (fw->info.isp.sp.enable.in_frame != 0) 2711 in = in_frame; 2712 2713 if (fw->info.isp.sp.enable.out_frame != 0) 2714 vf = vf_frame; 2715 2716 ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary, 2717 out, in, vf, fw, binary_mode); 2718 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 2719 &extra_stage); 2720 if (err) 2721 return err; 2722 if (fw->info.isp.sp.enable.output != 0) 2723 in_frame = extra_stage->args.out_frame[0]; 2724 if (my_stage && !*my_stage && extra_stage) 2725 *my_stage = extra_stage; 2726 if (vf_stage && !*vf_stage && extra_stage && 2727 fw->info.isp.sp.enable.vf_veceven) 2728 *vf_stage = extra_stage; 2729 } 2730 return err; 2731 } 2732 2733 static int add_vf_pp_stage( 2734 struct ia_css_pipe *pipe, 2735 struct ia_css_frame *in_frame, 2736 struct ia_css_frame *out_frame, 2737 struct ia_css_binary *vf_pp_binary, 2738 struct ia_css_pipeline_stage **vf_pp_stage) 2739 { 2740 struct ia_css_pipeline *me = NULL; 2741 const struct ia_css_fw_info *last_fw = NULL; 2742 int err = 0; 2743 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 2744 struct ia_css_pipeline_stage_desc stage_desc; 2745 2746 /* out_frame can be NULL ??? */ 2747 2748 if (!pipe) 2749 return -EINVAL; 2750 if (!in_frame) 2751 return -EINVAL; 2752 if (!vf_pp_binary) 2753 return -EINVAL; 2754 if (!vf_pp_stage) 2755 return -EINVAL; 2756 2757 ia_css_pipe_util_create_output_frames(out_frames); 2758 me = &pipe->pipeline; 2759 2760 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2761 "add_vf_pp_stage() enter:\n"); 2762 2763 *vf_pp_stage = NULL; 2764 2765 last_fw = last_output_firmware(pipe->vf_stage); 2766 if (!pipe->extra_config.disable_vf_pp) { 2767 if (last_fw) { 2768 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 2769 ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary, 2770 out_frames, in_frame, NULL); 2771 } else { 2772 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 2773 ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary, 2774 out_frames, in_frame, NULL); 2775 } 2776 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, vf_pp_stage); 2777 if (err) 2778 return err; 2779 in_frame = (*vf_pp_stage)->args.out_frame[0]; 2780 } 2781 err = add_firmwares(me, vf_pp_binary, pipe->vf_stage, last_fw, 2782 IA_CSS_BINARY_MODE_VF_PP, 2783 in_frame, out_frame, NULL, 2784 vf_pp_stage, NULL); 2785 return err; 2786 } 2787 2788 static int add_yuv_scaler_stage( 2789 struct ia_css_pipe *pipe, 2790 struct ia_css_pipeline *me, 2791 struct ia_css_frame *in_frame, 2792 struct ia_css_frame *out_frame, 2793 struct ia_css_frame *internal_out_frame, 2794 struct ia_css_binary *yuv_scaler_binary, 2795 struct ia_css_pipeline_stage **pre_vf_pp_stage) 2796 { 2797 const struct ia_css_fw_info *last_fw; 2798 int err = 0; 2799 struct ia_css_frame *vf_frame = NULL; 2800 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 2801 struct ia_css_pipeline_stage_desc stage_desc; 2802 2803 /* out_frame can be NULL ??? */ 2804 assert(in_frame); 2805 assert(pipe); 2806 assert(me); 2807 assert(yuv_scaler_binary); 2808 assert(pre_vf_pp_stage); 2809 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2810 "add_yuv_scaler_stage() enter:\n"); 2811 2812 *pre_vf_pp_stage = NULL; 2813 ia_css_pipe_util_create_output_frames(out_frames); 2814 2815 last_fw = last_output_firmware(pipe->output_stage); 2816 2817 if (last_fw) { 2818 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 2819 ia_css_pipe_get_generic_stage_desc(&stage_desc, 2820 yuv_scaler_binary, out_frames, in_frame, vf_frame); 2821 } else { 2822 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 2823 ia_css_pipe_util_set_output_frames(out_frames, 1, internal_out_frame); 2824 ia_css_pipe_get_generic_stage_desc(&stage_desc, 2825 yuv_scaler_binary, out_frames, in_frame, vf_frame); 2826 } 2827 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 2828 pre_vf_pp_stage); 2829 if (err) 2830 return err; 2831 in_frame = (*pre_vf_pp_stage)->args.out_frame[0]; 2832 2833 err = add_firmwares(me, yuv_scaler_binary, pipe->output_stage, last_fw, 2834 IA_CSS_BINARY_MODE_CAPTURE_PP, 2835 in_frame, out_frame, vf_frame, 2836 NULL, pre_vf_pp_stage); 2837 /* If a firmware produce vf_pp output, we set that as vf_pp input */ 2838 (*pre_vf_pp_stage)->args.vf_downscale_log2 = 2839 yuv_scaler_binary->vf_downscale_log2; 2840 2841 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2842 "add_yuv_scaler_stage() leave:\n"); 2843 return err; 2844 } 2845 2846 static int add_capture_pp_stage( 2847 struct ia_css_pipe *pipe, 2848 struct ia_css_pipeline *me, 2849 struct ia_css_frame *in_frame, 2850 struct ia_css_frame *out_frame, 2851 struct ia_css_binary *capture_pp_binary, 2852 struct ia_css_pipeline_stage **capture_pp_stage) 2853 { 2854 const struct ia_css_fw_info *last_fw = NULL; 2855 int err = 0; 2856 struct ia_css_frame *vf_frame = NULL; 2857 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 2858 struct ia_css_pipeline_stage_desc stage_desc; 2859 2860 /* out_frame can be NULL ??? */ 2861 assert(in_frame); 2862 assert(pipe); 2863 assert(me); 2864 assert(capture_pp_binary); 2865 assert(capture_pp_stage); 2866 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 2867 "add_capture_pp_stage() enter:\n"); 2868 2869 *capture_pp_stage = NULL; 2870 ia_css_pipe_util_create_output_frames(out_frames); 2871 2872 last_fw = last_output_firmware(pipe->output_stage); 2873 err = ia_css_frame_allocate_from_info(&vf_frame, 2874 &capture_pp_binary->vf_frame_info); 2875 if (err) 2876 return err; 2877 if (last_fw) { 2878 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 2879 ia_css_pipe_get_generic_stage_desc(&stage_desc, 2880 capture_pp_binary, out_frames, NULL, vf_frame); 2881 } else { 2882 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 2883 ia_css_pipe_get_generic_stage_desc(&stage_desc, 2884 capture_pp_binary, out_frames, NULL, vf_frame); 2885 } 2886 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 2887 capture_pp_stage); 2888 if (err) 2889 return err; 2890 err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw, 2891 IA_CSS_BINARY_MODE_CAPTURE_PP, 2892 in_frame, out_frame, vf_frame, 2893 NULL, capture_pp_stage); 2894 /* If a firmware produce vf_pp output, we set that as vf_pp input */ 2895 if (*capture_pp_stage) { 2896 (*capture_pp_stage)->args.vf_downscale_log2 = 2897 capture_pp_binary->vf_downscale_log2; 2898 } 2899 return err; 2900 } 2901 2902 static void sh_css_setup_queues(void) 2903 { 2904 const struct ia_css_fw_info *fw; 2905 unsigned int HIVE_ADDR_host_sp_queues_initialized; 2906 2907 sh_css_hmm_buffer_record_init(); 2908 2909 sh_css_event_init_irq_mask(); 2910 2911 fw = &sh_css_sp_fw; 2912 HIVE_ADDR_host_sp_queues_initialized = 2913 fw->info.sp.host_sp_queues_initialized; 2914 2915 ia_css_bufq_init(); 2916 2917 /* set "host_sp_queues_initialized" to "true" */ 2918 sp_dmem_store_uint32(SP0_ID, 2919 (unsigned int)sp_address_of(host_sp_queues_initialized), 2920 (uint32_t)(1)); 2921 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_setup_queues() leave:\n"); 2922 } 2923 2924 static int 2925 init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, 2926 struct ia_css_frame *vf_frame, unsigned int idx) 2927 { 2928 int err = 0; 2929 unsigned int thread_id; 2930 enum sh_css_queue_id queue_id; 2931 2932 assert(vf_frame); 2933 2934 sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->frame_info, idx); 2935 vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 2936 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 2937 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id); 2938 vf_frame->dynamic_queue_id = queue_id; 2939 vf_frame->buf_type = IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx; 2940 2941 err = ia_css_frame_init_planes(vf_frame); 2942 return err; 2943 } 2944 2945 static unsigned int 2946 get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config) 2947 { 2948 assert(config); 2949 if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) || 2950 (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) 2951 return 1; 2952 2953 return 0; 2954 } 2955 2956 static unsigned int 2957 get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config) 2958 { 2959 assert(config); 2960 if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) || 2961 (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) 2962 return 1; 2963 2964 return 0; 2965 } 2966 2967 /* 2968 * This function is to get the sum of all extra pixels in addition to the effective 2969 * input, it includes dvs envelop and filter run-in 2970 */ 2971 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe, 2972 unsigned int *extra_row, unsigned int *extra_column) 2973 { 2974 enum ia_css_pipe_id pipe_id = pipe->mode; 2975 unsigned int left_cropping = 0, top_cropping = 0; 2976 unsigned int i; 2977 struct ia_css_resolution dvs_env = pipe->config.dvs_envelope; 2978 2979 /* 2980 * The dvs envelope info may not be correctly sent down via pipe config 2981 * The check is made and the correct value is populated in the binary info 2982 * Use this value when computing crop, else excess lines may get trimmed 2983 */ 2984 switch (pipe_id) { 2985 case IA_CSS_PIPE_ID_PREVIEW: 2986 if (pipe->pipe_settings.preview.preview_binary.info) { 2987 left_cropping = 2988 pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping; 2989 top_cropping = 2990 pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping; 2991 } 2992 dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope; 2993 break; 2994 case IA_CSS_PIPE_ID_VIDEO: 2995 if (pipe->pipe_settings.video.video_binary.info) { 2996 left_cropping = 2997 pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping; 2998 top_cropping = 2999 pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping; 3000 } 3001 dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope; 3002 break; 3003 case IA_CSS_PIPE_ID_CAPTURE: 3004 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 3005 if (pipe->pipe_settings.capture.primary_binary[i].info) { 3006 left_cropping += 3007 pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping; 3008 top_cropping += 3009 pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping; 3010 } 3011 dvs_env.width += 3012 pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width; 3013 dvs_env.height += 3014 pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height; 3015 } 3016 break; 3017 default: 3018 break; 3019 } 3020 3021 *extra_row = top_cropping + dvs_env.height; 3022 *extra_column = left_cropping + dvs_env.width; 3023 } 3024 3025 void 3026 ia_css_get_crop_offsets( 3027 struct ia_css_pipe *pipe, 3028 struct ia_css_frame_info *in_frame) 3029 { 3030 unsigned int row = 0; 3031 unsigned int column = 0; 3032 struct ia_css_resolution *input_res; 3033 struct ia_css_resolution *effective_res; 3034 unsigned int extra_row = 0, extra_col = 0; 3035 unsigned int min_reqd_height, min_reqd_width; 3036 3037 assert(pipe); 3038 assert(pipe->stream); 3039 assert(in_frame); 3040 3041 IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u", 3042 pipe, pipe->config.input_effective_res.width, 3043 pipe->config.input_effective_res.height); 3044 3045 input_res = &pipe->stream->config.input_config.input_res; 3046 3047 if (IS_ISP2401) 3048 effective_res = &pipe->config.input_effective_res; 3049 else 3050 effective_res = &pipe->stream->config.input_config.effective_res; 3051 3052 get_pipe_extra_pixel(pipe, &extra_row, &extra_col); 3053 3054 in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order; 3055 3056 min_reqd_height = effective_res->height + extra_row; 3057 min_reqd_width = effective_res->width + extra_col; 3058 3059 if (input_res->height > min_reqd_height) { 3060 row = (input_res->height - min_reqd_height) / 2; 3061 row &= ~0x1; 3062 } 3063 if (input_res->width > min_reqd_width) { 3064 column = (input_res->width - min_reqd_width) / 2; 3065 column &= ~0x1; 3066 } 3067 3068 /* 3069 * TODO: 3070 * 1. Require the special support for RAW10 packed mode. 3071 * 2. Require the special support for the online use cases. 3072 */ 3073 3074 /* 3075 * ISP expects GRBG bayer order, we skip one line and/or one row 3076 * to correct in case the input bayer order is different. 3077 */ 3078 column += get_crop_columns_for_bayer_order(&pipe->stream->config); 3079 row += get_crop_lines_for_bayer_order(&pipe->stream->config); 3080 3081 in_frame->crop_info.start_column = column; 3082 in_frame->crop_info.start_line = row; 3083 3084 IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row); 3085 3086 return; 3087 } 3088 3089 static int 3090 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, 3091 struct ia_css_frame *frame, enum ia_css_frame_format format) 3092 { 3093 struct ia_css_frame *in_frame; 3094 int err = 0; 3095 unsigned int thread_id; 3096 enum sh_css_queue_id queue_id; 3097 3098 assert(frame); 3099 in_frame = frame; 3100 3101 in_frame->frame_info.format = format; 3102 3103 if (IS_ISP2401 && format == IA_CSS_FRAME_FORMAT_RAW) { 3104 in_frame->frame_info.format = (pipe->stream->config.pack_raw_pixels) ? 3105 IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW; 3106 } 3107 3108 in_frame->frame_info.res.width = pipe->stream->config.input_config.input_res.width; 3109 in_frame->frame_info.res.height = pipe->stream->config.input_config.input_res.height; 3110 in_frame->frame_info.raw_bit_depth = ia_css_pipe_util_pipe_input_format_bpp(pipe); 3111 ia_css_frame_info_set_width(&in_frame->frame_info, 3112 pipe->stream->config.input_config.input_res.width, 0); 3113 in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 3114 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3115 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id); 3116 in_frame->dynamic_queue_id = queue_id; 3117 in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME; 3118 3119 if (IS_ISP2401) 3120 ia_css_get_crop_offsets(pipe, &in_frame->frame_info); 3121 3122 err = ia_css_frame_init_planes(in_frame); 3123 3124 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "%s() bayer_order = %d\n", 3125 __func__, in_frame->frame_info.raw_bayer_order); 3126 3127 return err; 3128 } 3129 3130 static int 3131 init_out_frameinfo_defaults(struct ia_css_pipe *pipe, 3132 struct ia_css_frame *out_frame, unsigned int idx) 3133 { 3134 int err = 0; 3135 unsigned int thread_id; 3136 enum sh_css_queue_id queue_id; 3137 3138 assert(out_frame); 3139 3140 sh_css_pipe_get_output_frame_info(pipe, &out_frame->frame_info, idx); 3141 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 3142 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3143 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id); 3144 out_frame->dynamic_queue_id = queue_id; 3145 out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx; 3146 err = ia_css_frame_init_planes(out_frame); 3147 3148 return err; 3149 } 3150 3151 /* Create stages for video pipe */ 3152 static int create_host_video_pipeline(struct ia_css_pipe *pipe) 3153 { 3154 struct ia_css_pipeline_stage_desc stage_desc; 3155 struct ia_css_binary *copy_binary, *video_binary, 3156 *yuv_scaler_binary, *vf_pp_binary; 3157 struct ia_css_pipeline_stage *copy_stage = NULL; 3158 struct ia_css_pipeline_stage *video_stage = NULL; 3159 struct ia_css_pipeline_stage *yuv_scaler_stage = NULL; 3160 struct ia_css_pipeline_stage *vf_pp_stage = NULL; 3161 struct ia_css_pipeline *me; 3162 struct ia_css_frame *in_frame = NULL; 3163 struct ia_css_frame *out_frame; 3164 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 3165 struct ia_css_frame *vf_frame = NULL; 3166 int err = 0; 3167 bool need_copy = false; 3168 bool need_vf_pp = false; 3169 bool need_yuv_pp = false; 3170 bool need_in_frameinfo_memory = false; 3171 3172 unsigned int i, num_yuv_scaler; 3173 bool *is_output_stage = NULL; 3174 3175 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3176 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 3177 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3178 return -EINVAL; 3179 } 3180 ia_css_pipe_util_create_output_frames(out_frames); 3181 out_frame = &pipe->out_frame_struct; 3182 3183 /* pipeline already created as part of create_host_pipeline_structure */ 3184 me = &pipe->pipeline; 3185 ia_css_pipeline_clean(me); 3186 3187 me->dvs_frame_delay = pipe->dvs_frame_delay; 3188 3189 if (IS_ISP2401) { 3190 /* 3191 * When the input system is 2401, always enable 'in_frameinfo_memory' 3192 * except for the following: online or continuous 3193 */ 3194 need_in_frameinfo_memory = !(pipe->stream->config.online || 3195 pipe->stream->config.continuous); 3196 } else { 3197 /* Construct in_frame info (only in case we have dynamic input */ 3198 need_in_frameinfo_memory = pipe->stream->config.mode == 3199 IA_CSS_INPUT_MODE_MEMORY; 3200 } 3201 3202 /* Construct in_frame info (only in case we have dynamic input */ 3203 if (need_in_frameinfo_memory) { 3204 in_frame = &pipe->in_frame_struct; 3205 err = init_in_frameinfo_memory_defaults(pipe, in_frame, 3206 IA_CSS_FRAME_FORMAT_RAW); 3207 if (err) 3208 goto ERR; 3209 } 3210 3211 out_frame->data = 0; 3212 err = init_out_frameinfo_defaults(pipe, out_frame, 0); 3213 if (err) 3214 goto ERR; 3215 3216 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 3217 vf_frame = &pipe->vf_frame_struct; 3218 vf_frame->data = 0; 3219 err = init_vf_frameinfo_defaults(pipe, vf_frame, 0); 3220 if (err) 3221 goto ERR; 3222 } 3223 3224 copy_binary = &pipe->pipe_settings.video.copy_binary; 3225 video_binary = &pipe->pipe_settings.video.video_binary; 3226 vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary; 3227 3228 yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary; 3229 num_yuv_scaler = pipe->pipe_settings.video.num_yuv_scaler; 3230 is_output_stage = pipe->pipe_settings.video.is_output_stage; 3231 3232 need_copy = (copy_binary && copy_binary->info); 3233 need_vf_pp = (vf_pp_binary && vf_pp_binary->info); 3234 need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info); 3235 3236 if (need_copy) { 3237 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3238 ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, 3239 out_frames, NULL, NULL); 3240 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3241 ©_stage); 3242 if (err) 3243 goto ERR; 3244 in_frame = me->stages->args.out_frame[0]; 3245 } else if (pipe->stream->config.continuous) { 3246 if (IS_ISP2401) 3247 /* 3248 * When continuous is enabled, configure in_frame with the 3249 * last pipe, which is the copy pipe. 3250 */ 3251 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 3252 else 3253 in_frame = pipe->continuous_frames[0]; 3254 } 3255 3256 ia_css_pipe_util_set_output_frames(out_frames, 0, 3257 need_yuv_pp ? NULL : out_frame); 3258 3259 /* 3260 * when the video binary supports a second output pin, 3261 * it can directly produce the vf_frame. 3262 */ 3263 if (need_vf_pp) { 3264 ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary, 3265 out_frames, in_frame, NULL); 3266 } else { 3267 ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary, 3268 out_frames, in_frame, vf_frame); 3269 } 3270 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3271 &video_stage); 3272 if (err) 3273 goto ERR; 3274 3275 /* If we use copy iso video, the input must be yuv iso raw */ 3276 if (video_stage) { 3277 video_stage->args.copy_vf = 3278 video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY; 3279 video_stage->args.copy_output = video_stage->args.copy_vf; 3280 } 3281 3282 /* when the video binary supports only 1 output pin, vf_pp is needed to 3283 produce the vf_frame.*/ 3284 if (need_vf_pp && video_stage) { 3285 in_frame = video_stage->args.out_vf_frame; 3286 err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary, 3287 &vf_pp_stage); 3288 if (err) 3289 goto ERR; 3290 } 3291 if (video_stage) { 3292 int frm; 3293 3294 for (frm = 0; frm < NUM_VIDEO_TNR_FRAMES; frm++) { 3295 video_stage->args.tnr_frames[frm] = 3296 pipe->pipe_settings.video.tnr_frames[frm]; 3297 } 3298 for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) { 3299 video_stage->args.delay_frames[frm] = 3300 pipe->pipe_settings.video.delay_frames[frm]; 3301 } 3302 } 3303 3304 if (need_yuv_pp && video_stage) { 3305 struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0]; 3306 struct ia_css_frame *tmp_out_frame = NULL; 3307 3308 for (i = 0; i < num_yuv_scaler; i++) { 3309 tmp_out_frame = is_output_stage[i] ? out_frame : NULL; 3310 3311 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 3312 tmp_out_frame, NULL, 3313 &yuv_scaler_binary[i], 3314 &yuv_scaler_stage); 3315 3316 if (err) { 3317 IA_CSS_LEAVE_ERR_PRIVATE(err); 3318 return err; 3319 } 3320 /* we use output port 1 as internal output port */ 3321 if (yuv_scaler_stage) 3322 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 3323 } 3324 } 3325 3326 pipe->pipeline.acquire_isp_each_stage = false; 3327 ia_css_pipeline_finalize_stages(&pipe->pipeline, 3328 pipe->stream->config.continuous); 3329 3330 ERR: 3331 IA_CSS_LEAVE_ERR_PRIVATE(err); 3332 return err; 3333 } 3334 3335 /* Create stages for preview */ 3336 static int 3337 create_host_preview_pipeline(struct ia_css_pipe *pipe) 3338 { 3339 struct ia_css_pipeline_stage *copy_stage = NULL; 3340 struct ia_css_pipeline_stage *preview_stage = NULL; 3341 struct ia_css_pipeline_stage *vf_pp_stage = NULL; 3342 struct ia_css_pipeline_stage_desc stage_desc; 3343 struct ia_css_pipeline *me = NULL; 3344 struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL; 3345 struct ia_css_frame *in_frame = NULL; 3346 int err = 0; 3347 struct ia_css_frame *out_frame; 3348 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 3349 bool need_in_frameinfo_memory = false; 3350 bool sensor = false; 3351 bool buffered_sensor = false; 3352 bool online = false; 3353 bool continuous = false; 3354 3355 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3356 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { 3357 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3358 return -EINVAL; 3359 } 3360 3361 ia_css_pipe_util_create_output_frames(out_frames); 3362 /* pipeline already created as part of create_host_pipeline_structure */ 3363 me = &pipe->pipeline; 3364 ia_css_pipeline_clean(me); 3365 3366 if (IS_ISP2401) { 3367 /* 3368 * When the input system is 2401, always enable 'in_frameinfo_memory' 3369 * except for the following: 3370 * - Direct Sensor Mode Online Preview 3371 * - Buffered Sensor Mode Online Preview 3372 * - Direct Sensor Mode Continuous Preview 3373 * - Buffered Sensor Mode Continuous Preview 3374 */ 3375 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 3376 buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 3377 online = pipe->stream->config.online; 3378 continuous = pipe->stream->config.continuous; 3379 need_in_frameinfo_memory = 3380 !((sensor && (online || continuous)) || (buffered_sensor && 3381 (online || continuous))); 3382 } else { 3383 /* Construct in_frame info (only in case we have dynamic input */ 3384 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 3385 } 3386 if (need_in_frameinfo_memory) { 3387 err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, 3388 IA_CSS_FRAME_FORMAT_RAW); 3389 if (err) 3390 goto ERR; 3391 3392 in_frame = &me->in_frame; 3393 } else { 3394 in_frame = NULL; 3395 } 3396 err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0); 3397 if (err) 3398 goto ERR; 3399 out_frame = &me->out_frame[0]; 3400 3401 copy_binary = &pipe->pipe_settings.preview.copy_binary; 3402 preview_binary = &pipe->pipe_settings.preview.preview_binary; 3403 if (pipe->pipe_settings.preview.vf_pp_binary.info) 3404 vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary; 3405 3406 if (pipe->pipe_settings.preview.copy_binary.info) { 3407 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3408 ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, 3409 out_frames, NULL, NULL); 3410 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3411 ©_stage); 3412 if (err) 3413 goto ERR; 3414 in_frame = me->stages->args.out_frame[0]; 3415 } else if (pipe->stream->config.continuous) { 3416 if (IS_ISP2401) { 3417 /* 3418 * When continuous is enabled, configure in_frame with the 3419 * last pipe, which is the copy pipe. 3420 */ 3421 if (continuous || !online) 3422 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 3423 } else { 3424 in_frame = pipe->continuous_frames[0]; 3425 } 3426 } 3427 3428 if (vf_pp_binary) { 3429 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3430 ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, 3431 out_frames, in_frame, NULL); 3432 } else { 3433 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 3434 ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, 3435 out_frames, in_frame, NULL); 3436 } 3437 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3438 &preview_stage); 3439 if (err) 3440 goto ERR; 3441 /* If we use copy iso preview, the input must be yuv iso raw */ 3442 preview_stage->args.copy_vf = 3443 preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY; 3444 preview_stage->args.copy_output = !preview_stage->args.copy_vf; 3445 if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) { 3446 /* in case of copy, use the vf frame as output frame */ 3447 preview_stage->args.out_vf_frame = 3448 preview_stage->args.out_frame[0]; 3449 } 3450 if (vf_pp_binary) { 3451 if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY) 3452 in_frame = preview_stage->args.out_vf_frame; 3453 else 3454 in_frame = preview_stage->args.out_frame[0]; 3455 err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary, 3456 &vf_pp_stage); 3457 if (err) 3458 goto ERR; 3459 } 3460 3461 pipe->pipeline.acquire_isp_each_stage = false; 3462 ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); 3463 3464 ERR: 3465 IA_CSS_LEAVE_ERR_PRIVATE(err); 3466 return err; 3467 } 3468 3469 static void send_raw_frames(struct ia_css_pipe *pipe) 3470 { 3471 if (pipe->stream->config.continuous) { 3472 unsigned int i; 3473 3474 sh_css_update_host2sp_cont_num_raw_frames 3475 (pipe->stream->config.init_num_cont_raw_buf, true); 3476 sh_css_update_host2sp_cont_num_raw_frames 3477 (pipe->stream->config.target_num_cont_raw_buf, false); 3478 3479 /* Hand-over all the SP-internal buffers */ 3480 for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) { 3481 sh_css_update_host2sp_offline_frame(i, 3482 pipe->continuous_frames[i], pipe->cont_md_buffers[i]); 3483 } 3484 } 3485 3486 return; 3487 } 3488 3489 static int 3490 preview_start(struct ia_css_pipe *pipe) 3491 { 3492 int err = 0; 3493 struct ia_css_pipe *copy_pipe, *capture_pipe; 3494 enum sh_css_pipe_config_override copy_ovrd; 3495 enum ia_css_input_mode preview_pipe_input_mode; 3496 unsigned int thread_id; 3497 3498 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3499 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { 3500 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3501 return -EINVAL; 3502 } 3503 3504 preview_pipe_input_mode = pipe->stream->config.mode; 3505 3506 copy_pipe = pipe->pipe_settings.preview.copy_pipe; 3507 capture_pipe = pipe->pipe_settings.preview.capture_pipe; 3508 3509 sh_css_metrics_start_frame(); 3510 3511 /* multi stream video needs mipi buffers */ 3512 err = send_mipi_frames(pipe); 3513 if (err) { 3514 IA_CSS_LEAVE_ERR_PRIVATE(err); 3515 return err; 3516 } 3517 send_raw_frames(pipe); 3518 3519 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3520 copy_ovrd = 1 << thread_id; 3521 3522 if (pipe->stream->cont_capt) { 3523 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 3524 &thread_id); 3525 copy_ovrd |= 1 << thread_id; 3526 } 3527 3528 /* Construct and load the copy pipe */ 3529 if (pipe->stream->config.continuous) { 3530 sh_css_sp_init_pipeline(©_pipe->pipeline, 3531 IA_CSS_PIPE_ID_COPY, 3532 (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe), 3533 false, 3534 pipe->stream->config.pixels_per_clock == 2, false, 3535 false, pipe->required_bds_factor, 3536 copy_ovrd, 3537 pipe->stream->config.mode, 3538 &pipe->stream->config.metadata_config, 3539 &pipe->stream->info.metadata_info, 3540 pipe->stream->config.source.port.port); 3541 3542 /* 3543 * make the preview pipe start with mem mode input, copy handles 3544 * the actual mode 3545 */ 3546 preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY; 3547 } 3548 3549 /* Construct and load the capture pipe */ 3550 if (pipe->stream->cont_capt) { 3551 sh_css_sp_init_pipeline(&capture_pipe->pipeline, 3552 IA_CSS_PIPE_ID_CAPTURE, 3553 (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe), 3554 capture_pipe->config.default_capture_config.enable_xnr != 0, 3555 capture_pipe->stream->config.pixels_per_clock == 2, 3556 true, /* continuous */ 3557 false, /* offline */ 3558 capture_pipe->required_bds_factor, 3559 0, 3560 IA_CSS_INPUT_MODE_MEMORY, 3561 &pipe->stream->config.metadata_config, 3562 &pipe->stream->info.metadata_info, 3563 (enum mipi_port_id)0); 3564 } 3565 3566 start_pipe(pipe, copy_ovrd, preview_pipe_input_mode); 3567 3568 IA_CSS_LEAVE_ERR_PRIVATE(err); 3569 return err; 3570 } 3571 3572 int 3573 ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, 3574 const struct ia_css_buffer *buffer) 3575 { 3576 int return_err = 0; 3577 unsigned int thread_id; 3578 enum sh_css_queue_id queue_id; 3579 struct ia_css_pipeline *pipeline; 3580 struct ia_css_pipeline_stage *stage; 3581 struct ia_css_rmgr_vbuf_handle p_vbuf; 3582 struct ia_css_rmgr_vbuf_handle *h_vbuf; 3583 struct sh_css_hmm_buffer ddr_buffer; 3584 enum ia_css_buffer_type buf_type; 3585 enum ia_css_pipe_id pipe_id; 3586 bool ret_err; 3587 3588 IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); 3589 3590 if ((!pipe) || (!buffer)) { 3591 IA_CSS_LEAVE_ERR(-EINVAL); 3592 return -EINVAL; 3593 } 3594 3595 buf_type = buffer->type; 3596 3597 pipe_id = pipe->mode; 3598 3599 IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type); 3600 3601 assert(pipe_id < IA_CSS_PIPE_ID_NUM); 3602 assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); 3603 if (buf_type == IA_CSS_BUFFER_TYPE_INVALID || 3604 buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE || 3605 pipe_id >= IA_CSS_PIPE_ID_NUM) { 3606 IA_CSS_LEAVE_ERR(-EINVAL); 3607 return -EINVAL; 3608 } 3609 3610 ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3611 if (!ret_err) { 3612 IA_CSS_LEAVE_ERR(-EINVAL); 3613 return -EINVAL; 3614 } 3615 3616 ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); 3617 if (!ret_err) { 3618 IA_CSS_LEAVE_ERR(-EINVAL); 3619 return -EINVAL; 3620 } 3621 3622 if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { 3623 IA_CSS_LEAVE_ERR(-EINVAL); 3624 return -EINVAL; 3625 } 3626 3627 if (!sh_css_sp_is_running()) { 3628 IA_CSS_LOG("SP is not running!"); 3629 IA_CSS_LEAVE_ERR(-EBUSY); 3630 /* SP is not running. The queues are not valid */ 3631 return -EBUSY; 3632 } 3633 3634 pipeline = &pipe->pipeline; 3635 3636 assert(pipeline || pipe_id == IA_CSS_PIPE_ID_COPY); 3637 3638 assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr)); 3639 ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL); 3640 ddr_buffer.cookie_ptr = buffer->driver_cookie; 3641 ddr_buffer.timing_data = buffer->timing_data; 3642 3643 if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) { 3644 if (!buffer->data.stats_3a) { 3645 IA_CSS_LEAVE_ERR(-EINVAL); 3646 return -EINVAL; 3647 } 3648 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a); 3649 ddr_buffer.payload.s3a = *buffer->data.stats_3a; 3650 } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) { 3651 if (!buffer->data.stats_dvs) { 3652 IA_CSS_LEAVE_ERR(-EINVAL); 3653 return -EINVAL; 3654 } 3655 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs); 3656 ddr_buffer.payload.dis = *buffer->data.stats_dvs; 3657 } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) { 3658 if (!buffer->data.metadata) { 3659 IA_CSS_LEAVE_ERR(-EINVAL); 3660 return -EINVAL; 3661 } 3662 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata); 3663 ddr_buffer.payload.metadata = *buffer->data.metadata; 3664 } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || 3665 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 3666 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || 3667 buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || 3668 buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) { 3669 if (!buffer->data.frame) { 3670 IA_CSS_LEAVE_ERR(-EINVAL); 3671 return -EINVAL; 3672 } 3673 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame); 3674 ddr_buffer.payload.frame.frame_data = buffer->data.frame->data; 3675 ddr_buffer.payload.frame.flashed = 0; 3676 3677 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 3678 "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n", 3679 buf_type, buffer->data.frame->data); 3680 3681 } 3682 3683 /* start of test for using rmgr for acq/rel memory */ 3684 p_vbuf.vptr = 0; 3685 p_vbuf.count = 0; 3686 p_vbuf.size = sizeof(struct sh_css_hmm_buffer); 3687 h_vbuf = &p_vbuf; 3688 /* TODO: change next to correct pool for optimization */ 3689 ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf); 3690 3691 if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) { 3692 IA_CSS_LEAVE_ERR(-EINVAL); 3693 return -EINVAL; 3694 } 3695 3696 hmm_store(h_vbuf->vptr, 3697 (void *)(&ddr_buffer), 3698 sizeof(struct sh_css_hmm_buffer)); 3699 if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS || 3700 buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS || 3701 buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) { 3702 if (!pipeline) { 3703 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); 3704 IA_CSS_LOG("pipeline is empty!"); 3705 IA_CSS_LEAVE_ERR(-EINVAL); 3706 return -EINVAL; 3707 } 3708 3709 for (stage = pipeline->stages; stage; stage = stage->next) { 3710 /* 3711 * The SP will read the params after it got 3712 * empty 3a and dis 3713 */ 3714 if (stage->binary && stage->binary->info && 3715 (stage->binary->info->sp.enable.s3a || 3716 stage->binary->info->sp.enable.dis)) { 3717 /* there is a stage that needs it */ 3718 return_err = ia_css_bufq_enqueue_buffer(thread_id, 3719 queue_id, 3720 (uint32_t)h_vbuf->vptr); 3721 } 3722 } 3723 } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || 3724 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 3725 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || 3726 buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || 3727 buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME || 3728 buf_type == IA_CSS_BUFFER_TYPE_METADATA) { 3729 return_err = ia_css_bufq_enqueue_buffer(thread_id, 3730 queue_id, 3731 (uint32_t)h_vbuf->vptr); 3732 if (!return_err && 3733 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { 3734 IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d", 3735 ddr_buffer.payload.frame.frame_data, 3736 queue_id, thread_id); 3737 } 3738 } 3739 3740 if (!return_err) { 3741 if (sh_css_hmm_buffer_record_acquire( 3742 h_vbuf, buf_type, 3743 HOST_ADDRESS(ddr_buffer.kernel_ptr))) { 3744 IA_CSS_LOG("send vbuf=%p", h_vbuf); 3745 } else { 3746 return_err = -EINVAL; 3747 IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n"); 3748 } 3749 } 3750 3751 /* 3752 * Tell the SP which queues are not empty, 3753 * by sending the software event. 3754 */ 3755 if (!return_err) { 3756 if (!sh_css_sp_is_running()) { 3757 /* SP is not running. The queues are not valid */ 3758 IA_CSS_LOG("SP is not running!"); 3759 IA_CSS_LEAVE_ERR(-EBUSY); 3760 return -EBUSY; 3761 } 3762 return_err = ia_css_bufq_enqueue_psys_event( 3763 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED, 3764 (uint8_t)thread_id, 3765 queue_id, 3766 0); 3767 } else { 3768 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); 3769 IA_CSS_ERROR("buffer not enqueued"); 3770 } 3771 3772 IA_CSS_LEAVE("return value = %d", return_err); 3773 3774 return return_err; 3775 } 3776 3777 /* 3778 * TODO: Free up the hmm memory space. 3779 */ 3780 int 3781 ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, 3782 struct ia_css_buffer *buffer) 3783 { 3784 int return_err; 3785 enum sh_css_queue_id queue_id; 3786 ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0; 3787 struct sh_css_hmm_buffer ddr_buffer; 3788 enum ia_css_buffer_type buf_type; 3789 enum ia_css_pipe_id pipe_id; 3790 unsigned int thread_id; 3791 hrt_address kernel_ptr = 0; 3792 bool ret_err; 3793 3794 IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); 3795 3796 if ((!pipe) || (!buffer)) { 3797 IA_CSS_LEAVE_ERR(-EINVAL); 3798 return -EINVAL; 3799 } 3800 3801 pipe_id = pipe->mode; 3802 3803 buf_type = buffer->type; 3804 3805 IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type); 3806 3807 ddr_buffer.kernel_ptr = 0; 3808 3809 ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3810 if (!ret_err) { 3811 IA_CSS_LEAVE_ERR(-EINVAL); 3812 return -EINVAL; 3813 } 3814 3815 ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); 3816 if (!ret_err) { 3817 IA_CSS_LEAVE_ERR(-EINVAL); 3818 return -EINVAL; 3819 } 3820 3821 if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { 3822 IA_CSS_LEAVE_ERR(-EINVAL); 3823 return -EINVAL; 3824 } 3825 3826 if (!sh_css_sp_is_running()) { 3827 IA_CSS_LOG("SP is not running!"); 3828 IA_CSS_LEAVE_ERR(-EBUSY); 3829 /* SP is not running. The queues are not valid */ 3830 return -EBUSY; 3831 } 3832 3833 return_err = ia_css_bufq_dequeue_buffer(queue_id, 3834 (uint32_t *)&ddr_buffer_addr); 3835 3836 if (!return_err) { 3837 struct ia_css_frame *frame; 3838 struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL; 3839 3840 IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr); 3841 3842 /* Validate the ddr_buffer_addr and buf_type */ 3843 hmm_buffer_record = sh_css_hmm_buffer_record_validate( 3844 ddr_buffer_addr, buf_type); 3845 if (hmm_buffer_record) { 3846 /* 3847 * valid hmm_buffer_record found. Save the kernel_ptr 3848 * for validation after performing hmm_load. The 3849 * vbuf handle and buffer_record can be released. 3850 */ 3851 kernel_ptr = hmm_buffer_record->kernel_ptr; 3852 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf); 3853 sh_css_hmm_buffer_record_reset(hmm_buffer_record); 3854 } else { 3855 IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)", 3856 ddr_buffer_addr, buf_type); 3857 IA_CSS_LEAVE_ERR(-EINVAL); 3858 return -EINVAL; 3859 } 3860 3861 hmm_load(ddr_buffer_addr, 3862 &ddr_buffer, 3863 sizeof(struct sh_css_hmm_buffer)); 3864 3865 /* 3866 * if the kernel_ptr is 0 or an invalid, return an error. 3867 * do not access the buffer via the kernal_ptr. 3868 */ 3869 if ((ddr_buffer.kernel_ptr == 0) || 3870 (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) { 3871 IA_CSS_ERROR("kernel_ptr invalid"); 3872 IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr); 3873 IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr)); 3874 IA_CSS_ERROR("buf_type: %d\n", buf_type); 3875 IA_CSS_LEAVE_ERR(-EINVAL); 3876 return -EINVAL; 3877 } 3878 3879 if (ddr_buffer.kernel_ptr != 0) { 3880 /* 3881 * buffer->exp_id : all instances to be removed later 3882 * once the driver change is completed. See patch #5758 3883 * for reference 3884 */ 3885 buffer->exp_id = 0; 3886 buffer->driver_cookie = ddr_buffer.cookie_ptr; 3887 buffer->timing_data = ddr_buffer.timing_data; 3888 3889 if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 3890 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 3891 buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick; 3892 } 3893 3894 switch (buf_type) { 3895 case IA_CSS_BUFFER_TYPE_INPUT_FRAME: 3896 case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: 3897 case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 3898 if (pipe && pipe->stop_requested) { 3899 if (!IS_ISP2401) { 3900 /* 3901 * free mipi frames only for old input 3902 * system for 2401 it is done in 3903 * ia_css_stream_destroy call 3904 */ 3905 return_err = free_mipi_frames(pipe); 3906 if (return_err) { 3907 IA_CSS_LOG("free_mipi_frames() failed"); 3908 IA_CSS_LEAVE_ERR(return_err); 3909 return return_err; 3910 } 3911 } 3912 pipe->stop_requested = false; 3913 } 3914 fallthrough; 3915 case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: 3916 case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: 3917 frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 3918 buffer->data.frame = frame; 3919 buffer->exp_id = ddr_buffer.payload.frame.exp_id; 3920 frame->exp_id = ddr_buffer.payload.frame.exp_id; 3921 frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id; 3922 if (ddr_buffer.payload.frame.flashed == 1) 3923 frame->flash_state = 3924 IA_CSS_FRAME_FLASH_STATE_PARTIAL; 3925 if (ddr_buffer.payload.frame.flashed == 2) 3926 frame->flash_state = 3927 IA_CSS_FRAME_FLASH_STATE_FULL; 3928 frame->valid = pipe->num_invalid_frames == 0; 3929 if (!frame->valid) 3930 pipe->num_invalid_frames--; 3931 3932 if (frame->frame_info.format == IA_CSS_FRAME_FORMAT_BINARY_8) { 3933 if (IS_ISP2401) 3934 frame->planes.binary.size = frame->data_bytes; 3935 else 3936 frame->planes.binary.size = 3937 sh_css_sp_get_binary_copy_size(); 3938 } 3939 if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { 3940 IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d", 3941 frame->data, frame->isp_config_id, thread_id); 3942 } 3943 3944 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 3945 "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n", 3946 buf_type, buffer->data.frame->data); 3947 3948 break; 3949 case IA_CSS_BUFFER_TYPE_3A_STATISTICS: 3950 buffer->data.stats_3a = 3951 (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 3952 buffer->exp_id = ddr_buffer.payload.s3a.exp_id; 3953 buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id; 3954 buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id; 3955 break; 3956 case IA_CSS_BUFFER_TYPE_DIS_STATISTICS: 3957 buffer->data.stats_dvs = 3958 (struct ia_css_isp_dvs_statistics *) 3959 HOST_ADDRESS(ddr_buffer.kernel_ptr); 3960 buffer->exp_id = ddr_buffer.payload.dis.exp_id; 3961 buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id; 3962 break; 3963 case IA_CSS_BUFFER_TYPE_LACE_STATISTICS: 3964 break; 3965 case IA_CSS_BUFFER_TYPE_METADATA: 3966 buffer->data.metadata = 3967 (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 3968 buffer->exp_id = ddr_buffer.payload.metadata.exp_id; 3969 buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id; 3970 break; 3971 default: 3972 return_err = -EINVAL; 3973 break; 3974 } 3975 } 3976 } 3977 3978 /* 3979 * Tell the SP which queues are not full, 3980 * by sending the software event. 3981 */ 3982 if (!return_err) { 3983 if (!sh_css_sp_is_running()) { 3984 IA_CSS_LOG("SP is not running!"); 3985 IA_CSS_LEAVE_ERR(-EBUSY); 3986 /* SP is not running. The queues are not valid */ 3987 return -EBUSY; 3988 } 3989 ia_css_bufq_enqueue_psys_event( 3990 IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED, 3991 0, 3992 queue_id, 3993 0); 3994 } 3995 IA_CSS_LEAVE("buffer=%p", buffer); 3996 3997 return return_err; 3998 } 3999 4000 /* 4001 * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h 4002 * TODO: modify and move it if possible. 4003 * 4004 * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC: 4005 * 1) "enum ia_css_event_type" (ia_css_event_public.h) 4006 * 2) "enum sh_css_sp_event_type" (sh_css_internal.h) 4007 * 3) "enum ia_css_event_type event_id_2_event_mask" (event_handler.sp.c) 4008 * 4) "enum ia_css_event_type convert_event_sp_to_host_domain" (sh_css.c) 4009 */ 4010 static enum ia_css_event_type convert_event_sp_to_host_domain[] = { 4011 IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE, /* Output frame ready. */ 4012 IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE, /* Second output frame ready. */ 4013 IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE, /* Viewfinder Output frame ready. */ 4014 IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE, /* Second viewfinder Output frame ready. */ 4015 IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE, /* Indication that 3A statistics are available. */ 4016 IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE, /* Indication that DIS statistics are available. */ 4017 IA_CSS_EVENT_TYPE_PIPELINE_DONE, /* Pipeline Done event, sent after last pipeline stage. */ 4018 IA_CSS_EVENT_TYPE_FRAME_TAGGED, /* Frame tagged. */ 4019 IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE, /* Input frame ready. */ 4020 IA_CSS_EVENT_TYPE_METADATA_DONE, /* Metadata ready. */ 4021 IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE, /* Indication that LACE statistics are available. */ 4022 IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE, /* Extension stage executed. */ 4023 IA_CSS_EVENT_TYPE_TIMER, /* Timing measurement data. */ 4024 IA_CSS_EVENT_TYPE_PORT_EOF, /* End Of Frame event, sent when in buffered sensor mode. */ 4025 IA_CSS_EVENT_TYPE_FW_WARNING, /* Performance warning encountered by FW */ 4026 IA_CSS_EVENT_TYPE_FW_ASSERT, /* Assertion hit by FW */ 4027 0, /* error if sp passes SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */ 4028 }; 4029 4030 int 4031 ia_css_dequeue_psys_event(struct ia_css_event *event) 4032 { 4033 enum ia_css_pipe_id pipe_id = 0; 4034 u8 payload[4] = {0, 0, 0, 0}; 4035 int ret_err; 4036 4037 /* 4038 * TODO: 4039 * a) use generic decoding function , same as the one used by sp. 4040 * b) group decode and dequeue into eventQueue module 4041 * 4042 * We skip the IA_CSS_ENTER logging call 4043 * to avoid flooding the logs when the host application 4044 * uses polling. 4045 */ 4046 if (!event) 4047 return -EINVAL; 4048 4049 /* SP is not running. The queues are not valid */ 4050 if (!sh_css_sp_is_running()) 4051 return -EBUSY; 4052 4053 /* dequeue the event (if any) from the psys event queue */ 4054 ret_err = ia_css_bufq_dequeue_psys_event(payload); 4055 if (ret_err) 4056 return ret_err; 4057 4058 IA_CSS_LOG("event dequeued from psys event queue"); 4059 4060 /* Tell the SP that we dequeued an event from the event queue. */ 4061 ia_css_bufq_enqueue_psys_event( 4062 IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0); 4063 4064 /* 4065 * Events are decoded into 4 bytes of payload, the first byte 4066 * contains the sp event type. This is converted to a host enum. 4067 * TODO: can this enum conversion be eliminated 4068 */ 4069 event->type = convert_event_sp_to_host_domain[payload[0]]; 4070 /* Some sane default values since not all events use all fields. */ 4071 event->pipe = NULL; 4072 event->port = MIPI_PORT0_ID; 4073 event->exp_id = 0; 4074 event->fw_warning = IA_CSS_FW_WARNING_NONE; 4075 event->fw_handle = 0; 4076 event->timer_data = 0; 4077 event->timer_code = 0; 4078 event->timer_subcode = 0; 4079 4080 if (event->type == IA_CSS_EVENT_TYPE_TIMER) { 4081 /* 4082 * timer event ??? get the 2nd event and decode the data 4083 * into the event struct 4084 */ 4085 u32 tmp_data; 4086 /* 1st event: LSB 16-bit timer data and code */ 4087 event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8)); 4088 event->timer_code = payload[2]; 4089 payload[0] = payload[1] = payload[2] = payload[3] = 0; 4090 ret_err = ia_css_bufq_dequeue_psys_event(payload); 4091 if (ret_err) { 4092 /* no 2nd event ??? an error */ 4093 /* 4094 * Putting IA_CSS_ERROR is resulting in failures in 4095 * Merrifield smoke testing 4096 */ 4097 IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n"); 4098 return ret_err; 4099 } 4100 ia_css_bufq_enqueue_psys_event( 4101 IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0); 4102 event->type = convert_event_sp_to_host_domain[payload[0]]; 4103 /* It's a timer */ 4104 if (event->type == IA_CSS_EVENT_TYPE_TIMER) { 4105 /* 2nd event data: MSB 16-bit timer and subcode */ 4106 tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8)); 4107 event->timer_data |= (tmp_data << 16); 4108 event->timer_subcode = payload[2]; 4109 } else { 4110 /* 4111 * It's a non timer event. So clear first half of the 4112 * timer event data. 4113 * If the second part of the TIMER event is not 4114 * received, we discard the first half of the timer 4115 * data and process the non timer event without 4116 * affecting the flow. So the non timer event falls 4117 * through the code. 4118 */ 4119 event->timer_data = 0; 4120 event->timer_code = 0; 4121 event->timer_subcode = 0; 4122 IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded"); 4123 } 4124 } 4125 if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) { 4126 event->port = (enum mipi_port_id)payload[1]; 4127 event->exp_id = payload[3]; 4128 } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) { 4129 event->fw_warning = (enum ia_css_fw_warning)payload[1]; 4130 /* exp_id is only available in these warning types */ 4131 if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED || 4132 event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED) 4133 event->exp_id = payload[3]; 4134 } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) { 4135 event->fw_assert_module_id = payload[1]; /* module */ 4136 event->fw_assert_line_no = (payload[2] << 8) + payload[3]; 4137 /* payload[2] is line_no>>8, payload[3] is line_no&0xff */ 4138 } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) { 4139 /* 4140 * pipe related events. 4141 * payload[1] contains the pipe_num, 4142 * payload[2] contains the pipe_id. These are different. 4143 */ 4144 event->pipe = find_pipe_by_num(payload[1]); 4145 pipe_id = (enum ia_css_pipe_id)payload[2]; 4146 /* Check to see if pipe still exists */ 4147 if (!event->pipe) 4148 return -EBUSY; 4149 4150 if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) { 4151 /* find the capture pipe that goes with this */ 4152 int i, n; 4153 4154 n = event->pipe->stream->num_pipes; 4155 for (i = 0; i < n; i++) { 4156 struct ia_css_pipe *p = 4157 event->pipe->stream->pipes[i]; 4158 if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) { 4159 event->pipe = p; 4160 break; 4161 } 4162 } 4163 event->exp_id = payload[3]; 4164 } 4165 if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) { 4166 /* payload[3] contains the acc fw handle. */ 4167 u32 stage_num = (uint32_t)payload[3]; 4168 4169 ret_err = ia_css_pipeline_get_fw_from_stage( 4170 &event->pipe->pipeline, 4171 stage_num, 4172 &event->fw_handle); 4173 if (ret_err) { 4174 IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u", 4175 stage_num); 4176 return ret_err; 4177 } 4178 } 4179 } 4180 4181 if (event->pipe) 4182 IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id); 4183 else 4184 IA_CSS_LEAVE("event_id=%d", event->type); 4185 4186 return 0; 4187 } 4188 4189 int 4190 ia_css_dequeue_isys_event(struct ia_css_event *event) 4191 { 4192 u8 payload[4] = {0, 0, 0, 0}; 4193 int err = 0; 4194 4195 /* 4196 * We skip the IA_CSS_ENTER logging call 4197 * to avoid flooding the logs when the host application 4198 * uses polling. 4199 */ 4200 if (!event) 4201 return -EINVAL; 4202 4203 /* SP is not running. The queues are not valid */ 4204 if (!sh_css_sp_is_running()) 4205 return -EBUSY; 4206 4207 err = ia_css_bufq_dequeue_isys_event(payload); 4208 if (err) 4209 return err; 4210 4211 IA_CSS_LOG("event dequeued from isys event queue"); 4212 4213 /* Update SP state to indicate that element was dequeued. */ 4214 ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED); 4215 4216 /* Fill return struct with appropriate info */ 4217 event->type = IA_CSS_EVENT_TYPE_PORT_EOF; 4218 /* EOF events are associated with a CSI port, not with a pipe */ 4219 event->pipe = NULL; 4220 event->port = payload[1]; 4221 event->exp_id = payload[3]; 4222 4223 IA_CSS_LEAVE_ERR(err); 4224 return err; 4225 } 4226 4227 static int 4228 sh_css_pipe_start(struct ia_css_stream *stream) 4229 { 4230 int err = 0; 4231 4232 struct ia_css_pipe *pipe; 4233 enum ia_css_pipe_id pipe_id; 4234 unsigned int thread_id; 4235 4236 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 4237 4238 if (!stream) { 4239 IA_CSS_LEAVE_ERR(-EINVAL); 4240 return -EINVAL; 4241 } 4242 pipe = stream->last_pipe; 4243 if (!pipe) { 4244 IA_CSS_LEAVE_ERR(-EINVAL); 4245 return -EINVAL; 4246 } 4247 4248 pipe_id = pipe->mode; 4249 4250 if (stream->started) { 4251 IA_CSS_WARNING("Cannot start stream that is already started"); 4252 IA_CSS_LEAVE_ERR(err); 4253 return err; 4254 } 4255 4256 pipe->stop_requested = false; 4257 4258 switch (pipe_id) { 4259 case IA_CSS_PIPE_ID_PREVIEW: 4260 err = preview_start(pipe); 4261 break; 4262 case IA_CSS_PIPE_ID_VIDEO: 4263 err = video_start(pipe); 4264 break; 4265 case IA_CSS_PIPE_ID_CAPTURE: 4266 err = capture_start(pipe); 4267 break; 4268 case IA_CSS_PIPE_ID_YUVPP: 4269 err = yuvpp_start(pipe); 4270 break; 4271 default: 4272 err = -EINVAL; 4273 } 4274 /* DH regular multi pipe - not continuous mode: start the next pipes too */ 4275 if (!stream->config.continuous) { 4276 int i; 4277 4278 for (i = 1; i < stream->num_pipes && 0 == err ; i++) { 4279 switch (stream->pipes[i]->mode) { 4280 case IA_CSS_PIPE_ID_PREVIEW: 4281 stream->pipes[i]->stop_requested = false; 4282 err = preview_start(stream->pipes[i]); 4283 break; 4284 case IA_CSS_PIPE_ID_VIDEO: 4285 stream->pipes[i]->stop_requested = false; 4286 err = video_start(stream->pipes[i]); 4287 break; 4288 case IA_CSS_PIPE_ID_CAPTURE: 4289 stream->pipes[i]->stop_requested = false; 4290 err = capture_start(stream->pipes[i]); 4291 break; 4292 case IA_CSS_PIPE_ID_YUVPP: 4293 stream->pipes[i]->stop_requested = false; 4294 err = yuvpp_start(stream->pipes[i]); 4295 break; 4296 default: 4297 err = -EINVAL; 4298 } 4299 } 4300 } 4301 if (err) { 4302 IA_CSS_LEAVE_ERR_PRIVATE(err); 4303 return err; 4304 } 4305 4306 /* 4307 * Force ISP parameter calculation after a mode change 4308 * Acceleration API examples pass NULL for stream but they 4309 * don't use ISP parameters anyway. So this should be okay. 4310 * The SP binary (jpeg) copy does not use any parameters. 4311 */ 4312 if (!copy_on_sp(pipe)) { 4313 sh_css_invalidate_params(stream); 4314 err = sh_css_param_update_isp_params(pipe, 4315 stream->isp_params_configs, true, NULL); 4316 if (err) { 4317 IA_CSS_LEAVE_ERR_PRIVATE(err); 4318 return err; 4319 } 4320 } 4321 4322 ia_css_debug_pipe_graph_dump_epilogue(); 4323 4324 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 4325 4326 if (!sh_css_sp_is_running()) { 4327 IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY); 4328 /* SP is not running. The queues are not valid */ 4329 return -EBUSY; 4330 } 4331 ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM, 4332 (uint8_t)thread_id, 0, 0); 4333 4334 /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */ 4335 if (!stream->config.continuous) { 4336 int i; 4337 4338 for (i = 1; i < stream->num_pipes; i++) { 4339 ia_css_pipeline_get_sp_thread_id( 4340 ia_css_pipe_get_pipe_num(stream->pipes[i]), 4341 &thread_id); 4342 ia_css_bufq_enqueue_psys_event( 4343 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4344 (uint8_t)thread_id, 0, 0); 4345 } 4346 } 4347 4348 /* in case of continuous capture mode, we also start capture thread and copy thread*/ 4349 if (pipe->stream->config.continuous) { 4350 struct ia_css_pipe *copy_pipe = NULL; 4351 4352 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) 4353 copy_pipe = pipe->pipe_settings.preview.copy_pipe; 4354 else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) 4355 copy_pipe = pipe->pipe_settings.video.copy_pipe; 4356 4357 if (!copy_pipe) { 4358 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4359 return -EINVAL; 4360 } 4361 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe), 4362 &thread_id); 4363 /* by the time we reach here q is initialized and handle is available.*/ 4364 ia_css_bufq_enqueue_psys_event( 4365 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4366 (uint8_t)thread_id, 0, 0); 4367 } 4368 if (pipe->stream->cont_capt) { 4369 struct ia_css_pipe *capture_pipe = NULL; 4370 4371 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) 4372 capture_pipe = pipe->pipe_settings.preview.capture_pipe; 4373 else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) 4374 capture_pipe = pipe->pipe_settings.video.capture_pipe; 4375 4376 if (!capture_pipe) { 4377 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4378 return -EINVAL; 4379 } 4380 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 4381 &thread_id); 4382 /* by the time we reach here q is initialized and handle is available.*/ 4383 ia_css_bufq_enqueue_psys_event( 4384 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4385 (uint8_t)thread_id, 0, 0); 4386 } 4387 4388 stream->started = true; 4389 4390 IA_CSS_LEAVE_ERR_PRIVATE(err); 4391 return err; 4392 } 4393 4394 /* ISP2400 */ 4395 void 4396 sh_css_enable_cont_capt(bool enable, bool stop_copy_preview) 4397 { 4398 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4399 "sh_css_enable_cont_capt() enter: enable=%d\n", enable); 4400 //my_css.cont_capt = enable; 4401 my_css.stop_copy_preview = stop_copy_preview; 4402 } 4403 4404 bool 4405 sh_css_continuous_is_enabled(uint8_t pipe_num) 4406 { 4407 struct ia_css_pipe *pipe; 4408 bool continuous; 4409 4410 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4411 "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num); 4412 4413 pipe = find_pipe_by_num(pipe_num); 4414 continuous = pipe && pipe->stream->config.continuous; 4415 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4416 "sh_css_continuous_is_enabled() leave: enable=%d\n", 4417 continuous); 4418 return continuous; 4419 } 4420 4421 /* ISP2400 */ 4422 int 4423 ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream, 4424 int *buffer_depth) 4425 { 4426 if (!buffer_depth) 4427 return -EINVAL; 4428 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n"); 4429 (void)stream; 4430 *buffer_depth = NUM_CONTINUOUS_FRAMES; 4431 return 0; 4432 } 4433 4434 int 4435 ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) 4436 { 4437 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth); 4438 (void)stream; 4439 if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1) 4440 return -EINVAL; 4441 /* ok, value allowed */ 4442 stream->config.target_num_cont_raw_buf = buffer_depth; 4443 /* TODO: check what to regarding initialization */ 4444 return 0; 4445 } 4446 4447 /* ISP2401 */ 4448 int 4449 ia_css_stream_get_buffer_depth(struct ia_css_stream *stream, 4450 int *buffer_depth) 4451 { 4452 if (!buffer_depth) 4453 return -EINVAL; 4454 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n"); 4455 (void)stream; 4456 *buffer_depth = stream->config.target_num_cont_raw_buf; 4457 return 0; 4458 } 4459 4460 unsigned int 4461 sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx) 4462 { 4463 OP___assert(port < N_CSI_PORTS); 4464 OP___assert(idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT); 4465 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 4466 "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n", 4467 port, idx, my_css.mipi_sizes_for_check[port][idx]); 4468 return my_css.mipi_sizes_for_check[port][idx]; 4469 } 4470 4471 static int sh_css_pipe_configure_output( 4472 struct ia_css_pipe *pipe, 4473 unsigned int width, 4474 unsigned int height, 4475 unsigned int padded_width, 4476 enum ia_css_frame_format format, 4477 unsigned int idx) 4478 { 4479 int err = 0; 4480 4481 IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d", 4482 pipe, width, height, padded_width, format, idx); 4483 if (!pipe) { 4484 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4485 return -EINVAL; 4486 } 4487 4488 err = ia_css_util_check_res(width, height); 4489 if (err) { 4490 IA_CSS_LEAVE_ERR_PRIVATE(err); 4491 return err; 4492 } 4493 if (pipe->output_info[idx].res.width != width || 4494 pipe->output_info[idx].res.height != height || 4495 pipe->output_info[idx].format != format) { 4496 ia_css_frame_info_init( 4497 &pipe->output_info[idx], 4498 width, 4499 height, 4500 format, 4501 padded_width); 4502 } 4503 IA_CSS_LEAVE_ERR_PRIVATE(0); 4504 return 0; 4505 } 4506 4507 static int 4508 sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe, 4509 struct ia_css_shading_info *shading_info, 4510 struct ia_css_pipe_config *pipe_config) 4511 { 4512 int err = 0; 4513 struct ia_css_binary *binary = NULL; 4514 4515 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 4516 "sh_css_pipe_get_shading_info() enter:\n"); 4517 4518 binary = ia_css_pipe_get_shading_correction_binary(pipe); 4519 4520 if (binary) { 4521 err = ia_css_binary_get_shading_info(binary, 4522 IA_CSS_SHADING_CORRECTION_TYPE_1, 4523 pipe->required_bds_factor, 4524 (const struct ia_css_stream_config *)&pipe->stream->config, 4525 shading_info, pipe_config); 4526 4527 /* 4528 * Other function calls can be added here when other shading 4529 * correction types will be added in the future. 4530 */ 4531 } else { 4532 /* 4533 * When the pipe does not have a binary which has the shading 4534 * correction, this function does not need to fill the shading 4535 * information. It is not a error case, and then 4536 * this function should return 0. 4537 */ 4538 memset(shading_info, 0, sizeof(*shading_info)); 4539 } 4540 return err; 4541 } 4542 4543 static int 4544 sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, 4545 struct ia_css_grid_info *info) 4546 { 4547 int err = 0; 4548 struct ia_css_binary *binary = NULL; 4549 4550 assert(pipe); 4551 assert(info); 4552 4553 IA_CSS_ENTER_PRIVATE(""); 4554 4555 binary = ia_css_pipe_get_s3a_binary(pipe); 4556 4557 if (binary) { 4558 err = ia_css_binary_3a_grid_info(binary, info, pipe); 4559 if (err) 4560 goto err; 4561 } else { 4562 memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); 4563 } 4564 4565 binary = ia_css_pipe_get_sdis_binary(pipe); 4566 4567 if (binary) { 4568 ia_css_binary_dvs_grid_info(binary, info, pipe); 4569 ia_css_binary_dvs_stat_grid_info(binary, info, pipe); 4570 } else { 4571 memset(&info->dvs_grid, 0, sizeof(info->dvs_grid)); 4572 memset(&info->dvs_grid.dvs_stat_grid_info, 0, 4573 sizeof(info->dvs_grid.dvs_stat_grid_info)); 4574 } 4575 4576 if (binary) { 4577 /* copy pipe does not have ISP binary*/ 4578 info->isp_in_width = binary->internal_frame_info.res.width; 4579 info->isp_in_height = binary->internal_frame_info.res.height; 4580 } 4581 4582 info->vamem_type = IA_CSS_VAMEM_TYPE_2; 4583 4584 err: 4585 IA_CSS_LEAVE_ERR_PRIVATE(err); 4586 return err; 4587 } 4588 4589 /* ISP2401 */ 4590 /* 4591 * @brief Check if a format is supported by the pipe. 4592 * 4593 */ 4594 static int 4595 ia_css_pipe_check_format(struct ia_css_pipe *pipe, 4596 enum ia_css_frame_format format) 4597 { 4598 const enum ia_css_frame_format *supported_formats; 4599 int number_of_formats; 4600 int found = 0; 4601 int i; 4602 4603 IA_CSS_ENTER_PRIVATE(""); 4604 4605 if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) { 4606 IA_CSS_ERROR("Pipe or binary info is not set"); 4607 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4608 return -EINVAL; 4609 } 4610 4611 supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats; 4612 number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format); 4613 4614 for (i = 0; i < number_of_formats && !found; i++) { 4615 if (supported_formats[i] == format) { 4616 found = 1; 4617 break; 4618 } 4619 } 4620 if (!found) { 4621 IA_CSS_ERROR("Requested format is not supported by binary"); 4622 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4623 return -EINVAL; 4624 } 4625 IA_CSS_LEAVE_ERR_PRIVATE(0); 4626 return 0; 4627 } 4628 4629 static int load_video_binaries(struct ia_css_pipe *pipe) 4630 { 4631 struct ia_css_frame_info video_in_info, tnr_info, 4632 *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info; 4633 bool online; 4634 int err = 0; 4635 bool continuous = pipe->stream->config.continuous; 4636 unsigned int i; 4637 unsigned int num_output_pins; 4638 struct ia_css_frame_info video_bin_out_info; 4639 bool need_scaler = false; 4640 bool vf_res_different_than_output = false; 4641 bool need_vf_pp = false; 4642 int vf_ds_log2; 4643 struct ia_css_video_settings *mycs = &pipe->pipe_settings.video; 4644 4645 IA_CSS_ENTER_PRIVATE(""); 4646 assert(pipe); 4647 assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO); 4648 /* 4649 * we only test the video_binary because offline video doesn't need a 4650 * vf_pp binary and online does not (always use) the copy_binary. 4651 * All are always reset at the same time anyway. 4652 */ 4653 if (mycs->video_binary.info) 4654 return 0; 4655 4656 online = pipe->stream->config.online; 4657 pipe_out_info = &pipe->output_info[0]; 4658 pipe_vf_out_info = &pipe->vf_output_info[0]; 4659 4660 assert(pipe_out_info); 4661 4662 /* 4663 * There is no explicit input format requirement for raw or yuv 4664 * What matters is that there is a binary that supports the stream format. 4665 * This is checked in the binary_find(), so no need to check it here 4666 */ 4667 err = ia_css_util_check_input(&pipe->stream->config, false, false); 4668 if (err) 4669 return err; 4670 /* cannot have online video and input_mode memory */ 4671 if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY) 4672 return -EINVAL; 4673 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 4674 err = ia_css_util_check_vf_out_info(pipe_out_info, 4675 pipe_vf_out_info); 4676 if (err) 4677 return err; 4678 } else { 4679 err = ia_css_frame_check_info(pipe_out_info); 4680 if (err) 4681 return err; 4682 } 4683 4684 if (pipe->out_yuv_ds_input_info.res.width) 4685 video_bin_out_info = pipe->out_yuv_ds_input_info; 4686 else 4687 video_bin_out_info = *pipe_out_info; 4688 4689 /* Video */ 4690 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 4691 video_vf_info = pipe_vf_out_info; 4692 vf_res_different_than_output = (video_vf_info->res.width != 4693 video_bin_out_info.res.width) || 4694 (video_vf_info->res.height != video_bin_out_info.res.height); 4695 } else { 4696 video_vf_info = NULL; 4697 } 4698 4699 need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res); 4700 4701 /* we build up the pipeline starting at the end */ 4702 /* YUV post-processing if needed */ 4703 if (need_scaler) { 4704 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 4705 4706 /* NV12 is the common format that is supported by both */ 4707 /* yuv_scaler and the video_xx_isp2_min binaries. */ 4708 video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12; 4709 4710 err = ia_css_pipe_create_cas_scaler_desc_single_output( 4711 &video_bin_out_info, 4712 pipe_out_info, 4713 NULL, 4714 &cas_scaler_descr); 4715 if (err) 4716 return err; 4717 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 4718 mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, 4719 sizeof(struct ia_css_binary), 4720 GFP_KERNEL); 4721 if (!mycs->yuv_scaler_binary) { 4722 err = -ENOMEM; 4723 return err; 4724 } 4725 mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, 4726 sizeof(bool), GFP_KERNEL); 4727 if (!mycs->is_output_stage) { 4728 err = -ENOMEM; 4729 return err; 4730 } 4731 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 4732 struct ia_css_binary_descr yuv_scaler_descr; 4733 4734 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 4735 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 4736 &yuv_scaler_descr, &cas_scaler_descr.in_info[i], 4737 &cas_scaler_descr.out_info[i], 4738 &cas_scaler_descr.internal_out_info[i], 4739 &cas_scaler_descr.vf_info[i]); 4740 err = ia_css_binary_find(&yuv_scaler_descr, 4741 &mycs->yuv_scaler_binary[i]); 4742 if (err) { 4743 kfree(mycs->is_output_stage); 4744 mycs->is_output_stage = NULL; 4745 return err; 4746 } 4747 } 4748 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 4749 } 4750 4751 { 4752 struct ia_css_binary_descr video_descr; 4753 enum ia_css_frame_format vf_info_format; 4754 4755 err = ia_css_pipe_get_video_binarydesc(pipe, 4756 &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info, 4757 video_vf_info, 4758 pipe->stream->config.left_padding); 4759 if (err) 4760 return err; 4761 4762 /* 4763 * In the case where video_vf_info is not NULL, this allows 4764 * us to find a potential video library with desired vf format. 4765 * If success, no vf_pp binary is needed. 4766 * If failed, we will look up video binary with YUV_LINE vf format 4767 */ 4768 err = ia_css_binary_find(&video_descr, 4769 &mycs->video_binary); 4770 4771 if (err) { 4772 /* This will do another video binary lookup later for YUV_LINE format*/ 4773 if (video_vf_info) 4774 need_vf_pp = true; 4775 else 4776 return err; 4777 } else if (video_vf_info) { 4778 /* 4779 * The first video binary lookup is successful, but we 4780 * may still need vf_pp binary based on additional check 4781 */ 4782 num_output_pins = mycs->video_binary.info->num_output_pins; 4783 vf_ds_log2 = mycs->video_binary.vf_downscale_log2; 4784 4785 /* 4786 * If the binary has dual output pins, we need vf_pp 4787 * if the resolution is different. 4788 */ 4789 need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output); 4790 4791 /* 4792 * If the binary has single output pin, we need vf_pp 4793 * if additional scaling is needed for vf 4794 */ 4795 need_vf_pp |= ((num_output_pins == 1) && 4796 ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) || 4797 (video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height))); 4798 } 4799 4800 if (need_vf_pp) { 4801 /* save the current vf_info format for restoration later */ 4802 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4803 "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n"); 4804 4805 vf_info_format = video_vf_info->format; 4806 4807 if (!pipe->config.enable_vfpp_bci) 4808 ia_css_frame_info_set_format(video_vf_info, 4809 IA_CSS_FRAME_FORMAT_YUV_LINE); 4810 4811 ia_css_binary_destroy_isp_parameters(&mycs->video_binary); 4812 4813 err = ia_css_binary_find(&video_descr, 4814 &mycs->video_binary); 4815 4816 /* restore original vf_info format */ 4817 ia_css_frame_info_set_format(video_vf_info, 4818 vf_info_format); 4819 if (err) 4820 return err; 4821 } 4822 } 4823 4824 /* 4825 * If a video binary does not use a ref_frame, we set the frame delay 4826 * to 0. This is the case for the 1-stage low-power video binary. 4827 */ 4828 if (!mycs->video_binary.info->sp.enable.ref_frame) 4829 pipe->dvs_frame_delay = 0; 4830 4831 /* 4832 * The delay latency determines the number of invalid frames after 4833 * a stream is started. 4834 */ 4835 pipe->num_invalid_frames = pipe->dvs_frame_delay; 4836 pipe->info.num_invalid_frames = pipe->num_invalid_frames; 4837 4838 /* 4839 * Viewfinder frames also decrement num_invalid_frames. If the pipe 4840 * outputs a viewfinder output, then we need double the number of 4841 * invalid frames 4842 */ 4843 if (video_vf_info) 4844 pipe->num_invalid_frames *= 2; 4845 4846 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4847 "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n", 4848 pipe->num_invalid_frames, pipe->dvs_frame_delay); 4849 4850 /* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */ 4851 if (!IS_ISP2401) { 4852 /* Copy */ 4853 if (!online && !continuous) { 4854 /* 4855 * TODO: what exactly needs doing, prepend the copy binary to 4856 * video base this only on !online? 4857 */ 4858 err = load_copy_binary(pipe, 4859 &mycs->copy_binary, 4860 &mycs->video_binary); 4861 if (err) 4862 return err; 4863 } 4864 } 4865 4866 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) { 4867 struct ia_css_binary_descr vf_pp_descr; 4868 4869 if (mycs->video_binary.vf_frame_info.format 4870 == IA_CSS_FRAME_FORMAT_YUV_LINE) { 4871 ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, 4872 &mycs->video_binary.vf_frame_info, 4873 pipe_vf_out_info); 4874 } else { 4875 /* 4876 * output from main binary is not yuv line. currently 4877 * this is possible only when bci is enabled on vfpp 4878 * output 4879 */ 4880 assert(pipe->config.enable_vfpp_bci); 4881 ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr, 4882 &mycs->video_binary.vf_frame_info, 4883 pipe_vf_out_info, NULL, NULL); 4884 } 4885 4886 err = ia_css_binary_find(&vf_pp_descr, 4887 &mycs->vf_pp_binary); 4888 if (err) 4889 return err; 4890 } 4891 4892 err = allocate_delay_frames(pipe); 4893 4894 if (err) 4895 return err; 4896 4897 if (mycs->video_binary.info->sp.enable.block_output) { 4898 tnr_info = mycs->video_binary.out_frame_info[0]; 4899 4900 /* Make tnr reference buffers output block height align */ 4901 tnr_info.res.height = CEIL_MUL(tnr_info.res.height, 4902 mycs->video_binary.info->sp.block.output_block_height); 4903 } else { 4904 tnr_info = mycs->video_binary.internal_frame_info; 4905 } 4906 tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE; 4907 tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH; 4908 4909 for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) { 4910 if (mycs->tnr_frames[i]) { 4911 ia_css_frame_free(mycs->tnr_frames[i]); 4912 mycs->tnr_frames[i] = NULL; 4913 } 4914 err = ia_css_frame_allocate_from_info( 4915 &mycs->tnr_frames[i], 4916 &tnr_info); 4917 if (err) 4918 return err; 4919 } 4920 IA_CSS_LEAVE_PRIVATE(""); 4921 return 0; 4922 } 4923 4924 static int 4925 unload_video_binaries(struct ia_css_pipe *pipe) 4926 { 4927 unsigned int i; 4928 4929 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 4930 4931 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 4932 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4933 return -EINVAL; 4934 } 4935 ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary); 4936 ia_css_binary_unload(&pipe->pipe_settings.video.video_binary); 4937 ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary); 4938 4939 for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++) 4940 ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]); 4941 4942 kfree(pipe->pipe_settings.video.is_output_stage); 4943 pipe->pipe_settings.video.is_output_stage = NULL; 4944 kfree(pipe->pipe_settings.video.yuv_scaler_binary); 4945 pipe->pipe_settings.video.yuv_scaler_binary = NULL; 4946 4947 IA_CSS_LEAVE_ERR_PRIVATE(0); 4948 return 0; 4949 } 4950 4951 static int video_start(struct ia_css_pipe *pipe) 4952 { 4953 int err = 0; 4954 struct ia_css_pipe *copy_pipe, *capture_pipe; 4955 enum sh_css_pipe_config_override copy_ovrd; 4956 enum ia_css_input_mode video_pipe_input_mode; 4957 unsigned int thread_id; 4958 4959 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 4960 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 4961 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4962 return -EINVAL; 4963 } 4964 4965 video_pipe_input_mode = pipe->stream->config.mode; 4966 4967 copy_pipe = pipe->pipe_settings.video.copy_pipe; 4968 capture_pipe = pipe->pipe_settings.video.capture_pipe; 4969 4970 sh_css_metrics_start_frame(); 4971 4972 /* multi stream video needs mipi buffers */ 4973 4974 err = send_mipi_frames(pipe); 4975 if (err) 4976 return err; 4977 4978 send_raw_frames(pipe); 4979 4980 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 4981 copy_ovrd = 1 << thread_id; 4982 4983 if (pipe->stream->cont_capt) { 4984 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 4985 &thread_id); 4986 copy_ovrd |= 1 << thread_id; 4987 } 4988 4989 /* Construct and load the copy pipe */ 4990 if (pipe->stream->config.continuous) { 4991 sh_css_sp_init_pipeline(©_pipe->pipeline, 4992 IA_CSS_PIPE_ID_COPY, 4993 (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe), 4994 false, 4995 pipe->stream->config.pixels_per_clock == 2, false, 4996 false, pipe->required_bds_factor, 4997 copy_ovrd, 4998 pipe->stream->config.mode, 4999 &pipe->stream->config.metadata_config, 5000 &pipe->stream->info.metadata_info, 5001 pipe->stream->config.source.port.port); 5002 5003 /* 5004 * make the video pipe start with mem mode input, copy handles 5005 * the actual mode 5006 */ 5007 video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY; 5008 } 5009 5010 /* Construct and load the capture pipe */ 5011 if (pipe->stream->cont_capt) { 5012 sh_css_sp_init_pipeline(&capture_pipe->pipeline, 5013 IA_CSS_PIPE_ID_CAPTURE, 5014 (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe), 5015 capture_pipe->config.default_capture_config.enable_xnr != 0, 5016 capture_pipe->stream->config.pixels_per_clock == 2, 5017 true, /* continuous */ 5018 false, /* offline */ 5019 capture_pipe->required_bds_factor, 5020 0, 5021 IA_CSS_INPUT_MODE_MEMORY, 5022 &pipe->stream->config.metadata_config, 5023 &pipe->stream->info.metadata_info, 5024 (enum mipi_port_id)0); 5025 } 5026 5027 start_pipe(pipe, copy_ovrd, video_pipe_input_mode); 5028 5029 IA_CSS_LEAVE_ERR_PRIVATE(err); 5030 return err; 5031 } 5032 5033 static 5034 int sh_css_pipe_get_viewfinder_frame_info( 5035 struct ia_css_pipe *pipe, 5036 struct ia_css_frame_info *info, 5037 unsigned int idx) 5038 { 5039 assert(pipe); 5040 assert(info); 5041 5042 /* We could print the pointer as input arg, and the values as output */ 5043 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5044 "sh_css_pipe_get_viewfinder_frame_info() enter: void\n"); 5045 5046 if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE && 5047 (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW || 5048 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER)) 5049 return -EINVAL; 5050 /* offline video does not generate viewfinder output */ 5051 *info = pipe->vf_output_info[idx]; 5052 5053 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5054 "sh_css_pipe_get_viewfinder_frame_info() leave: \ 5055 info.res.width=%d, info.res.height=%d, \ 5056 info.padded_width=%d, info.format=%d, \ 5057 info.raw_bit_depth=%d, info.raw_bayer_order=%d\n", 5058 info->res.width, info->res.height, 5059 info->padded_width, info->format, 5060 info->raw_bit_depth, info->raw_bayer_order); 5061 5062 return 0; 5063 } 5064 5065 static int 5066 sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width, 5067 unsigned int height, unsigned int min_width, 5068 enum ia_css_frame_format format, 5069 unsigned int idx) 5070 { 5071 int err = 0; 5072 5073 IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n", 5074 pipe, width, height, min_width, format, idx); 5075 5076 if (!pipe) { 5077 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5078 return -EINVAL; 5079 } 5080 5081 err = ia_css_util_check_res(width, height); 5082 if (err) { 5083 IA_CSS_LEAVE_ERR_PRIVATE(err); 5084 return err; 5085 } 5086 if (pipe->vf_output_info[idx].res.width != width || 5087 pipe->vf_output_info[idx].res.height != height || 5088 pipe->vf_output_info[idx].format != format) 5089 ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height, 5090 format, min_width); 5091 5092 IA_CSS_LEAVE_ERR_PRIVATE(0); 5093 return 0; 5094 } 5095 5096 static int load_copy_binaries(struct ia_css_pipe *pipe) 5097 { 5098 int err = 0; 5099 5100 assert(pipe); 5101 IA_CSS_ENTER_PRIVATE(""); 5102 5103 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5104 pipe->mode == IA_CSS_PIPE_ID_COPY); 5105 if (pipe->pipe_settings.capture.copy_binary.info) 5106 return 0; 5107 5108 err = ia_css_frame_check_info(&pipe->output_info[0]); 5109 if (err) 5110 goto ERR; 5111 5112 err = verify_copy_out_frame_format(pipe); 5113 if (err) 5114 goto ERR; 5115 5116 err = load_copy_binary(pipe, 5117 &pipe->pipe_settings.capture.copy_binary, 5118 NULL); 5119 5120 ERR: 5121 IA_CSS_LEAVE_ERR_PRIVATE(err); 5122 return err; 5123 } 5124 5125 static bool need_capture_pp( 5126 const struct ia_css_pipe *pipe) 5127 { 5128 const struct ia_css_frame_info *out_info = &pipe->output_info[0]; 5129 5130 IA_CSS_ENTER_LEAVE_PRIVATE(""); 5131 assert(pipe); 5132 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 5133 5134 /* determine whether we need to use the capture_pp binary. 5135 * This is needed for: 5136 * 1. XNR or 5137 * 2. Digital Zoom or 5138 * 3. YUV downscaling 5139 */ 5140 if (pipe->out_yuv_ds_input_info.res.width && 5141 ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) || 5142 (pipe->out_yuv_ds_input_info.res.height != out_info->res.height))) 5143 return true; 5144 5145 if (pipe->config.default_capture_config.enable_xnr != 0) 5146 return true; 5147 5148 if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) || 5149 (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) || 5150 pipe->config.enable_dz) 5151 return true; 5152 5153 return false; 5154 } 5155 5156 static bool need_capt_ldc( 5157 const struct ia_css_pipe *pipe) 5158 { 5159 IA_CSS_ENTER_LEAVE_PRIVATE(""); 5160 assert(pipe); 5161 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 5162 return (pipe->extra_config.enable_dvs_6axis) ? true : false; 5163 } 5164 5165 static int set_num_primary_stages(unsigned int *num, 5166 enum ia_css_pipe_version version) 5167 { 5168 int err = 0; 5169 5170 if (!num) 5171 return -EINVAL; 5172 5173 switch (version) { 5174 case IA_CSS_PIPE_VERSION_2_6_1: 5175 *num = NUM_PRIMARY_HQ_STAGES; 5176 break; 5177 case IA_CSS_PIPE_VERSION_2_2: 5178 case IA_CSS_PIPE_VERSION_1: 5179 *num = NUM_PRIMARY_STAGES; 5180 break; 5181 default: 5182 err = -EINVAL; 5183 break; 5184 } 5185 5186 return err; 5187 } 5188 5189 static int load_primary_binaries( 5190 struct ia_css_pipe *pipe) 5191 { 5192 bool online = false; 5193 bool need_pp = false; 5194 bool need_isp_copy_binary = false; 5195 bool need_ldc = false; 5196 bool sensor = false; 5197 bool memory, continuous; 5198 struct ia_css_frame_info prim_in_info, 5199 prim_out_info, 5200 capt_pp_out_info, vf_info, 5201 *vf_pp_in_info, *pipe_out_info, 5202 *pipe_vf_out_info, *capt_pp_in_info, 5203 capt_ldc_out_info; 5204 int err = 0; 5205 struct ia_css_capture_settings *mycs; 5206 unsigned int i; 5207 bool need_extra_yuv_scaler = false; 5208 struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES]; 5209 5210 IA_CSS_ENTER_PRIVATE(""); 5211 assert(pipe); 5212 assert(pipe->stream); 5213 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5214 pipe->mode == IA_CSS_PIPE_ID_COPY); 5215 5216 online = pipe->stream->config.online; 5217 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 5218 memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 5219 continuous = pipe->stream->config.continuous; 5220 5221 mycs = &pipe->pipe_settings.capture; 5222 pipe_out_info = &pipe->output_info[0]; 5223 pipe_vf_out_info = &pipe->vf_output_info[0]; 5224 5225 if (mycs->primary_binary[0].info) 5226 return 0; 5227 5228 err = set_num_primary_stages(&mycs->num_primary_stage, 5229 pipe->config.isp_pipe_version); 5230 if (err) { 5231 IA_CSS_LEAVE_ERR_PRIVATE(err); 5232 return err; 5233 } 5234 5235 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 5236 err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info); 5237 if (err) { 5238 IA_CSS_LEAVE_ERR_PRIVATE(err); 5239 return err; 5240 } 5241 } else { 5242 err = ia_css_frame_check_info(pipe_out_info); 5243 if (err) { 5244 IA_CSS_LEAVE_ERR_PRIVATE(err); 5245 return err; 5246 } 5247 } 5248 need_pp = need_capture_pp(pipe); 5249 5250 /* 5251 * we use the vf output info to get the primary/capture_pp binary 5252 * configured for vf_veceven. It will select the closest downscaling 5253 * factor. 5254 */ 5255 vf_info = *pipe_vf_out_info; 5256 5257 /* 5258 * WARNING: The #if def flag has been added below as a 5259 * temporary solution to solve the problem of enabling the 5260 * view finder in a single binary in a capture flow. The 5261 * vf-pp stage has been removed for Skycam in the solution 5262 * provided. The vf-pp stage should be re-introduced when 5263 * required. This should not be considered as a clean solution. 5264 * Proper investigation should be done to come up with the clean 5265 * solution. 5266 */ 5267 ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE); 5268 5269 /* 5270 * TODO: All this yuv_scaler and capturepp calculation logic 5271 * can be shared later. Capture_pp is also a yuv_scale binary 5272 * with extra XNR funcionality. Therefore, it can be made as the 5273 * first step of the cascade. 5274 */ 5275 capt_pp_out_info = pipe->out_yuv_ds_input_info; 5276 capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420; 5277 capt_pp_out_info.res.width /= MAX_PREFERRED_YUV_DS_PER_STEP; 5278 capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP; 5279 ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0); 5280 5281 need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res, 5282 pipe_out_info->res); 5283 5284 if (need_extra_yuv_scaler) { 5285 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 5286 5287 err = ia_css_pipe_create_cas_scaler_desc_single_output( 5288 &capt_pp_out_info, 5289 pipe_out_info, 5290 NULL, 5291 &cas_scaler_descr); 5292 if (err) { 5293 IA_CSS_LEAVE_ERR_PRIVATE(err); 5294 return err; 5295 } 5296 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 5297 mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, 5298 sizeof(struct ia_css_binary), 5299 GFP_KERNEL); 5300 if (!mycs->yuv_scaler_binary) { 5301 err = -ENOMEM; 5302 IA_CSS_LEAVE_ERR_PRIVATE(err); 5303 return err; 5304 } 5305 mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, 5306 sizeof(bool), GFP_KERNEL); 5307 if (!mycs->is_output_stage) { 5308 err = -ENOMEM; 5309 IA_CSS_LEAVE_ERR_PRIVATE(err); 5310 return err; 5311 } 5312 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 5313 struct ia_css_binary_descr yuv_scaler_descr; 5314 5315 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 5316 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 5317 &yuv_scaler_descr, &cas_scaler_descr.in_info[i], 5318 &cas_scaler_descr.out_info[i], 5319 &cas_scaler_descr.internal_out_info[i], 5320 &cas_scaler_descr.vf_info[i]); 5321 err = ia_css_binary_find(&yuv_scaler_descr, 5322 &mycs->yuv_scaler_binary[i]); 5323 if (err) { 5324 IA_CSS_LEAVE_ERR_PRIVATE(err); 5325 return err; 5326 } 5327 } 5328 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 5329 5330 } else { 5331 capt_pp_out_info = pipe->output_info[0]; 5332 } 5333 5334 /* TODO Do we disable ldc for skycam */ 5335 need_ldc = need_capt_ldc(pipe); 5336 5337 /* we build up the pipeline starting at the end */ 5338 /* Capture post-processing */ 5339 if (need_pp) { 5340 struct ia_css_binary_descr capture_pp_descr; 5341 5342 capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info; 5343 5344 ia_css_pipe_get_capturepp_binarydesc(pipe, 5345 &capture_pp_descr, 5346 capt_pp_in_info, 5347 &capt_pp_out_info, 5348 &vf_info); 5349 5350 err = ia_css_binary_find(&capture_pp_descr, 5351 &mycs->capture_pp_binary); 5352 if (err) { 5353 IA_CSS_LEAVE_ERR_PRIVATE(err); 5354 return err; 5355 } 5356 5357 if (need_ldc) { 5358 struct ia_css_binary_descr capt_ldc_descr; 5359 5360 ia_css_pipe_get_ldc_binarydesc(pipe, 5361 &capt_ldc_descr, 5362 &prim_out_info, 5363 &capt_ldc_out_info); 5364 5365 err = ia_css_binary_find(&capt_ldc_descr, 5366 &mycs->capture_ldc_binary); 5367 if (err) { 5368 IA_CSS_LEAVE_ERR_PRIVATE(err); 5369 return err; 5370 } 5371 } 5372 } else { 5373 prim_out_info = *pipe_out_info; 5374 } 5375 5376 /* Primary */ 5377 for (i = 0; i < mycs->num_primary_stage; i++) { 5378 struct ia_css_frame_info *local_vf_info = NULL; 5379 5380 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && 5381 (i == mycs->num_primary_stage - 1)) 5382 local_vf_info = &vf_info; 5383 ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], 5384 &prim_in_info, &prim_out_info, 5385 local_vf_info, i); 5386 err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]); 5387 if (err) { 5388 IA_CSS_LEAVE_ERR_PRIVATE(err); 5389 return err; 5390 } 5391 } 5392 5393 /* Viewfinder post-processing */ 5394 if (need_pp) 5395 vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info; 5396 else 5397 vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info; 5398 5399 /* 5400 * WARNING: The #if def flag has been added below as a 5401 * temporary solution to solve the problem of enabling the 5402 * view finder in a single binary in a capture flow. The 5403 * vf-pp stage has been removed for Skycam in the solution 5404 * provided. The vf-pp stage should be re-introduced when 5405 * required. Thisshould not be considered as a clean solution. 5406 * Proper * investigation should be done to come up with the clean 5407 * solution. 5408 */ 5409 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 5410 struct ia_css_binary_descr vf_pp_descr; 5411 5412 ia_css_pipe_get_vfpp_binarydesc(pipe, 5413 &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); 5414 err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary); 5415 if (err) { 5416 IA_CSS_LEAVE_ERR_PRIVATE(err); 5417 return err; 5418 } 5419 } 5420 err = allocate_delay_frames(pipe); 5421 5422 if (err) 5423 return err; 5424 5425 if (IS_ISP2401) 5426 /* 5427 * When the input system is 2401, only the Direct Sensor Mode 5428 * Offline Capture uses the ISP copy binary. 5429 */ 5430 need_isp_copy_binary = !online && sensor; 5431 else 5432 need_isp_copy_binary = !online && !continuous && !memory; 5433 5434 /* ISP Copy */ 5435 if (need_isp_copy_binary) { 5436 err = load_copy_binary(pipe, 5437 &mycs->copy_binary, 5438 &mycs->primary_binary[0]); 5439 if (err) { 5440 IA_CSS_LEAVE_ERR_PRIVATE(err); 5441 return err; 5442 } 5443 } 5444 5445 return 0; 5446 } 5447 5448 static int 5449 allocate_delay_frames(struct ia_css_pipe *pipe) 5450 { 5451 unsigned int num_delay_frames = 0, i = 0; 5452 unsigned int dvs_frame_delay = 0; 5453 struct ia_css_frame_info ref_info; 5454 int err = 0; 5455 enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO; 5456 struct ia_css_frame **delay_frames = NULL; 5457 5458 IA_CSS_ENTER_PRIVATE(""); 5459 5460 if (!pipe) { 5461 IA_CSS_ERROR("Invalid args - pipe %p", pipe); 5462 return -EINVAL; 5463 } 5464 5465 mode = pipe->mode; 5466 dvs_frame_delay = pipe->dvs_frame_delay; 5467 5468 if (dvs_frame_delay > 0) 5469 num_delay_frames = dvs_frame_delay + 1; 5470 5471 switch (mode) { 5472 case IA_CSS_PIPE_ID_CAPTURE: { 5473 struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture; 5474 (void)mycs_capture; 5475 return err; 5476 } 5477 break; 5478 case IA_CSS_PIPE_ID_VIDEO: { 5479 struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video; 5480 5481 ref_info = mycs_video->video_binary.internal_frame_info; 5482 5483 /* 5484 * The ref frame expects 5485 * 1. Y plane 5486 * 2. UV plane with line interleaving, like below 5487 * UUUUUU(width/2 times) VVVVVVVV..(width/2 times) 5488 * 5489 * This format is not YUV420(which has Y, U and V planes). 5490 * Its closer to NV12, except that the UV plane has UV 5491 * interleaving, like UVUVUVUVUVUVUVUVU... 5492 * 5493 * TODO: make this ref_frame format as a separate frame format 5494 */ 5495 ref_info.format = IA_CSS_FRAME_FORMAT_NV12; 5496 delay_frames = mycs_video->delay_frames; 5497 } 5498 break; 5499 case IA_CSS_PIPE_ID_PREVIEW: { 5500 struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview; 5501 5502 ref_info = mycs_preview->preview_binary.internal_frame_info; 5503 5504 /* 5505 * The ref frame expects 5506 * 1. Y plane 5507 * 2. UV plane with line interleaving, like below 5508 * UUUUUU(width/2 times) VVVVVVVV..(width/2 times) 5509 * 5510 * This format is not YUV420(which has Y, U and V planes). 5511 * Its closer to NV12, except that the UV plane has UV 5512 * interleaving, like UVUVUVUVUVUVUVUVU... 5513 * 5514 * TODO: make this ref_frame format as a separate frame format 5515 */ 5516 ref_info.format = IA_CSS_FRAME_FORMAT_NV12; 5517 delay_frames = mycs_preview->delay_frames; 5518 } 5519 break; 5520 default: 5521 return -EINVAL; 5522 } 5523 5524 ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH; 5525 5526 assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES); 5527 for (i = 0; i < num_delay_frames; i++) { 5528 err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info); 5529 if (err) 5530 return err; 5531 } 5532 IA_CSS_LEAVE_PRIVATE(""); 5533 return 0; 5534 } 5535 5536 static int load_advanced_binaries(struct ia_css_pipe *pipe) 5537 { 5538 struct ia_css_frame_info pre_in_info, gdc_in_info, 5539 post_in_info, post_out_info, 5540 vf_info, *vf_pp_in_info, *pipe_out_info, 5541 *pipe_vf_out_info; 5542 bool need_pp; 5543 bool need_isp_copy = true; 5544 int err = 0; 5545 5546 IA_CSS_ENTER_PRIVATE(""); 5547 5548 assert(pipe); 5549 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5550 pipe->mode == IA_CSS_PIPE_ID_COPY); 5551 if (pipe->pipe_settings.capture.pre_isp_binary.info) 5552 return 0; 5553 pipe_out_info = &pipe->output_info[0]; 5554 pipe_vf_out_info = &pipe->vf_output_info[0]; 5555 5556 vf_info = *pipe_vf_out_info; 5557 err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info); 5558 if (err) 5559 return err; 5560 need_pp = need_capture_pp(pipe); 5561 5562 ia_css_frame_info_set_format(&vf_info, 5563 IA_CSS_FRAME_FORMAT_YUV_LINE); 5564 5565 /* we build up the pipeline starting at the end */ 5566 /* Capture post-processing */ 5567 if (need_pp) { 5568 struct ia_css_binary_descr capture_pp_descr; 5569 5570 ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, 5571 &post_out_info, 5572 pipe_out_info, &vf_info); 5573 err = ia_css_binary_find(&capture_pp_descr, 5574 &pipe->pipe_settings.capture.capture_pp_binary); 5575 if (err) 5576 return err; 5577 } else { 5578 post_out_info = *pipe_out_info; 5579 } 5580 5581 /* Post-gdc */ 5582 { 5583 struct ia_css_binary_descr post_gdc_descr; 5584 5585 ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr, 5586 &post_in_info, 5587 &post_out_info, &vf_info); 5588 err = ia_css_binary_find(&post_gdc_descr, 5589 &pipe->pipe_settings.capture.post_isp_binary); 5590 if (err) 5591 return err; 5592 } 5593 5594 /* Gdc */ 5595 { 5596 struct ia_css_binary_descr gdc_descr; 5597 5598 ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info, 5599 &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); 5600 err = ia_css_binary_find(&gdc_descr, 5601 &pipe->pipe_settings.capture.anr_gdc_binary); 5602 if (err) 5603 return err; 5604 } 5605 pipe->pipe_settings.capture.anr_gdc_binary.left_padding = 5606 pipe->pipe_settings.capture.post_isp_binary.left_padding; 5607 5608 /* Pre-gdc */ 5609 { 5610 struct ia_css_binary_descr pre_gdc_descr; 5611 5612 ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info, 5613 &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); 5614 err = ia_css_binary_find(&pre_gdc_descr, 5615 &pipe->pipe_settings.capture.pre_isp_binary); 5616 if (err) 5617 return err; 5618 } 5619 pipe->pipe_settings.capture.pre_isp_binary.left_padding = 5620 pipe->pipe_settings.capture.anr_gdc_binary.left_padding; 5621 5622 /* Viewfinder post-processing */ 5623 if (need_pp) { 5624 vf_pp_in_info = 5625 &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info; 5626 } else { 5627 vf_pp_in_info = 5628 &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info; 5629 } 5630 5631 { 5632 struct ia_css_binary_descr vf_pp_descr; 5633 5634 ia_css_pipe_get_vfpp_binarydesc(pipe, 5635 &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); 5636 err = ia_css_binary_find(&vf_pp_descr, 5637 &pipe->pipe_settings.capture.vf_pp_binary); 5638 if (err) 5639 return err; 5640 } 5641 5642 /* Copy */ 5643 if (IS_ISP2401) 5644 /* For CSI2+, only the direct sensor mode/online requires ISP copy */ 5645 need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 5646 5647 if (need_isp_copy) 5648 load_copy_binary(pipe, 5649 &pipe->pipe_settings.capture.copy_binary, 5650 &pipe->pipe_settings.capture.pre_isp_binary); 5651 5652 return err; 5653 } 5654 5655 static int load_bayer_isp_binaries(struct ia_css_pipe *pipe) 5656 { 5657 struct ia_css_frame_info pre_isp_in_info, *pipe_out_info; 5658 int err = 0; 5659 struct ia_css_binary_descr pre_de_descr; 5660 5661 IA_CSS_ENTER_PRIVATE(""); 5662 assert(pipe); 5663 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5664 pipe->mode == IA_CSS_PIPE_ID_COPY); 5665 pipe_out_info = &pipe->output_info[0]; 5666 5667 if (pipe->pipe_settings.capture.pre_isp_binary.info) 5668 return 0; 5669 5670 err = ia_css_frame_check_info(pipe_out_info); 5671 if (err) 5672 return err; 5673 5674 ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr, 5675 &pre_isp_in_info, 5676 pipe_out_info); 5677 5678 err = ia_css_binary_find(&pre_de_descr, 5679 &pipe->pipe_settings.capture.pre_isp_binary); 5680 5681 return err; 5682 } 5683 5684 static int load_low_light_binaries(struct ia_css_pipe *pipe) 5685 { 5686 struct ia_css_frame_info pre_in_info, anr_in_info, 5687 post_in_info, post_out_info, 5688 vf_info, *pipe_vf_out_info, *pipe_out_info, 5689 *vf_pp_in_info; 5690 bool need_pp; 5691 bool need_isp_copy = true; 5692 int err = 0; 5693 5694 IA_CSS_ENTER_PRIVATE(""); 5695 assert(pipe); 5696 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5697 pipe->mode == IA_CSS_PIPE_ID_COPY); 5698 5699 if (pipe->pipe_settings.capture.pre_isp_binary.info) 5700 return 0; 5701 pipe_vf_out_info = &pipe->vf_output_info[0]; 5702 pipe_out_info = &pipe->output_info[0]; 5703 5704 vf_info = *pipe_vf_out_info; 5705 err = ia_css_util_check_vf_out_info(pipe_out_info, 5706 &vf_info); 5707 if (err) 5708 return err; 5709 need_pp = need_capture_pp(pipe); 5710 5711 ia_css_frame_info_set_format(&vf_info, 5712 IA_CSS_FRAME_FORMAT_YUV_LINE); 5713 5714 /* we build up the pipeline starting at the end */ 5715 /* Capture post-processing */ 5716 if (need_pp) { 5717 struct ia_css_binary_descr capture_pp_descr; 5718 5719 ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, 5720 &post_out_info, 5721 pipe_out_info, &vf_info); 5722 err = ia_css_binary_find(&capture_pp_descr, 5723 &pipe->pipe_settings.capture.capture_pp_binary); 5724 if (err) 5725 return err; 5726 } else { 5727 post_out_info = *pipe_out_info; 5728 } 5729 5730 /* Post-anr */ 5731 { 5732 struct ia_css_binary_descr post_anr_descr; 5733 5734 ia_css_pipe_get_post_anr_binarydesc(pipe, 5735 &post_anr_descr, &post_in_info, &post_out_info, &vf_info); 5736 err = ia_css_binary_find(&post_anr_descr, 5737 &pipe->pipe_settings.capture.post_isp_binary); 5738 if (err) 5739 return err; 5740 } 5741 5742 /* Anr */ 5743 { 5744 struct ia_css_binary_descr anr_descr; 5745 5746 ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info, 5747 &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); 5748 err = ia_css_binary_find(&anr_descr, 5749 &pipe->pipe_settings.capture.anr_gdc_binary); 5750 if (err) 5751 return err; 5752 } 5753 pipe->pipe_settings.capture.anr_gdc_binary.left_padding = 5754 pipe->pipe_settings.capture.post_isp_binary.left_padding; 5755 5756 /* Pre-anr */ 5757 { 5758 struct ia_css_binary_descr pre_anr_descr; 5759 5760 ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info, 5761 &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); 5762 err = ia_css_binary_find(&pre_anr_descr, 5763 &pipe->pipe_settings.capture.pre_isp_binary); 5764 if (err) 5765 return err; 5766 } 5767 pipe->pipe_settings.capture.pre_isp_binary.left_padding = 5768 pipe->pipe_settings.capture.anr_gdc_binary.left_padding; 5769 5770 /* Viewfinder post-processing */ 5771 if (need_pp) { 5772 vf_pp_in_info = 5773 &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info; 5774 } else { 5775 vf_pp_in_info = 5776 &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info; 5777 } 5778 5779 { 5780 struct ia_css_binary_descr vf_pp_descr; 5781 5782 ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, 5783 vf_pp_in_info, pipe_vf_out_info); 5784 err = ia_css_binary_find(&vf_pp_descr, 5785 &pipe->pipe_settings.capture.vf_pp_binary); 5786 if (err) 5787 return err; 5788 } 5789 5790 /* Copy */ 5791 if (IS_ISP2401) 5792 /* For CSI2+, only the direct sensor mode/online requires ISP copy */ 5793 need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 5794 5795 if (need_isp_copy) 5796 err = load_copy_binary(pipe, 5797 &pipe->pipe_settings.capture.copy_binary, 5798 &pipe->pipe_settings.capture.pre_isp_binary); 5799 5800 return err; 5801 } 5802 5803 static bool copy_on_sp(struct ia_css_pipe *pipe) 5804 { 5805 bool rval; 5806 5807 assert(pipe); 5808 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n"); 5809 5810 rval = true; 5811 5812 rval &= (pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 5813 5814 rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW); 5815 5816 rval &= ((pipe->stream->config.input_config.format == 5817 ATOMISP_INPUT_FORMAT_BINARY_8) || 5818 (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)); 5819 5820 return rval; 5821 } 5822 5823 static int load_capture_binaries(struct ia_css_pipe *pipe) 5824 { 5825 int err = 0; 5826 bool must_be_raw; 5827 5828 IA_CSS_ENTER_PRIVATE(""); 5829 assert(pipe); 5830 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5831 pipe->mode == IA_CSS_PIPE_ID_COPY); 5832 5833 if (pipe->pipe_settings.capture.primary_binary[0].info) { 5834 IA_CSS_LEAVE_ERR_PRIVATE(0); 5835 return 0; 5836 } 5837 5838 /* in primary, advanced,low light or bayer, 5839 the input format must be raw */ 5840 must_be_raw = 5841 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED || 5842 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER || 5843 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT; 5844 err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false); 5845 if (err) { 5846 IA_CSS_LEAVE_ERR_PRIVATE(err); 5847 return err; 5848 } 5849 if (copy_on_sp(pipe) && 5850 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 5851 ia_css_frame_info_init( 5852 &pipe->output_info[0], 5853 JPEG_BYTES, 5854 1, 5855 IA_CSS_FRAME_FORMAT_BINARY_8, 5856 0); 5857 IA_CSS_LEAVE_ERR_PRIVATE(0); 5858 return 0; 5859 } 5860 5861 switch (pipe->config.default_capture_config.mode) { 5862 case IA_CSS_CAPTURE_MODE_RAW: 5863 err = load_copy_binaries(pipe); 5864 if (!err && IS_ISP2401) 5865 pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online; 5866 5867 break; 5868 case IA_CSS_CAPTURE_MODE_BAYER: 5869 err = load_bayer_isp_binaries(pipe); 5870 break; 5871 case IA_CSS_CAPTURE_MODE_PRIMARY: 5872 err = load_primary_binaries(pipe); 5873 break; 5874 case IA_CSS_CAPTURE_MODE_ADVANCED: 5875 err = load_advanced_binaries(pipe); 5876 break; 5877 case IA_CSS_CAPTURE_MODE_LOW_LIGHT: 5878 err = load_low_light_binaries(pipe); 5879 break; 5880 } 5881 if (err) { 5882 IA_CSS_LEAVE_ERR_PRIVATE(err); 5883 return err; 5884 } 5885 5886 IA_CSS_LEAVE_ERR_PRIVATE(err); 5887 return err; 5888 } 5889 5890 static int 5891 unload_capture_binaries(struct ia_css_pipe *pipe) 5892 { 5893 unsigned int i; 5894 5895 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 5896 5897 if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE && 5898 pipe->mode != IA_CSS_PIPE_ID_COPY)) { 5899 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5900 return -EINVAL; 5901 } 5902 ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary); 5903 for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++) 5904 ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]); 5905 ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary); 5906 ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary); 5907 ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary); 5908 ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary); 5909 ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary); 5910 ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary); 5911 5912 for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++) 5913 ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]); 5914 5915 kfree(pipe->pipe_settings.capture.is_output_stage); 5916 pipe->pipe_settings.capture.is_output_stage = NULL; 5917 kfree(pipe->pipe_settings.capture.yuv_scaler_binary); 5918 pipe->pipe_settings.capture.yuv_scaler_binary = NULL; 5919 5920 IA_CSS_LEAVE_ERR_PRIVATE(0); 5921 return 0; 5922 } 5923 5924 static bool 5925 need_downscaling(const struct ia_css_resolution in_res, 5926 const struct ia_css_resolution out_res) 5927 { 5928 if (in_res.width > out_res.width || in_res.height > out_res.height) 5929 return true; 5930 5931 return false; 5932 } 5933 5934 static bool 5935 need_yuv_scaler_stage(const struct ia_css_pipe *pipe) 5936 { 5937 unsigned int i; 5938 struct ia_css_resolution in_res, out_res; 5939 5940 bool need_format_conversion = false; 5941 5942 IA_CSS_ENTER_PRIVATE(""); 5943 assert(pipe); 5944 assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP); 5945 5946 /* TODO: make generic function */ 5947 need_format_conversion = 5948 ((pipe->stream->config.input_config.format == 5949 ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) && 5950 (pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8)); 5951 5952 in_res = pipe->config.input_effective_res; 5953 5954 if (pipe->config.enable_dz) 5955 return true; 5956 5957 if ((pipe->output_info[0].res.width != 0) && need_format_conversion) 5958 return true; 5959 5960 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 5961 out_res = pipe->output_info[i].res; 5962 5963 /* A non-zero width means it is a valid output port */ 5964 if ((out_res.width != 0) && need_downscaling(in_res, out_res)) 5965 return true; 5966 } 5967 5968 return false; 5969 } 5970 5971 /* 5972 * TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc 5973 * which has some hard-coded knowledge which prevents reuse of the function. 5974 * Later, merge this with ia_css_pipe_create_cas_scaler_desc 5975 */ 5976 static int ia_css_pipe_create_cas_scaler_desc_single_output( 5977 struct ia_css_frame_info *cas_scaler_in_info, 5978 struct ia_css_frame_info *cas_scaler_out_info, 5979 struct ia_css_frame_info *cas_scaler_vf_info, 5980 struct ia_css_cas_binary_descr *descr) 5981 { 5982 unsigned int i; 5983 unsigned int hor_ds_factor = 0, ver_ds_factor = 0; 5984 int err = 0; 5985 struct ia_css_frame_info tmp_in_info; 5986 5987 unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP; 5988 5989 assert(cas_scaler_in_info); 5990 assert(cas_scaler_out_info); 5991 5992 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5993 "ia_css_pipe_create_cas_scaler_desc() enter:\n"); 5994 5995 /* We assume that this function is used only for single output port case. */ 5996 descr->num_output_stage = 1; 5997 5998 hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width, 5999 cas_scaler_out_info->res.width); 6000 ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height, 6001 cas_scaler_out_info->res.height); 6002 /* use the same horizontal and vertical downscaling factor for simplicity */ 6003 assert(hor_ds_factor == ver_ds_factor); 6004 6005 i = 1; 6006 while (i < hor_ds_factor) { 6007 descr->num_stage++; 6008 i *= max_scale_factor_per_stage; 6009 } 6010 6011 descr->in_info = kmalloc(descr->num_stage * 6012 sizeof(struct ia_css_frame_info), 6013 GFP_KERNEL); 6014 if (!descr->in_info) { 6015 err = -ENOMEM; 6016 goto ERR; 6017 } 6018 descr->internal_out_info = kmalloc(descr->num_stage * 6019 sizeof(struct ia_css_frame_info), 6020 GFP_KERNEL); 6021 if (!descr->internal_out_info) { 6022 err = -ENOMEM; 6023 goto ERR; 6024 } 6025 descr->out_info = kmalloc(descr->num_stage * 6026 sizeof(struct ia_css_frame_info), 6027 GFP_KERNEL); 6028 if (!descr->out_info) { 6029 err = -ENOMEM; 6030 goto ERR; 6031 } 6032 descr->vf_info = kmalloc(descr->num_stage * 6033 sizeof(struct ia_css_frame_info), 6034 GFP_KERNEL); 6035 if (!descr->vf_info) { 6036 err = -ENOMEM; 6037 goto ERR; 6038 } 6039 descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), 6040 GFP_KERNEL); 6041 if (!descr->is_output_stage) { 6042 err = -ENOMEM; 6043 goto ERR; 6044 } 6045 6046 tmp_in_info = *cas_scaler_in_info; 6047 for (i = 0; i < descr->num_stage; i++) { 6048 descr->in_info[i] = tmp_in_info; 6049 if ((tmp_in_info.res.width / max_scale_factor_per_stage) <= 6050 cas_scaler_out_info->res.width) { 6051 descr->is_output_stage[i] = true; 6052 if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) { 6053 descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width; 6054 descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height; 6055 descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width; 6056 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6057 } else { 6058 assert(i == (descr->num_stage - 1)); 6059 descr->internal_out_info[i].res.width = 0; 6060 descr->internal_out_info[i].res.height = 0; 6061 } 6062 descr->out_info[i].res.width = cas_scaler_out_info->res.width; 6063 descr->out_info[i].res.height = cas_scaler_out_info->res.height; 6064 descr->out_info[i].padded_width = cas_scaler_out_info->padded_width; 6065 descr->out_info[i].format = cas_scaler_out_info->format; 6066 if (cas_scaler_vf_info) { 6067 descr->vf_info[i].res.width = cas_scaler_vf_info->res.width; 6068 descr->vf_info[i].res.height = cas_scaler_vf_info->res.height; 6069 descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width; 6070 ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE); 6071 } else { 6072 descr->vf_info[i].res.width = 0; 6073 descr->vf_info[i].res.height = 0; 6074 descr->vf_info[i].padded_width = 0; 6075 } 6076 } else { 6077 descr->is_output_stage[i] = false; 6078 descr->internal_out_info[i].res.width = tmp_in_info.res.width / 6079 max_scale_factor_per_stage; 6080 descr->internal_out_info[i].res.height = tmp_in_info.res.height / 6081 max_scale_factor_per_stage; 6082 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6083 ia_css_frame_info_init(&descr->internal_out_info[i], 6084 tmp_in_info.res.width / max_scale_factor_per_stage, 6085 tmp_in_info.res.height / max_scale_factor_per_stage, 6086 IA_CSS_FRAME_FORMAT_YUV420, 0); 6087 descr->out_info[i].res.width = 0; 6088 descr->out_info[i].res.height = 0; 6089 descr->vf_info[i].res.width = 0; 6090 descr->vf_info[i].res.height = 0; 6091 } 6092 tmp_in_info = descr->internal_out_info[i]; 6093 } 6094 ERR: 6095 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6096 "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n", 6097 err); 6098 return err; 6099 } 6100 6101 /* FIXME: merge most of this and single output version */ 6102 static int 6103 ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe, 6104 struct ia_css_cas_binary_descr *descr) 6105 { 6106 struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; 6107 struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6108 struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6109 struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; 6110 unsigned int i, j; 6111 unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE], 6112 ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE], 6113 scale_factor = 0; 6114 unsigned int num_stages = 0; 6115 int err = 0; 6116 6117 unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP; 6118 6119 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6120 "ia_css_pipe_create_cas_scaler_desc() enter:\n"); 6121 6122 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6123 out_info[i] = NULL; 6124 vf_out_info[i] = NULL; 6125 hor_scale_factor[i] = 0; 6126 ver_scale_factor[i] = 0; 6127 } 6128 6129 in_info.res = pipe->config.input_effective_res; 6130 in_info.padded_width = in_info.res.width; 6131 descr->num_output_stage = 0; 6132 /* Find out how much scaling we need for each output */ 6133 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6134 if (pipe->output_info[i].res.width != 0) { 6135 out_info[i] = &pipe->output_info[i]; 6136 if (pipe->vf_output_info[i].res.width != 0) 6137 vf_out_info[i] = &pipe->vf_output_info[i]; 6138 descr->num_output_stage += 1; 6139 } 6140 6141 if (out_info[i]) { 6142 hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width); 6143 ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height); 6144 /* use the same horizontal and vertical scaling factor for simplicity */ 6145 assert(hor_scale_factor[i] == ver_scale_factor[i]); 6146 scale_factor = 1; 6147 do { 6148 num_stages++; 6149 scale_factor *= max_scale_factor_per_stage; 6150 } while (scale_factor < hor_scale_factor[i]); 6151 6152 in_info.res = out_info[i]->res; 6153 } 6154 } 6155 6156 if (need_yuv_scaler_stage(pipe) && (num_stages == 0)) 6157 num_stages = 1; 6158 6159 descr->num_stage = num_stages; 6160 6161 descr->in_info = kmalloc_array(descr->num_stage, 6162 sizeof(struct ia_css_frame_info), 6163 GFP_KERNEL); 6164 if (!descr->in_info) { 6165 err = -ENOMEM; 6166 goto ERR; 6167 } 6168 descr->internal_out_info = kmalloc(descr->num_stage * 6169 sizeof(struct ia_css_frame_info), 6170 GFP_KERNEL); 6171 if (!descr->internal_out_info) { 6172 err = -ENOMEM; 6173 goto ERR; 6174 } 6175 descr->out_info = kmalloc(descr->num_stage * 6176 sizeof(struct ia_css_frame_info), 6177 GFP_KERNEL); 6178 if (!descr->out_info) { 6179 err = -ENOMEM; 6180 goto ERR; 6181 } 6182 descr->vf_info = kmalloc(descr->num_stage * 6183 sizeof(struct ia_css_frame_info), 6184 GFP_KERNEL); 6185 if (!descr->vf_info) { 6186 err = -ENOMEM; 6187 goto ERR; 6188 } 6189 descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), 6190 GFP_KERNEL); 6191 if (!descr->is_output_stage) { 6192 err = -ENOMEM; 6193 goto ERR; 6194 } 6195 6196 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6197 if (out_info[i]) { 6198 if (i > 0) { 6199 assert((out_info[i - 1]->res.width >= out_info[i]->res.width) && 6200 (out_info[i - 1]->res.height >= out_info[i]->res.height)); 6201 } 6202 } 6203 } 6204 6205 tmp_in_info.res = pipe->config.input_effective_res; 6206 tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420; 6207 for (i = 0, j = 0; i < descr->num_stage; i++) { 6208 assert(j < 2); 6209 assert(out_info[j]); 6210 6211 descr->in_info[i] = tmp_in_info; 6212 if ((tmp_in_info.res.width / max_scale_factor_per_stage) <= 6213 out_info[j]->res.width) { 6214 descr->is_output_stage[i] = true; 6215 if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) { 6216 descr->internal_out_info[i].res.width = out_info[j]->res.width; 6217 descr->internal_out_info[i].res.height = out_info[j]->res.height; 6218 descr->internal_out_info[i].padded_width = out_info[j]->padded_width; 6219 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6220 } else { 6221 assert(i == (descr->num_stage - 1)); 6222 descr->internal_out_info[i].res.width = 0; 6223 descr->internal_out_info[i].res.height = 0; 6224 } 6225 descr->out_info[i].res.width = out_info[j]->res.width; 6226 descr->out_info[i].res.height = out_info[j]->res.height; 6227 descr->out_info[i].padded_width = out_info[j]->padded_width; 6228 descr->out_info[i].format = out_info[j]->format; 6229 if (vf_out_info[j]) { 6230 descr->vf_info[i].res.width = vf_out_info[j]->res.width; 6231 descr->vf_info[i].res.height = vf_out_info[j]->res.height; 6232 descr->vf_info[i].padded_width = vf_out_info[j]->padded_width; 6233 ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE); 6234 } else { 6235 descr->vf_info[i].res.width = 0; 6236 descr->vf_info[i].res.height = 0; 6237 descr->vf_info[i].padded_width = 0; 6238 } 6239 j++; 6240 } else { 6241 descr->is_output_stage[i] = false; 6242 descr->internal_out_info[i].res.width = tmp_in_info.res.width / 6243 max_scale_factor_per_stage; 6244 descr->internal_out_info[i].res.height = tmp_in_info.res.height / 6245 max_scale_factor_per_stage; 6246 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6247 ia_css_frame_info_init(&descr->internal_out_info[i], 6248 tmp_in_info.res.width / max_scale_factor_per_stage, 6249 tmp_in_info.res.height / max_scale_factor_per_stage, 6250 IA_CSS_FRAME_FORMAT_YUV420, 0); 6251 descr->out_info[i].res.width = 0; 6252 descr->out_info[i].res.height = 0; 6253 descr->vf_info[i].res.width = 0; 6254 descr->vf_info[i].res.height = 0; 6255 } 6256 tmp_in_info = descr->internal_out_info[i]; 6257 } 6258 ERR: 6259 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6260 "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n", 6261 err); 6262 return err; 6263 } 6264 6265 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr 6266 *descr) 6267 { 6268 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6269 "ia_css_pipe_destroy_cas_scaler_desc() enter:\n"); 6270 kfree(descr->in_info); 6271 descr->in_info = NULL; 6272 kfree(descr->internal_out_info); 6273 descr->internal_out_info = NULL; 6274 kfree(descr->out_info); 6275 descr->out_info = NULL; 6276 kfree(descr->vf_info); 6277 descr->vf_info = NULL; 6278 kfree(descr->is_output_stage); 6279 descr->is_output_stage = NULL; 6280 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6281 "ia_css_pipe_destroy_cas_scaler_desc() leave\n"); 6282 } 6283 6284 static int 6285 load_yuvpp_binaries(struct ia_css_pipe *pipe) 6286 { 6287 int err = 0; 6288 bool need_scaler = false; 6289 struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6290 struct ia_css_yuvpp_settings *mycs; 6291 struct ia_css_binary *next_binary; 6292 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 6293 unsigned int i, j; 6294 bool need_isp_copy_binary = false; 6295 6296 IA_CSS_ENTER_PRIVATE(""); 6297 assert(pipe); 6298 assert(pipe->stream); 6299 assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP); 6300 6301 if (pipe->pipe_settings.yuvpp.copy_binary.info) 6302 goto ERR; 6303 6304 /* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */ 6305 err = ia_css_util_check_input(&pipe->stream->config, false, false); 6306 if (err) 6307 goto ERR; 6308 6309 mycs = &pipe->pipe_settings.yuvpp; 6310 6311 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6312 if (pipe->vf_output_info[i].res.width != 0) { 6313 err = ia_css_util_check_vf_out_info(&pipe->output_info[i], 6314 &pipe->vf_output_info[i]); 6315 if (err) 6316 goto ERR; 6317 } 6318 vf_pp_in_info[i] = NULL; 6319 } 6320 6321 need_scaler = need_yuv_scaler_stage(pipe); 6322 6323 /* we build up the pipeline starting at the end */ 6324 /* Capture post-processing */ 6325 if (need_scaler) { 6326 struct ia_css_binary_descr yuv_scaler_descr; 6327 6328 err = ia_css_pipe_create_cas_scaler_desc(pipe, 6329 &cas_scaler_descr); 6330 if (err) 6331 goto ERR; 6332 mycs->num_output = cas_scaler_descr.num_output_stage; 6333 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 6334 mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, 6335 sizeof(struct ia_css_binary), 6336 GFP_KERNEL); 6337 if (!mycs->yuv_scaler_binary) { 6338 err = -ENOMEM; 6339 goto ERR; 6340 } 6341 mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, 6342 sizeof(bool), GFP_KERNEL); 6343 if (!mycs->is_output_stage) { 6344 err = -ENOMEM; 6345 goto ERR; 6346 } 6347 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 6348 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 6349 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 6350 &yuv_scaler_descr, 6351 &cas_scaler_descr.in_info[i], 6352 &cas_scaler_descr.out_info[i], 6353 &cas_scaler_descr.internal_out_info[i], 6354 &cas_scaler_descr.vf_info[i]); 6355 err = ia_css_binary_find(&yuv_scaler_descr, 6356 &mycs->yuv_scaler_binary[i]); 6357 if (err) 6358 goto ERR; 6359 } 6360 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 6361 } else { 6362 mycs->num_output = 1; 6363 } 6364 6365 if (need_scaler) 6366 next_binary = &mycs->yuv_scaler_binary[0]; 6367 else 6368 next_binary = NULL; 6369 6370 /* 6371 * NOTES 6372 * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when 6373 * its input is "ATOMISP_INPUT_FORMAT_YUV422_8"? 6374 * 6375 * In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_ 6376 * binary". However, the "yuv_scale_binary" does NOT support the input-frame 6377 * format as "IA_CSS_STREAM _FORMAT_YUV422_8". 6378 * 6379 * Hence, the "isp_copy_binary" is required to be present in front of the "yuv 6380 * _scale_binary". It would translate the input-frame to the frame formats that 6381 * are supported by the "yuv_scale_binary". 6382 * 6383 * Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_ 6384 * pp_defs.h" for the list of input-frame formats that are supported by the 6385 * "yuv_scale_binary". 6386 */ 6387 if (IS_ISP2401) 6388 need_isp_copy_binary = 6389 (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8); 6390 else 6391 need_isp_copy_binary = true; 6392 6393 if (need_isp_copy_binary) { 6394 err = load_copy_binary(pipe, 6395 &mycs->copy_binary, 6396 next_binary); 6397 6398 if (err) 6399 goto ERR; 6400 6401 /* 6402 * NOTES 6403 * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified? 6404 * 6405 * In some use cases, the first stage in the "yuvpp" pipe is the 6406 * "isp_copy_binary". The "isp_copy_binary" is designed to process 6407 * the input from either the system DDR or from the IPU internal VMEM. 6408 * So it provides the flag "online" to specify where its input is from, 6409 * i.e.: 6410 * 6411 * (1) "online <= true", the input is from the IPU internal VMEM. 6412 * (2) "online <= false", the input is from the system DDR. 6413 * 6414 * In other use cases, the first stage in the "yuvpp" pipe is the 6415 * "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the 6416 * input ONLY from the system DDR. So it does not provide the flag "online" 6417 * to specify where its input is from. 6418 */ 6419 pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online; 6420 } 6421 6422 /* Viewfinder post-processing */ 6423 if (need_scaler) { 6424 for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) { 6425 if (mycs->is_output_stage[i]) { 6426 assert(j < 2); 6427 vf_pp_in_info[j] = 6428 &mycs->yuv_scaler_binary[i].vf_frame_info; 6429 j++; 6430 } 6431 } 6432 mycs->num_vf_pp = j; 6433 } else { 6434 vf_pp_in_info[0] = 6435 &mycs->copy_binary.vf_frame_info; 6436 for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) 6437 vf_pp_in_info[i] = NULL; 6438 6439 mycs->num_vf_pp = 1; 6440 } 6441 mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp, 6442 sizeof(struct ia_css_binary), 6443 GFP_KERNEL); 6444 if (!mycs->vf_pp_binary) { 6445 err = -ENOMEM; 6446 goto ERR; 6447 } 6448 6449 { 6450 struct ia_css_binary_descr vf_pp_descr; 6451 6452 for (i = 0; i < mycs->num_vf_pp; i++) { 6453 if (pipe->vf_output_info[i].res.width != 0) { 6454 ia_css_pipe_get_vfpp_binarydesc(pipe, 6455 &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]); 6456 err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]); 6457 if (err) 6458 goto ERR; 6459 } 6460 } 6461 } 6462 6463 if (err) 6464 goto ERR; 6465 6466 ERR: 6467 if (need_scaler) 6468 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 6469 6470 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n", 6471 err); 6472 return err; 6473 } 6474 6475 static int 6476 unload_yuvpp_binaries(struct ia_css_pipe *pipe) 6477 { 6478 unsigned int i; 6479 6480 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 6481 6482 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 6483 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 6484 return -EINVAL; 6485 } 6486 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary); 6487 for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++) 6488 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]); 6489 6490 for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++) 6491 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]); 6492 6493 kfree(pipe->pipe_settings.yuvpp.is_output_stage); 6494 pipe->pipe_settings.yuvpp.is_output_stage = NULL; 6495 kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary); 6496 pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL; 6497 kfree(pipe->pipe_settings.yuvpp.vf_pp_binary); 6498 pipe->pipe_settings.yuvpp.vf_pp_binary = NULL; 6499 6500 IA_CSS_LEAVE_ERR_PRIVATE(0); 6501 return 0; 6502 } 6503 6504 static int yuvpp_start(struct ia_css_pipe *pipe) 6505 { 6506 int err = 0; 6507 enum sh_css_pipe_config_override copy_ovrd; 6508 enum ia_css_input_mode yuvpp_pipe_input_mode; 6509 unsigned int thread_id; 6510 6511 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 6512 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 6513 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 6514 return -EINVAL; 6515 } 6516 6517 yuvpp_pipe_input_mode = pipe->stream->config.mode; 6518 6519 sh_css_metrics_start_frame(); 6520 6521 /* multi stream video needs mipi buffers */ 6522 6523 err = send_mipi_frames(pipe); 6524 if (err) { 6525 IA_CSS_LEAVE_ERR_PRIVATE(err); 6526 return err; 6527 } 6528 6529 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 6530 copy_ovrd = 1 << thread_id; 6531 6532 start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode); 6533 6534 IA_CSS_LEAVE_ERR_PRIVATE(err); 6535 return err; 6536 } 6537 6538 static int 6539 sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) 6540 { 6541 int err = 0; 6542 6543 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 6544 6545 if (!pipe) { 6546 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 6547 return -EINVAL; 6548 } 6549 /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/ 6550 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) { 6551 IA_CSS_LEAVE_ERR_PRIVATE(0); 6552 return 0; 6553 } 6554 6555 switch (pipe->mode) { 6556 case IA_CSS_PIPE_ID_PREVIEW: 6557 err = unload_preview_binaries(pipe); 6558 break; 6559 case IA_CSS_PIPE_ID_VIDEO: 6560 err = unload_video_binaries(pipe); 6561 break; 6562 case IA_CSS_PIPE_ID_CAPTURE: 6563 err = unload_capture_binaries(pipe); 6564 break; 6565 case IA_CSS_PIPE_ID_YUVPP: 6566 err = unload_yuvpp_binaries(pipe); 6567 break; 6568 default: 6569 break; 6570 } 6571 IA_CSS_LEAVE_ERR_PRIVATE(err); 6572 return err; 6573 } 6574 6575 static int 6576 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) 6577 { 6578 int err = 0; 6579 6580 assert(pipe); 6581 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n"); 6582 6583 /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/ 6584 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) 6585 return err; 6586 6587 switch (pipe->mode) { 6588 case IA_CSS_PIPE_ID_PREVIEW: 6589 err = load_preview_binaries(pipe); 6590 break; 6591 case IA_CSS_PIPE_ID_VIDEO: 6592 err = load_video_binaries(pipe); 6593 break; 6594 case IA_CSS_PIPE_ID_CAPTURE: 6595 err = load_capture_binaries(pipe); 6596 break; 6597 case IA_CSS_PIPE_ID_YUVPP: 6598 err = load_yuvpp_binaries(pipe); 6599 break; 6600 default: 6601 err = -EINVAL; 6602 break; 6603 } 6604 if (err) { 6605 if (sh_css_pipe_unload_binaries(pipe)) { 6606 /* 6607 * currently css does not support multiple error 6608 * returns in a single function, using -EINVAL in 6609 * this case 6610 */ 6611 err = -EINVAL; 6612 } 6613 } 6614 return err; 6615 } 6616 6617 static int 6618 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) 6619 { 6620 struct ia_css_pipeline *me; 6621 int err = 0; 6622 struct ia_css_pipeline_stage *vf_pp_stage = NULL, 6623 *copy_stage = NULL, 6624 *yuv_scaler_stage = NULL; 6625 struct ia_css_binary *copy_binary, 6626 *vf_pp_binary, 6627 *yuv_scaler_binary; 6628 bool need_scaler = false; 6629 unsigned int num_stage, num_output_stage; 6630 unsigned int i, j; 6631 6632 struct ia_css_frame *in_frame = NULL; 6633 struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6634 struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 6635 struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6636 struct ia_css_pipeline_stage_desc stage_desc; 6637 bool need_in_frameinfo_memory = false; 6638 bool sensor = false; 6639 bool buffered_sensor = false; 6640 bool online = false; 6641 bool continuous = false; 6642 6643 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 6644 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 6645 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 6646 return -EINVAL; 6647 } 6648 me = &pipe->pipeline; 6649 ia_css_pipeline_clean(me); 6650 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6651 out_frame[i] = NULL; 6652 vf_frame[i] = NULL; 6653 } 6654 ia_css_pipe_util_create_output_frames(bin_out_frame); 6655 num_stage = pipe->pipe_settings.yuvpp.num_yuv_scaler; 6656 num_output_stage = pipe->pipe_settings.yuvpp.num_output; 6657 6658 if (IS_ISP2401) { 6659 /* 6660 * When the input system is 2401, always enable 'in_frameinfo_memory' 6661 * except for the following: 6662 * - Direct Sensor Mode Online Capture 6663 * - Direct Sensor Mode Continuous Capture 6664 * - Buffered Sensor Mode Continuous Capture 6665 */ 6666 sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 6667 buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR; 6668 online = pipe->stream->config.online; 6669 continuous = pipe->stream->config.continuous; 6670 need_in_frameinfo_memory = 6671 !((sensor && (online || continuous)) || (buffered_sensor && continuous)); 6672 } else { 6673 /* Construct in_frame info (only in case we have dynamic input */ 6674 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 6675 } 6676 /* 6677 * the input frame can come from: 6678 * 6679 * a) memory: connect yuvscaler to me->in_frame 6680 * b) sensor, via copy binary: connect yuvscaler to copy binary later 6681 * on 6682 */ 6683 if (need_in_frameinfo_memory) { 6684 /* TODO: improve for different input formats. */ 6685 6686 /* 6687 * "pipe->stream->config.input_config.format" represents the sensor output 6688 * frame format, e.g. YUV422 8-bit. 6689 * 6690 * "in_frame_format" represents the imaging pipe's input frame format, e.g. 6691 * Bayer-Quad RAW. 6692 */ 6693 int in_frame_format; 6694 6695 if (pipe->stream->config.input_config.format == 6696 ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) { 6697 in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8; 6698 } else if (pipe->stream->config.input_config.format == 6699 ATOMISP_INPUT_FORMAT_YUV422_8) { 6700 /* 6701 * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8", 6702 * the "isp_copy_var" binary is selected as the first stage in the yuvpp 6703 * pipe. 6704 * 6705 * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from 6706 * the frame buffer (at DDR) to the frame-line buffer (at VMEM). 6707 * 6708 * By now, the "isp_copy_var" binary does NOT provide a separated 6709 * frame-line buffer to store the YUV422-8 pixels. Instead, it stores 6710 * the YUV422-8 pixels in the frame-line buffer which is designed to 6711 * store the Bayer-Quad RAW pixels. 6712 * 6713 * To direct the "isp_copy_var" binary reading from the RAW frame-line 6714 * buffer, its input frame format must be specified as "IA_CSS_FRAME_ 6715 * FORMAT_RAW". 6716 */ 6717 in_frame_format = IA_CSS_FRAME_FORMAT_RAW; 6718 } else { 6719 in_frame_format = IA_CSS_FRAME_FORMAT_NV12; 6720 } 6721 6722 err = init_in_frameinfo_memory_defaults(pipe, 6723 &me->in_frame, 6724 in_frame_format); 6725 6726 if (err) { 6727 IA_CSS_LEAVE_ERR_PRIVATE(err); 6728 return err; 6729 } 6730 6731 in_frame = &me->in_frame; 6732 } else { 6733 in_frame = NULL; 6734 } 6735 6736 for (i = 0; i < num_output_stage; i++) { 6737 assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE); 6738 if (pipe->output_info[i].res.width != 0) { 6739 err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i); 6740 if (err) { 6741 IA_CSS_LEAVE_ERR_PRIVATE(err); 6742 return err; 6743 } 6744 out_frame[i] = &me->out_frame[i]; 6745 } 6746 6747 /* Construct vf_frame info (only in case we have VF) */ 6748 if (pipe->vf_output_info[i].res.width != 0) { 6749 err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i); 6750 if (err) { 6751 IA_CSS_LEAVE_ERR_PRIVATE(err); 6752 return err; 6753 } 6754 vf_frame[i] = &me->vf_frame[i]; 6755 } 6756 } 6757 6758 copy_binary = &pipe->pipe_settings.yuvpp.copy_binary; 6759 vf_pp_binary = pipe->pipe_settings.yuvpp.vf_pp_binary; 6760 yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary; 6761 need_scaler = need_yuv_scaler_stage(pipe); 6762 6763 if (pipe->pipe_settings.yuvpp.copy_binary.info) { 6764 struct ia_css_frame *in_frame_local = NULL; 6765 6766 if (IS_ISP2401 && !online) { 6767 /* After isp copy is enabled in_frame needs to be passed. */ 6768 in_frame_local = in_frame; 6769 } 6770 6771 if (need_scaler) { 6772 ia_css_pipe_util_set_output_frames(bin_out_frame, 6773 0, NULL); 6774 ia_css_pipe_get_generic_stage_desc(&stage_desc, 6775 copy_binary, 6776 bin_out_frame, 6777 in_frame_local, 6778 NULL); 6779 } else { 6780 ia_css_pipe_util_set_output_frames(bin_out_frame, 6781 0, out_frame[0]); 6782 ia_css_pipe_get_generic_stage_desc(&stage_desc, 6783 copy_binary, 6784 bin_out_frame, 6785 in_frame_local, 6786 NULL); 6787 } 6788 6789 err = ia_css_pipeline_create_and_add_stage(me, 6790 &stage_desc, 6791 ©_stage); 6792 6793 if (err) { 6794 IA_CSS_LEAVE_ERR_PRIVATE(err); 6795 return err; 6796 } 6797 6798 if (copy_stage) { 6799 /* if we use yuv scaler binary, vf output should be from there */ 6800 copy_stage->args.copy_vf = !need_scaler; 6801 /* for yuvpp pipe, it should always be enabled */ 6802 copy_stage->args.copy_output = true; 6803 /* connect output of copy binary to input of yuv scaler */ 6804 in_frame = copy_stage->args.out_frame[0]; 6805 } 6806 } 6807 6808 if (need_scaler) { 6809 struct ia_css_frame *tmp_out_frame = NULL; 6810 struct ia_css_frame *tmp_vf_frame = NULL; 6811 struct ia_css_frame *tmp_in_frame = in_frame; 6812 6813 for (i = 0, j = 0; i < num_stage; i++) { 6814 assert(j < num_output_stage); 6815 if (pipe->pipe_settings.yuvpp.is_output_stage[i]) { 6816 tmp_out_frame = out_frame[j]; 6817 tmp_vf_frame = vf_frame[j]; 6818 } else { 6819 tmp_out_frame = NULL; 6820 tmp_vf_frame = NULL; 6821 } 6822 6823 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 6824 tmp_out_frame, 6825 NULL, 6826 &yuv_scaler_binary[i], 6827 &yuv_scaler_stage); 6828 6829 if (err) { 6830 IA_CSS_LEAVE_ERR_PRIVATE(err); 6831 return err; 6832 } 6833 /* we use output port 1 as internal output port */ 6834 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 6835 if (pipe->pipe_settings.yuvpp.is_output_stage[i]) { 6836 if (tmp_vf_frame && (tmp_vf_frame->frame_info.res.width != 0)) { 6837 in_frame = yuv_scaler_stage->args.out_vf_frame; 6838 err = add_vf_pp_stage(pipe, in_frame, 6839 tmp_vf_frame, 6840 &vf_pp_binary[j], 6841 &vf_pp_stage); 6842 6843 if (err) { 6844 IA_CSS_LEAVE_ERR_PRIVATE(err); 6845 return err; 6846 } 6847 } 6848 j++; 6849 } 6850 } 6851 } else if (copy_stage) { 6852 if (vf_frame[0] && vf_frame[0]->frame_info.res.width != 0) { 6853 in_frame = copy_stage->args.out_vf_frame; 6854 err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], 6855 &vf_pp_binary[0], &vf_pp_stage); 6856 } 6857 if (err) { 6858 IA_CSS_LEAVE_ERR_PRIVATE(err); 6859 return err; 6860 } 6861 } 6862 6863 ia_css_pipeline_finalize_stages(&pipe->pipeline, 6864 pipe->stream->config.continuous); 6865 6866 IA_CSS_LEAVE_ERR_PRIVATE(0); 6867 6868 return 0; 6869 } 6870 6871 static int 6872 create_host_copy_pipeline(struct ia_css_pipe *pipe, 6873 unsigned int max_input_width, 6874 struct ia_css_frame *out_frame) 6875 { 6876 struct ia_css_pipeline *me; 6877 int err = 0; 6878 struct ia_css_pipeline_stage_desc stage_desc; 6879 6880 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6881 "create_host_copy_pipeline() enter:\n"); 6882 6883 /* pipeline already created as part of create_host_pipeline_structure */ 6884 me = &pipe->pipeline; 6885 ia_css_pipeline_clean(me); 6886 6887 /* Construct out_frame info */ 6888 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 6889 6890 if (copy_on_sp(pipe) && 6891 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 6892 ia_css_frame_info_init(&out_frame->frame_info, JPEG_BYTES, 1, 6893 IA_CSS_FRAME_FORMAT_BINARY_8, 0); 6894 } else if (out_frame->frame_info.format == IA_CSS_FRAME_FORMAT_RAW) { 6895 out_frame->frame_info.raw_bit_depth = 6896 ia_css_pipe_util_pipe_input_format_bpp(pipe); 6897 } 6898 6899 me->num_stages = 1; 6900 me->pipe_id = IA_CSS_PIPE_ID_COPY; 6901 pipe->mode = IA_CSS_PIPE_ID_COPY; 6902 6903 ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, 6904 IA_CSS_PIPELINE_RAW_COPY, 6905 max_input_width); 6906 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL); 6907 6908 ia_css_pipeline_finalize_stages(&pipe->pipeline, 6909 pipe->stream->config.continuous); 6910 6911 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6912 "create_host_copy_pipeline() leave:\n"); 6913 6914 return err; 6915 } 6916 6917 static int 6918 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) 6919 { 6920 struct ia_css_pipeline *me = &pipe->pipeline; 6921 int err = 0; 6922 struct ia_css_pipeline_stage_desc stage_desc; 6923 struct ia_css_frame *out_frame = &me->out_frame[0]; 6924 struct ia_css_pipeline_stage *out_stage = NULL; 6925 unsigned int thread_id; 6926 enum sh_css_queue_id queue_id; 6927 unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS; 6928 6929 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6930 "create_host_isyscopy_capture_pipeline() enter:\n"); 6931 ia_css_pipeline_clean(me); 6932 6933 /* Construct out_frame info */ 6934 err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->frame_info, 0); 6935 if (err) 6936 return err; 6937 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 6938 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 6939 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id); 6940 out_frame->dynamic_queue_id = queue_id; 6941 out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME; 6942 6943 me->num_stages = 1; 6944 me->pipe_id = IA_CSS_PIPE_ID_CAPTURE; 6945 pipe->mode = IA_CSS_PIPE_ID_CAPTURE; 6946 ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, 6947 IA_CSS_PIPELINE_ISYS_COPY, 6948 max_input_width); 6949 err = ia_css_pipeline_create_and_add_stage(me, 6950 &stage_desc, &out_stage); 6951 if (err) 6952 return err; 6953 6954 ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous); 6955 6956 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6957 "create_host_isyscopy_capture_pipeline() leave:\n"); 6958 6959 return err; 6960 } 6961 6962 static int 6963 create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) 6964 { 6965 struct ia_css_pipeline *me; 6966 int err = 0; 6967 enum ia_css_capture_mode mode; 6968 struct ia_css_pipeline_stage *current_stage = NULL; 6969 struct ia_css_pipeline_stage *yuv_scaler_stage = NULL; 6970 struct ia_css_binary *copy_binary, 6971 *primary_binary[MAX_NUM_PRIMARY_STAGES], 6972 *vf_pp_binary, 6973 *pre_isp_binary, 6974 *anr_gdc_binary, 6975 *post_isp_binary, 6976 *yuv_scaler_binary, 6977 *capture_pp_binary, 6978 *capture_ldc_binary; 6979 bool need_pp = false; 6980 bool raw; 6981 6982 struct ia_css_frame *in_frame; 6983 struct ia_css_frame *out_frame; 6984 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 6985 struct ia_css_frame *vf_frame; 6986 struct ia_css_pipeline_stage_desc stage_desc; 6987 bool need_in_frameinfo_memory = false; 6988 bool sensor = false; 6989 bool buffered_sensor = false; 6990 bool online = false; 6991 bool continuous = false; 6992 unsigned int i, num_yuv_scaler, num_primary_stage; 6993 bool need_yuv_pp = false; 6994 bool *is_output_stage = NULL; 6995 bool need_ldc = false; 6996 6997 IA_CSS_ENTER_PRIVATE(""); 6998 assert(pipe); 6999 assert(pipe->stream); 7000 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 7001 pipe->mode == IA_CSS_PIPE_ID_COPY); 7002 7003 me = &pipe->pipeline; 7004 mode = pipe->config.default_capture_config.mode; 7005 raw = (mode == IA_CSS_CAPTURE_MODE_RAW); 7006 ia_css_pipeline_clean(me); 7007 ia_css_pipe_util_create_output_frames(out_frames); 7008 7009 if (IS_ISP2401) { 7010 /* 7011 * When the input system is 2401, always enable 'in_frameinfo_memory' 7012 * except for the following: 7013 * - Direct Sensor Mode Online Capture 7014 * - Direct Sensor Mode Online Capture 7015 * - Direct Sensor Mode Continuous Capture 7016 * - Buffered Sensor Mode Continuous Capture 7017 */ 7018 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 7019 buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 7020 online = pipe->stream->config.online; 7021 continuous = pipe->stream->config.continuous; 7022 need_in_frameinfo_memory = 7023 !((sensor && (online || continuous)) || (buffered_sensor && 7024 (online || continuous))); 7025 } else { 7026 /* Construct in_frame info (only in case we have dynamic input */ 7027 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 7028 } 7029 7030 if (need_in_frameinfo_memory) { 7031 err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, 7032 IA_CSS_FRAME_FORMAT_RAW); 7033 if (err) { 7034 IA_CSS_LEAVE_ERR_PRIVATE(err); 7035 return err; 7036 } 7037 7038 in_frame = &me->in_frame; 7039 } else { 7040 in_frame = NULL; 7041 } 7042 7043 err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0); 7044 if (err) { 7045 IA_CSS_LEAVE_ERR_PRIVATE(err); 7046 return err; 7047 } 7048 out_frame = &me->out_frame[0]; 7049 7050 /* Construct vf_frame info (only in case we have VF) */ 7051 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 7052 if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) { 7053 /* These modes don't support viewfinder output */ 7054 vf_frame = NULL; 7055 } else { 7056 init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0); 7057 vf_frame = &me->vf_frame[0]; 7058 } 7059 } else { 7060 vf_frame = NULL; 7061 } 7062 7063 copy_binary = &pipe->pipe_settings.capture.copy_binary; 7064 num_primary_stage = pipe->pipe_settings.capture.num_primary_stage; 7065 if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) { 7066 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7067 return -EINVAL; 7068 } 7069 7070 for (i = 0; i < num_primary_stage; i++) 7071 primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i]; 7072 7073 vf_pp_binary = &pipe->pipe_settings.capture.vf_pp_binary; 7074 pre_isp_binary = &pipe->pipe_settings.capture.pre_isp_binary; 7075 anr_gdc_binary = &pipe->pipe_settings.capture.anr_gdc_binary; 7076 post_isp_binary = &pipe->pipe_settings.capture.post_isp_binary; 7077 capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary; 7078 yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary; 7079 num_yuv_scaler = pipe->pipe_settings.capture.num_yuv_scaler; 7080 is_output_stage = pipe->pipe_settings.capture.is_output_stage; 7081 capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary; 7082 7083 need_pp = (need_capture_pp(pipe) || pipe->output_stage) && 7084 mode != IA_CSS_CAPTURE_MODE_RAW && 7085 mode != IA_CSS_CAPTURE_MODE_BAYER; 7086 need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info); 7087 need_ldc = (capture_ldc_binary && capture_ldc_binary->info); 7088 7089 if (pipe->pipe_settings.capture.copy_binary.info) { 7090 if (raw) { 7091 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 7092 if (IS_ISP2401) { 7093 if (!continuous) { 7094 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7095 copy_binary, 7096 out_frames, 7097 in_frame, 7098 NULL); 7099 } else { 7100 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 7101 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7102 copy_binary, 7103 out_frames, 7104 in_frame, 7105 NULL); 7106 } 7107 } else { 7108 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7109 copy_binary, 7110 out_frames, 7111 NULL, NULL); 7112 } 7113 } else { 7114 ia_css_pipe_util_set_output_frames(out_frames, 0, 7115 in_frame); 7116 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7117 copy_binary, 7118 out_frames, 7119 NULL, NULL); 7120 } 7121 7122 err = ia_css_pipeline_create_and_add_stage(me, 7123 &stage_desc, 7124 ¤t_stage); 7125 if (err) { 7126 IA_CSS_LEAVE_ERR_PRIVATE(err); 7127 return err; 7128 } 7129 } else if (pipe->stream->config.continuous) { 7130 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 7131 } 7132 7133 if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 7134 struct ia_css_frame *local_in_frame = NULL; 7135 struct ia_css_frame *local_out_frame = NULL; 7136 7137 for (i = 0; i < num_primary_stage; i++) { 7138 if (i == 0) 7139 local_in_frame = in_frame; 7140 else 7141 local_in_frame = NULL; 7142 if (!need_pp && (i == num_primary_stage - 1) && (!IS_ISP2401 || !need_ldc)) 7143 local_out_frame = out_frame; 7144 else 7145 local_out_frame = NULL; 7146 ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame); 7147 /* 7148 * WARNING: The #if def flag has been added below as a 7149 * temporary solution to solve the problem of enabling the 7150 * view finder in a single binary in a capture flow. The 7151 * vf-pp stage has been removed from Skycam in the solution 7152 * provided. The vf-pp stage should be re-introduced when 7153 * required. This * should not be considered as a clean solution. 7154 * Proper investigation should be done to come up with the clean 7155 * solution. 7156 */ 7157 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7158 primary_binary[i], 7159 out_frames, 7160 local_in_frame, 7161 NULL); 7162 err = ia_css_pipeline_create_and_add_stage(me, 7163 &stage_desc, 7164 ¤t_stage); 7165 if (err) { 7166 IA_CSS_LEAVE_ERR_PRIVATE(err); 7167 return err; 7168 } 7169 } 7170 /* If we use copy iso primary, the input must be yuv iso raw */ 7171 current_stage->args.copy_vf = 7172 primary_binary[0]->info->sp.pipeline.mode == 7173 IA_CSS_BINARY_MODE_COPY; 7174 current_stage->args.copy_output = current_stage->args.copy_vf; 7175 } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED || 7176 mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 7177 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7178 ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, 7179 out_frames, in_frame, NULL); 7180 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7181 NULL); 7182 if (err) { 7183 IA_CSS_LEAVE_ERR_PRIVATE(err); 7184 return err; 7185 } 7186 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7187 ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary, 7188 out_frames, NULL, NULL); 7189 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7190 NULL); 7191 if (err) { 7192 IA_CSS_LEAVE_ERR_PRIVATE(err); 7193 return err; 7194 } 7195 7196 if (need_pp) { 7197 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7198 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7199 post_isp_binary, 7200 out_frames, 7201 NULL, NULL); 7202 } else { 7203 ia_css_pipe_util_set_output_frames(out_frames, 0, 7204 out_frame); 7205 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7206 post_isp_binary, 7207 out_frames, 7208 NULL, NULL); 7209 } 7210 7211 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7212 ¤t_stage); 7213 if (err) { 7214 IA_CSS_LEAVE_ERR_PRIVATE(err); 7215 return err; 7216 } 7217 } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) { 7218 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 7219 ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, 7220 out_frames, in_frame, NULL); 7221 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7222 NULL); 7223 if (err) { 7224 IA_CSS_LEAVE_ERR_PRIVATE(err); 7225 return err; 7226 } 7227 } 7228 7229 if (need_pp && current_stage) { 7230 struct ia_css_frame *local_in_frame = NULL; 7231 7232 local_in_frame = current_stage->args.out_frame[0]; 7233 7234 if (need_ldc) { 7235 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7236 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7237 capture_ldc_binary, 7238 out_frames, 7239 local_in_frame, 7240 NULL); 7241 err = ia_css_pipeline_create_and_add_stage(me, 7242 &stage_desc, 7243 ¤t_stage); 7244 local_in_frame = current_stage->args.out_frame[0]; 7245 } 7246 err = add_capture_pp_stage(pipe, me, local_in_frame, 7247 need_yuv_pp ? NULL : out_frame, 7248 capture_pp_binary, 7249 ¤t_stage); 7250 if (err) { 7251 IA_CSS_LEAVE_ERR_PRIVATE(err); 7252 return err; 7253 } 7254 } 7255 7256 if (need_yuv_pp && current_stage) { 7257 struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0]; 7258 struct ia_css_frame *tmp_out_frame = NULL; 7259 7260 for (i = 0; i < num_yuv_scaler; i++) { 7261 if (is_output_stage[i]) 7262 tmp_out_frame = out_frame; 7263 else 7264 tmp_out_frame = NULL; 7265 7266 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 7267 tmp_out_frame, NULL, 7268 &yuv_scaler_binary[i], 7269 &yuv_scaler_stage); 7270 if (err) { 7271 IA_CSS_LEAVE_ERR_PRIVATE(err); 7272 return err; 7273 } 7274 /* we use output port 1 as internal output port */ 7275 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 7276 } 7277 } 7278 7279 /* 7280 * WARNING: The #if def flag has been added below as a 7281 * temporary solution to solve the problem of enabling the 7282 * view finder in a single binary in a capture flow. The vf-pp 7283 * stage has been removed from Skycam in the solution provided. 7284 * The vf-pp stage should be re-introduced when required. This 7285 * should not be considered as a clean solution. Proper 7286 * investigation should be done to come up with the clean solution. 7287 */ 7288 if (mode != IA_CSS_CAPTURE_MODE_RAW && 7289 mode != IA_CSS_CAPTURE_MODE_BAYER && 7290 current_stage && vf_frame) { 7291 in_frame = current_stage->args.out_vf_frame; 7292 err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary, 7293 ¤t_stage); 7294 if (err) { 7295 IA_CSS_LEAVE_ERR_PRIVATE(err); 7296 return err; 7297 } 7298 } 7299 ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); 7300 7301 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7302 "create_host_regular_capture_pipeline() leave:\n"); 7303 7304 return 0; 7305 } 7306 7307 static int 7308 create_host_capture_pipeline(struct ia_css_pipe *pipe) 7309 { 7310 int err = 0; 7311 7312 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7313 7314 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) 7315 err = create_host_isyscopy_capture_pipeline(pipe); 7316 else 7317 err = create_host_regular_capture_pipeline(pipe); 7318 if (err) { 7319 IA_CSS_LEAVE_ERR_PRIVATE(err); 7320 return err; 7321 } 7322 7323 IA_CSS_LEAVE_ERR_PRIVATE(err); 7324 7325 return err; 7326 } 7327 7328 static int capture_start(struct ia_css_pipe *pipe) 7329 { 7330 struct ia_css_pipeline *me; 7331 unsigned int thread_id; 7332 7333 int err = 0; 7334 enum sh_css_pipe_config_override copy_ovrd; 7335 7336 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7337 if (!pipe) { 7338 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7339 return -EINVAL; 7340 } 7341 7342 me = &pipe->pipeline; 7343 7344 if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW || 7345 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) && 7346 (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) { 7347 if (copy_on_sp(pipe)) { 7348 err = start_copy_on_sp(pipe, &me->out_frame[0]); 7349 IA_CSS_LEAVE_ERR_PRIVATE(err); 7350 return err; 7351 } 7352 } 7353 /* old isys: need to send_mipi_frames() in all pipe modes */ 7354 if (!IS_ISP2401 || pipe->config.mode != IA_CSS_PIPE_MODE_COPY) { 7355 err = send_mipi_frames(pipe); 7356 if (err) { 7357 IA_CSS_LEAVE_ERR_PRIVATE(err); 7358 return err; 7359 } 7360 } 7361 7362 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 7363 copy_ovrd = 1 << thread_id; 7364 7365 start_pipe(pipe, copy_ovrd, pipe->stream->config.mode); 7366 7367 /* 7368 * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured, 7369 * which is currently done in start_binary(); but COPY pipe contains no binary, 7370 * and does not call start_binary(); so we need to configure the rx here. 7371 */ 7372 if (!IS_ISP2401 && 7373 pipe->config.mode == IA_CSS_PIPE_MODE_COPY && 7374 pipe->stream->reconfigure_css_rx) { 7375 ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, 7376 pipe->stream->config.mode); 7377 pipe->stream->reconfigure_css_rx = false; 7378 } 7379 7380 IA_CSS_LEAVE_ERR_PRIVATE(err); 7381 return err; 7382 } 7383 7384 static int 7385 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, 7386 struct ia_css_frame_info *info, 7387 unsigned int idx) 7388 { 7389 assert(pipe); 7390 assert(info); 7391 7392 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7393 "sh_css_pipe_get_output_frame_info() enter:\n"); 7394 7395 *info = pipe->output_info[idx]; 7396 if (copy_on_sp(pipe) && 7397 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 7398 ia_css_frame_info_init( 7399 info, 7400 JPEG_BYTES, 7401 1, 7402 IA_CSS_FRAME_FORMAT_BINARY_8, 7403 0); 7404 } else if (info->format == IA_CSS_FRAME_FORMAT_RAW || 7405 info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) { 7406 info->raw_bit_depth = 7407 ia_css_pipe_util_pipe_input_format_bpp(pipe); 7408 } 7409 7410 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7411 "sh_css_pipe_get_output_frame_info() leave:\n"); 7412 return 0; 7413 } 7414 7415 void 7416 ia_css_stream_send_input_frame(const struct ia_css_stream *stream, 7417 const unsigned short *data, 7418 unsigned int width, 7419 unsigned int height) 7420 { 7421 assert(stream); 7422 7423 ia_css_inputfifo_send_input_frame( 7424 data, width, height, 7425 stream->config.channel_id, 7426 stream->config.input_config.format, 7427 stream->config.pixels_per_clock == 2); 7428 } 7429 7430 void 7431 ia_css_stream_start_input_frame(const struct ia_css_stream *stream) 7432 { 7433 assert(stream); 7434 7435 ia_css_inputfifo_start_frame( 7436 stream->config.channel_id, 7437 stream->config.input_config.format, 7438 stream->config.pixels_per_clock == 2); 7439 } 7440 7441 void 7442 ia_css_stream_send_input_line(const struct ia_css_stream *stream, 7443 const unsigned short *data, 7444 unsigned int width, 7445 const unsigned short *data2, 7446 unsigned int width2) 7447 { 7448 assert(stream); 7449 7450 ia_css_inputfifo_send_line(stream->config.channel_id, 7451 data, width, data2, width2); 7452 } 7453 7454 void 7455 ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream, 7456 enum atomisp_input_format format, 7457 const unsigned short *data, 7458 unsigned int width) 7459 { 7460 assert(stream); 7461 if (!data || width == 0) 7462 return; 7463 ia_css_inputfifo_send_embedded_line(stream->config.channel_id, 7464 format, data, width); 7465 } 7466 7467 void 7468 ia_css_stream_end_input_frame(const struct ia_css_stream *stream) 7469 { 7470 assert(stream); 7471 7472 ia_css_inputfifo_end_frame(stream->config.channel_id); 7473 } 7474 7475 bool 7476 ia_css_pipeline_uses_params(struct ia_css_pipeline *me) 7477 { 7478 struct ia_css_pipeline_stage *stage; 7479 7480 assert(me); 7481 7482 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7483 "ia_css_pipeline_uses_params() enter: me=%p\n", me); 7484 7485 for (stage = me->stages; stage; stage = stage->next) 7486 if (stage->binary_info && stage->binary_info->enable.params) { 7487 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7488 "ia_css_pipeline_uses_params() leave: return_bool=true\n"); 7489 return true; 7490 } 7491 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7492 "ia_css_pipeline_uses_params() leave: return_bool=false\n"); 7493 return false; 7494 } 7495 7496 /* 7497 * @brief Tag a specific frame in continuous capture. 7498 * Refer to "sh_css_internal.h" for details. 7499 */ 7500 int ia_css_stream_capture_frame(struct ia_css_stream *stream, 7501 unsigned int exp_id) 7502 { 7503 struct sh_css_tag_descr tag_descr; 7504 u32 encoded_tag_descr; 7505 int err; 7506 7507 assert(stream); 7508 IA_CSS_ENTER("exp_id=%d", exp_id); 7509 7510 /* Only continuous streams have a tagger */ 7511 if (exp_id == 0 || !stream->config.continuous) { 7512 IA_CSS_LEAVE_ERR(-EINVAL); 7513 return -EINVAL; 7514 } 7515 7516 if (!sh_css_sp_is_running()) { 7517 /* SP is not running. The queues are not valid */ 7518 IA_CSS_LEAVE_ERR(-EBUSY); 7519 return -EBUSY; 7520 } 7521 7522 /* Create the tag descriptor from the parameters */ 7523 sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr); 7524 /* Encode the tag descriptor into a 32-bit value */ 7525 encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr); 7526 /* 7527 * Enqueue the encoded tag to the host2sp queue. 7528 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0 7529 * on both host and the SP side. 7530 * It is mainly because it is enough to have only one tag_cmd queue 7531 */ 7532 err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr); 7533 7534 IA_CSS_LEAVE_ERR(err); 7535 return err; 7536 } 7537 7538 /* 7539 * @brief Configure the continuous capture. 7540 * Refer to "sh_css_internal.h" for details. 7541 */ 7542 int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures, 7543 unsigned int skip, int offset) 7544 { 7545 struct sh_css_tag_descr tag_descr; 7546 unsigned int encoded_tag_descr; 7547 int return_err; 7548 7549 if (!stream) 7550 return -EINVAL; 7551 7552 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7553 "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n", 7554 num_captures, skip, offset); 7555 7556 /* Check if the tag descriptor is valid */ 7557 if (num_captures < SH_CSS_MINIMUM_TAG_ID) { 7558 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7559 "ia_css_stream_capture() leave: return_err=%d\n", 7560 -EINVAL); 7561 return -EINVAL; 7562 } 7563 7564 /* Create the tag descriptor from the parameters */ 7565 sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr); 7566 7567 /* Encode the tag descriptor into a 32-bit value */ 7568 encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr); 7569 7570 if (!sh_css_sp_is_running()) { 7571 /* SP is not running. The queues are not valid */ 7572 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7573 "ia_css_stream_capture() leaving:queues unavailable\n"); 7574 return -EBUSY; 7575 } 7576 7577 /* 7578 * Enqueue the encoded tag to the host2sp queue. 7579 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0 7580 * on both host and the SP side. 7581 * It is mainly because it is enough to have only one tag_cmd queue 7582 */ 7583 return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr); 7584 7585 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7586 "ia_css_stream_capture() leave: return_err=%d\n", 7587 return_err); 7588 7589 return return_err; 7590 } 7591 7592 void ia_css_stream_request_flash(struct ia_css_stream *stream) 7593 { 7594 (void)stream; 7595 7596 assert(stream); 7597 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7598 "ia_css_stream_request_flash() enter: void\n"); 7599 7600 if (!IS_ISP2401 || sh_css_sp_is_running()) { 7601 if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash) && IS_ISP2401) { 7602 IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); 7603 ia_css_debug_dump_sp_sw_debug_info(); 7604 } 7605 } else { 7606 IA_CSS_LOG("SP is not running!"); 7607 } 7608 7609 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7610 "ia_css_stream_request_flash() leave: return_void\n"); 7611 } 7612 7613 static void 7614 sh_css_init_host_sp_control_vars(void) 7615 { 7616 const struct ia_css_fw_info *fw; 7617 unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started; 7618 7619 unsigned int HIVE_ADDR_host_sp_queues_initialized; 7620 unsigned int HIVE_ADDR_sp_sleep_mode; 7621 unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb; 7622 unsigned int HIVE_ADDR_sp_stop_copy_preview; 7623 unsigned int HIVE_ADDR_host_sp_com; 7624 unsigned int o = offsetof(struct host_sp_communication, host2sp_command) 7625 / sizeof(int); 7626 7627 unsigned int i; 7628 7629 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7630 "sh_css_init_host_sp_control_vars() enter: void\n"); 7631 7632 fw = &sh_css_sp_fw; 7633 HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started; 7634 7635 HIVE_ADDR_host_sp_queues_initialized = 7636 fw->info.sp.host_sp_queues_initialized; 7637 HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode; 7638 HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb; 7639 HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview; 7640 HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com; 7641 7642 sp_dmem_store_uint32(SP0_ID, 7643 (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started), 7644 (uint32_t)(0)); 7645 7646 sp_dmem_store_uint32(SP0_ID, 7647 (unsigned int)sp_address_of(host_sp_queues_initialized), 7648 (uint32_t)(0)); 7649 sp_dmem_store_uint32(SP0_ID, 7650 (unsigned int)sp_address_of(sp_sleep_mode), 7651 (uint32_t)(0)); 7652 sp_dmem_store_uint32(SP0_ID, 7653 (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb), 7654 (uint32_t)(false)); 7655 sp_dmem_store_uint32(SP0_ID, 7656 (unsigned int)sp_address_of(sp_stop_copy_preview), 7657 my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0)); 7658 store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready); 7659 7660 for (i = 0; i < N_CSI_PORTS; i++) { 7661 sh_css_update_host2sp_num_mipi_frames 7662 (my_css.num_mipi_frames[i]); 7663 } 7664 7665 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7666 "sh_css_init_host_sp_control_vars() leave: return_void\n"); 7667 } 7668 7669 /* 7670 * create the internal structures and fill in the configuration data 7671 */ 7672 7673 static const struct 7674 ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG; 7675 7676 void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config) 7677 { 7678 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n"); 7679 memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config)); 7680 } 7681 7682 void 7683 ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config) 7684 { 7685 if (!extra_config) { 7686 IA_CSS_ERROR("NULL input parameter"); 7687 return; 7688 } 7689 7690 extra_config->enable_raw_binning = false; 7691 extra_config->enable_yuv_ds = false; 7692 extra_config->enable_high_speed = false; 7693 extra_config->enable_dvs_6axis = false; 7694 extra_config->enable_reduced_pipe = false; 7695 extra_config->disable_vf_pp = false; 7696 extra_config->enable_fractional_ds = false; 7697 } 7698 7699 void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config) 7700 { 7701 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n"); 7702 assert(stream_config); 7703 memset(stream_config, 0, sizeof(*stream_config)); 7704 stream_config->online = true; 7705 stream_config->left_padding = -1; 7706 stream_config->pixels_per_clock = 1; 7707 /* 7708 * temporary default value for backwards compatibility. 7709 * This field used to be hardcoded within CSS but this has now 7710 * been moved to the stream_config struct. 7711 */ 7712 stream_config->source.port.rxcount = 0x04040404; 7713 } 7714 7715 int ia_css_pipe_create(const struct ia_css_pipe_config *config, 7716 struct ia_css_pipe **pipe) 7717 { 7718 int err = 0; 7719 7720 IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe); 7721 7722 if (!config || !pipe) { 7723 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7724 return -EINVAL; 7725 } 7726 7727 err = ia_css_pipe_create_extra(config, NULL, pipe); 7728 7729 if (err == 0) 7730 IA_CSS_LOG("pipe created successfully = %p", *pipe); 7731 7732 IA_CSS_LEAVE_ERR_PRIVATE(err); 7733 7734 return err; 7735 } 7736 7737 int 7738 ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, 7739 const struct ia_css_pipe_extra_config *extra_config, 7740 struct ia_css_pipe **pipe) 7741 { 7742 int err = -EINVAL; 7743 struct ia_css_pipe *internal_pipe = NULL; 7744 unsigned int i; 7745 7746 IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe); 7747 7748 /* do not allow to create more than the maximum limit */ 7749 if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) { 7750 IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC); 7751 return -EINVAL; 7752 } 7753 7754 if ((!pipe) || (!config)) { 7755 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7756 return -EINVAL; 7757 } 7758 7759 ia_css_debug_dump_pipe_config(config); 7760 ia_css_debug_dump_pipe_extra_config(extra_config); 7761 7762 err = create_pipe(config->mode, &internal_pipe, false); 7763 if (err) { 7764 IA_CSS_LEAVE_ERR_PRIVATE(err); 7765 return err; 7766 } 7767 7768 /* now we have a pipe structure to fill */ 7769 internal_pipe->config = *config; 7770 if (extra_config) 7771 internal_pipe->extra_config = *extra_config; 7772 else 7773 ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config); 7774 7775 /* 7776 * Use config value when dvs_frame_delay setting equal to 2, 7777 * otherwise always 1 by default 7778 */ 7779 if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2) 7780 internal_pipe->dvs_frame_delay = 2; 7781 else 7782 internal_pipe->dvs_frame_delay = 1; 7783 7784 /* 7785 * we still keep enable_raw_binning for backward compatibility, 7786 * for any new fractional bayer downscaling, we should use 7787 * bayer_ds_out_res. if both are specified, bayer_ds_out_res will 7788 * take precedence.if none is specified, we set bayer_ds_out_res 7789 * equal to IF output resolution(IF may do cropping on sensor output) 7790 * or use default decimation factor 1. 7791 */ 7792 7793 /* YUV downscaling */ 7794 if ((internal_pipe->config.vf_pp_in_res.width || 7795 internal_pipe->config.capt_pp_in_res.width)) { 7796 enum ia_css_frame_format format; 7797 7798 if (internal_pipe->config.vf_pp_in_res.width) { 7799 format = IA_CSS_FRAME_FORMAT_YUV_LINE; 7800 ia_css_frame_info_init( 7801 &internal_pipe->vf_yuv_ds_input_info, 7802 internal_pipe->config.vf_pp_in_res.width, 7803 internal_pipe->config.vf_pp_in_res.height, 7804 format, 0); 7805 } 7806 if (internal_pipe->config.capt_pp_in_res.width) { 7807 format = IA_CSS_FRAME_FORMAT_YUV420; 7808 ia_css_frame_info_init( 7809 &internal_pipe->out_yuv_ds_input_info, 7810 internal_pipe->config.capt_pp_in_res.width, 7811 internal_pipe->config.capt_pp_in_res.height, 7812 format, 0); 7813 } 7814 } 7815 if (internal_pipe->config.vf_pp_in_res.width && 7816 internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) { 7817 ia_css_frame_info_init( 7818 &internal_pipe->vf_yuv_ds_input_info, 7819 internal_pipe->config.vf_pp_in_res.width, 7820 internal_pipe->config.vf_pp_in_res.height, 7821 IA_CSS_FRAME_FORMAT_YUV_LINE, 0); 7822 } 7823 /* handle bayer downscaling output info */ 7824 if (internal_pipe->config.bayer_ds_out_res.width) { 7825 ia_css_frame_info_init( 7826 &internal_pipe->bds_output_info, 7827 internal_pipe->config.bayer_ds_out_res.width, 7828 internal_pipe->config.bayer_ds_out_res.height, 7829 IA_CSS_FRAME_FORMAT_RAW, 0); 7830 } 7831 7832 /* handle output info, assume always needed */ 7833 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 7834 if (internal_pipe->config.output_info[i].res.width) { 7835 err = sh_css_pipe_configure_output( 7836 internal_pipe, 7837 internal_pipe->config.output_info[i].res.width, 7838 internal_pipe->config.output_info[i].res.height, 7839 internal_pipe->config.output_info[i].padded_width, 7840 internal_pipe->config.output_info[i].format, 7841 i); 7842 if (err) { 7843 IA_CSS_LEAVE_ERR_PRIVATE(err); 7844 kvfree(internal_pipe); 7845 internal_pipe = NULL; 7846 return err; 7847 } 7848 } 7849 7850 /* handle vf output info, when configured */ 7851 internal_pipe->enable_viewfinder[i] = 7852 (internal_pipe->config.vf_output_info[i].res.width != 0); 7853 if (internal_pipe->config.vf_output_info[i].res.width) { 7854 err = sh_css_pipe_configure_viewfinder( 7855 internal_pipe, 7856 internal_pipe->config.vf_output_info[i].res.width, 7857 internal_pipe->config.vf_output_info[i].res.height, 7858 internal_pipe->config.vf_output_info[i].padded_width, 7859 internal_pipe->config.vf_output_info[i].format, 7860 i); 7861 if (err) { 7862 IA_CSS_LEAVE_ERR_PRIVATE(err); 7863 kvfree(internal_pipe); 7864 internal_pipe = NULL; 7865 return err; 7866 } 7867 } 7868 } 7869 /* set all info to zeroes first */ 7870 memset(&internal_pipe->info, 0, sizeof(internal_pipe->info)); 7871 7872 /* all went well, return the pipe */ 7873 *pipe = internal_pipe; 7874 IA_CSS_LEAVE_ERR_PRIVATE(0); 7875 return 0; 7876 } 7877 7878 int 7879 ia_css_pipe_get_info(const struct ia_css_pipe *pipe, 7880 struct ia_css_pipe_info *pipe_info) 7881 { 7882 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 7883 "ia_css_pipe_get_info()\n"); 7884 if (!pipe_info) { 7885 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 7886 "ia_css_pipe_get_info: pipe_info cannot be NULL\n"); 7887 return -EINVAL; 7888 } 7889 if (!pipe || !pipe->stream) { 7890 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 7891 "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n"); 7892 return -EINVAL; 7893 } 7894 /* we succeeded return the info */ 7895 *pipe_info = pipe->info; 7896 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n"); 7897 return 0; 7898 } 7899 7900 bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info) 7901 { 7902 unsigned int i; 7903 7904 if (pipe_info) { 7905 for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) { 7906 if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable) 7907 return true; 7908 } 7909 } 7910 7911 return false; 7912 } 7913 7914 int 7915 ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe, 7916 int pin_index, 7917 enum ia_css_frame_format new_format) 7918 { 7919 int err = 0; 7920 7921 IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format); 7922 7923 if (!pipe) { 7924 IA_CSS_ERROR("pipe is not set"); 7925 err = -EINVAL; 7926 IA_CSS_LEAVE_ERR_PRIVATE(err); 7927 return err; 7928 } 7929 if (0 != pin_index && 1 != pin_index) { 7930 IA_CSS_ERROR("pin index is not valid"); 7931 err = -EINVAL; 7932 IA_CSS_LEAVE_ERR_PRIVATE(err); 7933 return err; 7934 } 7935 if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) { 7936 IA_CSS_ERROR("new format is not valid"); 7937 err = -EINVAL; 7938 IA_CSS_LEAVE_ERR_PRIVATE(err); 7939 return err; 7940 } else { 7941 err = ia_css_pipe_check_format(pipe, new_format); 7942 if (!err) { 7943 if (pin_index == 0) 7944 pipe->output_info[0].format = new_format; 7945 else 7946 pipe->vf_output_info[0].format = new_format; 7947 } 7948 } 7949 IA_CSS_LEAVE_ERR_PRIVATE(err); 7950 return err; 7951 } 7952 7953 /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */ 7954 static int 7955 ia_css_stream_configure_rx(struct ia_css_stream *stream) 7956 { 7957 struct ia_css_input_port *config; 7958 7959 assert(stream); 7960 7961 config = &stream->config.source.port; 7962 /* AM: this code is not reliable, especially for 2400 */ 7963 if (config->num_lanes == 1) 7964 stream->csi_rx_config.mode = MONO_1L_1L_0L; 7965 else if (config->num_lanes == 2) 7966 stream->csi_rx_config.mode = MONO_2L_1L_0L; 7967 else if (config->num_lanes == 3) 7968 stream->csi_rx_config.mode = MONO_3L_1L_0L; 7969 else if (config->num_lanes == 4) 7970 stream->csi_rx_config.mode = MONO_4L_1L_0L; 7971 else if (config->num_lanes != 0) 7972 return -EINVAL; 7973 7974 if (config->port > MIPI_PORT2_ID) 7975 return -EINVAL; 7976 stream->csi_rx_config.port = 7977 ia_css_isys_port_to_mipi_port(config->port); 7978 stream->csi_rx_config.timeout = config->timeout; 7979 stream->csi_rx_config.initcount = 0; 7980 stream->csi_rx_config.synccount = 0x28282828; 7981 stream->csi_rx_config.rxcount = config->rxcount; 7982 if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE) 7983 stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE; 7984 else 7985 /* 7986 * not implemented yet, requires extension of the rx_cfg_t 7987 * struct 7988 */ 7989 return -EINVAL; 7990 7991 stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2); 7992 stream->reconfigure_css_rx = true; 7993 return 0; 7994 } 7995 7996 static struct ia_css_pipe * 7997 find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes, 7998 enum ia_css_pipe_mode mode, bool copy_pipe) 7999 { 8000 unsigned int i; 8001 8002 assert(pipes); 8003 for (i = 0; i < num_pipes; i++) { 8004 assert(pipes[i]); 8005 if (pipes[i]->config.mode != mode) 8006 continue; 8007 if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY) 8008 continue; 8009 return pipes[i]; 8010 } 8011 return NULL; 8012 } 8013 8014 static int 8015 metadata_info_init(const struct ia_css_metadata_config *mdc, 8016 struct ia_css_metadata_info *md) 8017 { 8018 /* Either both width and height should be set or neither */ 8019 if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0)) 8020 return -EINVAL; 8021 8022 md->resolution = mdc->resolution; 8023 /* 8024 * We round up the stride to a multiple of the width 8025 * of the port going to DDR, this is a HW requirements (DMA). 8026 */ 8027 md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES); 8028 md->size = mdc->resolution.height * md->stride; 8029 return 0; 8030 } 8031 8032 int 8033 ia_css_stream_create(const struct ia_css_stream_config *stream_config, 8034 int num_pipes, 8035 struct ia_css_pipe *pipes[], 8036 struct ia_css_stream **stream) 8037 { 8038 struct ia_css_pipe *curr_pipe; 8039 struct ia_css_stream *curr_stream = NULL; 8040 bool spcopyonly; 8041 bool sensor_binning_changed; 8042 int i, j; 8043 int err = -EINVAL; 8044 struct ia_css_metadata_info md_info; 8045 struct ia_css_resolution effective_res; 8046 8047 IA_CSS_ENTER("num_pipes=%d", num_pipes); 8048 ia_css_debug_dump_stream_config(stream_config, num_pipes); 8049 8050 /* some checks */ 8051 if (num_pipes == 0 || 8052 !stream || 8053 !pipes) { 8054 err = -EINVAL; 8055 IA_CSS_LEAVE_ERR(err); 8056 return err; 8057 } 8058 8059 if (!IS_ISP2401) { 8060 /* We don't support metadata for JPEG stream, since they both use str2mem */ 8061 if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 && 8062 stream_config->metadata_config.resolution.height > 0) { 8063 err = -EINVAL; 8064 IA_CSS_LEAVE_ERR(err); 8065 return err; 8066 } 8067 } else { 8068 if (stream_config->online && stream_config->pack_raw_pixels) { 8069 IA_CSS_LOG("online and pack raw is invalid on input system 2401"); 8070 err = -EINVAL; 8071 IA_CSS_LEAVE_ERR(err); 8072 return err; 8073 } 8074 } 8075 8076 ia_css_debug_pipe_graph_dump_stream_config(stream_config); 8077 8078 /* check if mipi size specified */ 8079 if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) 8080 if (!IS_ISP2401 || !stream_config->online) 8081 { 8082 unsigned int port = (unsigned int)stream_config->source.port.port; 8083 8084 if (port >= N_MIPI_PORT_ID) { 8085 err = -EINVAL; 8086 IA_CSS_LEAVE_ERR(err); 8087 return err; 8088 } 8089 8090 if (my_css.size_mem_words != 0) { 8091 my_css.mipi_frame_size[port] = my_css.size_mem_words; 8092 } else if (stream_config->mipi_buffer_config.size_mem_words != 0) { 8093 my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words; 8094 } else { 8095 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8096 "ia_css_stream_create() exit: error, need to set mipi frame size.\n"); 8097 assert(stream_config->mipi_buffer_config.size_mem_words != 0); 8098 err = -EINVAL; 8099 IA_CSS_LEAVE_ERR(err); 8100 return err; 8101 } 8102 8103 if (my_css.size_mem_words != 0) { 8104 my_css.num_mipi_frames[port] = 8105 2; /* Temp change: Default for backwards compatibility. */ 8106 } else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) { 8107 my_css.num_mipi_frames[port] = 8108 stream_config->mipi_buffer_config.nof_mipi_buffers; 8109 } else { 8110 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8111 "ia_css_stream_create() exit: error, need to set number of mipi frames.\n"); 8112 assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0); 8113 err = -EINVAL; 8114 IA_CSS_LEAVE_ERR(err); 8115 return err; 8116 } 8117 } 8118 8119 /* Currently we only supported metadata up to a certain size. */ 8120 err = metadata_info_init(&stream_config->metadata_config, &md_info); 8121 if (err) { 8122 IA_CSS_LEAVE_ERR(err); 8123 return err; 8124 } 8125 8126 /* allocate the stream instance */ 8127 curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL); 8128 if (!curr_stream) { 8129 err = -ENOMEM; 8130 IA_CSS_LEAVE_ERR(err); 8131 return err; 8132 } 8133 /* default all to 0 */ 8134 curr_stream->info.metadata_info = md_info; 8135 8136 /* allocate pipes */ 8137 curr_stream->num_pipes = num_pipes; 8138 curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL); 8139 if (!curr_stream->pipes) { 8140 curr_stream->num_pipes = 0; 8141 kfree(curr_stream); 8142 curr_stream = NULL; 8143 err = -ENOMEM; 8144 IA_CSS_LEAVE_ERR(err); 8145 return err; 8146 } 8147 /* store pipes */ 8148 spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY); 8149 for (i = 0; i < num_pipes; i++) 8150 curr_stream->pipes[i] = pipes[i]; 8151 curr_stream->last_pipe = curr_stream->pipes[0]; 8152 /* take over stream config */ 8153 curr_stream->config = *stream_config; 8154 8155 if (IS_ISP2401) { 8156 if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR && 8157 stream_config->online) 8158 curr_stream->config.online = false; 8159 8160 if (curr_stream->config.online) { 8161 curr_stream->config.source.port.num_lanes = 8162 stream_config->source.port.num_lanes; 8163 curr_stream->config.mode = IA_CSS_INPUT_MODE_BUFFERED_SENSOR; 8164 } 8165 } 8166 /* in case driver doesn't configure init number of raw buffers, configure it here */ 8167 if (curr_stream->config.target_num_cont_raw_buf == 0) 8168 curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES; 8169 if (curr_stream->config.init_num_cont_raw_buf == 0) 8170 curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf; 8171 8172 /* Enable locking & unlocking of buffers in RAW buffer pool */ 8173 if (curr_stream->config.ia_css_enable_raw_buffer_locking) 8174 sh_css_sp_configure_enable_raw_pool_locking( 8175 curr_stream->config.lock_all); 8176 8177 /* copy mode specific stuff */ 8178 switch (curr_stream->config.mode) { 8179 case IA_CSS_INPUT_MODE_SENSOR: 8180 case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: 8181 if (!IS_ISP2401) 8182 ia_css_stream_configure_rx(curr_stream); 8183 break; 8184 case IA_CSS_INPUT_MODE_TPG: 8185 if (!IS_ISP2401) { 8186 IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d", 8187 curr_stream->config.source.tpg.x_mask, 8188 curr_stream->config.source.tpg.y_mask, 8189 curr_stream->config.source.tpg.x_delta, 8190 curr_stream->config.source.tpg.y_delta, 8191 curr_stream->config.source.tpg.xy_mask); 8192 8193 sh_css_sp_configure_tpg( 8194 curr_stream->config.source.tpg.x_mask, 8195 curr_stream->config.source.tpg.y_mask, 8196 curr_stream->config.source.tpg.x_delta, 8197 curr_stream->config.source.tpg.y_delta, 8198 curr_stream->config.source.tpg.xy_mask); 8199 } 8200 break; 8201 case IA_CSS_INPUT_MODE_PRBS: 8202 if (!IS_ISP2401) { 8203 IA_CSS_LOG("mode prbs"); 8204 sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed); 8205 } 8206 break; 8207 case IA_CSS_INPUT_MODE_MEMORY: 8208 IA_CSS_LOG("mode memory"); 8209 curr_stream->reconfigure_css_rx = false; 8210 break; 8211 default: 8212 IA_CSS_LOG("mode sensor/default"); 8213 } 8214 8215 for (i = 0; i < num_pipes; i++) { 8216 struct ia_css_resolution effective_res; 8217 8218 curr_pipe = pipes[i]; 8219 /* set current stream */ 8220 curr_pipe->stream = curr_stream; 8221 /* take over effective info */ 8222 8223 effective_res = curr_pipe->config.input_effective_res; 8224 if (effective_res.height == 0 || effective_res.width == 0) { 8225 effective_res = curr_pipe->stream->config.input_config.effective_res; 8226 8227 curr_pipe->config.input_effective_res = effective_res; 8228 } 8229 IA_CSS_LOG("effective_res=%dx%d", 8230 effective_res.width, 8231 effective_res.height); 8232 } 8233 8234 err = ia_css_stream_isp_parameters_init(curr_stream); 8235 if (err) 8236 goto ERR; 8237 IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs); 8238 8239 /* sensor binning */ 8240 if (!spcopyonly) { 8241 sensor_binning_changed = 8242 sh_css_params_set_binning_factor(curr_stream, 8243 curr_stream->config.sensor_binning_factor); 8244 } else { 8245 sensor_binning_changed = false; 8246 } 8247 8248 IA_CSS_LOG("sensor_binning=%d, changed=%d", 8249 curr_stream->config.sensor_binning_factor, sensor_binning_changed); 8250 /* loop over pipes */ 8251 IA_CSS_LOG("num_pipes=%d", num_pipes); 8252 curr_stream->cont_capt = false; 8253 /* Temporary hack: we give the preview pipe a reference to the capture 8254 * pipe in continuous capture mode. */ 8255 if (curr_stream->config.continuous) { 8256 /* Search for the preview pipe and create the copy pipe */ 8257 struct ia_css_pipe *preview_pipe; 8258 struct ia_css_pipe *video_pipe; 8259 struct ia_css_pipe *capture_pipe = NULL; 8260 struct ia_css_pipe *copy_pipe = NULL; 8261 8262 if (num_pipes >= 2) { 8263 curr_stream->cont_capt = true; 8264 curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder; 8265 curr_stream->stop_copy_preview = my_css.stop_copy_preview; 8266 } 8267 8268 /* Create copy pipe here, since it may not be exposed to the driver */ 8269 preview_pipe = find_pipe(pipes, num_pipes, 8270 IA_CSS_PIPE_MODE_PREVIEW, false); 8271 video_pipe = find_pipe(pipes, num_pipes, 8272 IA_CSS_PIPE_MODE_VIDEO, false); 8273 8274 if (curr_stream->cont_capt) { 8275 capture_pipe = find_pipe(pipes, num_pipes, 8276 IA_CSS_PIPE_MODE_CAPTURE, 8277 false); 8278 if (!capture_pipe) { 8279 err = -EINVAL; 8280 goto ERR; 8281 } 8282 } 8283 /* We do not support preview and video pipe at the same time */ 8284 if (preview_pipe && video_pipe) { 8285 err = -EINVAL; 8286 goto ERR; 8287 } 8288 8289 if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) { 8290 err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, ©_pipe, true); 8291 if (err) 8292 goto ERR; 8293 ia_css_pipe_config_defaults(©_pipe->config); 8294 preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe; 8295 copy_pipe->stream = curr_stream; 8296 } 8297 if (preview_pipe && curr_stream->cont_capt) 8298 preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe; 8299 8300 if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) { 8301 err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, ©_pipe, true); 8302 if (err) 8303 goto ERR; 8304 ia_css_pipe_config_defaults(©_pipe->config); 8305 video_pipe->pipe_settings.video.copy_pipe = copy_pipe; 8306 copy_pipe->stream = curr_stream; 8307 } 8308 if (video_pipe && curr_stream->cont_capt) 8309 video_pipe->pipe_settings.video.capture_pipe = capture_pipe; 8310 } 8311 for (i = 0; i < num_pipes; i++) { 8312 curr_pipe = pipes[i]; 8313 /* set current stream */ 8314 curr_pipe->stream = curr_stream; 8315 8316 /* take over effective info */ 8317 8318 effective_res = curr_pipe->config.input_effective_res; 8319 err = ia_css_util_check_res( 8320 effective_res.width, 8321 effective_res.height); 8322 if (err) 8323 goto ERR; 8324 8325 /* sensor binning per pipe */ 8326 if (sensor_binning_changed) 8327 sh_css_pipe_free_shading_table(curr_pipe); 8328 } 8329 8330 /* now pipes have been configured, info should be available */ 8331 for (i = 0; i < num_pipes; i++) { 8332 struct ia_css_pipe_info *pipe_info = NULL; 8333 8334 curr_pipe = pipes[i]; 8335 8336 err = sh_css_pipe_load_binaries(curr_pipe); 8337 if (err) 8338 goto ERR; 8339 8340 /* handle each pipe */ 8341 pipe_info = &curr_pipe->info; 8342 for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) { 8343 err = sh_css_pipe_get_output_frame_info(curr_pipe, 8344 &pipe_info->output_info[j], j); 8345 if (err) 8346 goto ERR; 8347 } 8348 8349 if (!spcopyonly) { 8350 if (!IS_ISP2401) 8351 err = sh_css_pipe_get_shading_info(curr_pipe, 8352 &pipe_info->shading_info, 8353 NULL); 8354 else 8355 err = sh_css_pipe_get_shading_info(curr_pipe, 8356 &pipe_info->shading_info, 8357 &curr_pipe->config); 8358 8359 if (err) 8360 goto ERR; 8361 err = sh_css_pipe_get_grid_info(curr_pipe, 8362 &pipe_info->grid_info); 8363 if (err) 8364 goto ERR; 8365 for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) { 8366 sh_css_pipe_get_viewfinder_frame_info(curr_pipe, 8367 &pipe_info->vf_output_info[j], 8368 j); 8369 if (err) 8370 goto ERR; 8371 } 8372 } 8373 8374 my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe; 8375 } 8376 8377 curr_stream->started = false; 8378 8379 /* Map SP threads before doing anything. */ 8380 err = map_sp_threads(curr_stream, true); 8381 if (err) { 8382 IA_CSS_LOG("map_sp_threads: return_err=%d", err); 8383 goto ERR; 8384 } 8385 8386 for (i = 0; i < num_pipes; i++) { 8387 curr_pipe = pipes[i]; 8388 ia_css_pipe_map_queue(curr_pipe, true); 8389 } 8390 8391 /* Create host side pipeline objects without stages */ 8392 err = create_host_pipeline_structure(curr_stream); 8393 if (err) { 8394 IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err); 8395 goto ERR; 8396 } 8397 8398 /* assign curr_stream */ 8399 *stream = curr_stream; 8400 8401 ERR: 8402 if (!err) { 8403 /* working mode: enter into the seed list */ 8404 if (my_css_save.mode == sh_css_mode_working) { 8405 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { 8406 if (!my_css_save.stream_seeds[i].stream) { 8407 IA_CSS_LOG("entered stream into loc=%d", i); 8408 my_css_save.stream_seeds[i].orig_stream = stream; 8409 my_css_save.stream_seeds[i].stream = curr_stream; 8410 my_css_save.stream_seeds[i].num_pipes = num_pipes; 8411 my_css_save.stream_seeds[i].stream_config = *stream_config; 8412 for (j = 0; j < num_pipes; j++) { 8413 my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config; 8414 my_css_save.stream_seeds[i].pipes[j] = pipes[j]; 8415 my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j]; 8416 } 8417 break; 8418 } 8419 } 8420 } else { 8421 ia_css_stream_destroy(curr_stream); 8422 } 8423 } else { 8424 ia_css_stream_destroy(curr_stream); 8425 } 8426 IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode); 8427 return err; 8428 } 8429 8430 int 8431 ia_css_stream_destroy(struct ia_css_stream *stream) 8432 { 8433 int i; 8434 int err = 0; 8435 8436 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 8437 if (!stream) { 8438 err = -EINVAL; 8439 IA_CSS_LEAVE_ERR_PRIVATE(err); 8440 return err; 8441 } 8442 8443 ia_css_stream_isp_parameters_uninit(stream); 8444 8445 if ((stream->last_pipe) && 8446 ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) { 8447 if (IS_ISP2401) { 8448 for (i = 0; i < stream->num_pipes; i++) { 8449 struct ia_css_pipe *entry = stream->pipes[i]; 8450 unsigned int sp_thread_id; 8451 struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal; 8452 8453 assert(entry); 8454 if (entry) { 8455 /* get the SP thread id */ 8456 if (!ia_css_pipeline_get_sp_thread_id( 8457 ia_css_pipe_get_pipe_num(entry), &sp_thread_id)) 8458 return -EINVAL; 8459 8460 /* get the target input terminal */ 8461 sp_pipeline_input_terminal = 8462 &sh_css_sp_group.pipe_io[sp_thread_id].input; 8463 8464 for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { 8465 ia_css_isys_stream_h isys_stream = 8466 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]; 8467 if (stream->config.isys_config[i].valid && isys_stream->valid) 8468 ia_css_isys_stream_destroy(isys_stream); 8469 } 8470 } 8471 } 8472 8473 if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 8474 for (i = 0; i < stream->num_pipes; i++) { 8475 struct ia_css_pipe *entry = stream->pipes[i]; 8476 /* 8477 * free any mipi frames that are remaining: 8478 * some test stream create-destroy cycles do 8479 * not generate output frames 8480 * and the mipi buffer is not freed in the 8481 * deque function 8482 */ 8483 if (entry) 8484 free_mipi_frames(entry); 8485 } 8486 } 8487 stream_unregister_with_csi_rx(stream); 8488 } 8489 8490 for (i = 0; i < stream->num_pipes; i++) { 8491 struct ia_css_pipe *curr_pipe = stream->pipes[i]; 8492 8493 assert(curr_pipe); 8494 ia_css_pipe_map_queue(curr_pipe, false); 8495 } 8496 8497 err = map_sp_threads(stream, false); 8498 if (err) { 8499 IA_CSS_LEAVE_ERR_PRIVATE(err); 8500 return err; 8501 } 8502 } 8503 8504 /* remove references from pipes to stream */ 8505 for (i = 0; i < stream->num_pipes; i++) { 8506 struct ia_css_pipe *entry = stream->pipes[i]; 8507 8508 assert(entry); 8509 if (entry) { 8510 /* clear reference to stream */ 8511 entry->stream = NULL; 8512 /* check internal copy pipe */ 8513 if (entry->mode == IA_CSS_PIPE_ID_PREVIEW && 8514 entry->pipe_settings.preview.copy_pipe) { 8515 IA_CSS_LOG("clearing stream on internal preview copy pipe"); 8516 entry->pipe_settings.preview.copy_pipe->stream = NULL; 8517 } 8518 if (entry->mode == IA_CSS_PIPE_ID_VIDEO && 8519 entry->pipe_settings.video.copy_pipe) { 8520 IA_CSS_LOG("clearing stream on internal video copy pipe"); 8521 entry->pipe_settings.video.copy_pipe->stream = NULL; 8522 } 8523 err = sh_css_pipe_unload_binaries(entry); 8524 } 8525 } 8526 /* free associated memory of stream struct */ 8527 kfree(stream->pipes); 8528 stream->pipes = NULL; 8529 stream->num_pipes = 0; 8530 8531 /* working mode: take out of the seed list */ 8532 if (my_css_save.mode == sh_css_mode_working) { 8533 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { 8534 if (my_css_save.stream_seeds[i].stream == stream) { 8535 IA_CSS_LOG("took out stream %d", i); 8536 my_css_save.stream_seeds[i].stream = NULL; 8537 break; 8538 } 8539 } 8540 } 8541 8542 kfree(stream); 8543 IA_CSS_LEAVE_ERR(err); 8544 8545 return err; 8546 } 8547 8548 int 8549 ia_css_stream_get_info(const struct ia_css_stream *stream, 8550 struct ia_css_stream_info *stream_info) 8551 { 8552 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n"); 8553 assert(stream); 8554 assert(stream_info); 8555 8556 *stream_info = stream->info; 8557 return 0; 8558 } 8559 8560 int 8561 ia_css_stream_start(struct ia_css_stream *stream) 8562 { 8563 int err = 0; 8564 8565 IA_CSS_ENTER("stream = %p", stream); 8566 if ((!stream) || (!stream->last_pipe)) { 8567 IA_CSS_LEAVE_ERR(-EINVAL); 8568 return -EINVAL; 8569 } 8570 IA_CSS_LOG("starting %d", stream->last_pipe->mode); 8571 8572 sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf); 8573 8574 /* Create host side pipeline. */ 8575 err = create_host_pipeline(stream); 8576 if (err) { 8577 IA_CSS_LEAVE_ERR(err); 8578 return err; 8579 } 8580 8581 if (IS_ISP2401 && 8582 ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) || 8583 (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))) 8584 stream_register_with_csi_rx(stream); 8585 8586 /* Initialize mipi size checks */ 8587 if (!IS_ISP2401 && stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 8588 unsigned int idx; 8589 unsigned int port = (unsigned int)(stream->config.source.port.port); 8590 8591 for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) { 8592 sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 8593 sh_css_get_mipi_sizes_for_check(port, idx); 8594 } 8595 } 8596 8597 if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) { 8598 if (IS_ISP2401) 8599 err = sh_css_config_input_network_2401(stream); 8600 else 8601 err = sh_css_config_input_network_2400(stream); 8602 if (err) 8603 return err; 8604 } 8605 8606 err = sh_css_pipe_start(stream); 8607 IA_CSS_LEAVE_ERR(err); 8608 return err; 8609 } 8610 8611 int 8612 ia_css_stream_stop(struct ia_css_stream *stream) 8613 { 8614 int err = 0; 8615 8616 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n"); 8617 assert(stream); 8618 assert(stream->last_pipe); 8619 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n", 8620 stream->last_pipe->mode); 8621 8622 /* De-initialize mipi size checks */ 8623 if (!IS_ISP2401 && stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 8624 unsigned int idx; 8625 unsigned int port = (unsigned int)(stream->config.source.port.port); 8626 8627 for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) 8628 sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0; 8629 } 8630 8631 err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline); 8632 if (err) 8633 return err; 8634 8635 /* 8636 * Ideally, unmapping should happen after pipeline_stop, but current 8637 * semantics do not allow that. 8638 */ 8639 /* err = map_sp_threads(stream, false); */ 8640 8641 return err; 8642 } 8643 8644 bool 8645 ia_css_stream_has_stopped(struct ia_css_stream *stream) 8646 { 8647 bool stopped; 8648 8649 assert(stream); 8650 8651 stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline); 8652 8653 return stopped; 8654 } 8655 8656 /* ISP2400 */ 8657 /* 8658 * Destroy the stream and all the pipes related to it. 8659 * The stream handle is used to identify the correct entry in the css_save struct 8660 */ 8661 int 8662 ia_css_stream_unload(struct ia_css_stream *stream) 8663 { 8664 int i; 8665 8666 assert(stream); 8667 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() enter,\n"); 8668 /* some checks */ 8669 assert(stream); 8670 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) 8671 if (my_css_save.stream_seeds[i].stream == stream) { 8672 int j; 8673 8674 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8675 "ia_css_stream_unload(): unloading %d (%p)\n", i, 8676 my_css_save.stream_seeds[i].stream); 8677 ia_css_stream_destroy(stream); 8678 for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) 8679 ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]); 8680 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8681 "ia_css_stream_unload(): after unloading %d (%p)\n", i, 8682 my_css_save.stream_seeds[i].stream); 8683 break; 8684 } 8685 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() exit,\n"); 8686 return 0; 8687 } 8688 8689 int 8690 ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe, 8691 enum ia_css_pipe_id *pipe_id) 8692 { 8693 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n"); 8694 if (pipe) 8695 *pipe_id = pipe->mode; 8696 else 8697 *pipe_id = IA_CSS_PIPE_ID_COPY; 8698 8699 return 0; 8700 } 8701 8702 enum atomisp_input_format 8703 ia_css_stream_get_format(const struct ia_css_stream *stream) 8704 { 8705 return stream->config.input_config.format; 8706 } 8707 8708 bool 8709 ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) 8710 { 8711 return (stream->config.pixels_per_clock == 2); 8712 } 8713 8714 struct ia_css_binary * 8715 ia_css_stream_get_shading_correction_binary(const struct ia_css_stream 8716 *stream) 8717 { 8718 struct ia_css_pipe *pipe; 8719 8720 assert(stream); 8721 8722 pipe = stream->pipes[0]; 8723 8724 if (stream->num_pipes == 2) { 8725 assert(stream->pipes[1]); 8726 if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO || 8727 stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW) 8728 pipe = stream->pipes[1]; 8729 } 8730 8731 return ia_css_pipe_get_shading_correction_binary(pipe); 8732 } 8733 8734 struct ia_css_binary * 8735 ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) 8736 { 8737 int i; 8738 struct ia_css_pipe *video_pipe = NULL; 8739 8740 /* First we find the video pipe */ 8741 for (i = 0; i < stream->num_pipes; i++) { 8742 struct ia_css_pipe *pipe = stream->pipes[i]; 8743 8744 if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) { 8745 video_pipe = pipe; 8746 break; 8747 } 8748 } 8749 if (video_pipe) 8750 return &video_pipe->pipe_settings.video.video_binary; 8751 return NULL; 8752 } 8753 8754 struct ia_css_binary * 8755 ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) 8756 { 8757 struct ia_css_pipe *pipe; 8758 struct ia_css_binary *s3a_binary = NULL; 8759 8760 assert(stream); 8761 8762 pipe = stream->pipes[0]; 8763 8764 if (stream->num_pipes == 2) { 8765 assert(stream->pipes[1]); 8766 if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO || 8767 stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW) 8768 pipe = stream->pipes[1]; 8769 } 8770 8771 s3a_binary = ia_css_pipe_get_s3a_binary(pipe); 8772 8773 return s3a_binary; 8774 } 8775 8776 int 8777 ia_css_stream_set_output_padded_width(struct ia_css_stream *stream, 8778 unsigned int output_padded_width) 8779 { 8780 struct ia_css_pipe *pipe; 8781 8782 assert(stream); 8783 8784 pipe = stream->last_pipe; 8785 8786 assert(pipe); 8787 8788 /* set the config also just in case (redundant info? why do we save config in pipe?) */ 8789 pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width; 8790 pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width; 8791 8792 return 0; 8793 } 8794 8795 static struct ia_css_binary * 8796 ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) 8797 { 8798 struct ia_css_binary *binary = NULL; 8799 8800 assert(pipe); 8801 8802 switch (pipe->config.mode) { 8803 case IA_CSS_PIPE_MODE_PREVIEW: 8804 binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary; 8805 break; 8806 case IA_CSS_PIPE_MODE_VIDEO: 8807 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 8808 break; 8809 case IA_CSS_PIPE_MODE_CAPTURE: 8810 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 8811 unsigned int i; 8812 8813 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 8814 if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) { 8815 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i]; 8816 break; 8817 } 8818 } 8819 } else if (pipe->config.default_capture_config.mode == 8820 IA_CSS_CAPTURE_MODE_BAYER) 8821 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 8822 else if (pipe->config.default_capture_config.mode == 8823 IA_CSS_CAPTURE_MODE_ADVANCED || 8824 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 8825 if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1) 8826 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 8827 else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2) 8828 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary; 8829 } 8830 break; 8831 default: 8832 break; 8833 } 8834 8835 if (binary && binary->info->sp.enable.sc) 8836 return binary; 8837 8838 return NULL; 8839 } 8840 8841 static struct ia_css_binary * 8842 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) 8843 { 8844 struct ia_css_binary *binary = NULL; 8845 8846 assert(pipe); 8847 8848 switch (pipe->config.mode) { 8849 case IA_CSS_PIPE_MODE_PREVIEW: 8850 binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary; 8851 break; 8852 case IA_CSS_PIPE_MODE_VIDEO: 8853 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 8854 break; 8855 case IA_CSS_PIPE_MODE_CAPTURE: 8856 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 8857 unsigned int i; 8858 8859 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 8860 if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) { 8861 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i]; 8862 break; 8863 } 8864 } 8865 } else if (pipe->config.default_capture_config.mode == 8866 IA_CSS_CAPTURE_MODE_BAYER) { 8867 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 8868 } else if (pipe->config.default_capture_config.mode == 8869 IA_CSS_CAPTURE_MODE_ADVANCED || 8870 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 8871 if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1) 8872 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 8873 else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2) 8874 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary; 8875 else 8876 assert(0); 8877 } 8878 break; 8879 default: 8880 break; 8881 } 8882 8883 if (binary && !binary->info->sp.enable.s3a) 8884 binary = NULL; 8885 8886 return binary; 8887 } 8888 8889 static struct ia_css_binary * 8890 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) 8891 { 8892 struct ia_css_binary *binary = NULL; 8893 8894 assert(pipe); 8895 8896 switch (pipe->config.mode) { 8897 case IA_CSS_PIPE_MODE_VIDEO: 8898 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 8899 break; 8900 default: 8901 break; 8902 } 8903 8904 if (binary && !binary->info->sp.enable.dis) 8905 binary = NULL; 8906 8907 return binary; 8908 } 8909 8910 struct ia_css_pipeline * 8911 ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) 8912 { 8913 assert(pipe); 8914 8915 return (struct ia_css_pipeline *)&pipe->pipeline; 8916 } 8917 8918 unsigned int 8919 ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) 8920 { 8921 assert(pipe); 8922 8923 /* 8924 * KW was not sure this function was not returning a value 8925 * that was out of range; so added an assert, and, for the 8926 * case when asserts are not enabled, clip to the largest 8927 * value; pipe_num is unsigned so the value cannot be too small 8928 */ 8929 assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX); 8930 8931 if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX) 8932 return (IA_CSS_PIPELINE_NUM_MAX - 1); 8933 8934 return pipe->pipe_num; 8935 } 8936 8937 unsigned int 8938 ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) 8939 { 8940 assert(pipe); 8941 8942 return (unsigned int)pipe->config.isp_pipe_version; 8943 } 8944 8945 #define SP_START_TIMEOUT_US 30000000 8946 8947 int 8948 ia_css_start_sp(void) 8949 { 8950 unsigned long timeout; 8951 int err = 0; 8952 8953 IA_CSS_ENTER(""); 8954 sh_css_sp_start_isp(); 8955 8956 /* waiting for the SP is completely started */ 8957 timeout = SP_START_TIMEOUT_US; 8958 while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) { 8959 timeout--; 8960 udelay(1); 8961 } 8962 if (timeout == 0) { 8963 IA_CSS_ERROR("timeout during SP initialization"); 8964 return -EINVAL; 8965 } 8966 8967 /* Workaround, in order to run two streams in parallel. See TASK 4271*/ 8968 /* TODO: Fix this. */ 8969 8970 sh_css_init_host_sp_control_vars(); 8971 8972 /* buffers should be initialized only when sp is started */ 8973 /* AM: At the moment it will be done only when there is no stream active. */ 8974 8975 sh_css_setup_queues(); 8976 ia_css_bufq_dump_queue_info(); 8977 8978 IA_CSS_LEAVE_ERR(err); 8979 return err; 8980 } 8981 8982 /* 8983 * Time to wait SP for termincate. Only condition when this can happen 8984 * is a fatal hw failure, but we must be able to detect this and emit 8985 * a proper error trace. 8986 */ 8987 #define SP_SHUTDOWN_TIMEOUT_US 200000 8988 8989 int 8990 ia_css_stop_sp(void) 8991 { 8992 unsigned long timeout; 8993 int err = 0; 8994 8995 IA_CSS_ENTER("void"); 8996 8997 if (!sh_css_sp_is_running()) { 8998 err = -EINVAL; 8999 IA_CSS_LEAVE("SP already stopped : return_err=%d", err); 9000 9001 /* Return an error - stop SP should not have been called by driver */ 9002 return err; 9003 } 9004 9005 /* For now, stop whole SP */ 9006 if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) { 9007 IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); 9008 ia_css_debug_dump_sp_sw_debug_info(); 9009 } 9010 9011 sh_css_sp_set_sp_running(false); 9012 9013 timeout = SP_SHUTDOWN_TIMEOUT_US; 9014 while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) { 9015 timeout--; 9016 udelay(1); 9017 } 9018 if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED) 9019 IA_CSS_WARNING("SP has not terminated (SW)"); 9020 9021 if (timeout == 0) { 9022 IA_CSS_WARNING("SP is not idle"); 9023 ia_css_debug_dump_sp_sw_debug_info(); 9024 } 9025 timeout = SP_SHUTDOWN_TIMEOUT_US; 9026 while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) { 9027 timeout--; 9028 udelay(1); 9029 } 9030 if (timeout == 0) { 9031 IA_CSS_WARNING("ISP is not idle"); 9032 ia_css_debug_dump_sp_sw_debug_info(); 9033 } 9034 9035 sh_css_hmm_buffer_record_uninit(); 9036 9037 /* clear pending param sets from refcount */ 9038 sh_css_param_clear_param_sets(); 9039 9040 IA_CSS_LEAVE_ERR(err); 9041 return err; 9042 } 9043 9044 int 9045 ia_css_update_continuous_frames(struct ia_css_stream *stream) 9046 { 9047 struct ia_css_pipe *pipe; 9048 unsigned int i; 9049 9050 ia_css_debug_dtrace( 9051 IA_CSS_DEBUG_TRACE, 9052 "sh_css_update_continuous_frames() enter:\n"); 9053 9054 if (!stream) { 9055 ia_css_debug_dtrace( 9056 IA_CSS_DEBUG_TRACE, 9057 "sh_css_update_continuous_frames() leave: invalid stream, return_void\n"); 9058 return -EINVAL; 9059 } 9060 9061 pipe = stream->continuous_pipe; 9062 9063 for (i = stream->config.init_num_cont_raw_buf; 9064 i < stream->config.target_num_cont_raw_buf; i++) 9065 sh_css_update_host2sp_offline_frame(i, 9066 pipe->continuous_frames[i], pipe->cont_md_buffers[i]); 9067 9068 sh_css_update_host2sp_cont_num_raw_frames 9069 (stream->config.target_num_cont_raw_buf, true); 9070 ia_css_debug_dtrace( 9071 IA_CSS_DEBUG_TRACE, 9072 "sh_css_update_continuous_frames() leave: return_void\n"); 9073 9074 return 0; 9075 } 9076 9077 void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map) 9078 { 9079 unsigned int thread_id; 9080 unsigned int pipe_num; 9081 bool need_input_queue; 9082 9083 IA_CSS_ENTER(""); 9084 assert(pipe); 9085 9086 pipe_num = pipe->pipe_num; 9087 9088 ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); 9089 9090 if (IS_ISP2401) 9091 need_input_queue = true; 9092 else 9093 need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 9094 9095 /* map required buffer queues to resources */ 9096 /* TODO: to be improved */ 9097 if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) { 9098 if (need_input_queue) 9099 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 9100 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 9101 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 9102 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 9103 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 9104 if (pipe->pipe_settings.preview.preview_binary.info && 9105 pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a) 9106 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 9107 } else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) { 9108 unsigned int i; 9109 9110 if (need_input_queue) 9111 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 9112 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 9113 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map); 9114 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 9115 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 9116 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 9117 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 9118 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 9119 if (pipe->pipe_settings.capture.primary_binary[i].info && 9120 pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) { 9121 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 9122 break; 9123 } 9124 } 9125 } else if (pipe->config.default_capture_config.mode == 9126 IA_CSS_CAPTURE_MODE_ADVANCED || 9127 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT || 9128 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) { 9129 if (pipe->pipe_settings.capture.pre_isp_binary.info && 9130 pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a) 9131 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 9132 } 9133 } else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) { 9134 if (need_input_queue) 9135 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 9136 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 9137 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) 9138 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map); 9139 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 9140 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 9141 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 9142 if (pipe->pipe_settings.video.video_binary.info && 9143 pipe->pipe_settings.video.video_binary.info->sp.enable.s3a) 9144 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 9145 if (pipe->pipe_settings.video.video_binary.info && 9146 (pipe->pipe_settings.video.video_binary.info->sp.enable.dis 9147 )) 9148 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map); 9149 } else if (pipe->mode == IA_CSS_PIPE_ID_COPY) { 9150 if (need_input_queue) 9151 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 9152 if (!pipe->stream->config.continuous) 9153 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 9154 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 9155 } else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) { 9156 unsigned int idx; 9157 9158 for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) { 9159 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map); 9160 if (pipe->enable_viewfinder[idx]) 9161 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map); 9162 } 9163 if (need_input_queue) 9164 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 9165 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 9166 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 9167 } 9168 IA_CSS_LEAVE(""); 9169 } 9170 9171 9172 int 9173 ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) 9174 { 9175 int ret; 9176 9177 IA_CSS_ENTER(""); 9178 9179 /* 9180 * Only continuous streams have a tagger to which we can send the 9181 * unlock message. 9182 */ 9183 if (!stream || !stream->config.continuous) { 9184 IA_CSS_ERROR("invalid stream pointer"); 9185 return -EINVAL; 9186 } 9187 9188 if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID || 9189 exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) { 9190 IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id); 9191 return -EINVAL; 9192 } 9193 9194 /* 9195 * Send the event. Since we verified that the exp_id is valid, 9196 * we can safely assign it to an 8-bit argument here. 9197 */ 9198 ret = ia_css_bufq_enqueue_psys_event( 9199 IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0); 9200 9201 IA_CSS_LEAVE_ERR(ret); 9202 return ret; 9203 } 9204 9205 static void 9206 sh_css_hmm_buffer_record_init(void) 9207 { 9208 int i; 9209 9210 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) 9211 sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]); 9212 } 9213 9214 static void 9215 sh_css_hmm_buffer_record_uninit(void) 9216 { 9217 int i; 9218 struct sh_css_hmm_buffer_record *buffer_record = NULL; 9219 9220 buffer_record = &hmm_buffer_record[0]; 9221 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 9222 if (buffer_record->in_use) { 9223 if (buffer_record->h_vbuf) 9224 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf); 9225 sh_css_hmm_buffer_record_reset(buffer_record); 9226 } 9227 buffer_record++; 9228 } 9229 } 9230 9231 static void 9232 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) 9233 { 9234 assert(buffer_record); 9235 buffer_record->in_use = false; 9236 buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID; 9237 buffer_record->h_vbuf = NULL; 9238 buffer_record->kernel_ptr = 0; 9239 } 9240 9241 static struct sh_css_hmm_buffer_record 9242 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf, 9243 enum ia_css_buffer_type type, 9244 hrt_address kernel_ptr) 9245 { 9246 int i; 9247 struct sh_css_hmm_buffer_record *buffer_record = NULL; 9248 struct sh_css_hmm_buffer_record *out_buffer_record = NULL; 9249 9250 assert(h_vbuf); 9251 assert((type > IA_CSS_BUFFER_TYPE_INVALID) && 9252 (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)); 9253 assert(kernel_ptr != 0); 9254 9255 buffer_record = &hmm_buffer_record[0]; 9256 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 9257 if (!buffer_record->in_use) { 9258 buffer_record->in_use = true; 9259 buffer_record->type = type; 9260 buffer_record->h_vbuf = h_vbuf; 9261 buffer_record->kernel_ptr = kernel_ptr; 9262 out_buffer_record = buffer_record; 9263 break; 9264 } 9265 buffer_record++; 9266 } 9267 9268 return out_buffer_record; 9269 } 9270 9271 static struct sh_css_hmm_buffer_record 9272 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr, 9273 enum ia_css_buffer_type type) 9274 { 9275 int i; 9276 struct sh_css_hmm_buffer_record *buffer_record = NULL; 9277 bool found_record = false; 9278 9279 buffer_record = &hmm_buffer_record[0]; 9280 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 9281 if ((buffer_record->in_use) && 9282 (buffer_record->type == type) && 9283 (buffer_record->h_vbuf) && 9284 (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) { 9285 found_record = true; 9286 break; 9287 } 9288 buffer_record++; 9289 } 9290 9291 if (found_record) 9292 return buffer_record; 9293 else 9294 return NULL; 9295 } 9296