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