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