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