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