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