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