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( 3228 const struct ia_css_stream_config *config) 3229 { 3230 assert(config); 3231 if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) 3232 || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) 3233 return 1; 3234 3235 return 0; 3236 } 3237 3238 static unsigned int 3239 get_crop_columns_for_bayer_order( 3240 const struct ia_css_stream_config *config) 3241 { 3242 assert(config); 3243 if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) 3244 || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) 3245 return 1; 3246 3247 return 0; 3248 } 3249 3250 /* This function is to get the sum of all extra pixels in addition to the effective 3251 * input, it includes dvs envelop and filter run-in */ 3252 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe, 3253 unsigned int *extra_row, unsigned int *extra_column) 3254 { 3255 enum ia_css_pipe_id pipe_id = pipe->mode; 3256 unsigned int left_cropping = 0, top_cropping = 0; 3257 unsigned int i; 3258 struct ia_css_resolution dvs_env = pipe->config.dvs_envelope; 3259 3260 /* The dvs envelope info may not be correctly sent down via pipe config 3261 * The check is made and the correct value is populated in the binary info 3262 * Use this value when computing crop, else excess lines may get trimmed 3263 */ 3264 switch (pipe_id) { 3265 case IA_CSS_PIPE_ID_PREVIEW: 3266 if (pipe->pipe_settings.preview.preview_binary.info) { 3267 left_cropping = 3268 pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping; 3269 top_cropping = 3270 pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping; 3271 } 3272 dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope; 3273 break; 3274 case IA_CSS_PIPE_ID_VIDEO: 3275 if (pipe->pipe_settings.video.video_binary.info) { 3276 left_cropping = 3277 pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping; 3278 top_cropping = 3279 pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping; 3280 } 3281 dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope; 3282 break; 3283 case IA_CSS_PIPE_ID_CAPTURE: 3284 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 3285 if (pipe->pipe_settings.capture.primary_binary[i].info) { 3286 left_cropping += 3287 pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping; 3288 top_cropping += 3289 pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping; 3290 } 3291 dvs_env.width += 3292 pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width; 3293 dvs_env.height += 3294 pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height; 3295 } 3296 break; 3297 default: 3298 break; 3299 } 3300 3301 *extra_row = top_cropping + dvs_env.height; 3302 *extra_column = left_cropping + dvs_env.width; 3303 } 3304 3305 void 3306 ia_css_get_crop_offsets( 3307 struct ia_css_pipe *pipe, 3308 struct ia_css_frame_info *in_frame) 3309 { 3310 unsigned int row = 0; 3311 unsigned int column = 0; 3312 struct ia_css_resolution *input_res; 3313 struct ia_css_resolution *effective_res; 3314 unsigned int extra_row = 0, extra_col = 0; 3315 unsigned int min_reqd_height, min_reqd_width; 3316 3317 assert(pipe); 3318 assert(pipe->stream); 3319 assert(in_frame); 3320 3321 IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u", 3322 pipe, pipe->config.input_effective_res.width, 3323 pipe->config.input_effective_res.height); 3324 3325 input_res = &pipe->stream->config.input_config.input_res; 3326 #ifndef ISP2401 3327 effective_res = &pipe->stream->config.input_config.effective_res; 3328 #else 3329 effective_res = &pipe->config.input_effective_res; 3330 #endif 3331 3332 get_pipe_extra_pixel(pipe, &extra_row, &extra_col); 3333 3334 in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order; 3335 3336 min_reqd_height = effective_res->height + extra_row; 3337 min_reqd_width = effective_res->width + extra_col; 3338 3339 if (input_res->height > min_reqd_height) { 3340 row = (input_res->height - min_reqd_height) / 2; 3341 row &= ~0x1; 3342 } 3343 if (input_res->width > min_reqd_width) { 3344 column = (input_res->width - min_reqd_width) / 2; 3345 column &= ~0x1; 3346 } 3347 3348 /* 3349 * TODO: 3350 * 1. Require the special support for RAW10 packed mode. 3351 * 2. Require the special support for the online use cases. 3352 */ 3353 3354 /* ISP expects GRBG bayer order, we skip one line and/or one row 3355 * to correct in case the input bayer order is different. 3356 */ 3357 column += get_crop_columns_for_bayer_order(&pipe->stream->config); 3358 row += get_crop_lines_for_bayer_order(&pipe->stream->config); 3359 3360 in_frame->crop_info.start_column = column; 3361 in_frame->crop_info.start_line = row; 3362 3363 IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row); 3364 3365 return; 3366 } 3367 #endif 3368 3369 static int 3370 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, 3371 struct ia_css_frame *frame, enum ia_css_frame_format format) 3372 { 3373 struct ia_css_frame *in_frame; 3374 int err = 0; 3375 unsigned int thread_id; 3376 enum sh_css_queue_id queue_id; 3377 3378 assert(frame); 3379 in_frame = frame; 3380 3381 in_frame->info.format = format; 3382 3383 #ifdef ISP2401 3384 if (format == IA_CSS_FRAME_FORMAT_RAW) 3385 in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ? 3386 IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW; 3387 #endif 3388 3389 in_frame->info.res.width = pipe->stream->config.input_config.input_res.width; 3390 in_frame->info.res.height = pipe->stream->config.input_config.input_res.height; 3391 in_frame->info.raw_bit_depth = 3392 ia_css_pipe_util_pipe_input_format_bpp(pipe); 3393 ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0); 3394 in_frame->contiguous = false; 3395 in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 3396 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3397 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id); 3398 in_frame->dynamic_queue_id = queue_id; 3399 in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME; 3400 #ifdef ISP2401 3401 ia_css_get_crop_offsets(pipe, &in_frame->info); 3402 #endif 3403 err = ia_css_frame_init_planes(in_frame); 3404 3405 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 3406 "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order); 3407 3408 return err; 3409 } 3410 3411 static int 3412 init_out_frameinfo_defaults(struct ia_css_pipe *pipe, 3413 struct ia_css_frame *out_frame, unsigned int idx) 3414 { 3415 int err = 0; 3416 unsigned int thread_id; 3417 enum sh_css_queue_id queue_id; 3418 3419 assert(out_frame); 3420 3421 sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx); 3422 out_frame->contiguous = false; 3423 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 3424 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3425 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id); 3426 out_frame->dynamic_queue_id = queue_id; 3427 out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx; 3428 err = ia_css_frame_init_planes(out_frame); 3429 3430 return err; 3431 } 3432 3433 /* Create stages for video pipe */ 3434 static int create_host_video_pipeline(struct ia_css_pipe *pipe) 3435 { 3436 struct ia_css_pipeline_stage_desc stage_desc; 3437 struct ia_css_binary *copy_binary, *video_binary, 3438 *yuv_scaler_binary, *vf_pp_binary; 3439 struct ia_css_pipeline_stage *copy_stage = NULL; 3440 struct ia_css_pipeline_stage *video_stage = NULL; 3441 struct ia_css_pipeline_stage *yuv_scaler_stage = NULL; 3442 struct ia_css_pipeline_stage *vf_pp_stage = NULL; 3443 struct ia_css_pipeline *me; 3444 struct ia_css_frame *in_frame = NULL; 3445 struct ia_css_frame *out_frame; 3446 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 3447 struct ia_css_frame *vf_frame = NULL; 3448 int err = 0; 3449 bool need_copy = false; 3450 bool need_vf_pp = false; 3451 bool need_yuv_pp = false; 3452 bool need_in_frameinfo_memory = false; 3453 3454 unsigned int i, num_yuv_scaler; 3455 bool *is_output_stage = NULL; 3456 3457 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3458 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 3459 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3460 return -EINVAL; 3461 } 3462 ia_css_pipe_util_create_output_frames(out_frames); 3463 out_frame = &pipe->out_frame_struct; 3464 3465 /* pipeline already created as part of create_host_pipeline_structure */ 3466 me = &pipe->pipeline; 3467 ia_css_pipeline_clean(me); 3468 3469 me->dvs_frame_delay = pipe->dvs_frame_delay; 3470 3471 #ifdef ISP2401 3472 /* When the input system is 2401, always enable 'in_frameinfo_memory' 3473 * except for the following: online or continuous 3474 */ 3475 need_in_frameinfo_memory = !(pipe->stream->config.online || 3476 pipe->stream->config.continuous); 3477 #else 3478 /* Construct in_frame info (only in case we have dynamic input */ 3479 need_in_frameinfo_memory = pipe->stream->config.mode == 3480 IA_CSS_INPUT_MODE_MEMORY; 3481 #endif 3482 3483 /* Construct in_frame info (only in case we have dynamic input */ 3484 if (need_in_frameinfo_memory) { 3485 in_frame = &pipe->in_frame_struct; 3486 err = init_in_frameinfo_memory_defaults(pipe, in_frame, 3487 IA_CSS_FRAME_FORMAT_RAW); 3488 if (err) 3489 goto ERR; 3490 } 3491 3492 out_frame->data = 0; 3493 err = init_out_frameinfo_defaults(pipe, out_frame, 0); 3494 if (err) 3495 goto ERR; 3496 3497 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 3498 vf_frame = &pipe->vf_frame_struct; 3499 vf_frame->data = 0; 3500 err = init_vf_frameinfo_defaults(pipe, vf_frame, 0); 3501 if (err) 3502 goto ERR; 3503 } 3504 3505 copy_binary = &pipe->pipe_settings.video.copy_binary; 3506 video_binary = &pipe->pipe_settings.video.video_binary; 3507 vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary; 3508 3509 yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary; 3510 num_yuv_scaler = pipe->pipe_settings.video.num_yuv_scaler; 3511 is_output_stage = pipe->pipe_settings.video.is_output_stage; 3512 3513 need_copy = (copy_binary && copy_binary->info); 3514 need_vf_pp = (vf_pp_binary && vf_pp_binary->info); 3515 need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info); 3516 3517 if (need_copy) { 3518 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3519 ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, 3520 out_frames, NULL, NULL); 3521 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3522 ©_stage); 3523 if (err) 3524 goto ERR; 3525 in_frame = me->stages->args.out_frame[0]; 3526 } else if (pipe->stream->config.continuous) { 3527 #ifdef ISP2401 3528 /* When continuous is enabled, configure in_frame with the 3529 * last pipe, which is the copy pipe. 3530 */ 3531 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 3532 #else 3533 in_frame = pipe->continuous_frames[0]; 3534 #endif 3535 } 3536 3537 ia_css_pipe_util_set_output_frames(out_frames, 0, 3538 need_yuv_pp ? NULL : out_frame); 3539 3540 /* when the video binary supports a second output pin, 3541 it can directly produce the vf_frame. */ 3542 if (need_vf_pp) { 3543 ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary, 3544 out_frames, in_frame, NULL); 3545 } else { 3546 ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary, 3547 out_frames, in_frame, vf_frame); 3548 } 3549 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3550 &video_stage); 3551 if (err) 3552 goto ERR; 3553 3554 /* If we use copy iso video, the input must be yuv iso raw */ 3555 if (video_stage) { 3556 video_stage->args.copy_vf = 3557 video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY; 3558 video_stage->args.copy_output = video_stage->args.copy_vf; 3559 } 3560 3561 /* when the video binary supports only 1 output pin, vf_pp is needed to 3562 produce the vf_frame.*/ 3563 if (need_vf_pp && video_stage) { 3564 in_frame = video_stage->args.out_vf_frame; 3565 err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary, 3566 &vf_pp_stage); 3567 if (err) 3568 goto ERR; 3569 } 3570 if (video_stage) { 3571 int frm; 3572 3573 for (frm = 0; frm < NUM_TNR_FRAMES; frm++) { 3574 video_stage->args.tnr_frames[frm] = 3575 pipe->pipe_settings.video.tnr_frames[frm]; 3576 } 3577 for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) { 3578 video_stage->args.delay_frames[frm] = 3579 pipe->pipe_settings.video.delay_frames[frm]; 3580 } 3581 } 3582 3583 /* Append Extension on Video out, if enabled */ 3584 if (!need_vf_pp && video_stage && pipe->config.acc_extension && 3585 (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) { 3586 struct ia_css_frame *out = NULL; 3587 struct ia_css_frame *in = NULL; 3588 3589 if ((pipe->config.acc_extension->info.isp.sp.enable.output) && 3590 (pipe->config.acc_extension->info.isp.sp.enable.in_frame) && 3591 (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) { 3592 /* In/Out Frame mapping to support output frame extension.*/ 3593 out = video_stage->args.out_frame[0]; 3594 err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]); 3595 if (err) 3596 goto ERR; 3597 video_stage->args.out_frame[0] = in; 3598 } 3599 3600 err = add_firmwares(me, video_binary, pipe->output_stage, 3601 last_output_firmware(pipe->output_stage), 3602 IA_CSS_BINARY_MODE_VIDEO, 3603 in, out, NULL, &video_stage, NULL); 3604 if (err) 3605 goto ERR; 3606 } 3607 3608 if (need_yuv_pp && video_stage) { 3609 struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0]; 3610 struct ia_css_frame *tmp_out_frame = NULL; 3611 3612 for (i = 0; i < num_yuv_scaler; i++) { 3613 tmp_out_frame = is_output_stage[i] ? out_frame : NULL; 3614 3615 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 3616 tmp_out_frame, NULL, 3617 &yuv_scaler_binary[i], 3618 &yuv_scaler_stage); 3619 3620 if (err) { 3621 IA_CSS_LEAVE_ERR_PRIVATE(err); 3622 return err; 3623 } 3624 /* we use output port 1 as internal output port */ 3625 if (yuv_scaler_stage) 3626 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 3627 } 3628 } 3629 3630 pipe->pipeline.acquire_isp_each_stage = false; 3631 ia_css_pipeline_finalize_stages(&pipe->pipeline, 3632 pipe->stream->config.continuous); 3633 3634 ERR: 3635 IA_CSS_LEAVE_ERR_PRIVATE(err); 3636 return err; 3637 } 3638 3639 static int 3640 create_host_acc_pipeline(struct ia_css_pipe *pipe) 3641 { 3642 int err = 0; 3643 const struct ia_css_fw_info *fw; 3644 unsigned int i; 3645 3646 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3647 if ((!pipe) || (!pipe->stream)) { 3648 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3649 return -EINVAL; 3650 } 3651 3652 pipe->pipeline.num_execs = pipe->config.acc_num_execs; 3653 /* Reset pipe_qos_config to default disable all QOS extension stages */ 3654 if (pipe->config.acc_extension) 3655 pipe->pipeline.pipe_qos_config = 0; 3656 3657 fw = pipe->vf_stage; 3658 for (i = 0; fw; fw = fw->next) { 3659 err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); 3660 if (err) 3661 goto ERR; 3662 } 3663 3664 for (i = 0; i < pipe->config.num_acc_stages; i++) { 3665 struct ia_css_fw_info *fw = pipe->config.acc_stages[i]; 3666 3667 err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); 3668 if (err) 3669 goto ERR; 3670 } 3671 3672 ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); 3673 3674 ERR: 3675 IA_CSS_LEAVE_ERR_PRIVATE(err); 3676 return err; 3677 } 3678 3679 /* Create stages for preview */ 3680 static int 3681 create_host_preview_pipeline(struct ia_css_pipe *pipe) 3682 { 3683 struct ia_css_pipeline_stage *copy_stage = NULL; 3684 struct ia_css_pipeline_stage *preview_stage = NULL; 3685 struct ia_css_pipeline_stage *vf_pp_stage = NULL; 3686 struct ia_css_pipeline_stage_desc stage_desc; 3687 struct ia_css_pipeline *me = NULL; 3688 struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL; 3689 struct ia_css_frame *in_frame = NULL; 3690 int err = 0; 3691 struct ia_css_frame *out_frame; 3692 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 3693 bool need_in_frameinfo_memory = false; 3694 #ifdef ISP2401 3695 bool sensor = false; 3696 bool buffered_sensor = false; 3697 bool online = false; 3698 bool continuous = false; 3699 #endif 3700 3701 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3702 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { 3703 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3704 return -EINVAL; 3705 } 3706 3707 ia_css_pipe_util_create_output_frames(out_frames); 3708 /* pipeline already created as part of create_host_pipeline_structure */ 3709 me = &pipe->pipeline; 3710 ia_css_pipeline_clean(me); 3711 3712 #ifdef ISP2401 3713 /* When the input system is 2401, always enable 'in_frameinfo_memory' 3714 * except for the following: 3715 * - Direct Sensor Mode Online Preview 3716 * - Buffered Sensor Mode Online Preview 3717 * - Direct Sensor Mode Continuous Preview 3718 * - Buffered Sensor Mode Continuous Preview 3719 */ 3720 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 3721 buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 3722 online = pipe->stream->config.online; 3723 continuous = pipe->stream->config.continuous; 3724 need_in_frameinfo_memory = 3725 !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous))); 3726 #else 3727 /* Construct in_frame info (only in case we have dynamic input */ 3728 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 3729 #endif 3730 if (need_in_frameinfo_memory) { 3731 err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, 3732 IA_CSS_FRAME_FORMAT_RAW); 3733 if (err) 3734 goto ERR; 3735 3736 in_frame = &me->in_frame; 3737 } else { 3738 in_frame = NULL; 3739 } 3740 3741 err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0); 3742 if (err) 3743 goto ERR; 3744 out_frame = &me->out_frame[0]; 3745 3746 copy_binary = &pipe->pipe_settings.preview.copy_binary; 3747 preview_binary = &pipe->pipe_settings.preview.preview_binary; 3748 if (pipe->pipe_settings.preview.vf_pp_binary.info) 3749 vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary; 3750 3751 if (pipe->pipe_settings.preview.copy_binary.info) { 3752 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3753 ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, 3754 out_frames, NULL, NULL); 3755 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3756 ©_stage); 3757 if (err) 3758 goto ERR; 3759 in_frame = me->stages->args.out_frame[0]; 3760 } else if (pipe->stream->config.continuous) { 3761 #ifdef ISP2401 3762 /* When continuous is enabled, configure in_frame with the 3763 * last pipe, which is the copy pipe. 3764 */ 3765 if (continuous || !online) 3766 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 3767 3768 #else 3769 in_frame = pipe->continuous_frames[0]; 3770 #endif 3771 } 3772 3773 if (vf_pp_binary) { 3774 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 3775 ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, 3776 out_frames, in_frame, NULL); 3777 } else { 3778 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 3779 ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, 3780 out_frames, in_frame, NULL); 3781 } 3782 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 3783 &preview_stage); 3784 if (err) 3785 goto ERR; 3786 /* If we use copy iso preview, the input must be yuv iso raw */ 3787 preview_stage->args.copy_vf = 3788 preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY; 3789 preview_stage->args.copy_output = !preview_stage->args.copy_vf; 3790 if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) { 3791 /* in case of copy, use the vf frame as output frame */ 3792 preview_stage->args.out_vf_frame = 3793 preview_stage->args.out_frame[0]; 3794 } 3795 if (vf_pp_binary) { 3796 if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY) 3797 in_frame = preview_stage->args.out_vf_frame; 3798 else 3799 in_frame = preview_stage->args.out_frame[0]; 3800 err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary, 3801 &vf_pp_stage); 3802 if (err) 3803 goto ERR; 3804 } 3805 3806 pipe->pipeline.acquire_isp_each_stage = false; 3807 ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); 3808 3809 ERR: 3810 IA_CSS_LEAVE_ERR_PRIVATE(err); 3811 return err; 3812 } 3813 3814 static void send_raw_frames(struct ia_css_pipe *pipe) 3815 { 3816 if (pipe->stream->config.continuous) { 3817 unsigned int i; 3818 3819 sh_css_update_host2sp_cont_num_raw_frames 3820 (pipe->stream->config.init_num_cont_raw_buf, true); 3821 sh_css_update_host2sp_cont_num_raw_frames 3822 (pipe->stream->config.target_num_cont_raw_buf, false); 3823 3824 /* Hand-over all the SP-internal buffers */ 3825 for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) { 3826 sh_css_update_host2sp_offline_frame(i, 3827 pipe->continuous_frames[i], pipe->cont_md_buffers[i]); 3828 } 3829 } 3830 3831 return; 3832 } 3833 3834 static int 3835 preview_start(struct ia_css_pipe *pipe) 3836 { 3837 int err = 0; 3838 struct ia_css_pipe *copy_pipe, *capture_pipe; 3839 struct ia_css_pipe *acc_pipe; 3840 enum sh_css_pipe_config_override copy_ovrd; 3841 enum ia_css_input_mode preview_pipe_input_mode; 3842 const struct ia_css_coordinate *coord = NULL; 3843 const struct ia_css_isp_parameters *params = NULL; 3844 3845 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 3846 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { 3847 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 3848 return -EINVAL; 3849 } 3850 3851 preview_pipe_input_mode = pipe->stream->config.mode; 3852 3853 copy_pipe = pipe->pipe_settings.preview.copy_pipe; 3854 capture_pipe = pipe->pipe_settings.preview.capture_pipe; 3855 acc_pipe = pipe->pipe_settings.preview.acc_pipe; 3856 3857 sh_css_metrics_start_frame(); 3858 3859 /* multi stream video needs mipi buffers */ 3860 err = send_mipi_frames(pipe); 3861 if (err) { 3862 IA_CSS_LEAVE_ERR_PRIVATE(err); 3863 return err; 3864 } 3865 send_raw_frames(pipe); 3866 3867 { 3868 unsigned int thread_id; 3869 3870 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 3871 copy_ovrd = 1 << thread_id; 3872 3873 if (pipe->stream->cont_capt) { 3874 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 3875 &thread_id); 3876 copy_ovrd |= 1 << thread_id; 3877 } 3878 } 3879 3880 if (IS_ISP2401) { 3881 coord = &pipe->config.internal_frame_origin_bqs_on_sctbl; 3882 params = pipe->stream->isp_params_configs; 3883 } 3884 3885 /* Construct and load the copy pipe */ 3886 if (pipe->stream->config.continuous) { 3887 sh_css_sp_init_pipeline(©_pipe->pipeline, 3888 IA_CSS_PIPE_ID_COPY, 3889 (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe), 3890 false, 3891 pipe->stream->config.pixels_per_clock == 2, false, 3892 false, pipe->required_bds_factor, 3893 copy_ovrd, 3894 pipe->stream->config.mode, 3895 &pipe->stream->config.metadata_config, 3896 &pipe->stream->info.metadata_info, 3897 pipe->stream->config.source.port.port, 3898 coord, 3899 params); 3900 3901 /* make the preview pipe start with mem mode input, copy handles 3902 the actual mode */ 3903 preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY; 3904 } 3905 3906 /* Construct and load the capture pipe */ 3907 if (pipe->stream->cont_capt) { 3908 sh_css_sp_init_pipeline(&capture_pipe->pipeline, 3909 IA_CSS_PIPE_ID_CAPTURE, 3910 (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe), 3911 capture_pipe->config.default_capture_config.enable_xnr != 0, 3912 capture_pipe->stream->config.pixels_per_clock == 2, 3913 true, /* continuous */ 3914 false, /* offline */ 3915 capture_pipe->required_bds_factor, 3916 0, 3917 IA_CSS_INPUT_MODE_MEMORY, 3918 &pipe->stream->config.metadata_config, 3919 &pipe->stream->info.metadata_info, 3920 (enum mipi_port_id)0, 3921 coord, 3922 params); 3923 } 3924 3925 if (acc_pipe) { 3926 sh_css_sp_init_pipeline(&acc_pipe->pipeline, 3927 IA_CSS_PIPE_ID_ACC, 3928 (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe), 3929 false, 3930 pipe->stream->config.pixels_per_clock == 2, 3931 false, /* continuous */ 3932 false, /* offline */ 3933 pipe->required_bds_factor, 3934 0, 3935 IA_CSS_INPUT_MODE_MEMORY, 3936 NULL, 3937 NULL, 3938 (enum mipi_port_id)0, 3939 coord, 3940 params); 3941 } 3942 3943 start_pipe(pipe, copy_ovrd, preview_pipe_input_mode); 3944 3945 IA_CSS_LEAVE_ERR_PRIVATE(err); 3946 return err; 3947 } 3948 3949 int 3950 ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, 3951 const struct ia_css_buffer *buffer) 3952 { 3953 int return_err = 0; 3954 unsigned int thread_id; 3955 enum sh_css_queue_id queue_id; 3956 struct ia_css_pipeline *pipeline; 3957 struct ia_css_pipeline_stage *stage; 3958 struct ia_css_rmgr_vbuf_handle p_vbuf; 3959 struct ia_css_rmgr_vbuf_handle *h_vbuf; 3960 struct sh_css_hmm_buffer ddr_buffer; 3961 enum ia_css_buffer_type buf_type; 3962 enum ia_css_pipe_id pipe_id; 3963 bool ret_err; 3964 3965 IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); 3966 3967 if ((!pipe) || (!buffer)) { 3968 IA_CSS_LEAVE_ERR(-EINVAL); 3969 return -EINVAL; 3970 } 3971 3972 buf_type = buffer->type; 3973 /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME 3974 is removed */ 3975 #if 0 3976 if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { 3977 bool found_pipe = false; 3978 3979 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 3980 if ((buffer->data.frame->info.res.width == pipe->output_info[i].res.width) && 3981 (buffer->data.frame->info.res.height == pipe->output_info[i].res.height)) { 3982 buf_type += i; 3983 found_pipe = true; 3984 break; 3985 } 3986 } 3987 if (!found_pipe) 3988 return -EINVAL; 3989 } 3990 if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 3991 bool found_pipe = false; 3992 3993 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 3994 if ((buffer->data.frame->info.res.width == pipe->vf_output_info[i].res.width) && 3995 (buffer->data.frame->info.res.height == pipe->vf_output_info[i].res.height)) { 3996 buf_type += i; 3997 found_pipe = true; 3998 break; 3999 } 4000 } 4001 if (!found_pipe) 4002 return -EINVAL; 4003 } 4004 #endif 4005 pipe_id = pipe->mode; 4006 4007 IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type); 4008 4009 assert(pipe_id < IA_CSS_PIPE_ID_NUM); 4010 assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); 4011 if (buf_type == IA_CSS_BUFFER_TYPE_INVALID || 4012 buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE || 4013 pipe_id >= IA_CSS_PIPE_ID_NUM) { 4014 IA_CSS_LEAVE_ERR(-EINVAL); 4015 return -EINVAL; 4016 } 4017 4018 ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 4019 if (!ret_err) { 4020 IA_CSS_LEAVE_ERR(-EINVAL); 4021 return -EINVAL; 4022 } 4023 4024 ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); 4025 if (!ret_err) { 4026 IA_CSS_LEAVE_ERR(-EINVAL); 4027 return -EINVAL; 4028 } 4029 4030 if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { 4031 IA_CSS_LEAVE_ERR(-EINVAL); 4032 return -EINVAL; 4033 } 4034 4035 if (!sh_css_sp_is_running()) { 4036 IA_CSS_LOG("SP is not running!"); 4037 IA_CSS_LEAVE_ERR(-EBUSY); 4038 /* SP is not running. The queues are not valid */ 4039 return -EBUSY; 4040 } 4041 4042 pipeline = &pipe->pipeline; 4043 4044 assert(pipeline || 4045 pipe_id == IA_CSS_PIPE_ID_COPY || 4046 pipe_id == IA_CSS_PIPE_ID_ACC); 4047 4048 assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr)); 4049 ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL); 4050 ddr_buffer.cookie_ptr = buffer->driver_cookie; 4051 ddr_buffer.timing_data = buffer->timing_data; 4052 4053 if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) { 4054 if (!buffer->data.stats_3a) { 4055 IA_CSS_LEAVE_ERR(-EINVAL); 4056 return -EINVAL; 4057 } 4058 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a); 4059 ddr_buffer.payload.s3a = *buffer->data.stats_3a; 4060 } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) { 4061 if (!buffer->data.stats_dvs) { 4062 IA_CSS_LEAVE_ERR(-EINVAL); 4063 return -EINVAL; 4064 } 4065 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs); 4066 ddr_buffer.payload.dis = *buffer->data.stats_dvs; 4067 } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) { 4068 if (!buffer->data.metadata) { 4069 IA_CSS_LEAVE_ERR(-EINVAL); 4070 return -EINVAL; 4071 } 4072 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata); 4073 ddr_buffer.payload.metadata = *buffer->data.metadata; 4074 } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || 4075 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 4076 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || 4077 buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || 4078 buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) { 4079 if (!buffer->data.frame) { 4080 IA_CSS_LEAVE_ERR(-EINVAL); 4081 return -EINVAL; 4082 } 4083 ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame); 4084 ddr_buffer.payload.frame.frame_data = buffer->data.frame->data; 4085 ddr_buffer.payload.frame.flashed = 0; 4086 4087 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4088 "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n", 4089 buf_type, buffer->data.frame->data); 4090 4091 #if CONFIG_ON_FRAME_ENQUEUE() 4092 return_err = set_config_on_frame_enqueue( 4093 &buffer->data.frame->info, 4094 &ddr_buffer.payload.frame); 4095 if (return_err) { 4096 IA_CSS_LEAVE_ERR(return_err); 4097 return return_err; 4098 } 4099 #endif 4100 } 4101 4102 /* start of test for using rmgr for acq/rel memory */ 4103 p_vbuf.vptr = 0; 4104 p_vbuf.count = 0; 4105 p_vbuf.size = sizeof(struct sh_css_hmm_buffer); 4106 h_vbuf = &p_vbuf; 4107 /* TODO: change next to correct pool for optimization */ 4108 ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf); 4109 4110 if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) { 4111 IA_CSS_LEAVE_ERR(-EINVAL); 4112 return -EINVAL; 4113 } 4114 4115 hmm_store(h_vbuf->vptr, 4116 (void *)(&ddr_buffer), 4117 sizeof(struct sh_css_hmm_buffer)); 4118 if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS || 4119 buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS || 4120 buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) { 4121 if (!pipeline) { 4122 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); 4123 IA_CSS_LOG("pipeline is empty!"); 4124 IA_CSS_LEAVE_ERR(-EINVAL); 4125 return -EINVAL; 4126 } 4127 4128 for (stage = pipeline->stages; stage; stage = stage->next) { 4129 /* The SP will read the params 4130 after it got empty 3a and dis */ 4131 if (STATS_ENABLED(stage)) { 4132 /* there is a stage that needs it */ 4133 return_err = ia_css_bufq_enqueue_buffer(thread_id, 4134 queue_id, 4135 (uint32_t)h_vbuf->vptr); 4136 } 4137 } 4138 } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || 4139 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 4140 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || 4141 buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || 4142 buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME || 4143 buf_type == IA_CSS_BUFFER_TYPE_METADATA) { 4144 return_err = ia_css_bufq_enqueue_buffer(thread_id, 4145 queue_id, 4146 (uint32_t)h_vbuf->vptr); 4147 #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) 4148 if (!return_err && 4149 buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { 4150 IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d", 4151 ddr_buffer.payload.frame.frame_data, 4152 queue_id, thread_id); 4153 } 4154 #endif 4155 } 4156 4157 if (!return_err) { 4158 if (sh_css_hmm_buffer_record_acquire( 4159 h_vbuf, buf_type, 4160 HOST_ADDRESS(ddr_buffer.kernel_ptr))) { 4161 IA_CSS_LOG("send vbuf=%p", h_vbuf); 4162 } else { 4163 return_err = -EINVAL; 4164 IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n"); 4165 } 4166 } 4167 4168 /* 4169 * Tell the SP which queues are not empty, 4170 * by sending the software event. 4171 */ 4172 if (!return_err) { 4173 if (!sh_css_sp_is_running()) { 4174 /* SP is not running. The queues are not valid */ 4175 IA_CSS_LOG("SP is not running!"); 4176 IA_CSS_LEAVE_ERR(-EBUSY); 4177 return -EBUSY; 4178 } 4179 return_err = ia_css_bufq_enqueue_psys_event( 4180 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED, 4181 (uint8_t)thread_id, 4182 queue_id, 4183 0); 4184 } else { 4185 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); 4186 IA_CSS_ERROR("buffer not enqueued"); 4187 } 4188 4189 IA_CSS_LEAVE("return value = %d", return_err); 4190 4191 return return_err; 4192 } 4193 4194 /* 4195 * TODO: Free up the hmm memory space. 4196 */ 4197 int 4198 ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, 4199 struct ia_css_buffer *buffer) 4200 { 4201 int return_err; 4202 enum sh_css_queue_id queue_id; 4203 ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0; 4204 struct sh_css_hmm_buffer ddr_buffer; 4205 enum ia_css_buffer_type buf_type; 4206 enum ia_css_pipe_id pipe_id; 4207 unsigned int thread_id; 4208 hrt_address kernel_ptr = 0; 4209 bool ret_err; 4210 4211 IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); 4212 4213 if ((!pipe) || (!buffer)) { 4214 IA_CSS_LEAVE_ERR(-EINVAL); 4215 return -EINVAL; 4216 } 4217 4218 pipe_id = pipe->mode; 4219 4220 buf_type = buffer->type; 4221 4222 IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type); 4223 4224 ddr_buffer.kernel_ptr = 0; 4225 4226 ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 4227 if (!ret_err) { 4228 IA_CSS_LEAVE_ERR(-EINVAL); 4229 return -EINVAL; 4230 } 4231 4232 ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); 4233 if (!ret_err) { 4234 IA_CSS_LEAVE_ERR(-EINVAL); 4235 return -EINVAL; 4236 } 4237 4238 if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { 4239 IA_CSS_LEAVE_ERR(-EINVAL); 4240 return -EINVAL; 4241 } 4242 4243 if (!sh_css_sp_is_running()) { 4244 IA_CSS_LOG("SP is not running!"); 4245 IA_CSS_LEAVE_ERR(-EBUSY); 4246 /* SP is not running. The queues are not valid */ 4247 return -EBUSY; 4248 } 4249 4250 return_err = ia_css_bufq_dequeue_buffer(queue_id, 4251 (uint32_t *)&ddr_buffer_addr); 4252 4253 if (!return_err) { 4254 struct ia_css_frame *frame; 4255 struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL; 4256 4257 IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr); 4258 4259 /* Validate the ddr_buffer_addr and buf_type */ 4260 hmm_buffer_record = sh_css_hmm_buffer_record_validate( 4261 ddr_buffer_addr, buf_type); 4262 if (hmm_buffer_record) { 4263 /* valid hmm_buffer_record found. Save the kernel_ptr 4264 * for validation after performing hmm_load. The 4265 * vbuf handle and buffer_record can be released. 4266 */ 4267 kernel_ptr = hmm_buffer_record->kernel_ptr; 4268 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf); 4269 sh_css_hmm_buffer_record_reset(hmm_buffer_record); 4270 } else { 4271 IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)", 4272 ddr_buffer_addr, buf_type); 4273 IA_CSS_LEAVE_ERR(-EINVAL); 4274 return -EINVAL; 4275 } 4276 4277 hmm_load(ddr_buffer_addr, 4278 &ddr_buffer, 4279 sizeof(struct sh_css_hmm_buffer)); 4280 4281 /* if the kernel_ptr is 0 or an invalid, return an error. 4282 * do not access the buffer via the kernal_ptr. 4283 */ 4284 if ((ddr_buffer.kernel_ptr == 0) || 4285 (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) { 4286 IA_CSS_ERROR("kernel_ptr invalid"); 4287 IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr); 4288 IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr)); 4289 IA_CSS_ERROR("buf_type: %d\n", buf_type); 4290 IA_CSS_LEAVE_ERR(-EINVAL); 4291 return -EINVAL; 4292 } 4293 4294 if (ddr_buffer.kernel_ptr != 0) { 4295 /* buffer->exp_id : all instances to be removed later once the driver change 4296 * is completed. See patch #5758 for reference */ 4297 buffer->exp_id = 0; 4298 buffer->driver_cookie = ddr_buffer.cookie_ptr; 4299 buffer->timing_data = ddr_buffer.timing_data; 4300 4301 if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || 4302 buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 4303 buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick; 4304 } 4305 4306 switch (buf_type) { 4307 case IA_CSS_BUFFER_TYPE_INPUT_FRAME: 4308 case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: 4309 case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 4310 if (pipe && pipe->stop_requested) { 4311 #if !defined(ISP2401) 4312 /* free mipi frames only for old input system 4313 * for 2401 it is done in ia_css_stream_destroy call 4314 */ 4315 return_err = free_mipi_frames(pipe); 4316 if (return_err) { 4317 IA_CSS_LOG("free_mipi_frames() failed"); 4318 IA_CSS_LEAVE_ERR(return_err); 4319 return return_err; 4320 } 4321 #endif 4322 pipe->stop_requested = false; 4323 } 4324 fallthrough; 4325 case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: 4326 case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: 4327 frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 4328 buffer->data.frame = frame; 4329 buffer->exp_id = ddr_buffer.payload.frame.exp_id; 4330 frame->exp_id = ddr_buffer.payload.frame.exp_id; 4331 frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id; 4332 if (ddr_buffer.payload.frame.flashed == 1) 4333 frame->flash_state = 4334 IA_CSS_FRAME_FLASH_STATE_PARTIAL; 4335 if (ddr_buffer.payload.frame.flashed == 2) 4336 frame->flash_state = 4337 IA_CSS_FRAME_FLASH_STATE_FULL; 4338 frame->valid = pipe->num_invalid_frames == 0; 4339 if (!frame->valid) 4340 pipe->num_invalid_frames--; 4341 4342 if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) { 4343 #ifdef ISP2401 4344 frame->planes.binary.size = frame->data_bytes; 4345 #else 4346 frame->planes.binary.size = 4347 sh_css_sp_get_binary_copy_size(); 4348 #endif 4349 } 4350 #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) 4351 if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { 4352 IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d", 4353 frame->data, frame->isp_config_id, thread_id); 4354 } 4355 #endif 4356 4357 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4358 "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n", 4359 buf_type, buffer->data.frame->data); 4360 4361 break; 4362 case IA_CSS_BUFFER_TYPE_3A_STATISTICS: 4363 buffer->data.stats_3a = 4364 (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 4365 buffer->exp_id = ddr_buffer.payload.s3a.exp_id; 4366 buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id; 4367 buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id; 4368 break; 4369 case IA_CSS_BUFFER_TYPE_DIS_STATISTICS: 4370 buffer->data.stats_dvs = 4371 (struct ia_css_isp_dvs_statistics *) 4372 HOST_ADDRESS(ddr_buffer.kernel_ptr); 4373 buffer->exp_id = ddr_buffer.payload.dis.exp_id; 4374 buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id; 4375 break; 4376 case IA_CSS_BUFFER_TYPE_LACE_STATISTICS: 4377 break; 4378 case IA_CSS_BUFFER_TYPE_METADATA: 4379 buffer->data.metadata = 4380 (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr); 4381 buffer->exp_id = ddr_buffer.payload.metadata.exp_id; 4382 buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id; 4383 break; 4384 default: 4385 return_err = -EINVAL; 4386 break; 4387 } 4388 } 4389 } 4390 4391 /* 4392 * Tell the SP which queues are not full, 4393 * by sending the software event. 4394 */ 4395 if (!return_err) { 4396 if (!sh_css_sp_is_running()) { 4397 IA_CSS_LOG("SP is not running!"); 4398 IA_CSS_LEAVE_ERR(-EBUSY); 4399 /* SP is not running. The queues are not valid */ 4400 return -EBUSY; 4401 } 4402 ia_css_bufq_enqueue_psys_event( 4403 IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED, 4404 0, 4405 queue_id, 4406 0); 4407 } 4408 IA_CSS_LEAVE("buffer=%p", buffer); 4409 4410 return return_err; 4411 } 4412 4413 /* 4414 * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h 4415 * TODO: modify and move it if possible. 4416 * 4417 * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC: 4418 * 1) "enum ia_css_event_type" (ia_css_event_public.h) 4419 * 2) "enum sh_css_sp_event_type" (sh_css_internal.h) 4420 * 3) "enum ia_css_event_type event_id_2_event_mask" (event_handler.sp.c) 4421 * 4) "enum ia_css_event_type convert_event_sp_to_host_domain" (sh_css.c) 4422 */ 4423 static enum ia_css_event_type convert_event_sp_to_host_domain[] = { 4424 IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE, /** Output frame ready. */ 4425 IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE, /** Second output frame ready. */ 4426 IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE, /** Viewfinder Output frame ready. */ 4427 IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE, /** Second viewfinder Output frame ready. */ 4428 IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE, /** Indication that 3A statistics are available. */ 4429 IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE, /** Indication that DIS statistics are available. */ 4430 IA_CSS_EVENT_TYPE_PIPELINE_DONE, /** Pipeline Done event, sent after last pipeline stage. */ 4431 IA_CSS_EVENT_TYPE_FRAME_TAGGED, /** Frame tagged. */ 4432 IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE, /** Input frame ready. */ 4433 IA_CSS_EVENT_TYPE_METADATA_DONE, /** Metadata ready. */ 4434 IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE, /** Indication that LACE statistics are available. */ 4435 IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE, /** Extension stage executed. */ 4436 IA_CSS_EVENT_TYPE_TIMER, /** Timing measurement data. */ 4437 IA_CSS_EVENT_TYPE_PORT_EOF, /** End Of Frame event, sent when in buffered sensor mode. */ 4438 IA_CSS_EVENT_TYPE_FW_WARNING, /** Performance warning encountered by FW */ 4439 IA_CSS_EVENT_TYPE_FW_ASSERT, /** Assertion hit by FW */ 4440 0, /* error if sp passes SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */ 4441 }; 4442 4443 int 4444 ia_css_dequeue_event(struct ia_css_event *event) 4445 { 4446 return ia_css_dequeue_psys_event(event); 4447 } 4448 4449 int 4450 ia_css_dequeue_psys_event(struct ia_css_event *event) 4451 { 4452 enum ia_css_pipe_id pipe_id = 0; 4453 u8 payload[4] = {0, 0, 0, 0}; 4454 int ret_err; 4455 4456 /*TODO: 4457 * a) use generic decoding function , same as the one used by sp. 4458 * b) group decode and dequeue into eventQueue module 4459 * 4460 * We skip the IA_CSS_ENTER logging call 4461 * to avoid flooding the logs when the host application 4462 * uses polling. */ 4463 if (!event) 4464 return -EINVAL; 4465 4466 /* SP is not running. The queues are not valid */ 4467 if (!sh_css_sp_is_running()) 4468 return -EBUSY; 4469 4470 /* dequeue the event (if any) from the psys event queue */ 4471 ret_err = ia_css_bufq_dequeue_psys_event(payload); 4472 if (ret_err) 4473 return ret_err; 4474 4475 IA_CSS_LOG("event dequeued from psys event queue"); 4476 4477 /* Tell the SP that we dequeued an event from the event queue. */ 4478 ia_css_bufq_enqueue_psys_event( 4479 IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0); 4480 4481 /* Events are decoded into 4 bytes of payload, the first byte 4482 * contains the sp event type. This is converted to a host enum. 4483 * TODO: can this enum conversion be eliminated */ 4484 event->type = convert_event_sp_to_host_domain[payload[0]]; 4485 /* Some sane default values since not all events use all fields. */ 4486 event->pipe = NULL; 4487 event->port = MIPI_PORT0_ID; 4488 event->exp_id = 0; 4489 event->fw_warning = IA_CSS_FW_WARNING_NONE; 4490 event->fw_handle = 0; 4491 event->timer_data = 0; 4492 event->timer_code = 0; 4493 event->timer_subcode = 0; 4494 4495 if (event->type == IA_CSS_EVENT_TYPE_TIMER) { 4496 /* timer event ??? get the 2nd event and decode the data into the event struct */ 4497 u32 tmp_data; 4498 /* 1st event: LSB 16-bit timer data and code */ 4499 event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8)); 4500 event->timer_code = payload[2]; 4501 payload[0] = payload[1] = payload[2] = payload[3] = 0; 4502 ret_err = ia_css_bufq_dequeue_psys_event(payload); 4503 if (ret_err) { 4504 /* no 2nd event ??? an error */ 4505 /* Putting IA_CSS_ERROR is resulting in failures in 4506 * Merrifield smoke testing */ 4507 IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n"); 4508 return ret_err; 4509 } 4510 ia_css_bufq_enqueue_psys_event( 4511 IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0); 4512 event->type = convert_event_sp_to_host_domain[payload[0]]; 4513 /* It's a timer */ 4514 if (event->type == IA_CSS_EVENT_TYPE_TIMER) { 4515 /* 2nd event data: MSB 16-bit timer and subcode */ 4516 tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8)); 4517 event->timer_data |= (tmp_data << 16); 4518 event->timer_subcode = payload[2]; 4519 } else { 4520 /* It's a non timer event. So clear first half of the timer event data. 4521 * If the second part of the TIMER event is not received, we discard 4522 * the first half of the timer data and process the non timer event without 4523 * affecting the flow. So the non timer event falls through 4524 * the code. */ 4525 event->timer_data = 0; 4526 event->timer_code = 0; 4527 event->timer_subcode = 0; 4528 IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded"); 4529 } 4530 } 4531 if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) { 4532 event->port = (enum mipi_port_id)payload[1]; 4533 event->exp_id = payload[3]; 4534 } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) { 4535 event->fw_warning = (enum ia_css_fw_warning)payload[1]; 4536 /* exp_id is only available in these warning types */ 4537 if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED || 4538 event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED) 4539 event->exp_id = payload[3]; 4540 } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) { 4541 event->fw_assert_module_id = payload[1]; /* module */ 4542 event->fw_assert_line_no = (payload[2] << 8) + payload[3]; 4543 /* payload[2] is line_no>>8, payload[3] is line_no&0xff */ 4544 } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) { 4545 /* pipe related events. 4546 * payload[1] contains the pipe_num, 4547 * payload[2] contains the pipe_id. These are different. */ 4548 event->pipe = find_pipe_by_num(payload[1]); 4549 pipe_id = (enum ia_css_pipe_id)payload[2]; 4550 /* Check to see if pipe still exists */ 4551 if (!event->pipe) 4552 return -EBUSY; 4553 4554 if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) { 4555 /* find the capture pipe that goes with this */ 4556 int i, n; 4557 4558 n = event->pipe->stream->num_pipes; 4559 for (i = 0; i < n; i++) { 4560 struct ia_css_pipe *p = 4561 event->pipe->stream->pipes[i]; 4562 if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) { 4563 event->pipe = p; 4564 break; 4565 } 4566 } 4567 event->exp_id = payload[3]; 4568 } 4569 if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) { 4570 /* payload[3] contains the acc fw handle. */ 4571 u32 stage_num = (uint32_t)payload[3]; 4572 4573 ret_err = ia_css_pipeline_get_fw_from_stage( 4574 &event->pipe->pipeline, 4575 stage_num, 4576 &event->fw_handle); 4577 if (ret_err) { 4578 IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u", 4579 stage_num); 4580 return ret_err; 4581 } 4582 } 4583 } 4584 4585 if (event->pipe) 4586 IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id); 4587 else 4588 IA_CSS_LEAVE("event_id=%d", event->type); 4589 4590 return 0; 4591 } 4592 4593 int 4594 ia_css_dequeue_isys_event(struct ia_css_event *event) 4595 { 4596 u8 payload[4] = {0, 0, 0, 0}; 4597 int err = 0; 4598 4599 /* We skip the IA_CSS_ENTER logging call 4600 * to avoid flooding the logs when the host application 4601 * uses polling. */ 4602 if (!event) 4603 return -EINVAL; 4604 4605 /* SP is not running. The queues are not valid */ 4606 if (!sh_css_sp_is_running()) 4607 return -EBUSY; 4608 4609 err = ia_css_bufq_dequeue_isys_event(payload); 4610 if (err) 4611 return err; 4612 4613 IA_CSS_LOG("event dequeued from isys event queue"); 4614 4615 /* Update SP state to indicate that element was dequeued. */ 4616 ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED); 4617 4618 /* Fill return struct with appropriate info */ 4619 event->type = IA_CSS_EVENT_TYPE_PORT_EOF; 4620 /* EOF events are associated with a CSI port, not with a pipe */ 4621 event->pipe = NULL; 4622 event->port = payload[1]; 4623 event->exp_id = payload[3]; 4624 4625 IA_CSS_LEAVE_ERR(err); 4626 return err; 4627 } 4628 4629 static void 4630 acc_start(struct ia_css_pipe *pipe) 4631 { 4632 assert(pipe); 4633 assert(pipe->stream); 4634 4635 start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD, 4636 pipe->stream->config.mode); 4637 } 4638 4639 static int 4640 sh_css_pipe_start(struct ia_css_stream *stream) 4641 { 4642 int err = 0; 4643 4644 struct ia_css_pipe *pipe; 4645 enum ia_css_pipe_id pipe_id; 4646 unsigned int thread_id; 4647 4648 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 4649 4650 if (!stream) { 4651 IA_CSS_LEAVE_ERR(-EINVAL); 4652 return -EINVAL; 4653 } 4654 pipe = stream->last_pipe; 4655 if (!pipe) { 4656 IA_CSS_LEAVE_ERR(-EINVAL); 4657 return -EINVAL; 4658 } 4659 4660 pipe_id = pipe->mode; 4661 4662 if (stream->started) { 4663 IA_CSS_WARNING("Cannot start stream that is already started"); 4664 IA_CSS_LEAVE_ERR(err); 4665 return err; 4666 } 4667 4668 pipe->stop_requested = false; 4669 4670 switch (pipe_id) { 4671 case IA_CSS_PIPE_ID_PREVIEW: 4672 err = preview_start(pipe); 4673 break; 4674 case IA_CSS_PIPE_ID_VIDEO: 4675 err = video_start(pipe); 4676 break; 4677 case IA_CSS_PIPE_ID_CAPTURE: 4678 err = capture_start(pipe); 4679 break; 4680 case IA_CSS_PIPE_ID_YUVPP: 4681 err = yuvpp_start(pipe); 4682 break; 4683 case IA_CSS_PIPE_ID_ACC: 4684 acc_start(pipe); 4685 break; 4686 default: 4687 err = -EINVAL; 4688 } 4689 /* DH regular multi pipe - not continuous mode: start the next pipes too */ 4690 if (!stream->config.continuous) { 4691 int i; 4692 4693 for (i = 1; i < stream->num_pipes && 0 == err ; i++) { 4694 switch (stream->pipes[i]->mode) { 4695 case IA_CSS_PIPE_ID_PREVIEW: 4696 stream->pipes[i]->stop_requested = false; 4697 err = preview_start(stream->pipes[i]); 4698 break; 4699 case IA_CSS_PIPE_ID_VIDEO: 4700 stream->pipes[i]->stop_requested = false; 4701 err = video_start(stream->pipes[i]); 4702 break; 4703 case IA_CSS_PIPE_ID_CAPTURE: 4704 stream->pipes[i]->stop_requested = false; 4705 err = capture_start(stream->pipes[i]); 4706 break; 4707 case IA_CSS_PIPE_ID_YUVPP: 4708 stream->pipes[i]->stop_requested = false; 4709 err = yuvpp_start(stream->pipes[i]); 4710 break; 4711 case IA_CSS_PIPE_ID_ACC: 4712 stream->pipes[i]->stop_requested = false; 4713 acc_start(stream->pipes[i]); 4714 break; 4715 default: 4716 err = -EINVAL; 4717 } 4718 } 4719 } 4720 if (err) { 4721 IA_CSS_LEAVE_ERR_PRIVATE(err); 4722 return err; 4723 } 4724 4725 /* Force ISP parameter calculation after a mode change 4726 * Acceleration API examples pass NULL for stream but they 4727 * don't use ISP parameters anyway. So this should be okay. 4728 * The SP binary (jpeg) copy does not use any parameters. 4729 */ 4730 if (!copy_on_sp(pipe)) { 4731 sh_css_invalidate_params(stream); 4732 err = sh_css_param_update_isp_params(pipe, 4733 stream->isp_params_configs, true, NULL); 4734 if (err) { 4735 IA_CSS_LEAVE_ERR_PRIVATE(err); 4736 return err; 4737 } 4738 } 4739 4740 ia_css_debug_pipe_graph_dump_epilogue(); 4741 4742 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 4743 4744 if (!sh_css_sp_is_running()) { 4745 IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY); 4746 /* SP is not running. The queues are not valid */ 4747 return -EBUSY; 4748 } 4749 ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM, 4750 (uint8_t)thread_id, 0, 0); 4751 4752 /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */ 4753 if (!stream->config.continuous) { 4754 int i; 4755 4756 for (i = 1; i < stream->num_pipes; i++) { 4757 ia_css_pipeline_get_sp_thread_id( 4758 ia_css_pipe_get_pipe_num(stream->pipes[i]), 4759 &thread_id); 4760 ia_css_bufq_enqueue_psys_event( 4761 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4762 (uint8_t)thread_id, 0, 0); 4763 } 4764 } 4765 4766 /* in case of continuous capture mode, we also start capture thread and copy thread*/ 4767 if (pipe->stream->config.continuous) { 4768 struct ia_css_pipe *copy_pipe = NULL; 4769 4770 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) 4771 copy_pipe = pipe->pipe_settings.preview.copy_pipe; 4772 else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) 4773 copy_pipe = pipe->pipe_settings.video.copy_pipe; 4774 4775 if (!copy_pipe) { 4776 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4777 return -EINVAL; 4778 } 4779 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe), 4780 &thread_id); 4781 /* by the time we reach here q is initialized and handle is available.*/ 4782 ia_css_bufq_enqueue_psys_event( 4783 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4784 (uint8_t)thread_id, 0, 0); 4785 } 4786 if (pipe->stream->cont_capt) { 4787 struct ia_css_pipe *capture_pipe = NULL; 4788 4789 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) 4790 capture_pipe = pipe->pipe_settings.preview.capture_pipe; 4791 else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) 4792 capture_pipe = pipe->pipe_settings.video.capture_pipe; 4793 4794 if (!capture_pipe) { 4795 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 4796 return -EINVAL; 4797 } 4798 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 4799 &thread_id); 4800 /* by the time we reach here q is initialized and handle is available.*/ 4801 ia_css_bufq_enqueue_psys_event( 4802 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4803 (uint8_t)thread_id, 0, 0); 4804 } 4805 4806 /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */ 4807 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) { 4808 struct ia_css_pipe *acc_pipe = NULL; 4809 4810 acc_pipe = pipe->pipe_settings.preview.acc_pipe; 4811 4812 if (acc_pipe) { 4813 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe), 4814 &thread_id); 4815 /* by the time we reach here q is initialized and handle is available.*/ 4816 ia_css_bufq_enqueue_psys_event( 4817 IA_CSS_PSYS_SW_EVENT_START_STREAM, 4818 (uint8_t)thread_id, 0, 0); 4819 } 4820 } 4821 4822 stream->started = true; 4823 4824 IA_CSS_LEAVE_ERR_PRIVATE(err); 4825 return err; 4826 } 4827 4828 /* ISP2400 */ 4829 void 4830 sh_css_enable_cont_capt(bool enable, bool stop_copy_preview) 4831 { 4832 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4833 "sh_css_enable_cont_capt() enter: enable=%d\n", enable); 4834 //my_css.cont_capt = enable; 4835 my_css.stop_copy_preview = stop_copy_preview; 4836 } 4837 4838 bool 4839 sh_css_continuous_is_enabled(uint8_t pipe_num) 4840 { 4841 struct ia_css_pipe *pipe; 4842 bool continuous; 4843 4844 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4845 "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num); 4846 4847 pipe = find_pipe_by_num(pipe_num); 4848 continuous = pipe && pipe->stream->config.continuous; 4849 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 4850 "sh_css_continuous_is_enabled() leave: enable=%d\n", 4851 continuous); 4852 return continuous; 4853 } 4854 4855 /* ISP2400 */ 4856 int 4857 ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream, 4858 int *buffer_depth) 4859 { 4860 if (!buffer_depth) 4861 return -EINVAL; 4862 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n"); 4863 (void)stream; 4864 *buffer_depth = NUM_CONTINUOUS_FRAMES; 4865 return 0; 4866 } 4867 4868 int 4869 ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) 4870 { 4871 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth); 4872 (void)stream; 4873 if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1) 4874 return -EINVAL; 4875 /* ok, value allowed */ 4876 stream->config.target_num_cont_raw_buf = buffer_depth; 4877 /* TODO: check what to regarding initialization */ 4878 return 0; 4879 } 4880 4881 /* ISP2401 */ 4882 int 4883 ia_css_stream_get_buffer_depth(struct ia_css_stream *stream, 4884 int *buffer_depth) 4885 { 4886 if (!buffer_depth) 4887 return -EINVAL; 4888 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n"); 4889 (void)stream; 4890 *buffer_depth = stream->config.target_num_cont_raw_buf; 4891 return 0; 4892 } 4893 4894 /* 4895 * @brief Stop all "ia_css_pipe" instances in the target 4896 * "ia_css_stream" instance. 4897 * 4898 * Refer to "Local prototypes" for more info. 4899 */ 4900 /* ISP2401 */ 4901 static int 4902 sh_css_pipes_stop(struct ia_css_stream *stream) 4903 { 4904 int err = 0; 4905 struct ia_css_pipe *main_pipe; 4906 enum ia_css_pipe_id main_pipe_id; 4907 int i; 4908 4909 if (!stream) { 4910 IA_CSS_LOG("stream does NOT exist!"); 4911 err = -EINVAL; 4912 goto ERR; 4913 } 4914 4915 main_pipe = stream->last_pipe; 4916 if (!main_pipe) { 4917 IA_CSS_LOG("main_pipe does NOT exist!"); 4918 err = -EINVAL; 4919 goto ERR; 4920 } 4921 4922 main_pipe_id = main_pipe->mode; 4923 IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id); 4924 4925 /* 4926 * Stop all "ia_css_pipe" instances in this target 4927 * "ia_css_stream" instance. 4928 */ 4929 for (i = 0; i < stream->num_pipes; i++) { 4930 /* send the "stop" request to the "ia_css_pipe" instance */ 4931 IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d", 4932 stream->pipes[i]->pipeline.pipe_id); 4933 err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline); 4934 4935 /* 4936 * Exit this loop if "ia_css_pipeline_request_stop()" 4937 * returns the error code. 4938 * 4939 * The error code would be generated in the following 4940 * two cases: 4941 * (1) The Scalar Processor has already been stopped. 4942 * (2) The "Host->SP" event queue is full. 4943 * 4944 * As the convention of using CSS API 2.0/2.1, such CSS 4945 * error code would be propogated from the CSS-internal 4946 * API returned value to the CSS API returned value. Then 4947 * the CSS driver should capture these error code and 4948 * handle it in the driver exception handling mechanism. 4949 */ 4950 if (err) 4951 goto ERR; 4952 } 4953 4954 /* 4955 * In the CSS firmware use scenario "Continuous Preview" 4956 * as well as "Continuous Video", the "ia_css_pipe" instance 4957 * "Copy Pipe" is activated. This "Copy Pipe" is private to 4958 * the CSS firmware so that it is not listed in the target 4959 * "ia_css_stream" instance. 4960 * 4961 * We need to stop this "Copy Pipe", as well. 4962 */ 4963 if (main_pipe->stream->config.continuous) { 4964 struct ia_css_pipe *copy_pipe = NULL; 4965 4966 /* get the reference to "Copy Pipe" */ 4967 if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW) 4968 copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; 4969 else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO) 4970 copy_pipe = main_pipe->pipe_settings.video.copy_pipe; 4971 4972 /* return the error code if "Copy Pipe" does NOT exist */ 4973 if (!copy_pipe) { 4974 IA_CSS_LOG("Copy Pipe does NOT exist!"); 4975 err = -EINVAL; 4976 goto ERR; 4977 } 4978 4979 /* send the "stop" request to "Copy Pipe" */ 4980 IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d", 4981 copy_pipe->pipeline.pipe_id); 4982 err = ia_css_pipeline_request_stop(©_pipe->pipeline); 4983 } 4984 4985 ERR: 4986 IA_CSS_LEAVE_ERR_PRIVATE(err); 4987 return err; 4988 } 4989 4990 /* 4991 * @brief Check if all "ia_css_pipe" instances in the target 4992 * "ia_css_stream" instance have stopped. 4993 * 4994 * Refer to "Local prototypes" for more info. 4995 */ 4996 /* ISP2401 */ 4997 static bool 4998 sh_css_pipes_have_stopped(struct ia_css_stream *stream) 4999 { 5000 bool rval = true; 5001 5002 struct ia_css_pipe *main_pipe; 5003 enum ia_css_pipe_id main_pipe_id; 5004 5005 int i; 5006 5007 if (!stream) { 5008 IA_CSS_LOG("stream does NOT exist!"); 5009 rval = false; 5010 goto RET; 5011 } 5012 5013 main_pipe = stream->last_pipe; 5014 5015 if (!main_pipe) { 5016 IA_CSS_LOG("main_pipe does NOT exist!"); 5017 rval = false; 5018 goto RET; 5019 } 5020 5021 main_pipe_id = main_pipe->mode; 5022 IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id); 5023 5024 /* 5025 * Check if every "ia_css_pipe" instance in this target 5026 * "ia_css_stream" instance has stopped. 5027 */ 5028 for (i = 0; i < stream->num_pipes; i++) { 5029 rval = rval && ia_css_pipeline_has_stopped(&stream->pipes[i]->pipeline); 5030 IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d", 5031 stream->pipes[i]->pipeline.pipe_id, 5032 rval); 5033 } 5034 5035 /* 5036 * In the CSS firmware use scenario "Continuous Preview" 5037 * as well as "Continuous Video", the "ia_css_pipe" instance 5038 * "Copy Pipe" is activated. This "Copy Pipe" is private to 5039 * the CSS firmware so that it is not listed in the target 5040 * "ia_css_stream" instance. 5041 * 5042 * We need to check if this "Copy Pipe" has stopped, as well. 5043 */ 5044 if (main_pipe->stream->config.continuous) { 5045 struct ia_css_pipe *copy_pipe = NULL; 5046 5047 /* get the reference to "Copy Pipe" */ 5048 if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW) 5049 copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; 5050 else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO) 5051 copy_pipe = main_pipe->pipe_settings.video.copy_pipe; 5052 5053 /* return if "Copy Pipe" does NOT exist */ 5054 if (!copy_pipe) { 5055 IA_CSS_LOG("Copy Pipe does NOT exist!"); 5056 5057 rval = false; 5058 goto RET; 5059 } 5060 5061 /* check if "Copy Pipe" has stopped or not */ 5062 rval = rval && ia_css_pipeline_has_stopped(©_pipe->pipeline); 5063 IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d", 5064 copy_pipe->pipeline.pipe_id, 5065 rval); 5066 } 5067 5068 RET: 5069 IA_CSS_LEAVE_PRIVATE("rval=%d", rval); 5070 return rval; 5071 } 5072 5073 #if !defined(ISP2401) 5074 unsigned int 5075 sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx) 5076 { 5077 OP___assert(port < N_CSI_PORTS); 5078 OP___assert(idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT); 5079 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5080 "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n", 5081 port, idx, my_css.mipi_sizes_for_check[port][idx]); 5082 return my_css.mipi_sizes_for_check[port][idx]; 5083 } 5084 #endif 5085 5086 static int sh_css_pipe_configure_output( 5087 struct ia_css_pipe *pipe, 5088 unsigned int width, 5089 unsigned int height, 5090 unsigned int padded_width, 5091 enum ia_css_frame_format format, 5092 unsigned int idx) 5093 { 5094 int err = 0; 5095 5096 IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d", 5097 pipe, width, height, padded_width, format, idx); 5098 if (!pipe) { 5099 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5100 return -EINVAL; 5101 } 5102 5103 err = ia_css_util_check_res(width, height); 5104 if (err) { 5105 IA_CSS_LEAVE_ERR_PRIVATE(err); 5106 return err; 5107 } 5108 if (pipe->output_info[idx].res.width != width || 5109 pipe->output_info[idx].res.height != height || 5110 pipe->output_info[idx].format != format) { 5111 ia_css_frame_info_init( 5112 &pipe->output_info[idx], 5113 width, 5114 height, 5115 format, 5116 padded_width); 5117 } 5118 IA_CSS_LEAVE_ERR_PRIVATE(0); 5119 return 0; 5120 } 5121 5122 static int 5123 sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe, 5124 struct ia_css_shading_info *shading_info, 5125 struct ia_css_pipe_config *pipe_config) 5126 { 5127 int err = 0; 5128 struct ia_css_binary *binary = NULL; 5129 5130 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5131 "sh_css_pipe_get_shading_info() enter:\n"); 5132 5133 binary = ia_css_pipe_get_shading_correction_binary(pipe); 5134 5135 if (binary) { 5136 err = ia_css_binary_get_shading_info(binary, 5137 IA_CSS_SHADING_CORRECTION_TYPE_1, 5138 pipe->required_bds_factor, 5139 (const struct ia_css_stream_config *)&pipe->stream->config, 5140 shading_info, pipe_config); 5141 5142 /* Other function calls can be added here when other shading correction types will be added 5143 * in the future. 5144 */ 5145 } else { 5146 /* When the pipe does not have a binary which has the shading 5147 * correction, this function does not need to fill the shading 5148 * information. It is not a error case, and then 5149 * this function should return 0. 5150 */ 5151 memset(shading_info, 0, sizeof(*shading_info)); 5152 } 5153 return err; 5154 } 5155 5156 static int 5157 sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, 5158 struct ia_css_grid_info *info) 5159 { 5160 int err = 0; 5161 struct ia_css_binary *binary = NULL; 5162 5163 assert(pipe); 5164 assert(info); 5165 5166 IA_CSS_ENTER_PRIVATE(""); 5167 5168 binary = ia_css_pipe_get_s3a_binary(pipe); 5169 5170 if (binary) { 5171 err = ia_css_binary_3a_grid_info(binary, info, pipe); 5172 if (err) 5173 goto ERR; 5174 } else { 5175 memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); 5176 } 5177 5178 binary = ia_css_pipe_get_sdis_binary(pipe); 5179 5180 if (binary) { 5181 ia_css_binary_dvs_grid_info(binary, info, pipe); 5182 ia_css_binary_dvs_stat_grid_info(binary, info, pipe); 5183 } else { 5184 memset(&info->dvs_grid.dvs_grid_info, 0, 5185 sizeof(info->dvs_grid.dvs_grid_info)); 5186 memset(&info->dvs_grid.dvs_stat_grid_info, 0, 5187 sizeof(info->dvs_grid.dvs_stat_grid_info)); 5188 } 5189 5190 if (binary) { 5191 /* copy pipe does not have ISP binary*/ 5192 info->isp_in_width = binary->internal_frame_info.res.width; 5193 info->isp_in_height = binary->internal_frame_info.res.height; 5194 } 5195 5196 info->vamem_type = IA_CSS_VAMEM_TYPE_2; 5197 5198 ERR : 5199 IA_CSS_LEAVE_ERR_PRIVATE(err); 5200 return err; 5201 } 5202 5203 /* ISP2401 */ 5204 /* 5205 * @brief Check if a format is supported by the pipe. 5206 * 5207 */ 5208 static int 5209 ia_css_pipe_check_format(struct ia_css_pipe *pipe, 5210 enum ia_css_frame_format format) 5211 { 5212 const enum ia_css_frame_format *supported_formats; 5213 int number_of_formats; 5214 int found = 0; 5215 int i; 5216 5217 IA_CSS_ENTER_PRIVATE(""); 5218 5219 if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) { 5220 IA_CSS_ERROR("Pipe or binary info is not set"); 5221 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5222 return -EINVAL; 5223 } 5224 5225 supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats; 5226 number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format); 5227 5228 for (i = 0; i < number_of_formats && !found; i++) { 5229 if (supported_formats[i] == format) { 5230 found = 1; 5231 break; 5232 } 5233 } 5234 if (!found) { 5235 IA_CSS_ERROR("Requested format is not supported by binary"); 5236 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5237 return -EINVAL; 5238 } 5239 IA_CSS_LEAVE_ERR_PRIVATE(0); 5240 return 0; 5241 } 5242 5243 static int load_video_binaries(struct ia_css_pipe *pipe) 5244 { 5245 struct ia_css_frame_info video_in_info, tnr_info, 5246 *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info; 5247 bool online; 5248 int err = 0; 5249 bool continuous = pipe->stream->config.continuous; 5250 unsigned int i; 5251 unsigned int num_output_pins; 5252 struct ia_css_frame_info video_bin_out_info; 5253 bool need_scaler = false; 5254 bool vf_res_different_than_output = false; 5255 bool need_vf_pp = false; 5256 int vf_ds_log2; 5257 struct ia_css_video_settings *mycs = &pipe->pipe_settings.video; 5258 5259 IA_CSS_ENTER_PRIVATE(""); 5260 assert(pipe); 5261 assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO); 5262 /* we only test the video_binary because offline video doesn't need a 5263 * vf_pp binary and online does not (always use) the copy_binary. 5264 * All are always reset at the same time anyway. 5265 */ 5266 if (mycs->video_binary.info) 5267 return 0; 5268 5269 online = pipe->stream->config.online; 5270 pipe_out_info = &pipe->output_info[0]; 5271 pipe_vf_out_info = &pipe->vf_output_info[0]; 5272 5273 assert(pipe_out_info); 5274 5275 /* 5276 * There is no explicit input format requirement for raw or yuv 5277 * What matters is that there is a binary that supports the stream format. 5278 * This is checked in the binary_find(), so no need to check it here 5279 */ 5280 err = ia_css_util_check_input(&pipe->stream->config, false, false); 5281 if (err) 5282 return err; 5283 /* cannot have online video and input_mode memory */ 5284 if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY) 5285 return -EINVAL; 5286 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 5287 err = ia_css_util_check_vf_out_info(pipe_out_info, 5288 pipe_vf_out_info); 5289 if (err) 5290 return err; 5291 } else { 5292 err = ia_css_frame_check_info(pipe_out_info); 5293 if (err) 5294 return err; 5295 } 5296 5297 if (pipe->out_yuv_ds_input_info.res.width) 5298 video_bin_out_info = pipe->out_yuv_ds_input_info; 5299 else 5300 video_bin_out_info = *pipe_out_info; 5301 5302 /* Video */ 5303 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 5304 video_vf_info = pipe_vf_out_info; 5305 vf_res_different_than_output = (video_vf_info->res.width != 5306 video_bin_out_info.res.width) || 5307 (video_vf_info->res.height != video_bin_out_info.res.height); 5308 } else { 5309 video_vf_info = NULL; 5310 } 5311 5312 need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res); 5313 5314 /* we build up the pipeline starting at the end */ 5315 /* YUV post-processing if needed */ 5316 if (need_scaler) { 5317 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 5318 5319 /* NV12 is the common format that is supported by both */ 5320 /* yuv_scaler and the video_xx_isp2_min binaries. */ 5321 video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12; 5322 5323 err = ia_css_pipe_create_cas_scaler_desc_single_output( 5324 &video_bin_out_info, 5325 pipe_out_info, 5326 NULL, 5327 &cas_scaler_descr); 5328 if (err) 5329 return err; 5330 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 5331 mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * 5332 sizeof(struct ia_css_binary), GFP_KERNEL); 5333 if (!mycs->yuv_scaler_binary) { 5334 err = -ENOMEM; 5335 return err; 5336 } 5337 mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage 5338 * sizeof(bool), GFP_KERNEL); 5339 if (!mycs->is_output_stage) { 5340 err = -ENOMEM; 5341 return err; 5342 } 5343 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 5344 struct ia_css_binary_descr yuv_scaler_descr; 5345 5346 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 5347 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 5348 &yuv_scaler_descr, &cas_scaler_descr.in_info[i], 5349 &cas_scaler_descr.out_info[i], 5350 &cas_scaler_descr.internal_out_info[i], 5351 &cas_scaler_descr.vf_info[i]); 5352 err = ia_css_binary_find(&yuv_scaler_descr, 5353 &mycs->yuv_scaler_binary[i]); 5354 if (err) { 5355 kfree(mycs->is_output_stage); 5356 mycs->is_output_stage = NULL; 5357 return err; 5358 } 5359 } 5360 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 5361 } 5362 5363 { 5364 struct ia_css_binary_descr video_descr; 5365 enum ia_css_frame_format vf_info_format; 5366 5367 err = ia_css_pipe_get_video_binarydesc(pipe, 5368 &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info, 5369 video_vf_info, 5370 pipe->stream->config.left_padding); 5371 if (err) 5372 return err; 5373 5374 /* In the case where video_vf_info is not NULL, this allows 5375 * us to find a potential video library with desired vf format. 5376 * If success, no vf_pp binary is needed. 5377 * If failed, we will look up video binary with YUV_LINE vf format 5378 */ 5379 err = ia_css_binary_find(&video_descr, 5380 &mycs->video_binary); 5381 5382 if (err) { 5383 /* This will do another video binary lookup later for YUV_LINE format*/ 5384 if (video_vf_info) 5385 need_vf_pp = true; 5386 else 5387 return err; 5388 } else if (video_vf_info) { 5389 /* The first video binary lookup is successful, but we may 5390 * still need vf_pp binary based on additiona check */ 5391 num_output_pins = mycs->video_binary.info->num_output_pins; 5392 vf_ds_log2 = mycs->video_binary.vf_downscale_log2; 5393 5394 /* If the binary has dual output pins, we need vf_pp if the resolution 5395 * is different. */ 5396 need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output); 5397 5398 /* If the binary has single output pin, we need vf_pp if additional 5399 * scaling is needed for vf */ 5400 need_vf_pp |= ((num_output_pins == 1) && 5401 ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) || 5402 (video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height))); 5403 } 5404 5405 if (need_vf_pp) { 5406 /* save the current vf_info format for restoration later */ 5407 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 5408 "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n"); 5409 5410 vf_info_format = video_vf_info->format; 5411 5412 if (!pipe->config.enable_vfpp_bci) 5413 ia_css_frame_info_set_format(video_vf_info, 5414 IA_CSS_FRAME_FORMAT_YUV_LINE); 5415 5416 ia_css_binary_destroy_isp_parameters(&mycs->video_binary); 5417 5418 err = ia_css_binary_find(&video_descr, 5419 &mycs->video_binary); 5420 5421 /* restore original vf_info format */ 5422 ia_css_frame_info_set_format(video_vf_info, 5423 vf_info_format); 5424 if (err) 5425 return err; 5426 } 5427 } 5428 5429 /* If a video binary does not use a ref_frame, we set the frame delay 5430 * to 0. This is the case for the 1-stage low-power video binary. */ 5431 if (!mycs->video_binary.info->sp.enable.ref_frame) 5432 pipe->dvs_frame_delay = 0; 5433 5434 /* The delay latency determines the number of invalid frames after 5435 * a stream is started. */ 5436 pipe->num_invalid_frames = pipe->dvs_frame_delay; 5437 pipe->info.num_invalid_frames = pipe->num_invalid_frames; 5438 5439 /* Viewfinder frames also decrement num_invalid_frames. If the pipe 5440 * outputs a viewfinder output, then we need double the number of 5441 * invalid frames */ 5442 if (video_vf_info) 5443 pipe->num_invalid_frames *= 2; 5444 5445 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 5446 "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n", 5447 pipe->num_invalid_frames, pipe->dvs_frame_delay); 5448 5449 /* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */ 5450 #if !defined(ISP2401) 5451 /* Copy */ 5452 if (!online && !continuous) { 5453 /* TODO: what exactly needs doing, prepend the copy binary to 5454 * video base this only on !online? 5455 */ 5456 err = load_copy_binary(pipe, 5457 &mycs->copy_binary, 5458 &mycs->video_binary); 5459 if (err) 5460 return err; 5461 } 5462 #else 5463 (void)continuous; 5464 #endif 5465 5466 #if !defined(HAS_OUTPUT_SYSTEM) 5467 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) { 5468 struct ia_css_binary_descr vf_pp_descr; 5469 5470 if (mycs->video_binary.vf_frame_info.format 5471 == IA_CSS_FRAME_FORMAT_YUV_LINE) { 5472 ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, 5473 &mycs->video_binary.vf_frame_info, 5474 pipe_vf_out_info); 5475 } else { 5476 /* output from main binary is not yuv line. currently this is 5477 * possible only when bci is enabled on vfpp output */ 5478 assert(pipe->config.enable_vfpp_bci); 5479 ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr, 5480 &mycs->video_binary.vf_frame_info, 5481 pipe_vf_out_info, NULL, NULL); 5482 } 5483 5484 err = ia_css_binary_find(&vf_pp_descr, 5485 &mycs->vf_pp_binary); 5486 if (err) 5487 return err; 5488 } 5489 #endif 5490 5491 err = allocate_delay_frames(pipe); 5492 5493 if (err) 5494 return err; 5495 5496 if (mycs->video_binary.info->sp.enable.block_output) { 5497 unsigned int tnr_width; 5498 unsigned int tnr_height; 5499 5500 tnr_info = mycs->video_binary.out_frame_info[0]; 5501 5502 if (IS_ISP2401) { 5503 /* Select resolution for TNR. If 5504 * output_system_in_resolution(GDC_out_resolution) is 5505 * being used, then select that as it will also be in resolution for 5506 * TNR. At present, it only make sense for Skycam */ 5507 if (pipe->config.output_system_in_res.width && 5508 pipe->config.output_system_in_res.height) { 5509 tnr_width = pipe->config.output_system_in_res.width; 5510 tnr_height = pipe->config.output_system_in_res.height; 5511 } else { 5512 tnr_width = tnr_info.res.width; 5513 tnr_height = tnr_info.res.height; 5514 } 5515 5516 /* Make tnr reference buffers output block width(in pix) align */ 5517 tnr_info.res.width = CEIL_MUL(tnr_width, 5518 (mycs->video_binary.info->sp.block.block_width * ISP_NWAY)); 5519 tnr_info.padded_width = tnr_info.res.width; 5520 } else { 5521 tnr_height = tnr_info.res.height; 5522 } 5523 5524 /* Make tnr reference buffers output block height align */ 5525 tnr_info.res.height = CEIL_MUL(tnr_height, 5526 mycs->video_binary.info->sp.block.output_block_height); 5527 } else { 5528 tnr_info = mycs->video_binary.internal_frame_info; 5529 } 5530 tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE; 5531 tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH; 5532 5533 for (i = 0; i < NUM_TNR_FRAMES; i++) { 5534 if (mycs->tnr_frames[i]) { 5535 ia_css_frame_free(mycs->tnr_frames[i]); 5536 mycs->tnr_frames[i] = NULL; 5537 } 5538 err = ia_css_frame_allocate_from_info( 5539 &mycs->tnr_frames[i], 5540 &tnr_info); 5541 if (err) 5542 return err; 5543 } 5544 IA_CSS_LEAVE_PRIVATE(""); 5545 return 0; 5546 } 5547 5548 static int 5549 unload_video_binaries(struct ia_css_pipe *pipe) 5550 { 5551 unsigned int i; 5552 5553 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 5554 5555 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 5556 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5557 return -EINVAL; 5558 } 5559 ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary); 5560 ia_css_binary_unload(&pipe->pipe_settings.video.video_binary); 5561 ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary); 5562 5563 for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++) 5564 ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]); 5565 5566 kfree(pipe->pipe_settings.video.is_output_stage); 5567 pipe->pipe_settings.video.is_output_stage = NULL; 5568 kfree(pipe->pipe_settings.video.yuv_scaler_binary); 5569 pipe->pipe_settings.video.yuv_scaler_binary = NULL; 5570 5571 IA_CSS_LEAVE_ERR_PRIVATE(0); 5572 return 0; 5573 } 5574 5575 static int video_start(struct ia_css_pipe *pipe) 5576 { 5577 int err = 0; 5578 struct ia_css_pipe *copy_pipe, *capture_pipe; 5579 enum sh_css_pipe_config_override copy_ovrd; 5580 enum ia_css_input_mode video_pipe_input_mode; 5581 5582 const struct ia_css_coordinate *coord = NULL; 5583 const struct ia_css_isp_parameters *params = NULL; 5584 5585 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 5586 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { 5587 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5588 return -EINVAL; 5589 } 5590 5591 video_pipe_input_mode = pipe->stream->config.mode; 5592 5593 copy_pipe = pipe->pipe_settings.video.copy_pipe; 5594 capture_pipe = pipe->pipe_settings.video.capture_pipe; 5595 5596 sh_css_metrics_start_frame(); 5597 5598 /* multi stream video needs mipi buffers */ 5599 5600 err = send_mipi_frames(pipe); 5601 if (err) 5602 return err; 5603 5604 send_raw_frames(pipe); 5605 { 5606 unsigned int thread_id; 5607 5608 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 5609 copy_ovrd = 1 << thread_id; 5610 5611 if (pipe->stream->cont_capt) { 5612 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), 5613 &thread_id); 5614 copy_ovrd |= 1 << thread_id; 5615 } 5616 } 5617 5618 if (IS_ISP2401) { 5619 coord = &pipe->config.internal_frame_origin_bqs_on_sctbl; 5620 params = pipe->stream->isp_params_configs; 5621 } 5622 5623 /* Construct and load the copy pipe */ 5624 if (pipe->stream->config.continuous) { 5625 sh_css_sp_init_pipeline(©_pipe->pipeline, 5626 IA_CSS_PIPE_ID_COPY, 5627 (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe), 5628 false, 5629 pipe->stream->config.pixels_per_clock == 2, false, 5630 false, pipe->required_bds_factor, 5631 copy_ovrd, 5632 pipe->stream->config.mode, 5633 &pipe->stream->config.metadata_config, 5634 &pipe->stream->info.metadata_info, 5635 pipe->stream->config.source.port.port, 5636 coord, 5637 params); 5638 5639 /* make the video pipe start with mem mode input, copy handles 5640 the actual mode */ 5641 video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY; 5642 } 5643 5644 /* Construct and load the capture pipe */ 5645 if (pipe->stream->cont_capt) { 5646 sh_css_sp_init_pipeline(&capture_pipe->pipeline, 5647 IA_CSS_PIPE_ID_CAPTURE, 5648 (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe), 5649 capture_pipe->config.default_capture_config.enable_xnr != 0, 5650 capture_pipe->stream->config.pixels_per_clock == 2, 5651 true, /* continuous */ 5652 false, /* offline */ 5653 capture_pipe->required_bds_factor, 5654 0, 5655 IA_CSS_INPUT_MODE_MEMORY, 5656 &pipe->stream->config.metadata_config, 5657 &pipe->stream->info.metadata_info, 5658 (enum mipi_port_id)0, 5659 coord, 5660 params); 5661 } 5662 5663 start_pipe(pipe, copy_ovrd, video_pipe_input_mode); 5664 5665 IA_CSS_LEAVE_ERR_PRIVATE(err); 5666 return err; 5667 } 5668 5669 static 5670 int sh_css_pipe_get_viewfinder_frame_info( 5671 struct ia_css_pipe *pipe, 5672 struct ia_css_frame_info *info, 5673 unsigned int idx) 5674 { 5675 assert(pipe); 5676 assert(info); 5677 5678 /* We could print the pointer as input arg, and the values as output */ 5679 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5680 "sh_css_pipe_get_viewfinder_frame_info() enter: void\n"); 5681 5682 if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE && 5683 (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW || 5684 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER)) 5685 return -EINVAL; 5686 /* offline video does not generate viewfinder output */ 5687 *info = pipe->vf_output_info[idx]; 5688 5689 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 5690 "sh_css_pipe_get_viewfinder_frame_info() leave: \ 5691 info.res.width=%d, info.res.height=%d, \ 5692 info.padded_width=%d, info.format=%d, \ 5693 info.raw_bit_depth=%d, info.raw_bayer_order=%d\n", 5694 info->res.width, info->res.height, 5695 info->padded_width, info->format, 5696 info->raw_bit_depth, info->raw_bayer_order); 5697 5698 return 0; 5699 } 5700 5701 static int 5702 sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width, 5703 unsigned int height, unsigned int min_width, 5704 enum ia_css_frame_format format, 5705 unsigned int idx) 5706 { 5707 int err = 0; 5708 5709 IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n", 5710 pipe, width, height, min_width, format, idx); 5711 5712 if (!pipe) { 5713 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 5714 return -EINVAL; 5715 } 5716 5717 err = ia_css_util_check_res(width, height); 5718 if (err) { 5719 IA_CSS_LEAVE_ERR_PRIVATE(err); 5720 return err; 5721 } 5722 if (pipe->vf_output_info[idx].res.width != width || 5723 pipe->vf_output_info[idx].res.height != height || 5724 pipe->vf_output_info[idx].format != format) 5725 ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height, 5726 format, min_width); 5727 5728 IA_CSS_LEAVE_ERR_PRIVATE(0); 5729 return 0; 5730 } 5731 5732 static int load_copy_binaries(struct ia_css_pipe *pipe) 5733 { 5734 int err = 0; 5735 5736 assert(pipe); 5737 IA_CSS_ENTER_PRIVATE(""); 5738 5739 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5740 pipe->mode == IA_CSS_PIPE_ID_COPY); 5741 if (pipe->pipe_settings.capture.copy_binary.info) 5742 return 0; 5743 5744 err = ia_css_frame_check_info(&pipe->output_info[0]); 5745 if (err) 5746 goto ERR; 5747 5748 err = verify_copy_out_frame_format(pipe); 5749 if (err) 5750 goto ERR; 5751 5752 err = load_copy_binary(pipe, 5753 &pipe->pipe_settings.capture.copy_binary, 5754 NULL); 5755 5756 ERR: 5757 IA_CSS_LEAVE_ERR_PRIVATE(err); 5758 return err; 5759 } 5760 5761 static bool need_capture_pp( 5762 const struct ia_css_pipe *pipe) 5763 { 5764 const struct ia_css_frame_info *out_info = &pipe->output_info[0]; 5765 5766 IA_CSS_ENTER_LEAVE_PRIVATE(""); 5767 assert(pipe); 5768 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 5769 5770 if (IS_ISP2401) { 5771 /* ldc and capture_pp are not supported in the same pipeline */ 5772 if (need_capt_ldc(pipe)) 5773 return false; 5774 } 5775 5776 /* determine whether we need to use the capture_pp binary. 5777 * This is needed for: 5778 * 1. XNR or 5779 * 2. Digital Zoom or 5780 * 3. YUV downscaling 5781 */ 5782 if (pipe->out_yuv_ds_input_info.res.width && 5783 ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) || 5784 (pipe->out_yuv_ds_input_info.res.height != out_info->res.height))) 5785 return true; 5786 5787 if (pipe->config.default_capture_config.enable_xnr != 0) 5788 return true; 5789 5790 if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) || 5791 (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) || 5792 pipe->config.enable_dz) 5793 return true; 5794 5795 return false; 5796 } 5797 5798 static bool need_capt_ldc( 5799 const struct ia_css_pipe *pipe) 5800 { 5801 IA_CSS_ENTER_LEAVE_PRIVATE(""); 5802 assert(pipe); 5803 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 5804 return (pipe->extra_config.enable_dvs_6axis) ? true : false; 5805 } 5806 5807 static int set_num_primary_stages(unsigned int *num, 5808 enum ia_css_pipe_version version) 5809 { 5810 int err = 0; 5811 5812 if (!num) 5813 return -EINVAL; 5814 5815 switch (version) { 5816 case IA_CSS_PIPE_VERSION_2_6_1: 5817 *num = NUM_PRIMARY_HQ_STAGES; 5818 break; 5819 case IA_CSS_PIPE_VERSION_2_2: 5820 case IA_CSS_PIPE_VERSION_1: 5821 *num = NUM_PRIMARY_STAGES; 5822 break; 5823 default: 5824 err = -EINVAL; 5825 break; 5826 } 5827 5828 return err; 5829 } 5830 5831 static int load_primary_binaries( 5832 struct ia_css_pipe *pipe) 5833 { 5834 bool online = false; 5835 bool need_pp = false; 5836 bool need_isp_copy_binary = false; 5837 bool need_ldc = false; 5838 #ifdef ISP2401 5839 bool sensor = false; 5840 #else 5841 bool memory, continuous; 5842 #endif 5843 struct ia_css_frame_info prim_in_info, 5844 prim_out_info, 5845 capt_pp_out_info, vf_info, 5846 *vf_pp_in_info, *pipe_out_info, 5847 *pipe_vf_out_info, *capt_pp_in_info, 5848 capt_ldc_out_info; 5849 int err = 0; 5850 struct ia_css_capture_settings *mycs; 5851 unsigned int i; 5852 bool need_extra_yuv_scaler = false; 5853 struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES]; 5854 5855 IA_CSS_ENTER_PRIVATE(""); 5856 assert(pipe); 5857 assert(pipe->stream); 5858 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 5859 pipe->mode == IA_CSS_PIPE_ID_COPY); 5860 5861 online = pipe->stream->config.online; 5862 #ifdef ISP2401 5863 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 5864 #else 5865 memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 5866 continuous = pipe->stream->config.continuous; 5867 #endif 5868 5869 mycs = &pipe->pipe_settings.capture; 5870 pipe_out_info = &pipe->output_info[0]; 5871 pipe_vf_out_info = &pipe->vf_output_info[0]; 5872 5873 if (mycs->primary_binary[0].info) 5874 return 0; 5875 5876 err = set_num_primary_stages(&mycs->num_primary_stage, 5877 pipe->config.isp_pipe_version); 5878 if (err) { 5879 IA_CSS_LEAVE_ERR_PRIVATE(err); 5880 return err; 5881 } 5882 5883 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 5884 err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info); 5885 if (err) { 5886 IA_CSS_LEAVE_ERR_PRIVATE(err); 5887 return err; 5888 } 5889 } else { 5890 err = ia_css_frame_check_info(pipe_out_info); 5891 if (err) { 5892 IA_CSS_LEAVE_ERR_PRIVATE(err); 5893 return err; 5894 } 5895 } 5896 need_pp = need_capture_pp(pipe); 5897 5898 /* we use the vf output info to get the primary/capture_pp binary 5899 configured for vf_veceven. It will select the closest downscaling 5900 factor. */ 5901 vf_info = *pipe_vf_out_info; 5902 5903 /* 5904 * WARNING: The #if def flag has been added below as a 5905 * temporary solution to solve the problem of enabling the 5906 * view finder in a single binary in a capture flow. The 5907 * vf-pp stage has been removed for Skycam in the solution 5908 * provided. The vf-pp stage should be re-introduced when 5909 * required. This should not be considered as a clean solution. 5910 * Proper investigation should be done to come up with the clean 5911 * solution. 5912 * */ 5913 ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE); 5914 5915 /* TODO: All this yuv_scaler and capturepp calculation logic 5916 * can be shared later. Capture_pp is also a yuv_scale binary 5917 * with extra XNR funcionality. Therefore, it can be made as the 5918 * first step of the cascade. */ 5919 capt_pp_out_info = pipe->out_yuv_ds_input_info; 5920 capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420; 5921 capt_pp_out_info.res.width /= MAX_PREFERRED_YUV_DS_PER_STEP; 5922 capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP; 5923 ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0); 5924 5925 need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res, 5926 pipe_out_info->res); 5927 5928 if (need_extra_yuv_scaler) { 5929 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 5930 5931 err = ia_css_pipe_create_cas_scaler_desc_single_output( 5932 &capt_pp_out_info, 5933 pipe_out_info, 5934 NULL, 5935 &cas_scaler_descr); 5936 if (err) { 5937 IA_CSS_LEAVE_ERR_PRIVATE(err); 5938 return err; 5939 } 5940 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 5941 mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * 5942 sizeof(struct ia_css_binary), GFP_KERNEL); 5943 if (!mycs->yuv_scaler_binary) { 5944 err = -ENOMEM; 5945 IA_CSS_LEAVE_ERR_PRIVATE(err); 5946 return err; 5947 } 5948 mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * 5949 sizeof(bool), GFP_KERNEL); 5950 if (!mycs->is_output_stage) { 5951 err = -ENOMEM; 5952 IA_CSS_LEAVE_ERR_PRIVATE(err); 5953 return err; 5954 } 5955 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 5956 struct ia_css_binary_descr yuv_scaler_descr; 5957 5958 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 5959 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 5960 &yuv_scaler_descr, &cas_scaler_descr.in_info[i], 5961 &cas_scaler_descr.out_info[i], 5962 &cas_scaler_descr.internal_out_info[i], 5963 &cas_scaler_descr.vf_info[i]); 5964 err = ia_css_binary_find(&yuv_scaler_descr, 5965 &mycs->yuv_scaler_binary[i]); 5966 if (err) { 5967 IA_CSS_LEAVE_ERR_PRIVATE(err); 5968 return err; 5969 } 5970 } 5971 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 5972 5973 } else { 5974 capt_pp_out_info = pipe->output_info[0]; 5975 } 5976 5977 /* TODO Do we disable ldc for skycam */ 5978 need_ldc = need_capt_ldc(pipe); 5979 if (IS_ISP2401 && need_ldc) { 5980 /* ldc and capt_pp are not supported in the same pipeline */ 5981 struct ia_css_binary_descr capt_ldc_descr; 5982 5983 ia_css_pipe_get_ldc_binarydesc(pipe, 5984 &capt_ldc_descr, &prim_out_info, 5985 &capt_pp_out_info); 5986 5987 err = ia_css_binary_find(&capt_ldc_descr, 5988 &mycs->capture_ldc_binary); 5989 if (err) { 5990 IA_CSS_LEAVE_ERR_PRIVATE(err); 5991 return err; 5992 } 5993 need_pp = false; 5994 need_ldc = false; 5995 } 5996 5997 /* we build up the pipeline starting at the end */ 5998 /* Capture post-processing */ 5999 if (need_pp) { 6000 struct ia_css_binary_descr capture_pp_descr; 6001 6002 if (!IS_ISP2401) 6003 capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info; 6004 else 6005 capt_pp_in_info = &prim_out_info; 6006 6007 ia_css_pipe_get_capturepp_binarydesc(pipe, 6008 &capture_pp_descr, 6009 capt_pp_in_info, 6010 &capt_pp_out_info, 6011 &vf_info); 6012 6013 err = ia_css_binary_find(&capture_pp_descr, 6014 &mycs->capture_pp_binary); 6015 if (err) { 6016 IA_CSS_LEAVE_ERR_PRIVATE(err); 6017 return err; 6018 } 6019 6020 if (need_ldc) { 6021 struct ia_css_binary_descr capt_ldc_descr; 6022 6023 ia_css_pipe_get_ldc_binarydesc(pipe, 6024 &capt_ldc_descr, 6025 &prim_out_info, 6026 &capt_ldc_out_info); 6027 6028 err = ia_css_binary_find(&capt_ldc_descr, 6029 &mycs->capture_ldc_binary); 6030 if (err) { 6031 IA_CSS_LEAVE_ERR_PRIVATE(err); 6032 return err; 6033 } 6034 } 6035 } else { 6036 prim_out_info = *pipe_out_info; 6037 } 6038 6039 /* Primary */ 6040 for (i = 0; i < mycs->num_primary_stage; i++) { 6041 struct ia_css_frame_info *local_vf_info = NULL; 6042 6043 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && 6044 (i == mycs->num_primary_stage - 1)) 6045 local_vf_info = &vf_info; 6046 ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], 6047 &prim_in_info, &prim_out_info, 6048 local_vf_info, i); 6049 err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]); 6050 if (err) { 6051 IA_CSS_LEAVE_ERR_PRIVATE(err); 6052 return err; 6053 } 6054 } 6055 6056 /* Viewfinder post-processing */ 6057 if (need_pp) 6058 vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info; 6059 else 6060 vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info; 6061 6062 /* 6063 * WARNING: The #if def flag has been added below as a 6064 * temporary solution to solve the problem of enabling the 6065 * view finder in a single binary in a capture flow. The 6066 * vf-pp stage has been removed for Skycam in the solution 6067 * provided. The vf-pp stage should be re-introduced when 6068 * required. Thisshould not be considered as a clean solution. 6069 * Proper * investigation should be done to come up with the clean 6070 * solution. 6071 * */ 6072 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 6073 struct ia_css_binary_descr vf_pp_descr; 6074 6075 ia_css_pipe_get_vfpp_binarydesc(pipe, 6076 &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); 6077 err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary); 6078 if (err) { 6079 IA_CSS_LEAVE_ERR_PRIVATE(err); 6080 return err; 6081 } 6082 } 6083 err = allocate_delay_frames(pipe); 6084 6085 if (err) 6086 return err; 6087 6088 #ifdef ISP2401 6089 /* When the input system is 2401, only the Direct Sensor Mode 6090 * Offline Capture uses the ISP copy binary. 6091 */ 6092 need_isp_copy_binary = !online && sensor; 6093 #else 6094 need_isp_copy_binary = !online && !continuous && !memory; 6095 #endif 6096 6097 /* ISP Copy */ 6098 if (need_isp_copy_binary) { 6099 err = load_copy_binary(pipe, 6100 &mycs->copy_binary, 6101 &mycs->primary_binary[0]); 6102 if (err) { 6103 IA_CSS_LEAVE_ERR_PRIVATE(err); 6104 return err; 6105 } 6106 } 6107 6108 return 0; 6109 } 6110 6111 static int 6112 allocate_delay_frames(struct ia_css_pipe *pipe) 6113 { 6114 unsigned int num_delay_frames = 0, i = 0; 6115 unsigned int dvs_frame_delay = 0; 6116 struct ia_css_frame_info ref_info; 6117 int err = 0; 6118 enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO; 6119 struct ia_css_frame **delay_frames = NULL; 6120 6121 IA_CSS_ENTER_PRIVATE(""); 6122 6123 if (!pipe) { 6124 IA_CSS_ERROR("Invalid args - pipe %p", pipe); 6125 return -EINVAL; 6126 } 6127 6128 mode = pipe->mode; 6129 dvs_frame_delay = pipe->dvs_frame_delay; 6130 6131 if (dvs_frame_delay > 0) 6132 num_delay_frames = dvs_frame_delay + 1; 6133 6134 switch (mode) { 6135 case IA_CSS_PIPE_ID_CAPTURE: { 6136 struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture; 6137 (void)mycs_capture; 6138 return err; 6139 } 6140 break; 6141 case IA_CSS_PIPE_ID_VIDEO: { 6142 struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video; 6143 6144 ref_info = mycs_video->video_binary.internal_frame_info; 6145 /*The ref frame expects 6146 * 1. Y plane 6147 * 2. UV plane with line interleaving, like below 6148 * UUUUUU(width/2 times) VVVVVVVV..(width/2 times) 6149 * 6150 * This format is not YUV420(which has Y, U and V planes). 6151 * Its closer to NV12, except that the UV plane has UV 6152 * interleaving, like UVUVUVUVUVUVUVUVU... 6153 * 6154 * TODO: make this ref_frame format as a separate frame format 6155 */ 6156 ref_info.format = IA_CSS_FRAME_FORMAT_NV12; 6157 delay_frames = mycs_video->delay_frames; 6158 } 6159 break; 6160 case IA_CSS_PIPE_ID_PREVIEW: { 6161 struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview; 6162 6163 ref_info = mycs_preview->preview_binary.internal_frame_info; 6164 /*The ref frame expects 6165 * 1. Y plane 6166 * 2. UV plane with line interleaving, like below 6167 * UUUUUU(width/2 times) VVVVVVVV..(width/2 times) 6168 * 6169 * This format is not YUV420(which has Y, U and V planes). 6170 * Its closer to NV12, except that the UV plane has UV 6171 * interleaving, like UVUVUVUVUVUVUVUVU... 6172 * 6173 * TODO: make this ref_frame format as a separate frame format 6174 */ 6175 ref_info.format = IA_CSS_FRAME_FORMAT_NV12; 6176 delay_frames = mycs_preview->delay_frames; 6177 } 6178 break; 6179 default: 6180 return -EINVAL; 6181 } 6182 6183 ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH; 6184 6185 assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES); 6186 for (i = 0; i < num_delay_frames; i++) { 6187 err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info); 6188 if (err) 6189 return err; 6190 } 6191 IA_CSS_LEAVE_PRIVATE(""); 6192 return 0; 6193 } 6194 6195 static int load_advanced_binaries(struct ia_css_pipe *pipe) 6196 { 6197 struct ia_css_frame_info pre_in_info, gdc_in_info, 6198 post_in_info, post_out_info, 6199 vf_info, *vf_pp_in_info, *pipe_out_info, 6200 *pipe_vf_out_info; 6201 bool need_pp; 6202 bool need_isp_copy = true; 6203 int err = 0; 6204 6205 IA_CSS_ENTER_PRIVATE(""); 6206 6207 assert(pipe); 6208 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 6209 pipe->mode == IA_CSS_PIPE_ID_COPY); 6210 if (pipe->pipe_settings.capture.pre_isp_binary.info) 6211 return 0; 6212 pipe_out_info = &pipe->output_info[0]; 6213 pipe_vf_out_info = &pipe->vf_output_info[0]; 6214 6215 vf_info = *pipe_vf_out_info; 6216 err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info); 6217 if (err) 6218 return err; 6219 need_pp = need_capture_pp(pipe); 6220 6221 ia_css_frame_info_set_format(&vf_info, 6222 IA_CSS_FRAME_FORMAT_YUV_LINE); 6223 6224 /* we build up the pipeline starting at the end */ 6225 /* Capture post-processing */ 6226 if (need_pp) { 6227 struct ia_css_binary_descr capture_pp_descr; 6228 6229 ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, 6230 &post_out_info, 6231 pipe_out_info, &vf_info); 6232 err = ia_css_binary_find(&capture_pp_descr, 6233 &pipe->pipe_settings.capture.capture_pp_binary); 6234 if (err) 6235 return err; 6236 } else { 6237 post_out_info = *pipe_out_info; 6238 } 6239 6240 /* Post-gdc */ 6241 { 6242 struct ia_css_binary_descr post_gdc_descr; 6243 6244 ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr, 6245 &post_in_info, 6246 &post_out_info, &vf_info); 6247 err = ia_css_binary_find(&post_gdc_descr, 6248 &pipe->pipe_settings.capture.post_isp_binary); 6249 if (err) 6250 return err; 6251 } 6252 6253 /* Gdc */ 6254 { 6255 struct ia_css_binary_descr gdc_descr; 6256 6257 ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info, 6258 &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); 6259 err = ia_css_binary_find(&gdc_descr, 6260 &pipe->pipe_settings.capture.anr_gdc_binary); 6261 if (err) 6262 return err; 6263 } 6264 pipe->pipe_settings.capture.anr_gdc_binary.left_padding = 6265 pipe->pipe_settings.capture.post_isp_binary.left_padding; 6266 6267 /* Pre-gdc */ 6268 { 6269 struct ia_css_binary_descr pre_gdc_descr; 6270 6271 ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info, 6272 &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); 6273 err = ia_css_binary_find(&pre_gdc_descr, 6274 &pipe->pipe_settings.capture.pre_isp_binary); 6275 if (err) 6276 return err; 6277 } 6278 pipe->pipe_settings.capture.pre_isp_binary.left_padding = 6279 pipe->pipe_settings.capture.anr_gdc_binary.left_padding; 6280 6281 /* Viewfinder post-processing */ 6282 if (need_pp) { 6283 vf_pp_in_info = 6284 &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info; 6285 } else { 6286 vf_pp_in_info = 6287 &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info; 6288 } 6289 6290 { 6291 struct ia_css_binary_descr vf_pp_descr; 6292 6293 ia_css_pipe_get_vfpp_binarydesc(pipe, 6294 &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); 6295 err = ia_css_binary_find(&vf_pp_descr, 6296 &pipe->pipe_settings.capture.vf_pp_binary); 6297 if (err) 6298 return err; 6299 } 6300 6301 /* Copy */ 6302 #ifdef ISP2401 6303 /* For CSI2+, only the direct sensor mode/online requires ISP copy */ 6304 need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 6305 #endif 6306 if (need_isp_copy) 6307 load_copy_binary(pipe, 6308 &pipe->pipe_settings.capture.copy_binary, 6309 &pipe->pipe_settings.capture.pre_isp_binary); 6310 6311 return err; 6312 } 6313 6314 static int load_bayer_isp_binaries(struct ia_css_pipe *pipe) 6315 { 6316 struct ia_css_frame_info pre_isp_in_info, *pipe_out_info; 6317 int err = 0; 6318 struct ia_css_binary_descr pre_de_descr; 6319 6320 IA_CSS_ENTER_PRIVATE(""); 6321 assert(pipe); 6322 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 6323 pipe->mode == IA_CSS_PIPE_ID_COPY); 6324 pipe_out_info = &pipe->output_info[0]; 6325 6326 if (pipe->pipe_settings.capture.pre_isp_binary.info) 6327 return 0; 6328 6329 err = ia_css_frame_check_info(pipe_out_info); 6330 if (err) 6331 return err; 6332 6333 ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr, 6334 &pre_isp_in_info, 6335 pipe_out_info); 6336 6337 err = ia_css_binary_find(&pre_de_descr, 6338 &pipe->pipe_settings.capture.pre_isp_binary); 6339 6340 return err; 6341 } 6342 6343 static int load_low_light_binaries(struct ia_css_pipe *pipe) 6344 { 6345 struct ia_css_frame_info pre_in_info, anr_in_info, 6346 post_in_info, post_out_info, 6347 vf_info, *pipe_vf_out_info, *pipe_out_info, 6348 *vf_pp_in_info; 6349 bool need_pp; 6350 bool need_isp_copy = true; 6351 int err = 0; 6352 6353 IA_CSS_ENTER_PRIVATE(""); 6354 assert(pipe); 6355 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 6356 pipe->mode == IA_CSS_PIPE_ID_COPY); 6357 6358 if (pipe->pipe_settings.capture.pre_isp_binary.info) 6359 return 0; 6360 pipe_vf_out_info = &pipe->vf_output_info[0]; 6361 pipe_out_info = &pipe->output_info[0]; 6362 6363 vf_info = *pipe_vf_out_info; 6364 err = ia_css_util_check_vf_out_info(pipe_out_info, 6365 &vf_info); 6366 if (err) 6367 return err; 6368 need_pp = need_capture_pp(pipe); 6369 6370 ia_css_frame_info_set_format(&vf_info, 6371 IA_CSS_FRAME_FORMAT_YUV_LINE); 6372 6373 /* we build up the pipeline starting at the end */ 6374 /* Capture post-processing */ 6375 if (need_pp) { 6376 struct ia_css_binary_descr capture_pp_descr; 6377 6378 ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, 6379 &post_out_info, 6380 pipe_out_info, &vf_info); 6381 err = ia_css_binary_find(&capture_pp_descr, 6382 &pipe->pipe_settings.capture.capture_pp_binary); 6383 if (err) 6384 return err; 6385 } else { 6386 post_out_info = *pipe_out_info; 6387 } 6388 6389 /* Post-anr */ 6390 { 6391 struct ia_css_binary_descr post_anr_descr; 6392 6393 ia_css_pipe_get_post_anr_binarydesc(pipe, 6394 &post_anr_descr, &post_in_info, &post_out_info, &vf_info); 6395 err = ia_css_binary_find(&post_anr_descr, 6396 &pipe->pipe_settings.capture.post_isp_binary); 6397 if (err) 6398 return err; 6399 } 6400 6401 /* Anr */ 6402 { 6403 struct ia_css_binary_descr anr_descr; 6404 6405 ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info, 6406 &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); 6407 err = ia_css_binary_find(&anr_descr, 6408 &pipe->pipe_settings.capture.anr_gdc_binary); 6409 if (err) 6410 return err; 6411 } 6412 pipe->pipe_settings.capture.anr_gdc_binary.left_padding = 6413 pipe->pipe_settings.capture.post_isp_binary.left_padding; 6414 6415 /* Pre-anr */ 6416 { 6417 struct ia_css_binary_descr pre_anr_descr; 6418 6419 ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info, 6420 &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); 6421 err = ia_css_binary_find(&pre_anr_descr, 6422 &pipe->pipe_settings.capture.pre_isp_binary); 6423 if (err) 6424 return err; 6425 } 6426 pipe->pipe_settings.capture.pre_isp_binary.left_padding = 6427 pipe->pipe_settings.capture.anr_gdc_binary.left_padding; 6428 6429 /* Viewfinder post-processing */ 6430 if (need_pp) { 6431 vf_pp_in_info = 6432 &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info; 6433 } else { 6434 vf_pp_in_info = 6435 &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info; 6436 } 6437 6438 { 6439 struct ia_css_binary_descr vf_pp_descr; 6440 6441 ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, 6442 vf_pp_in_info, pipe_vf_out_info); 6443 err = ia_css_binary_find(&vf_pp_descr, 6444 &pipe->pipe_settings.capture.vf_pp_binary); 6445 if (err) 6446 return err; 6447 } 6448 6449 /* Copy */ 6450 #ifdef ISP2401 6451 /* For CSI2+, only the direct sensor mode/online requires ISP copy */ 6452 need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 6453 #endif 6454 if (need_isp_copy) 6455 err = load_copy_binary(pipe, 6456 &pipe->pipe_settings.capture.copy_binary, 6457 &pipe->pipe_settings.capture.pre_isp_binary); 6458 6459 return err; 6460 } 6461 6462 static bool copy_on_sp(struct ia_css_pipe *pipe) 6463 { 6464 bool rval; 6465 6466 assert(pipe); 6467 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n"); 6468 6469 rval = true; 6470 6471 rval &= (pipe->mode == IA_CSS_PIPE_ID_CAPTURE); 6472 6473 rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW); 6474 6475 rval &= ((pipe->stream->config.input_config.format == 6476 ATOMISP_INPUT_FORMAT_BINARY_8) || 6477 (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)); 6478 6479 return rval; 6480 } 6481 6482 static int load_capture_binaries(struct ia_css_pipe *pipe) 6483 { 6484 int err = 0; 6485 bool must_be_raw; 6486 6487 IA_CSS_ENTER_PRIVATE(""); 6488 assert(pipe); 6489 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 6490 pipe->mode == IA_CSS_PIPE_ID_COPY); 6491 6492 if (pipe->pipe_settings.capture.primary_binary[0].info) { 6493 IA_CSS_LEAVE_ERR_PRIVATE(0); 6494 return 0; 6495 } 6496 6497 /* in primary, advanced,low light or bayer, 6498 the input format must be raw */ 6499 must_be_raw = 6500 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED || 6501 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER || 6502 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT; 6503 err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false); 6504 if (err) { 6505 IA_CSS_LEAVE_ERR_PRIVATE(err); 6506 return err; 6507 } 6508 if (copy_on_sp(pipe) && 6509 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 6510 ia_css_frame_info_init( 6511 &pipe->output_info[0], 6512 JPEG_BYTES, 6513 1, 6514 IA_CSS_FRAME_FORMAT_BINARY_8, 6515 0); 6516 IA_CSS_LEAVE_ERR_PRIVATE(0); 6517 return 0; 6518 } 6519 6520 switch (pipe->config.default_capture_config.mode) { 6521 case IA_CSS_CAPTURE_MODE_RAW: 6522 err = load_copy_binaries(pipe); 6523 #if defined(ISP2401) 6524 if (!err) 6525 pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online; 6526 #endif 6527 break; 6528 case IA_CSS_CAPTURE_MODE_BAYER: 6529 err = load_bayer_isp_binaries(pipe); 6530 break; 6531 case IA_CSS_CAPTURE_MODE_PRIMARY: 6532 err = load_primary_binaries(pipe); 6533 break; 6534 case IA_CSS_CAPTURE_MODE_ADVANCED: 6535 err = load_advanced_binaries(pipe); 6536 break; 6537 case IA_CSS_CAPTURE_MODE_LOW_LIGHT: 6538 err = load_low_light_binaries(pipe); 6539 break; 6540 } 6541 if (err) { 6542 IA_CSS_LEAVE_ERR_PRIVATE(err); 6543 return err; 6544 } 6545 6546 IA_CSS_LEAVE_ERR_PRIVATE(err); 6547 return err; 6548 } 6549 6550 static int 6551 unload_capture_binaries(struct ia_css_pipe *pipe) 6552 { 6553 unsigned int i; 6554 6555 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 6556 6557 if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE && 6558 pipe->mode != IA_CSS_PIPE_ID_COPY)) { 6559 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 6560 return -EINVAL; 6561 } 6562 ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary); 6563 for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++) 6564 ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]); 6565 ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary); 6566 ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary); 6567 ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary); 6568 ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary); 6569 ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary); 6570 ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary); 6571 6572 for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++) 6573 ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]); 6574 6575 kfree(pipe->pipe_settings.capture.is_output_stage); 6576 pipe->pipe_settings.capture.is_output_stage = NULL; 6577 kfree(pipe->pipe_settings.capture.yuv_scaler_binary); 6578 pipe->pipe_settings.capture.yuv_scaler_binary = NULL; 6579 6580 IA_CSS_LEAVE_ERR_PRIVATE(0); 6581 return 0; 6582 } 6583 6584 static bool 6585 need_downscaling(const struct ia_css_resolution in_res, 6586 const struct ia_css_resolution out_res) 6587 { 6588 if (in_res.width > out_res.width || in_res.height > out_res.height) 6589 return true; 6590 6591 return false; 6592 } 6593 6594 static bool 6595 need_yuv_scaler_stage(const struct ia_css_pipe *pipe) 6596 { 6597 unsigned int i; 6598 struct ia_css_resolution in_res, out_res; 6599 6600 bool need_format_conversion = false; 6601 6602 IA_CSS_ENTER_PRIVATE(""); 6603 assert(pipe); 6604 assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP); 6605 6606 /* TODO: make generic function */ 6607 need_format_conversion = 6608 ((pipe->stream->config.input_config.format == 6609 ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) && 6610 (pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8)); 6611 6612 in_res = pipe->config.input_effective_res; 6613 6614 if (pipe->config.enable_dz) 6615 return true; 6616 6617 if ((pipe->output_info[0].res.width != 0) && need_format_conversion) 6618 return true; 6619 6620 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6621 out_res = pipe->output_info[i].res; 6622 6623 /* A non-zero width means it is a valid output port */ 6624 if ((out_res.width != 0) && need_downscaling(in_res, out_res)) 6625 return true; 6626 } 6627 6628 return false; 6629 } 6630 6631 /* TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc */ 6632 /* which has some hard-coded knowledge which prevents reuse of the function. */ 6633 /* Later, merge this with ia_css_pipe_create_cas_scaler_desc */ 6634 static int ia_css_pipe_create_cas_scaler_desc_single_output( 6635 struct ia_css_frame_info *cas_scaler_in_info, 6636 struct ia_css_frame_info *cas_scaler_out_info, 6637 struct ia_css_frame_info *cas_scaler_vf_info, 6638 struct ia_css_cas_binary_descr *descr) 6639 { 6640 unsigned int i; 6641 unsigned int hor_ds_factor = 0, ver_ds_factor = 0; 6642 int err = 0; 6643 struct ia_css_frame_info tmp_in_info; 6644 6645 unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP; 6646 6647 assert(cas_scaler_in_info); 6648 assert(cas_scaler_out_info); 6649 6650 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6651 "ia_css_pipe_create_cas_scaler_desc() enter:\n"); 6652 6653 /* We assume that this function is used only for single output port case. */ 6654 descr->num_output_stage = 1; 6655 6656 hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width, 6657 cas_scaler_out_info->res.width); 6658 ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height, 6659 cas_scaler_out_info->res.height); 6660 /* use the same horizontal and vertical downscaling factor for simplicity */ 6661 assert(hor_ds_factor == ver_ds_factor); 6662 6663 i = 1; 6664 while (i < hor_ds_factor) { 6665 descr->num_stage++; 6666 i *= max_scale_factor_per_stage; 6667 } 6668 6669 descr->in_info = kmalloc(descr->num_stage * 6670 sizeof(struct ia_css_frame_info), 6671 GFP_KERNEL); 6672 if (!descr->in_info) { 6673 err = -ENOMEM; 6674 goto ERR; 6675 } 6676 descr->internal_out_info = kmalloc(descr->num_stage * 6677 sizeof(struct ia_css_frame_info), 6678 GFP_KERNEL); 6679 if (!descr->internal_out_info) { 6680 err = -ENOMEM; 6681 goto ERR; 6682 } 6683 descr->out_info = kmalloc(descr->num_stage * 6684 sizeof(struct ia_css_frame_info), 6685 GFP_KERNEL); 6686 if (!descr->out_info) { 6687 err = -ENOMEM; 6688 goto ERR; 6689 } 6690 descr->vf_info = kmalloc(descr->num_stage * 6691 sizeof(struct ia_css_frame_info), 6692 GFP_KERNEL); 6693 if (!descr->vf_info) { 6694 err = -ENOMEM; 6695 goto ERR; 6696 } 6697 descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), 6698 GFP_KERNEL); 6699 if (!descr->is_output_stage) { 6700 err = -ENOMEM; 6701 goto ERR; 6702 } 6703 6704 tmp_in_info = *cas_scaler_in_info; 6705 for (i = 0; i < descr->num_stage; i++) { 6706 descr->in_info[i] = tmp_in_info; 6707 if ((tmp_in_info.res.width / max_scale_factor_per_stage) <= 6708 cas_scaler_out_info->res.width) { 6709 descr->is_output_stage[i] = true; 6710 if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) { 6711 descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width; 6712 descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height; 6713 descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width; 6714 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6715 } else { 6716 assert(i == (descr->num_stage - 1)); 6717 descr->internal_out_info[i].res.width = 0; 6718 descr->internal_out_info[i].res.height = 0; 6719 } 6720 descr->out_info[i].res.width = cas_scaler_out_info->res.width; 6721 descr->out_info[i].res.height = cas_scaler_out_info->res.height; 6722 descr->out_info[i].padded_width = cas_scaler_out_info->padded_width; 6723 descr->out_info[i].format = cas_scaler_out_info->format; 6724 if (cas_scaler_vf_info) { 6725 descr->vf_info[i].res.width = cas_scaler_vf_info->res.width; 6726 descr->vf_info[i].res.height = cas_scaler_vf_info->res.height; 6727 descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width; 6728 ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE); 6729 } else { 6730 descr->vf_info[i].res.width = 0; 6731 descr->vf_info[i].res.height = 0; 6732 descr->vf_info[i].padded_width = 0; 6733 } 6734 } else { 6735 descr->is_output_stage[i] = false; 6736 descr->internal_out_info[i].res.width = tmp_in_info.res.width / 6737 max_scale_factor_per_stage; 6738 descr->internal_out_info[i].res.height = tmp_in_info.res.height / 6739 max_scale_factor_per_stage; 6740 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6741 ia_css_frame_info_init(&descr->internal_out_info[i], 6742 tmp_in_info.res.width / max_scale_factor_per_stage, 6743 tmp_in_info.res.height / max_scale_factor_per_stage, 6744 IA_CSS_FRAME_FORMAT_YUV420, 0); 6745 descr->out_info[i].res.width = 0; 6746 descr->out_info[i].res.height = 0; 6747 descr->vf_info[i].res.width = 0; 6748 descr->vf_info[i].res.height = 0; 6749 } 6750 tmp_in_info = descr->internal_out_info[i]; 6751 } 6752 ERR: 6753 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6754 "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n", 6755 err); 6756 return err; 6757 } 6758 6759 /* FIXME: merge most of this and single output version */ 6760 static int 6761 ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe, 6762 struct ia_css_cas_binary_descr *descr) 6763 { 6764 struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; 6765 struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6766 struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6767 struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; 6768 unsigned int i, j; 6769 unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE], 6770 ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE], 6771 scale_factor = 0; 6772 unsigned int num_stages = 0; 6773 int err = 0; 6774 6775 unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP; 6776 6777 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6778 "ia_css_pipe_create_cas_scaler_desc() enter:\n"); 6779 6780 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6781 out_info[i] = NULL; 6782 vf_out_info[i] = NULL; 6783 hor_scale_factor[i] = 0; 6784 ver_scale_factor[i] = 0; 6785 } 6786 6787 in_info.res = pipe->config.input_effective_res; 6788 in_info.padded_width = in_info.res.width; 6789 descr->num_output_stage = 0; 6790 /* Find out how much scaling we need for each output */ 6791 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6792 if (pipe->output_info[i].res.width != 0) { 6793 out_info[i] = &pipe->output_info[i]; 6794 if (pipe->vf_output_info[i].res.width != 0) 6795 vf_out_info[i] = &pipe->vf_output_info[i]; 6796 descr->num_output_stage += 1; 6797 } 6798 6799 if (out_info[i]) { 6800 hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width); 6801 ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height); 6802 /* use the same horizontal and vertical scaling factor for simplicity */ 6803 assert(hor_scale_factor[i] == ver_scale_factor[i]); 6804 scale_factor = 1; 6805 do { 6806 num_stages++; 6807 scale_factor *= max_scale_factor_per_stage; 6808 } while (scale_factor < hor_scale_factor[i]); 6809 6810 in_info.res = out_info[i]->res; 6811 } 6812 } 6813 6814 if (need_yuv_scaler_stage(pipe) && (num_stages == 0)) 6815 num_stages = 1; 6816 6817 descr->num_stage = num_stages; 6818 6819 descr->in_info = kmalloc_array(descr->num_stage, 6820 sizeof(struct ia_css_frame_info), 6821 GFP_KERNEL); 6822 if (!descr->in_info) { 6823 err = -ENOMEM; 6824 goto ERR; 6825 } 6826 descr->internal_out_info = kmalloc(descr->num_stage * 6827 sizeof(struct ia_css_frame_info), 6828 GFP_KERNEL); 6829 if (!descr->internal_out_info) { 6830 err = -ENOMEM; 6831 goto ERR; 6832 } 6833 descr->out_info = kmalloc(descr->num_stage * 6834 sizeof(struct ia_css_frame_info), 6835 GFP_KERNEL); 6836 if (!descr->out_info) { 6837 err = -ENOMEM; 6838 goto ERR; 6839 } 6840 descr->vf_info = kmalloc(descr->num_stage * 6841 sizeof(struct ia_css_frame_info), 6842 GFP_KERNEL); 6843 if (!descr->vf_info) { 6844 err = -ENOMEM; 6845 goto ERR; 6846 } 6847 descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), 6848 GFP_KERNEL); 6849 if (!descr->is_output_stage) { 6850 err = -ENOMEM; 6851 goto ERR; 6852 } 6853 6854 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6855 if (out_info[i]) { 6856 if (i > 0) { 6857 assert((out_info[i - 1]->res.width >= out_info[i]->res.width) && 6858 (out_info[i - 1]->res.height >= out_info[i]->res.height)); 6859 } 6860 } 6861 } 6862 6863 tmp_in_info.res = pipe->config.input_effective_res; 6864 tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420; 6865 for (i = 0, j = 0; i < descr->num_stage; i++) { 6866 assert(j < 2); 6867 assert(out_info[j]); 6868 6869 descr->in_info[i] = tmp_in_info; 6870 if ((tmp_in_info.res.width / max_scale_factor_per_stage) <= 6871 out_info[j]->res.width) { 6872 descr->is_output_stage[i] = true; 6873 if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) { 6874 descr->internal_out_info[i].res.width = out_info[j]->res.width; 6875 descr->internal_out_info[i].res.height = out_info[j]->res.height; 6876 descr->internal_out_info[i].padded_width = out_info[j]->padded_width; 6877 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6878 } else { 6879 assert(i == (descr->num_stage - 1)); 6880 descr->internal_out_info[i].res.width = 0; 6881 descr->internal_out_info[i].res.height = 0; 6882 } 6883 descr->out_info[i].res.width = out_info[j]->res.width; 6884 descr->out_info[i].res.height = out_info[j]->res.height; 6885 descr->out_info[i].padded_width = out_info[j]->padded_width; 6886 descr->out_info[i].format = out_info[j]->format; 6887 if (vf_out_info[j]) { 6888 descr->vf_info[i].res.width = vf_out_info[j]->res.width; 6889 descr->vf_info[i].res.height = vf_out_info[j]->res.height; 6890 descr->vf_info[i].padded_width = vf_out_info[j]->padded_width; 6891 ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE); 6892 } else { 6893 descr->vf_info[i].res.width = 0; 6894 descr->vf_info[i].res.height = 0; 6895 descr->vf_info[i].padded_width = 0; 6896 } 6897 j++; 6898 } else { 6899 descr->is_output_stage[i] = false; 6900 descr->internal_out_info[i].res.width = tmp_in_info.res.width / 6901 max_scale_factor_per_stage; 6902 descr->internal_out_info[i].res.height = tmp_in_info.res.height / 6903 max_scale_factor_per_stage; 6904 descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; 6905 ia_css_frame_info_init(&descr->internal_out_info[i], 6906 tmp_in_info.res.width / max_scale_factor_per_stage, 6907 tmp_in_info.res.height / max_scale_factor_per_stage, 6908 IA_CSS_FRAME_FORMAT_YUV420, 0); 6909 descr->out_info[i].res.width = 0; 6910 descr->out_info[i].res.height = 0; 6911 descr->vf_info[i].res.width = 0; 6912 descr->vf_info[i].res.height = 0; 6913 } 6914 tmp_in_info = descr->internal_out_info[i]; 6915 } 6916 ERR: 6917 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6918 "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n", 6919 err); 6920 return err; 6921 } 6922 6923 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr 6924 *descr) 6925 { 6926 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6927 "ia_css_pipe_destroy_cas_scaler_desc() enter:\n"); 6928 kfree(descr->in_info); 6929 descr->in_info = NULL; 6930 kfree(descr->internal_out_info); 6931 descr->internal_out_info = NULL; 6932 kfree(descr->out_info); 6933 descr->out_info = NULL; 6934 kfree(descr->vf_info); 6935 descr->vf_info = NULL; 6936 kfree(descr->is_output_stage); 6937 descr->is_output_stage = NULL; 6938 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 6939 "ia_css_pipe_destroy_cas_scaler_desc() leave\n"); 6940 } 6941 6942 static int 6943 load_yuvpp_binaries(struct ia_css_pipe *pipe) 6944 { 6945 int err = 0; 6946 bool need_scaler = false; 6947 struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 6948 struct ia_css_yuvpp_settings *mycs; 6949 struct ia_css_binary *next_binary; 6950 struct ia_css_cas_binary_descr cas_scaler_descr = { }; 6951 unsigned int i, j; 6952 bool need_isp_copy_binary = false; 6953 6954 IA_CSS_ENTER_PRIVATE(""); 6955 assert(pipe); 6956 assert(pipe->stream); 6957 assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP); 6958 6959 if (pipe->pipe_settings.yuvpp.copy_binary.info) 6960 goto ERR; 6961 6962 /* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */ 6963 err = ia_css_util_check_input(&pipe->stream->config, false, false); 6964 if (err) 6965 goto ERR; 6966 6967 mycs = &pipe->pipe_settings.yuvpp; 6968 6969 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 6970 if (pipe->vf_output_info[i].res.width != 0) { 6971 err = ia_css_util_check_vf_out_info(&pipe->output_info[i], 6972 &pipe->vf_output_info[i]); 6973 if (err) 6974 goto ERR; 6975 } 6976 vf_pp_in_info[i] = NULL; 6977 } 6978 6979 need_scaler = need_yuv_scaler_stage(pipe); 6980 6981 /* we build up the pipeline starting at the end */ 6982 /* Capture post-processing */ 6983 if (need_scaler) { 6984 struct ia_css_binary_descr yuv_scaler_descr; 6985 6986 err = ia_css_pipe_create_cas_scaler_desc(pipe, 6987 &cas_scaler_descr); 6988 if (err) 6989 goto ERR; 6990 mycs->num_output = cas_scaler_descr.num_output_stage; 6991 mycs->num_yuv_scaler = cas_scaler_descr.num_stage; 6992 mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * 6993 sizeof(struct ia_css_binary), 6994 GFP_KERNEL); 6995 if (!mycs->yuv_scaler_binary) { 6996 err = -ENOMEM; 6997 goto ERR; 6998 } 6999 mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * 7000 sizeof(bool), GFP_KERNEL); 7001 if (!mycs->is_output_stage) { 7002 err = -ENOMEM; 7003 goto ERR; 7004 } 7005 for (i = 0; i < cas_scaler_descr.num_stage; i++) { 7006 mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; 7007 ia_css_pipe_get_yuvscaler_binarydesc(pipe, 7008 &yuv_scaler_descr, 7009 &cas_scaler_descr.in_info[i], 7010 &cas_scaler_descr.out_info[i], 7011 &cas_scaler_descr.internal_out_info[i], 7012 &cas_scaler_descr.vf_info[i]); 7013 err = ia_css_binary_find(&yuv_scaler_descr, 7014 &mycs->yuv_scaler_binary[i]); 7015 if (err) 7016 goto ERR; 7017 } 7018 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 7019 } else { 7020 mycs->num_output = 1; 7021 } 7022 7023 if (need_scaler) 7024 next_binary = &mycs->yuv_scaler_binary[0]; 7025 else 7026 next_binary = NULL; 7027 7028 #if defined(ISP2401) 7029 /* 7030 * NOTES 7031 * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when 7032 * its input is "ATOMISP_INPUT_FORMAT_YUV422_8"? 7033 * 7034 * In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_ 7035 * binary". However, the "yuv_scale_binary" does NOT support the input-frame 7036 * format as "IA_CSS_STREAM _FORMAT_YUV422_8". 7037 * 7038 * Hence, the "isp_copy_binary" is required to be present in front of the "yuv 7039 * _scale_binary". It would translate the input-frame to the frame formats that 7040 * are supported by the "yuv_scale_binary". 7041 * 7042 * Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_ 7043 * pp_defs.h" for the list of input-frame formats that are supported by the 7044 * "yuv_scale_binary". 7045 */ 7046 need_isp_copy_binary = 7047 (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8); 7048 #else /* !ISP2401 */ 7049 need_isp_copy_binary = true; 7050 #endif /* ISP2401 */ 7051 7052 if (need_isp_copy_binary) { 7053 err = load_copy_binary(pipe, 7054 &mycs->copy_binary, 7055 next_binary); 7056 7057 if (err) 7058 goto ERR; 7059 7060 /* 7061 * NOTES 7062 * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified? 7063 * 7064 * In some use cases, the first stage in the "yuvpp" pipe is the 7065 * "isp_copy_binary". The "isp_copy_binary" is designed to process 7066 * the input from either the system DDR or from the IPU internal VMEM. 7067 * So it provides the flag "online" to specify where its input is from, 7068 * i.e.: 7069 * 7070 * (1) "online <= true", the input is from the IPU internal VMEM. 7071 * (2) "online <= false", the input is from the system DDR. 7072 * 7073 * In other use cases, the first stage in the "yuvpp" pipe is the 7074 * "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the 7075 * input ONLY from the system DDR. So it does not provide the flag "online" 7076 * to specify where its input is from. 7077 */ 7078 pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online; 7079 } 7080 7081 /* Viewfinder post-processing */ 7082 if (need_scaler) { 7083 for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) { 7084 if (mycs->is_output_stage[i]) { 7085 assert(j < 2); 7086 vf_pp_in_info[j] = 7087 &mycs->yuv_scaler_binary[i].vf_frame_info; 7088 j++; 7089 } 7090 } 7091 mycs->num_vf_pp = j; 7092 } else { 7093 vf_pp_in_info[0] = 7094 &mycs->copy_binary.vf_frame_info; 7095 for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) 7096 vf_pp_in_info[i] = NULL; 7097 7098 mycs->num_vf_pp = 1; 7099 } 7100 mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * 7101 sizeof(struct ia_css_binary), 7102 GFP_KERNEL); 7103 if (!mycs->vf_pp_binary) { 7104 err = -ENOMEM; 7105 goto ERR; 7106 } 7107 7108 { 7109 struct ia_css_binary_descr vf_pp_descr; 7110 7111 for (i = 0; i < mycs->num_vf_pp; i++) { 7112 if (pipe->vf_output_info[i].res.width != 0) { 7113 ia_css_pipe_get_vfpp_binarydesc(pipe, 7114 &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]); 7115 err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]); 7116 if (err) 7117 goto ERR; 7118 } 7119 } 7120 } 7121 7122 if (err) 7123 goto ERR; 7124 7125 ERR: 7126 if (need_scaler) 7127 ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); 7128 7129 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n", 7130 err); 7131 return err; 7132 } 7133 7134 static int 7135 unload_yuvpp_binaries(struct ia_css_pipe *pipe) 7136 { 7137 unsigned int i; 7138 7139 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7140 7141 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 7142 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7143 return -EINVAL; 7144 } 7145 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary); 7146 for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++) 7147 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]); 7148 7149 for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++) 7150 ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]); 7151 7152 kfree(pipe->pipe_settings.yuvpp.is_output_stage); 7153 pipe->pipe_settings.yuvpp.is_output_stage = NULL; 7154 kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary); 7155 pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL; 7156 kfree(pipe->pipe_settings.yuvpp.vf_pp_binary); 7157 pipe->pipe_settings.yuvpp.vf_pp_binary = NULL; 7158 7159 IA_CSS_LEAVE_ERR_PRIVATE(0); 7160 return 0; 7161 } 7162 7163 static int yuvpp_start(struct ia_css_pipe *pipe) 7164 { 7165 int err = 0; 7166 enum sh_css_pipe_config_override copy_ovrd; 7167 enum ia_css_input_mode yuvpp_pipe_input_mode; 7168 7169 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7170 if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 7171 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7172 return -EINVAL; 7173 } 7174 7175 yuvpp_pipe_input_mode = pipe->stream->config.mode; 7176 7177 sh_css_metrics_start_frame(); 7178 7179 /* multi stream video needs mipi buffers */ 7180 7181 err = send_mipi_frames(pipe); 7182 if (err) { 7183 IA_CSS_LEAVE_ERR_PRIVATE(err); 7184 return err; 7185 } 7186 7187 { 7188 unsigned int thread_id; 7189 7190 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 7191 copy_ovrd = 1 << thread_id; 7192 } 7193 7194 start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode); 7195 7196 IA_CSS_LEAVE_ERR_PRIVATE(err); 7197 return err; 7198 } 7199 7200 static int 7201 sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) 7202 { 7203 int err = 0; 7204 7205 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7206 7207 if (!pipe) { 7208 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7209 return -EINVAL; 7210 } 7211 /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/ 7212 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) { 7213 IA_CSS_LEAVE_ERR_PRIVATE(0); 7214 return 0; 7215 } 7216 7217 switch (pipe->mode) { 7218 case IA_CSS_PIPE_ID_PREVIEW: 7219 err = unload_preview_binaries(pipe); 7220 break; 7221 case IA_CSS_PIPE_ID_VIDEO: 7222 err = unload_video_binaries(pipe); 7223 break; 7224 case IA_CSS_PIPE_ID_CAPTURE: 7225 err = unload_capture_binaries(pipe); 7226 break; 7227 case IA_CSS_PIPE_ID_YUVPP: 7228 err = unload_yuvpp_binaries(pipe); 7229 break; 7230 default: 7231 break; 7232 } 7233 IA_CSS_LEAVE_ERR_PRIVATE(err); 7234 return err; 7235 } 7236 7237 static int 7238 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) 7239 { 7240 int err = 0; 7241 7242 assert(pipe); 7243 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n"); 7244 7245 /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/ 7246 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) 7247 return err; 7248 7249 switch (pipe->mode) { 7250 case IA_CSS_PIPE_ID_PREVIEW: 7251 err = load_preview_binaries(pipe); 7252 break; 7253 case IA_CSS_PIPE_ID_VIDEO: 7254 err = load_video_binaries(pipe); 7255 break; 7256 case IA_CSS_PIPE_ID_CAPTURE: 7257 err = load_capture_binaries(pipe); 7258 break; 7259 case IA_CSS_PIPE_ID_YUVPP: 7260 err = load_yuvpp_binaries(pipe); 7261 break; 7262 case IA_CSS_PIPE_ID_ACC: 7263 break; 7264 default: 7265 err = -EINVAL; 7266 break; 7267 } 7268 if (err) { 7269 if (sh_css_pipe_unload_binaries(pipe)) { 7270 /* currently css does not support multiple error returns in a single function, 7271 * using -EINVAL in this case */ 7272 err = -EINVAL; 7273 } 7274 } 7275 return err; 7276 } 7277 7278 static int 7279 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) 7280 { 7281 struct ia_css_pipeline *me; 7282 int err = 0; 7283 struct ia_css_pipeline_stage *vf_pp_stage = NULL, 7284 *copy_stage = NULL, 7285 *yuv_scaler_stage = NULL; 7286 struct ia_css_binary *copy_binary, 7287 *vf_pp_binary, 7288 *yuv_scaler_binary; 7289 bool need_scaler = false; 7290 unsigned int num_stage, num_output_stage; 7291 unsigned int i, j; 7292 7293 struct ia_css_frame *in_frame = NULL; 7294 struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 7295 struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 7296 struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; 7297 struct ia_css_pipeline_stage_desc stage_desc; 7298 bool need_in_frameinfo_memory = false; 7299 #ifdef ISP2401 7300 bool sensor = false; 7301 bool buffered_sensor = false; 7302 bool online = false; 7303 bool continuous = false; 7304 #endif 7305 7306 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7307 if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { 7308 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7309 return -EINVAL; 7310 } 7311 me = &pipe->pipeline; 7312 ia_css_pipeline_clean(me); 7313 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 7314 out_frame[i] = NULL; 7315 vf_frame[i] = NULL; 7316 } 7317 ia_css_pipe_util_create_output_frames(bin_out_frame); 7318 num_stage = pipe->pipe_settings.yuvpp.num_yuv_scaler; 7319 num_output_stage = pipe->pipe_settings.yuvpp.num_output; 7320 7321 #ifdef ISP2401 7322 /* When the input system is 2401, always enable 'in_frameinfo_memory' 7323 * except for the following: 7324 * - Direct Sensor Mode Online Capture 7325 * - Direct Sensor Mode Continuous Capture 7326 * - Buffered Sensor Mode Continuous Capture 7327 */ 7328 sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR; 7329 buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR; 7330 online = pipe->stream->config.online; 7331 continuous = pipe->stream->config.continuous; 7332 need_in_frameinfo_memory = 7333 !((sensor && (online || continuous)) || (buffered_sensor && continuous)); 7334 #else 7335 /* Construct in_frame info (only in case we have dynamic input */ 7336 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 7337 #endif 7338 /* the input frame can come from: 7339 * a) memory: connect yuvscaler to me->in_frame 7340 * b) sensor, via copy binary: connect yuvscaler to copy binary later on */ 7341 if (need_in_frameinfo_memory) { 7342 /* TODO: improve for different input formats. */ 7343 7344 /* 7345 * "pipe->stream->config.input_config.format" represents the sensor output 7346 * frame format, e.g. YUV422 8-bit. 7347 * 7348 * "in_frame_format" represents the imaging pipe's input frame format, e.g. 7349 * Bayer-Quad RAW. 7350 */ 7351 int in_frame_format; 7352 7353 if (pipe->stream->config.input_config.format == 7354 ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) { 7355 in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8; 7356 } else if (pipe->stream->config.input_config.format == 7357 ATOMISP_INPUT_FORMAT_YUV422_8) { 7358 /* 7359 * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8", 7360 * the "isp_copy_var" binary is selected as the first stage in the yuvpp 7361 * pipe. 7362 * 7363 * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from 7364 * the frame buffer (at DDR) to the frame-line buffer (at VMEM). 7365 * 7366 * By now, the "isp_copy_var" binary does NOT provide a separated 7367 * frame-line buffer to store the YUV422-8 pixels. Instead, it stores 7368 * the YUV422-8 pixels in the frame-line buffer which is designed to 7369 * store the Bayer-Quad RAW pixels. 7370 * 7371 * To direct the "isp_copy_var" binary reading from the RAW frame-line 7372 * buffer, its input frame format must be specified as "IA_CSS_FRAME_ 7373 * FORMAT_RAW". 7374 */ 7375 in_frame_format = IA_CSS_FRAME_FORMAT_RAW; 7376 } else { 7377 in_frame_format = IA_CSS_FRAME_FORMAT_NV12; 7378 } 7379 7380 err = init_in_frameinfo_memory_defaults(pipe, 7381 &me->in_frame, 7382 in_frame_format); 7383 7384 if (err) { 7385 IA_CSS_LEAVE_ERR_PRIVATE(err); 7386 return err; 7387 } 7388 7389 in_frame = &me->in_frame; 7390 } else { 7391 in_frame = NULL; 7392 } 7393 7394 for (i = 0; i < num_output_stage; i++) { 7395 assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE); 7396 if (pipe->output_info[i].res.width != 0) { 7397 err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i); 7398 if (err) { 7399 IA_CSS_LEAVE_ERR_PRIVATE(err); 7400 return err; 7401 } 7402 out_frame[i] = &me->out_frame[i]; 7403 } 7404 7405 /* Construct vf_frame info (only in case we have VF) */ 7406 if (pipe->vf_output_info[i].res.width != 0) { 7407 err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i); 7408 if (err) { 7409 IA_CSS_LEAVE_ERR_PRIVATE(err); 7410 return err; 7411 } 7412 vf_frame[i] = &me->vf_frame[i]; 7413 } 7414 } 7415 7416 copy_binary = &pipe->pipe_settings.yuvpp.copy_binary; 7417 vf_pp_binary = pipe->pipe_settings.yuvpp.vf_pp_binary; 7418 yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary; 7419 need_scaler = need_yuv_scaler_stage(pipe); 7420 7421 if (pipe->pipe_settings.yuvpp.copy_binary.info) { 7422 struct ia_css_frame *in_frame_local = NULL; 7423 7424 #ifdef ISP2401 7425 /* After isp copy is enabled in_frame needs to be passed. */ 7426 if (!online) 7427 in_frame_local = in_frame; 7428 #endif 7429 7430 if (need_scaler) { 7431 ia_css_pipe_util_set_output_frames(bin_out_frame, 7432 0, NULL); 7433 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7434 copy_binary, 7435 bin_out_frame, 7436 in_frame_local, 7437 NULL); 7438 } else { 7439 ia_css_pipe_util_set_output_frames(bin_out_frame, 7440 0, out_frame[0]); 7441 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7442 copy_binary, 7443 bin_out_frame, 7444 in_frame_local, 7445 NULL); 7446 } 7447 7448 err = ia_css_pipeline_create_and_add_stage(me, 7449 &stage_desc, 7450 ©_stage); 7451 7452 if (err) { 7453 IA_CSS_LEAVE_ERR_PRIVATE(err); 7454 return err; 7455 } 7456 7457 if (copy_stage) { 7458 /* if we use yuv scaler binary, vf output should be from there */ 7459 copy_stage->args.copy_vf = !need_scaler; 7460 /* for yuvpp pipe, it should always be enabled */ 7461 copy_stage->args.copy_output = true; 7462 /* connect output of copy binary to input of yuv scaler */ 7463 in_frame = copy_stage->args.out_frame[0]; 7464 } 7465 } 7466 7467 if (need_scaler) { 7468 struct ia_css_frame *tmp_out_frame = NULL; 7469 struct ia_css_frame *tmp_vf_frame = NULL; 7470 struct ia_css_frame *tmp_in_frame = in_frame; 7471 7472 for (i = 0, j = 0; i < num_stage; i++) { 7473 assert(j < num_output_stage); 7474 if (pipe->pipe_settings.yuvpp.is_output_stage[i]) { 7475 tmp_out_frame = out_frame[j]; 7476 tmp_vf_frame = vf_frame[j]; 7477 } else { 7478 tmp_out_frame = NULL; 7479 tmp_vf_frame = NULL; 7480 } 7481 7482 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 7483 tmp_out_frame, 7484 NULL, 7485 &yuv_scaler_binary[i], 7486 &yuv_scaler_stage); 7487 7488 if (err) { 7489 IA_CSS_LEAVE_ERR_PRIVATE(err); 7490 return err; 7491 } 7492 /* we use output port 1 as internal output port */ 7493 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 7494 if (pipe->pipe_settings.yuvpp.is_output_stage[i]) { 7495 if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) { 7496 in_frame = yuv_scaler_stage->args.out_vf_frame; 7497 err = add_vf_pp_stage(pipe, in_frame, 7498 tmp_vf_frame, 7499 &vf_pp_binary[j], 7500 &vf_pp_stage); 7501 7502 if (err) { 7503 IA_CSS_LEAVE_ERR_PRIVATE(err); 7504 return err; 7505 } 7506 } 7507 j++; 7508 } 7509 } 7510 } else if (copy_stage) { 7511 if (vf_frame[0] && vf_frame[0]->info.res.width != 0) { 7512 in_frame = copy_stage->args.out_vf_frame; 7513 err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], 7514 &vf_pp_binary[0], &vf_pp_stage); 7515 } 7516 if (err) { 7517 IA_CSS_LEAVE_ERR_PRIVATE(err); 7518 return err; 7519 } 7520 } 7521 7522 ia_css_pipeline_finalize_stages(&pipe->pipeline, 7523 pipe->stream->config.continuous); 7524 7525 IA_CSS_LEAVE_ERR_PRIVATE(0); 7526 7527 return 0; 7528 } 7529 7530 static int 7531 create_host_copy_pipeline(struct ia_css_pipe *pipe, 7532 unsigned int max_input_width, 7533 struct ia_css_frame *out_frame) 7534 { 7535 struct ia_css_pipeline *me; 7536 int err = 0; 7537 struct ia_css_pipeline_stage_desc stage_desc; 7538 7539 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7540 "create_host_copy_pipeline() enter:\n"); 7541 7542 /* pipeline already created as part of create_host_pipeline_structure */ 7543 me = &pipe->pipeline; 7544 ia_css_pipeline_clean(me); 7545 7546 /* Construct out_frame info */ 7547 out_frame->contiguous = false; 7548 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 7549 7550 if (copy_on_sp(pipe) && 7551 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 7552 ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1, 7553 IA_CSS_FRAME_FORMAT_BINARY_8, 0); 7554 } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) { 7555 out_frame->info.raw_bit_depth = 7556 ia_css_pipe_util_pipe_input_format_bpp(pipe); 7557 } 7558 7559 me->num_stages = 1; 7560 me->pipe_id = IA_CSS_PIPE_ID_COPY; 7561 pipe->mode = IA_CSS_PIPE_ID_COPY; 7562 7563 ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, 7564 IA_CSS_PIPELINE_RAW_COPY, 7565 max_input_width); 7566 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL); 7567 7568 ia_css_pipeline_finalize_stages(&pipe->pipeline, 7569 pipe->stream->config.continuous); 7570 7571 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7572 "create_host_copy_pipeline() leave:\n"); 7573 7574 return err; 7575 } 7576 7577 static int 7578 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) 7579 { 7580 struct ia_css_pipeline *me = &pipe->pipeline; 7581 int err = 0; 7582 struct ia_css_pipeline_stage_desc stage_desc; 7583 struct ia_css_frame *out_frame = &me->out_frame[0]; 7584 struct ia_css_pipeline_stage *out_stage = NULL; 7585 unsigned int thread_id; 7586 enum sh_css_queue_id queue_id; 7587 unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS; 7588 7589 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7590 "create_host_isyscopy_capture_pipeline() enter:\n"); 7591 ia_css_pipeline_clean(me); 7592 7593 /* Construct out_frame info */ 7594 err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0); 7595 if (err) 7596 return err; 7597 out_frame->contiguous = false; 7598 out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; 7599 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 7600 ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id); 7601 out_frame->dynamic_queue_id = queue_id; 7602 out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME; 7603 7604 me->num_stages = 1; 7605 me->pipe_id = IA_CSS_PIPE_ID_CAPTURE; 7606 pipe->mode = IA_CSS_PIPE_ID_CAPTURE; 7607 ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, 7608 IA_CSS_PIPELINE_ISYS_COPY, 7609 max_input_width); 7610 err = ia_css_pipeline_create_and_add_stage(me, 7611 &stage_desc, &out_stage); 7612 if (err) 7613 return err; 7614 7615 ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous); 7616 7617 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7618 "create_host_isyscopy_capture_pipeline() leave:\n"); 7619 7620 return err; 7621 } 7622 7623 static int 7624 create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) 7625 { 7626 struct ia_css_pipeline *me; 7627 int err = 0; 7628 enum ia_css_capture_mode mode; 7629 struct ia_css_pipeline_stage *current_stage = NULL; 7630 struct ia_css_pipeline_stage *yuv_scaler_stage = NULL; 7631 struct ia_css_binary *copy_binary, 7632 *primary_binary[MAX_NUM_PRIMARY_STAGES], 7633 *vf_pp_binary, 7634 *pre_isp_binary, 7635 *anr_gdc_binary, 7636 *post_isp_binary, 7637 *yuv_scaler_binary, 7638 *capture_pp_binary, 7639 *capture_ldc_binary; 7640 bool need_pp = false; 7641 bool raw; 7642 7643 struct ia_css_frame *in_frame; 7644 struct ia_css_frame *out_frame; 7645 struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; 7646 struct ia_css_frame *vf_frame; 7647 struct ia_css_pipeline_stage_desc stage_desc; 7648 bool need_in_frameinfo_memory = false; 7649 #ifdef ISP2401 7650 bool sensor = false; 7651 bool buffered_sensor = false; 7652 bool online = false; 7653 bool continuous = false; 7654 #endif 7655 unsigned int i, num_yuv_scaler, num_primary_stage; 7656 bool need_yuv_pp = false; 7657 bool *is_output_stage = NULL; 7658 bool need_ldc = false; 7659 7660 IA_CSS_ENTER_PRIVATE(""); 7661 assert(pipe); 7662 assert(pipe->stream); 7663 assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || 7664 pipe->mode == IA_CSS_PIPE_ID_COPY); 7665 7666 me = &pipe->pipeline; 7667 mode = pipe->config.default_capture_config.mode; 7668 raw = (mode == IA_CSS_CAPTURE_MODE_RAW); 7669 ia_css_pipeline_clean(me); 7670 ia_css_pipe_util_create_output_frames(out_frames); 7671 7672 #ifdef ISP2401 7673 /* When the input system is 2401, always enable 'in_frameinfo_memory' 7674 * except for the following: 7675 * - Direct Sensor Mode Online Capture 7676 * - Direct Sensor Mode Online Capture 7677 * - Direct Sensor Mode Continuous Capture 7678 * - Buffered Sensor Mode Continuous Capture 7679 */ 7680 sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR); 7681 buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 7682 online = pipe->stream->config.online; 7683 continuous = pipe->stream->config.continuous; 7684 need_in_frameinfo_memory = 7685 !((sensor && (online || continuous)) || (buffered_sensor && (online || continuous))); 7686 #else 7687 /* Construct in_frame info (only in case we have dynamic input */ 7688 need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 7689 #endif 7690 if (need_in_frameinfo_memory) { 7691 err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, 7692 IA_CSS_FRAME_FORMAT_RAW); 7693 if (err) { 7694 IA_CSS_LEAVE_ERR_PRIVATE(err); 7695 return err; 7696 } 7697 7698 in_frame = &me->in_frame; 7699 } else { 7700 in_frame = NULL; 7701 } 7702 7703 err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0); 7704 if (err) { 7705 IA_CSS_LEAVE_ERR_PRIVATE(err); 7706 return err; 7707 } 7708 out_frame = &me->out_frame[0]; 7709 7710 /* Construct vf_frame info (only in case we have VF) */ 7711 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { 7712 if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) { 7713 /* These modes don't support viewfinder output */ 7714 vf_frame = NULL; 7715 } else { 7716 init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0); 7717 vf_frame = &me->vf_frame[0]; 7718 } 7719 } else { 7720 vf_frame = NULL; 7721 } 7722 7723 copy_binary = &pipe->pipe_settings.capture.copy_binary; 7724 num_primary_stage = pipe->pipe_settings.capture.num_primary_stage; 7725 if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) { 7726 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 7727 return -EINVAL; 7728 } 7729 7730 for (i = 0; i < num_primary_stage; i++) 7731 primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i]; 7732 7733 vf_pp_binary = &pipe->pipe_settings.capture.vf_pp_binary; 7734 pre_isp_binary = &pipe->pipe_settings.capture.pre_isp_binary; 7735 anr_gdc_binary = &pipe->pipe_settings.capture.anr_gdc_binary; 7736 post_isp_binary = &pipe->pipe_settings.capture.post_isp_binary; 7737 capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary; 7738 yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary; 7739 num_yuv_scaler = pipe->pipe_settings.capture.num_yuv_scaler; 7740 is_output_stage = pipe->pipe_settings.capture.is_output_stage; 7741 capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary; 7742 7743 need_pp = (need_capture_pp(pipe) || pipe->output_stage) && 7744 mode != IA_CSS_CAPTURE_MODE_RAW && 7745 mode != IA_CSS_CAPTURE_MODE_BAYER; 7746 need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info); 7747 need_ldc = (capture_ldc_binary && capture_ldc_binary->info); 7748 7749 if (pipe->pipe_settings.capture.copy_binary.info) { 7750 if (raw) { 7751 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 7752 #if defined(ISP2401) 7753 if (!continuous) { 7754 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7755 copy_binary, 7756 out_frames, 7757 in_frame, 7758 NULL); 7759 } else { 7760 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 7761 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7762 copy_binary, 7763 out_frames, 7764 in_frame, 7765 NULL); 7766 } 7767 #else 7768 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7769 copy_binary, 7770 out_frames, 7771 NULL, NULL); 7772 #endif 7773 } else { 7774 ia_css_pipe_util_set_output_frames(out_frames, 0, 7775 in_frame); 7776 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7777 copy_binary, 7778 out_frames, 7779 NULL, NULL); 7780 } 7781 7782 err = ia_css_pipeline_create_and_add_stage(me, 7783 &stage_desc, 7784 ¤t_stage); 7785 if (err) { 7786 IA_CSS_LEAVE_ERR_PRIVATE(err); 7787 return err; 7788 } 7789 } else if (pipe->stream->config.continuous) { 7790 in_frame = pipe->stream->last_pipe->continuous_frames[0]; 7791 } 7792 7793 if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 7794 struct ia_css_frame *local_in_frame = NULL; 7795 struct ia_css_frame *local_out_frame = NULL; 7796 7797 for (i = 0; i < num_primary_stage; i++) { 7798 if (i == 0) 7799 local_in_frame = in_frame; 7800 else 7801 local_in_frame = NULL; 7802 #ifndef ISP2401 7803 if (!need_pp && (i == num_primary_stage - 1)) 7804 #else 7805 if (!need_pp && (i == num_primary_stage - 1) && !need_ldc) 7806 #endif 7807 local_out_frame = out_frame; 7808 else 7809 local_out_frame = NULL; 7810 ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame); 7811 /* 7812 * WARNING: The #if def flag has been added below as a 7813 * temporary solution to solve the problem of enabling the 7814 * view finder in a single binary in a capture flow. The 7815 * vf-pp stage has been removed from Skycam in the solution 7816 * provided. The vf-pp stage should be re-introduced when 7817 * required. This * should not be considered as a clean solution. 7818 * Proper investigation should be done to come up with the clean 7819 * solution. 7820 * */ 7821 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7822 primary_binary[i], 7823 out_frames, 7824 local_in_frame, 7825 NULL); 7826 err = ia_css_pipeline_create_and_add_stage(me, 7827 &stage_desc, 7828 ¤t_stage); 7829 if (err) { 7830 IA_CSS_LEAVE_ERR_PRIVATE(err); 7831 return err; 7832 } 7833 } 7834 /* If we use copy iso primary, 7835 the input must be yuv iso raw */ 7836 current_stage->args.copy_vf = 7837 primary_binary[0]->info->sp.pipeline.mode == 7838 IA_CSS_BINARY_MODE_COPY; 7839 current_stage->args.copy_output = current_stage->args.copy_vf; 7840 } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED || 7841 mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 7842 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7843 ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, 7844 out_frames, in_frame, NULL); 7845 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7846 NULL); 7847 if (err) { 7848 IA_CSS_LEAVE_ERR_PRIVATE(err); 7849 return err; 7850 } 7851 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7852 ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary, 7853 out_frames, NULL, NULL); 7854 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7855 NULL); 7856 if (err) { 7857 IA_CSS_LEAVE_ERR_PRIVATE(err); 7858 return err; 7859 } 7860 7861 if (need_pp) { 7862 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7863 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7864 post_isp_binary, 7865 out_frames, 7866 NULL, NULL); 7867 } else { 7868 ia_css_pipe_util_set_output_frames(out_frames, 0, 7869 out_frame); 7870 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7871 post_isp_binary, 7872 out_frames, 7873 NULL, NULL); 7874 } 7875 7876 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7877 ¤t_stage); 7878 if (err) { 7879 IA_CSS_LEAVE_ERR_PRIVATE(err); 7880 return err; 7881 } 7882 } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) { 7883 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 7884 ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, 7885 out_frames, in_frame, NULL); 7886 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7887 NULL); 7888 if (err) { 7889 IA_CSS_LEAVE_ERR_PRIVATE(err); 7890 return err; 7891 } 7892 } 7893 7894 #ifndef ISP2401 7895 if (need_pp && current_stage) { 7896 struct ia_css_frame *local_in_frame = NULL; 7897 7898 local_in_frame = current_stage->args.out_frame[0]; 7899 7900 if (need_ldc) { 7901 ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); 7902 ia_css_pipe_get_generic_stage_desc(&stage_desc, 7903 capture_ldc_binary, 7904 out_frames, 7905 local_in_frame, 7906 NULL); 7907 err = ia_css_pipeline_create_and_add_stage(me, 7908 &stage_desc, 7909 ¤t_stage); 7910 local_in_frame = current_stage->args.out_frame[0]; 7911 } 7912 err = add_capture_pp_stage(pipe, me, local_in_frame, 7913 need_yuv_pp ? NULL : out_frame, 7914 #else 7915 /* ldc and capture_pp not supported in same pipeline */ 7916 if (need_ldc && current_stage) { 7917 in_frame = current_stage->args.out_frame[0]; 7918 ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); 7919 ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary, 7920 out_frames, in_frame, NULL); 7921 err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, 7922 NULL); 7923 } else if (need_pp && current_stage) { 7924 in_frame = current_stage->args.out_frame[0]; 7925 err = add_capture_pp_stage(pipe, me, in_frame, 7926 need_yuv_pp ? NULL : out_frame, 7927 #endif 7928 capture_pp_binary, 7929 ¤t_stage); 7930 if (err) { 7931 IA_CSS_LEAVE_ERR_PRIVATE(err); 7932 return err; 7933 } 7934 } 7935 7936 if (need_yuv_pp && current_stage) { 7937 struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0]; 7938 struct ia_css_frame *tmp_out_frame = NULL; 7939 7940 for (i = 0; i < num_yuv_scaler; i++) { 7941 if (is_output_stage[i]) 7942 tmp_out_frame = out_frame; 7943 else 7944 tmp_out_frame = NULL; 7945 7946 err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, 7947 tmp_out_frame, NULL, 7948 &yuv_scaler_binary[i], 7949 &yuv_scaler_stage); 7950 if (err) { 7951 IA_CSS_LEAVE_ERR_PRIVATE(err); 7952 return err; 7953 } 7954 /* we use output port 1 as internal output port */ 7955 tmp_in_frame = yuv_scaler_stage->args.out_frame[1]; 7956 } 7957 } 7958 7959 /* 7960 * WARNING: The #if def flag has been added below as a 7961 * temporary solution to solve the problem of enabling the 7962 * view finder in a single binary in a capture flow. The vf-pp 7963 * stage has been removed from Skycam in the solution provided. 7964 * The vf-pp stage should be re-introduced when required. This 7965 * should not be considered as a clean solution. Proper 7966 * investigation should be done to come up with the clean solution. 7967 * */ 7968 if (mode != IA_CSS_CAPTURE_MODE_RAW && 7969 mode != IA_CSS_CAPTURE_MODE_BAYER && 7970 current_stage && vf_frame) { 7971 in_frame = current_stage->args.out_vf_frame; 7972 err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary, 7973 ¤t_stage); 7974 if (err) { 7975 IA_CSS_LEAVE_ERR_PRIVATE(err); 7976 return err; 7977 } 7978 } 7979 ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); 7980 7981 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 7982 "create_host_regular_capture_pipeline() leave:\n"); 7983 7984 return 0; 7985 } 7986 7987 static int 7988 create_host_capture_pipeline(struct ia_css_pipe *pipe) 7989 { 7990 int err = 0; 7991 7992 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 7993 7994 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) 7995 err = create_host_isyscopy_capture_pipeline(pipe); 7996 else 7997 err = create_host_regular_capture_pipeline(pipe); 7998 if (err) { 7999 IA_CSS_LEAVE_ERR_PRIVATE(err); 8000 return err; 8001 } 8002 8003 IA_CSS_LEAVE_ERR_PRIVATE(err); 8004 8005 return err; 8006 } 8007 8008 static int capture_start(struct ia_css_pipe *pipe) 8009 { 8010 struct ia_css_pipeline *me; 8011 8012 int err = 0; 8013 enum sh_css_pipe_config_override copy_ovrd; 8014 8015 IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); 8016 if (!pipe) { 8017 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8018 return -EINVAL; 8019 } 8020 8021 me = &pipe->pipeline; 8022 8023 if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW || 8024 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) && 8025 (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) { 8026 if (copy_on_sp(pipe)) { 8027 err = start_copy_on_sp(pipe, &me->out_frame[0]); 8028 IA_CSS_LEAVE_ERR_PRIVATE(err); 8029 return err; 8030 } 8031 } 8032 8033 #if !defined(ISP2401) 8034 /* old isys: need to send_mipi_frames() in all pipe modes */ 8035 err = send_mipi_frames(pipe); 8036 if (err) { 8037 IA_CSS_LEAVE_ERR_PRIVATE(err); 8038 return err; 8039 } 8040 #elif defined(ISP2401) 8041 if (pipe->config.mode != IA_CSS_PIPE_MODE_COPY) { 8042 err = send_mipi_frames(pipe); 8043 if (err) { 8044 IA_CSS_LEAVE_ERR_PRIVATE(err); 8045 return err; 8046 } 8047 } 8048 8049 #endif 8050 8051 { 8052 unsigned int thread_id; 8053 8054 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 8055 copy_ovrd = 1 << thread_id; 8056 } 8057 start_pipe(pipe, copy_ovrd, pipe->stream->config.mode); 8058 8059 #if !defined(ISP2401) 8060 /* 8061 * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured, 8062 * which is currently done in start_binary(); but COPY pipe contains no binary, 8063 * and does not call start_binary(); so we need to configure the rx here. 8064 */ 8065 if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY && 8066 pipe->stream->reconfigure_css_rx) { 8067 ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, 8068 pipe->stream->config.mode); 8069 pipe->stream->reconfigure_css_rx = false; 8070 } 8071 #endif 8072 8073 IA_CSS_LEAVE_ERR_PRIVATE(err); 8074 return err; 8075 } 8076 8077 static int 8078 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, 8079 struct ia_css_frame_info *info, 8080 unsigned int idx) 8081 { 8082 assert(pipe); 8083 assert(info); 8084 8085 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 8086 "sh_css_pipe_get_output_frame_info() enter:\n"); 8087 8088 *info = pipe->output_info[idx]; 8089 if (copy_on_sp(pipe) && 8090 pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { 8091 ia_css_frame_info_init( 8092 info, 8093 JPEG_BYTES, 8094 1, 8095 IA_CSS_FRAME_FORMAT_BINARY_8, 8096 0); 8097 } else if (info->format == IA_CSS_FRAME_FORMAT_RAW || 8098 info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) { 8099 info->raw_bit_depth = 8100 ia_css_pipe_util_pipe_input_format_bpp(pipe); 8101 } 8102 8103 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 8104 "sh_css_pipe_get_output_frame_info() leave:\n"); 8105 return 0; 8106 } 8107 8108 void 8109 ia_css_stream_send_input_frame(const struct ia_css_stream *stream, 8110 const unsigned short *data, 8111 unsigned int width, 8112 unsigned int height) 8113 { 8114 assert(stream); 8115 8116 ia_css_inputfifo_send_input_frame( 8117 data, width, height, 8118 stream->config.channel_id, 8119 stream->config.input_config.format, 8120 stream->config.pixels_per_clock == 2); 8121 } 8122 8123 void 8124 ia_css_stream_start_input_frame(const struct ia_css_stream *stream) 8125 { 8126 assert(stream); 8127 8128 ia_css_inputfifo_start_frame( 8129 stream->config.channel_id, 8130 stream->config.input_config.format, 8131 stream->config.pixels_per_clock == 2); 8132 } 8133 8134 void 8135 ia_css_stream_send_input_line(const struct ia_css_stream *stream, 8136 const unsigned short *data, 8137 unsigned int width, 8138 const unsigned short *data2, 8139 unsigned int width2) 8140 { 8141 assert(stream); 8142 8143 ia_css_inputfifo_send_line(stream->config.channel_id, 8144 data, width, data2, width2); 8145 } 8146 8147 void 8148 ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream, 8149 enum atomisp_input_format format, 8150 const unsigned short *data, 8151 unsigned int width) 8152 { 8153 assert(stream); 8154 if (!data || width == 0) 8155 return; 8156 ia_css_inputfifo_send_embedded_line(stream->config.channel_id, 8157 format, data, width); 8158 } 8159 8160 void 8161 ia_css_stream_end_input_frame(const struct ia_css_stream *stream) 8162 { 8163 assert(stream); 8164 8165 ia_css_inputfifo_end_frame(stream->config.channel_id); 8166 } 8167 8168 static void 8169 append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) 8170 { 8171 IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware); 8172 if (!l) { 8173 IA_CSS_ERROR("NULL fw_info"); 8174 IA_CSS_LEAVE_PRIVATE(""); 8175 return; 8176 } 8177 while (*l) 8178 l = &(*l)->next; 8179 *l = firmware; 8180 /*firmware->next = NULL;*/ /* when multiple acc extensions are loaded, 'next' can be not NULL */ 8181 IA_CSS_LEAVE_PRIVATE(""); 8182 } 8183 8184 static void 8185 remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) 8186 { 8187 assert(*l); 8188 assert(firmware); 8189 (void)l; 8190 (void)firmware; 8191 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n"); 8192 8193 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n"); 8194 return; /* removing single and multiple firmware is handled in acc_unload_extension() */ 8195 } 8196 8197 static int upload_isp_code(struct ia_css_fw_info *firmware) 8198 { 8199 ia_css_ptr binary; 8200 8201 if (!firmware) { 8202 IA_CSS_ERROR("NULL input parameter"); 8203 return -EINVAL; 8204 } 8205 binary = firmware->info.isp.xmem_addr; 8206 8207 if (!binary) { 8208 unsigned int size = firmware->blob.size; 8209 const unsigned char *blob; 8210 const unsigned char *binary_name; 8211 8212 binary_name = 8213 (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME( 8214 firmware)); 8215 blob = binary_name + 8216 strlen((const char *)binary_name) + 8217 1; 8218 binary = sh_css_load_blob(blob, size); 8219 firmware->info.isp.xmem_addr = binary; 8220 } 8221 8222 if (!binary) 8223 return -ENOMEM; 8224 return 0; 8225 } 8226 8227 static int 8228 acc_load_extension(struct ia_css_fw_info *firmware) 8229 { 8230 int err; 8231 struct ia_css_fw_info *hd = firmware; 8232 8233 while (hd) { 8234 err = upload_isp_code(hd); 8235 if (err) 8236 return err; 8237 hd = hd->next; 8238 } 8239 8240 if (!firmware) 8241 return -EINVAL; 8242 firmware->loaded = true; 8243 return 0; 8244 } 8245 8246 static void 8247 acc_unload_extension(struct ia_css_fw_info *firmware) 8248 { 8249 struct ia_css_fw_info *hd = firmware; 8250 struct ia_css_fw_info *hdn = NULL; 8251 8252 if (!firmware) /* should not happen */ 8253 return; 8254 /* unload and remove multiple firmwares */ 8255 while (hd) { 8256 hdn = (hd->next) ? &(*hd->next) : NULL; 8257 if (hd->info.isp.xmem_addr) { 8258 hmm_free(hd->info.isp.xmem_addr); 8259 hd->info.isp.xmem_addr = mmgr_NULL; 8260 } 8261 hd->isp_code = NULL; 8262 hd->next = NULL; 8263 hd = hdn; 8264 } 8265 8266 firmware->loaded = false; 8267 } 8268 8269 /* Load firmware for extension */ 8270 static int 8271 ia_css_pipe_load_extension(struct ia_css_pipe *pipe, 8272 struct ia_css_fw_info *firmware) 8273 { 8274 int err = 0; 8275 8276 IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe); 8277 8278 if ((!firmware) || (!pipe)) { 8279 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8280 return -EINVAL; 8281 } 8282 8283 if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT) 8284 append_firmware(&pipe->output_stage, firmware); 8285 else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER) 8286 append_firmware(&pipe->vf_stage, firmware); 8287 err = acc_load_extension(firmware); 8288 8289 IA_CSS_LEAVE_ERR_PRIVATE(err); 8290 return err; 8291 } 8292 8293 /* Unload firmware for extension */ 8294 static void 8295 ia_css_pipe_unload_extension(struct ia_css_pipe *pipe, 8296 struct ia_css_fw_info *firmware) 8297 { 8298 IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe); 8299 8300 if ((!firmware) || (!pipe)) { 8301 IA_CSS_ERROR("NULL input parameters"); 8302 IA_CSS_LEAVE_PRIVATE(""); 8303 return; 8304 } 8305 8306 if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT) 8307 remove_firmware(&pipe->output_stage, firmware); 8308 else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER) 8309 remove_firmware(&pipe->vf_stage, firmware); 8310 acc_unload_extension(firmware); 8311 8312 IA_CSS_LEAVE_PRIVATE(""); 8313 } 8314 8315 bool 8316 ia_css_pipeline_uses_params(struct ia_css_pipeline *me) 8317 { 8318 struct ia_css_pipeline_stage *stage; 8319 8320 assert(me); 8321 8322 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8323 "ia_css_pipeline_uses_params() enter: me=%p\n", me); 8324 8325 for (stage = me->stages; stage; stage = stage->next) 8326 if (stage->binary_info && stage->binary_info->enable.params) { 8327 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8328 "ia_css_pipeline_uses_params() leave: return_bool=true\n"); 8329 return true; 8330 } 8331 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8332 "ia_css_pipeline_uses_params() leave: return_bool=false\n"); 8333 return false; 8334 } 8335 8336 static int 8337 sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline, 8338 const void *acc_fw) 8339 { 8340 struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw; 8341 /* In QoS case, load_extension already called, so skipping */ 8342 int err = 0; 8343 8344 if (!fw->loaded) 8345 err = acc_load_extension(fw); 8346 8347 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8348 "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n", 8349 pipeline, acc_fw); 8350 8351 if (!err) { 8352 struct ia_css_pipeline_stage_desc stage_desc; 8353 8354 ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw); 8355 err = ia_css_pipeline_create_and_add_stage(pipeline, 8356 &stage_desc, 8357 NULL); 8358 } 8359 8360 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8361 "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err); 8362 return err; 8363 } 8364 8365 /* 8366 * @brief Tag a specific frame in continuous capture. 8367 * Refer to "sh_css_internal.h" for details. 8368 */ 8369 int ia_css_stream_capture_frame(struct ia_css_stream *stream, 8370 unsigned int exp_id) 8371 { 8372 struct sh_css_tag_descr tag_descr; 8373 u32 encoded_tag_descr; 8374 int err; 8375 8376 assert(stream); 8377 IA_CSS_ENTER("exp_id=%d", exp_id); 8378 8379 /* Only continuous streams have a tagger */ 8380 if (exp_id == 0 || !stream->config.continuous) { 8381 IA_CSS_LEAVE_ERR(-EINVAL); 8382 return -EINVAL; 8383 } 8384 8385 if (!sh_css_sp_is_running()) { 8386 /* SP is not running. The queues are not valid */ 8387 IA_CSS_LEAVE_ERR(-EBUSY); 8388 return -EBUSY; 8389 } 8390 8391 /* Create the tag descriptor from the parameters */ 8392 sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr); 8393 /* Encode the tag descriptor into a 32-bit value */ 8394 encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr); 8395 /* Enqueue the encoded tag to the host2sp queue. 8396 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0 8397 * on both host and the SP side. 8398 * It is mainly because it is enough to have only one tag_cmd queue */ 8399 err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr); 8400 8401 IA_CSS_LEAVE_ERR(err); 8402 return err; 8403 } 8404 8405 /* 8406 * @brief Configure the continuous capture. 8407 * Refer to "sh_css_internal.h" for details. 8408 */ 8409 int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures, 8410 unsigned int skip, int offset) 8411 { 8412 struct sh_css_tag_descr tag_descr; 8413 unsigned int encoded_tag_descr; 8414 int return_err; 8415 8416 if (!stream) 8417 return -EINVAL; 8418 8419 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8420 "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n", 8421 num_captures, skip, offset); 8422 8423 /* Check if the tag descriptor is valid */ 8424 if (num_captures < SH_CSS_MINIMUM_TAG_ID) { 8425 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8426 "ia_css_stream_capture() leave: return_err=%d\n", 8427 -EINVAL); 8428 return -EINVAL; 8429 } 8430 8431 /* Create the tag descriptor from the parameters */ 8432 sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr); 8433 8434 /* Encode the tag descriptor into a 32-bit value */ 8435 encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr); 8436 8437 if (!sh_css_sp_is_running()) { 8438 /* SP is not running. The queues are not valid */ 8439 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8440 "ia_css_stream_capture() leaving:queues unavailable\n"); 8441 return -EBUSY; 8442 } 8443 8444 /* Enqueue the encoded tag to the host2sp queue. 8445 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0 8446 * on both host and the SP side. 8447 * It is mainly because it is enough to have only one tag_cmd queue */ 8448 return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr); 8449 8450 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8451 "ia_css_stream_capture() leave: return_err=%d\n", 8452 return_err); 8453 8454 return return_err; 8455 } 8456 8457 void ia_css_stream_request_flash(struct ia_css_stream *stream) 8458 { 8459 (void)stream; 8460 8461 assert(stream); 8462 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8463 "ia_css_stream_request_flash() enter: void\n"); 8464 8465 #ifndef ISP2401 8466 sh_css_write_host2sp_command(host2sp_cmd_start_flash); 8467 #else 8468 if (sh_css_sp_is_running()) { 8469 if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) { 8470 IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); 8471 ia_css_debug_dump_sp_sw_debug_info(); 8472 ia_css_debug_dump_debug_info(NULL); 8473 } 8474 } else { 8475 IA_CSS_LOG("SP is not running!"); 8476 } 8477 8478 #endif 8479 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8480 "ia_css_stream_request_flash() leave: return_void\n"); 8481 } 8482 8483 static void 8484 sh_css_init_host_sp_control_vars(void) 8485 { 8486 const struct ia_css_fw_info *fw; 8487 unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started; 8488 8489 unsigned int HIVE_ADDR_host_sp_queues_initialized; 8490 unsigned int HIVE_ADDR_sp_sleep_mode; 8491 unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb; 8492 #ifndef ISP2401 8493 unsigned int HIVE_ADDR_sp_stop_copy_preview; 8494 #endif 8495 unsigned int HIVE_ADDR_host_sp_com; 8496 unsigned int o = offsetof(struct host_sp_communication, host2sp_command) 8497 / sizeof(int); 8498 8499 unsigned int i; 8500 8501 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 8502 "sh_css_init_host_sp_control_vars() enter: void\n"); 8503 8504 fw = &sh_css_sp_fw; 8505 HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started; 8506 8507 HIVE_ADDR_host_sp_queues_initialized = 8508 fw->info.sp.host_sp_queues_initialized; 8509 HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode; 8510 HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb; 8511 #ifndef ISP2401 8512 HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview; 8513 #endif 8514 HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com; 8515 8516 (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */ 8517 8518 (void)HIVE_ADDR_sp_sleep_mode; 8519 (void)HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb; 8520 #ifndef ISP2401 8521 (void)HIVE_ADDR_sp_stop_copy_preview; 8522 #endif 8523 (void)HIVE_ADDR_host_sp_com; 8524 8525 sp_dmem_store_uint32(SP0_ID, 8526 (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started), 8527 (uint32_t)(0)); 8528 8529 sp_dmem_store_uint32(SP0_ID, 8530 (unsigned int)sp_address_of(host_sp_queues_initialized), 8531 (uint32_t)(0)); 8532 sp_dmem_store_uint32(SP0_ID, 8533 (unsigned int)sp_address_of(sp_sleep_mode), 8534 (uint32_t)(0)); 8535 sp_dmem_store_uint32(SP0_ID, 8536 (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb), 8537 (uint32_t)(false)); 8538 #ifndef ISP2401 8539 sp_dmem_store_uint32(SP0_ID, 8540 (unsigned int)sp_address_of(sp_stop_copy_preview), 8541 my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0)); 8542 #endif 8543 store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready); 8544 8545 for (i = 0; i < N_CSI_PORTS; i++) { 8546 sh_css_update_host2sp_num_mipi_frames 8547 (my_css.num_mipi_frames[i]); 8548 } 8549 8550 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, 8551 "sh_css_init_host_sp_control_vars() leave: return_void\n"); 8552 } 8553 8554 /* 8555 * create the internal structures and fill in the configuration data 8556 */ 8557 8558 static const struct 8559 ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG; 8560 8561 void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config) 8562 { 8563 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n"); 8564 memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config)); 8565 } 8566 8567 void 8568 ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config) 8569 { 8570 if (!extra_config) { 8571 IA_CSS_ERROR("NULL input parameter"); 8572 return; 8573 } 8574 8575 extra_config->enable_raw_binning = false; 8576 extra_config->enable_yuv_ds = false; 8577 extra_config->enable_high_speed = false; 8578 extra_config->enable_dvs_6axis = false; 8579 extra_config->enable_reduced_pipe = false; 8580 extra_config->disable_vf_pp = false; 8581 extra_config->enable_fractional_ds = false; 8582 } 8583 8584 void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config) 8585 { 8586 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n"); 8587 assert(stream_config); 8588 memset(stream_config, 0, sizeof(*stream_config)); 8589 stream_config->online = true; 8590 stream_config->left_padding = -1; 8591 stream_config->pixels_per_clock = 1; 8592 /* temporary default value for backwards compatibility. 8593 * This field used to be hardcoded within CSS but this has now 8594 * been moved to the stream_config struct. */ 8595 stream_config->source.port.rxcount = 0x04040404; 8596 } 8597 8598 static int 8599 ia_css_acc_pipe_create(struct ia_css_pipe *pipe) 8600 { 8601 int err = 0; 8602 8603 if (!pipe) { 8604 IA_CSS_ERROR("NULL input parameter"); 8605 return -EINVAL; 8606 } 8607 8608 /* There is not meaning for num_execs = 0 semantically. Run atleast once. */ 8609 if (pipe->config.acc_num_execs == 0) 8610 pipe->config.acc_num_execs = 1; 8611 8612 if (pipe->config.acc_extension) 8613 err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension); 8614 8615 return err; 8616 } 8617 8618 int ia_css_pipe_create(const struct ia_css_pipe_config *config, 8619 struct ia_css_pipe **pipe) 8620 { 8621 int err = 0; 8622 8623 IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe); 8624 8625 if (!config || !pipe) { 8626 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8627 return -EINVAL; 8628 } 8629 8630 err = ia_css_pipe_create_extra(config, NULL, pipe); 8631 8632 if (err == 0) 8633 IA_CSS_LOG("pipe created successfully = %p", *pipe); 8634 8635 IA_CSS_LEAVE_ERR_PRIVATE(err); 8636 8637 return err; 8638 } 8639 8640 int 8641 ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, 8642 const struct ia_css_pipe_extra_config *extra_config, 8643 struct ia_css_pipe **pipe) 8644 { 8645 int err = -EINVAL; 8646 struct ia_css_pipe *internal_pipe = NULL; 8647 unsigned int i; 8648 8649 IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe); 8650 8651 /* do not allow to create more than the maximum limit */ 8652 if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) { 8653 IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC); 8654 return -EINVAL; 8655 } 8656 8657 if ((!pipe) || (!config)) { 8658 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8659 return -EINVAL; 8660 } 8661 8662 ia_css_debug_dump_pipe_config(config); 8663 ia_css_debug_dump_pipe_extra_config(extra_config); 8664 8665 err = create_pipe(config->mode, &internal_pipe, false); 8666 if (err) { 8667 IA_CSS_LEAVE_ERR_PRIVATE(err); 8668 return err; 8669 } 8670 8671 /* now we have a pipe structure to fill */ 8672 internal_pipe->config = *config; 8673 if (extra_config) 8674 internal_pipe->extra_config = *extra_config; 8675 else 8676 ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config); 8677 8678 if (config->mode == IA_CSS_PIPE_MODE_ACC) { 8679 /* Temporary hack to migrate acceleration to CSS 2.0. 8680 * In the future the code for all pipe types should be 8681 * unified. */ 8682 *pipe = internal_pipe; 8683 if (!internal_pipe->config.acc_extension && 8684 internal_pipe->config.num_acc_stages == 8685 0) { /* if no acc binary and no standalone stage */ 8686 *pipe = NULL; 8687 IA_CSS_LEAVE_ERR_PRIVATE(0); 8688 return 0; 8689 } 8690 return ia_css_acc_pipe_create(internal_pipe); 8691 } 8692 8693 /* Use config value when dvs_frame_delay setting equal to 2, otherwise always 1 by default */ 8694 if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2) 8695 internal_pipe->dvs_frame_delay = 2; 8696 else 8697 internal_pipe->dvs_frame_delay = 1; 8698 8699 /* we still keep enable_raw_binning for backward compatibility, for any new 8700 fractional bayer downscaling, we should use bayer_ds_out_res. if both are 8701 specified, bayer_ds_out_res will take precedence.if none is specified, we 8702 set bayer_ds_out_res equal to IF output resolution(IF may do cropping on 8703 sensor output) or use default decimation factor 1. */ 8704 if (internal_pipe->extra_config.enable_raw_binning && 8705 internal_pipe->config.bayer_ds_out_res.width) { 8706 /* fill some code here, if no code is needed, please remove it during integration */ 8707 } 8708 8709 /* YUV downscaling */ 8710 if ((internal_pipe->config.vf_pp_in_res.width || 8711 internal_pipe->config.capt_pp_in_res.width)) { 8712 enum ia_css_frame_format format; 8713 8714 if (internal_pipe->config.vf_pp_in_res.width) { 8715 format = IA_CSS_FRAME_FORMAT_YUV_LINE; 8716 ia_css_frame_info_init( 8717 &internal_pipe->vf_yuv_ds_input_info, 8718 internal_pipe->config.vf_pp_in_res.width, 8719 internal_pipe->config.vf_pp_in_res.height, 8720 format, 0); 8721 } 8722 if (internal_pipe->config.capt_pp_in_res.width) { 8723 format = IA_CSS_FRAME_FORMAT_YUV420; 8724 ia_css_frame_info_init( 8725 &internal_pipe->out_yuv_ds_input_info, 8726 internal_pipe->config.capt_pp_in_res.width, 8727 internal_pipe->config.capt_pp_in_res.height, 8728 format, 0); 8729 } 8730 } 8731 if (internal_pipe->config.vf_pp_in_res.width && 8732 internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) { 8733 ia_css_frame_info_init( 8734 &internal_pipe->vf_yuv_ds_input_info, 8735 internal_pipe->config.vf_pp_in_res.width, 8736 internal_pipe->config.vf_pp_in_res.height, 8737 IA_CSS_FRAME_FORMAT_YUV_LINE, 0); 8738 } 8739 /* handle bayer downscaling output info */ 8740 if (internal_pipe->config.bayer_ds_out_res.width) { 8741 ia_css_frame_info_init( 8742 &internal_pipe->bds_output_info, 8743 internal_pipe->config.bayer_ds_out_res.width, 8744 internal_pipe->config.bayer_ds_out_res.height, 8745 IA_CSS_FRAME_FORMAT_RAW, 0); 8746 } 8747 8748 /* handle output info, assume always needed */ 8749 for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { 8750 if (internal_pipe->config.output_info[i].res.width) { 8751 err = sh_css_pipe_configure_output( 8752 internal_pipe, 8753 internal_pipe->config.output_info[i].res.width, 8754 internal_pipe->config.output_info[i].res.height, 8755 internal_pipe->config.output_info[i].padded_width, 8756 internal_pipe->config.output_info[i].format, 8757 i); 8758 if (err) { 8759 IA_CSS_LEAVE_ERR_PRIVATE(err); 8760 kvfree(internal_pipe); 8761 internal_pipe = NULL; 8762 return err; 8763 } 8764 } 8765 8766 /* handle vf output info, when configured */ 8767 internal_pipe->enable_viewfinder[i] = 8768 (internal_pipe->config.vf_output_info[i].res.width != 0); 8769 if (internal_pipe->config.vf_output_info[i].res.width) { 8770 err = sh_css_pipe_configure_viewfinder( 8771 internal_pipe, 8772 internal_pipe->config.vf_output_info[i].res.width, 8773 internal_pipe->config.vf_output_info[i].res.height, 8774 internal_pipe->config.vf_output_info[i].padded_width, 8775 internal_pipe->config.vf_output_info[i].format, 8776 i); 8777 if (err) { 8778 IA_CSS_LEAVE_ERR_PRIVATE(err); 8779 kvfree(internal_pipe); 8780 internal_pipe = NULL; 8781 return err; 8782 } 8783 } 8784 } 8785 if (internal_pipe->config.acc_extension) { 8786 err = ia_css_pipe_load_extension(internal_pipe, 8787 internal_pipe->config.acc_extension); 8788 if (err) { 8789 IA_CSS_LEAVE_ERR_PRIVATE(err); 8790 kvfree(internal_pipe); 8791 return err; 8792 } 8793 } 8794 /* set all info to zeroes first */ 8795 memset(&internal_pipe->info, 0, sizeof(internal_pipe->info)); 8796 8797 /* all went well, return the pipe */ 8798 *pipe = internal_pipe; 8799 IA_CSS_LEAVE_ERR_PRIVATE(0); 8800 return 0; 8801 } 8802 8803 int 8804 ia_css_pipe_get_info(const struct ia_css_pipe *pipe, 8805 struct ia_css_pipe_info *pipe_info) 8806 { 8807 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 8808 "ia_css_pipe_get_info()\n"); 8809 if (!pipe_info) { 8810 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 8811 "ia_css_pipe_get_info: pipe_info cannot be NULL\n"); 8812 return -EINVAL; 8813 } 8814 if (!pipe || !pipe->stream) { 8815 ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, 8816 "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n"); 8817 return -EINVAL; 8818 } 8819 /* we succeeded return the info */ 8820 *pipe_info = pipe->info; 8821 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n"); 8822 return 0; 8823 } 8824 8825 bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info) 8826 { 8827 unsigned int i; 8828 8829 if (pipe_info) { 8830 for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) { 8831 if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable) 8832 return true; 8833 } 8834 } 8835 8836 return false; 8837 } 8838 8839 int 8840 ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe, 8841 int pin_index, 8842 enum ia_css_frame_format new_format) 8843 { 8844 int err = 0; 8845 8846 IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format); 8847 8848 if (!pipe) { 8849 IA_CSS_ERROR("pipe is not set"); 8850 err = -EINVAL; 8851 IA_CSS_LEAVE_ERR_PRIVATE(err); 8852 return err; 8853 } 8854 if (0 != pin_index && 1 != pin_index) { 8855 IA_CSS_ERROR("pin index is not valid"); 8856 err = -EINVAL; 8857 IA_CSS_LEAVE_ERR_PRIVATE(err); 8858 return err; 8859 } 8860 if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) { 8861 IA_CSS_ERROR("new format is not valid"); 8862 err = -EINVAL; 8863 IA_CSS_LEAVE_ERR_PRIVATE(err); 8864 return err; 8865 } else { 8866 err = ia_css_pipe_check_format(pipe, new_format); 8867 if (!err) { 8868 if (pin_index == 0) 8869 pipe->output_info[0].format = new_format; 8870 else 8871 pipe->vf_output_info[0].format = new_format; 8872 } 8873 } 8874 IA_CSS_LEAVE_ERR_PRIVATE(err); 8875 return err; 8876 } 8877 8878 #if !defined(ISP2401) 8879 /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */ 8880 static int 8881 ia_css_stream_configure_rx(struct ia_css_stream *stream) 8882 { 8883 struct ia_css_input_port *config; 8884 8885 assert(stream); 8886 8887 config = &stream->config.source.port; 8888 /* AM: this code is not reliable, especially for 2400 */ 8889 if (config->num_lanes == 1) 8890 stream->csi_rx_config.mode = MONO_1L_1L_0L; 8891 else if (config->num_lanes == 2) 8892 stream->csi_rx_config.mode = MONO_2L_1L_0L; 8893 else if (config->num_lanes == 3) 8894 stream->csi_rx_config.mode = MONO_3L_1L_0L; 8895 else if (config->num_lanes == 4) 8896 stream->csi_rx_config.mode = MONO_4L_1L_0L; 8897 else if (config->num_lanes != 0) 8898 return -EINVAL; 8899 8900 if (config->port > MIPI_PORT2_ID) 8901 return -EINVAL; 8902 stream->csi_rx_config.port = 8903 ia_css_isys_port_to_mipi_port(config->port); 8904 stream->csi_rx_config.timeout = config->timeout; 8905 stream->csi_rx_config.initcount = 0; 8906 stream->csi_rx_config.synccount = 0x28282828; 8907 stream->csi_rx_config.rxcount = config->rxcount; 8908 if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE) 8909 stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE; 8910 else 8911 /* not implemented yet, requires extension of the rx_cfg_t 8912 * struct */ 8913 return -EINVAL; 8914 8915 stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2); 8916 stream->reconfigure_css_rx = true; 8917 return 0; 8918 } 8919 #endif 8920 8921 static struct ia_css_pipe * 8922 find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes, 8923 enum ia_css_pipe_mode mode, bool copy_pipe) 8924 { 8925 unsigned int i; 8926 8927 assert(pipes); 8928 for (i = 0; i < num_pipes; i++) { 8929 assert(pipes[i]); 8930 if (pipes[i]->config.mode != mode) 8931 continue; 8932 if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY) 8933 continue; 8934 return pipes[i]; 8935 } 8936 return NULL; 8937 } 8938 8939 static int 8940 ia_css_acc_stream_create(struct ia_css_stream *stream) 8941 { 8942 int i; 8943 int err = 0; 8944 8945 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 8946 8947 if (!stream) { 8948 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8949 return -EINVAL; 8950 } 8951 8952 for (i = 0; i < stream->num_pipes; i++) { 8953 struct ia_css_pipe *pipe = stream->pipes[i]; 8954 8955 if (!pipe) { 8956 IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); 8957 return -EINVAL; 8958 } 8959 8960 pipe->stream = stream; 8961 } 8962 8963 /* Map SP threads before doing anything. */ 8964 err = map_sp_threads(stream, true); 8965 if (err) { 8966 IA_CSS_LEAVE_ERR_PRIVATE(err); 8967 return err; 8968 } 8969 8970 for (i = 0; i < stream->num_pipes; i++) { 8971 struct ia_css_pipe *pipe = stream->pipes[i]; 8972 8973 assert(pipe); 8974 ia_css_pipe_map_queue(pipe, true); 8975 } 8976 8977 err = create_host_pipeline_structure(stream); 8978 if (err) { 8979 IA_CSS_LEAVE_ERR_PRIVATE(err); 8980 return err; 8981 } 8982 8983 stream->started = false; 8984 8985 IA_CSS_LEAVE_ERR_PRIVATE(0); 8986 8987 return 0; 8988 } 8989 8990 static int 8991 metadata_info_init(const struct ia_css_metadata_config *mdc, 8992 struct ia_css_metadata_info *md) 8993 { 8994 /* Either both width and height should be set or neither */ 8995 if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0)) 8996 return -EINVAL; 8997 8998 md->resolution = mdc->resolution; 8999 /* We round up the stride to a multiple of the width 9000 * of the port going to DDR, this is a HW requirements (DMA). */ 9001 md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES); 9002 md->size = mdc->resolution.height * md->stride; 9003 return 0; 9004 } 9005 9006 /* ISP2401 */ 9007 static int check_pipe_resolutions(const struct ia_css_pipe *pipe) 9008 { 9009 int err = 0; 9010 9011 IA_CSS_ENTER_PRIVATE(""); 9012 9013 if (!pipe || !pipe->stream) { 9014 IA_CSS_ERROR("null arguments"); 9015 err = -EINVAL; 9016 goto EXIT; 9017 } 9018 9019 if (ia_css_util_check_res(pipe->config.input_effective_res.width, 9020 pipe->config.input_effective_res.height) != 0) { 9021 IA_CSS_ERROR("effective resolution not supported"); 9022 err = -EINVAL; 9023 goto EXIT; 9024 } 9025 if (!ia_css_util_resolution_is_zero( 9026 pipe->stream->config.input_config.input_res)) { 9027 if (!ia_css_util_res_leq(pipe->config.input_effective_res, 9028 pipe->stream->config.input_config.input_res)) { 9029 IA_CSS_ERROR("effective resolution is larger than input resolution"); 9030 err = -EINVAL; 9031 goto EXIT; 9032 } 9033 } 9034 if (!ia_css_util_resolution_is_even(pipe->config.output_info[0].res)) { 9035 IA_CSS_ERROR("output resolution must be even"); 9036 err = -EINVAL; 9037 goto EXIT; 9038 } 9039 if (!ia_css_util_resolution_is_even(pipe->config.vf_output_info[0].res)) { 9040 IA_CSS_ERROR("VF resolution must be even"); 9041 err = -EINVAL; 9042 goto EXIT; 9043 } 9044 EXIT: 9045 IA_CSS_LEAVE_ERR_PRIVATE(err); 9046 return err; 9047 } 9048 9049 int 9050 ia_css_stream_create(const struct ia_css_stream_config *stream_config, 9051 int num_pipes, 9052 struct ia_css_pipe *pipes[], 9053 struct ia_css_stream **stream) 9054 { 9055 struct ia_css_pipe *curr_pipe; 9056 struct ia_css_stream *curr_stream = NULL; 9057 bool spcopyonly; 9058 bool sensor_binning_changed; 9059 int i, j; 9060 int err = -EINVAL; 9061 struct ia_css_metadata_info md_info; 9062 struct ia_css_resolution effective_res; 9063 #ifdef ISP2401 9064 bool aspect_ratio_crop_enabled = false; 9065 #endif 9066 9067 IA_CSS_ENTER("num_pipes=%d", num_pipes); 9068 ia_css_debug_dump_stream_config(stream_config, num_pipes); 9069 9070 /* some checks */ 9071 if (num_pipes == 0 || 9072 !stream || 9073 !pipes) { 9074 err = -EINVAL; 9075 IA_CSS_LEAVE_ERR(err); 9076 return err; 9077 } 9078 9079 #if !defined(ISP2401) 9080 /* We don't support metadata for JPEG stream, since they both use str2mem */ 9081 if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 && 9082 stream_config->metadata_config.resolution.height > 0) { 9083 err = -EINVAL; 9084 IA_CSS_LEAVE_ERR(err); 9085 return err; 9086 } 9087 #endif 9088 9089 #ifdef ISP2401 9090 if (stream_config->online && stream_config->pack_raw_pixels) { 9091 IA_CSS_LOG("online and pack raw is invalid on input system 2401"); 9092 err = -EINVAL; 9093 IA_CSS_LEAVE_ERR(err); 9094 return err; 9095 } 9096 #endif 9097 9098 ia_css_debug_pipe_graph_dump_stream_config(stream_config); 9099 9100 /* check if mipi size specified */ 9101 if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) 9102 #ifdef ISP2401 9103 if (!stream_config->online) 9104 #endif 9105 { 9106 unsigned int port = (unsigned int)stream_config->source.port.port; 9107 9108 if (port >= N_MIPI_PORT_ID) { 9109 err = -EINVAL; 9110 IA_CSS_LEAVE_ERR(err); 9111 return err; 9112 } 9113 9114 if (my_css.size_mem_words != 0) { 9115 my_css.mipi_frame_size[port] = my_css.size_mem_words; 9116 } else if (stream_config->mipi_buffer_config.size_mem_words != 0) { 9117 my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words; 9118 } else { 9119 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 9120 "ia_css_stream_create() exit: error, need to set mipi frame size.\n"); 9121 assert(stream_config->mipi_buffer_config.size_mem_words != 0); 9122 err = -EINVAL; 9123 IA_CSS_LEAVE_ERR(err); 9124 return err; 9125 } 9126 9127 if (my_css.size_mem_words != 0) { 9128 my_css.num_mipi_frames[port] = 9129 2; /* Temp change: Default for backwards compatibility. */ 9130 } else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) { 9131 my_css.num_mipi_frames[port] = 9132 stream_config->mipi_buffer_config.nof_mipi_buffers; 9133 } else { 9134 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 9135 "ia_css_stream_create() exit: error, need to set number of mipi frames.\n"); 9136 assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0); 9137 err = -EINVAL; 9138 IA_CSS_LEAVE_ERR(err); 9139 return err; 9140 } 9141 } 9142 9143 /* Currently we only supported metadata up to a certain size. */ 9144 err = metadata_info_init(&stream_config->metadata_config, &md_info); 9145 if (err) { 9146 IA_CSS_LEAVE_ERR(err); 9147 return err; 9148 } 9149 9150 /* allocate the stream instance */ 9151 curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL); 9152 if (!curr_stream) { 9153 err = -ENOMEM; 9154 IA_CSS_LEAVE_ERR(err); 9155 return err; 9156 } 9157 /* default all to 0 */ 9158 curr_stream->info.metadata_info = md_info; 9159 9160 /* allocate pipes */ 9161 curr_stream->num_pipes = num_pipes; 9162 curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL); 9163 if (!curr_stream->pipes) { 9164 curr_stream->num_pipes = 0; 9165 kfree(curr_stream); 9166 curr_stream = NULL; 9167 err = -ENOMEM; 9168 IA_CSS_LEAVE_ERR(err); 9169 return err; 9170 } 9171 /* store pipes */ 9172 spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY); 9173 for (i = 0; i < num_pipes; i++) 9174 curr_stream->pipes[i] = pipes[i]; 9175 curr_stream->last_pipe = curr_stream->pipes[0]; 9176 /* take over stream config */ 9177 curr_stream->config = *stream_config; 9178 9179 #if defined(ISP2401) 9180 if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR && 9181 stream_config->online) 9182 curr_stream->config.online = false; 9183 #endif 9184 9185 #ifdef ISP2401 9186 if (curr_stream->config.online) { 9187 curr_stream->config.source.port.num_lanes = 9188 stream_config->source.port.num_lanes; 9189 curr_stream->config.mode = IA_CSS_INPUT_MODE_BUFFERED_SENSOR; 9190 } 9191 #endif 9192 /* in case driver doesn't configure init number of raw buffers, configure it here */ 9193 if (curr_stream->config.target_num_cont_raw_buf == 0) 9194 curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES; 9195 if (curr_stream->config.init_num_cont_raw_buf == 0) 9196 curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf; 9197 9198 /* Enable locking & unlocking of buffers in RAW buffer pool */ 9199 if (curr_stream->config.ia_css_enable_raw_buffer_locking) 9200 sh_css_sp_configure_enable_raw_pool_locking( 9201 curr_stream->config.lock_all); 9202 9203 /* copy mode specific stuff */ 9204 switch (curr_stream->config.mode) { 9205 case IA_CSS_INPUT_MODE_SENSOR: 9206 case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: 9207 #if !defined(ISP2401) 9208 ia_css_stream_configure_rx(curr_stream); 9209 #endif 9210 break; 9211 case IA_CSS_INPUT_MODE_TPG: 9212 #if !defined(ISP2401) 9213 IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d", 9214 curr_stream->config.source.tpg.x_mask, 9215 curr_stream->config.source.tpg.y_mask, 9216 curr_stream->config.source.tpg.x_delta, 9217 curr_stream->config.source.tpg.y_delta, 9218 curr_stream->config.source.tpg.xy_mask); 9219 9220 sh_css_sp_configure_tpg( 9221 curr_stream->config.source.tpg.x_mask, 9222 curr_stream->config.source.tpg.y_mask, 9223 curr_stream->config.source.tpg.x_delta, 9224 curr_stream->config.source.tpg.y_delta, 9225 curr_stream->config.source.tpg.xy_mask); 9226 #endif 9227 break; 9228 case IA_CSS_INPUT_MODE_PRBS: 9229 #if !defined(ISP2401) 9230 IA_CSS_LOG("mode prbs"); 9231 sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed); 9232 #endif 9233 break; 9234 case IA_CSS_INPUT_MODE_MEMORY: 9235 IA_CSS_LOG("mode memory"); 9236 curr_stream->reconfigure_css_rx = false; 9237 break; 9238 default: 9239 IA_CSS_LOG("mode sensor/default"); 9240 } 9241 9242 #ifdef ISP2401 9243 err = aspect_ratio_crop_init(curr_stream, pipes, 9244 &aspect_ratio_crop_enabled); 9245 if (err) { 9246 IA_CSS_LEAVE_ERR(err); 9247 goto ERR; 9248 } 9249 #endif 9250 for (i = 0; i < num_pipes; i++) { 9251 struct ia_css_resolution effective_res; 9252 9253 curr_pipe = pipes[i]; 9254 /* set current stream */ 9255 curr_pipe->stream = curr_stream; 9256 /* take over effective info */ 9257 9258 effective_res = curr_pipe->config.input_effective_res; 9259 if (effective_res.height == 0 || effective_res.width == 0) { 9260 effective_res = curr_pipe->stream->config.input_config.effective_res; 9261 9262 #if defined(ISP2401) 9263 /* The aspect ratio cropping is currently only 9264 * supported on the new input system. */ 9265 if (aspect_ratio_crop_check(aspect_ratio_crop_enabled, curr_pipe)) { 9266 struct ia_css_resolution crop_res; 9267 9268 err = aspect_ratio_crop(curr_pipe, &crop_res); 9269 if (!err) { 9270 effective_res = crop_res; 9271 } else { 9272 /* in case of error fallback to default 9273 * effective resolution from driver. */ 9274 IA_CSS_LOG("aspect_ratio_crop() failed with err(%d)", err); 9275 } 9276 } 9277 #endif 9278 curr_pipe->config.input_effective_res = effective_res; 9279 } 9280 IA_CSS_LOG("effective_res=%dx%d", 9281 effective_res.width, 9282 effective_res.height); 9283 } 9284 9285 if (IS_ISP2401) { 9286 for (i = 0; i < num_pipes; i++) { 9287 if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC && 9288 pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) { 9289 err = check_pipe_resolutions(pipes[i]); 9290 if (err) 9291 goto ERR; 9292 } 9293 } 9294 } 9295 9296 err = ia_css_stream_isp_parameters_init(curr_stream); 9297 if (err) 9298 goto ERR; 9299 IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs); 9300 9301 if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) { 9302 *stream = curr_stream; 9303 err = ia_css_acc_stream_create(curr_stream); 9304 goto ERR; 9305 } 9306 /* sensor binning */ 9307 if (!spcopyonly) { 9308 sensor_binning_changed = 9309 sh_css_params_set_binning_factor(curr_stream, 9310 curr_stream->config.sensor_binning_factor); 9311 } else { 9312 sensor_binning_changed = false; 9313 } 9314 9315 IA_CSS_LOG("sensor_binning=%d, changed=%d", 9316 curr_stream->config.sensor_binning_factor, sensor_binning_changed); 9317 /* loop over pipes */ 9318 IA_CSS_LOG("num_pipes=%d", num_pipes); 9319 curr_stream->cont_capt = false; 9320 /* Temporary hack: we give the preview pipe a reference to the capture 9321 * pipe in continuous capture mode. */ 9322 if (curr_stream->config.continuous) { 9323 /* Search for the preview pipe and create the copy pipe */ 9324 struct ia_css_pipe *preview_pipe; 9325 struct ia_css_pipe *video_pipe; 9326 struct ia_css_pipe *acc_pipe; 9327 struct ia_css_pipe *capture_pipe = NULL; 9328 struct ia_css_pipe *copy_pipe = NULL; 9329 9330 if (num_pipes >= 2) { 9331 curr_stream->cont_capt = true; 9332 curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder; 9333 9334 if (!IS_ISP2401) 9335 curr_stream->stop_copy_preview = my_css.stop_copy_preview; 9336 } 9337 9338 /* Create copy pipe here, since it may not be exposed to the driver */ 9339 preview_pipe = find_pipe(pipes, num_pipes, 9340 IA_CSS_PIPE_MODE_PREVIEW, false); 9341 video_pipe = find_pipe(pipes, num_pipes, 9342 IA_CSS_PIPE_MODE_VIDEO, false); 9343 acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC, 9344 false); 9345 if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt) 9346 curr_stream->cont_capt = 9347 false; /* preview + QoS case will not need cont_capt switch */ 9348 if (curr_stream->cont_capt) { 9349 capture_pipe = find_pipe(pipes, num_pipes, 9350 IA_CSS_PIPE_MODE_CAPTURE, 9351 false); 9352 if (!capture_pipe) { 9353 err = -EINVAL; 9354 goto ERR; 9355 } 9356 } 9357 /* We do not support preview and video pipe at the same time */ 9358 if (preview_pipe && video_pipe) { 9359 err = -EINVAL; 9360 goto ERR; 9361 } 9362 9363 if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) { 9364 err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, ©_pipe, true); 9365 if (err) 9366 goto ERR; 9367 ia_css_pipe_config_defaults(©_pipe->config); 9368 preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe; 9369 copy_pipe->stream = curr_stream; 9370 } 9371 if (preview_pipe && curr_stream->cont_capt) 9372 preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe; 9373 9374 if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) { 9375 err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, ©_pipe, true); 9376 if (err) 9377 goto ERR; 9378 ia_css_pipe_config_defaults(©_pipe->config); 9379 video_pipe->pipe_settings.video.copy_pipe = copy_pipe; 9380 copy_pipe->stream = curr_stream; 9381 } 9382 if (video_pipe && curr_stream->cont_capt) 9383 video_pipe->pipe_settings.video.capture_pipe = capture_pipe; 9384 9385 if (preview_pipe && acc_pipe) 9386 preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe; 9387 } 9388 for (i = 0; i < num_pipes; i++) { 9389 curr_pipe = pipes[i]; 9390 /* set current stream */ 9391 curr_pipe->stream = curr_stream; 9392 9393 if (!IS_ISP2401) { 9394 /* take over effective info */ 9395 9396 effective_res = curr_pipe->config.input_effective_res; 9397 err = ia_css_util_check_res( 9398 effective_res.width, 9399 effective_res.height); 9400 if (err) 9401 goto ERR; 9402 } 9403 /* sensor binning per pipe */ 9404 if (sensor_binning_changed) 9405 sh_css_pipe_free_shading_table(curr_pipe); 9406 } 9407 9408 /* now pipes have been configured, info should be available */ 9409 for (i = 0; i < num_pipes; i++) { 9410 struct ia_css_pipe_info *pipe_info = NULL; 9411 9412 curr_pipe = pipes[i]; 9413 9414 err = sh_css_pipe_load_binaries(curr_pipe); 9415 if (err) 9416 goto ERR; 9417 9418 /* handle each pipe */ 9419 pipe_info = &curr_pipe->info; 9420 for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) { 9421 err = sh_css_pipe_get_output_frame_info(curr_pipe, 9422 &pipe_info->output_info[j], j); 9423 if (err) 9424 goto ERR; 9425 } 9426 9427 if (IS_ISP2401) 9428 pipe_info->output_system_in_res_info = curr_pipe->config.output_system_in_res; 9429 9430 if (!spcopyonly) { 9431 if (!IS_ISP2401) 9432 err = sh_css_pipe_get_shading_info(curr_pipe, 9433 &pipe_info->shading_info, 9434 NULL); 9435 else 9436 err = sh_css_pipe_get_shading_info(curr_pipe, 9437 &pipe_info->shading_info, 9438 &curr_pipe->config); 9439 9440 if (err) 9441 goto ERR; 9442 err = sh_css_pipe_get_grid_info(curr_pipe, 9443 &pipe_info->grid_info); 9444 if (err) 9445 goto ERR; 9446 for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) { 9447 sh_css_pipe_get_viewfinder_frame_info(curr_pipe, 9448 &pipe_info->vf_output_info[j], 9449 j); 9450 if (err) 9451 goto ERR; 9452 } 9453 } 9454 9455 my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe; 9456 } 9457 9458 curr_stream->started = false; 9459 9460 /* Map SP threads before doing anything. */ 9461 err = map_sp_threads(curr_stream, true); 9462 if (err) { 9463 IA_CSS_LOG("map_sp_threads: return_err=%d", err); 9464 goto ERR; 9465 } 9466 9467 for (i = 0; i < num_pipes; i++) { 9468 curr_pipe = pipes[i]; 9469 ia_css_pipe_map_queue(curr_pipe, true); 9470 } 9471 9472 /* Create host side pipeline objects without stages */ 9473 err = create_host_pipeline_structure(curr_stream); 9474 if (err) { 9475 IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err); 9476 goto ERR; 9477 } 9478 9479 /* assign curr_stream */ 9480 *stream = curr_stream; 9481 9482 ERR: 9483 if (!err) { 9484 /* working mode: enter into the seed list */ 9485 if (my_css_save.mode == sh_css_mode_working) { 9486 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { 9487 if (!my_css_save.stream_seeds[i].stream) { 9488 IA_CSS_LOG("entered stream into loc=%d", i); 9489 my_css_save.stream_seeds[i].orig_stream = stream; 9490 my_css_save.stream_seeds[i].stream = curr_stream; 9491 my_css_save.stream_seeds[i].num_pipes = num_pipes; 9492 my_css_save.stream_seeds[i].stream_config = *stream_config; 9493 for (j = 0; j < num_pipes; j++) { 9494 my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config; 9495 my_css_save.stream_seeds[i].pipes[j] = pipes[j]; 9496 my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j]; 9497 } 9498 break; 9499 } 9500 } 9501 } else { 9502 ia_css_stream_destroy(curr_stream); 9503 } 9504 } else { 9505 ia_css_stream_destroy(curr_stream); 9506 } 9507 IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode); 9508 return err; 9509 } 9510 9511 int 9512 ia_css_stream_destroy(struct ia_css_stream *stream) 9513 { 9514 int i; 9515 int err = 0; 9516 9517 IA_CSS_ENTER_PRIVATE("stream = %p", stream); 9518 if (!stream) { 9519 err = -EINVAL; 9520 IA_CSS_LEAVE_ERR_PRIVATE(err); 9521 return err; 9522 } 9523 9524 ia_css_stream_isp_parameters_uninit(stream); 9525 9526 if ((stream->last_pipe) && 9527 ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) { 9528 #if defined(ISP2401) 9529 bool free_mpi; 9530 9531 for (i = 0; i < stream->num_pipes; i++) { 9532 struct ia_css_pipe *entry = stream->pipes[i]; 9533 unsigned int sp_thread_id; 9534 struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal; 9535 9536 assert(entry); 9537 if (entry) { 9538 /* get the SP thread id */ 9539 if (!ia_css_pipeline_get_sp_thread_id( 9540 ia_css_pipe_get_pipe_num(entry), &sp_thread_id)) 9541 return -EINVAL; 9542 /* get the target input terminal */ 9543 sp_pipeline_input_terminal = 9544 &sh_css_sp_group.pipe_io[sp_thread_id].input; 9545 9546 for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { 9547 ia_css_isys_stream_h isys_stream = 9548 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]; 9549 if (stream->config.isys_config[i].valid && isys_stream->valid) 9550 ia_css_isys_stream_destroy(isys_stream); 9551 } 9552 } 9553 } 9554 free_mpi = stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR; 9555 if (IS_ISP2401) { 9556 free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_TPG; 9557 free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_PRBS; 9558 } 9559 9560 if (free_mpi) { 9561 for (i = 0; i < stream->num_pipes; i++) { 9562 struct ia_css_pipe *entry = stream->pipes[i]; 9563 /* free any mipi frames that are remaining: 9564 * some test stream create-destroy cycles do not generate output frames 9565 * and the mipi buffer is not freed in the deque function 9566 */ 9567 if (entry) 9568 free_mipi_frames(entry); 9569 } 9570 } 9571 stream_unregister_with_csi_rx(stream); 9572 #endif 9573 9574 for (i = 0; i < stream->num_pipes; i++) { 9575 struct ia_css_pipe *curr_pipe = stream->pipes[i]; 9576 9577 assert(curr_pipe); 9578 ia_css_pipe_map_queue(curr_pipe, false); 9579 } 9580 9581 err = map_sp_threads(stream, false); 9582 if (err) { 9583 IA_CSS_LEAVE_ERR_PRIVATE(err); 9584 return err; 9585 } 9586 } 9587 9588 /* remove references from pipes to stream */ 9589 for (i = 0; i < stream->num_pipes; i++) { 9590 struct ia_css_pipe *entry = stream->pipes[i]; 9591 9592 assert(entry); 9593 if (entry) { 9594 /* clear reference to stream */ 9595 entry->stream = NULL; 9596 /* check internal copy pipe */ 9597 if (entry->mode == IA_CSS_PIPE_ID_PREVIEW && 9598 entry->pipe_settings.preview.copy_pipe) { 9599 IA_CSS_LOG("clearing stream on internal preview copy pipe"); 9600 entry->pipe_settings.preview.copy_pipe->stream = NULL; 9601 } 9602 if (entry->mode == IA_CSS_PIPE_ID_VIDEO && 9603 entry->pipe_settings.video.copy_pipe) { 9604 IA_CSS_LOG("clearing stream on internal video copy pipe"); 9605 entry->pipe_settings.video.copy_pipe->stream = NULL; 9606 } 9607 err = sh_css_pipe_unload_binaries(entry); 9608 } 9609 } 9610 /* free associated memory of stream struct */ 9611 kfree(stream->pipes); 9612 stream->pipes = NULL; 9613 stream->num_pipes = 0; 9614 9615 /* working mode: take out of the seed list */ 9616 if (my_css_save.mode == sh_css_mode_working) { 9617 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { 9618 if (my_css_save.stream_seeds[i].stream == stream) { 9619 IA_CSS_LOG("took out stream %d", i); 9620 my_css_save.stream_seeds[i].stream = NULL; 9621 break; 9622 } 9623 } 9624 } 9625 9626 kfree(stream); 9627 IA_CSS_LEAVE_ERR(err); 9628 9629 return err; 9630 } 9631 9632 int 9633 ia_css_stream_get_info(const struct ia_css_stream *stream, 9634 struct ia_css_stream_info *stream_info) 9635 { 9636 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n"); 9637 assert(stream); 9638 assert(stream_info); 9639 9640 *stream_info = stream->info; 9641 return 0; 9642 } 9643 9644 /* 9645 * Rebuild a stream, including allocating structs, setting configuration and 9646 * building the required pipes. 9647 * The data is taken from the css_save struct updated upon stream creation. 9648 * The stream handle is used to identify the correct entry in the css_save struct 9649 */ 9650 int 9651 ia_css_stream_load(struct ia_css_stream *stream) 9652 { 9653 int i, j, err; 9654 9655 if (IS_ISP2401) { 9656 /* TODO remove function - DEPRECATED */ 9657 (void)stream; 9658 return -ENOTSUPP; 9659 } 9660 9661 assert(stream); 9662 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n"); 9663 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { 9664 if (my_css_save.stream_seeds[i].stream != stream) 9665 continue; 9666 9667 for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) { 9668 int k; 9669 9670 err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j], 9671 &my_css_save.stream_seeds[i].pipes[j]); 9672 if (!err) 9673 continue; 9674 9675 for (k = 0; k < j; k++) 9676 ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]); 9677 return err; 9678 } 9679 err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config, 9680 my_css_save.stream_seeds[i].num_pipes, 9681 my_css_save.stream_seeds[i].pipes, 9682 &my_css_save.stream_seeds[i].stream); 9683 if (!err) 9684 break; 9685 9686 ia_css_stream_destroy(stream); 9687 for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) 9688 ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]); 9689 return err; 9690 } 9691 9692 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n"); 9693 return 0; 9694 } 9695 9696 int 9697 ia_css_stream_start(struct ia_css_stream *stream) 9698 { 9699 int err = 0; 9700 9701 IA_CSS_ENTER("stream = %p", stream); 9702 if ((!stream) || (!stream->last_pipe)) { 9703 IA_CSS_LEAVE_ERR(-EINVAL); 9704 return -EINVAL; 9705 } 9706 IA_CSS_LOG("starting %d", stream->last_pipe->mode); 9707 9708 sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf); 9709 9710 /* Create host side pipeline. */ 9711 err = create_host_pipeline(stream); 9712 if (err) { 9713 IA_CSS_LEAVE_ERR(err); 9714 return err; 9715 } 9716 9717 #if defined(ISP2401) 9718 if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) || 9719 (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)) 9720 stream_register_with_csi_rx(stream); 9721 #endif 9722 9723 #if !defined(ISP2401) 9724 /* Initialize mipi size checks */ 9725 if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 9726 unsigned int idx; 9727 unsigned int port = (unsigned int)(stream->config.source.port.port); 9728 9729 for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) { 9730 sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 9731 sh_css_get_mipi_sizes_for_check(port, idx); 9732 } 9733 } 9734 #endif 9735 9736 if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) { 9737 err = sh_css_config_input_network(stream); 9738 if (err) 9739 return err; 9740 } 9741 9742 err = sh_css_pipe_start(stream); 9743 IA_CSS_LEAVE_ERR(err); 9744 return err; 9745 } 9746 9747 int 9748 ia_css_stream_stop(struct ia_css_stream *stream) 9749 { 9750 int err = 0; 9751 9752 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n"); 9753 assert(stream); 9754 assert(stream->last_pipe); 9755 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n", 9756 stream->last_pipe->mode); 9757 9758 #if !defined(ISP2401) 9759 /* De-initialize mipi size checks */ 9760 if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 9761 unsigned int idx; 9762 unsigned int port = (unsigned int)(stream->config.source.port.port); 9763 9764 for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) 9765 sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0; 9766 } 9767 #endif 9768 9769 if (!IS_ISP2401) 9770 err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline); 9771 else 9772 err = sh_css_pipes_stop(stream); 9773 9774 if (err) 9775 return err; 9776 9777 /* Ideally, unmapping should happen after pipeline_stop, but current 9778 * semantics do not allow that. */ 9779 /* err = map_sp_threads(stream, false); */ 9780 9781 return err; 9782 } 9783 9784 bool 9785 ia_css_stream_has_stopped(struct ia_css_stream *stream) 9786 { 9787 bool stopped; 9788 9789 assert(stream); 9790 9791 if (!IS_ISP2401) 9792 stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline); 9793 else 9794 stopped = sh_css_pipes_have_stopped(stream); 9795 9796 return stopped; 9797 } 9798 9799 /* ISP2400 */ 9800 /* 9801 * Destroy the stream and all the pipes related to it. 9802 * The stream handle is used to identify the correct entry in the css_save struct 9803 */ 9804 int 9805 ia_css_stream_unload(struct ia_css_stream *stream) 9806 { 9807 int i; 9808 9809 assert(stream); 9810 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() enter,\n"); 9811 /* some checks */ 9812 assert(stream); 9813 for (i = 0; i < MAX_ACTIVE_STREAMS; i++) 9814 if (my_css_save.stream_seeds[i].stream == stream) { 9815 int j; 9816 9817 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 9818 "ia_css_stream_unload(): unloading %d (%p)\n", i, 9819 my_css_save.stream_seeds[i].stream); 9820 ia_css_stream_destroy(stream); 9821 for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) 9822 ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]); 9823 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, 9824 "ia_css_stream_unload(): after unloading %d (%p)\n", i, 9825 my_css_save.stream_seeds[i].stream); 9826 break; 9827 } 9828 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_unload() exit,\n"); 9829 return 0; 9830 } 9831 9832 int 9833 ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe, 9834 enum ia_css_pipe_id *pipe_id) 9835 { 9836 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n"); 9837 if (pipe) 9838 *pipe_id = pipe->mode; 9839 else 9840 *pipe_id = IA_CSS_PIPE_ID_COPY; 9841 9842 return 0; 9843 } 9844 9845 enum atomisp_input_format 9846 ia_css_stream_get_format(const struct ia_css_stream *stream) 9847 { 9848 return stream->config.input_config.format; 9849 } 9850 9851 bool 9852 ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) 9853 { 9854 return (stream->config.pixels_per_clock == 2); 9855 } 9856 9857 struct ia_css_binary * 9858 ia_css_stream_get_shading_correction_binary(const struct ia_css_stream 9859 *stream) 9860 { 9861 struct ia_css_pipe *pipe; 9862 9863 assert(stream); 9864 9865 pipe = stream->pipes[0]; 9866 9867 if (stream->num_pipes == 2) { 9868 assert(stream->pipes[1]); 9869 if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO || 9870 stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW) 9871 pipe = stream->pipes[1]; 9872 } 9873 9874 return ia_css_pipe_get_shading_correction_binary(pipe); 9875 } 9876 9877 struct ia_css_binary * 9878 ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) 9879 { 9880 int i; 9881 struct ia_css_pipe *video_pipe = NULL; 9882 9883 /* First we find the video pipe */ 9884 for (i = 0; i < stream->num_pipes; i++) { 9885 struct ia_css_pipe *pipe = stream->pipes[i]; 9886 9887 if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) { 9888 video_pipe = pipe; 9889 break; 9890 } 9891 } 9892 if (video_pipe) 9893 return &video_pipe->pipe_settings.video.video_binary; 9894 return NULL; 9895 } 9896 9897 struct ia_css_binary * 9898 ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) 9899 { 9900 struct ia_css_pipe *pipe; 9901 struct ia_css_binary *s3a_binary = NULL; 9902 9903 assert(stream); 9904 9905 pipe = stream->pipes[0]; 9906 9907 if (stream->num_pipes == 2) { 9908 assert(stream->pipes[1]); 9909 if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO || 9910 stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW) 9911 pipe = stream->pipes[1]; 9912 } 9913 9914 s3a_binary = ia_css_pipe_get_s3a_binary(pipe); 9915 9916 return s3a_binary; 9917 } 9918 9919 int 9920 ia_css_stream_set_output_padded_width(struct ia_css_stream *stream, 9921 unsigned int output_padded_width) 9922 { 9923 struct ia_css_pipe *pipe; 9924 9925 assert(stream); 9926 9927 pipe = stream->last_pipe; 9928 9929 assert(pipe); 9930 9931 /* set the config also just in case (redundant info? why do we save config in pipe?) */ 9932 pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width; 9933 pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width; 9934 9935 return 0; 9936 } 9937 9938 static struct ia_css_binary * 9939 ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) 9940 { 9941 struct ia_css_binary *binary = NULL; 9942 9943 assert(pipe); 9944 9945 switch (pipe->config.mode) { 9946 case IA_CSS_PIPE_MODE_PREVIEW: 9947 binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary; 9948 break; 9949 case IA_CSS_PIPE_MODE_VIDEO: 9950 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 9951 break; 9952 case IA_CSS_PIPE_MODE_CAPTURE: 9953 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 9954 unsigned int i; 9955 9956 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 9957 if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) { 9958 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i]; 9959 break; 9960 } 9961 } 9962 } else if (pipe->config.default_capture_config.mode == 9963 IA_CSS_CAPTURE_MODE_BAYER) 9964 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 9965 else if (pipe->config.default_capture_config.mode == 9966 IA_CSS_CAPTURE_MODE_ADVANCED || 9967 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 9968 if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1) 9969 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 9970 else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2) 9971 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary; 9972 } 9973 break; 9974 default: 9975 break; 9976 } 9977 9978 if (binary && binary->info->sp.enable.sc) 9979 return binary; 9980 9981 return NULL; 9982 } 9983 9984 static struct ia_css_binary * 9985 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) 9986 { 9987 struct ia_css_binary *binary = NULL; 9988 9989 assert(pipe); 9990 9991 switch (pipe->config.mode) { 9992 case IA_CSS_PIPE_MODE_PREVIEW: 9993 binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary; 9994 break; 9995 case IA_CSS_PIPE_MODE_VIDEO: 9996 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 9997 break; 9998 case IA_CSS_PIPE_MODE_CAPTURE: 9999 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 10000 unsigned int i; 10001 10002 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 10003 if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) { 10004 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i]; 10005 break; 10006 } 10007 } 10008 } else if (pipe->config.default_capture_config.mode == 10009 IA_CSS_CAPTURE_MODE_BAYER) { 10010 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 10011 } else if (pipe->config.default_capture_config.mode == 10012 IA_CSS_CAPTURE_MODE_ADVANCED || 10013 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { 10014 if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1) 10015 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; 10016 else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2) 10017 binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary; 10018 else 10019 assert(0); 10020 } 10021 break; 10022 default: 10023 break; 10024 } 10025 10026 if (binary && !binary->info->sp.enable.s3a) 10027 binary = NULL; 10028 10029 return binary; 10030 } 10031 10032 static struct ia_css_binary * 10033 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) 10034 { 10035 struct ia_css_binary *binary = NULL; 10036 10037 assert(pipe); 10038 10039 switch (pipe->config.mode) { 10040 case IA_CSS_PIPE_MODE_VIDEO: 10041 binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary; 10042 break; 10043 default: 10044 break; 10045 } 10046 10047 if (binary && !binary->info->sp.enable.dis) 10048 binary = NULL; 10049 10050 return binary; 10051 } 10052 10053 struct ia_css_pipeline * 10054 ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) 10055 { 10056 assert(pipe); 10057 10058 return (struct ia_css_pipeline *)&pipe->pipeline; 10059 } 10060 10061 unsigned int 10062 ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) 10063 { 10064 assert(pipe); 10065 10066 /* KW was not sure this function was not returning a value 10067 that was out of range; so added an assert, and, for the 10068 case when asserts are not enabled, clip to the largest 10069 value; pipe_num is unsigned so the value cannot be too small 10070 */ 10071 assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX); 10072 10073 if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX) 10074 return (IA_CSS_PIPELINE_NUM_MAX - 1); 10075 10076 return pipe->pipe_num; 10077 } 10078 10079 unsigned int 10080 ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) 10081 { 10082 assert(pipe); 10083 10084 return (unsigned int)pipe->config.isp_pipe_version; 10085 } 10086 10087 #define SP_START_TIMEOUT_US 30000000 10088 10089 int 10090 ia_css_start_sp(void) 10091 { 10092 unsigned long timeout; 10093 int err = 0; 10094 10095 IA_CSS_ENTER(""); 10096 sh_css_sp_start_isp(); 10097 10098 /* waiting for the SP is completely started */ 10099 timeout = SP_START_TIMEOUT_US; 10100 while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) { 10101 timeout--; 10102 udelay(1); 10103 } 10104 if (timeout == 0) { 10105 IA_CSS_ERROR("timeout during SP initialization"); 10106 return -EINVAL; 10107 } 10108 10109 /* Workaround, in order to run two streams in parallel. See TASK 4271*/ 10110 /* TODO: Fix this. */ 10111 10112 sh_css_init_host_sp_control_vars(); 10113 10114 /* buffers should be initialized only when sp is started */ 10115 /* AM: At the moment it will be done only when there is no stream active. */ 10116 10117 sh_css_setup_queues(); 10118 ia_css_bufq_dump_queue_info(); 10119 10120 IA_CSS_LEAVE_ERR(err); 10121 return err; 10122 } 10123 10124 /* 10125 * Time to wait SP for termincate. Only condition when this can happen 10126 * is a fatal hw failure, but we must be able to detect this and emit 10127 * a proper error trace. 10128 */ 10129 #define SP_SHUTDOWN_TIMEOUT_US 200000 10130 10131 int 10132 ia_css_stop_sp(void) 10133 { 10134 unsigned long timeout; 10135 int err = 0; 10136 10137 IA_CSS_ENTER("void"); 10138 10139 if (!sh_css_sp_is_running()) { 10140 err = -EINVAL; 10141 IA_CSS_LEAVE("SP already stopped : return_err=%d", err); 10142 10143 /* Return an error - stop SP should not have been called by driver */ 10144 return err; 10145 } 10146 10147 /* For now, stop whole SP */ 10148 if (!IS_ISP2401) { 10149 sh_css_write_host2sp_command(host2sp_cmd_terminate); 10150 } else { 10151 if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) { 10152 IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); 10153 ia_css_debug_dump_sp_sw_debug_info(); 10154 ia_css_debug_dump_debug_info(NULL); 10155 } 10156 } 10157 10158 sh_css_sp_set_sp_running(false); 10159 10160 timeout = SP_SHUTDOWN_TIMEOUT_US; 10161 while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) { 10162 timeout--; 10163 udelay(1); 10164 } 10165 if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)) 10166 IA_CSS_WARNING("SP has not terminated (SW)"); 10167 10168 if (timeout == 0) { 10169 IA_CSS_WARNING("SP is not idle"); 10170 ia_css_debug_dump_sp_sw_debug_info(); 10171 } 10172 timeout = SP_SHUTDOWN_TIMEOUT_US; 10173 while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) { 10174 timeout--; 10175 udelay(1); 10176 } 10177 if (timeout == 0) { 10178 IA_CSS_WARNING("ISP is not idle"); 10179 ia_css_debug_dump_sp_sw_debug_info(); 10180 } 10181 10182 sh_css_hmm_buffer_record_uninit(); 10183 10184 /* clear pending param sets from refcount */ 10185 sh_css_param_clear_param_sets(); 10186 10187 IA_CSS_LEAVE_ERR(err); 10188 return err; 10189 } 10190 10191 int 10192 ia_css_update_continuous_frames(struct ia_css_stream *stream) 10193 { 10194 struct ia_css_pipe *pipe; 10195 unsigned int i; 10196 10197 ia_css_debug_dtrace( 10198 IA_CSS_DEBUG_TRACE, 10199 "sh_css_update_continuous_frames() enter:\n"); 10200 10201 if (!stream) { 10202 ia_css_debug_dtrace( 10203 IA_CSS_DEBUG_TRACE, 10204 "sh_css_update_continuous_frames() leave: invalid stream, return_void\n"); 10205 return -EINVAL; 10206 } 10207 10208 pipe = stream->continuous_pipe; 10209 10210 for (i = stream->config.init_num_cont_raw_buf; 10211 i < stream->config.target_num_cont_raw_buf; i++) 10212 sh_css_update_host2sp_offline_frame(i, 10213 pipe->continuous_frames[i], pipe->cont_md_buffers[i]); 10214 10215 sh_css_update_host2sp_cont_num_raw_frames 10216 (stream->config.target_num_cont_raw_buf, true); 10217 ia_css_debug_dtrace( 10218 IA_CSS_DEBUG_TRACE, 10219 "sh_css_update_continuous_frames() leave: return_void\n"); 10220 10221 return 0; 10222 } 10223 10224 void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map) 10225 { 10226 unsigned int thread_id; 10227 unsigned int pipe_num; 10228 bool need_input_queue; 10229 10230 IA_CSS_ENTER(""); 10231 assert(pipe); 10232 10233 pipe_num = pipe->pipe_num; 10234 10235 ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); 10236 10237 #if defined(ISP2401) 10238 need_input_queue = true; 10239 #else 10240 need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; 10241 #endif 10242 10243 /* map required buffer queues to resources */ 10244 /* TODO: to be improved */ 10245 if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) { 10246 if (need_input_queue) 10247 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10248 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 10249 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 10250 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 10251 #if defined SH_CSS_ENABLE_METADATA 10252 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10253 #endif 10254 if (pipe->pipe_settings.preview.preview_binary.info && 10255 pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a) 10256 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 10257 } else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) { 10258 unsigned int i; 10259 10260 if (need_input_queue) 10261 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10262 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 10263 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map); 10264 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 10265 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 10266 #if defined SH_CSS_ENABLE_METADATA 10267 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10268 #endif 10269 if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) { 10270 for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) { 10271 if (pipe->pipe_settings.capture.primary_binary[i].info && 10272 pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) { 10273 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 10274 break; 10275 } 10276 } 10277 } else if (pipe->config.default_capture_config.mode == 10278 IA_CSS_CAPTURE_MODE_ADVANCED || 10279 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT || 10280 pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) { 10281 if (pipe->pipe_settings.capture.pre_isp_binary.info && 10282 pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a) 10283 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 10284 } 10285 } else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) { 10286 if (need_input_queue) 10287 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10288 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 10289 if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) 10290 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map); 10291 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 10292 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 10293 #if defined SH_CSS_ENABLE_METADATA 10294 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10295 #endif 10296 if (pipe->pipe_settings.video.video_binary.info && 10297 pipe->pipe_settings.video.video_binary.info->sp.enable.s3a) 10298 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map); 10299 if (pipe->pipe_settings.video.video_binary.info && 10300 (pipe->pipe_settings.video.video_binary.info->sp.enable.dis 10301 )) 10302 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map); 10303 } else if (pipe->mode == IA_CSS_PIPE_ID_COPY) { 10304 if (need_input_queue) 10305 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10306 if (!pipe->stream->config.continuous) 10307 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 10308 #if defined SH_CSS_ENABLE_METADATA 10309 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10310 #endif 10311 } else if (pipe->mode == IA_CSS_PIPE_ID_ACC) { 10312 if (need_input_queue) 10313 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10314 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map); 10315 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 10316 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map); 10317 #if defined SH_CSS_ENABLE_METADATA 10318 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10319 #endif 10320 } else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) { 10321 unsigned int idx; 10322 10323 for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) { 10324 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map); 10325 if (pipe->enable_viewfinder[idx]) 10326 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map); 10327 } 10328 if (need_input_queue) 10329 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map); 10330 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map); 10331 #if defined SH_CSS_ENABLE_METADATA 10332 ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map); 10333 #endif 10334 } 10335 IA_CSS_LEAVE(""); 10336 } 10337 10338 #if CONFIG_ON_FRAME_ENQUEUE() 10339 static int set_config_on_frame_enqueue(struct ia_css_frame_info 10340 *info, struct frame_data_wrapper *frame) 10341 { 10342 frame->config_on_frame_enqueue.padded_width = 0; 10343 10344 /* currently we support configuration on frame enqueue only on YUV formats */ 10345 /* on other formats the padded_width is zeroed for no configuration override */ 10346 switch (info->format) { 10347 case IA_CSS_FRAME_FORMAT_YUV420: 10348 case IA_CSS_FRAME_FORMAT_NV12: 10349 if (info->padded_width > info->res.width) 10350 frame->config_on_frame_enqueue.padded_width = info->padded_width; 10351 else if ((info->padded_width < info->res.width) && (info->padded_width > 0)) 10352 return -EINVAL; 10353 10354 /* nothing to do if width == padded width or padded width is zeroed (the same) */ 10355 break; 10356 default: 10357 break; 10358 } 10359 10360 return 0; 10361 } 10362 #endif 10363 10364 int 10365 ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) 10366 { 10367 int ret; 10368 10369 IA_CSS_ENTER(""); 10370 10371 /* Only continuous streams have a tagger to which we can send the 10372 * unlock message. */ 10373 if (!stream || !stream->config.continuous) { 10374 IA_CSS_ERROR("invalid stream pointer"); 10375 return -EINVAL; 10376 } 10377 10378 if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID || 10379 exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) { 10380 IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id); 10381 return -EINVAL; 10382 } 10383 10384 /* Send the event. Since we verified that the exp_id is valid, 10385 * we can safely assign it to an 8-bit argument here. */ 10386 ret = ia_css_bufq_enqueue_psys_event( 10387 IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0); 10388 10389 IA_CSS_LEAVE_ERR(ret); 10390 return ret; 10391 } 10392 10393 /* @brief Set the state (Enable or Disable) of the Extension stage in the 10394 * given pipe. 10395 */ 10396 int 10397 ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, 10398 bool enable) 10399 { 10400 unsigned int thread_id; 10401 struct ia_css_pipeline_stage *stage; 10402 int err = 0; 10403 10404 IA_CSS_ENTER(""); 10405 10406 /* Parameter Check */ 10407 if (!pipe || !pipe->stream) { 10408 IA_CSS_ERROR("Invalid Pipe."); 10409 err = -EINVAL; 10410 } else if (!(pipe->config.acc_extension)) { 10411 IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)"); 10412 err = -EINVAL; 10413 } else if (!sh_css_sp_is_running()) { 10414 IA_CSS_ERROR("Leaving: queue unavailable."); 10415 err = -EBUSY; 10416 } else { 10417 /* Query the threadid and stage_num for the Extension firmware*/ 10418 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 10419 err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); 10420 if (!err) { 10421 /* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/ 10422 err = ia_css_bufq_enqueue_psys_event( 10423 (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE, 10424 (uint8_t)thread_id, 10425 (uint8_t)stage->stage_num, 10426 enable ? 1 : 0); 10427 if (!err) { 10428 if (enable) 10429 SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num); 10430 else 10431 SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num); 10432 } 10433 } 10434 } 10435 IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable); 10436 return err; 10437 } 10438 10439 /* @brief Get the state (Enable or Disable) of the Extension stage in the 10440 * given pipe. 10441 */ 10442 int 10443 ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, 10444 bool *enable) 10445 { 10446 struct ia_css_pipeline_stage *stage; 10447 unsigned int thread_id; 10448 int err = 0; 10449 10450 IA_CSS_ENTER(""); 10451 10452 /* Parameter Check */ 10453 if (!pipe || !pipe->stream) { 10454 IA_CSS_ERROR("Invalid Pipe."); 10455 err = -EINVAL; 10456 } else if (!(pipe->config.acc_extension)) { 10457 IA_CSS_ERROR("Invalid Pipe (No Extension Firmware)."); 10458 err = -EINVAL; 10459 } else if (!sh_css_sp_is_running()) { 10460 IA_CSS_ERROR("Leaving: queue unavailable."); 10461 err = -EBUSY; 10462 } else { 10463 /* Query the threadid and stage_num corresponding to the Extension firmware*/ 10464 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 10465 err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); 10466 10467 if (!err) { 10468 /* Get the Extension State */ 10469 *enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id], 10470 stage->stage_num)) ? true : false; 10471 } 10472 } 10473 IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable); 10474 return err; 10475 } 10476 10477 /* ISP2401 */ 10478 int 10479 ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, 10480 u32 fw_handle, 10481 struct ia_css_isp_param_css_segments *css_seg, 10482 struct ia_css_isp_param_isp_segments *isp_seg) 10483 { 10484 unsigned int HIVE_ADDR_sp_group; 10485 static struct sh_css_sp_group sp_group; 10486 static struct sh_css_sp_stage sp_stage; 10487 static struct sh_css_isp_stage isp_stage; 10488 const struct ia_css_fw_info *fw; 10489 unsigned int thread_id; 10490 struct ia_css_pipeline_stage *stage; 10491 int err = 0; 10492 int stage_num = 0; 10493 enum ia_css_isp_memories mem; 10494 bool enabled; 10495 10496 IA_CSS_ENTER(""); 10497 10498 fw = &sh_css_sp_fw; 10499 10500 /* Parameter Check */ 10501 if (!pipe || !pipe->stream) { 10502 IA_CSS_ERROR("Invalid Pipe."); 10503 err = -EINVAL; 10504 } else if (!(pipe->config.acc_extension)) { 10505 IA_CSS_ERROR("Invalid Pipe (No Extension Firmware)."); 10506 err = -EINVAL; 10507 } else if (!sh_css_sp_is_running()) { 10508 IA_CSS_ERROR("Leaving: queue unavailable."); 10509 err = -EBUSY; 10510 } else { 10511 /* Query the thread_id and stage_num corresponding to the Extension firmware */ 10512 ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); 10513 err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); 10514 if (!err) { 10515 /* Get the Extension State */ 10516 enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id], 10517 stage->stage_num)) ? true : false; 10518 /* Update mapped arg only when extension stage is not enabled */ 10519 if (enabled) { 10520 IA_CSS_ERROR("Leaving: cannot update when stage is enabled."); 10521 err = -EBUSY; 10522 } else { 10523 stage_num = stage->stage_num; 10524 10525 HIVE_ADDR_sp_group = fw->info.sp.group; 10526 sp_dmem_load(SP0_ID, 10527 (unsigned int)sp_address_of(sp_group), 10528 &sp_group, 10529 sizeof(struct sh_css_sp_group)); 10530 hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num], 10531 &sp_stage, sizeof(struct sh_css_sp_stage)); 10532 10533 hmm_load(sp_stage.isp_stage_addr, 10534 &isp_stage, sizeof(struct sh_css_isp_stage)); 10535 10536 for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) { 10537 isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address = 10538 css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address; 10539 isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size = 10540 css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size; 10541 isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address 10542 = 10543 isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address; 10544 isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size 10545 = 10546 isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size; 10547 } 10548 10549 hmm_store(sp_stage.isp_stage_addr, 10550 &isp_stage, 10551 sizeof(struct sh_css_isp_stage)); 10552 } 10553 } 10554 } 10555 IA_CSS_LEAVE("err:%d handle:%u", err, fw_handle); 10556 return err; 10557 } 10558 10559 #ifdef ISP2401 10560 static int 10561 aspect_ratio_crop_init(struct ia_css_stream *curr_stream, 10562 struct ia_css_pipe *pipes[], 10563 bool *do_crop_status) 10564 { 10565 int err = 0; 10566 int i; 10567 struct ia_css_pipe *curr_pipe; 10568 u32 pipe_mask = 0; 10569 10570 if ((!curr_stream) || 10571 (curr_stream->num_pipes == 0) || 10572 (!pipes) || 10573 (!do_crop_status)) { 10574 err = -EINVAL; 10575 IA_CSS_LEAVE_ERR(err); 10576 return err; 10577 } 10578 10579 for (i = 0; i < curr_stream->num_pipes; i++) { 10580 curr_pipe = pipes[i]; 10581 pipe_mask |= (1 << curr_pipe->config.mode); 10582 } 10583 10584 *do_crop_status = 10585 (((pipe_mask & (1 << IA_CSS_PIPE_MODE_PREVIEW)) || 10586 (pipe_mask & (1 << IA_CSS_PIPE_MODE_VIDEO))) && 10587 (pipe_mask & (1 << IA_CSS_PIPE_MODE_CAPTURE)) && 10588 curr_stream->config.continuous); 10589 return 0; 10590 } 10591 10592 static bool 10593 aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) 10594 { 10595 bool status = false; 10596 10597 if ((curr_pipe) && enabled) { 10598 if ((curr_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) || 10599 (curr_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) || 10600 (curr_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)) 10601 status = true; 10602 } 10603 10604 return status; 10605 } 10606 10607 static int 10608 aspect_ratio_crop(struct ia_css_pipe *curr_pipe, 10609 struct ia_css_resolution *effective_res) 10610 { 10611 int err = 0; 10612 struct ia_css_resolution crop_res; 10613 struct ia_css_resolution *in_res = NULL; 10614 struct ia_css_resolution *out_res = NULL; 10615 bool use_bds_output_info = false; 10616 bool use_vf_pp_in_res = false; 10617 bool use_capt_pp_in_res = false; 10618 10619 if ((!curr_pipe) || 10620 (!effective_res)) { 10621 err = -EINVAL; 10622 IA_CSS_LEAVE_ERR(err); 10623 return err; 10624 } 10625 10626 if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) && 10627 (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) && 10628 (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) { 10629 err = -EINVAL; 10630 IA_CSS_LEAVE_ERR(err); 10631 return err; 10632 } 10633 10634 use_bds_output_info = 10635 ((curr_pipe->bds_output_info.res.width != 0) && 10636 (curr_pipe->bds_output_info.res.height != 0)); 10637 10638 use_vf_pp_in_res = 10639 ((curr_pipe->config.vf_pp_in_res.width != 0) && 10640 (curr_pipe->config.vf_pp_in_res.height != 0)); 10641 10642 use_capt_pp_in_res = 10643 ((curr_pipe->config.capt_pp_in_res.width != 0) && 10644 (curr_pipe->config.capt_pp_in_res.height != 0)); 10645 10646 in_res = &curr_pipe->stream->config.input_config.effective_res; 10647 out_res = &curr_pipe->output_info[0].res; 10648 10649 switch (curr_pipe->config.mode) { 10650 case IA_CSS_PIPE_MODE_PREVIEW: 10651 if (use_bds_output_info) 10652 out_res = &curr_pipe->bds_output_info.res; 10653 else if (use_vf_pp_in_res) 10654 out_res = &curr_pipe->config.vf_pp_in_res; 10655 break; 10656 case IA_CSS_PIPE_MODE_VIDEO: 10657 if (use_bds_output_info) 10658 out_res = &curr_pipe->bds_output_info.res; 10659 break; 10660 case IA_CSS_PIPE_MODE_CAPTURE: 10661 if (use_capt_pp_in_res) 10662 out_res = &curr_pipe->config.capt_pp_in_res; 10663 break; 10664 case IA_CSS_PIPE_MODE_ACC: 10665 case IA_CSS_PIPE_MODE_COPY: 10666 case IA_CSS_PIPE_MODE_YUVPP: 10667 default: 10668 IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n", 10669 curr_pipe->config.mode); 10670 assert(0); 10671 break; 10672 } 10673 10674 err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res); 10675 if (!err) 10676 *effective_res = crop_res; 10677 else 10678 /* in case of error fallback to default 10679 * effective resolution from driver. */ 10680 IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err); 10681 10682 return err; 10683 } 10684 #endif 10685 10686 static void 10687 sh_css_hmm_buffer_record_init(void) 10688 { 10689 int i; 10690 10691 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) 10692 sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]); 10693 } 10694 10695 static void 10696 sh_css_hmm_buffer_record_uninit(void) 10697 { 10698 int i; 10699 struct sh_css_hmm_buffer_record *buffer_record = NULL; 10700 10701 buffer_record = &hmm_buffer_record[0]; 10702 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 10703 if (buffer_record->in_use) { 10704 if (buffer_record->h_vbuf) 10705 ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf); 10706 sh_css_hmm_buffer_record_reset(buffer_record); 10707 } 10708 buffer_record++; 10709 } 10710 } 10711 10712 static void 10713 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) 10714 { 10715 assert(buffer_record); 10716 buffer_record->in_use = false; 10717 buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID; 10718 buffer_record->h_vbuf = NULL; 10719 buffer_record->kernel_ptr = 0; 10720 } 10721 10722 static struct sh_css_hmm_buffer_record 10723 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf, 10724 enum ia_css_buffer_type type, 10725 hrt_address kernel_ptr) 10726 { 10727 int i; 10728 struct sh_css_hmm_buffer_record *buffer_record = NULL; 10729 struct sh_css_hmm_buffer_record *out_buffer_record = NULL; 10730 10731 assert(h_vbuf); 10732 assert((type > IA_CSS_BUFFER_TYPE_INVALID) && 10733 (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)); 10734 assert(kernel_ptr != 0); 10735 10736 buffer_record = &hmm_buffer_record[0]; 10737 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 10738 if (!buffer_record->in_use) { 10739 buffer_record->in_use = true; 10740 buffer_record->type = type; 10741 buffer_record->h_vbuf = h_vbuf; 10742 buffer_record->kernel_ptr = kernel_ptr; 10743 out_buffer_record = buffer_record; 10744 break; 10745 } 10746 buffer_record++; 10747 } 10748 10749 return out_buffer_record; 10750 } 10751 10752 static struct sh_css_hmm_buffer_record 10753 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr, 10754 enum ia_css_buffer_type type) 10755 { 10756 int i; 10757 struct sh_css_hmm_buffer_record *buffer_record = NULL; 10758 bool found_record = false; 10759 10760 buffer_record = &hmm_buffer_record[0]; 10761 for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) { 10762 if ((buffer_record->in_use) && 10763 (buffer_record->type == type) && 10764 (buffer_record->h_vbuf) && 10765 (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) { 10766 found_record = true; 10767 break; 10768 } 10769 buffer_record++; 10770 } 10771 10772 if (found_record) 10773 return buffer_record; 10774 else 10775 return NULL; 10776 } 10777