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