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