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