1 /* 2 * Support for Clovertrail PNW Camera Imaging ISP subsystem. 3 * 4 * Copyright (c) 2013 Intel Corporation. All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 8 * 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * 16 */ 17 18 #include <media/videobuf-vmalloc.h> 19 #include <media/v4l2-dev.h> 20 #include <media/v4l2-event.h> 21 22 #include "mmu/isp_mmu.h" 23 #include "mmu/sh_mmu_mrfld.h" 24 #include "hmm/hmm_bo.h" 25 #include "hmm/hmm.h" 26 27 #include "atomisp_compat.h" 28 #include "atomisp_internal.h" 29 #include "atomisp_cmd.h" 30 #include "atomisp-regs.h" 31 #include "atomisp_fops.h" 32 #include "atomisp_ioctl.h" 33 #include "atomisp_acc.h" 34 35 #include <asm/intel-mid.h> 36 37 #include "ia_css_debug.h" 38 #include "ia_css_isp_param.h" 39 #include "sh_css_hrt.h" 40 #include "ia_css_isys.h" 41 42 #include <linux/pm_runtime.h> 43 44 /* Assume max number of ACC stages */ 45 #define MAX_ACC_STAGES 20 46 47 /* Ideally, this should come from CSS headers */ 48 #define NO_LINK -1 49 50 /* 51 * to serialize MMIO access , this is due to ISP2400 silicon issue Sighting 52 * #4684168, if concurrency access happened, system may hard hang. 53 */ 54 static DEFINE_SPINLOCK(mmio_lock); 55 56 enum frame_info_type { 57 ATOMISP_CSS_VF_FRAME, 58 ATOMISP_CSS_SECOND_VF_FRAME, 59 ATOMISP_CSS_OUTPUT_FRAME, 60 ATOMISP_CSS_SECOND_OUTPUT_FRAME, 61 ATOMISP_CSS_RAW_FRAME, 62 }; 63 64 struct bayer_ds_factor { 65 unsigned int numerator; 66 unsigned int denominator; 67 }; 68 69 static void atomisp_css2_hw_store_8(hrt_address addr, uint8_t data) 70 { 71 unsigned long flags; 72 73 spin_lock_irqsave(&mmio_lock, flags); 74 _hrt_master_port_store_8(addr, data); 75 spin_unlock_irqrestore(&mmio_lock, flags); 76 } 77 78 static void atomisp_css2_hw_store_16(hrt_address addr, uint16_t data) 79 { 80 unsigned long flags; 81 82 spin_lock_irqsave(&mmio_lock, flags); 83 _hrt_master_port_store_16(addr, data); 84 spin_unlock_irqrestore(&mmio_lock, flags); 85 } 86 87 void atomisp_css2_hw_store_32(hrt_address addr, uint32_t data) 88 { 89 unsigned long flags; 90 91 spin_lock_irqsave(&mmio_lock, flags); 92 _hrt_master_port_store_32(addr, data); 93 spin_unlock_irqrestore(&mmio_lock, flags); 94 } 95 96 static uint8_t atomisp_css2_hw_load_8(hrt_address addr) 97 { 98 unsigned long flags; 99 u8 ret; 100 101 spin_lock_irqsave(&mmio_lock, flags); 102 ret = _hrt_master_port_load_8(addr); 103 spin_unlock_irqrestore(&mmio_lock, flags); 104 return ret; 105 } 106 107 static uint16_t atomisp_css2_hw_load_16(hrt_address addr) 108 { 109 unsigned long flags; 110 u16 ret; 111 112 spin_lock_irqsave(&mmio_lock, flags); 113 ret = _hrt_master_port_load_16(addr); 114 spin_unlock_irqrestore(&mmio_lock, flags); 115 return ret; 116 } 117 118 static uint32_t atomisp_css2_hw_load_32(hrt_address addr) 119 { 120 unsigned long flags; 121 u32 ret; 122 123 spin_lock_irqsave(&mmio_lock, flags); 124 ret = _hrt_master_port_load_32(addr); 125 spin_unlock_irqrestore(&mmio_lock, flags); 126 return ret; 127 } 128 129 static void atomisp_css2_hw_store(hrt_address addr, 130 const void *from, uint32_t n) 131 { 132 unsigned long flags; 133 unsigned int i; 134 unsigned int _to = (unsigned int)addr; 135 const char *_from = (const char *)from; 136 137 spin_lock_irqsave(&mmio_lock, flags); 138 for (i = 0; i < n; i++, _to++, _from++) 139 _hrt_master_port_store_8(_to, *_from); 140 spin_unlock_irqrestore(&mmio_lock, flags); 141 } 142 143 static void atomisp_css2_hw_load(hrt_address addr, void *to, uint32_t n) 144 { 145 unsigned long flags; 146 unsigned int i; 147 char *_to = (char *)to; 148 unsigned int _from = (unsigned int)addr; 149 150 spin_lock_irqsave(&mmio_lock, flags); 151 for (i = 0; i < n; i++, _to++, _from++) 152 *_to = _hrt_master_port_load_8(_from); 153 spin_unlock_irqrestore(&mmio_lock, flags); 154 } 155 156 static int atomisp_css2_dbg_print(const char *fmt, va_list args) 157 { 158 vprintk(fmt, args); 159 return 0; 160 } 161 162 static int atomisp_css2_dbg_ftrace_print(const char *fmt, va_list args) 163 { 164 ftrace_vprintk(fmt, args); 165 return 0; 166 } 167 168 static int atomisp_css2_err_print(const char *fmt, va_list args) 169 { 170 vprintk(fmt, args); 171 return 0; 172 } 173 174 void atomisp_load_uint32(hrt_address addr, uint32_t *data) 175 { 176 *data = atomisp_css2_hw_load_32(addr); 177 } 178 179 static int hmm_get_mmu_base_addr(unsigned int *mmu_base_addr) 180 { 181 if (!sh_mmu_mrfld.get_pd_base) { 182 dev_err(atomisp_dev, "get mmu base address failed.\n"); 183 return -EINVAL; 184 } 185 186 *mmu_base_addr = sh_mmu_mrfld.get_pd_base(&bo_device.mmu, 187 bo_device.mmu.base_address); 188 return 0; 189 } 190 191 static void __dump_pipe_config(struct atomisp_sub_device *asd, 192 struct atomisp_stream_env *stream_env, 193 unsigned int pipe_id) 194 { 195 struct atomisp_device *isp = asd->isp; 196 197 if (stream_env->pipes[pipe_id]) { 198 struct ia_css_pipe_config *p_config; 199 struct ia_css_pipe_extra_config *pe_config; 200 201 p_config = &stream_env->pipe_configs[pipe_id]; 202 pe_config = &stream_env->pipe_extra_configs[pipe_id]; 203 dev_dbg(isp->dev, "dumping pipe[%d] config:\n", pipe_id); 204 dev_dbg(isp->dev, 205 "pipe_config.pipe_mode:%d.\n", p_config->mode); 206 dev_dbg(isp->dev, 207 "pipe_config.output_info[0] w=%d, h=%d.\n", 208 p_config->output_info[0].res.width, 209 p_config->output_info[0].res.height); 210 dev_dbg(isp->dev, 211 "pipe_config.vf_pp_in_res w=%d, h=%d.\n", 212 p_config->vf_pp_in_res.width, 213 p_config->vf_pp_in_res.height); 214 dev_dbg(isp->dev, 215 "pipe_config.capt_pp_in_res w=%d, h=%d.\n", 216 p_config->capt_pp_in_res.width, 217 p_config->capt_pp_in_res.height); 218 dev_dbg(isp->dev, 219 "pipe_config.output.padded w=%d.\n", 220 p_config->output_info[0].padded_width); 221 dev_dbg(isp->dev, 222 "pipe_config.vf_output_info[0] w=%d, h=%d.\n", 223 p_config->vf_output_info[0].res.width, 224 p_config->vf_output_info[0].res.height); 225 dev_dbg(isp->dev, 226 "pipe_config.bayer_ds_out_res w=%d, h=%d.\n", 227 p_config->bayer_ds_out_res.width, 228 p_config->bayer_ds_out_res.height); 229 dev_dbg(isp->dev, 230 "pipe_config.envelope w=%d, h=%d.\n", 231 p_config->dvs_envelope.width, 232 p_config->dvs_envelope.height); 233 dev_dbg(isp->dev, 234 "pipe_config.dvs_frame_delay=%d.\n", 235 p_config->dvs_frame_delay); 236 dev_dbg(isp->dev, 237 "pipe_config.isp_pipe_version:%d.\n", 238 p_config->isp_pipe_version); 239 dev_dbg(isp->dev, 240 "pipe_config.acc_extension=%p.\n", 241 p_config->acc_extension); 242 dev_dbg(isp->dev, 243 "pipe_config.acc_stages=%p.\n", 244 p_config->acc_stages); 245 dev_dbg(isp->dev, 246 "pipe_config.num_acc_stages=%d.\n", 247 p_config->num_acc_stages); 248 dev_dbg(isp->dev, 249 "pipe_config.acc_num_execs=%d.\n", 250 p_config->acc_num_execs); 251 dev_dbg(isp->dev, 252 "pipe_config.default_capture_config.capture_mode=%d.\n", 253 p_config->default_capture_config.mode); 254 dev_dbg(isp->dev, 255 "pipe_config.enable_dz=%d.\n", 256 p_config->enable_dz); 257 dev_dbg(isp->dev, 258 "pipe_config.default_capture_config.enable_xnr=%d.\n", 259 p_config->default_capture_config.enable_xnr); 260 dev_dbg(isp->dev, 261 "dumping pipe[%d] extra config:\n", pipe_id); 262 dev_dbg(isp->dev, 263 "pipe_extra_config.enable_raw_binning:%d.\n", 264 pe_config->enable_raw_binning); 265 dev_dbg(isp->dev, 266 "pipe_extra_config.enable_yuv_ds:%d.\n", 267 pe_config->enable_yuv_ds); 268 dev_dbg(isp->dev, 269 "pipe_extra_config.enable_high_speed:%d.\n", 270 pe_config->enable_high_speed); 271 dev_dbg(isp->dev, 272 "pipe_extra_config.enable_dvs_6axis:%d.\n", 273 pe_config->enable_dvs_6axis); 274 dev_dbg(isp->dev, 275 "pipe_extra_config.enable_reduced_pipe:%d.\n", 276 pe_config->enable_reduced_pipe); 277 dev_dbg(isp->dev, 278 "pipe_(extra_)config.enable_dz:%d.\n", 279 p_config->enable_dz); 280 dev_dbg(isp->dev, 281 "pipe_extra_config.disable_vf_pp:%d.\n", 282 pe_config->disable_vf_pp); 283 } 284 } 285 286 static void __dump_stream_config(struct atomisp_sub_device *asd, 287 struct atomisp_stream_env *stream_env) 288 { 289 struct atomisp_device *isp = asd->isp; 290 struct ia_css_stream_config *s_config; 291 int j; 292 bool valid_stream = false; 293 294 for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { 295 if (stream_env->pipes[j]) { 296 __dump_pipe_config(asd, stream_env, j); 297 valid_stream = true; 298 } 299 } 300 if (!valid_stream) 301 return; 302 s_config = &stream_env->stream_config; 303 dev_dbg(isp->dev, "stream_config.mode=%d.\n", s_config->mode); 304 305 if (s_config->mode == IA_CSS_INPUT_MODE_SENSOR || 306 s_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { 307 dev_dbg(isp->dev, "stream_config.source.port.port=%d.\n", 308 s_config->source.port.port); 309 dev_dbg(isp->dev, "stream_config.source.port.num_lanes=%d.\n", 310 s_config->source.port.num_lanes); 311 dev_dbg(isp->dev, "stream_config.source.port.timeout=%d.\n", 312 s_config->source.port.timeout); 313 dev_dbg(isp->dev, "stream_config.source.port.rxcount=0x%x.\n", 314 s_config->source.port.rxcount); 315 dev_dbg(isp->dev, "stream_config.source.port.compression.type=%d.\n", 316 s_config->source.port.compression.type); 317 dev_dbg(isp->dev, 318 "stream_config.source.port.compression.compressed_bits_per_pixel=%d.\n", 319 s_config->source.port.compression. 320 compressed_bits_per_pixel); 321 dev_dbg(isp->dev, 322 "stream_config.source.port.compression.uncompressed_bits_per_pixel=%d.\n", 323 s_config->source.port.compression. 324 uncompressed_bits_per_pixel); 325 } else if (s_config->mode == IA_CSS_INPUT_MODE_TPG) { 326 dev_dbg(isp->dev, "stream_config.source.tpg.id=%d.\n", 327 s_config->source.tpg.id); 328 dev_dbg(isp->dev, "stream_config.source.tpg.mode=%d.\n", 329 s_config->source.tpg.mode); 330 dev_dbg(isp->dev, "stream_config.source.tpg.x_mask=%d.\n", 331 s_config->source.tpg.x_mask); 332 dev_dbg(isp->dev, "stream_config.source.tpg.x_delta=%d.\n", 333 s_config->source.tpg.x_delta); 334 dev_dbg(isp->dev, "stream_config.source.tpg.y_mask=%d.\n", 335 s_config->source.tpg.y_mask); 336 dev_dbg(isp->dev, "stream_config.source.tpg.y_delta=%d.\n", 337 s_config->source.tpg.y_delta); 338 dev_dbg(isp->dev, "stream_config.source.tpg.xy_mask=%d.\n", 339 s_config->source.tpg.xy_mask); 340 } else if (s_config->mode == IA_CSS_INPUT_MODE_PRBS) { 341 dev_dbg(isp->dev, "stream_config.source.prbs.id=%d.\n", 342 s_config->source.prbs.id); 343 dev_dbg(isp->dev, "stream_config.source.prbs.h_blank=%d.\n", 344 s_config->source.prbs.h_blank); 345 dev_dbg(isp->dev, "stream_config.source.prbs.v_blank=%d.\n", 346 s_config->source.prbs.v_blank); 347 dev_dbg(isp->dev, "stream_config.source.prbs.seed=%d.\n", 348 s_config->source.prbs.seed); 349 dev_dbg(isp->dev, "stream_config.source.prbs.seed1=%d.\n", 350 s_config->source.prbs.seed1); 351 } 352 353 for (j = 0; j < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; j++) { 354 dev_dbg(isp->dev, "stream_configisys_config[%d].input_res w=%d, h=%d.\n", 355 j, 356 s_config->isys_config[j].input_res.width, 357 s_config->isys_config[j].input_res.height); 358 359 dev_dbg(isp->dev, "stream_configisys_config[%d].linked_isys_stream_id=%d\n", 360 j, 361 s_config->isys_config[j].linked_isys_stream_id); 362 363 dev_dbg(isp->dev, "stream_configisys_config[%d].format=%d\n", 364 j, 365 s_config->isys_config[j].format); 366 367 dev_dbg(isp->dev, "stream_configisys_config[%d].valid=%d.\n", 368 j, 369 s_config->isys_config[j].valid); 370 } 371 372 dev_dbg(isp->dev, "stream_config.input_config.input_res w=%d, h=%d.\n", 373 s_config->input_config.input_res.width, 374 s_config->input_config.input_res.height); 375 376 dev_dbg(isp->dev, "stream_config.input_config.effective_res w=%d, h=%d.\n", 377 s_config->input_config.effective_res.width, 378 s_config->input_config.effective_res.height); 379 380 dev_dbg(isp->dev, "stream_config.input_config.format=%d\n", 381 s_config->input_config.format); 382 383 dev_dbg(isp->dev, "stream_config.input_config.bayer_order=%d.\n", 384 s_config->input_config.bayer_order); 385 386 dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n", 387 s_config->pixels_per_clock); 388 dev_dbg(isp->dev, "stream_config.online=%d.\n", s_config->online); 389 dev_dbg(isp->dev, "stream_config.continuous=%d.\n", 390 s_config->continuous); 391 dev_dbg(isp->dev, "stream_config.disable_cont_viewfinder=%d.\n", 392 s_config->disable_cont_viewfinder); 393 dev_dbg(isp->dev, "stream_config.channel_id=%d.\n", 394 s_config->channel_id); 395 dev_dbg(isp->dev, "stream_config.init_num_cont_raw_buf=%d.\n", 396 s_config->init_num_cont_raw_buf); 397 dev_dbg(isp->dev, "stream_config.target_num_cont_raw_buf=%d.\n", 398 s_config->target_num_cont_raw_buf); 399 dev_dbg(isp->dev, "stream_config.left_padding=%d.\n", 400 s_config->left_padding); 401 dev_dbg(isp->dev, "stream_config.sensor_binning_factor=%d.\n", 402 s_config->sensor_binning_factor); 403 dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n", 404 s_config->pixels_per_clock); 405 dev_dbg(isp->dev, "stream_config.pack_raw_pixels=%d.\n", 406 s_config->pack_raw_pixels); 407 dev_dbg(isp->dev, "stream_config.flash_gpio_pin=%d.\n", 408 s_config->flash_gpio_pin); 409 dev_dbg(isp->dev, "stream_config.mipi_buffer_config.size_mem_words=%d.\n", 410 s_config->mipi_buffer_config.size_mem_words); 411 dev_dbg(isp->dev, "stream_config.mipi_buffer_config.contiguous=%d.\n", 412 s_config->mipi_buffer_config.contiguous); 413 dev_dbg(isp->dev, "stream_config.metadata_config.data_type=%d.\n", 414 s_config->metadata_config.data_type); 415 dev_dbg(isp->dev, "stream_config.metadata_config.resolution w=%d, h=%d.\n", 416 s_config->metadata_config.resolution.width, 417 s_config->metadata_config.resolution.height); 418 } 419 420 static int __destroy_stream(struct atomisp_sub_device *asd, 421 struct atomisp_stream_env *stream_env, bool force) 422 { 423 struct atomisp_device *isp = asd->isp; 424 int i; 425 unsigned long timeout; 426 427 if (!stream_env->stream) 428 return 0; 429 430 if (!force) { 431 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 432 if (stream_env->update_pipe[i]) 433 break; 434 435 if (i == IA_CSS_PIPE_ID_NUM) 436 return 0; 437 } 438 439 if (stream_env->stream_state == CSS_STREAM_STARTED 440 && ia_css_stream_stop(stream_env->stream) != 0) { 441 dev_err(isp->dev, "stop stream failed.\n"); 442 return -EINVAL; 443 } 444 445 if (stream_env->stream_state == CSS_STREAM_STARTED) { 446 timeout = jiffies + msecs_to_jiffies(40); 447 while (1) { 448 if (ia_css_stream_has_stopped(stream_env->stream)) 449 break; 450 451 if (time_after(jiffies, timeout)) { 452 dev_warn(isp->dev, "stop stream timeout.\n"); 453 break; 454 } 455 456 usleep_range(100, 200); 457 } 458 } 459 460 stream_env->stream_state = CSS_STREAM_STOPPED; 461 462 if (ia_css_stream_destroy(stream_env->stream)) { 463 dev_err(isp->dev, "destroy stream failed.\n"); 464 return -EINVAL; 465 } 466 stream_env->stream_state = CSS_STREAM_UNINIT; 467 stream_env->stream = NULL; 468 469 return 0; 470 } 471 472 static int __destroy_streams(struct atomisp_sub_device *asd, bool force) 473 { 474 int ret, i; 475 476 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 477 ret = __destroy_stream(asd, &asd->stream_env[i], force); 478 if (ret) 479 return ret; 480 } 481 asd->stream_prepared = false; 482 return 0; 483 } 484 485 static int __create_stream(struct atomisp_sub_device *asd, 486 struct atomisp_stream_env *stream_env) 487 { 488 int pipe_index = 0, i; 489 struct ia_css_pipe *multi_pipes[IA_CSS_PIPE_ID_NUM]; 490 491 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { 492 if (stream_env->pipes[i]) 493 multi_pipes[pipe_index++] = stream_env->pipes[i]; 494 } 495 if (pipe_index == 0) 496 return 0; 497 498 stream_env->stream_config.target_num_cont_raw_buf = 499 asd->continuous_raw_buffer_size->val; 500 stream_env->stream_config.channel_id = stream_env->ch_id; 501 stream_env->stream_config.ia_css_enable_raw_buffer_locking = 502 asd->enable_raw_buffer_lock->val; 503 504 __dump_stream_config(asd, stream_env); 505 if (ia_css_stream_create(&stream_env->stream_config, 506 pipe_index, multi_pipes, &stream_env->stream) != 0) 507 return -EINVAL; 508 if (ia_css_stream_get_info(stream_env->stream, 509 &stream_env->stream_info) != 0) { 510 ia_css_stream_destroy(stream_env->stream); 511 stream_env->stream = NULL; 512 return -EINVAL; 513 } 514 515 stream_env->stream_state = CSS_STREAM_CREATED; 516 return 0; 517 } 518 519 static int __create_streams(struct atomisp_sub_device *asd) 520 { 521 int ret, i; 522 523 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 524 ret = __create_stream(asd, &asd->stream_env[i]); 525 if (ret) 526 goto rollback; 527 } 528 asd->stream_prepared = true; 529 return 0; 530 rollback: 531 for (i--; i >= 0; i--) 532 __destroy_stream(asd, &asd->stream_env[i], true); 533 return ret; 534 } 535 536 static int __destroy_stream_pipes(struct atomisp_sub_device *asd, 537 struct atomisp_stream_env *stream_env, 538 bool force) 539 { 540 struct atomisp_device *isp = asd->isp; 541 int ret = 0; 542 int i; 543 544 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { 545 if (!stream_env->pipes[i] || 546 !(force || stream_env->update_pipe[i])) 547 continue; 548 if (ia_css_pipe_destroy(stream_env->pipes[i]) 549 != 0) { 550 dev_err(isp->dev, 551 "destroy pipe[%d]failed.cannot recover.\n", i); 552 ret = -EINVAL; 553 } 554 stream_env->pipes[i] = NULL; 555 stream_env->update_pipe[i] = false; 556 } 557 return ret; 558 } 559 560 static int __destroy_pipes(struct atomisp_sub_device *asd, bool force) 561 { 562 struct atomisp_device *isp = asd->isp; 563 int i; 564 int ret = 0; 565 566 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 567 if (asd->stream_env[i].stream) { 568 dev_err(isp->dev, 569 "cannot destroy css pipes for stream[%d].\n", 570 i); 571 continue; 572 } 573 574 ret = __destroy_stream_pipes(asd, &asd->stream_env[i], force); 575 if (ret) 576 return ret; 577 } 578 579 return 0; 580 } 581 582 void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd) 583 { 584 __destroy_streams(asd, true); 585 __destroy_pipes(asd, true); 586 } 587 588 static void __apply_additional_pipe_config( 589 struct atomisp_sub_device *asd, 590 struct atomisp_stream_env *stream_env, 591 enum ia_css_pipe_id pipe_id) 592 { 593 struct atomisp_device *isp = asd->isp; 594 595 if (pipe_id < 0 || pipe_id >= IA_CSS_PIPE_ID_NUM) { 596 dev_err(isp->dev, 597 "wrong pipe_id for additional pipe config.\n"); 598 return; 599 } 600 601 /* apply default pipe config */ 602 stream_env->pipe_configs[pipe_id].isp_pipe_version = 2; 603 stream_env->pipe_configs[pipe_id].enable_dz = 604 asd->disable_dz->val ? false : true; 605 /* apply isp 2.2 specific config for baytrail*/ 606 switch (pipe_id) { 607 case IA_CSS_PIPE_ID_CAPTURE: 608 /* enable capture pp/dz manually or digital zoom would 609 * fail*/ 610 if (stream_env->pipe_configs[pipe_id]. 611 default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW) 612 stream_env->pipe_configs[pipe_id].enable_dz = false; 613 614 if (atomisp_hw_is_isp2401) { 615 /* the isp default to use ISP2.2 and the camera hal will 616 * control whether use isp2.7 */ 617 if (asd->select_isp_version->val == ATOMISP_CSS_ISP_PIPE_VERSION_2_7) 618 stream_env->pipe_configs[pipe_id].isp_pipe_version = SH_CSS_ISP_PIPE_VERSION_2_7; 619 else 620 stream_env->pipe_configs[pipe_id].isp_pipe_version = SH_CSS_ISP_PIPE_VERSION_2_2; 621 } 622 break; 623 case IA_CSS_PIPE_ID_VIDEO: 624 /* enable reduced pipe to have binary 625 * video_dz_2_min selected*/ 626 stream_env->pipe_extra_configs[pipe_id] 627 .enable_reduced_pipe = true; 628 stream_env->pipe_configs[pipe_id] 629 .enable_dz = false; 630 if (ATOMISP_SOC_CAMERA(asd)) 631 stream_env->pipe_configs[pipe_id].enable_dz = true; 632 633 if (asd->params.video_dis_en) { 634 stream_env->pipe_extra_configs[pipe_id] 635 .enable_dvs_6axis = true; 636 stream_env->pipe_configs[pipe_id] 637 .dvs_frame_delay = 638 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; 639 } 640 break; 641 case IA_CSS_PIPE_ID_PREVIEW: 642 break; 643 case IA_CSS_PIPE_ID_YUVPP: 644 case IA_CSS_PIPE_ID_COPY: 645 if (ATOMISP_SOC_CAMERA(asd)) 646 stream_env->pipe_configs[pipe_id].enable_dz = true; 647 else 648 stream_env->pipe_configs[pipe_id].enable_dz = false; 649 break; 650 case IA_CSS_PIPE_ID_ACC: 651 stream_env->pipe_configs[pipe_id].mode = IA_CSS_PIPE_MODE_ACC; 652 stream_env->pipe_configs[pipe_id].enable_dz = false; 653 break; 654 default: 655 break; 656 } 657 } 658 659 static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd, 660 enum ia_css_pipe_id pipe_id) 661 { 662 if (!asd) 663 return false; 664 665 if (pipe_id == IA_CSS_PIPE_ID_ACC || pipe_id == IA_CSS_PIPE_ID_YUVPP) 666 return true; 667 668 if (asd->vfpp) { 669 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 670 if (pipe_id == IA_CSS_PIPE_ID_VIDEO) 671 return true; 672 else 673 return false; 674 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 675 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) 676 return true; 677 else 678 return false; 679 } 680 } 681 682 if (!asd->run_mode) 683 return false; 684 685 if (asd->copy_mode && pipe_id == IA_CSS_PIPE_ID_COPY) 686 return true; 687 688 switch (asd->run_mode->val) { 689 case ATOMISP_RUN_MODE_STILL_CAPTURE: 690 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) 691 return true; 692 else 693 return false; 694 case ATOMISP_RUN_MODE_PREVIEW: 695 if (!asd->continuous_mode->val) { 696 if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) 697 return true; 698 else 699 return false; 700 } 701 /* fall through to ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */ 702 case ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE: 703 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE || 704 pipe_id == IA_CSS_PIPE_ID_PREVIEW) 705 return true; 706 else 707 return false; 708 case ATOMISP_RUN_MODE_VIDEO: 709 if (!asd->continuous_mode->val) { 710 if (pipe_id == IA_CSS_PIPE_ID_VIDEO || 711 pipe_id == IA_CSS_PIPE_ID_YUVPP) 712 return true; 713 else 714 return false; 715 } 716 /* fall through to ATOMISP_RUN_MODE_SDV */ 717 case ATOMISP_RUN_MODE_SDV: 718 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE || 719 pipe_id == IA_CSS_PIPE_ID_VIDEO) 720 return true; 721 else 722 return false; 723 } 724 725 return false; 726 } 727 728 static int __create_pipe(struct atomisp_sub_device *asd, 729 struct atomisp_stream_env *stream_env, 730 enum ia_css_pipe_id pipe_id) 731 { 732 struct atomisp_device *isp = asd->isp; 733 struct ia_css_pipe_extra_config extra_config; 734 int ret; 735 736 if (pipe_id >= IA_CSS_PIPE_ID_NUM) 737 return -EINVAL; 738 739 if (pipe_id != IA_CSS_PIPE_ID_ACC && 740 !stream_env->pipe_configs[pipe_id].output_info[0].res.width) 741 return 0; 742 743 if (pipe_id == IA_CSS_PIPE_ID_ACC && 744 !stream_env->pipe_configs[pipe_id].acc_extension) 745 return 0; 746 747 if (!is_pipe_valid_to_current_run_mode(asd, pipe_id)) 748 return 0; 749 750 ia_css_pipe_extra_config_defaults(&extra_config); 751 752 __apply_additional_pipe_config(asd, stream_env, pipe_id); 753 if (!memcmp(&extra_config, 754 &stream_env->pipe_extra_configs[pipe_id], 755 sizeof(extra_config))) 756 ret = ia_css_pipe_create( 757 &stream_env->pipe_configs[pipe_id], 758 &stream_env->pipes[pipe_id]); 759 else 760 ret = ia_css_pipe_create_extra( 761 &stream_env->pipe_configs[pipe_id], 762 &stream_env->pipe_extra_configs[pipe_id], 763 &stream_env->pipes[pipe_id]); 764 if (ret) 765 dev_err(isp->dev, "create pipe[%d] error.\n", pipe_id); 766 return ret; 767 } 768 769 static int __create_pipes(struct atomisp_sub_device *asd) 770 { 771 int ret; 772 int i, j; 773 774 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 775 for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { 776 ret = __create_pipe(asd, &asd->stream_env[i], j); 777 if (ret) 778 break; 779 } 780 if (j < IA_CSS_PIPE_ID_NUM) 781 goto pipe_err; 782 } 783 return 0; 784 pipe_err: 785 for (; i >= 0; i--) { 786 for (j--; j >= 0; j--) { 787 if (asd->stream_env[i].pipes[j]) { 788 ia_css_pipe_destroy(asd->stream_env[i].pipes[j]); 789 asd->stream_env[i].pipes[j] = NULL; 790 } 791 } 792 j = IA_CSS_PIPE_ID_NUM; 793 } 794 return -EINVAL; 795 } 796 797 void atomisp_create_pipes_stream(struct atomisp_sub_device *asd) 798 { 799 __create_pipes(asd); 800 __create_streams(asd); 801 } 802 803 int atomisp_css_update_stream(struct atomisp_sub_device *asd) 804 { 805 int ret; 806 struct atomisp_device *isp = asd->isp; 807 808 if (__destroy_streams(asd, true)) 809 dev_warn(isp->dev, "destroy stream failed.\n"); 810 811 if (__destroy_pipes(asd, true)) 812 dev_warn(isp->dev, "destroy pipe failed.\n"); 813 814 ret = __create_pipes(asd); 815 if (ret) { 816 dev_err(isp->dev, "create pipe failed %d.\n", ret); 817 return -EIO; 818 } 819 820 ret = __create_streams(asd); 821 if (ret) { 822 dev_warn(isp->dev, "create stream failed %d.\n", ret); 823 __destroy_pipes(asd, true); 824 return -EIO; 825 } 826 827 return 0; 828 } 829 830 int atomisp_css_init(struct atomisp_device *isp) 831 { 832 unsigned int mmu_base_addr; 833 int ret; 834 int err; 835 836 ret = hmm_get_mmu_base_addr(&mmu_base_addr); 837 if (ret) 838 return ret; 839 840 /* Init ISP */ 841 err = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL, 842 (uint32_t)mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE); 843 if (err) { 844 dev_err(isp->dev, "css init failed --- bad firmware?\n"); 845 return -EINVAL; 846 } 847 ia_css_enable_isys_event_queue(true); 848 849 isp->css_initialized = true; 850 dev_dbg(isp->dev, "sh_css_init success\n"); 851 852 return 0; 853 } 854 855 static inline int __set_css_print_env(struct atomisp_device *isp, int opt) 856 { 857 int ret = 0; 858 859 if (opt == 0) 860 isp->css_env.isp_css_env.print_env.debug_print = NULL; 861 else if (opt == 1) 862 isp->css_env.isp_css_env.print_env.debug_print = 863 atomisp_css2_dbg_ftrace_print; 864 else if (opt == 2) 865 isp->css_env.isp_css_env.print_env.debug_print = 866 atomisp_css2_dbg_print; 867 else 868 ret = -EINVAL; 869 870 return ret; 871 } 872 873 int atomisp_css_load_firmware(struct atomisp_device *isp) 874 { 875 int err; 876 877 /* set css env */ 878 isp->css_env.isp_css_fw.data = (void *)isp->firmware->data; 879 isp->css_env.isp_css_fw.bytes = isp->firmware->size; 880 881 isp->css_env.isp_css_env.hw_access_env.store_8 = 882 atomisp_css2_hw_store_8; 883 isp->css_env.isp_css_env.hw_access_env.store_16 = 884 atomisp_css2_hw_store_16; 885 isp->css_env.isp_css_env.hw_access_env.store_32 = 886 atomisp_css2_hw_store_32; 887 888 isp->css_env.isp_css_env.hw_access_env.load_8 = atomisp_css2_hw_load_8; 889 isp->css_env.isp_css_env.hw_access_env.load_16 = 890 atomisp_css2_hw_load_16; 891 isp->css_env.isp_css_env.hw_access_env.load_32 = 892 atomisp_css2_hw_load_32; 893 894 isp->css_env.isp_css_env.hw_access_env.load = atomisp_css2_hw_load; 895 isp->css_env.isp_css_env.hw_access_env.store = atomisp_css2_hw_store; 896 897 __set_css_print_env(isp, dbg_func); 898 899 isp->css_env.isp_css_env.print_env.error_print = atomisp_css2_err_print; 900 901 /* load isp fw into ISP memory */ 902 err = ia_css_load_firmware(isp->dev, &isp->css_env.isp_css_env, 903 &isp->css_env.isp_css_fw); 904 if (err) { 905 dev_err(isp->dev, "css load fw failed.\n"); 906 return -EINVAL; 907 } 908 909 return 0; 910 } 911 912 void atomisp_css_uninit(struct atomisp_device *isp) 913 { 914 struct atomisp_sub_device *asd; 915 unsigned int i; 916 917 for (i = 0; i < isp->num_of_streams; i++) { 918 asd = &isp->asd[i]; 919 memset(&asd->params.config, 0, sizeof(asd->params.config)); 920 asd->params.css_update_params_needed = false; 921 } 922 923 isp->css_initialized = false; 924 ia_css_uninit(); 925 } 926 927 void atomisp_css_suspend(struct atomisp_device *isp) 928 { 929 isp->css_initialized = false; 930 ia_css_uninit(); 931 } 932 933 int atomisp_css_resume(struct atomisp_device *isp) 934 { 935 unsigned int mmu_base_addr; 936 int ret; 937 938 ret = hmm_get_mmu_base_addr(&mmu_base_addr); 939 if (ret) { 940 dev_err(isp->dev, "get base address error.\n"); 941 return -EINVAL; 942 } 943 944 ret = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL, 945 mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE); 946 if (ret) { 947 dev_err(isp->dev, "re-init css failed.\n"); 948 return -EINVAL; 949 } 950 ia_css_enable_isys_event_queue(true); 951 952 isp->css_initialized = true; 953 return 0; 954 } 955 956 int atomisp_css_irq_translate(struct atomisp_device *isp, 957 unsigned int *infos) 958 { 959 int err; 960 961 err = ia_css_irq_translate(infos); 962 if (err) { 963 dev_warn(isp->dev, 964 "%s:failed to translate irq (err = %d,infos = %d)\n", 965 __func__, err, *infos); 966 return -EINVAL; 967 } 968 969 return 0; 970 } 971 972 void atomisp_css_rx_get_irq_info(enum mipi_port_id port, 973 unsigned int *infos) 974 { 975 #ifndef ISP2401_NEW_INPUT_SYSTEM 976 ia_css_isys_rx_get_irq_info(port, infos); 977 #else 978 *infos = 0; 979 #endif 980 } 981 982 void atomisp_css_rx_clear_irq_info(enum mipi_port_id port, 983 unsigned int infos) 984 { 985 #ifndef ISP2401_NEW_INPUT_SYSTEM 986 ia_css_isys_rx_clear_irq_info(port, infos); 987 #endif 988 } 989 990 int atomisp_css_irq_enable(struct atomisp_device *isp, 991 enum ia_css_irq_info info, bool enable) 992 { 993 dev_dbg(isp->dev, "%s: css irq info 0x%08x: %s.\n", 994 __func__, info, 995 enable ? "enable" : "disable"); 996 if (ia_css_irq_enable(info, enable)) { 997 dev_warn(isp->dev, "%s:Invalid irq info: 0x%08x when %s.\n", 998 __func__, info, 999 enable ? "enabling" : "disabling"); 1000 return -EINVAL; 1001 } 1002 1003 return 0; 1004 } 1005 1006 void atomisp_css_init_struct(struct atomisp_sub_device *asd) 1007 { 1008 int i, j; 1009 1010 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 1011 asd->stream_env[i].stream = NULL; 1012 for (j = 0; j < IA_CSS_PIPE_MODE_NUM; j++) { 1013 asd->stream_env[i].pipes[j] = NULL; 1014 asd->stream_env[i].update_pipe[j] = false; 1015 ia_css_pipe_config_defaults( 1016 &asd->stream_env[i].pipe_configs[j]); 1017 ia_css_pipe_extra_config_defaults( 1018 &asd->stream_env[i].pipe_extra_configs[j]); 1019 } 1020 ia_css_stream_config_defaults(&asd->stream_env[i].stream_config); 1021 } 1022 } 1023 1024 int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd, 1025 struct videobuf_vmalloc_memory *vm_mem, 1026 enum atomisp_input_stream_id stream_id, 1027 enum ia_css_buffer_type css_buf_type, 1028 enum ia_css_pipe_id css_pipe_id) 1029 { 1030 struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; 1031 struct ia_css_buffer css_buf = {0}; 1032 int err; 1033 1034 css_buf.type = css_buf_type; 1035 css_buf.data.frame = vm_mem->vaddr; 1036 1037 err = ia_css_pipe_enqueue_buffer( 1038 stream_env->pipes[css_pipe_id], &css_buf); 1039 if (err) 1040 return -EINVAL; 1041 1042 return 0; 1043 } 1044 1045 int atomisp_q_metadata_buffer_to_css(struct atomisp_sub_device *asd, 1046 struct atomisp_metadata_buf *metadata_buf, 1047 enum atomisp_input_stream_id stream_id, 1048 enum ia_css_pipe_id css_pipe_id) 1049 { 1050 struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; 1051 struct ia_css_buffer buffer = {0}; 1052 struct atomisp_device *isp = asd->isp; 1053 1054 buffer.type = IA_CSS_BUFFER_TYPE_METADATA; 1055 buffer.data.metadata = metadata_buf->metadata; 1056 if (ia_css_pipe_enqueue_buffer(stream_env->pipes[css_pipe_id], 1057 &buffer)) { 1058 dev_err(isp->dev, "failed to q meta data buffer\n"); 1059 return -EINVAL; 1060 } 1061 1062 return 0; 1063 } 1064 1065 int atomisp_q_s3a_buffer_to_css(struct atomisp_sub_device *asd, 1066 struct atomisp_s3a_buf *s3a_buf, 1067 enum atomisp_input_stream_id stream_id, 1068 enum ia_css_pipe_id css_pipe_id) 1069 { 1070 struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; 1071 struct ia_css_buffer buffer = {0}; 1072 struct atomisp_device *isp = asd->isp; 1073 1074 buffer.type = IA_CSS_BUFFER_TYPE_3A_STATISTICS; 1075 buffer.data.stats_3a = s3a_buf->s3a_data; 1076 if (ia_css_pipe_enqueue_buffer( 1077 stream_env->pipes[css_pipe_id], 1078 &buffer)) { 1079 dev_dbg(isp->dev, "failed to q s3a stat buffer\n"); 1080 return -EINVAL; 1081 } 1082 1083 return 0; 1084 } 1085 1086 int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd, 1087 struct atomisp_dis_buf *dis_buf, 1088 enum atomisp_input_stream_id stream_id, 1089 enum ia_css_pipe_id css_pipe_id) 1090 { 1091 struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id]; 1092 struct ia_css_buffer buffer = {0}; 1093 struct atomisp_device *isp = asd->isp; 1094 1095 buffer.type = IA_CSS_BUFFER_TYPE_DIS_STATISTICS; 1096 buffer.data.stats_dvs = dis_buf->dis_data; 1097 if (ia_css_pipe_enqueue_buffer( 1098 stream_env->pipes[css_pipe_id], 1099 &buffer)) { 1100 dev_dbg(isp->dev, "failed to q dvs stat buffer\n"); 1101 return -EINVAL; 1102 } 1103 1104 return 0; 1105 } 1106 1107 int atomisp_css_start(struct atomisp_sub_device *asd, 1108 enum ia_css_pipe_id pipe_id, bool in_reset) 1109 { 1110 struct atomisp_device *isp = asd->isp; 1111 bool sp_is_started = false; 1112 int ret = 0, i = 0; 1113 1114 if (in_reset) { 1115 if (__destroy_streams(asd, true)) 1116 dev_warn(isp->dev, "destroy stream failed.\n"); 1117 1118 if (__destroy_pipes(asd, true)) 1119 dev_warn(isp->dev, "destroy pipe failed.\n"); 1120 1121 if (__create_pipes(asd)) { 1122 dev_err(isp->dev, "create pipe error.\n"); 1123 return -EINVAL; 1124 } 1125 if (__create_streams(asd)) { 1126 dev_err(isp->dev, "create stream error.\n"); 1127 ret = -EINVAL; 1128 goto stream_err; 1129 } 1130 /* in_reset == true, extension firmwares are reloaded after the recovery */ 1131 atomisp_acc_load_extensions(asd); 1132 } 1133 1134 /* 1135 * For dual steam case, it is possible that: 1136 * 1: for this stream, it is at the stage that: 1137 * - after set_fmt is called 1138 * - before stream on is called 1139 * 2: for the other stream, the stream off is called which css reset 1140 * has been done. 1141 * 1142 * Thus the stream created in set_fmt get destroyed and need to be 1143 * recreated in the next stream on. 1144 */ 1145 if (asd->stream_prepared == false) { 1146 if (__create_pipes(asd)) { 1147 dev_err(isp->dev, "create pipe error.\n"); 1148 return -EINVAL; 1149 } 1150 if (__create_streams(asd)) { 1151 dev_err(isp->dev, "create stream error.\n"); 1152 ret = -EINVAL; 1153 goto stream_err; 1154 } 1155 } 1156 /* 1157 * SP can only be started one time 1158 * if atomisp_subdev_streaming_count() tell there already has some 1159 * subdev at streamming, then SP should already be started previously, 1160 * so need to skip start sp procedure 1161 */ 1162 if (atomisp_streaming_count(isp)) { 1163 dev_dbg(isp->dev, "skip start sp\n"); 1164 } else { 1165 if (!sh_css_hrt_system_is_idle()) 1166 dev_err(isp->dev, "CSS HW not idle before starting SP\n"); 1167 if (ia_css_start_sp()) { 1168 dev_err(isp->dev, "start sp error.\n"); 1169 ret = -EINVAL; 1170 goto start_err; 1171 } else { 1172 sp_is_started = true; 1173 } 1174 } 1175 1176 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 1177 if (asd->stream_env[i].stream) { 1178 if (ia_css_stream_start(asd->stream_env[i] 1179 .stream) != 0) { 1180 dev_err(isp->dev, "stream[%d] start error.\n", i); 1181 ret = -EINVAL; 1182 goto start_err; 1183 } else { 1184 asd->stream_env[i].stream_state = CSS_STREAM_STARTED; 1185 dev_dbg(isp->dev, "stream[%d] started.\n", i); 1186 } 1187 } 1188 } 1189 1190 return 0; 1191 1192 start_err: 1193 __destroy_streams(asd, true); 1194 stream_err: 1195 __destroy_pipes(asd, true); 1196 1197 /* css 2.0 API limitation: ia_css_stop_sp() could be only called after 1198 * destroy all pipes 1199 */ 1200 /* 1201 * SP can not be stop if other streams are in use 1202 */ 1203 if ((atomisp_streaming_count(isp) == 0) && sp_is_started) 1204 ia_css_stop_sp(); 1205 1206 return ret; 1207 } 1208 1209 void atomisp_css_update_isp_params(struct atomisp_sub_device *asd) 1210 { 1211 /* 1212 * FIXME! 1213 * for ISP2401 new input system, this api is under development. 1214 * Calling it would cause kernel panic. 1215 * 1216 * VIED BZ: 1458 1217 * 1218 * Check if it is Cherry Trail and also new input system 1219 */ 1220 if (asd->copy_mode) { 1221 dev_warn(asd->isp->dev, 1222 "%s: ia_css_stream_set_isp_config() not supported in copy mode!.\n", 1223 __func__); 1224 return; 1225 } 1226 1227 ia_css_stream_set_isp_config( 1228 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 1229 &asd->params.config); 1230 memset(&asd->params.config, 0, sizeof(asd->params.config)); 1231 } 1232 1233 void atomisp_css_update_isp_params_on_pipe(struct atomisp_sub_device *asd, 1234 struct ia_css_pipe *pipe) 1235 { 1236 int ret; 1237 1238 if (!pipe) { 1239 atomisp_css_update_isp_params(asd); 1240 return; 1241 } 1242 1243 dev_dbg(asd->isp->dev, 1244 "%s: apply parameter for ia_css_frame %p with isp_config_id %d on pipe %p.\n", 1245 __func__, asd->params.config.output_frame, 1246 asd->params.config.isp_config_id, pipe); 1247 1248 ret = ia_css_stream_set_isp_config_on_pipe( 1249 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 1250 &asd->params.config, pipe); 1251 if (ret) 1252 dev_warn(asd->isp->dev, "%s: ia_css_stream_set_isp_config_on_pipe failed %d\n", 1253 __func__, ret); 1254 memset(&asd->params.config, 0, sizeof(asd->params.config)); 1255 } 1256 1257 int atomisp_css_queue_buffer(struct atomisp_sub_device *asd, 1258 enum atomisp_input_stream_id stream_id, 1259 enum ia_css_pipe_id pipe_id, 1260 enum ia_css_buffer_type buf_type, 1261 struct atomisp_css_buffer *isp_css_buffer) 1262 { 1263 if (ia_css_pipe_enqueue_buffer( 1264 asd->stream_env[stream_id].pipes[pipe_id], 1265 &isp_css_buffer->css_buffer) 1266 != 0) 1267 return -EINVAL; 1268 1269 return 0; 1270 } 1271 1272 int atomisp_css_dequeue_buffer(struct atomisp_sub_device *asd, 1273 enum atomisp_input_stream_id stream_id, 1274 enum ia_css_pipe_id pipe_id, 1275 enum ia_css_buffer_type buf_type, 1276 struct atomisp_css_buffer *isp_css_buffer) 1277 { 1278 struct atomisp_device *isp = asd->isp; 1279 int err; 1280 1281 err = ia_css_pipe_dequeue_buffer( 1282 asd->stream_env[stream_id].pipes[pipe_id], 1283 &isp_css_buffer->css_buffer); 1284 if (err) { 1285 dev_err(isp->dev, 1286 "ia_css_pipe_dequeue_buffer failed: 0x%x\n", err); 1287 return -EINVAL; 1288 } 1289 1290 return 0; 1291 } 1292 1293 int atomisp_css_allocate_stat_buffers(struct atomisp_sub_device *asd, 1294 u16 stream_id, 1295 struct atomisp_s3a_buf *s3a_buf, 1296 struct atomisp_dis_buf *dis_buf, 1297 struct atomisp_metadata_buf *md_buf) 1298 { 1299 struct atomisp_device *isp = asd->isp; 1300 struct ia_css_dvs_grid_info *dvs_grid_info = 1301 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 1302 1303 if (s3a_buf && asd->params.curr_grid_info.s3a_grid.enable) { 1304 void *s3a_ptr; 1305 1306 s3a_buf->s3a_data = ia_css_isp_3a_statistics_allocate( 1307 &asd->params.curr_grid_info.s3a_grid); 1308 if (!s3a_buf->s3a_data) { 1309 dev_err(isp->dev, "3a buf allocation failed.\n"); 1310 return -EINVAL; 1311 } 1312 1313 s3a_ptr = hmm_vmap(s3a_buf->s3a_data->data_ptr, true); 1314 s3a_buf->s3a_map = ia_css_isp_3a_statistics_map_allocate( 1315 s3a_buf->s3a_data, s3a_ptr); 1316 } 1317 1318 if (dis_buf && dvs_grid_info && dvs_grid_info->enable) { 1319 void *dvs_ptr; 1320 1321 dis_buf->dis_data = ia_css_isp_dvs2_statistics_allocate( 1322 dvs_grid_info); 1323 if (!dis_buf->dis_data) { 1324 dev_err(isp->dev, "dvs buf allocation failed.\n"); 1325 if (s3a_buf) 1326 ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); 1327 return -EINVAL; 1328 } 1329 1330 dvs_ptr = hmm_vmap(dis_buf->dis_data->data_ptr, true); 1331 dis_buf->dvs_map = ia_css_isp_dvs_statistics_map_allocate( 1332 dis_buf->dis_data, dvs_ptr); 1333 } 1334 1335 if (asd->stream_env[stream_id].stream_info. 1336 metadata_info.size && md_buf) { 1337 md_buf->metadata = ia_css_metadata_allocate( 1338 &asd->stream_env[stream_id].stream_info.metadata_info); 1339 if (!md_buf->metadata) { 1340 if (s3a_buf) 1341 ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); 1342 if (dis_buf) 1343 ia_css_isp_dvs2_statistics_free(dis_buf->dis_data); 1344 dev_err(isp->dev, "metadata buf allocation failed.\n"); 1345 return -EINVAL; 1346 } 1347 md_buf->md_vptr = hmm_vmap(md_buf->metadata->address, false); 1348 } 1349 1350 return 0; 1351 } 1352 1353 void atomisp_css_free_3a_buffer(struct atomisp_s3a_buf *s3a_buf) 1354 { 1355 if (s3a_buf->s3a_data) 1356 hmm_vunmap(s3a_buf->s3a_data->data_ptr); 1357 1358 ia_css_isp_3a_statistics_map_free(s3a_buf->s3a_map); 1359 s3a_buf->s3a_map = NULL; 1360 ia_css_isp_3a_statistics_free(s3a_buf->s3a_data); 1361 } 1362 1363 void atomisp_css_free_dis_buffer(struct atomisp_dis_buf *dis_buf) 1364 { 1365 if (dis_buf->dis_data) 1366 hmm_vunmap(dis_buf->dis_data->data_ptr); 1367 1368 ia_css_isp_dvs_statistics_map_free(dis_buf->dvs_map); 1369 dis_buf->dvs_map = NULL; 1370 ia_css_isp_dvs2_statistics_free(dis_buf->dis_data); 1371 } 1372 1373 void atomisp_css_free_metadata_buffer(struct atomisp_metadata_buf *metadata_buf) 1374 { 1375 if (metadata_buf->md_vptr) { 1376 hmm_vunmap(metadata_buf->metadata->address); 1377 metadata_buf->md_vptr = NULL; 1378 } 1379 ia_css_metadata_free(metadata_buf->metadata); 1380 } 1381 1382 void atomisp_css_free_stat_buffers(struct atomisp_sub_device *asd) 1383 { 1384 struct atomisp_s3a_buf *s3a_buf, *_s3a_buf; 1385 struct atomisp_dis_buf *dis_buf, *_dis_buf; 1386 struct atomisp_metadata_buf *md_buf, *_md_buf; 1387 struct ia_css_dvs_grid_info *dvs_grid_info = 1388 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 1389 unsigned int i; 1390 1391 /* 3A statistics use vmalloc, DIS use kmalloc */ 1392 if (dvs_grid_info && dvs_grid_info->enable) { 1393 ia_css_dvs2_coefficients_free(asd->params.css_param.dvs2_coeff); 1394 ia_css_dvs2_statistics_free(asd->params.dvs_stat); 1395 asd->params.css_param.dvs2_coeff = NULL; 1396 asd->params.dvs_stat = NULL; 1397 asd->params.dvs_hor_proj_bytes = 0; 1398 asd->params.dvs_ver_proj_bytes = 0; 1399 asd->params.dvs_hor_coef_bytes = 0; 1400 asd->params.dvs_ver_coef_bytes = 0; 1401 asd->params.dis_proj_data_valid = false; 1402 list_for_each_entry_safe(dis_buf, _dis_buf, 1403 &asd->dis_stats, list) { 1404 atomisp_css_free_dis_buffer(dis_buf); 1405 list_del(&dis_buf->list); 1406 kfree(dis_buf); 1407 } 1408 list_for_each_entry_safe(dis_buf, _dis_buf, 1409 &asd->dis_stats_in_css, list) { 1410 atomisp_css_free_dis_buffer(dis_buf); 1411 list_del(&dis_buf->list); 1412 kfree(dis_buf); 1413 } 1414 } 1415 if (asd->params.curr_grid_info.s3a_grid.enable) { 1416 ia_css_3a_statistics_free(asd->params.s3a_user_stat); 1417 asd->params.s3a_user_stat = NULL; 1418 asd->params.s3a_output_bytes = 0; 1419 list_for_each_entry_safe(s3a_buf, _s3a_buf, 1420 &asd->s3a_stats, list) { 1421 atomisp_css_free_3a_buffer(s3a_buf); 1422 list_del(&s3a_buf->list); 1423 kfree(s3a_buf); 1424 } 1425 list_for_each_entry_safe(s3a_buf, _s3a_buf, 1426 &asd->s3a_stats_in_css, list) { 1427 atomisp_css_free_3a_buffer(s3a_buf); 1428 list_del(&s3a_buf->list); 1429 kfree(s3a_buf); 1430 } 1431 list_for_each_entry_safe(s3a_buf, _s3a_buf, 1432 &asd->s3a_stats_ready, list) { 1433 atomisp_css_free_3a_buffer(s3a_buf); 1434 list_del(&s3a_buf->list); 1435 kfree(s3a_buf); 1436 } 1437 } 1438 1439 if (asd->params.css_param.dvs_6axis) { 1440 ia_css_dvs2_6axis_config_free(asd->params.css_param.dvs_6axis); 1441 asd->params.css_param.dvs_6axis = NULL; 1442 } 1443 1444 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 1445 list_for_each_entry_safe(md_buf, _md_buf, 1446 &asd->metadata[i], list) { 1447 atomisp_css_free_metadata_buffer(md_buf); 1448 list_del(&md_buf->list); 1449 kfree(md_buf); 1450 } 1451 list_for_each_entry_safe(md_buf, _md_buf, 1452 &asd->metadata_in_css[i], list) { 1453 atomisp_css_free_metadata_buffer(md_buf); 1454 list_del(&md_buf->list); 1455 kfree(md_buf); 1456 } 1457 list_for_each_entry_safe(md_buf, _md_buf, 1458 &asd->metadata_ready[i], list) { 1459 atomisp_css_free_metadata_buffer(md_buf); 1460 list_del(&md_buf->list); 1461 kfree(md_buf); 1462 } 1463 } 1464 asd->params.metadata_width_size = 0; 1465 atomisp_free_metadata_output_buf(asd); 1466 } 1467 1468 int atomisp_css_get_grid_info(struct atomisp_sub_device *asd, 1469 enum ia_css_pipe_id pipe_id, 1470 int source_pad) 1471 { 1472 struct ia_css_pipe_info p_info; 1473 struct ia_css_grid_info old_info; 1474 struct atomisp_device *isp = asd->isp; 1475 int stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); 1476 int md_width = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 1477 stream_config.metadata_config.resolution.width; 1478 1479 memset(&p_info, 0, sizeof(struct ia_css_pipe_info)); 1480 memset(&old_info, 0, sizeof(struct ia_css_grid_info)); 1481 1482 if (ia_css_pipe_get_info( 1483 asd->stream_env[stream_index].pipes[pipe_id], 1484 &p_info) != 0) { 1485 dev_err(isp->dev, "ia_css_pipe_get_info failed\n"); 1486 return -EINVAL; 1487 } 1488 1489 memcpy(&old_info, &asd->params.curr_grid_info, 1490 sizeof(struct ia_css_grid_info)); 1491 memcpy(&asd->params.curr_grid_info, &p_info.grid_info, 1492 sizeof(struct ia_css_grid_info)); 1493 /* 1494 * Record which css pipe enables s3a_grid. 1495 * Currently would have one css pipe that need it 1496 */ 1497 if (asd->params.curr_grid_info.s3a_grid.enable) { 1498 if (asd->params.s3a_enabled_pipe != IA_CSS_PIPE_ID_NUM) 1499 dev_dbg(isp->dev, "css pipe %d enabled s3a grid replaced by: %d.\n", 1500 asd->params.s3a_enabled_pipe, pipe_id); 1501 asd->params.s3a_enabled_pipe = pipe_id; 1502 } 1503 1504 /* If the grid info has not changed and the buffers for 3A and 1505 * DIS statistics buffers are allocated or buffer size would be zero 1506 * then no need to do anything. */ 1507 if (((!memcmp(&old_info, &asd->params.curr_grid_info, sizeof(old_info)) 1508 && asd->params.s3a_user_stat && asd->params.dvs_stat) 1509 || asd->params.curr_grid_info.s3a_grid.width == 0 1510 || asd->params.curr_grid_info.s3a_grid.height == 0) 1511 && asd->params.metadata_width_size == md_width) { 1512 dev_dbg(isp->dev, 1513 "grid info change escape. memcmp=%d, s3a_user_stat=%d,dvs_stat=%d, s3a.width=%d, s3a.height=%d, metadata width =%d\n", 1514 !memcmp(&old_info, &asd->params.curr_grid_info, 1515 sizeof(old_info)), 1516 !!asd->params.s3a_user_stat, !!asd->params.dvs_stat, 1517 asd->params.curr_grid_info.s3a_grid.width, 1518 asd->params.curr_grid_info.s3a_grid.height, 1519 asd->params.metadata_width_size); 1520 return -EINVAL; 1521 } 1522 asd->params.metadata_width_size = md_width; 1523 1524 return 0; 1525 } 1526 1527 int atomisp_alloc_3a_output_buf(struct atomisp_sub_device *asd) 1528 { 1529 if (!asd->params.curr_grid_info.s3a_grid.width || 1530 !asd->params.curr_grid_info.s3a_grid.height) 1531 return 0; 1532 1533 asd->params.s3a_user_stat = ia_css_3a_statistics_allocate( 1534 &asd->params.curr_grid_info.s3a_grid); 1535 if (!asd->params.s3a_user_stat) 1536 return -ENOMEM; 1537 /* 3A statistics. These can be big, so we use vmalloc. */ 1538 asd->params.s3a_output_bytes = 1539 asd->params.curr_grid_info.s3a_grid.width * 1540 asd->params.curr_grid_info.s3a_grid.height * 1541 sizeof(*asd->params.s3a_user_stat->data); 1542 1543 return 0; 1544 } 1545 1546 int atomisp_alloc_dis_coef_buf(struct atomisp_sub_device *asd) 1547 { 1548 struct ia_css_dvs_grid_info *dvs_grid = 1549 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 1550 1551 if (!dvs_grid) 1552 return 0; 1553 1554 if (!dvs_grid->enable) { 1555 dev_dbg(asd->isp->dev, "%s: dvs_grid not enabled.\n", __func__); 1556 return 0; 1557 } 1558 1559 /* DIS coefficients. */ 1560 asd->params.css_param.dvs2_coeff = ia_css_dvs2_coefficients_allocate( 1561 dvs_grid); 1562 if (!asd->params.css_param.dvs2_coeff) 1563 return -ENOMEM; 1564 1565 asd->params.dvs_hor_coef_bytes = dvs_grid->num_hor_coefs * 1566 sizeof(*asd->params.css_param.dvs2_coeff->hor_coefs.odd_real); 1567 1568 asd->params.dvs_ver_coef_bytes = dvs_grid->num_ver_coefs * 1569 sizeof(*asd->params.css_param.dvs2_coeff->ver_coefs.odd_real); 1570 1571 /* DIS projections. */ 1572 asd->params.dis_proj_data_valid = false; 1573 asd->params.dvs_stat = ia_css_dvs2_statistics_allocate(dvs_grid); 1574 if (!asd->params.dvs_stat) 1575 return -ENOMEM; 1576 1577 asd->params.dvs_hor_proj_bytes = 1578 dvs_grid->aligned_height * dvs_grid->aligned_width * 1579 sizeof(*asd->params.dvs_stat->hor_prod.odd_real); 1580 1581 asd->params.dvs_ver_proj_bytes = 1582 dvs_grid->aligned_height * dvs_grid->aligned_width * 1583 sizeof(*asd->params.dvs_stat->ver_prod.odd_real); 1584 1585 return 0; 1586 } 1587 1588 int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd) 1589 { 1590 int i; 1591 1592 /* We allocate the cpu-side buffer used for communication with user 1593 * space */ 1594 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 1595 asd->params.metadata_user[i] = kvmalloc( 1596 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 1597 stream_info.metadata_info.size, GFP_KERNEL); 1598 if (!asd->params.metadata_user[i]) { 1599 while (--i >= 0) { 1600 kvfree(asd->params.metadata_user[i]); 1601 asd->params.metadata_user[i] = NULL; 1602 } 1603 return -ENOMEM; 1604 } 1605 } 1606 1607 return 0; 1608 } 1609 1610 void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd) 1611 { 1612 unsigned int i; 1613 1614 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 1615 if (asd->params.metadata_user[i]) { 1616 kvfree(asd->params.metadata_user[i]); 1617 asd->params.metadata_user[i] = NULL; 1618 } 1619 } 1620 } 1621 1622 void atomisp_css_get_dis_statistics(struct atomisp_sub_device *asd, 1623 struct atomisp_css_buffer *isp_css_buffer, 1624 struct ia_css_isp_dvs_statistics_map *dvs_map) 1625 { 1626 if (asd->params.dvs_stat) { 1627 if (dvs_map) 1628 ia_css_translate_dvs2_statistics( 1629 asd->params.dvs_stat, dvs_map); 1630 else 1631 ia_css_get_dvs2_statistics(asd->params.dvs_stat, 1632 isp_css_buffer->css_buffer.data.stats_dvs); 1633 } 1634 } 1635 1636 int atomisp_css_dequeue_event(struct atomisp_css_event *current_event) 1637 { 1638 if (ia_css_dequeue_event(¤t_event->event)) 1639 return -EINVAL; 1640 1641 return 0; 1642 } 1643 1644 void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd, 1645 struct atomisp_css_event *current_event) 1646 { 1647 /* 1648 * FIXME! 1649 * Pipe ID reported in CSS event is not correct for new system's 1650 * copy pipe. 1651 * VIED BZ: 1463 1652 */ 1653 ia_css_temp_pipe_to_pipe_id(current_event->event.pipe, 1654 ¤t_event->pipe); 1655 if (asd && asd->copy_mode && 1656 current_event->pipe == IA_CSS_PIPE_ID_CAPTURE) 1657 current_event->pipe = IA_CSS_PIPE_ID_COPY; 1658 } 1659 1660 int atomisp_css_isys_set_resolution(struct atomisp_sub_device *asd, 1661 enum atomisp_input_stream_id stream_id, 1662 struct v4l2_mbus_framefmt *ffmt, 1663 int isys_stream) 1664 { 1665 struct ia_css_stream_config *s_config = 1666 &asd->stream_env[stream_id].stream_config; 1667 1668 if (isys_stream >= IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH) 1669 return -EINVAL; 1670 1671 s_config->isys_config[isys_stream].input_res.width = ffmt->width; 1672 s_config->isys_config[isys_stream].input_res.height = ffmt->height; 1673 return 0; 1674 } 1675 1676 int atomisp_css_input_set_resolution(struct atomisp_sub_device *asd, 1677 enum atomisp_input_stream_id stream_id, 1678 struct v4l2_mbus_framefmt *ffmt) 1679 { 1680 struct ia_css_stream_config *s_config = 1681 &asd->stream_env[stream_id].stream_config; 1682 1683 s_config->input_config.input_res.width = ffmt->width; 1684 s_config->input_config.input_res.height = ffmt->height; 1685 return 0; 1686 } 1687 1688 void atomisp_css_input_set_binning_factor(struct atomisp_sub_device *asd, 1689 enum atomisp_input_stream_id stream_id, 1690 unsigned int bin_factor) 1691 { 1692 asd->stream_env[stream_id] 1693 .stream_config.sensor_binning_factor = bin_factor; 1694 } 1695 1696 void atomisp_css_input_set_bayer_order(struct atomisp_sub_device *asd, 1697 enum atomisp_input_stream_id stream_id, 1698 enum ia_css_bayer_order bayer_order) 1699 { 1700 struct ia_css_stream_config *s_config = 1701 &asd->stream_env[stream_id].stream_config; 1702 s_config->input_config.bayer_order = bayer_order; 1703 } 1704 1705 void atomisp_css_isys_set_link(struct atomisp_sub_device *asd, 1706 enum atomisp_input_stream_id stream_id, 1707 int link, 1708 int isys_stream) 1709 { 1710 struct ia_css_stream_config *s_config = 1711 &asd->stream_env[stream_id].stream_config; 1712 1713 s_config->isys_config[isys_stream].linked_isys_stream_id = link; 1714 } 1715 1716 void atomisp_css_isys_set_valid(struct atomisp_sub_device *asd, 1717 enum atomisp_input_stream_id stream_id, 1718 bool valid, 1719 int isys_stream) 1720 { 1721 struct ia_css_stream_config *s_config = 1722 &asd->stream_env[stream_id].stream_config; 1723 1724 s_config->isys_config[isys_stream].valid = valid; 1725 } 1726 1727 void atomisp_css_isys_set_format(struct atomisp_sub_device *asd, 1728 enum atomisp_input_stream_id stream_id, 1729 enum atomisp_input_format format, 1730 int isys_stream) 1731 { 1732 struct ia_css_stream_config *s_config = 1733 &asd->stream_env[stream_id].stream_config; 1734 1735 s_config->isys_config[isys_stream].format = format; 1736 } 1737 1738 void atomisp_css_input_set_format(struct atomisp_sub_device *asd, 1739 enum atomisp_input_stream_id stream_id, 1740 enum atomisp_input_format format) 1741 { 1742 struct ia_css_stream_config *s_config = 1743 &asd->stream_env[stream_id].stream_config; 1744 1745 s_config->input_config.format = format; 1746 } 1747 1748 int atomisp_css_set_default_isys_config(struct atomisp_sub_device *asd, 1749 enum atomisp_input_stream_id stream_id, 1750 struct v4l2_mbus_framefmt *ffmt) 1751 { 1752 int i; 1753 struct ia_css_stream_config *s_config = 1754 &asd->stream_env[stream_id].stream_config; 1755 /* 1756 * Set all isys configs to not valid. 1757 * Currently we support only one stream per channel 1758 */ 1759 for (i = IA_CSS_STREAM_ISYS_STREAM_0; 1760 i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) 1761 s_config->isys_config[i].valid = false; 1762 1763 atomisp_css_isys_set_resolution(asd, stream_id, ffmt, 1764 IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 1765 atomisp_css_isys_set_format(asd, stream_id, 1766 s_config->input_config.format, 1767 IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 1768 atomisp_css_isys_set_link(asd, stream_id, NO_LINK, 1769 IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 1770 atomisp_css_isys_set_valid(asd, stream_id, true, 1771 IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 1772 1773 return 0; 1774 } 1775 1776 int atomisp_css_isys_two_stream_cfg(struct atomisp_sub_device *asd, 1777 enum atomisp_input_stream_id stream_id, 1778 enum atomisp_input_format input_format) 1779 { 1780 struct ia_css_stream_config *s_config = 1781 &asd->stream_env[stream_id].stream_config; 1782 1783 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width = 1784 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width; 1785 1786 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height = 1787 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height / 2; 1788 1789 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id 1790 = IA_CSS_STREAM_ISYS_STREAM_0; 1791 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format = 1792 ATOMISP_INPUT_FORMAT_USER_DEF1; 1793 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format = 1794 ATOMISP_INPUT_FORMAT_USER_DEF2; 1795 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true; 1796 return 0; 1797 } 1798 1799 void atomisp_css_isys_two_stream_cfg_update_stream1( 1800 struct atomisp_sub_device *asd, 1801 enum atomisp_input_stream_id stream_id, 1802 enum atomisp_input_format input_format, 1803 unsigned int width, unsigned int height) 1804 { 1805 struct ia_css_stream_config *s_config = 1806 &asd->stream_env[stream_id].stream_config; 1807 1808 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width = 1809 width; 1810 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height = 1811 height; 1812 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format = 1813 input_format; 1814 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].valid = true; 1815 } 1816 1817 void atomisp_css_isys_two_stream_cfg_update_stream2( 1818 struct atomisp_sub_device *asd, 1819 enum atomisp_input_stream_id stream_id, 1820 enum atomisp_input_format input_format, 1821 unsigned int width, unsigned int height) 1822 { 1823 struct ia_css_stream_config *s_config = 1824 &asd->stream_env[stream_id].stream_config; 1825 1826 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width = 1827 width; 1828 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height = 1829 height; 1830 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id 1831 = IA_CSS_STREAM_ISYS_STREAM_0; 1832 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format = 1833 input_format; 1834 s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true; 1835 } 1836 1837 int atomisp_css_input_set_effective_resolution( 1838 struct atomisp_sub_device *asd, 1839 enum atomisp_input_stream_id stream_id, 1840 unsigned int width, unsigned int height) 1841 { 1842 struct ia_css_stream_config *s_config = 1843 &asd->stream_env[stream_id].stream_config; 1844 s_config->input_config.effective_res.width = width; 1845 s_config->input_config.effective_res.height = height; 1846 return 0; 1847 } 1848 1849 void atomisp_css_video_set_dis_envelope(struct atomisp_sub_device *asd, 1850 unsigned int dvs_w, unsigned int dvs_h) 1851 { 1852 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1853 .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.width = dvs_w; 1854 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1855 .pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.height = dvs_h; 1856 } 1857 1858 void atomisp_css_input_set_two_pixels_per_clock( 1859 struct atomisp_sub_device *asd, 1860 bool two_ppc) 1861 { 1862 int i; 1863 1864 if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1865 .stream_config.pixels_per_clock == (two_ppc ? 2 : 1)) 1866 return; 1867 1868 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1869 .stream_config.pixels_per_clock = (two_ppc ? 2 : 1); 1870 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 1871 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1872 .update_pipe[i] = true; 1873 } 1874 1875 void atomisp_css_enable_raw_binning(struct atomisp_sub_device *asd, 1876 bool enable) 1877 { 1878 struct atomisp_stream_env *stream_env = 1879 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 1880 unsigned int pipe; 1881 1882 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) 1883 pipe = IA_CSS_PIPE_ID_VIDEO; 1884 else 1885 pipe = IA_CSS_PIPE_ID_PREVIEW; 1886 1887 stream_env->pipe_extra_configs[pipe].enable_raw_binning = enable; 1888 stream_env->update_pipe[pipe] = true; 1889 if (enable) 1890 stream_env->pipe_configs[pipe].output_info[0].padded_width = 1891 stream_env->stream_config.input_config.effective_res.width; 1892 } 1893 1894 void atomisp_css_enable_dz(struct atomisp_sub_device *asd, bool enable) 1895 { 1896 int i; 1897 1898 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 1899 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1900 .pipe_configs[i].enable_dz = enable; 1901 } 1902 1903 void atomisp_css_capture_set_mode(struct atomisp_sub_device *asd, 1904 enum ia_css_capture_mode mode) 1905 { 1906 struct atomisp_stream_env *stream_env = 1907 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 1908 1909 if (stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE] 1910 .default_capture_config.mode == mode) 1911 return; 1912 1913 stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. 1914 default_capture_config.mode = mode; 1915 stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; 1916 } 1917 1918 void atomisp_css_input_set_mode(struct atomisp_sub_device *asd, 1919 enum ia_css_input_mode mode) 1920 { 1921 int i; 1922 struct atomisp_device *isp = asd->isp; 1923 unsigned int size_mem_words; 1924 1925 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) 1926 asd->stream_env[i].stream_config.mode = mode; 1927 1928 if (isp->inputs[asd->input_curr].type == TEST_PATTERN) { 1929 struct ia_css_stream_config *s_config = 1930 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_config; 1931 s_config->mode = IA_CSS_INPUT_MODE_TPG; 1932 s_config->source.tpg.mode = IA_CSS_TPG_MODE_CHECKERBOARD; 1933 s_config->source.tpg.x_mask = (1 << 4) - 1; 1934 s_config->source.tpg.x_delta = -2; 1935 s_config->source.tpg.y_mask = (1 << 4) - 1; 1936 s_config->source.tpg.y_delta = 3; 1937 s_config->source.tpg.xy_mask = (1 << 8) - 1; 1938 return; 1939 } 1940 1941 if (mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) 1942 return; 1943 1944 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 1945 /* 1946 * TODO: sensor needs to export the embedded_data_size_words 1947 * information to atomisp for each setting. 1948 * Here using a large safe value. 1949 */ 1950 struct ia_css_stream_config *s_config = 1951 &asd->stream_env[i].stream_config; 1952 1953 if (s_config->input_config.input_res.width == 0) 1954 continue; 1955 1956 if (ia_css_mipi_frame_calculate_size( 1957 s_config->input_config.input_res.width, 1958 s_config->input_config.input_res.height, 1959 s_config->input_config.format, 1960 true, 1961 0x13000, 1962 &size_mem_words) != 0) { 1963 if (intel_mid_identify_cpu() == 1964 INTEL_MID_CPU_CHIP_TANGIER) 1965 size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_2; 1966 else 1967 size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_1; 1968 dev_warn(asd->isp->dev, 1969 "ia_css_mipi_frame_calculate_size failed,applying pre-defined MIPI buffer size %u.\n", 1970 size_mem_words); 1971 } 1972 s_config->mipi_buffer_config.size_mem_words = size_mem_words; 1973 s_config->mipi_buffer_config.nof_mipi_buffers = 2; 1974 } 1975 } 1976 1977 void atomisp_css_capture_enable_online(struct atomisp_sub_device *asd, 1978 unsigned short stream_index, bool enable) 1979 { 1980 struct atomisp_stream_env *stream_env = 1981 &asd->stream_env[stream_index]; 1982 1983 if (stream_env->stream_config.online == !!enable) 1984 return; 1985 1986 stream_env->stream_config.online = !!enable; 1987 stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; 1988 } 1989 1990 void atomisp_css_preview_enable_online(struct atomisp_sub_device *asd, 1991 unsigned short stream_index, bool enable) 1992 { 1993 struct atomisp_stream_env *stream_env = 1994 &asd->stream_env[stream_index]; 1995 int i; 1996 1997 if (stream_env->stream_config.online != !!enable) { 1998 stream_env->stream_config.online = !!enable; 1999 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 2000 stream_env->update_pipe[i] = true; 2001 } 2002 } 2003 2004 void atomisp_css_video_enable_online(struct atomisp_sub_device *asd, 2005 bool enable) 2006 { 2007 struct atomisp_stream_env *stream_env = 2008 &asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO]; 2009 int i; 2010 2011 if (stream_env->stream_config.online != enable) { 2012 stream_env->stream_config.online = enable; 2013 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 2014 stream_env->update_pipe[i] = true; 2015 } 2016 } 2017 2018 void atomisp_css_enable_continuous(struct atomisp_sub_device *asd, 2019 bool enable) 2020 { 2021 struct atomisp_stream_env *stream_env = 2022 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2023 int i; 2024 2025 /* 2026 * To SOC camera, there is only one YUVPP pipe in any case 2027 * including ZSL/SDV/continuous viewfinder, so always set 2028 * stream_config.continuous to 0. 2029 */ 2030 if (ATOMISP_USE_YUVPP(asd)) { 2031 stream_env->stream_config.continuous = 0; 2032 stream_env->stream_config.online = 1; 2033 return; 2034 } 2035 2036 if (stream_env->stream_config.continuous != !!enable) { 2037 stream_env->stream_config.continuous = !!enable; 2038 stream_env->stream_config.pack_raw_pixels = true; 2039 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 2040 stream_env->update_pipe[i] = true; 2041 } 2042 } 2043 2044 void atomisp_css_enable_cvf(struct atomisp_sub_device *asd, 2045 bool enable) 2046 { 2047 struct atomisp_stream_env *stream_env = 2048 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2049 int i; 2050 2051 if (stream_env->stream_config.disable_cont_viewfinder != !enable) { 2052 stream_env->stream_config.disable_cont_viewfinder = !enable; 2053 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 2054 stream_env->update_pipe[i] = true; 2055 } 2056 } 2057 2058 int atomisp_css_input_configure_port( 2059 struct atomisp_sub_device *asd, 2060 enum mipi_port_id port, 2061 unsigned int num_lanes, 2062 unsigned int timeout, 2063 unsigned int mipi_freq, 2064 enum atomisp_input_format metadata_format, 2065 unsigned int metadata_width, 2066 unsigned int metadata_height) 2067 { 2068 int i; 2069 struct atomisp_stream_env *stream_env; 2070 /* 2071 * Calculate rx_count as follows: 2072 * Input: mipi_freq : CSI-2 bus frequency in Hz 2073 * UI = 1 / (2 * mipi_freq) : period of one bit on the bus 2074 * min = 85e-9 + 6 * UI : Limits for rx_count in seconds 2075 * max = 145e-9 + 10 * UI 2076 * rxcount0 = min / (4 / mipi_freq) : convert seconds to byte clocks 2077 * rxcount = rxcount0 - 2 : adjust for better results 2078 * The formula below is simplified version of the above with 2079 * 10-bit fixed points for improved accuracy. 2080 */ 2081 const unsigned int rxcount = 2082 min(((mipi_freq / 46000) - 1280) >> 10, 0xffU) * 0x01010101U; 2083 2084 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 2085 stream_env = &asd->stream_env[i]; 2086 stream_env->stream_config.source.port.port = port; 2087 stream_env->stream_config.source.port.num_lanes = num_lanes; 2088 stream_env->stream_config.source.port.timeout = timeout; 2089 if (mipi_freq) 2090 stream_env->stream_config.source.port.rxcount = rxcount; 2091 stream_env->stream_config. 2092 metadata_config.data_type = metadata_format; 2093 stream_env->stream_config. 2094 metadata_config.resolution.width = metadata_width; 2095 stream_env->stream_config. 2096 metadata_config.resolution.height = metadata_height; 2097 } 2098 2099 return 0; 2100 } 2101 2102 int atomisp_css_frame_allocate(struct ia_css_frame **frame, 2103 unsigned int width, unsigned int height, 2104 enum ia_css_frame_format format, 2105 unsigned int padded_width, 2106 unsigned int raw_bit_depth) 2107 { 2108 if (ia_css_frame_allocate(frame, width, height, format, 2109 padded_width, raw_bit_depth) != 0) 2110 return -ENOMEM; 2111 2112 return 0; 2113 } 2114 2115 int atomisp_css_frame_allocate_from_info(struct ia_css_frame **frame, 2116 const struct ia_css_frame_info *info) 2117 { 2118 if (ia_css_frame_allocate_from_info(frame, info)) 2119 return -ENOMEM; 2120 2121 return 0; 2122 } 2123 2124 void atomisp_css_frame_free(struct ia_css_frame *frame) 2125 { 2126 ia_css_frame_free(frame); 2127 } 2128 2129 int atomisp_css_frame_map(struct ia_css_frame **frame, 2130 const struct ia_css_frame_info *info, 2131 const void __user *data, uint16_t attribute, 2132 unsigned int pgnr) 2133 { 2134 if (ia_css_frame_map(frame, info, data, attribute, pgnr) 2135 != 0) 2136 return -ENOMEM; 2137 2138 return 0; 2139 } 2140 2141 int atomisp_css_set_black_frame(struct atomisp_sub_device *asd, 2142 const struct ia_css_frame *raw_black_frame) 2143 { 2144 if (sh_css_set_black_frame( 2145 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 2146 raw_black_frame) != 0) 2147 return -ENOMEM; 2148 2149 return 0; 2150 } 2151 2152 int atomisp_css_allocate_continuous_frames(bool init_time, 2153 struct atomisp_sub_device *asd) 2154 { 2155 if (ia_css_alloc_continuous_frame_remain( 2156 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) 2157 != 0) 2158 return -EINVAL; 2159 return 0; 2160 } 2161 2162 void atomisp_css_update_continuous_frames(struct atomisp_sub_device *asd) 2163 { 2164 ia_css_update_continuous_frames( 2165 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream); 2166 } 2167 2168 int atomisp_css_stop(struct atomisp_sub_device *asd, 2169 enum ia_css_pipe_id pipe_id, bool in_reset) 2170 { 2171 struct atomisp_device *isp = asd->isp; 2172 struct atomisp_s3a_buf *s3a_buf; 2173 struct atomisp_dis_buf *dis_buf; 2174 struct atomisp_metadata_buf *md_buf; 2175 unsigned long irqflags; 2176 unsigned int i; 2177 2178 /* if is called in atomisp_reset(), force destroy stream */ 2179 if (__destroy_streams(asd, true)) 2180 dev_err(isp->dev, "destroy stream failed.\n"); 2181 2182 /* if is called in atomisp_reset(), force destroy all pipes */ 2183 if (__destroy_pipes(asd, true)) 2184 dev_err(isp->dev, "destroy pipes failed.\n"); 2185 2186 atomisp_init_raw_buffer_bitmap(asd); 2187 2188 /* 2189 * SP can not be stop if other streams are in use 2190 */ 2191 if (atomisp_streaming_count(isp) == 0) 2192 ia_css_stop_sp(); 2193 2194 if (!in_reset) { 2195 struct atomisp_stream_env *stream_env; 2196 int i, j; 2197 2198 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { 2199 stream_env = &asd->stream_env[i]; 2200 for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) { 2201 ia_css_pipe_config_defaults( 2202 &stream_env->pipe_configs[j]); 2203 ia_css_pipe_extra_config_defaults( 2204 &stream_env->pipe_extra_configs[j]); 2205 } 2206 ia_css_stream_config_defaults( 2207 &stream_env->stream_config); 2208 } 2209 memset(&asd->params.config, 0, sizeof(asd->params.config)); 2210 asd->params.css_update_params_needed = false; 2211 } 2212 2213 /* move stats buffers to free queue list */ 2214 while (!list_empty(&asd->s3a_stats_in_css)) { 2215 s3a_buf = list_entry(asd->s3a_stats_in_css.next, 2216 struct atomisp_s3a_buf, list); 2217 list_del(&s3a_buf->list); 2218 list_add_tail(&s3a_buf->list, &asd->s3a_stats); 2219 } 2220 while (!list_empty(&asd->s3a_stats_ready)) { 2221 s3a_buf = list_entry(asd->s3a_stats_ready.next, 2222 struct atomisp_s3a_buf, list); 2223 list_del(&s3a_buf->list); 2224 list_add_tail(&s3a_buf->list, &asd->s3a_stats); 2225 } 2226 2227 spin_lock_irqsave(&asd->dis_stats_lock, irqflags); 2228 while (!list_empty(&asd->dis_stats_in_css)) { 2229 dis_buf = list_entry(asd->dis_stats_in_css.next, 2230 struct atomisp_dis_buf, list); 2231 list_del(&dis_buf->list); 2232 list_add_tail(&dis_buf->list, &asd->dis_stats); 2233 } 2234 asd->params.dis_proj_data_valid = false; 2235 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); 2236 2237 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 2238 while (!list_empty(&asd->metadata_in_css[i])) { 2239 md_buf = list_entry(asd->metadata_in_css[i].next, 2240 struct atomisp_metadata_buf, list); 2241 list_del(&md_buf->list); 2242 list_add_tail(&md_buf->list, &asd->metadata[i]); 2243 } 2244 while (!list_empty(&asd->metadata_ready[i])) { 2245 md_buf = list_entry(asd->metadata_ready[i].next, 2246 struct atomisp_metadata_buf, list); 2247 list_del(&md_buf->list); 2248 list_add_tail(&md_buf->list, &asd->metadata[i]); 2249 } 2250 } 2251 2252 atomisp_flush_params_queue(&asd->video_out_capture); 2253 atomisp_flush_params_queue(&asd->video_out_vf); 2254 atomisp_flush_params_queue(&asd->video_out_preview); 2255 atomisp_flush_params_queue(&asd->video_out_video_capture); 2256 atomisp_free_css_parameters(&asd->params.css_param); 2257 memset(&asd->params.css_param, 0, sizeof(asd->params.css_param)); 2258 return 0; 2259 } 2260 2261 int atomisp_css_continuous_set_num_raw_frames( 2262 struct atomisp_sub_device *asd, 2263 int num_frames) 2264 { 2265 if (asd->enable_raw_buffer_lock->val) { 2266 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2267 .stream_config.init_num_cont_raw_buf = 2268 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN; 2269 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 2270 asd->params.video_dis_en) 2271 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2272 .stream_config.init_num_cont_raw_buf += 2273 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; 2274 } else { 2275 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2276 .stream_config.init_num_cont_raw_buf = 2277 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES; 2278 } 2279 2280 if (asd->params.video_dis_en) 2281 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2282 .stream_config.init_num_cont_raw_buf += 2283 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; 2284 2285 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2286 .stream_config.target_num_cont_raw_buf = num_frames; 2287 return 0; 2288 } 2289 2290 void atomisp_css_disable_vf_pp(struct atomisp_sub_device *asd, 2291 bool disable) 2292 { 2293 int i; 2294 2295 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 2296 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2297 .pipe_extra_configs[i].disable_vf_pp = !!disable; 2298 } 2299 2300 static enum ia_css_pipe_mode __pipe_id_to_pipe_mode( 2301 struct atomisp_sub_device *asd, 2302 enum ia_css_pipe_id pipe_id) 2303 { 2304 struct atomisp_device *isp = asd->isp; 2305 struct camera_mipi_info *mipi_info = atomisp_to_sensor_mipi_info( 2306 isp->inputs[asd->input_curr].camera); 2307 2308 switch (pipe_id) { 2309 case IA_CSS_PIPE_ID_COPY: 2310 /* Currently only YUVPP mode supports YUV420_Legacy format. 2311 * Revert this when other pipe modes can support 2312 * YUV420_Legacy format. 2313 */ 2314 if (mipi_info && mipi_info->input_format == 2315 ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) 2316 return IA_CSS_PIPE_MODE_YUVPP; 2317 return IA_CSS_PIPE_MODE_COPY; 2318 case IA_CSS_PIPE_ID_PREVIEW: 2319 return IA_CSS_PIPE_MODE_PREVIEW; 2320 case IA_CSS_PIPE_ID_CAPTURE: 2321 return IA_CSS_PIPE_MODE_CAPTURE; 2322 case IA_CSS_PIPE_ID_VIDEO: 2323 return IA_CSS_PIPE_MODE_VIDEO; 2324 case IA_CSS_PIPE_ID_ACC: 2325 return IA_CSS_PIPE_MODE_ACC; 2326 case IA_CSS_PIPE_ID_YUVPP: 2327 return IA_CSS_PIPE_MODE_YUVPP; 2328 default: 2329 WARN_ON(1); 2330 return IA_CSS_PIPE_MODE_PREVIEW; 2331 } 2332 } 2333 2334 static void __configure_output(struct atomisp_sub_device *asd, 2335 unsigned int stream_index, 2336 unsigned int width, unsigned int height, 2337 unsigned int min_width, 2338 enum ia_css_frame_format format, 2339 enum ia_css_pipe_id pipe_id) 2340 { 2341 struct atomisp_device *isp = asd->isp; 2342 struct atomisp_stream_env *stream_env = 2343 &asd->stream_env[stream_index]; 2344 struct ia_css_stream_config *s_config = &stream_env->stream_config; 2345 2346 stream_env->pipe_configs[pipe_id].mode = 2347 __pipe_id_to_pipe_mode(asd, pipe_id); 2348 stream_env->update_pipe[pipe_id] = true; 2349 2350 stream_env->pipe_configs[pipe_id].output_info[0].res.width = width; 2351 stream_env->pipe_configs[pipe_id].output_info[0].res.height = height; 2352 stream_env->pipe_configs[pipe_id].output_info[0].format = format; 2353 stream_env->pipe_configs[pipe_id].output_info[0].padded_width = min_width; 2354 2355 /* isp binary 2.2 specific setting*/ 2356 if (width > s_config->input_config.effective_res.width || 2357 height > s_config->input_config.effective_res.height) { 2358 s_config->input_config.effective_res.width = width; 2359 s_config->input_config.effective_res.height = height; 2360 } 2361 2362 dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n", 2363 pipe_id, width, height, format); 2364 } 2365 2366 static void __configure_video_preview_output(struct atomisp_sub_device *asd, 2367 unsigned int stream_index, 2368 unsigned int width, unsigned int height, 2369 unsigned int min_width, 2370 enum ia_css_frame_format format, 2371 enum ia_css_pipe_id pipe_id) 2372 { 2373 struct atomisp_device *isp = asd->isp; 2374 struct atomisp_stream_env *stream_env = 2375 &asd->stream_env[stream_index]; 2376 struct ia_css_frame_info *css_output_info; 2377 struct ia_css_stream_config *stream_config = &stream_env->stream_config; 2378 2379 stream_env->pipe_configs[pipe_id].mode = 2380 __pipe_id_to_pipe_mode(asd, pipe_id); 2381 stream_env->update_pipe[pipe_id] = true; 2382 2383 /* 2384 * second_output will be as video main output in SDV mode 2385 * with SOC camera. output will be as video main output in 2386 * normal video mode. 2387 */ 2388 if (asd->continuous_mode->val) 2389 css_output_info = &stream_env->pipe_configs[pipe_id]. 2390 output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; 2391 else 2392 css_output_info = &stream_env->pipe_configs[pipe_id]. 2393 output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; 2394 2395 css_output_info->res.width = width; 2396 css_output_info->res.height = height; 2397 css_output_info->format = format; 2398 css_output_info->padded_width = min_width; 2399 2400 /* isp binary 2.2 specific setting*/ 2401 if (width > stream_config->input_config.effective_res.width || 2402 height > stream_config->input_config.effective_res.height) { 2403 stream_config->input_config.effective_res.width = width; 2404 stream_config->input_config.effective_res.height = height; 2405 } 2406 2407 dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n", 2408 pipe_id, width, height, format); 2409 } 2410 2411 /* 2412 * For CSS2.1, capture pipe uses capture_pp_in_res to configure yuv 2413 * downscaling input resolution. 2414 */ 2415 static void __configure_capture_pp_input(struct atomisp_sub_device *asd, 2416 unsigned int width, unsigned int height, 2417 enum ia_css_pipe_id pipe_id) 2418 { 2419 struct atomisp_device *isp = asd->isp; 2420 struct atomisp_stream_env *stream_env = 2421 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2422 struct ia_css_stream_config *stream_config = &stream_env->stream_config; 2423 struct ia_css_pipe_config *pipe_configs = 2424 &stream_env->pipe_configs[pipe_id]; 2425 struct ia_css_pipe_extra_config *pipe_extra_configs = 2426 &stream_env->pipe_extra_configs[pipe_id]; 2427 unsigned int hor_ds_factor = 0, ver_ds_factor = 0; 2428 2429 if (width == 0 && height == 0) 2430 return; 2431 2432 if (width * 9 / 10 < pipe_configs->output_info[0].res.width || 2433 height * 9 / 10 < pipe_configs->output_info[0].res.height) 2434 return; 2435 /* here just copy the calculation in css */ 2436 hor_ds_factor = CEIL_DIV(width >> 1, 2437 pipe_configs->output_info[0].res.width); 2438 ver_ds_factor = CEIL_DIV(height >> 1, 2439 pipe_configs->output_info[0].res.height); 2440 2441 if ((asd->isp->media_dev.hw_revision < 2442 (ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) || 2443 IS_CHT) && hor_ds_factor != ver_ds_factor) { 2444 dev_warn(asd->isp->dev, 2445 "Cropping for capture due to FW limitation"); 2446 return; 2447 } 2448 2449 pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); 2450 stream_env->update_pipe[pipe_id] = true; 2451 2452 pipe_extra_configs->enable_yuv_ds = true; 2453 2454 pipe_configs->capt_pp_in_res.width = 2455 stream_config->input_config.effective_res.width; 2456 pipe_configs->capt_pp_in_res.height = 2457 stream_config->input_config.effective_res.height; 2458 2459 dev_dbg(isp->dev, "configuring pipe[%d]capture pp input w=%d.h=%d.\n", 2460 pipe_id, width, height); 2461 } 2462 2463 /* 2464 * For CSS2.1, preview pipe could support bayer downscaling, yuv decimation and 2465 * yuv downscaling, which needs addtional configurations. 2466 */ 2467 static void __configure_preview_pp_input(struct atomisp_sub_device *asd, 2468 unsigned int width, unsigned int height, 2469 enum ia_css_pipe_id pipe_id) 2470 { 2471 struct atomisp_device *isp = asd->isp; 2472 int out_width, out_height, yuv_ds_in_width, yuv_ds_in_height; 2473 struct atomisp_stream_env *stream_env = 2474 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2475 struct ia_css_stream_config *stream_config = &stream_env->stream_config; 2476 struct ia_css_pipe_config *pipe_configs = 2477 &stream_env->pipe_configs[pipe_id]; 2478 struct ia_css_pipe_extra_config *pipe_extra_configs = 2479 &stream_env->pipe_extra_configs[pipe_id]; 2480 struct ia_css_resolution *bayer_ds_out_res = 2481 &pipe_configs->bayer_ds_out_res; 2482 struct ia_css_resolution *vf_pp_in_res = 2483 &pipe_configs->vf_pp_in_res; 2484 struct ia_css_resolution *effective_res = 2485 &stream_config->input_config.effective_res; 2486 2487 const struct bayer_ds_factor bds_fct[] = {{2, 1}, {3, 2}, {5, 4} }; 2488 /* 2489 * BZ201033: YUV decimation factor of 4 causes couple of rightmost 2490 * columns to be shaded. Remove this factor to work around the CSS bug. 2491 * const unsigned int yuv_dec_fct[] = {4, 2}; 2492 */ 2493 const unsigned int yuv_dec_fct[] = { 2 }; 2494 unsigned int i; 2495 2496 if (width == 0 && height == 0) 2497 return; 2498 2499 pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); 2500 stream_env->update_pipe[pipe_id] = true; 2501 2502 out_width = pipe_configs->output_info[0].res.width; 2503 out_height = pipe_configs->output_info[0].res.height; 2504 2505 /* 2506 * The ISP could do bayer downscaling, yuv decimation and yuv 2507 * downscaling: 2508 * 1: Bayer Downscaling: between effective resolution and 2509 * bayer_ds_res_out; 2510 * 2: YUV Decimation: between bayer_ds_res_out and vf_pp_in_res; 2511 * 3: YUV Downscaling: between vf_pp_in_res and final vf output 2512 * 2513 * Rule for Bayer Downscaling: support factor 2, 1.5 and 1.25 2514 * Rule for YUV Decimation: support factor 2, 4 2515 * Rule for YUV Downscaling: arbitrary value below 2 2516 * 2517 * General rule of factor distribution among these stages: 2518 * 1: try to do Bayer downscaling first if not in online mode. 2519 * 2: try to do maximum of 2 for YUV downscaling 2520 * 3: the remainling for YUV decimation 2521 * 2522 * Note: 2523 * Do not configure bayer_ds_out_res if: 2524 * online == 1 or continuous == 0 or raw_binning = 0 2525 */ 2526 if (stream_config->online || !stream_config->continuous || 2527 !pipe_extra_configs->enable_raw_binning) { 2528 bayer_ds_out_res->width = 0; 2529 bayer_ds_out_res->height = 0; 2530 } else { 2531 bayer_ds_out_res->width = effective_res->width; 2532 bayer_ds_out_res->height = effective_res->height; 2533 2534 for (i = 0; i < ARRAY_SIZE(bds_fct); i++) { 2535 if (effective_res->width >= out_width * 2536 bds_fct[i].numerator / bds_fct[i].denominator && 2537 effective_res->height >= out_height * 2538 bds_fct[i].numerator / bds_fct[i].denominator) { 2539 bayer_ds_out_res->width = 2540 effective_res->width * 2541 bds_fct[i].denominator / 2542 bds_fct[i].numerator; 2543 bayer_ds_out_res->height = 2544 effective_res->height * 2545 bds_fct[i].denominator / 2546 bds_fct[i].numerator; 2547 break; 2548 } 2549 } 2550 } 2551 /* 2552 * calculate YUV Decimation, YUV downscaling facor: 2553 * YUV Downscaling factor must not exceed 2. 2554 * YUV Decimation factor could be 2, 4. 2555 */ 2556 /* first decide the yuv_ds input resolution */ 2557 if (bayer_ds_out_res->width == 0) { 2558 yuv_ds_in_width = effective_res->width; 2559 yuv_ds_in_height = effective_res->height; 2560 } else { 2561 yuv_ds_in_width = bayer_ds_out_res->width; 2562 yuv_ds_in_height = bayer_ds_out_res->height; 2563 } 2564 2565 vf_pp_in_res->width = yuv_ds_in_width; 2566 vf_pp_in_res->height = yuv_ds_in_height; 2567 2568 /* find out the yuv decimation factor */ 2569 for (i = 0; i < ARRAY_SIZE(yuv_dec_fct); i++) { 2570 if (yuv_ds_in_width >= out_width * yuv_dec_fct[i] && 2571 yuv_ds_in_height >= out_height * yuv_dec_fct[i]) { 2572 vf_pp_in_res->width = yuv_ds_in_width / yuv_dec_fct[i]; 2573 vf_pp_in_res->height = yuv_ds_in_height / yuv_dec_fct[i]; 2574 break; 2575 } 2576 } 2577 2578 if (vf_pp_in_res->width == out_width && 2579 vf_pp_in_res->height == out_height) { 2580 pipe_extra_configs->enable_yuv_ds = false; 2581 vf_pp_in_res->width = 0; 2582 vf_pp_in_res->height = 0; 2583 } else { 2584 pipe_extra_configs->enable_yuv_ds = true; 2585 } 2586 2587 dev_dbg(isp->dev, "configuring pipe[%d]preview pp input w=%d.h=%d.\n", 2588 pipe_id, width, height); 2589 } 2590 2591 /* 2592 * For CSS2.1, offline video pipe could support bayer decimation, and 2593 * yuv downscaling, which needs addtional configurations. 2594 */ 2595 static void __configure_video_pp_input(struct atomisp_sub_device *asd, 2596 unsigned int width, unsigned int height, 2597 enum ia_css_pipe_id pipe_id) 2598 { 2599 struct atomisp_device *isp = asd->isp; 2600 int out_width, out_height; 2601 struct atomisp_stream_env *stream_env = 2602 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2603 struct ia_css_stream_config *stream_config = &stream_env->stream_config; 2604 struct ia_css_pipe_config *pipe_configs = 2605 &stream_env->pipe_configs[pipe_id]; 2606 struct ia_css_pipe_extra_config *pipe_extra_configs = 2607 &stream_env->pipe_extra_configs[pipe_id]; 2608 struct ia_css_resolution *bayer_ds_out_res = 2609 &pipe_configs->bayer_ds_out_res; 2610 struct ia_css_resolution *effective_res = 2611 &stream_config->input_config.effective_res; 2612 2613 const struct bayer_ds_factor bds_factors[] = { 2614 {8, 1}, {6, 1}, {4, 1}, {3, 1}, {2, 1}, {3, 2} 2615 }; 2616 unsigned int i; 2617 2618 if (width == 0 && height == 0) 2619 return; 2620 2621 pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id); 2622 stream_env->update_pipe[pipe_id] = true; 2623 2624 pipe_extra_configs->enable_yuv_ds = false; 2625 2626 /* 2627 * If DVS is enabled, video binary will take care the dvs envelope 2628 * and usually the bayer_ds_out_res should be larger than 120% of 2629 * destination resolution, the extra 20% will be cropped as DVS 2630 * envelope. But, if the bayer_ds_out_res is less than 120% of the 2631 * destination. The ISP can still work, but DVS quality is not good. 2632 */ 2633 /* taking at least 10% as envelope */ 2634 if (asd->params.video_dis_en) { 2635 out_width = pipe_configs->output_info[0].res.width * 110 / 100; 2636 out_height = pipe_configs->output_info[0].res.height * 110 / 100; 2637 } else { 2638 out_width = pipe_configs->output_info[0].res.width; 2639 out_height = pipe_configs->output_info[0].res.height; 2640 } 2641 2642 /* 2643 * calculate bayer decimate factor: 2644 * 1: only 1.5, 2, 4 and 8 get supported 2645 * 2: Do not configure bayer_ds_out_res if: 2646 * online == 1 or continuous == 0 or raw_binning = 0 2647 */ 2648 if (stream_config->online || !stream_config->continuous) { 2649 bayer_ds_out_res->width = 0; 2650 bayer_ds_out_res->height = 0; 2651 goto done; 2652 } 2653 2654 pipe_extra_configs->enable_raw_binning = true; 2655 bayer_ds_out_res->width = effective_res->width; 2656 bayer_ds_out_res->height = effective_res->height; 2657 2658 for (i = 0; i < sizeof(bds_factors) / sizeof(struct bayer_ds_factor); 2659 i++) { 2660 if (effective_res->width >= out_width * 2661 bds_factors[i].numerator / bds_factors[i].denominator && 2662 effective_res->height >= out_height * 2663 bds_factors[i].numerator / bds_factors[i].denominator) { 2664 bayer_ds_out_res->width = effective_res->width * 2665 bds_factors[i].denominator / 2666 bds_factors[i].numerator; 2667 bayer_ds_out_res->height = effective_res->height * 2668 bds_factors[i].denominator / 2669 bds_factors[i].numerator; 2670 break; 2671 } 2672 } 2673 2674 /* 2675 * DVS is cropped from BDS output, so we do not really need to set the 2676 * envelope to 20% of output resolution here. always set it to 12x12 2677 * per firmware requirement. 2678 */ 2679 pipe_configs->dvs_envelope.width = 12; 2680 pipe_configs->dvs_envelope.height = 12; 2681 2682 done: 2683 if (pipe_id == IA_CSS_PIPE_ID_YUVPP) 2684 stream_config->left_padding = -1; 2685 else 2686 stream_config->left_padding = 12; 2687 dev_dbg(isp->dev, "configuring pipe[%d]video pp input w=%d.h=%d.\n", 2688 pipe_id, width, height); 2689 } 2690 2691 static void __configure_vf_output(struct atomisp_sub_device *asd, 2692 unsigned int width, unsigned int height, 2693 unsigned int min_width, 2694 enum ia_css_frame_format format, 2695 enum ia_css_pipe_id pipe_id) 2696 { 2697 struct atomisp_device *isp = asd->isp; 2698 struct atomisp_stream_env *stream_env = 2699 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2700 stream_env->pipe_configs[pipe_id].mode = 2701 __pipe_id_to_pipe_mode(asd, pipe_id); 2702 stream_env->update_pipe[pipe_id] = true; 2703 2704 stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width; 2705 stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height; 2706 stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format; 2707 stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width = 2708 min_width; 2709 dev_dbg(isp->dev, 2710 "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n", 2711 pipe_id, width, height, format); 2712 } 2713 2714 static void __configure_video_vf_output(struct atomisp_sub_device *asd, 2715 unsigned int width, unsigned int height, 2716 unsigned int min_width, 2717 enum ia_css_frame_format format, 2718 enum ia_css_pipe_id pipe_id) 2719 { 2720 struct atomisp_device *isp = asd->isp; 2721 struct atomisp_stream_env *stream_env = 2722 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2723 struct ia_css_frame_info *css_output_info; 2724 2725 stream_env->pipe_configs[pipe_id].mode = 2726 __pipe_id_to_pipe_mode(asd, pipe_id); 2727 stream_env->update_pipe[pipe_id] = true; 2728 2729 /* 2730 * second_vf_output will be as video viewfinder in SDV mode 2731 * with SOC camera. vf_output will be as video viewfinder in 2732 * normal video mode. 2733 */ 2734 if (asd->continuous_mode->val) 2735 css_output_info = &stream_env->pipe_configs[pipe_id]. 2736 vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; 2737 else 2738 css_output_info = &stream_env->pipe_configs[pipe_id]. 2739 vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; 2740 2741 css_output_info->res.width = width; 2742 css_output_info->res.height = height; 2743 css_output_info->format = format; 2744 css_output_info->padded_width = min_width; 2745 dev_dbg(isp->dev, 2746 "configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n", 2747 pipe_id, width, height, format); 2748 } 2749 2750 static int __get_frame_info(struct atomisp_sub_device *asd, 2751 unsigned int stream_index, 2752 struct ia_css_frame_info *info, 2753 enum frame_info_type type, 2754 enum ia_css_pipe_id pipe_id) 2755 { 2756 struct atomisp_device *isp = asd->isp; 2757 int ret; 2758 struct ia_css_pipe_info p_info; 2759 2760 /* FIXME! No need to destroy/recreate all streams */ 2761 if (__destroy_streams(asd, true)) 2762 dev_warn(isp->dev, "destroy stream failed.\n"); 2763 2764 if (__destroy_pipes(asd, true)) 2765 dev_warn(isp->dev, "destroy pipe failed.\n"); 2766 2767 if (__create_pipes(asd)) 2768 return -EINVAL; 2769 2770 if (__create_streams(asd)) 2771 goto stream_err; 2772 2773 ret = ia_css_pipe_get_info( 2774 asd->stream_env[stream_index] 2775 .pipes[pipe_id], &p_info); 2776 if (!ret) { 2777 switch (type) { 2778 case ATOMISP_CSS_VF_FRAME: 2779 *info = p_info.vf_output_info[0]; 2780 dev_dbg(isp->dev, "getting vf frame info.\n"); 2781 break; 2782 case ATOMISP_CSS_SECOND_VF_FRAME: 2783 *info = p_info.vf_output_info[1]; 2784 dev_dbg(isp->dev, "getting second vf frame info.\n"); 2785 break; 2786 case ATOMISP_CSS_OUTPUT_FRAME: 2787 *info = p_info.output_info[0]; 2788 dev_dbg(isp->dev, "getting main frame info.\n"); 2789 break; 2790 case ATOMISP_CSS_SECOND_OUTPUT_FRAME: 2791 *info = p_info.output_info[1]; 2792 dev_dbg(isp->dev, "getting second main frame info.\n"); 2793 break; 2794 case ATOMISP_CSS_RAW_FRAME: 2795 *info = p_info.raw_output_info; 2796 dev_dbg(isp->dev, "getting raw frame info.\n"); 2797 } 2798 dev_dbg(isp->dev, "get frame info: w=%d, h=%d, num_invalid_frames %d.\n", 2799 info->res.width, info->res.height, p_info.num_invalid_frames); 2800 return 0; 2801 } 2802 2803 stream_err: 2804 __destroy_pipes(asd, true); 2805 return -EINVAL; 2806 } 2807 2808 static unsigned int atomisp_get_pipe_index(struct atomisp_sub_device *asd, 2809 uint16_t source_pad) 2810 { 2811 struct atomisp_device *isp = asd->isp; 2812 /* 2813 * to SOC camera, use yuvpp pipe. 2814 */ 2815 if (ATOMISP_USE_YUVPP(asd)) 2816 return IA_CSS_PIPE_ID_YUVPP; 2817 2818 switch (source_pad) { 2819 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: 2820 if (asd->yuvpp_mode) 2821 return IA_CSS_PIPE_ID_YUVPP; 2822 if (asd->copy_mode) 2823 return IA_CSS_PIPE_ID_COPY; 2824 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO 2825 || asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) 2826 return IA_CSS_PIPE_ID_VIDEO; 2827 else 2828 return IA_CSS_PIPE_ID_CAPTURE; 2829 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: 2830 if (asd->copy_mode) 2831 return IA_CSS_PIPE_ID_COPY; 2832 return IA_CSS_PIPE_ID_CAPTURE; 2833 case ATOMISP_SUBDEV_PAD_SOURCE_VF: 2834 if (!atomisp_is_mbuscode_raw( 2835 asd->fmt[asd->capture_pad].fmt.code)) 2836 return IA_CSS_PIPE_ID_CAPTURE; 2837 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: 2838 if (asd->yuvpp_mode) 2839 return IA_CSS_PIPE_ID_YUVPP; 2840 if (asd->copy_mode) 2841 return IA_CSS_PIPE_ID_COPY; 2842 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) 2843 return IA_CSS_PIPE_ID_VIDEO; 2844 else 2845 return IA_CSS_PIPE_ID_PREVIEW; 2846 } 2847 dev_warn(isp->dev, 2848 "invalid source pad:%d, return default preview pipe index.\n", 2849 source_pad); 2850 return IA_CSS_PIPE_ID_PREVIEW; 2851 } 2852 2853 int atomisp_get_css_frame_info(struct atomisp_sub_device *asd, 2854 u16 source_pad, 2855 struct ia_css_frame_info *frame_info) 2856 { 2857 struct ia_css_pipe_info info; 2858 int pipe_index = atomisp_get_pipe_index(asd, source_pad); 2859 int stream_index; 2860 struct atomisp_device *isp = asd->isp; 2861 2862 if (ATOMISP_SOC_CAMERA(asd)) 2863 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); 2864 else { 2865 stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ? 2866 ATOMISP_INPUT_STREAM_VIDEO : 2867 atomisp_source_pad_to_stream_id(asd, source_pad); 2868 } 2869 2870 if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index] 2871 .pipes[pipe_index], &info)) { 2872 dev_err(isp->dev, "ia_css_pipe_get_info FAILED"); 2873 return -EINVAL; 2874 } 2875 2876 switch (source_pad) { 2877 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: 2878 *frame_info = info.output_info[0]; 2879 break; 2880 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: 2881 if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) 2882 *frame_info = info. 2883 output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; 2884 else 2885 *frame_info = info. 2886 output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; 2887 break; 2888 case ATOMISP_SUBDEV_PAD_SOURCE_VF: 2889 if (stream_index == ATOMISP_INPUT_STREAM_POSTVIEW) 2890 *frame_info = info.output_info[0]; 2891 else 2892 *frame_info = info.vf_output_info[0]; 2893 break; 2894 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: 2895 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 2896 (pipe_index == IA_CSS_PIPE_ID_VIDEO || 2897 pipe_index == IA_CSS_PIPE_ID_YUVPP)) 2898 if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) 2899 *frame_info = info. 2900 vf_output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; 2901 else 2902 *frame_info = info. 2903 vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; 2904 else if (ATOMISP_USE_YUVPP(asd) && asd->continuous_mode->val) 2905 *frame_info = 2906 info.output_info[ATOMISP_CSS_OUTPUT_SECOND_INDEX]; 2907 else 2908 *frame_info = 2909 info.output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX]; 2910 2911 break; 2912 default: 2913 frame_info = NULL; 2914 break; 2915 } 2916 return frame_info ? 0 : -EINVAL; 2917 } 2918 2919 int atomisp_css_copy_configure_output(struct atomisp_sub_device *asd, 2920 unsigned int stream_index, 2921 unsigned int width, unsigned int height, 2922 unsigned int padded_width, 2923 enum ia_css_frame_format format) 2924 { 2925 asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_COPY]. 2926 default_capture_config.mode = 2927 IA_CSS_CAPTURE_MODE_RAW; 2928 2929 __configure_output(asd, stream_index, width, height, padded_width, 2930 format, IA_CSS_PIPE_ID_COPY); 2931 return 0; 2932 } 2933 2934 int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd, 2935 unsigned int stream_index, 2936 unsigned int width, unsigned int height, 2937 unsigned int padded_width, 2938 enum ia_css_frame_format format) 2939 { 2940 asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_YUVPP]. 2941 default_capture_config.mode = 2942 IA_CSS_CAPTURE_MODE_RAW; 2943 2944 __configure_output(asd, stream_index, width, height, padded_width, 2945 format, IA_CSS_PIPE_ID_YUVPP); 2946 return 0; 2947 } 2948 2949 int atomisp_css_yuvpp_configure_viewfinder( 2950 struct atomisp_sub_device *asd, 2951 unsigned int stream_index, 2952 unsigned int width, unsigned int height, 2953 unsigned int min_width, 2954 enum ia_css_frame_format format) 2955 { 2956 struct atomisp_stream_env *stream_env = 2957 &asd->stream_env[stream_index]; 2958 enum ia_css_pipe_id pipe_id = IA_CSS_PIPE_ID_YUVPP; 2959 2960 stream_env->pipe_configs[pipe_id].mode = 2961 __pipe_id_to_pipe_mode(asd, pipe_id); 2962 stream_env->update_pipe[pipe_id] = true; 2963 2964 stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width; 2965 stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height; 2966 stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format; 2967 stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width = 2968 min_width; 2969 return 0; 2970 } 2971 2972 int atomisp_css_yuvpp_get_output_frame_info( 2973 struct atomisp_sub_device *asd, 2974 unsigned int stream_index, 2975 struct ia_css_frame_info *info) 2976 { 2977 return __get_frame_info(asd, stream_index, info, 2978 ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_YUVPP); 2979 } 2980 2981 int atomisp_css_yuvpp_get_viewfinder_frame_info( 2982 struct atomisp_sub_device *asd, 2983 unsigned int stream_index, 2984 struct ia_css_frame_info *info) 2985 { 2986 return __get_frame_info(asd, stream_index, info, 2987 ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_YUVPP); 2988 } 2989 2990 int atomisp_css_preview_configure_output(struct atomisp_sub_device *asd, 2991 unsigned int width, unsigned int height, 2992 unsigned int min_width, 2993 enum ia_css_frame_format format) 2994 { 2995 /* 2996 * to SOC camera, use yuvpp pipe. 2997 */ 2998 if (ATOMISP_USE_YUVPP(asd)) 2999 __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, 3000 height, 3001 min_width, format, IA_CSS_PIPE_ID_YUVPP); 3002 else 3003 __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, 3004 min_width, format, IA_CSS_PIPE_ID_PREVIEW); 3005 return 0; 3006 } 3007 3008 int atomisp_css_capture_configure_output(struct atomisp_sub_device *asd, 3009 unsigned int width, unsigned int height, 3010 unsigned int min_width, 3011 enum ia_css_frame_format format) 3012 { 3013 enum ia_css_pipe_id pipe_id; 3014 3015 /* 3016 * to SOC camera, use yuvpp pipe. 3017 */ 3018 if (ATOMISP_USE_YUVPP(asd)) 3019 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3020 else 3021 pipe_id = IA_CSS_PIPE_ID_CAPTURE; 3022 3023 __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, 3024 min_width, format, pipe_id); 3025 return 0; 3026 } 3027 3028 int atomisp_css_video_configure_output(struct atomisp_sub_device *asd, 3029 unsigned int width, unsigned int height, 3030 unsigned int min_width, 3031 enum ia_css_frame_format format) 3032 { 3033 /* 3034 * to SOC camera, use yuvpp pipe. 3035 */ 3036 if (ATOMISP_USE_YUVPP(asd)) 3037 __configure_video_preview_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, 3038 height, 3039 min_width, format, IA_CSS_PIPE_ID_YUVPP); 3040 else 3041 __configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height, 3042 min_width, format, IA_CSS_PIPE_ID_VIDEO); 3043 return 0; 3044 } 3045 3046 int atomisp_css_video_configure_viewfinder( 3047 struct atomisp_sub_device *asd, 3048 unsigned int width, unsigned int height, 3049 unsigned int min_width, 3050 enum ia_css_frame_format format) 3051 { 3052 /* 3053 * to SOC camera, video will use yuvpp pipe. 3054 */ 3055 if (ATOMISP_USE_YUVPP(asd)) 3056 __configure_video_vf_output(asd, width, height, min_width, format, 3057 IA_CSS_PIPE_ID_YUVPP); 3058 else 3059 __configure_vf_output(asd, width, height, min_width, format, 3060 IA_CSS_PIPE_ID_VIDEO); 3061 return 0; 3062 } 3063 3064 int atomisp_css_capture_configure_viewfinder( 3065 struct atomisp_sub_device *asd, 3066 unsigned int width, unsigned int height, 3067 unsigned int min_width, 3068 enum ia_css_frame_format format) 3069 { 3070 enum ia_css_pipe_id pipe_id; 3071 3072 /* 3073 * to SOC camera, video will use yuvpp pipe. 3074 */ 3075 if (ATOMISP_USE_YUVPP(asd)) 3076 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3077 else 3078 pipe_id = IA_CSS_PIPE_ID_CAPTURE; 3079 3080 __configure_vf_output(asd, width, height, min_width, format, 3081 pipe_id); 3082 return 0; 3083 } 3084 3085 int atomisp_css_video_get_viewfinder_frame_info( 3086 struct atomisp_sub_device *asd, 3087 struct ia_css_frame_info *info) 3088 { 3089 enum ia_css_pipe_id pipe_id; 3090 enum frame_info_type frame_type = ATOMISP_CSS_VF_FRAME; 3091 3092 if (ATOMISP_USE_YUVPP(asd)) { 3093 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3094 if (asd->continuous_mode->val) 3095 frame_type = ATOMISP_CSS_SECOND_VF_FRAME; 3096 } else { 3097 pipe_id = IA_CSS_PIPE_ID_VIDEO; 3098 } 3099 3100 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3101 frame_type, pipe_id); 3102 } 3103 3104 int atomisp_css_capture_get_viewfinder_frame_info( 3105 struct atomisp_sub_device *asd, 3106 struct ia_css_frame_info *info) 3107 { 3108 enum ia_css_pipe_id pipe_id; 3109 3110 if (ATOMISP_USE_YUVPP(asd)) 3111 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3112 else 3113 pipe_id = IA_CSS_PIPE_ID_CAPTURE; 3114 3115 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3116 ATOMISP_CSS_VF_FRAME, pipe_id); 3117 } 3118 3119 int atomisp_css_capture_get_output_raw_frame_info( 3120 struct atomisp_sub_device *asd, 3121 struct ia_css_frame_info *info) 3122 { 3123 if (ATOMISP_USE_YUVPP(asd)) 3124 return 0; 3125 3126 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3127 ATOMISP_CSS_RAW_FRAME, IA_CSS_PIPE_ID_CAPTURE); 3128 } 3129 3130 int atomisp_css_copy_get_output_frame_info( 3131 struct atomisp_sub_device *asd, 3132 unsigned int stream_index, 3133 struct ia_css_frame_info *info) 3134 { 3135 return __get_frame_info(asd, stream_index, info, 3136 ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_COPY); 3137 } 3138 3139 int atomisp_css_preview_get_output_frame_info( 3140 struct atomisp_sub_device *asd, 3141 struct ia_css_frame_info *info) 3142 { 3143 enum ia_css_pipe_id pipe_id; 3144 enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME; 3145 3146 if (ATOMISP_USE_YUVPP(asd)) { 3147 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3148 if (asd->continuous_mode->val) 3149 frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME; 3150 } else { 3151 pipe_id = IA_CSS_PIPE_ID_PREVIEW; 3152 } 3153 3154 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3155 frame_type, pipe_id); 3156 } 3157 3158 int atomisp_css_capture_get_output_frame_info( 3159 struct atomisp_sub_device *asd, 3160 struct ia_css_frame_info *info) 3161 { 3162 enum ia_css_pipe_id pipe_id; 3163 3164 if (ATOMISP_USE_YUVPP(asd)) 3165 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3166 else 3167 pipe_id = IA_CSS_PIPE_ID_CAPTURE; 3168 3169 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3170 ATOMISP_CSS_OUTPUT_FRAME, pipe_id); 3171 } 3172 3173 int atomisp_css_video_get_output_frame_info( 3174 struct atomisp_sub_device *asd, 3175 struct ia_css_frame_info *info) 3176 { 3177 enum ia_css_pipe_id pipe_id; 3178 enum frame_info_type frame_type = ATOMISP_CSS_OUTPUT_FRAME; 3179 3180 if (ATOMISP_USE_YUVPP(asd)) { 3181 pipe_id = IA_CSS_PIPE_ID_YUVPP; 3182 if (asd->continuous_mode->val) 3183 frame_type = ATOMISP_CSS_SECOND_OUTPUT_FRAME; 3184 } else { 3185 pipe_id = IA_CSS_PIPE_ID_VIDEO; 3186 } 3187 3188 return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info, 3189 frame_type, pipe_id); 3190 } 3191 3192 int atomisp_css_preview_configure_pp_input( 3193 struct atomisp_sub_device *asd, 3194 unsigned int width, unsigned int height) 3195 { 3196 struct atomisp_stream_env *stream_env = 3197 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 3198 __configure_preview_pp_input(asd, width, height, 3199 ATOMISP_USE_YUVPP(asd) ? 3200 IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_PREVIEW); 3201 3202 if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. 3203 capt_pp_in_res.width) 3204 __configure_capture_pp_input(asd, width, height, 3205 ATOMISP_USE_YUVPP(asd) ? 3206 IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); 3207 return 0; 3208 } 3209 3210 int atomisp_css_capture_configure_pp_input( 3211 struct atomisp_sub_device *asd, 3212 unsigned int width, unsigned int height) 3213 { 3214 __configure_capture_pp_input(asd, width, height, 3215 ATOMISP_USE_YUVPP(asd) ? 3216 IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); 3217 return 0; 3218 } 3219 3220 int atomisp_css_video_configure_pp_input( 3221 struct atomisp_sub_device *asd, 3222 unsigned int width, unsigned int height) 3223 { 3224 struct atomisp_stream_env *stream_env = 3225 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 3226 3227 __configure_video_pp_input(asd, width, height, 3228 ATOMISP_USE_YUVPP(asd) ? 3229 IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_VIDEO); 3230 3231 if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]. 3232 capt_pp_in_res.width) 3233 __configure_capture_pp_input(asd, width, height, 3234 ATOMISP_USE_YUVPP(asd) ? 3235 IA_CSS_PIPE_ID_YUVPP : IA_CSS_PIPE_ID_CAPTURE); 3236 return 0; 3237 } 3238 3239 int atomisp_css_offline_capture_configure(struct atomisp_sub_device *asd, 3240 int num_captures, unsigned int skip, int offset) 3241 { 3242 int ret; 3243 3244 dev_dbg(asd->isp->dev, "%s num_capture:%d skip:%d offset:%d\n", 3245 __func__, num_captures, skip, offset); 3246 3247 ret = ia_css_stream_capture( 3248 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3249 num_captures, skip, offset); 3250 if (ret) 3251 return -EINVAL; 3252 3253 return 0; 3254 } 3255 3256 int atomisp_css_exp_id_capture(struct atomisp_sub_device *asd, int exp_id) 3257 { 3258 int ret; 3259 3260 ret = ia_css_stream_capture_frame( 3261 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3262 exp_id); 3263 if (ret == -ENOBUFS) { 3264 /* capture cmd queue is full */ 3265 return -EBUSY; 3266 } else if (ret) { 3267 return -EIO; 3268 } 3269 3270 return 0; 3271 } 3272 3273 int atomisp_css_exp_id_unlock(struct atomisp_sub_device *asd, int exp_id) 3274 { 3275 int ret; 3276 3277 ret = ia_css_unlock_raw_frame( 3278 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3279 exp_id); 3280 if (ret == -ENOBUFS) 3281 return -EAGAIN; 3282 else if (ret) 3283 return -EIO; 3284 3285 return 0; 3286 } 3287 3288 int atomisp_css_capture_enable_xnr(struct atomisp_sub_device *asd, 3289 bool enable) 3290 { 3291 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 3292 .pipe_configs[IA_CSS_PIPE_ID_CAPTURE] 3293 .default_capture_config.enable_xnr = enable; 3294 asd->params.capture_config.enable_xnr = enable; 3295 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 3296 .update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true; 3297 3298 return 0; 3299 } 3300 3301 void atomisp_css_send_input_frame(struct atomisp_sub_device *asd, 3302 unsigned short *data, unsigned int width, 3303 unsigned int height) 3304 { 3305 ia_css_stream_send_input_frame( 3306 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3307 data, width, height); 3308 } 3309 3310 bool atomisp_css_isp_has_started(void) 3311 { 3312 return ia_css_isp_has_started(); 3313 } 3314 3315 void atomisp_css_request_flash(struct atomisp_sub_device *asd) 3316 { 3317 ia_css_stream_request_flash( 3318 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream); 3319 } 3320 3321 void atomisp_css_set_wb_config(struct atomisp_sub_device *asd, 3322 struct ia_css_wb_config *wb_config) 3323 { 3324 asd->params.config.wb_config = wb_config; 3325 } 3326 3327 void atomisp_css_set_ob_config(struct atomisp_sub_device *asd, 3328 struct ia_css_ob_config *ob_config) 3329 { 3330 asd->params.config.ob_config = ob_config; 3331 } 3332 3333 void atomisp_css_set_dp_config(struct atomisp_sub_device *asd, 3334 struct ia_css_dp_config *dp_config) 3335 { 3336 asd->params.config.dp_config = dp_config; 3337 } 3338 3339 void atomisp_css_set_de_config(struct atomisp_sub_device *asd, 3340 struct ia_css_de_config *de_config) 3341 { 3342 asd->params.config.de_config = de_config; 3343 } 3344 3345 void atomisp_css_set_dz_config(struct atomisp_sub_device *asd, 3346 struct ia_css_dz_config *dz_config) 3347 { 3348 asd->params.config.dz_config = dz_config; 3349 } 3350 3351 void atomisp_css_set_default_de_config(struct atomisp_sub_device *asd) 3352 { 3353 asd->params.config.de_config = NULL; 3354 } 3355 3356 void atomisp_css_set_ce_config(struct atomisp_sub_device *asd, 3357 struct ia_css_ce_config *ce_config) 3358 { 3359 asd->params.config.ce_config = ce_config; 3360 } 3361 3362 void atomisp_css_set_nr_config(struct atomisp_sub_device *asd, 3363 struct ia_css_nr_config *nr_config) 3364 { 3365 asd->params.config.nr_config = nr_config; 3366 } 3367 3368 void atomisp_css_set_ee_config(struct atomisp_sub_device *asd, 3369 struct ia_css_ee_config *ee_config) 3370 { 3371 asd->params.config.ee_config = ee_config; 3372 } 3373 3374 void atomisp_css_set_tnr_config(struct atomisp_sub_device *asd, 3375 struct ia_css_tnr_config *tnr_config) 3376 { 3377 asd->params.config.tnr_config = tnr_config; 3378 } 3379 3380 void atomisp_css_set_cc_config(struct atomisp_sub_device *asd, 3381 struct ia_css_cc_config *cc_config) 3382 { 3383 asd->params.config.cc_config = cc_config; 3384 } 3385 3386 void atomisp_css_set_macc_table(struct atomisp_sub_device *asd, 3387 struct ia_css_macc_table *macc_table) 3388 { 3389 asd->params.config.macc_table = macc_table; 3390 } 3391 3392 void atomisp_css_set_macc_config(struct atomisp_sub_device *asd, 3393 struct ia_css_macc_config *macc_config) 3394 { 3395 asd->params.config.macc_config = macc_config; 3396 } 3397 3398 void atomisp_css_set_ecd_config(struct atomisp_sub_device *asd, 3399 struct ia_css_ecd_config *ecd_config) 3400 { 3401 asd->params.config.ecd_config = ecd_config; 3402 } 3403 3404 void atomisp_css_set_ynr_config(struct atomisp_sub_device *asd, 3405 struct ia_css_ynr_config *ynr_config) 3406 { 3407 asd->params.config.ynr_config = ynr_config; 3408 } 3409 3410 void atomisp_css_set_fc_config(struct atomisp_sub_device *asd, 3411 struct ia_css_fc_config *fc_config) 3412 { 3413 asd->params.config.fc_config = fc_config; 3414 } 3415 3416 void atomisp_css_set_ctc_config(struct atomisp_sub_device *asd, 3417 struct ia_css_ctc_config *ctc_config) 3418 { 3419 asd->params.config.ctc_config = ctc_config; 3420 } 3421 3422 void atomisp_css_set_cnr_config(struct atomisp_sub_device *asd, 3423 struct ia_css_cnr_config *cnr_config) 3424 { 3425 asd->params.config.cnr_config = cnr_config; 3426 } 3427 3428 void atomisp_css_set_aa_config(struct atomisp_sub_device *asd, 3429 struct ia_css_aa_config *aa_config) 3430 { 3431 asd->params.config.aa_config = aa_config; 3432 } 3433 3434 void atomisp_css_set_baa_config(struct atomisp_sub_device *asd, 3435 struct ia_css_aa_config *baa_config) 3436 { 3437 asd->params.config.baa_config = baa_config; 3438 } 3439 3440 void atomisp_css_set_anr_config(struct atomisp_sub_device *asd, 3441 struct ia_css_anr_config *anr_config) 3442 { 3443 asd->params.config.anr_config = anr_config; 3444 } 3445 3446 void atomisp_css_set_xnr_config(struct atomisp_sub_device *asd, 3447 struct ia_css_xnr_config *xnr_config) 3448 { 3449 asd->params.config.xnr_config = xnr_config; 3450 } 3451 3452 void atomisp_css_set_yuv2rgb_cc_config(struct atomisp_sub_device *asd, 3453 struct ia_css_cc_config *yuv2rgb_cc_config) 3454 { 3455 asd->params.config.yuv2rgb_cc_config = yuv2rgb_cc_config; 3456 } 3457 3458 void atomisp_css_set_rgb2yuv_cc_config(struct atomisp_sub_device *asd, 3459 struct ia_css_cc_config *rgb2yuv_cc_config) 3460 { 3461 asd->params.config.rgb2yuv_cc_config = rgb2yuv_cc_config; 3462 } 3463 3464 void atomisp_css_set_xnr_table(struct atomisp_sub_device *asd, 3465 struct ia_css_xnr_table *xnr_table) 3466 { 3467 asd->params.config.xnr_table = xnr_table; 3468 } 3469 3470 void atomisp_css_set_r_gamma_table(struct atomisp_sub_device *asd, 3471 struct ia_css_rgb_gamma_table *r_gamma_table) 3472 { 3473 asd->params.config.r_gamma_table = r_gamma_table; 3474 } 3475 3476 void atomisp_css_set_g_gamma_table(struct atomisp_sub_device *asd, 3477 struct ia_css_rgb_gamma_table *g_gamma_table) 3478 { 3479 asd->params.config.g_gamma_table = g_gamma_table; 3480 } 3481 3482 void atomisp_css_set_b_gamma_table(struct atomisp_sub_device *asd, 3483 struct ia_css_rgb_gamma_table *b_gamma_table) 3484 { 3485 asd->params.config.b_gamma_table = b_gamma_table; 3486 } 3487 3488 void atomisp_css_set_gamma_table(struct atomisp_sub_device *asd, 3489 struct ia_css_gamma_table *gamma_table) 3490 { 3491 asd->params.config.gamma_table = gamma_table; 3492 } 3493 3494 void atomisp_css_set_ctc_table(struct atomisp_sub_device *asd, 3495 struct ia_css_ctc_table *ctc_table) 3496 { 3497 int i; 3498 u16 *vamem_ptr = ctc_table->data.vamem_1; 3499 int data_size = IA_CSS_VAMEM_1_CTC_TABLE_SIZE; 3500 bool valid = false; 3501 3502 /* workaround: if ctc_table is all 0, do not apply it */ 3503 if (ctc_table->vamem_type == IA_CSS_VAMEM_TYPE_2) { 3504 vamem_ptr = ctc_table->data.vamem_2; 3505 data_size = IA_CSS_VAMEM_2_CTC_TABLE_SIZE; 3506 } 3507 3508 for (i = 0; i < data_size; i++) { 3509 if (*(vamem_ptr + i)) { 3510 valid = true; 3511 break; 3512 } 3513 } 3514 3515 if (valid) 3516 asd->params.config.ctc_table = ctc_table; 3517 else 3518 dev_warn(asd->isp->dev, "Bypass the invalid ctc_table.\n"); 3519 } 3520 3521 void atomisp_css_set_anr_thres(struct atomisp_sub_device *asd, 3522 struct ia_css_anr_thres *anr_thres) 3523 { 3524 asd->params.config.anr_thres = anr_thres; 3525 } 3526 3527 void atomisp_css_set_dvs_6axis(struct atomisp_sub_device *asd, 3528 struct ia_css_dvs_6axis_config *dvs_6axis) 3529 { 3530 asd->params.config.dvs_6axis_config = dvs_6axis; 3531 } 3532 3533 void atomisp_css_set_gc_config(struct atomisp_sub_device *asd, 3534 struct ia_css_gc_config *gc_config) 3535 { 3536 asd->params.config.gc_config = gc_config; 3537 } 3538 3539 void atomisp_css_set_3a_config(struct atomisp_sub_device *asd, 3540 struct ia_css_3a_config *s3a_config) 3541 { 3542 asd->params.config.s3a_config = s3a_config; 3543 } 3544 3545 void atomisp_css_video_set_dis_vector(struct atomisp_sub_device *asd, 3546 struct atomisp_dis_vector *vector) 3547 { 3548 if (!asd->params.config.motion_vector) 3549 asd->params.config.motion_vector = &asd->params.css_param.motion_vector; 3550 3551 memset(asd->params.config.motion_vector, 3552 0, sizeof(struct ia_css_vector)); 3553 asd->params.css_param.motion_vector.x = vector->x; 3554 asd->params.css_param.motion_vector.y = vector->y; 3555 } 3556 3557 static int atomisp_compare_dvs_grid(struct atomisp_sub_device *asd, 3558 struct atomisp_dvs_grid_info *atomgrid) 3559 { 3560 struct ia_css_dvs_grid_info *cur = 3561 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 3562 3563 if (!cur) { 3564 dev_err(asd->isp->dev, "dvs grid not available!\n"); 3565 return -EINVAL; 3566 } 3567 3568 if (sizeof(*cur) != sizeof(*atomgrid)) { 3569 dev_err(asd->isp->dev, "dvs grid mis-match!\n"); 3570 return -EINVAL; 3571 } 3572 3573 if (!cur->enable) { 3574 dev_err(asd->isp->dev, "dvs not enabled!\n"); 3575 return -EINVAL; 3576 } 3577 3578 return memcmp(atomgrid, cur, sizeof(*cur)); 3579 } 3580 3581 void atomisp_css_set_dvs2_coefs(struct atomisp_sub_device *asd, 3582 struct ia_css_dvs2_coefficients *coefs) 3583 { 3584 asd->params.config.dvs2_coefs = coefs; 3585 } 3586 3587 int atomisp_css_set_dis_coefs(struct atomisp_sub_device *asd, 3588 struct atomisp_dis_coefficients *coefs) 3589 { 3590 if (atomisp_compare_dvs_grid(asd, &coefs->grid_info) != 0) 3591 /* If the grid info in the argument differs from the current 3592 grid info, we tell the caller to reset the grid size and 3593 try again. */ 3594 return -EAGAIN; 3595 3596 if (!coefs->hor_coefs.odd_real || 3597 !coefs->hor_coefs.odd_imag || 3598 !coefs->hor_coefs.even_real || 3599 !coefs->hor_coefs.even_imag || 3600 !coefs->ver_coefs.odd_real || 3601 !coefs->ver_coefs.odd_imag || 3602 !coefs->ver_coefs.even_real || 3603 !coefs->ver_coefs.even_imag || 3604 !asd->params.css_param.dvs2_coeff->hor_coefs.odd_real || 3605 !asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag || 3606 !asd->params.css_param.dvs2_coeff->hor_coefs.even_real || 3607 !asd->params.css_param.dvs2_coeff->hor_coefs.even_imag || 3608 !asd->params.css_param.dvs2_coeff->ver_coefs.odd_real || 3609 !asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag || 3610 !asd->params.css_param.dvs2_coeff->ver_coefs.even_real || 3611 !asd->params.css_param.dvs2_coeff->ver_coefs.even_imag) 3612 return -EINVAL; 3613 3614 if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_real, 3615 coefs->hor_coefs.odd_real, asd->params.dvs_hor_coef_bytes)) 3616 return -EFAULT; 3617 if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag, 3618 coefs->hor_coefs.odd_imag, asd->params.dvs_hor_coef_bytes)) 3619 return -EFAULT; 3620 if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_real, 3621 coefs->hor_coefs.even_real, asd->params.dvs_hor_coef_bytes)) 3622 return -EFAULT; 3623 if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_imag, 3624 coefs->hor_coefs.even_imag, asd->params.dvs_hor_coef_bytes)) 3625 return -EFAULT; 3626 3627 if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_real, 3628 coefs->ver_coefs.odd_real, asd->params.dvs_ver_coef_bytes)) 3629 return -EFAULT; 3630 if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag, 3631 coefs->ver_coefs.odd_imag, asd->params.dvs_ver_coef_bytes)) 3632 return -EFAULT; 3633 if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_real, 3634 coefs->ver_coefs.even_real, asd->params.dvs_ver_coef_bytes)) 3635 return -EFAULT; 3636 if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_imag, 3637 coefs->ver_coefs.even_imag, asd->params.dvs_ver_coef_bytes)) 3638 return -EFAULT; 3639 3640 asd->params.css_param.update_flag.dvs2_coefs = 3641 (struct atomisp_dvs2_coefficients *) 3642 asd->params.css_param.dvs2_coeff; 3643 /* FIXME! */ 3644 /* asd->params.dis_proj_data_valid = false; */ 3645 asd->params.css_update_params_needed = true; 3646 3647 return 0; 3648 } 3649 3650 void atomisp_css_set_zoom_factor(struct atomisp_sub_device *asd, 3651 unsigned int zoom) 3652 { 3653 struct atomisp_device *isp = asd->isp; 3654 3655 if (zoom == asd->params.css_param.dz_config.dx && 3656 zoom == asd->params.css_param.dz_config.dy) { 3657 dev_dbg(isp->dev, "same zoom scale. skipped.\n"); 3658 return; 3659 } 3660 3661 memset(&asd->params.css_param.dz_config, 0, 3662 sizeof(struct ia_css_dz_config)); 3663 asd->params.css_param.dz_config.dx = zoom; 3664 asd->params.css_param.dz_config.dy = zoom; 3665 3666 asd->params.css_param.update_flag.dz_config = 3667 (struct atomisp_dz_config *)&asd->params.css_param.dz_config; 3668 asd->params.css_update_params_needed = true; 3669 } 3670 3671 void atomisp_css_set_formats_config(struct atomisp_sub_device *asd, 3672 struct ia_css_formats_config *formats_config) 3673 { 3674 asd->params.config.formats_config = formats_config; 3675 } 3676 3677 int atomisp_css_get_wb_config(struct atomisp_sub_device *asd, 3678 struct atomisp_wb_config *config) 3679 { 3680 struct ia_css_wb_config wb_config; 3681 struct ia_css_isp_config isp_config; 3682 struct atomisp_device *isp = asd->isp; 3683 3684 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3685 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3686 __func__); 3687 return -EINVAL; 3688 } 3689 memset(&wb_config, 0, sizeof(struct ia_css_wb_config)); 3690 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3691 isp_config.wb_config = &wb_config; 3692 ia_css_stream_get_isp_config( 3693 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3694 &isp_config); 3695 memcpy(config, &wb_config, sizeof(*config)); 3696 3697 return 0; 3698 } 3699 3700 int atomisp_css_get_ob_config(struct atomisp_sub_device *asd, 3701 struct atomisp_ob_config *config) 3702 { 3703 struct ia_css_ob_config ob_config; 3704 struct ia_css_isp_config isp_config; 3705 struct atomisp_device *isp = asd->isp; 3706 3707 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3708 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3709 __func__); 3710 return -EINVAL; 3711 } 3712 memset(&ob_config, 0, sizeof(struct ia_css_ob_config)); 3713 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3714 isp_config.ob_config = &ob_config; 3715 ia_css_stream_get_isp_config( 3716 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3717 &isp_config); 3718 memcpy(config, &ob_config, sizeof(*config)); 3719 3720 return 0; 3721 } 3722 3723 int atomisp_css_get_dp_config(struct atomisp_sub_device *asd, 3724 struct atomisp_dp_config *config) 3725 { 3726 struct ia_css_dp_config dp_config; 3727 struct ia_css_isp_config isp_config; 3728 struct atomisp_device *isp = asd->isp; 3729 3730 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3731 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3732 __func__); 3733 return -EINVAL; 3734 } 3735 memset(&dp_config, 0, sizeof(struct ia_css_dp_config)); 3736 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3737 isp_config.dp_config = &dp_config; 3738 ia_css_stream_get_isp_config( 3739 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3740 &isp_config); 3741 memcpy(config, &dp_config, sizeof(*config)); 3742 3743 return 0; 3744 } 3745 3746 int atomisp_css_get_de_config(struct atomisp_sub_device *asd, 3747 struct atomisp_de_config *config) 3748 { 3749 struct ia_css_de_config de_config; 3750 struct ia_css_isp_config isp_config; 3751 struct atomisp_device *isp = asd->isp; 3752 3753 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3754 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3755 __func__); 3756 return -EINVAL; 3757 } 3758 memset(&de_config, 0, sizeof(struct ia_css_de_config)); 3759 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3760 isp_config.de_config = &de_config; 3761 ia_css_stream_get_isp_config( 3762 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3763 &isp_config); 3764 memcpy(config, &de_config, sizeof(*config)); 3765 3766 return 0; 3767 } 3768 3769 int atomisp_css_get_nr_config(struct atomisp_sub_device *asd, 3770 struct atomisp_nr_config *config) 3771 { 3772 struct ia_css_nr_config nr_config; 3773 struct ia_css_isp_config isp_config; 3774 struct atomisp_device *isp = asd->isp; 3775 3776 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3777 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3778 __func__); 3779 return -EINVAL; 3780 } 3781 memset(&nr_config, 0, sizeof(struct ia_css_nr_config)); 3782 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3783 3784 isp_config.nr_config = &nr_config; 3785 ia_css_stream_get_isp_config( 3786 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3787 &isp_config); 3788 memcpy(config, &nr_config, sizeof(*config)); 3789 3790 return 0; 3791 } 3792 3793 int atomisp_css_get_ee_config(struct atomisp_sub_device *asd, 3794 struct atomisp_ee_config *config) 3795 { 3796 struct ia_css_ee_config ee_config; 3797 struct ia_css_isp_config isp_config; 3798 struct atomisp_device *isp = asd->isp; 3799 3800 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3801 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3802 __func__); 3803 return -EINVAL; 3804 } 3805 memset(&ee_config, 0, sizeof(struct ia_css_ee_config)); 3806 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3807 isp_config.ee_config = &ee_config; 3808 ia_css_stream_get_isp_config( 3809 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3810 &isp_config); 3811 memcpy(config, &ee_config, sizeof(*config)); 3812 3813 return 0; 3814 } 3815 3816 int atomisp_css_get_tnr_config(struct atomisp_sub_device *asd, 3817 struct atomisp_tnr_config *config) 3818 { 3819 struct ia_css_tnr_config tnr_config; 3820 struct ia_css_isp_config isp_config; 3821 struct atomisp_device *isp = asd->isp; 3822 3823 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3824 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3825 __func__); 3826 return -EINVAL; 3827 } 3828 memset(&tnr_config, 0, sizeof(struct ia_css_tnr_config)); 3829 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3830 isp_config.tnr_config = &tnr_config; 3831 ia_css_stream_get_isp_config( 3832 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3833 &isp_config); 3834 memcpy(config, &tnr_config, sizeof(*config)); 3835 3836 return 0; 3837 } 3838 3839 int atomisp_css_get_ctc_table(struct atomisp_sub_device *asd, 3840 struct atomisp_ctc_table *config) 3841 { 3842 struct ia_css_ctc_table *tab; 3843 struct ia_css_isp_config isp_config; 3844 struct atomisp_device *isp = asd->isp; 3845 3846 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3847 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3848 __func__); 3849 return -EINVAL; 3850 } 3851 3852 tab = vzalloc(sizeof(struct ia_css_ctc_table)); 3853 if (!tab) 3854 return -ENOMEM; 3855 3856 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3857 isp_config.ctc_table = tab; 3858 ia_css_stream_get_isp_config( 3859 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3860 &isp_config); 3861 memcpy(config, tab, sizeof(*tab)); 3862 vfree(tab); 3863 3864 return 0; 3865 } 3866 3867 int atomisp_css_get_gamma_table(struct atomisp_sub_device *asd, 3868 struct atomisp_gamma_table *config) 3869 { 3870 struct ia_css_gamma_table *tab; 3871 struct ia_css_isp_config isp_config; 3872 struct atomisp_device *isp = asd->isp; 3873 3874 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3875 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3876 __func__); 3877 return -EINVAL; 3878 } 3879 3880 tab = vzalloc(sizeof(struct ia_css_gamma_table)); 3881 if (!tab) 3882 return -ENOMEM; 3883 3884 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3885 isp_config.gamma_table = tab; 3886 ia_css_stream_get_isp_config( 3887 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3888 &isp_config); 3889 memcpy(config, tab, sizeof(*tab)); 3890 vfree(tab); 3891 3892 return 0; 3893 } 3894 3895 int atomisp_css_get_gc_config(struct atomisp_sub_device *asd, 3896 struct atomisp_gc_config *config) 3897 { 3898 struct ia_css_gc_config gc_config; 3899 struct ia_css_isp_config isp_config; 3900 struct atomisp_device *isp = asd->isp; 3901 3902 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3903 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3904 __func__); 3905 return -EINVAL; 3906 } 3907 memset(&gc_config, 0, sizeof(struct ia_css_gc_config)); 3908 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3909 isp_config.gc_config = &gc_config; 3910 ia_css_stream_get_isp_config( 3911 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3912 &isp_config); 3913 /* Get gamma correction params from current setup */ 3914 memcpy(config, &gc_config, sizeof(*config)); 3915 3916 return 0; 3917 } 3918 3919 int atomisp_css_get_3a_config(struct atomisp_sub_device *asd, 3920 struct atomisp_3a_config *config) 3921 { 3922 struct ia_css_3a_config s3a_config; 3923 struct ia_css_isp_config isp_config; 3924 struct atomisp_device *isp = asd->isp; 3925 3926 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3927 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3928 __func__); 3929 return -EINVAL; 3930 } 3931 memset(&s3a_config, 0, sizeof(struct ia_css_3a_config)); 3932 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3933 isp_config.s3a_config = &s3a_config; 3934 ia_css_stream_get_isp_config( 3935 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3936 &isp_config); 3937 /* Get white balance from current setup */ 3938 memcpy(config, &s3a_config, sizeof(*config)); 3939 3940 return 0; 3941 } 3942 3943 int atomisp_css_get_formats_config(struct atomisp_sub_device *asd, 3944 struct atomisp_formats_config *config) 3945 { 3946 struct ia_css_formats_config formats_config; 3947 struct ia_css_isp_config isp_config; 3948 struct atomisp_device *isp = asd->isp; 3949 3950 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3951 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3952 __func__); 3953 return -EINVAL; 3954 } 3955 memset(&formats_config, 0, sizeof(formats_config)); 3956 memset(&isp_config, 0, sizeof(isp_config)); 3957 isp_config.formats_config = &formats_config; 3958 ia_css_stream_get_isp_config( 3959 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3960 &isp_config); 3961 /* Get narrow gamma from current setup */ 3962 memcpy(config, &formats_config, sizeof(*config)); 3963 3964 return 0; 3965 } 3966 3967 int atomisp_css_get_zoom_factor(struct atomisp_sub_device *asd, 3968 unsigned int *zoom) 3969 { 3970 struct ia_css_dz_config dz_config; /** Digital Zoom */ 3971 struct ia_css_isp_config isp_config; 3972 struct atomisp_device *isp = asd->isp; 3973 3974 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 3975 dev_err(isp->dev, "%s called after streamoff, skipping.\n", 3976 __func__); 3977 return -EINVAL; 3978 } 3979 memset(&dz_config, 0, sizeof(struct ia_css_dz_config)); 3980 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 3981 isp_config.dz_config = &dz_config; 3982 ia_css_stream_get_isp_config( 3983 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3984 &isp_config); 3985 *zoom = dz_config.dx; 3986 3987 return 0; 3988 } 3989 3990 /* 3991 * Function to set/get image stablization statistics 3992 */ 3993 int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, 3994 struct atomisp_dis_statistics *stats) 3995 { 3996 struct atomisp_device *isp = asd->isp; 3997 struct atomisp_dis_buf *dis_buf; 3998 unsigned long flags; 3999 4000 if (!asd->params.dvs_stat->hor_prod.odd_real || 4001 !asd->params.dvs_stat->hor_prod.odd_imag || 4002 !asd->params.dvs_stat->hor_prod.even_real || 4003 !asd->params.dvs_stat->hor_prod.even_imag || 4004 !asd->params.dvs_stat->ver_prod.odd_real || 4005 !asd->params.dvs_stat->ver_prod.odd_imag || 4006 !asd->params.dvs_stat->ver_prod.even_real || 4007 !asd->params.dvs_stat->ver_prod.even_imag) 4008 return -EINVAL; 4009 4010 /* isp needs to be streaming to get DIS statistics */ 4011 spin_lock_irqsave(&isp->lock, flags); 4012 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) { 4013 spin_unlock_irqrestore(&isp->lock, flags); 4014 return -EINVAL; 4015 } 4016 spin_unlock_irqrestore(&isp->lock, flags); 4017 4018 if (atomisp_compare_dvs_grid(asd, &stats->dvs2_stat.grid_info) != 0) 4019 /* If the grid info in the argument differs from the current 4020 grid info, we tell the caller to reset the grid size and 4021 try again. */ 4022 return -EAGAIN; 4023 4024 spin_lock_irqsave(&asd->dis_stats_lock, flags); 4025 if (!asd->params.dis_proj_data_valid || list_empty(&asd->dis_stats)) { 4026 spin_unlock_irqrestore(&asd->dis_stats_lock, flags); 4027 dev_err(isp->dev, "dis statistics is not valid.\n"); 4028 return -EAGAIN; 4029 } 4030 4031 dis_buf = list_entry(asd->dis_stats.next, 4032 struct atomisp_dis_buf, list); 4033 list_del_init(&dis_buf->list); 4034 spin_unlock_irqrestore(&asd->dis_stats_lock, flags); 4035 4036 if (dis_buf->dvs_map) 4037 ia_css_translate_dvs2_statistics( 4038 asd->params.dvs_stat, dis_buf->dvs_map); 4039 else 4040 ia_css_get_dvs2_statistics(asd->params.dvs_stat, 4041 dis_buf->dis_data); 4042 stats->exp_id = dis_buf->dis_data->exp_id; 4043 4044 spin_lock_irqsave(&asd->dis_stats_lock, flags); 4045 list_add_tail(&dis_buf->list, &asd->dis_stats); 4046 spin_unlock_irqrestore(&asd->dis_stats_lock, flags); 4047 4048 if (copy_to_user(stats->dvs2_stat.ver_prod.odd_real, 4049 asd->params.dvs_stat->ver_prod.odd_real, 4050 asd->params.dvs_ver_proj_bytes)) 4051 return -EFAULT; 4052 if (copy_to_user(stats->dvs2_stat.ver_prod.odd_imag, 4053 asd->params.dvs_stat->ver_prod.odd_imag, 4054 asd->params.dvs_ver_proj_bytes)) 4055 return -EFAULT; 4056 if (copy_to_user(stats->dvs2_stat.ver_prod.even_real, 4057 asd->params.dvs_stat->ver_prod.even_real, 4058 asd->params.dvs_ver_proj_bytes)) 4059 return -EFAULT; 4060 if (copy_to_user(stats->dvs2_stat.ver_prod.even_imag, 4061 asd->params.dvs_stat->ver_prod.even_imag, 4062 asd->params.dvs_ver_proj_bytes)) 4063 return -EFAULT; 4064 if (copy_to_user(stats->dvs2_stat.hor_prod.odd_real, 4065 asd->params.dvs_stat->hor_prod.odd_real, 4066 asd->params.dvs_hor_proj_bytes)) 4067 return -EFAULT; 4068 if (copy_to_user(stats->dvs2_stat.hor_prod.odd_imag, 4069 asd->params.dvs_stat->hor_prod.odd_imag, 4070 asd->params.dvs_hor_proj_bytes)) 4071 return -EFAULT; 4072 if (copy_to_user(stats->dvs2_stat.hor_prod.even_real, 4073 asd->params.dvs_stat->hor_prod.even_real, 4074 asd->params.dvs_hor_proj_bytes)) 4075 return -EFAULT; 4076 if (copy_to_user(stats->dvs2_stat.hor_prod.even_imag, 4077 asd->params.dvs_stat->hor_prod.even_imag, 4078 asd->params.dvs_hor_proj_bytes)) 4079 return -EFAULT; 4080 4081 return 0; 4082 } 4083 4084 struct ia_css_shading_table *atomisp_css_shading_table_alloc( 4085 unsigned int width, unsigned int height) 4086 { 4087 return ia_css_shading_table_alloc(width, height); 4088 } 4089 4090 void atomisp_css_set_shading_table(struct atomisp_sub_device *asd, 4091 struct ia_css_shading_table *table) 4092 { 4093 asd->params.config.shading_table = table; 4094 } 4095 4096 void atomisp_css_shading_table_free(struct ia_css_shading_table *table) 4097 { 4098 ia_css_shading_table_free(table); 4099 } 4100 4101 struct ia_css_morph_table *atomisp_css_morph_table_allocate( 4102 unsigned int width, unsigned int height) 4103 { 4104 return ia_css_morph_table_allocate(width, height); 4105 } 4106 4107 void atomisp_css_set_morph_table(struct atomisp_sub_device *asd, 4108 struct ia_css_morph_table *table) 4109 { 4110 asd->params.config.morph_table = table; 4111 } 4112 4113 void atomisp_css_get_morph_table(struct atomisp_sub_device *asd, 4114 struct ia_css_morph_table *table) 4115 { 4116 struct ia_css_isp_config isp_config; 4117 struct atomisp_device *isp = asd->isp; 4118 4119 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 4120 dev_err(isp->dev, 4121 "%s called after streamoff, skipping.\n", __func__); 4122 return; 4123 } 4124 memset(table, 0, sizeof(struct ia_css_morph_table)); 4125 memset(&isp_config, 0, sizeof(struct ia_css_isp_config)); 4126 isp_config.morph_table = table; 4127 ia_css_stream_get_isp_config( 4128 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 4129 &isp_config); 4130 } 4131 4132 void atomisp_css_morph_table_free(struct ia_css_morph_table *table) 4133 { 4134 ia_css_morph_table_free(table); 4135 } 4136 4137 void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp, 4138 unsigned int overlap) 4139 { 4140 /* CSS 2.0 doesn't support this API. */ 4141 dev_dbg(isp->dev, "set cont prev start time is not supported.\n"); 4142 return; 4143 } 4144 4145 void atomisp_css_acc_done(struct atomisp_sub_device *asd) 4146 { 4147 complete(&asd->acc.acc_done); 4148 } 4149 4150 int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd) 4151 { 4152 int ret = 0; 4153 struct atomisp_device *isp = asd->isp; 4154 4155 /* Unlock the isp mutex taken in IOCTL handler before sleeping! */ 4156 rt_mutex_unlock(&isp->mutex); 4157 if (wait_for_completion_interruptible_timeout(&asd->acc.acc_done, 4158 ATOMISP_ISP_TIMEOUT_DURATION) == 0) { 4159 dev_err(isp->dev, "<%s: completion timeout\n", __func__); 4160 ia_css_debug_dump_sp_sw_debug_info(); 4161 ia_css_debug_dump_debug_info(__func__); 4162 ret = -EIO; 4163 } 4164 rt_mutex_lock(&isp->mutex); 4165 4166 return ret; 4167 } 4168 4169 /* Set the ACC binary arguments */ 4170 int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw) 4171 { 4172 unsigned int mem; 4173 4174 for (mem = 0; mem < ATOMISP_ACC_NR_MEMORY; mem++) { 4175 if (acc_fw->args[mem].length == 0) 4176 continue; 4177 4178 ia_css_isp_param_set_css_mem_init(&acc_fw->fw->mem_initializers, 4179 IA_CSS_PARAM_CLASS_PARAM, mem, 4180 acc_fw->args[mem].css_ptr, 4181 acc_fw->args[mem].length); 4182 } 4183 4184 return 0; 4185 } 4186 4187 /* Load acc binary extension */ 4188 int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd, 4189 struct ia_css_fw_info *fw, 4190 enum ia_css_pipe_id pipe_id, 4191 unsigned int type) 4192 { 4193 struct ia_css_fw_info **hd; 4194 4195 fw->next = NULL; 4196 hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 4197 .pipe_configs[pipe_id].acc_extension); 4198 while (*hd) 4199 hd = &(*hd)->next; 4200 *hd = fw; 4201 4202 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 4203 .update_pipe[pipe_id] = true; 4204 return 0; 4205 } 4206 4207 /* Unload acc binary extension */ 4208 void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd, 4209 struct ia_css_fw_info *fw, 4210 enum ia_css_pipe_id pipe_id) 4211 { 4212 struct ia_css_fw_info **hd; 4213 4214 hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 4215 .pipe_configs[pipe_id].acc_extension); 4216 while (*hd && *hd != fw) 4217 hd = &(*hd)->next; 4218 if (!*hd) { 4219 dev_err(asd->isp->dev, "did not find acc fw for removal\n"); 4220 return; 4221 } 4222 *hd = fw->next; 4223 fw->next = NULL; 4224 4225 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 4226 .update_pipe[pipe_id] = true; 4227 } 4228 4229 int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd) 4230 { 4231 struct atomisp_device *isp = asd->isp; 4232 struct ia_css_pipe_config *pipe_config; 4233 struct atomisp_stream_env *stream_env = 4234 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 4235 4236 if (stream_env->acc_stream) { 4237 if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { 4238 if (ia_css_stream_stop(stream_env->acc_stream) 4239 != 0) { 4240 dev_err(isp->dev, "stop acc_stream failed.\n"); 4241 return -EBUSY; 4242 } 4243 } 4244 4245 if (ia_css_stream_destroy(stream_env->acc_stream) 4246 != 0) { 4247 dev_err(isp->dev, "destroy acc_stream failed.\n"); 4248 return -EBUSY; 4249 } 4250 stream_env->acc_stream = NULL; 4251 } 4252 4253 pipe_config = &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; 4254 ia_css_pipe_config_defaults(pipe_config); 4255 asd->acc.acc_stages = kzalloc(MAX_ACC_STAGES * 4256 sizeof(void *), GFP_KERNEL); 4257 if (!asd->acc.acc_stages) 4258 return -ENOMEM; 4259 pipe_config->acc_stages = asd->acc.acc_stages; 4260 pipe_config->mode = IA_CSS_PIPE_MODE_ACC; 4261 pipe_config->num_acc_stages = 0; 4262 4263 /* 4264 * We delay the ACC pipeline creation to atomisp_css_start_acc_pipe, 4265 * because pipe configuration will soon be changed by 4266 * atomisp_css_load_acc_binary() 4267 */ 4268 return 0; 4269 } 4270 4271 int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd) 4272 { 4273 struct atomisp_device *isp = asd->isp; 4274 struct atomisp_stream_env *stream_env = 4275 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 4276 struct ia_css_pipe_config *pipe_config = 4277 &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; 4278 4279 if (ia_css_pipe_create(pipe_config, 4280 &stream_env->pipes[IA_CSS_PIPE_ID_ACC]) != 0) { 4281 dev_err(isp->dev, "%s: ia_css_pipe_create failed\n", 4282 __func__); 4283 return -EBADE; 4284 } 4285 4286 memset(&stream_env->acc_stream_config, 0, 4287 sizeof(struct ia_css_stream_config)); 4288 if (ia_css_stream_create(&stream_env->acc_stream_config, 1, 4289 &stream_env->pipes[IA_CSS_PIPE_ID_ACC], 4290 &stream_env->acc_stream) != 0) { 4291 dev_err(isp->dev, "%s: create acc_stream error.\n", __func__); 4292 return -EINVAL; 4293 } 4294 stream_env->acc_stream_state = CSS_STREAM_CREATED; 4295 4296 init_completion(&asd->acc.acc_done); 4297 asd->acc.pipeline = stream_env->pipes[IA_CSS_PIPE_ID_ACC]; 4298 4299 atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false); 4300 4301 if (ia_css_start_sp()) { 4302 dev_err(isp->dev, "start sp error.\n"); 4303 return -EIO; 4304 } 4305 4306 if (ia_css_stream_start(stream_env->acc_stream) 4307 != 0) { 4308 dev_err(isp->dev, "acc_stream start error.\n"); 4309 return -EIO; 4310 } 4311 4312 stream_env->acc_stream_state = CSS_STREAM_STARTED; 4313 return 0; 4314 } 4315 4316 int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd) 4317 { 4318 struct atomisp_stream_env *stream_env = 4319 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 4320 if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { 4321 ia_css_stream_stop(stream_env->acc_stream); 4322 stream_env->acc_stream_state = CSS_STREAM_STOPPED; 4323 } 4324 return 0; 4325 } 4326 4327 void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd) 4328 { 4329 struct atomisp_stream_env *stream_env = 4330 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 4331 if (stream_env->acc_stream) { 4332 if (ia_css_stream_destroy(stream_env->acc_stream) 4333 != 0) 4334 dev_warn(asd->isp->dev, 4335 "destroy acc_stream failed.\n"); 4336 stream_env->acc_stream = NULL; 4337 } 4338 4339 if (stream_env->pipes[IA_CSS_PIPE_ID_ACC]) { 4340 if (ia_css_pipe_destroy(stream_env->pipes[IA_CSS_PIPE_ID_ACC]) 4341 != 0) 4342 dev_warn(asd->isp->dev, 4343 "destroy ACC pipe failed.\n"); 4344 stream_env->pipes[IA_CSS_PIPE_ID_ACC] = NULL; 4345 stream_env->update_pipe[IA_CSS_PIPE_ID_ACC] = false; 4346 ia_css_pipe_config_defaults( 4347 &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]); 4348 ia_css_pipe_extra_config_defaults( 4349 &stream_env->pipe_extra_configs[IA_CSS_PIPE_ID_ACC]); 4350 } 4351 asd->acc.pipeline = NULL; 4352 4353 /* css 2.0 API limitation: ia_css_stop_sp() could be only called after 4354 * destroy all pipes 4355 */ 4356 ia_css_stop_sp(); 4357 4358 kfree(asd->acc.acc_stages); 4359 asd->acc.acc_stages = NULL; 4360 4361 atomisp_freq_scaling(asd->isp, ATOMISP_DFS_MODE_LOW, false); 4362 } 4363 4364 int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd, 4365 struct ia_css_fw_info *fw, 4366 unsigned int index) 4367 { 4368 struct ia_css_pipe_config *pipe_config = 4369 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 4370 .pipe_configs[IA_CSS_PIPE_ID_ACC]; 4371 4372 if (index >= MAX_ACC_STAGES) { 4373 dev_dbg(asd->isp->dev, "%s: index(%d) out of range\n", 4374 __func__, index); 4375 return -ENOMEM; 4376 } 4377 4378 pipe_config->acc_stages[index] = fw; 4379 pipe_config->num_acc_stages = index + 1; 4380 pipe_config->acc_num_execs = 1; 4381 4382 return 0; 4383 } 4384 4385 static struct atomisp_sub_device *__get_atomisp_subdev( 4386 struct ia_css_pipe *css_pipe, 4387 struct atomisp_device *isp, 4388 enum atomisp_input_stream_id *stream_id) 4389 { 4390 int i, j, k; 4391 struct atomisp_sub_device *asd; 4392 struct atomisp_stream_env *stream_env; 4393 4394 for (i = 0; i < isp->num_of_streams; i++) { 4395 asd = &isp->asd[i]; 4396 if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED && 4397 !asd->acc.pipeline) 4398 continue; 4399 for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) { 4400 stream_env = &asd->stream_env[j]; 4401 for (k = 0; k < IA_CSS_PIPE_ID_NUM; k++) { 4402 if (stream_env->pipes[k] && 4403 stream_env->pipes[k] == css_pipe) { 4404 *stream_id = j; 4405 return asd; 4406 } 4407 } 4408 } 4409 } 4410 4411 return NULL; 4412 } 4413 4414 int atomisp_css_isr_thread(struct atomisp_device *isp, 4415 bool *frame_done_found, 4416 bool *css_pipe_done) 4417 { 4418 enum atomisp_input_stream_id stream_id = 0; 4419 struct atomisp_css_event current_event; 4420 struct atomisp_sub_device *asd; 4421 bool reset_wdt_timer[MAX_STREAM_NUM] = {false}; 4422 int i; 4423 4424 while (!atomisp_css_dequeue_event(¤t_event)) { 4425 if (current_event.event.type == 4426 IA_CSS_EVENT_TYPE_FW_ASSERT) { 4427 /* 4428 * Received FW assertion signal, 4429 * trigger WDT to recover 4430 */ 4431 dev_err(isp->dev, 4432 "%s: ISP reports FW_ASSERT event! fw_assert_module_id %d fw_assert_line_no %d\n", 4433 __func__, 4434 current_event.event.fw_assert_module_id, 4435 current_event.event.fw_assert_line_no); 4436 for (i = 0; i < isp->num_of_streams; i++) 4437 atomisp_wdt_stop(&isp->asd[i], 0); 4438 4439 if (!atomisp_hw_is_isp2401) 4440 atomisp_wdt(&isp->asd[0].wdt); 4441 else 4442 queue_work(isp->wdt_work_queue, &isp->wdt_work); 4443 4444 return -EINVAL; 4445 } else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) { 4446 dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n", 4447 __func__, current_event.event.fw_warning, 4448 current_event.event.exp_id); 4449 continue; 4450 } 4451 4452 asd = __get_atomisp_subdev(current_event.event.pipe, 4453 isp, &stream_id); 4454 if (!asd) { 4455 if (current_event.event.type == IA_CSS_EVENT_TYPE_TIMER) 4456 dev_dbg(isp->dev, 4457 "event: Timer event."); 4458 else 4459 dev_warn(isp->dev, "%s:no subdev.event:%d", 4460 __func__, 4461 current_event.event.type); 4462 continue; 4463 } 4464 4465 atomisp_css_temp_pipe_to_pipe_id(asd, ¤t_event); 4466 switch (current_event.event.type) { 4467 case IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE: 4468 dev_dbg(isp->dev, "event: Output frame done"); 4469 frame_done_found[asd->index] = true; 4470 atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, 4471 current_event.pipe, true, stream_id); 4472 4473 if (!atomisp_hw_is_isp2401) 4474 reset_wdt_timer[asd->index] = true; /* ISP running */ 4475 4476 break; 4477 case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE: 4478 dev_dbg(isp->dev, "event: Second output frame done"); 4479 frame_done_found[asd->index] = true; 4480 atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME, 4481 current_event.pipe, true, stream_id); 4482 4483 if (!atomisp_hw_is_isp2401) 4484 reset_wdt_timer[asd->index] = true; /* ISP running */ 4485 4486 break; 4487 case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE: 4488 dev_dbg(isp->dev, "event: 3A stats frame done"); 4489 atomisp_buf_done(asd, 0, 4490 IA_CSS_BUFFER_TYPE_3A_STATISTICS, 4491 current_event.pipe, 4492 false, stream_id); 4493 break; 4494 case IA_CSS_EVENT_TYPE_METADATA_DONE: 4495 dev_dbg(isp->dev, "event: metadata frame done"); 4496 atomisp_buf_done(asd, 0, 4497 IA_CSS_BUFFER_TYPE_METADATA, 4498 current_event.pipe, 4499 false, stream_id); 4500 break; 4501 case IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE: 4502 dev_dbg(isp->dev, "event: VF output frame done"); 4503 atomisp_buf_done(asd, 0, 4504 IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, 4505 current_event.pipe, true, stream_id); 4506 4507 if (!atomisp_hw_is_isp2401) 4508 reset_wdt_timer[asd->index] = true; /* ISP running */ 4509 4510 break; 4511 case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE: 4512 dev_dbg(isp->dev, "event: second VF output frame done"); 4513 atomisp_buf_done(asd, 0, 4514 IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME, 4515 current_event.pipe, true, stream_id); 4516 if (!atomisp_hw_is_isp2401) 4517 reset_wdt_timer[asd->index] = true; /* ISP running */ 4518 4519 break; 4520 case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE: 4521 dev_dbg(isp->dev, "event: dis stats frame done"); 4522 atomisp_buf_done(asd, 0, 4523 IA_CSS_BUFFER_TYPE_DIS_STATISTICS, 4524 current_event.pipe, 4525 false, stream_id); 4526 break; 4527 case IA_CSS_EVENT_TYPE_PIPELINE_DONE: 4528 dev_dbg(isp->dev, "event: pipeline done"); 4529 css_pipe_done[asd->index] = true; 4530 break; 4531 case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE: 4532 dev_dbg(isp->dev, "event: acc stage done"); 4533 atomisp_acc_done(asd, current_event.event.fw_handle); 4534 break; 4535 default: 4536 dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n", 4537 current_event.event.type); 4538 break; 4539 } 4540 } 4541 4542 if (atomisp_hw_is_isp2401) 4543 return 0; 4544 4545 /* ISP2400: If there are no buffers queued then delete wdt timer. */ 4546 for (i = 0; i < isp->num_of_streams; i++) { 4547 asd = &isp->asd[i]; 4548 if (!asd) 4549 continue; 4550 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 4551 continue; 4552 if (!atomisp_buffers_queued(asd)) 4553 atomisp_wdt_stop(asd, false); 4554 else if (reset_wdt_timer[i]) 4555 /* SOF irq should not reset wdt timer. */ 4556 atomisp_wdt_refresh(asd, 4557 ATOMISP_WDT_KEEP_CURRENT_DELAY); 4558 } 4559 4560 return 0; 4561 } 4562 4563 bool atomisp_css_valid_sof(struct atomisp_device *isp) 4564 { 4565 unsigned int i, j; 4566 4567 /* Loop for each css stream */ 4568 for (i = 0; i < isp->num_of_streams; i++) { 4569 struct atomisp_sub_device *asd = &isp->asd[i]; 4570 /* Loop for each css vc stream */ 4571 for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) { 4572 if (asd->stream_env[j].stream && 4573 asd->stream_env[j].stream_config.mode == 4574 IA_CSS_INPUT_MODE_BUFFERED_SENSOR) 4575 return false; 4576 } 4577 } 4578 4579 return true; 4580 } 4581 4582 int atomisp_css_debug_dump_isp_binary(void) 4583 { 4584 ia_css_debug_dump_isp_binary(); 4585 return 0; 4586 } 4587 4588 int atomisp_css_dump_sp_raw_copy_linecount(bool reduced) 4589 { 4590 sh_css_dump_sp_raw_copy_linecount(reduced); 4591 return 0; 4592 } 4593 4594 int atomisp_css_dump_blob_infor(void) 4595 { 4596 struct ia_css_blob_descr *bd = sh_css_blob_info; 4597 unsigned int i, nm = sh_css_num_binaries; 4598 4599 if (nm == 0) 4600 return -EPERM; 4601 if (!bd) 4602 return -EPERM; 4603 4604 for (i = 1; i < sh_css_num_binaries; i++) 4605 dev_dbg(atomisp_dev, "Num%d binary id is %d, name is %s\n", i, 4606 bd[i - 1].header.info.isp.sp.id, bd[i - 1].name); 4607 4608 return 0; 4609 } 4610 4611 void atomisp_css_set_isp_config_id(struct atomisp_sub_device *asd, 4612 uint32_t isp_config_id) 4613 { 4614 asd->params.config.isp_config_id = isp_config_id; 4615 } 4616 4617 void atomisp_css_set_isp_config_applied_frame(struct atomisp_sub_device *asd, 4618 struct ia_css_frame *output_frame) 4619 { 4620 asd->params.config.output_frame = output_frame; 4621 } 4622 4623 int atomisp_get_css_dbgfunc(void) 4624 { 4625 return dbg_func; 4626 } 4627 4628 int atomisp_set_css_dbgfunc(struct atomisp_device *isp, int opt) 4629 { 4630 int ret; 4631 4632 ret = __set_css_print_env(isp, opt); 4633 if (ret == 0) 4634 dbg_func = opt; 4635 4636 return ret; 4637 } 4638 4639 void atomisp_en_dz_capt_pipe(struct atomisp_sub_device *asd, bool enable) 4640 { 4641 ia_css_en_dz_capt_pipe( 4642 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 4643 enable); 4644 } 4645 4646 struct ia_css_dvs_grid_info *atomisp_css_get_dvs_grid_info( 4647 struct ia_css_grid_info *grid_info) 4648 { 4649 if (!grid_info) 4650 return NULL; 4651 4652 #ifdef IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED 4653 return &grid_info->dvs_grid.dvs_grid_info; 4654 #else 4655 return &grid_info->dvs_grid; 4656 #endif 4657 } 4658