1 /* 2 * Support for Medifield PNW Camera Imaging ISP subsystem. 3 * 4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved. 5 * 6 * Copyright (c) 2010 Silicon Hive www.siliconhive.com. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 10 * 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * 18 */ 19 #include <linux/firmware.h> 20 #include <linux/pci.h> 21 #include <linux/interrupt.h> 22 #include <linux/kernel.h> 23 #include <linux/kfifo.h> 24 #include <linux/pm_runtime.h> 25 #include <linux/timer.h> 26 27 #include <asm/iosf_mbi.h> 28 29 #include <media/v4l2-event.h> 30 #include <media/videobuf-vmalloc.h> 31 32 #define CREATE_TRACE_POINTS 33 #include "atomisp_trace_event.h" 34 35 #include "atomisp_cmd.h" 36 #include "atomisp_common.h" 37 #include "atomisp_fops.h" 38 #include "atomisp_internal.h" 39 #include "atomisp_ioctl.h" 40 #include "atomisp-regs.h" 41 #include "atomisp_tables.h" 42 #include "atomisp_acc.h" 43 #include "atomisp_compat.h" 44 #include "atomisp_subdev.h" 45 #include "atomisp_dfs_tables.h" 46 47 #include "hrt/hive_isp_css_mm_hrt.h" 48 49 #include "sh_css_hrt.h" 50 #include "sh_css_defs.h" 51 #include "system_global.h" 52 #include "sh_css_internal.h" 53 #include "sh_css_sp.h" 54 #include "gp_device.h" 55 #include "device_access.h" 56 #include "irq.h" 57 58 #include "ia_css_types.h" 59 #include "ia_css_stream.h" 60 #include "error_support.h" 61 #include "bits.h" 62 63 /* We should never need to run the flash for more than 2 frames. 64 * At 15fps this means 133ms. We set the timeout a bit longer. 65 * Each flash driver is supposed to set its own timeout, but 66 * just in case someone else changed the timeout, we set it 67 * here to make sure we don't damage the flash hardware. */ 68 #define FLASH_TIMEOUT 800 /* ms */ 69 70 union host { 71 struct { 72 void *kernel_ptr; 73 void __user *user_ptr; 74 int size; 75 } scalar; 76 struct { 77 void *hmm_ptr; 78 } ptr; 79 }; 80 81 /* 82 * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. 83 * subdev->priv is set in mrst.c 84 */ 85 struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd) 86 { 87 return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd); 88 } 89 90 /* 91 * get struct atomisp_video_pipe from v4l2 video_device 92 */ 93 struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev) 94 { 95 return (struct atomisp_video_pipe *) 96 container_of(dev, struct atomisp_video_pipe, vdev); 97 } 98 99 /* 100 * get struct atomisp_acc_pipe from v4l2 video_device 101 */ 102 struct atomisp_acc_pipe *atomisp_to_acc_pipe(struct video_device *dev) 103 { 104 return (struct atomisp_acc_pipe *) 105 container_of(dev, struct atomisp_acc_pipe, vdev); 106 } 107 108 static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd) 109 { 110 struct v4l2_subdev_frame_interval fi; 111 struct atomisp_device *isp = asd->isp; 112 113 unsigned short fps = 0; 114 int ret; 115 116 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 117 video, g_frame_interval, &fi); 118 119 if (!ret && fi.interval.numerator) 120 fps = fi.interval.denominator / fi.interval.numerator; 121 122 return fps; 123 } 124 125 /* 126 * DFS progress is shown as follows: 127 * 1. Target frequency is calculated according to FPS/Resolution/ISP running 128 * mode. 129 * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1 130 * with proper rounding. 131 * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40 132 * to 200MHz in ISPSSPM1. 133 * 4. Wait for FREQVALID to be cleared by P-Unit. 134 * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3. 135 */ 136 static int write_target_freq_to_hw(struct atomisp_device *isp, 137 unsigned int new_freq) 138 { 139 unsigned int ratio, timeout, guar_ratio; 140 u32 isp_sspm1 = 0; 141 int i; 142 143 if (!isp->hpll_freq) { 144 dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n"); 145 return -EINVAL; 146 } 147 148 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 149 if (isp_sspm1 & ISP_FREQ_VALID_MASK) { 150 dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n"); 151 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, 152 isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET)); 153 } 154 155 ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1; 156 guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1; 157 158 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 159 isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET); 160 161 for (i = 0; i < ISP_DFS_TRY_TIMES; i++) { 162 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, 163 isp_sspm1 164 | ratio << ISP_REQ_FREQ_OFFSET 165 | 1 << ISP_FREQ_VALID_OFFSET 166 | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET); 167 168 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 169 timeout = 20; 170 while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) { 171 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 172 dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n"); 173 udelay(100); 174 timeout--; 175 } 176 177 if (timeout != 0) 178 break; 179 } 180 181 if (timeout == 0) { 182 dev_err(isp->dev, "DFS failed due to HW error.\n"); 183 return -EINVAL; 184 } 185 186 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 187 timeout = 10; 188 while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) { 189 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 190 dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n", 191 new_freq); 192 udelay(100); 193 timeout--; 194 } 195 if (timeout == 0) { 196 dev_err(isp->dev, "DFS target freq is rejected by HW.\n"); 197 return -EINVAL; 198 } 199 200 return 0; 201 } 202 203 int atomisp_freq_scaling(struct atomisp_device *isp, 204 enum atomisp_dfs_mode mode, 205 bool force) 206 { 207 /* FIXME! Only use subdev[0] status yet */ 208 struct atomisp_sub_device *asd = &isp->asd[0]; 209 const struct atomisp_dfs_config *dfs; 210 unsigned int new_freq; 211 struct atomisp_freq_scaling_rule curr_rules; 212 int i, ret; 213 unsigned short fps = 0; 214 215 if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP) { 216 dev_err(isp->dev, "DFS cannot proceed due to no power.\n"); 217 return -EINVAL; 218 } 219 220 if ((isp->pdev->device & ATOMISP_PCI_DEVICE_SOC_MASK) == 221 ATOMISP_PCI_DEVICE_SOC_CHT && ATOMISP_USE_YUVPP(asd)) 222 isp->dfs = &dfs_config_cht_soc; 223 224 dfs = isp->dfs; 225 226 if (dfs->lowest_freq == 0 || dfs->max_freq_at_vmin == 0 || 227 dfs->highest_freq == 0 || dfs->dfs_table_size == 0 || 228 !dfs->dfs_table) { 229 dev_err(isp->dev, "DFS configuration is invalid.\n"); 230 return -EINVAL; 231 } 232 233 if (mode == ATOMISP_DFS_MODE_LOW) { 234 new_freq = dfs->lowest_freq; 235 goto done; 236 } 237 238 if (mode == ATOMISP_DFS_MODE_MAX) { 239 new_freq = dfs->highest_freq; 240 goto done; 241 } 242 243 fps = atomisp_get_sensor_fps(asd); 244 if (fps == 0) 245 return -EINVAL; 246 247 curr_rules.width = asd->fmt[asd->capture_pad].fmt.width; 248 curr_rules.height = asd->fmt[asd->capture_pad].fmt.height; 249 curr_rules.fps = fps; 250 curr_rules.run_mode = asd->run_mode->val; 251 /* 252 * For continuous mode, we need to make the capture setting applied 253 * since preview mode, because there is no chance to do this when 254 * starting image capture. 255 */ 256 if (asd->continuous_mode->val) { 257 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) 258 curr_rules.run_mode = ATOMISP_RUN_MODE_SDV; 259 else 260 curr_rules.run_mode = 261 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE; 262 } 263 264 /* search for the target frequency by looping freq rules*/ 265 for (i = 0; i < dfs->dfs_table_size; i++) { 266 if (curr_rules.width != dfs->dfs_table[i].width && 267 dfs->dfs_table[i].width != ISP_FREQ_RULE_ANY) 268 continue; 269 if (curr_rules.height != dfs->dfs_table[i].height && 270 dfs->dfs_table[i].height != ISP_FREQ_RULE_ANY) 271 continue; 272 if (curr_rules.fps != dfs->dfs_table[i].fps && 273 dfs->dfs_table[i].fps != ISP_FREQ_RULE_ANY) 274 continue; 275 if (curr_rules.run_mode != dfs->dfs_table[i].run_mode && 276 dfs->dfs_table[i].run_mode != ISP_FREQ_RULE_ANY) 277 continue; 278 break; 279 } 280 281 if (i == dfs->dfs_table_size) 282 new_freq = dfs->max_freq_at_vmin; 283 else 284 new_freq = dfs->dfs_table[i].isp_freq; 285 286 done: 287 dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq); 288 289 if ((new_freq == isp->sw_contex.running_freq) && !force) 290 return 0; 291 292 dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq); 293 294 ret = write_target_freq_to_hw(isp, new_freq); 295 if (!ret) { 296 isp->sw_contex.running_freq = new_freq; 297 trace_ipu_pstate(new_freq, -1); 298 } 299 return ret; 300 } 301 302 /* 303 * reset and restore ISP 304 */ 305 int atomisp_reset(struct atomisp_device *isp) 306 { 307 /* Reset ISP by power-cycling it */ 308 int ret = 0; 309 310 dev_dbg(isp->dev, "%s\n", __func__); 311 atomisp_css_suspend(isp); 312 ret = atomisp_runtime_suspend(isp->dev); 313 if (ret < 0) 314 dev_err(isp->dev, "atomisp_runtime_suspend failed, %d\n", ret); 315 ret = atomisp_mrfld_power_down(isp); 316 if (ret < 0) { 317 dev_err(isp->dev, "can not disable ISP power\n"); 318 } else { 319 ret = atomisp_mrfld_power_up(isp); 320 if (ret < 0) 321 dev_err(isp->dev, "can not enable ISP power\n"); 322 ret = atomisp_runtime_resume(isp->dev); 323 if (ret < 0) 324 dev_err(isp->dev, "atomisp_runtime_resume failed, %d\n", ret); 325 } 326 ret = atomisp_css_resume(isp); 327 if (ret) 328 isp->isp_fatal_error = true; 329 330 return ret; 331 } 332 333 /* 334 * interrupt disable functions 335 */ 336 static void disable_isp_irq(enum hrt_isp_css_irq irq) 337 { 338 irq_disable_channel(IRQ0_ID, irq); 339 340 if (irq != hrt_isp_css_irq_sp) 341 return; 342 343 cnd_sp_irq_enable(SP0_ID, false); 344 } 345 346 /* 347 * interrupt clean function 348 */ 349 static void clear_isp_irq(enum hrt_isp_css_irq irq) 350 { 351 irq_clear_all(IRQ0_ID); 352 } 353 354 void atomisp_msi_irq_init(struct atomisp_device *isp, struct pci_dev *dev) 355 { 356 u32 msg32; 357 u16 msg16; 358 359 pci_read_config_dword(dev, PCI_MSI_CAPID, &msg32); 360 msg32 |= 1 << MSI_ENABLE_BIT; 361 pci_write_config_dword(dev, PCI_MSI_CAPID, msg32); 362 363 msg32 = (1 << INTR_IER) | (1 << INTR_IIR); 364 pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, msg32); 365 366 pci_read_config_word(dev, PCI_COMMAND, &msg16); 367 msg16 |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 368 PCI_COMMAND_INTX_DISABLE); 369 pci_write_config_word(dev, PCI_COMMAND, msg16); 370 } 371 372 void atomisp_msi_irq_uninit(struct atomisp_device *isp, struct pci_dev *dev) 373 { 374 u32 msg32; 375 u16 msg16; 376 377 pci_read_config_dword(dev, PCI_MSI_CAPID, &msg32); 378 msg32 &= ~(1 << MSI_ENABLE_BIT); 379 pci_write_config_dword(dev, PCI_MSI_CAPID, msg32); 380 381 msg32 = 0x0; 382 pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, msg32); 383 384 pci_read_config_word(dev, PCI_COMMAND, &msg16); 385 msg16 &= ~(PCI_COMMAND_MASTER); 386 pci_write_config_word(dev, PCI_COMMAND, msg16); 387 } 388 389 static void atomisp_sof_event(struct atomisp_sub_device *asd) 390 { 391 struct v4l2_event event = {0}; 392 393 event.type = V4L2_EVENT_FRAME_SYNC; 394 event.u.frame_sync.frame_sequence = atomic_read(&asd->sof_count); 395 396 v4l2_event_queue(asd->subdev.devnode, &event); 397 } 398 399 void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id) 400 { 401 struct v4l2_event event = {0}; 402 403 event.type = V4L2_EVENT_FRAME_END; 404 event.u.frame_sync.frame_sequence = exp_id; 405 406 v4l2_event_queue(asd->subdev.devnode, &event); 407 } 408 409 static void atomisp_3a_stats_ready_event(struct atomisp_sub_device *asd, 410 uint8_t exp_id) 411 { 412 struct v4l2_event event = {0}; 413 414 event.type = V4L2_EVENT_ATOMISP_3A_STATS_READY; 415 event.u.frame_sync.frame_sequence = exp_id; 416 417 v4l2_event_queue(asd->subdev.devnode, &event); 418 } 419 420 static void atomisp_metadata_ready_event(struct atomisp_sub_device *asd, 421 enum atomisp_metadata_type md_type) 422 { 423 struct v4l2_event event = {0}; 424 425 event.type = V4L2_EVENT_ATOMISP_METADATA_READY; 426 event.u.data[0] = md_type; 427 428 v4l2_event_queue(asd->subdev.devnode, &event); 429 } 430 431 static void atomisp_reset_event(struct atomisp_sub_device *asd) 432 { 433 struct v4l2_event event = {0}; 434 435 event.type = V4L2_EVENT_ATOMISP_CSS_RESET; 436 437 v4l2_event_queue(asd->subdev.devnode, &event); 438 } 439 440 static void print_csi_rx_errors(enum mipi_port_id port, 441 struct atomisp_device *isp) 442 { 443 u32 infos = 0; 444 445 atomisp_css_rx_get_irq_info(port, &infos); 446 447 dev_err(isp->dev, "CSI Receiver port %d errors:\n", port); 448 if (infos & CSS_RX_IRQ_INFO_BUFFER_OVERRUN) 449 dev_err(isp->dev, " buffer overrun"); 450 if (infos & CSS_RX_IRQ_INFO_ERR_SOT) 451 dev_err(isp->dev, " start-of-transmission error"); 452 if (infos & CSS_RX_IRQ_INFO_ERR_SOT_SYNC) 453 dev_err(isp->dev, " start-of-transmission sync error"); 454 if (infos & CSS_RX_IRQ_INFO_ERR_CONTROL) 455 dev_err(isp->dev, " control error"); 456 if (infos & CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) 457 dev_err(isp->dev, " 2 or more ECC errors"); 458 if (infos & CSS_RX_IRQ_INFO_ERR_CRC) 459 dev_err(isp->dev, " CRC mismatch"); 460 if (infos & CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) 461 dev_err(isp->dev, " unknown error"); 462 if (infos & CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) 463 dev_err(isp->dev, " frame sync error"); 464 if (infos & CSS_RX_IRQ_INFO_ERR_FRAME_DATA) 465 dev_err(isp->dev, " frame data error"); 466 if (infos & CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) 467 dev_err(isp->dev, " data timeout"); 468 if (infos & CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) 469 dev_err(isp->dev, " unknown escape command entry"); 470 if (infos & CSS_RX_IRQ_INFO_ERR_LINE_SYNC) 471 dev_err(isp->dev, " line sync error"); 472 } 473 474 /* Clear irq reg */ 475 static void clear_irq_reg(struct atomisp_device *isp) 476 { 477 u32 msg_ret; 478 479 pci_read_config_dword(isp->pdev, PCI_INTERRUPT_CTRL, &msg_ret); 480 msg_ret |= 1 << INTR_IIR; 481 pci_write_config_dword(isp->pdev, PCI_INTERRUPT_CTRL, msg_ret); 482 } 483 484 static struct atomisp_sub_device * 485 __get_asd_from_port(struct atomisp_device *isp, enum mipi_port_id port) 486 { 487 int i; 488 489 /* Check which isp subdev to send eof */ 490 for (i = 0; i < isp->num_of_streams; i++) { 491 struct atomisp_sub_device *asd = &isp->asd[i]; 492 struct camera_mipi_info *mipi_info; 493 494 mipi_info = atomisp_to_sensor_mipi_info( 495 isp->inputs[asd->input_curr].camera); 496 497 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED && 498 __get_mipi_port(isp, mipi_info->port) == port) { 499 return asd; 500 } 501 } 502 503 return NULL; 504 } 505 506 /* interrupt handling function*/ 507 irqreturn_t atomisp_isr(int irq, void *dev) 508 { 509 struct atomisp_device *isp = (struct atomisp_device *)dev; 510 struct atomisp_sub_device *asd; 511 struct atomisp_css_event eof_event; 512 unsigned int irq_infos = 0; 513 unsigned long flags; 514 unsigned int i; 515 int err; 516 517 spin_lock_irqsave(&isp->lock, flags); 518 if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP || 519 !isp->css_initialized) { 520 spin_unlock_irqrestore(&isp->lock, flags); 521 return IRQ_HANDLED; 522 } 523 err = atomisp_css_irq_translate(isp, &irq_infos); 524 if (err) { 525 spin_unlock_irqrestore(&isp->lock, flags); 526 return IRQ_NONE; 527 } 528 529 dev_dbg(isp->dev, "irq:0x%x\n", irq_infos); 530 531 clear_irq_reg(isp); 532 533 if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) 534 goto out_nowake; 535 536 for (i = 0; i < isp->num_of_streams; i++) { 537 asd = &isp->asd[i]; 538 539 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 540 continue; 541 /* 542 * Current SOF only support one stream, so the SOF only valid 543 * either solely one stream is running 544 */ 545 if (irq_infos & CSS_IRQ_INFO_CSS_RECEIVER_SOF) { 546 atomic_inc(&asd->sof_count); 547 atomisp_sof_event(asd); 548 549 /* If sequence_temp and sequence are the same 550 * there where no frames lost so we can increase 551 * sequence_temp. 552 * If not then processing of frame is still in progress 553 * and driver needs to keep old sequence_temp value. 554 * NOTE: There is assumption here that ISP will not 555 * start processing next frame from sensor before old 556 * one is completely done. */ 557 if (atomic_read(&asd->sequence) == atomic_read( 558 &asd->sequence_temp)) 559 atomic_set(&asd->sequence_temp, 560 atomic_read(&asd->sof_count)); 561 } 562 if (irq_infos & CSS_IRQ_INFO_EVENTS_READY) 563 atomic_set(&asd->sequence, 564 atomic_read(&asd->sequence_temp)); 565 } 566 567 if (irq_infos & CSS_IRQ_INFO_CSS_RECEIVER_SOF) 568 irq_infos &= ~CSS_IRQ_INFO_CSS_RECEIVER_SOF; 569 570 if ((irq_infos & CSS_IRQ_INFO_INPUT_SYSTEM_ERROR) || 571 (irq_infos & CSS_IRQ_INFO_IF_ERROR)) { 572 /* handle mipi receiver error */ 573 u32 rx_infos; 574 enum mipi_port_id port; 575 576 for (port = MIPI_PORT0_ID; port <= MIPI_PORT2_ID; 577 port++) { 578 print_csi_rx_errors(port, isp); 579 atomisp_css_rx_get_irq_info(port, &rx_infos); 580 atomisp_css_rx_clear_irq_info(port, rx_infos); 581 } 582 } 583 584 if (irq_infos & IA_CSS_IRQ_INFO_ISYS_EVENTS_READY) { 585 while (ia_css_dequeue_isys_event(&eof_event.event) == 586 IA_CSS_SUCCESS) { 587 /* EOF Event does not have the css_pipe returned */ 588 asd = __get_asd_from_port(isp, eof_event.event.port); 589 if (!asd) { 590 dev_err(isp->dev, "%s:no subdev.event:%d", __func__, 591 eof_event.event.type); 592 continue; 593 } 594 595 atomisp_eof_event(asd, eof_event.event.exp_id); 596 dev_dbg(isp->dev, "%s EOF exp_id %d, asd %d\n", 597 __func__, eof_event.event.exp_id, asd->index); 598 } 599 600 irq_infos &= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY; 601 if (irq_infos == 0) 602 goto out_nowake; 603 } 604 605 spin_unlock_irqrestore(&isp->lock, flags); 606 607 return IRQ_WAKE_THREAD; 608 609 out_nowake: 610 spin_unlock_irqrestore(&isp->lock, flags); 611 612 return IRQ_HANDLED; 613 } 614 615 void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd) 616 { 617 int i; 618 619 memset(asd->s3a_bufs_in_css, 0, sizeof(asd->s3a_bufs_in_css)); 620 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) 621 memset(asd->metadata_bufs_in_css[i], 0, 622 sizeof(asd->metadata_bufs_in_css[i])); 623 asd->dis_bufs_in_css = 0; 624 asd->video_out_capture.buffers_in_css = 0; 625 asd->video_out_vf.buffers_in_css = 0; 626 asd->video_out_preview.buffers_in_css = 0; 627 asd->video_out_video_capture.buffers_in_css = 0; 628 } 629 630 /* ISP2400 */ 631 bool atomisp_buffers_queued(struct atomisp_sub_device *asd) 632 { 633 return asd->video_out_capture.buffers_in_css || 634 asd->video_out_vf.buffers_in_css || 635 asd->video_out_preview.buffers_in_css || 636 asd->video_out_video_capture.buffers_in_css ? 637 true : false; 638 } 639 640 /* ISP2401 */ 641 bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe) 642 { 643 return pipe->buffers_in_css ? true : false; 644 } 645 646 /* 0x100000 is the start of dmem inside SP */ 647 #define SP_DMEM_BASE 0x100000 648 649 void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr, 650 unsigned int size) 651 { 652 unsigned int data = 0; 653 unsigned int size32 = DIV_ROUND_UP(size, sizeof(u32)); 654 655 dev_dbg(isp->dev, "atomisp_io_base:%p\n", atomisp_io_base); 656 dev_dbg(isp->dev, "%s, addr:0x%x, size: %d, size32: %d\n", __func__, 657 addr, size, size32); 658 if (size32 * 4 + addr > 0x4000) { 659 dev_err(isp->dev, "illegal size (%d) or addr (0x%x)\n", 660 size32, addr); 661 return; 662 } 663 addr += SP_DMEM_BASE; 664 do { 665 data = _hrt_master_port_uload_32(addr); 666 667 dev_dbg(isp->dev, "%s, \t [0x%x]:0x%x\n", __func__, addr, data); 668 addr += sizeof(unsigned int); 669 size32 -= 1; 670 } while (size32 > 0); 671 } 672 673 static struct videobuf_buffer *atomisp_css_frame_to_vbuf( 674 struct atomisp_video_pipe *pipe, struct atomisp_css_frame *frame) 675 { 676 struct videobuf_vmalloc_memory *vm_mem; 677 struct atomisp_css_frame *handle; 678 int i; 679 680 for (i = 0; pipe->capq.bufs[i]; i++) { 681 vm_mem = pipe->capq.bufs[i]->priv; 682 handle = vm_mem->vaddr; 683 if (handle && handle->data == frame->data) 684 return pipe->capq.bufs[i]; 685 } 686 687 return NULL; 688 } 689 690 static void atomisp_flush_video_pipe(struct atomisp_sub_device *asd, 691 struct atomisp_video_pipe *pipe) 692 { 693 unsigned long irqflags; 694 int i; 695 696 if (!pipe->users) 697 return; 698 699 for (i = 0; pipe->capq.bufs[i]; i++) { 700 spin_lock_irqsave(&pipe->irq_lock, irqflags); 701 if (pipe->capq.bufs[i]->state == VIDEOBUF_ACTIVE || 702 pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED) { 703 pipe->capq.bufs[i]->ts = ktime_get_ns(); 704 pipe->capq.bufs[i]->field_count = 705 atomic_read(&asd->sequence) << 1; 706 dev_dbg(asd->isp->dev, "release buffers on device %s\n", 707 pipe->vdev.name); 708 if (pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED) 709 list_del_init(&pipe->capq.bufs[i]->queue); 710 pipe->capq.bufs[i]->state = VIDEOBUF_ERROR; 711 wake_up(&pipe->capq.bufs[i]->done); 712 } 713 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 714 } 715 } 716 717 /* Returns queued buffers back to video-core */ 718 void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd) 719 { 720 atomisp_flush_video_pipe(asd, &asd->video_out_capture); 721 atomisp_flush_video_pipe(asd, &asd->video_out_vf); 722 atomisp_flush_video_pipe(asd, &asd->video_out_preview); 723 atomisp_flush_video_pipe(asd, &asd->video_out_video_capture); 724 } 725 726 /* clean out the parameters that did not apply */ 727 void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe) 728 { 729 struct atomisp_css_params_with_list *param; 730 731 while (!list_empty(&pipe->per_frame_params)) { 732 param = list_entry(pipe->per_frame_params.next, 733 struct atomisp_css_params_with_list, list); 734 list_del(¶m->list); 735 atomisp_free_css_parameters(¶m->params); 736 kvfree(param); 737 } 738 } 739 740 /* Re-queue per-frame parameters */ 741 static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe) 742 { 743 struct atomisp_css_params_with_list *param; 744 int i; 745 746 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 747 param = pipe->frame_params[i]; 748 if (param) 749 list_add_tail(¶m->list, &pipe->per_frame_params); 750 pipe->frame_params[i] = NULL; 751 } 752 atomisp_handle_parameter_and_buffer(pipe); 753 } 754 755 /* find atomisp_video_pipe with css pipe id, buffer type and atomisp run_mode */ 756 static struct atomisp_video_pipe *__atomisp_get_pipe( 757 struct atomisp_sub_device *asd, 758 enum atomisp_input_stream_id stream_id, 759 enum atomisp_css_pipe_id css_pipe_id, 760 enum atomisp_css_buffer_type buf_type) 761 { 762 struct atomisp_device *isp = asd->isp; 763 764 if (css_pipe_id == CSS_PIPE_ID_COPY && 765 isp->inputs[asd->input_curr].camera_caps-> 766 sensor[asd->sensor_curr].stream_num > 1) { 767 switch (stream_id) { 768 case ATOMISP_INPUT_STREAM_PREVIEW: 769 return &asd->video_out_preview; 770 case ATOMISP_INPUT_STREAM_POSTVIEW: 771 return &asd->video_out_vf; 772 case ATOMISP_INPUT_STREAM_VIDEO: 773 return &asd->video_out_video_capture; 774 case ATOMISP_INPUT_STREAM_CAPTURE: 775 default: 776 return &asd->video_out_capture; 777 } 778 } 779 780 /* video is same in online as in continuouscapture mode */ 781 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 782 /* 783 * Disable vf_pp and run CSS in still capture mode. In this 784 * mode, CSS does not cause extra latency with buffering, but 785 * scaling is not available. 786 */ 787 return &asd->video_out_capture; 788 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 789 /* 790 * Disable vf_pp and run CSS in video mode. This allows using 791 * ISP scaling but it has one frame delay due to CSS internal 792 * buffering. 793 */ 794 return &asd->video_out_video_capture; 795 } else if (css_pipe_id == CSS_PIPE_ID_YUVPP) { 796 /* 797 * to SOC camera, yuvpp pipe is run for capture/video/SDV/ZSL. 798 */ 799 if (asd->continuous_mode->val) { 800 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 801 /* SDV case */ 802 switch (buf_type) { 803 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 804 return &asd->video_out_video_capture; 805 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: 806 return &asd->video_out_preview; 807 case CSS_BUFFER_TYPE_OUTPUT_FRAME: 808 return &asd->video_out_capture; 809 default: 810 return &asd->video_out_vf; 811 } 812 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { 813 /* ZSL case */ 814 switch (buf_type) { 815 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 816 return &asd->video_out_preview; 817 case CSS_BUFFER_TYPE_OUTPUT_FRAME: 818 return &asd->video_out_capture; 819 default: 820 return &asd->video_out_vf; 821 } 822 } 823 } else if (buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) { 824 switch (asd->run_mode->val) { 825 case ATOMISP_RUN_MODE_VIDEO: 826 return &asd->video_out_video_capture; 827 case ATOMISP_RUN_MODE_PREVIEW: 828 return &asd->video_out_preview; 829 default: 830 return &asd->video_out_capture; 831 } 832 } else if (buf_type == CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 833 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) 834 return &asd->video_out_preview; 835 else 836 return &asd->video_out_vf; 837 } 838 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 839 /* For online video or SDV video pipe. */ 840 if (css_pipe_id == CSS_PIPE_ID_VIDEO || 841 css_pipe_id == CSS_PIPE_ID_COPY) { 842 if (buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) 843 return &asd->video_out_video_capture; 844 return &asd->video_out_preview; 845 } 846 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { 847 /* For online preview or ZSL preview pipe. */ 848 if (css_pipe_id == CSS_PIPE_ID_PREVIEW || 849 css_pipe_id == CSS_PIPE_ID_COPY) 850 return &asd->video_out_preview; 851 } 852 /* For capture pipe. */ 853 if (buf_type == CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) 854 return &asd->video_out_vf; 855 return &asd->video_out_capture; 856 } 857 858 enum atomisp_metadata_type 859 atomisp_get_metadata_type(struct atomisp_sub_device *asd, 860 enum ia_css_pipe_id pipe_id) { 861 if (!asd->continuous_mode->val) 862 return ATOMISP_MAIN_METADATA; 863 864 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) /* online capture pipe */ 865 return ATOMISP_SEC_METADATA; 866 else 867 return ATOMISP_MAIN_METADATA; 868 } 869 870 void atomisp_buf_done(struct atomisp_sub_device *asd, int error, 871 enum atomisp_css_buffer_type buf_type, 872 enum atomisp_css_pipe_id css_pipe_id, 873 bool q_buffers, enum atomisp_input_stream_id stream_id) 874 { 875 struct videobuf_buffer *vb = NULL; 876 struct atomisp_video_pipe *pipe = NULL; 877 struct atomisp_css_buffer buffer; 878 bool requeue = false; 879 int err; 880 unsigned long irqflags; 881 struct atomisp_css_frame *frame = NULL; 882 struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp; 883 struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp; 884 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp; 885 enum atomisp_metadata_type md_type; 886 struct atomisp_device *isp = asd->isp; 887 struct v4l2_control ctrl; 888 bool reset_wdt_timer = false; 889 890 if ( 891 buf_type != CSS_BUFFER_TYPE_METADATA && 892 buf_type != CSS_BUFFER_TYPE_3A_STATISTICS && 893 buf_type != CSS_BUFFER_TYPE_DIS_STATISTICS && 894 buf_type != CSS_BUFFER_TYPE_OUTPUT_FRAME && 895 buf_type != CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME && 896 buf_type != CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME && 897 buf_type != CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME && 898 buf_type != CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 899 dev_err(isp->dev, "%s, unsupported buffer type: %d\n", 900 __func__, buf_type); 901 return; 902 } 903 904 memset(&buffer, 0, sizeof(struct atomisp_css_buffer)); 905 buffer.css_buffer.type = buf_type; 906 err = atomisp_css_dequeue_buffer(asd, stream_id, css_pipe_id, 907 buf_type, &buffer); 908 if (err) { 909 dev_err(isp->dev, 910 "atomisp_css_dequeue_buffer failed: 0x%x\n", err); 911 return; 912 } 913 914 /* need to know the atomisp pipe for frame buffers */ 915 pipe = __atomisp_get_pipe(asd, stream_id, css_pipe_id, buf_type); 916 if (!pipe) { 917 dev_err(isp->dev, "error getting atomisp pipe\n"); 918 return; 919 } 920 921 switch (buf_type) { 922 case CSS_BUFFER_TYPE_3A_STATISTICS: 923 list_for_each_entry_safe(s3a_buf, _s3a_buf_tmp, 924 &asd->s3a_stats_in_css, list) { 925 if (s3a_buf->s3a_data == 926 buffer.css_buffer.data.stats_3a) { 927 list_del_init(&s3a_buf->list); 928 list_add_tail(&s3a_buf->list, 929 &asd->s3a_stats_ready); 930 break; 931 } 932 } 933 934 asd->s3a_bufs_in_css[css_pipe_id]--; 935 atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id); 936 dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n", 937 __func__, s3a_buf->s3a_data->exp_id); 938 break; 939 case CSS_BUFFER_TYPE_METADATA: 940 if (error) 941 break; 942 943 md_type = atomisp_get_metadata_type(asd, css_pipe_id); 944 list_for_each_entry_safe(md_buf, _md_buf_tmp, 945 &asd->metadata_in_css[md_type], list) { 946 if (md_buf->metadata == 947 buffer.css_buffer.data.metadata) { 948 list_del_init(&md_buf->list); 949 list_add_tail(&md_buf->list, 950 &asd->metadata_ready[md_type]); 951 break; 952 } 953 } 954 asd->metadata_bufs_in_css[stream_id][css_pipe_id]--; 955 atomisp_metadata_ready_event(asd, md_type); 956 dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n", 957 __func__, md_buf->metadata->exp_id); 958 break; 959 case CSS_BUFFER_TYPE_DIS_STATISTICS: 960 list_for_each_entry_safe(dis_buf, _dis_buf_tmp, 961 &asd->dis_stats_in_css, list) { 962 if (dis_buf->dis_data == 963 buffer.css_buffer.data.stats_dvs) { 964 spin_lock_irqsave(&asd->dis_stats_lock, 965 irqflags); 966 list_del_init(&dis_buf->list); 967 list_add(&dis_buf->list, &asd->dis_stats); 968 asd->params.dis_proj_data_valid = true; 969 spin_unlock_irqrestore(&asd->dis_stats_lock, 970 irqflags); 971 break; 972 } 973 } 974 asd->dis_bufs_in_css--; 975 dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n", 976 __func__, dis_buf->dis_data->exp_id); 977 break; 978 case CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: 979 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: 980 if (atomisp_hw_is_isp2401) 981 reset_wdt_timer = true; 982 983 pipe->buffers_in_css--; 984 frame = buffer.css_buffer.data.frame; 985 if (!frame) { 986 WARN_ON(1); 987 break; 988 } 989 if (!frame->valid) 990 error = true; 991 992 /* FIXME: 993 * YUVPP doesn't set postview exp_id correctlly in SDV mode. 994 * This is a WORKAROUND to set exp_id. see HSDES-1503911606. 995 */ 996 if (IS_BYT && buf_type == CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME && 997 asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd)) 998 frame->exp_id = (asd->postview_exp_id++) % 999 (ATOMISP_MAX_EXP_ID + 1); 1000 1001 dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n", 1002 __func__, frame->exp_id); 1003 if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) { 1004 if (frame->flash_state 1005 == CSS_FRAME_FLASH_STATE_PARTIAL) 1006 dev_dbg(isp->dev, "%s thumb partially flashed\n", 1007 __func__); 1008 else if (frame->flash_state 1009 == CSS_FRAME_FLASH_STATE_FULL) 1010 dev_dbg(isp->dev, "%s thumb completely flashed\n", 1011 __func__); 1012 else 1013 dev_dbg(isp->dev, "%s thumb no flash in this frame\n", 1014 __func__); 1015 } 1016 vb = atomisp_css_frame_to_vbuf(pipe, frame); 1017 WARN_ON(!vb); 1018 if (vb) 1019 pipe->frame_config_id[vb->i] = frame->isp_config_id; 1020 if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE && 1021 asd->pending_capture_request > 0) { 1022 err = atomisp_css_offline_capture_configure(asd, 1023 asd->params.offline_parm.num_captures, 1024 asd->params.offline_parm.skip_frames, 1025 asd->params.offline_parm.offset); 1026 1027 asd->pending_capture_request--; 1028 1029 if (atomisp_hw_is_isp2401) 1030 asd->re_trigger_capture = false; 1031 1032 dev_dbg(isp->dev, "Trigger capture again for new buffer. err=%d\n", 1033 err); 1034 } else if (atomisp_hw_is_isp2401) { 1035 asd->re_trigger_capture = true; 1036 } 1037 break; 1038 case CSS_BUFFER_TYPE_OUTPUT_FRAME: 1039 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 1040 if (atomisp_hw_is_isp2401) 1041 reset_wdt_timer = true; 1042 1043 pipe->buffers_in_css--; 1044 frame = buffer.css_buffer.data.frame; 1045 if (!frame) { 1046 WARN_ON(1); 1047 break; 1048 } 1049 1050 if (!frame->valid) 1051 error = true; 1052 1053 /* FIXME: 1054 * YUVPP doesn't set preview exp_id correctlly in ZSL mode. 1055 * This is a WORKAROUND to set exp_id. see HSDES-1503911606. 1056 */ 1057 if (IS_BYT && buf_type == CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME && 1058 asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd)) 1059 frame->exp_id = (asd->preview_exp_id++) % 1060 (ATOMISP_MAX_EXP_ID + 1); 1061 1062 dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n", 1063 __func__, frame->exp_id); 1064 vb = atomisp_css_frame_to_vbuf(pipe, frame); 1065 if (!vb) { 1066 WARN_ON(1); 1067 break; 1068 } 1069 1070 /* free the parameters */ 1071 if (pipe->frame_params[vb->i]) { 1072 if (asd->params.dvs_6axis == 1073 pipe->frame_params[vb->i]->params.dvs_6axis) 1074 asd->params.dvs_6axis = NULL; 1075 atomisp_free_css_parameters( 1076 &pipe->frame_params[vb->i]->params); 1077 kvfree(pipe->frame_params[vb->i]); 1078 pipe->frame_params[vb->i] = NULL; 1079 } 1080 1081 pipe->frame_config_id[vb->i] = frame->isp_config_id; 1082 ctrl.id = V4L2_CID_FLASH_MODE; 1083 if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) { 1084 if (frame->flash_state 1085 == CSS_FRAME_FLASH_STATE_PARTIAL) { 1086 asd->frame_status[vb->i] = 1087 ATOMISP_FRAME_STATUS_FLASH_PARTIAL; 1088 dev_dbg(isp->dev, "%s partially flashed\n", 1089 __func__); 1090 } else if (frame->flash_state 1091 == CSS_FRAME_FLASH_STATE_FULL) { 1092 asd->frame_status[vb->i] = 1093 ATOMISP_FRAME_STATUS_FLASH_EXPOSED; 1094 asd->params.num_flash_frames--; 1095 dev_dbg(isp->dev, "%s completely flashed\n", 1096 __func__); 1097 } else { 1098 asd->frame_status[vb->i] = 1099 ATOMISP_FRAME_STATUS_OK; 1100 dev_dbg(isp->dev, 1101 "%s no flash in this frame\n", 1102 __func__); 1103 } 1104 1105 /* Check if flashing sequence is done */ 1106 if (asd->frame_status[vb->i] == 1107 ATOMISP_FRAME_STATUS_FLASH_EXPOSED) 1108 asd->params.flash_state = ATOMISP_FLASH_DONE; 1109 } else if (isp->flash) { 1110 if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) == 1111 0 && ctrl.value == ATOMISP_FLASH_MODE_TORCH) { 1112 ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY; 1113 if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) 1114 == 0 && ctrl.value > 0) { 1115 asd->frame_status[vb->i] = 1116 ATOMISP_FRAME_STATUS_FLASH_EXPOSED; 1117 } else { 1118 asd->frame_status[vb->i] = 1119 ATOMISP_FRAME_STATUS_OK; 1120 } 1121 } else 1122 asd->frame_status[vb->i] = 1123 ATOMISP_FRAME_STATUS_OK; 1124 } else { 1125 asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK; 1126 } 1127 1128 asd->params.last_frame_status = asd->frame_status[vb->i]; 1129 1130 if (asd->continuous_mode->val) { 1131 if (css_pipe_id == CSS_PIPE_ID_PREVIEW || 1132 css_pipe_id == CSS_PIPE_ID_VIDEO) { 1133 asd->latest_preview_exp_id = frame->exp_id; 1134 } else if (css_pipe_id == 1135 CSS_PIPE_ID_CAPTURE) { 1136 if (asd->run_mode->val == 1137 ATOMISP_RUN_MODE_VIDEO) 1138 dev_dbg(isp->dev, "SDV capture raw buffer id: %u\n", 1139 frame->exp_id); 1140 else 1141 dev_dbg(isp->dev, "ZSL capture raw buffer id: %u\n", 1142 frame->exp_id); 1143 } 1144 } 1145 /* 1146 * Only after enabled the raw buffer lock 1147 * and in continuous mode. 1148 * in preview/video pipe, each buffer will 1149 * be locked automatically, so record it here. 1150 */ 1151 if (((css_pipe_id == CSS_PIPE_ID_PREVIEW) || 1152 (css_pipe_id == CSS_PIPE_ID_VIDEO)) && 1153 asd->enable_raw_buffer_lock->val && 1154 asd->continuous_mode->val) { 1155 atomisp_set_raw_buffer_bitmap(asd, frame->exp_id); 1156 WARN_ON(frame->exp_id > ATOMISP_MAX_EXP_ID); 1157 } 1158 1159 if (asd->params.css_update_params_needed) { 1160 atomisp_apply_css_parameters(asd, 1161 &asd->params.css_param); 1162 if (asd->params.css_param.update_flag.dz_config) 1163 atomisp_css_set_dz_config(asd, 1164 &asd->params.css_param.dz_config); 1165 /* New global dvs 6axis config should be blocked 1166 * here if there's a buffer with per-frame parameters 1167 * pending in CSS frame buffer queue. 1168 * This is to aviod zooming vibration since global 1169 * parameters take effect immediately while 1170 * per-frame parameters are taken after previous 1171 * buffers in CSS got processed. 1172 */ 1173 if (asd->params.dvs_6axis) 1174 atomisp_css_set_dvs_6axis(asd, 1175 asd->params.dvs_6axis); 1176 else 1177 asd->params.css_update_params_needed = false; 1178 /* The update flag should not be cleaned here 1179 * since it is still going to be used to make up 1180 * following per-frame parameters. 1181 * This will introduce more copy work since each 1182 * time when updating global parameters, the whole 1183 * parameter set are applied. 1184 * FIXME: A new set of parameter copy functions can 1185 * be added to make up per-frame parameters based on 1186 * solid structures stored in asd->params.css_param 1187 * instead of using shadow pointers in update flag. 1188 */ 1189 atomisp_css_update_isp_params(asd); 1190 } 1191 break; 1192 default: 1193 break; 1194 } 1195 if (vb) 1196 { 1197 vb->ts = ktime_get_ns(); 1198 vb->field_count = atomic_read(&asd->sequence) << 1; 1199 /*mark videobuffer done for dequeue*/ 1200 spin_lock_irqsave(&pipe->irq_lock, irqflags); 1201 vb->state = !error ? VIDEOBUF_DONE : VIDEOBUF_ERROR; 1202 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 1203 1204 /* 1205 * Frame capture done, wake up any process block on 1206 * current active buffer 1207 * possibly hold by videobuf_dqbuf() 1208 */ 1209 wake_up(&vb->done); 1210 } 1211 if (atomisp_hw_is_isp2401) 1212 atomic_set(&pipe->wdt_count, 0); 1213 1214 /* 1215 * Requeue should only be done for 3a and dis buffers. 1216 * Queue/dequeue order will change if driver recycles image buffers. 1217 */ 1218 if (requeue) 1219 { 1220 err = atomisp_css_queue_buffer(asd, 1221 stream_id, css_pipe_id, 1222 buf_type, &buffer); 1223 if (err) 1224 dev_err(isp->dev, "%s, q to css fails: %d\n", 1225 __func__, err); 1226 return; 1227 } 1228 if (!error && q_buffers) 1229 atomisp_qbuffers_to_css(asd); 1230 1231 if (atomisp_hw_is_isp2401) { 1232 /* If there are no buffers queued then 1233 * delete wdt timer. */ 1234 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 1235 return; 1236 if (!atomisp_buffers_queued_pipe(pipe)) 1237 atomisp_wdt_stop_pipe(pipe, false); 1238 else if (reset_wdt_timer) 1239 /* SOF irq should not reset wdt timer. */ 1240 atomisp_wdt_refresh_pipe(pipe, 1241 ATOMISP_WDT_KEEP_CURRENT_DELAY); 1242 } 1243 } 1244 1245 void atomisp_delayed_init_work(struct work_struct *work) 1246 { 1247 struct atomisp_sub_device *asd = container_of(work, 1248 struct atomisp_sub_device, 1249 delayed_init_work); 1250 /* 1251 * to SOC camera, use yuvpp pipe and no support continuous mode. 1252 */ 1253 if (!ATOMISP_USE_YUVPP(asd)) { 1254 struct v4l2_event event = {0}; 1255 1256 atomisp_css_allocate_continuous_frames(false, asd); 1257 atomisp_css_update_continuous_frames(asd); 1258 1259 event.type = V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE; 1260 v4l2_event_queue(asd->subdev.devnode, &event); 1261 } 1262 1263 /* signal streamon after delayed init is done */ 1264 asd->delayed_init = ATOMISP_DELAYED_INIT_DONE; 1265 complete(&asd->init_done); 1266 } 1267 1268 static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) 1269 { 1270 enum atomisp_css_pipe_id css_pipe_id; 1271 bool stream_restart[MAX_STREAM_NUM] = {0}; 1272 bool depth_mode = false; 1273 int i, ret, depth_cnt = 0; 1274 1275 if (!isp->sw_contex.file_input) 1276 atomisp_css_irq_enable(isp, 1277 CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); 1278 1279 BUG_ON(isp->num_of_streams > MAX_STREAM_NUM); 1280 1281 for (i = 0; i < isp->num_of_streams; i++) { 1282 struct atomisp_sub_device *asd = &isp->asd[i]; 1283 struct ia_css_pipeline *acc_pipeline; 1284 struct ia_css_pipe *acc_pipe = NULL; 1285 1286 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED && 1287 !asd->stream_prepared) 1288 continue; 1289 1290 /* 1291 * AtomISP::waitStageUpdate is blocked when WDT happens. 1292 * By calling acc_done() for all loaded fw_handles, 1293 * HAL will be unblocked. 1294 */ 1295 acc_pipe = asd->stream_env[i].pipes[CSS_PIPE_ID_ACC]; 1296 if (acc_pipe) { 1297 acc_pipeline = ia_css_pipe_get_pipeline(acc_pipe); 1298 if (acc_pipeline) { 1299 struct ia_css_pipeline_stage *stage; 1300 1301 for (stage = acc_pipeline->stages; stage; 1302 stage = stage->next) { 1303 const struct ia_css_fw_info *fw; 1304 1305 fw = stage->firmware; 1306 atomisp_acc_done(asd, fw->handle); 1307 } 1308 } 1309 } 1310 1311 depth_cnt++; 1312 1313 if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED) 1314 cancel_work_sync(&asd->delayed_init_work); 1315 1316 complete(&asd->init_done); 1317 asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED; 1318 1319 stream_restart[asd->index] = true; 1320 1321 asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING; 1322 1323 /* stream off sensor */ 1324 ret = v4l2_subdev_call( 1325 isp->inputs[asd->input_curr]. 1326 camera, video, s_stream, 0); 1327 if (ret) 1328 dev_warn(isp->dev, 1329 "can't stop streaming on sensor!\n"); 1330 1331 atomisp_acc_unload_extensions(asd); 1332 1333 atomisp_clear_css_buffer_counters(asd); 1334 1335 css_pipe_id = atomisp_get_css_pipe_id(asd); 1336 atomisp_css_stop(asd, css_pipe_id, true); 1337 1338 asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; 1339 1340 asd->preview_exp_id = 1; 1341 asd->postview_exp_id = 1; 1342 /* notify HAL the CSS reset */ 1343 dev_dbg(isp->dev, 1344 "send reset event to %s\n", asd->subdev.devnode->name); 1345 atomisp_reset_event(asd); 1346 } 1347 1348 /* clear irq */ 1349 disable_isp_irq(hrt_isp_css_irq_sp); 1350 clear_isp_irq(hrt_isp_css_irq_sp); 1351 1352 /* Set the SRSE to 3 before resetting */ 1353 pci_write_config_dword(isp->pdev, PCI_I_CONTROL, isp->saved_regs.i_control | 1354 MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); 1355 1356 /* reset ISP and restore its state */ 1357 isp->isp_timeout = true; 1358 atomisp_reset(isp); 1359 isp->isp_timeout = false; 1360 1361 if (!isp_timeout) { 1362 for (i = 0; i < isp->num_of_streams; i++) { 1363 if (isp->asd[i].depth_mode->val) 1364 return; 1365 } 1366 } 1367 1368 for (i = 0; i < isp->num_of_streams; i++) { 1369 struct atomisp_sub_device *asd = &isp->asd[i]; 1370 1371 if (!stream_restart[i]) 1372 continue; 1373 1374 if (isp->inputs[asd->input_curr].type != FILE_INPUT) 1375 atomisp_css_input_set_mode(asd, 1376 CSS_INPUT_MODE_SENSOR); 1377 1378 css_pipe_id = atomisp_get_css_pipe_id(asd); 1379 if (atomisp_css_start(asd, css_pipe_id, true)) 1380 dev_warn(isp->dev, 1381 "start SP failed, so do not set streaming to be enable!\n"); 1382 else 1383 asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED; 1384 1385 atomisp_csi2_configure(asd); 1386 } 1387 1388 if (!isp->sw_contex.file_input) { 1389 atomisp_css_irq_enable(isp, CSS_IRQ_INFO_CSS_RECEIVER_SOF, 1390 atomisp_css_valid_sof(isp)); 1391 1392 if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0) 1393 dev_dbg(isp->dev, "dfs failed!\n"); 1394 } else { 1395 if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, true) < 0) 1396 dev_dbg(isp->dev, "dfs failed!\n"); 1397 } 1398 1399 for (i = 0; i < isp->num_of_streams; i++) { 1400 struct atomisp_sub_device *asd; 1401 1402 asd = &isp->asd[i]; 1403 1404 if (!stream_restart[i]) 1405 continue; 1406 1407 if (asd->continuous_mode->val && 1408 asd->delayed_init == ATOMISP_DELAYED_INIT_NOT_QUEUED) { 1409 reinit_completion(&asd->init_done); 1410 asd->delayed_init = ATOMISP_DELAYED_INIT_QUEUED; 1411 queue_work(asd->delayed_init_workq, 1412 &asd->delayed_init_work); 1413 } 1414 /* 1415 * dequeueing buffers is not needed. CSS will recycle 1416 * buffers that it has. 1417 */ 1418 atomisp_flush_bufs_and_wakeup(asd); 1419 1420 /* Requeue unprocessed per-frame parameters. */ 1421 atomisp_recover_params_queue(&asd->video_out_capture); 1422 atomisp_recover_params_queue(&asd->video_out_preview); 1423 atomisp_recover_params_queue(&asd->video_out_video_capture); 1424 1425 if ((asd->depth_mode->val) && 1426 (depth_cnt == ATOMISP_DEPTH_SENSOR_STREAMON_COUNT)) { 1427 depth_mode = true; 1428 continue; 1429 } 1430 1431 ret = v4l2_subdev_call( 1432 isp->inputs[asd->input_curr].camera, video, 1433 s_stream, 1); 1434 if (ret) 1435 dev_warn(isp->dev, 1436 "can't start streaming on sensor!\n"); 1437 } 1438 1439 if (depth_mode) { 1440 if (atomisp_stream_on_master_slave_sensor(isp, true)) 1441 dev_warn(isp->dev, 1442 "master slave sensor stream on failed!\n"); 1443 } 1444 } 1445 1446 void atomisp_wdt_work(struct work_struct *work) 1447 { 1448 struct atomisp_device *isp = container_of(work, struct atomisp_device, 1449 wdt_work); 1450 int i; 1451 unsigned int pipe_wdt_cnt[MAX_STREAM_NUM][4] = { {0} }; 1452 bool css_recover = false; 1453 1454 rt_mutex_lock(&isp->mutex); 1455 if (!atomisp_streaming_count(isp)) { 1456 atomic_set(&isp->wdt_work_queued, 0); 1457 rt_mutex_unlock(&isp->mutex); 1458 return; 1459 } 1460 1461 if (!atomisp_hw_is_isp2401) { 1462 dev_err(isp->dev, "timeout %d of %d\n", 1463 atomic_read(&isp->wdt_count) + 1, 1464 ATOMISP_ISP_MAX_TIMEOUT_COUNT); 1465 1466 if (atomic_inc_return(&isp->wdt_count) < ATOMISP_ISP_MAX_TIMEOUT_COUNT) 1467 css_recover = true; 1468 } else { 1469 css_recover = true; 1470 1471 for (i = 0; i < isp->num_of_streams; i++) { 1472 struct atomisp_sub_device *asd = &isp->asd[i]; 1473 1474 pipe_wdt_cnt[i][0] += 1475 atomic_read(&asd->video_out_capture.wdt_count); 1476 pipe_wdt_cnt[i][1] += 1477 atomic_read(&asd->video_out_vf.wdt_count); 1478 pipe_wdt_cnt[i][2] += 1479 atomic_read(&asd->video_out_preview.wdt_count); 1480 pipe_wdt_cnt[i][3] += 1481 atomic_read(&asd->video_out_video_capture.wdt_count); 1482 css_recover = 1483 (pipe_wdt_cnt[i][0] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && 1484 pipe_wdt_cnt[i][1] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && 1485 pipe_wdt_cnt[i][2] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && 1486 pipe_wdt_cnt[i][3] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT) 1487 ? true : false; 1488 dev_err(isp->dev, 1489 "pipe on asd%d timeout cnt: (%d, %d, %d, %d) of %d, recover = %d\n", 1490 asd->index, pipe_wdt_cnt[i][0], pipe_wdt_cnt[i][1], 1491 pipe_wdt_cnt[i][2], pipe_wdt_cnt[i][3], 1492 ATOMISP_ISP_MAX_TIMEOUT_COUNT, css_recover); 1493 } 1494 } 1495 1496 if (css_recover) { 1497 unsigned int old_dbglevel = dbg_level; 1498 1499 atomisp_css_debug_dump_sp_sw_debug_info(); 1500 atomisp_css_debug_dump_debug_info(__func__); 1501 dbg_level = old_dbglevel; 1502 for (i = 0; i < isp->num_of_streams; i++) { 1503 struct atomisp_sub_device *asd = &isp->asd[i]; 1504 1505 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 1506 continue; 1507 dev_err(isp->dev, "%s, vdev %s buffers in css: %d\n", 1508 __func__, 1509 asd->video_out_capture.vdev.name, 1510 asd->video_out_capture. 1511 buffers_in_css); 1512 dev_err(isp->dev, 1513 "%s, vdev %s buffers in css: %d\n", 1514 __func__, 1515 asd->video_out_vf.vdev.name, 1516 asd->video_out_vf. 1517 buffers_in_css); 1518 dev_err(isp->dev, 1519 "%s, vdev %s buffers in css: %d\n", 1520 __func__, 1521 asd->video_out_preview.vdev.name, 1522 asd->video_out_preview. 1523 buffers_in_css); 1524 dev_err(isp->dev, 1525 "%s, vdev %s buffers in css: %d\n", 1526 __func__, 1527 asd->video_out_video_capture.vdev.name, 1528 asd->video_out_video_capture. 1529 buffers_in_css); 1530 dev_err(isp->dev, 1531 "%s, s3a buffers in css preview pipe:%d\n", 1532 __func__, 1533 asd->s3a_bufs_in_css[CSS_PIPE_ID_PREVIEW]); 1534 dev_err(isp->dev, 1535 "%s, s3a buffers in css capture pipe:%d\n", 1536 __func__, 1537 asd->s3a_bufs_in_css[CSS_PIPE_ID_CAPTURE]); 1538 dev_err(isp->dev, 1539 "%s, s3a buffers in css video pipe:%d\n", 1540 __func__, 1541 asd->s3a_bufs_in_css[CSS_PIPE_ID_VIDEO]); 1542 dev_err(isp->dev, 1543 "%s, dis buffers in css: %d\n", 1544 __func__, asd->dis_bufs_in_css); 1545 dev_err(isp->dev, 1546 "%s, metadata buffers in css preview pipe:%d\n", 1547 __func__, 1548 asd->metadata_bufs_in_css 1549 [ATOMISP_INPUT_STREAM_GENERAL] 1550 [CSS_PIPE_ID_PREVIEW]); 1551 dev_err(isp->dev, 1552 "%s, metadata buffers in css capture pipe:%d\n", 1553 __func__, 1554 asd->metadata_bufs_in_css 1555 [ATOMISP_INPUT_STREAM_GENERAL] 1556 [CSS_PIPE_ID_CAPTURE]); 1557 dev_err(isp->dev, 1558 "%s, metadata buffers in css video pipe:%d\n", 1559 __func__, 1560 asd->metadata_bufs_in_css 1561 [ATOMISP_INPUT_STREAM_GENERAL] 1562 [CSS_PIPE_ID_VIDEO]); 1563 if (asd->enable_raw_buffer_lock->val) { 1564 unsigned int j; 1565 1566 dev_err(isp->dev, "%s, raw_buffer_locked_count %d\n", 1567 __func__, asd->raw_buffer_locked_count); 1568 for (j = 0; j <= ATOMISP_MAX_EXP_ID / 32; j++) 1569 dev_err(isp->dev, "%s, raw_buffer_bitmap[%d]: 0x%x\n", 1570 __func__, j, 1571 asd->raw_buffer_bitmap[j]); 1572 } 1573 } 1574 1575 /*sh_css_dump_sp_state();*/ 1576 /*sh_css_dump_isp_state();*/ 1577 } else { 1578 for (i = 0; i < isp->num_of_streams; i++) { 1579 struct atomisp_sub_device *asd = &isp->asd[i]; 1580 1581 if (asd->streaming == 1582 ATOMISP_DEVICE_STREAMING_ENABLED) { 1583 atomisp_clear_css_buffer_counters(asd); 1584 atomisp_flush_bufs_and_wakeup(asd); 1585 complete(&asd->init_done); 1586 } 1587 if (atomisp_hw_is_isp2401) 1588 atomisp_wdt_stop(asd, false); 1589 } 1590 1591 if (!atomisp_hw_is_isp2401) { 1592 atomic_set(&isp->wdt_count, 0); 1593 } else { 1594 isp->isp_fatal_error = true; 1595 atomic_set(&isp->wdt_work_queued, 0); 1596 1597 rt_mutex_unlock(&isp->mutex); 1598 return; 1599 } 1600 } 1601 1602 __atomisp_css_recover(isp, true); 1603 if (atomisp_hw_is_isp2401) { 1604 for (i = 0; i < isp->num_of_streams; i++) { 1605 struct atomisp_sub_device *asd = &isp->asd[i]; 1606 1607 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 1608 continue; 1609 1610 atomisp_wdt_refresh(asd, 1611 isp->sw_contex.file_input ? 1612 ATOMISP_ISP_FILE_TIMEOUT_DURATION : 1613 ATOMISP_ISP_TIMEOUT_DURATION); 1614 } 1615 } 1616 1617 dev_err(isp->dev, "timeout recovery handling done\n"); 1618 atomic_set(&isp->wdt_work_queued, 0); 1619 1620 rt_mutex_unlock(&isp->mutex); 1621 } 1622 1623 void atomisp_css_flush(struct atomisp_device *isp) 1624 { 1625 int i; 1626 1627 if (!atomisp_streaming_count(isp)) 1628 return; 1629 1630 /* Disable wdt */ 1631 for (i = 0; i < isp->num_of_streams; i++) { 1632 struct atomisp_sub_device *asd = &isp->asd[i]; 1633 1634 atomisp_wdt_stop(asd, true); 1635 } 1636 1637 /* Start recover */ 1638 __atomisp_css_recover(isp, false); 1639 /* Restore wdt */ 1640 for (i = 0; i < isp->num_of_streams; i++) { 1641 struct atomisp_sub_device *asd = &isp->asd[i]; 1642 1643 if (asd->streaming != 1644 ATOMISP_DEVICE_STREAMING_ENABLED) 1645 continue; 1646 1647 atomisp_wdt_refresh(asd, 1648 isp->sw_contex.file_input ? 1649 ATOMISP_ISP_FILE_TIMEOUT_DURATION : 1650 ATOMISP_ISP_TIMEOUT_DURATION); 1651 } 1652 dev_dbg(isp->dev, "atomisp css flush done\n"); 1653 } 1654 1655 void atomisp_wdt(struct timer_list *t) 1656 { 1657 struct atomisp_sub_device *asd; 1658 struct atomisp_device *isp; 1659 1660 if (!atomisp_hw_is_isp2401) { 1661 asd = from_timer(asd, t, wdt); 1662 isp = asd->isp; 1663 } else { 1664 struct atomisp_video_pipe *pipe = from_timer(pipe, t, wdt); 1665 1666 asd = pipe->asd; 1667 isp = asd->isp; 1668 1669 atomic_inc(&pipe->wdt_count); 1670 dev_warn(isp->dev, 1671 "[WARNING]asd %d pipe %s ISP timeout %d!\n", 1672 asd->index, pipe->vdev.name, 1673 atomic_read(&pipe->wdt_count)); 1674 } 1675 1676 if (atomic_read(&isp->wdt_work_queued)) { 1677 dev_dbg(isp->dev, "ISP watchdog was put into workqueue\n"); 1678 return; 1679 } 1680 atomic_set(&isp->wdt_work_queued, 1); 1681 queue_work(isp->wdt_work_queue, &isp->wdt_work); 1682 } 1683 1684 /* ISP2400 */ 1685 void atomisp_wdt_start(struct atomisp_sub_device *asd) 1686 { 1687 atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION); 1688 } 1689 1690 /* ISP2401 */ 1691 void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe, 1692 unsigned int delay) 1693 { 1694 unsigned long next; 1695 1696 if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY) 1697 pipe->wdt_duration = delay; 1698 1699 next = jiffies + pipe->wdt_duration; 1700 1701 /* Override next if it has been pushed beyon the "next" time */ 1702 if (atomisp_is_wdt_running(pipe) && time_after(pipe->wdt_expires, next)) 1703 next = pipe->wdt_expires; 1704 1705 pipe->wdt_expires = next; 1706 1707 if (atomisp_is_wdt_running(pipe)) 1708 dev_dbg(pipe->asd->isp->dev, "WDT will hit after %d ms (%s)\n", 1709 ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name); 1710 else 1711 dev_dbg(pipe->asd->isp->dev, "WDT starts with %d ms period (%s)\n", 1712 ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name); 1713 1714 mod_timer(&pipe->wdt, next); 1715 } 1716 1717 void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay) 1718 { 1719 if (!atomisp_hw_is_isp2401) { 1720 unsigned long next; 1721 1722 if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY) 1723 asd->wdt_duration = delay; 1724 1725 next = jiffies + asd->wdt_duration; 1726 1727 /* Override next if it has been pushed beyon the "next" time */ 1728 if (atomisp_is_wdt_running(asd) && time_after(asd->wdt_expires, next)) 1729 next = asd->wdt_expires; 1730 1731 asd->wdt_expires = next; 1732 1733 if (atomisp_is_wdt_running(asd)) 1734 dev_dbg(asd->isp->dev, "WDT will hit after %d ms\n", 1735 ((int)(next - jiffies) * 1000 / HZ)); 1736 else 1737 dev_dbg(asd->isp->dev, "WDT starts with %d ms period\n", 1738 ((int)(next - jiffies) * 1000 / HZ)); 1739 1740 mod_timer(&asd->wdt, next); 1741 atomic_set(&asd->isp->wdt_count, 0); 1742 } else { 1743 dev_dbg(asd->isp->dev, "WDT refresh all:\n"); 1744 if (atomisp_is_wdt_running(&asd->video_out_capture)) 1745 atomisp_wdt_refresh_pipe(&asd->video_out_capture, delay); 1746 if (atomisp_is_wdt_running(&asd->video_out_preview)) 1747 atomisp_wdt_refresh_pipe(&asd->video_out_preview, delay); 1748 if (atomisp_is_wdt_running(&asd->video_out_vf)) 1749 atomisp_wdt_refresh_pipe(&asd->video_out_vf, delay); 1750 if (atomisp_is_wdt_running(&asd->video_out_video_capture)) 1751 atomisp_wdt_refresh_pipe(&asd->video_out_video_capture, delay); 1752 } 1753 } 1754 1755 /* ISP2401 */ 1756 void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync) 1757 { 1758 if (!atomisp_is_wdt_running(pipe)) 1759 return; 1760 1761 dev_dbg(pipe->asd->isp->dev, 1762 "WDT stop asd %d (%s)\n", pipe->asd->index, pipe->vdev.name); 1763 1764 if (sync) { 1765 del_timer_sync(&pipe->wdt); 1766 cancel_work_sync(&pipe->asd->isp->wdt_work); 1767 } else { 1768 del_timer(&pipe->wdt); 1769 } 1770 } 1771 1772 /* ISP 2401 */ 1773 void atomisp_wdt_start_pipe(struct atomisp_video_pipe *pipe) 1774 { 1775 atomisp_wdt_refresh_pipe(pipe, ATOMISP_ISP_TIMEOUT_DURATION); 1776 } 1777 1778 void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync) 1779 { 1780 dev_dbg(asd->isp->dev, "WDT stop:\n"); 1781 1782 if (!atomisp_hw_is_isp2401) { 1783 if (sync) { 1784 del_timer_sync(&asd->wdt); 1785 cancel_work_sync(&asd->isp->wdt_work); 1786 } else { 1787 del_timer(&asd->wdt); 1788 } 1789 } else { 1790 atomisp_wdt_stop_pipe(&asd->video_out_capture, sync); 1791 atomisp_wdt_stop_pipe(&asd->video_out_preview, sync); 1792 atomisp_wdt_stop_pipe(&asd->video_out_vf, sync); 1793 atomisp_wdt_stop_pipe(&asd->video_out_video_capture, sync); 1794 } 1795 } 1796 1797 void atomisp_setup_flash(struct atomisp_sub_device *asd) 1798 { 1799 struct atomisp_device *isp = asd->isp; 1800 struct v4l2_control ctrl; 1801 1802 if (!isp->flash) 1803 return; 1804 1805 if (asd->params.flash_state != ATOMISP_FLASH_REQUESTED && 1806 asd->params.flash_state != ATOMISP_FLASH_DONE) 1807 return; 1808 1809 if (asd->params.num_flash_frames) { 1810 /* make sure the timeout is set before setting flash mode */ 1811 ctrl.id = V4L2_CID_FLASH_TIMEOUT; 1812 ctrl.value = FLASH_TIMEOUT; 1813 1814 if (v4l2_s_ctrl(NULL, isp->flash->ctrl_handler, &ctrl)) { 1815 dev_err(isp->dev, "flash timeout configure failed\n"); 1816 return; 1817 } 1818 1819 atomisp_css_request_flash(asd); 1820 asd->params.flash_state = ATOMISP_FLASH_ONGOING; 1821 } else { 1822 asd->params.flash_state = ATOMISP_FLASH_IDLE; 1823 } 1824 } 1825 1826 irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) 1827 { 1828 struct atomisp_device *isp = isp_ptr; 1829 unsigned long flags; 1830 bool frame_done_found[MAX_STREAM_NUM] = {0}; 1831 bool css_pipe_done[MAX_STREAM_NUM] = {0}; 1832 unsigned int i; 1833 struct atomisp_sub_device *asd; 1834 1835 dev_dbg(isp->dev, ">%s\n", __func__); 1836 1837 spin_lock_irqsave(&isp->lock, flags); 1838 1839 if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) { 1840 spin_unlock_irqrestore(&isp->lock, flags); 1841 return IRQ_HANDLED; 1842 } 1843 1844 spin_unlock_irqrestore(&isp->lock, flags); 1845 1846 /* 1847 * The standard CSS2.0 API tells the following calling sequence of 1848 * dequeue ready buffers: 1849 * while (ia_css_dequeue_event(...)) { 1850 * switch (event.type) { 1851 * ... 1852 * ia_css_pipe_dequeue_buffer() 1853 * } 1854 * } 1855 * That is, dequeue event and buffer are one after another. 1856 * 1857 * But the following implementation is to first deuque all the event 1858 * to a FIFO, then process the event in the FIFO. 1859 * This will not have issue in single stream mode, but it do have some 1860 * issue in multiple stream case. The issue is that 1861 * ia_css_pipe_dequeue_buffer() will not return the corrent buffer in 1862 * a specific pipe. 1863 * 1864 * This is due to ia_css_pipe_dequeue_buffer() does not take the 1865 * ia_css_pipe parameter. 1866 * 1867 * So: 1868 * For CSS2.0: we change the way to not dequeue all the event at one 1869 * time, instead, dequue one and process one, then another 1870 */ 1871 rt_mutex_lock(&isp->mutex); 1872 if (atomisp_css_isr_thread(isp, frame_done_found, css_pipe_done)) 1873 goto out; 1874 1875 for (i = 0; i < isp->num_of_streams; i++) { 1876 asd = &isp->asd[i]; 1877 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 1878 continue; 1879 atomisp_setup_flash(asd); 1880 } 1881 out: 1882 rt_mutex_unlock(&isp->mutex); 1883 for (i = 0; i < isp->num_of_streams; i++) { 1884 asd = &isp->asd[i]; 1885 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED 1886 && css_pipe_done[asd->index] 1887 && isp->sw_contex.file_input) 1888 v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 1889 video, s_stream, 1); 1890 /* FIXME! FIX ACC implementation */ 1891 if (asd->acc.pipeline && css_pipe_done[asd->index]) 1892 atomisp_css_acc_done(asd); 1893 } 1894 dev_dbg(isp->dev, "<%s\n", __func__); 1895 1896 return IRQ_HANDLED; 1897 } 1898 1899 /* 1900 * utils for buffer allocation/free 1901 */ 1902 1903 int atomisp_get_frame_pgnr(struct atomisp_device *isp, 1904 const struct atomisp_css_frame *frame, u32 *p_pgnr) 1905 { 1906 if (!frame) { 1907 dev_err(isp->dev, "%s: NULL frame pointer ERROR.\n", __func__); 1908 return -EINVAL; 1909 } 1910 1911 *p_pgnr = DIV_ROUND_UP(frame->data_bytes, PAGE_SIZE); 1912 return 0; 1913 } 1914 1915 /* 1916 * Get internal fmt according to V4L2 fmt 1917 */ 1918 static enum atomisp_css_frame_format 1919 v4l2_fmt_to_sh_fmt(u32 fmt) { 1920 switch (fmt) 1921 { 1922 case V4L2_PIX_FMT_YUV420: 1923 return CSS_FRAME_FORMAT_YUV420; 1924 case V4L2_PIX_FMT_YVU420: 1925 return CSS_FRAME_FORMAT_YV12; 1926 case V4L2_PIX_FMT_YUV422P: 1927 return CSS_FRAME_FORMAT_YUV422; 1928 case V4L2_PIX_FMT_YUV444: 1929 return CSS_FRAME_FORMAT_YUV444; 1930 case V4L2_PIX_FMT_NV12: 1931 return CSS_FRAME_FORMAT_NV12; 1932 case V4L2_PIX_FMT_NV21: 1933 return CSS_FRAME_FORMAT_NV21; 1934 case V4L2_PIX_FMT_NV16: 1935 return CSS_FRAME_FORMAT_NV16; 1936 case V4L2_PIX_FMT_NV61: 1937 return CSS_FRAME_FORMAT_NV61; 1938 case V4L2_PIX_FMT_UYVY: 1939 return CSS_FRAME_FORMAT_UYVY; 1940 case V4L2_PIX_FMT_YUYV: 1941 return CSS_FRAME_FORMAT_YUYV; 1942 case V4L2_PIX_FMT_RGB24: 1943 return CSS_FRAME_FORMAT_PLANAR_RGB888; 1944 case V4L2_PIX_FMT_RGB32: 1945 return CSS_FRAME_FORMAT_RGBA888; 1946 case V4L2_PIX_FMT_RGB565: 1947 return CSS_FRAME_FORMAT_RGB565; 1948 case V4L2_PIX_FMT_JPEG: 1949 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW: 1950 return CSS_FRAME_FORMAT_BINARY_8; 1951 case V4L2_PIX_FMT_SBGGR16: 1952 case V4L2_PIX_FMT_SBGGR10: 1953 case V4L2_PIX_FMT_SGBRG10: 1954 case V4L2_PIX_FMT_SGRBG10: 1955 case V4L2_PIX_FMT_SRGGB10: 1956 case V4L2_PIX_FMT_SBGGR12: 1957 case V4L2_PIX_FMT_SGBRG12: 1958 case V4L2_PIX_FMT_SGRBG12: 1959 case V4L2_PIX_FMT_SRGGB12: 1960 case V4L2_PIX_FMT_SBGGR8: 1961 case V4L2_PIX_FMT_SGBRG8: 1962 case V4L2_PIX_FMT_SGRBG8: 1963 case V4L2_PIX_FMT_SRGGB8: 1964 return CSS_FRAME_FORMAT_RAW; 1965 default: 1966 return -EINVAL; 1967 } 1968 } 1969 1970 /* 1971 * raw format match between SH format and V4L2 format 1972 */ 1973 static int raw_output_format_match_input(u32 input, u32 output) 1974 { 1975 if ((input == CSS_FORMAT_RAW_12) && 1976 ((output == V4L2_PIX_FMT_SRGGB12) || 1977 (output == V4L2_PIX_FMT_SGRBG12) || 1978 (output == V4L2_PIX_FMT_SBGGR12) || 1979 (output == V4L2_PIX_FMT_SGBRG12))) 1980 return 0; 1981 1982 if ((input == CSS_FORMAT_RAW_10) && 1983 ((output == V4L2_PIX_FMT_SRGGB10) || 1984 (output == V4L2_PIX_FMT_SGRBG10) || 1985 (output == V4L2_PIX_FMT_SBGGR10) || 1986 (output == V4L2_PIX_FMT_SGBRG10))) 1987 return 0; 1988 1989 if ((input == CSS_FORMAT_RAW_8) && 1990 ((output == V4L2_PIX_FMT_SRGGB8) || 1991 (output == V4L2_PIX_FMT_SGRBG8) || 1992 (output == V4L2_PIX_FMT_SBGGR8) || 1993 (output == V4L2_PIX_FMT_SGBRG8))) 1994 return 0; 1995 1996 if ((input == CSS_FORMAT_RAW_16) && (output == V4L2_PIX_FMT_SBGGR16)) 1997 return 0; 1998 1999 return -EINVAL; 2000 } 2001 2002 static u32 get_pixel_depth(u32 pixelformat) 2003 { 2004 switch (pixelformat) { 2005 case V4L2_PIX_FMT_YUV420: 2006 case V4L2_PIX_FMT_NV12: 2007 case V4L2_PIX_FMT_NV21: 2008 case V4L2_PIX_FMT_YVU420: 2009 return 12; 2010 case V4L2_PIX_FMT_YUV422P: 2011 case V4L2_PIX_FMT_YUYV: 2012 case V4L2_PIX_FMT_UYVY: 2013 case V4L2_PIX_FMT_NV16: 2014 case V4L2_PIX_FMT_NV61: 2015 case V4L2_PIX_FMT_RGB565: 2016 case V4L2_PIX_FMT_SBGGR16: 2017 case V4L2_PIX_FMT_SBGGR12: 2018 case V4L2_PIX_FMT_SGBRG12: 2019 case V4L2_PIX_FMT_SGRBG12: 2020 case V4L2_PIX_FMT_SRGGB12: 2021 case V4L2_PIX_FMT_SBGGR10: 2022 case V4L2_PIX_FMT_SGBRG10: 2023 case V4L2_PIX_FMT_SGRBG10: 2024 case V4L2_PIX_FMT_SRGGB10: 2025 return 16; 2026 case V4L2_PIX_FMT_RGB24: 2027 case V4L2_PIX_FMT_YUV444: 2028 return 24; 2029 case V4L2_PIX_FMT_RGB32: 2030 return 32; 2031 case V4L2_PIX_FMT_JPEG: 2032 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW: 2033 case V4L2_PIX_FMT_SBGGR8: 2034 case V4L2_PIX_FMT_SGBRG8: 2035 case V4L2_PIX_FMT_SGRBG8: 2036 case V4L2_PIX_FMT_SRGGB8: 2037 return 8; 2038 default: 2039 return 8 * 2; /* raw type now */ 2040 } 2041 } 2042 2043 bool atomisp_is_mbuscode_raw(uint32_t code) 2044 { 2045 return code >= 0x3000 && code < 0x4000; 2046 } 2047 2048 /* 2049 * ISP features control function 2050 */ 2051 2052 /* 2053 * Set ISP capture mode based on current settings 2054 */ 2055 static void atomisp_update_capture_mode(struct atomisp_sub_device *asd) 2056 { 2057 if (asd->params.gdc_cac_en) 2058 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_ADVANCED); 2059 else if (asd->params.low_light) 2060 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_LOW_LIGHT); 2061 else if (asd->video_out_capture.sh_fmt == CSS_FRAME_FORMAT_RAW) 2062 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_RAW); 2063 else 2064 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_PRIMARY); 2065 } 2066 2067 /* ISP2401 */ 2068 int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, 2069 struct atomisp_s_runmode *runmode) 2070 { 2071 struct atomisp_device *isp = asd->isp; 2072 struct v4l2_ctrl *c; 2073 int ret = 0; 2074 2075 if (!(runmode && (runmode->mode & RUNMODE_MASK))) 2076 return -EINVAL; 2077 2078 mutex_lock(asd->ctrl_handler.lock); 2079 c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler, 2080 V4L2_CID_RUN_MODE); 2081 2082 if (c) 2083 ret = v4l2_ctrl_s_ctrl(c, runmode->mode); 2084 2085 mutex_unlock(asd->ctrl_handler.lock); 2086 return ret; 2087 } 2088 2089 /* 2090 * Function to enable/disable lens geometry distortion correction (GDC) and 2091 * chromatic aberration correction (CAC) 2092 */ 2093 int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag, 2094 __s32 *value) 2095 { 2096 if (flag == 0) { 2097 *value = asd->params.gdc_cac_en; 2098 return 0; 2099 } 2100 2101 asd->params.gdc_cac_en = !!*value; 2102 if (asd->params.gdc_cac_en) { 2103 atomisp_css_set_morph_table(asd, 2104 asd->params.css_param.morph_table); 2105 } else { 2106 atomisp_css_set_morph_table(asd, NULL); 2107 } 2108 asd->params.css_update_params_needed = true; 2109 atomisp_update_capture_mode(asd); 2110 return 0; 2111 } 2112 2113 /* 2114 * Function to enable/disable low light mode including ANR 2115 */ 2116 int atomisp_low_light(struct atomisp_sub_device *asd, int flag, 2117 __s32 *value) 2118 { 2119 if (flag == 0) { 2120 *value = asd->params.low_light; 2121 return 0; 2122 } 2123 2124 asd->params.low_light = (*value != 0); 2125 atomisp_update_capture_mode(asd); 2126 return 0; 2127 } 2128 2129 /* 2130 * Function to enable/disable extra noise reduction (XNR) in low light 2131 * condition 2132 */ 2133 int atomisp_xnr(struct atomisp_sub_device *asd, int flag, 2134 int *xnr_enable) 2135 { 2136 if (flag == 0) { 2137 *xnr_enable = asd->params.xnr_en; 2138 return 0; 2139 } 2140 2141 atomisp_css_capture_enable_xnr(asd, !!*xnr_enable); 2142 2143 return 0; 2144 } 2145 2146 /* 2147 * Function to configure bayer noise reduction 2148 */ 2149 int atomisp_nr(struct atomisp_sub_device *asd, int flag, 2150 struct atomisp_nr_config *arg) 2151 { 2152 if (flag == 0) { 2153 /* Get nr config from current setup */ 2154 if (atomisp_css_get_nr_config(asd, arg)) 2155 return -EINVAL; 2156 } else { 2157 /* Set nr config to isp parameters */ 2158 memcpy(&asd->params.css_param.nr_config, arg, 2159 sizeof(struct atomisp_css_nr_config)); 2160 atomisp_css_set_nr_config(asd, &asd->params.css_param.nr_config); 2161 asd->params.css_update_params_needed = true; 2162 } 2163 return 0; 2164 } 2165 2166 /* 2167 * Function to configure temporal noise reduction (TNR) 2168 */ 2169 int atomisp_tnr(struct atomisp_sub_device *asd, int flag, 2170 struct atomisp_tnr_config *config) 2171 { 2172 /* Get tnr config from current setup */ 2173 if (flag == 0) { 2174 /* Get tnr config from current setup */ 2175 if (atomisp_css_get_tnr_config(asd, config)) 2176 return -EINVAL; 2177 } else { 2178 /* Set tnr config to isp parameters */ 2179 memcpy(&asd->params.css_param.tnr_config, config, 2180 sizeof(struct atomisp_css_tnr_config)); 2181 atomisp_css_set_tnr_config(asd, &asd->params.css_param.tnr_config); 2182 asd->params.css_update_params_needed = true; 2183 } 2184 2185 return 0; 2186 } 2187 2188 /* 2189 * Function to configure black level compensation 2190 */ 2191 int atomisp_black_level(struct atomisp_sub_device *asd, int flag, 2192 struct atomisp_ob_config *config) 2193 { 2194 if (flag == 0) { 2195 /* Get ob config from current setup */ 2196 if (atomisp_css_get_ob_config(asd, config)) 2197 return -EINVAL; 2198 } else { 2199 /* Set ob config to isp parameters */ 2200 memcpy(&asd->params.css_param.ob_config, config, 2201 sizeof(struct atomisp_css_ob_config)); 2202 atomisp_css_set_ob_config(asd, &asd->params.css_param.ob_config); 2203 asd->params.css_update_params_needed = true; 2204 } 2205 2206 return 0; 2207 } 2208 2209 /* 2210 * Function to configure edge enhancement 2211 */ 2212 int atomisp_ee(struct atomisp_sub_device *asd, int flag, 2213 struct atomisp_ee_config *config) 2214 { 2215 if (flag == 0) { 2216 /* Get ee config from current setup */ 2217 if (atomisp_css_get_ee_config(asd, config)) 2218 return -EINVAL; 2219 } else { 2220 /* Set ee config to isp parameters */ 2221 memcpy(&asd->params.css_param.ee_config, config, 2222 sizeof(asd->params.css_param.ee_config)); 2223 atomisp_css_set_ee_config(asd, &asd->params.css_param.ee_config); 2224 asd->params.css_update_params_needed = true; 2225 } 2226 2227 return 0; 2228 } 2229 2230 /* 2231 * Function to update Gamma table for gamma, brightness and contrast config 2232 */ 2233 int atomisp_gamma(struct atomisp_sub_device *asd, int flag, 2234 struct atomisp_gamma_table *config) 2235 { 2236 if (flag == 0) { 2237 /* Get gamma table from current setup */ 2238 if (atomisp_css_get_gamma_table(asd, config)) 2239 return -EINVAL; 2240 } else { 2241 /* Set gamma table to isp parameters */ 2242 memcpy(&asd->params.css_param.gamma_table, config, 2243 sizeof(asd->params.css_param.gamma_table)); 2244 atomisp_css_set_gamma_table(asd, &asd->params.css_param.gamma_table); 2245 } 2246 2247 return 0; 2248 } 2249 2250 /* 2251 * Function to update Ctc table for Chroma Enhancement 2252 */ 2253 int atomisp_ctc(struct atomisp_sub_device *asd, int flag, 2254 struct atomisp_ctc_table *config) 2255 { 2256 if (flag == 0) { 2257 /* Get ctc table from current setup */ 2258 if (atomisp_css_get_ctc_table(asd, config)) 2259 return -EINVAL; 2260 } else { 2261 /* Set ctc table to isp parameters */ 2262 memcpy(&asd->params.css_param.ctc_table, config, 2263 sizeof(asd->params.css_param.ctc_table)); 2264 atomisp_css_set_ctc_table(asd, &asd->params.css_param.ctc_table); 2265 } 2266 2267 return 0; 2268 } 2269 2270 /* 2271 * Function to update gamma correction parameters 2272 */ 2273 int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag, 2274 struct atomisp_gc_config *config) 2275 { 2276 if (flag == 0) { 2277 /* Get gamma correction params from current setup */ 2278 if (atomisp_css_get_gc_config(asd, config)) 2279 return -EINVAL; 2280 } else { 2281 /* Set gamma correction params to isp parameters */ 2282 memcpy(&asd->params.css_param.gc_config, config, 2283 sizeof(asd->params.css_param.gc_config)); 2284 atomisp_css_set_gc_config(asd, &asd->params.css_param.gc_config); 2285 asd->params.css_update_params_needed = true; 2286 } 2287 2288 return 0; 2289 } 2290 2291 /* 2292 * Function to update narrow gamma flag 2293 */ 2294 int atomisp_formats(struct atomisp_sub_device *asd, int flag, 2295 struct atomisp_formats_config *config) 2296 { 2297 if (flag == 0) { 2298 /* Get narrow gamma flag from current setup */ 2299 if (atomisp_css_get_formats_config(asd, config)) 2300 return -EINVAL; 2301 } else { 2302 /* Set narrow gamma flag to isp parameters */ 2303 memcpy(&asd->params.css_param.formats_config, config, 2304 sizeof(asd->params.css_param.formats_config)); 2305 atomisp_css_set_formats_config(asd, &asd->params.css_param.formats_config); 2306 } 2307 2308 return 0; 2309 } 2310 2311 void atomisp_free_internal_buffers(struct atomisp_sub_device *asd) 2312 { 2313 atomisp_free_css_parameters(&asd->params.css_param); 2314 2315 if (asd->raw_output_frame) { 2316 atomisp_css_frame_free(asd->raw_output_frame); 2317 asd->raw_output_frame = NULL; 2318 } 2319 } 2320 2321 static void atomisp_update_grid_info(struct atomisp_sub_device *asd, 2322 enum atomisp_css_pipe_id pipe_id, 2323 int source_pad) 2324 { 2325 struct atomisp_device *isp = asd->isp; 2326 int err; 2327 u16 stream_id = atomisp_source_pad_to_stream_id(asd, source_pad); 2328 2329 if (atomisp_css_get_grid_info(asd, pipe_id, source_pad)) 2330 return; 2331 2332 /* We must free all buffers because they no longer match 2333 the grid size. */ 2334 atomisp_css_free_stat_buffers(asd); 2335 2336 err = atomisp_alloc_css_stat_bufs(asd, stream_id); 2337 if (err) { 2338 dev_err(isp->dev, "stat_buf allocate error\n"); 2339 goto err; 2340 } 2341 2342 if (atomisp_alloc_3a_output_buf(asd)) { 2343 /* Failure for 3A buffers does not influence DIS buffers */ 2344 if (asd->params.s3a_output_bytes != 0) { 2345 /* For SOC sensor happens s3a_output_bytes == 0, 2346 * using if condition to exclude false error log */ 2347 dev_err(isp->dev, "Failed to allocate memory for 3A statistics\n"); 2348 } 2349 goto err; 2350 } 2351 2352 if (atomisp_alloc_dis_coef_buf(asd)) { 2353 dev_err(isp->dev, 2354 "Failed to allocate memory for DIS statistics\n"); 2355 goto err; 2356 } 2357 2358 if (atomisp_alloc_metadata_output_buf(asd)) { 2359 dev_err(isp->dev, "Failed to allocate memory for metadata\n"); 2360 goto err; 2361 } 2362 2363 return; 2364 2365 err: 2366 atomisp_css_free_stat_buffers(asd); 2367 return; 2368 } 2369 2370 static void atomisp_curr_user_grid_info(struct atomisp_sub_device *asd, 2371 struct atomisp_grid_info *info) 2372 { 2373 memcpy(info, &asd->params.curr_grid_info.s3a_grid, 2374 sizeof(struct atomisp_css_3a_grid_info)); 2375 } 2376 2377 int atomisp_compare_grid(struct atomisp_sub_device *asd, 2378 struct atomisp_grid_info *atomgrid) 2379 { 2380 struct atomisp_grid_info tmp = {0}; 2381 2382 atomisp_curr_user_grid_info(asd, &tmp); 2383 return memcmp(atomgrid, &tmp, sizeof(tmp)); 2384 } 2385 2386 /* 2387 * Function to update Gdc table for gdc 2388 */ 2389 int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag, 2390 struct atomisp_morph_table *config) 2391 { 2392 int ret; 2393 int i; 2394 struct atomisp_device *isp = asd->isp; 2395 2396 if (flag == 0) { 2397 /* Get gdc table from current setup */ 2398 struct atomisp_css_morph_table tab = {0}; 2399 2400 atomisp_css_get_morph_table(asd, &tab); 2401 2402 config->width = tab.width; 2403 config->height = tab.height; 2404 2405 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) { 2406 ret = copy_to_user(config->coordinates_x[i], 2407 tab.coordinates_x[i], tab.height * 2408 tab.width * sizeof(*tab.coordinates_x[i])); 2409 if (ret) { 2410 dev_err(isp->dev, 2411 "Failed to copy to User for x\n"); 2412 return -EFAULT; 2413 } 2414 ret = copy_to_user(config->coordinates_y[i], 2415 tab.coordinates_y[i], tab.height * 2416 tab.width * sizeof(*tab.coordinates_y[i])); 2417 if (ret) { 2418 dev_err(isp->dev, 2419 "Failed to copy to User for y\n"); 2420 return -EFAULT; 2421 } 2422 } 2423 } else { 2424 struct atomisp_css_morph_table *tab = 2425 asd->params.css_param.morph_table; 2426 2427 /* free first if we have one */ 2428 if (tab) { 2429 atomisp_css_morph_table_free(tab); 2430 asd->params.css_param.morph_table = NULL; 2431 } 2432 2433 /* allocate new one */ 2434 tab = atomisp_css_morph_table_allocate(config->width, 2435 config->height); 2436 2437 if (!tab) { 2438 dev_err(isp->dev, "out of memory\n"); 2439 return -EINVAL; 2440 } 2441 2442 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) { 2443 ret = copy_from_user(tab->coordinates_x[i], 2444 config->coordinates_x[i], 2445 config->height * config->width * 2446 sizeof(*config->coordinates_x[i])); 2447 if (ret) { 2448 dev_err(isp->dev, 2449 "Failed to copy from User for x, ret %d\n", 2450 ret); 2451 atomisp_css_morph_table_free(tab); 2452 return -EFAULT; 2453 } 2454 ret = copy_from_user(tab->coordinates_y[i], 2455 config->coordinates_y[i], 2456 config->height * config->width * 2457 sizeof(*config->coordinates_y[i])); 2458 if (ret) { 2459 dev_err(isp->dev, 2460 "Failed to copy from User for y, ret is %d\n", 2461 ret); 2462 atomisp_css_morph_table_free(tab); 2463 return -EFAULT; 2464 } 2465 } 2466 asd->params.css_param.morph_table = tab; 2467 if (asd->params.gdc_cac_en) 2468 atomisp_css_set_morph_table(asd, tab); 2469 } 2470 2471 return 0; 2472 } 2473 2474 int atomisp_macc_table(struct atomisp_sub_device *asd, int flag, 2475 struct atomisp_macc_config *config) 2476 { 2477 struct atomisp_css_macc_table *macc_table; 2478 2479 switch (config->color_effect) { 2480 case V4L2_COLORFX_NONE: 2481 macc_table = &asd->params.css_param.macc_table; 2482 break; 2483 case V4L2_COLORFX_SKY_BLUE: 2484 macc_table = &blue_macc_table; 2485 break; 2486 case V4L2_COLORFX_GRASS_GREEN: 2487 macc_table = &green_macc_table; 2488 break; 2489 case V4L2_COLORFX_SKIN_WHITEN_LOW: 2490 macc_table = &skin_low_macc_table; 2491 break; 2492 case V4L2_COLORFX_SKIN_WHITEN: 2493 macc_table = &skin_medium_macc_table; 2494 break; 2495 case V4L2_COLORFX_SKIN_WHITEN_HIGH: 2496 macc_table = &skin_high_macc_table; 2497 break; 2498 default: 2499 return -EINVAL; 2500 } 2501 2502 if (flag == 0) { 2503 /* Get macc table from current setup */ 2504 memcpy(&config->table, macc_table, 2505 sizeof(struct atomisp_css_macc_table)); 2506 } else { 2507 memcpy(macc_table, &config->table, 2508 sizeof(struct atomisp_css_macc_table)); 2509 if (config->color_effect == asd->params.color_effect) 2510 atomisp_css_set_macc_table(asd, macc_table); 2511 } 2512 2513 return 0; 2514 } 2515 2516 int atomisp_set_dis_vector(struct atomisp_sub_device *asd, 2517 struct atomisp_dis_vector *vector) 2518 { 2519 atomisp_css_video_set_dis_vector(asd, vector); 2520 2521 asd->params.dis_proj_data_valid = false; 2522 asd->params.css_update_params_needed = true; 2523 return 0; 2524 } 2525 2526 /* 2527 * Function to set/get image stablization statistics 2528 */ 2529 int atomisp_get_dis_stat(struct atomisp_sub_device *asd, 2530 struct atomisp_dis_statistics *stats) 2531 { 2532 return atomisp_css_get_dis_stat(asd, stats); 2533 } 2534 2535 /* 2536 * Function set camrea_prefiles.xml current sensor pixel array size 2537 */ 2538 int atomisp_set_array_res(struct atomisp_sub_device *asd, 2539 struct atomisp_resolution *config) 2540 { 2541 dev_dbg(asd->isp->dev, ">%s start\n", __func__); 2542 if (!config) { 2543 dev_err(asd->isp->dev, "Set sensor array size is not valid\n"); 2544 return -EINVAL; 2545 } 2546 2547 asd->sensor_array_res.width = config->width; 2548 asd->sensor_array_res.height = config->height; 2549 return 0; 2550 } 2551 2552 /* 2553 * Function to get DVS2 BQ resolution settings 2554 */ 2555 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd, 2556 struct atomisp_dvs2_bq_resolutions *bq_res) 2557 { 2558 struct ia_css_pipe_config *pipe_cfg = NULL; 2559 struct ia_css_stream_config *stream_cfg = NULL; 2560 struct ia_css_stream_input_config *input_config = NULL; 2561 2562 struct ia_css_stream *stream = 2563 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream; 2564 if (!stream) { 2565 dev_warn(asd->isp->dev, "stream is not created"); 2566 return -EAGAIN; 2567 } 2568 2569 pipe_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2570 .pipe_configs[CSS_PIPE_ID_VIDEO]; 2571 stream_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 2572 .stream_config; 2573 input_config = &stream_cfg->input_config; 2574 2575 if (!bq_res) 2576 return -EINVAL; 2577 2578 /* the GDC output resolution */ 2579 bq_res->output_bq.width_bq = pipe_cfg->output_info[0].res.width / 2; 2580 bq_res->output_bq.height_bq = pipe_cfg->output_info[0].res.height / 2; 2581 2582 bq_res->envelope_bq.width_bq = 0; 2583 bq_res->envelope_bq.height_bq = 0; 2584 /* the GDC input resolution */ 2585 if (!asd->continuous_mode->val) { 2586 bq_res->source_bq.width_bq = bq_res->output_bq.width_bq + 2587 pipe_cfg->dvs_envelope.width / 2; 2588 bq_res->source_bq.height_bq = bq_res->output_bq.height_bq + 2589 pipe_cfg->dvs_envelope.height / 2; 2590 /* 2591 * Bad pixels caused by spatial filter processing 2592 * ISP filter resolution should be given by CSS/FW, but for now 2593 * there is not such API to query, and it is fixed value, so 2594 * hardcoded here. 2595 */ 2596 bq_res->ispfilter_bq.width_bq = 12 / 2; 2597 bq_res->ispfilter_bq.height_bq = 12 / 2; 2598 /* spatial filter shift, always 4 pixels */ 2599 bq_res->gdc_shift_bq.width_bq = 4 / 2; 2600 bq_res->gdc_shift_bq.height_bq = 4 / 2; 2601 2602 if (asd->params.video_dis_en) { 2603 bq_res->envelope_bq.width_bq = pipe_cfg->dvs_envelope.width 2604 / 2 - bq_res->ispfilter_bq.width_bq; 2605 bq_res->envelope_bq.height_bq = pipe_cfg->dvs_envelope.height 2606 / 2 - bq_res->ispfilter_bq.height_bq; 2607 } 2608 } else { 2609 unsigned int w_padding; 2610 unsigned int gdc_effective_input = 0; 2611 2612 /* For GDC: 2613 * gdc_effective_input = effective_input + envelope 2614 * 2615 * From the comment and formula in BZ1786, 2616 * we see the source_bq should be: 2617 * effective_input / bayer_ds_ratio 2618 */ 2619 bq_res->source_bq.width_bq = 2620 (input_config->effective_res.width * 2621 pipe_cfg->bayer_ds_out_res.width / 2622 input_config->effective_res.width + 1) / 2; 2623 bq_res->source_bq.height_bq = 2624 (input_config->effective_res.height * 2625 pipe_cfg->bayer_ds_out_res.height / 2626 input_config->effective_res.height + 1) / 2; 2627 2628 if (!asd->params.video_dis_en) { 2629 /* 2630 * We adjust the ispfilter_bq to: 2631 * ispfilter_bq = 128/BDS 2632 * we still need firmware team to provide an offical 2633 * formula for SDV. 2634 */ 2635 bq_res->ispfilter_bq.width_bq = 128 * 2636 pipe_cfg->bayer_ds_out_res.width / 2637 input_config->effective_res.width / 2; 2638 bq_res->ispfilter_bq.height_bq = 128 * 2639 pipe_cfg->bayer_ds_out_res.width / 2640 input_config->effective_res.width / 2; 2641 2642 if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) { 2643 /* No additional left padding for ISYS2401 */ 2644 bq_res->gdc_shift_bq.width_bq = 4 / 2; 2645 bq_res->gdc_shift_bq.height_bq = 4 / 2; 2646 } else { 2647 /* 2648 * For the w_padding and gdc_shift_bq cacluation 2649 * Please see the BZ 1786 and 4358 for more info. 2650 * Just test that this formula can work now, 2651 * but we still have no offical formula. 2652 * 2653 * w_padding = ceiling(gdc_effective_input 2654 * /128, 1) * 128 - effective_width 2655 * gdc_shift_bq = w_padding/BDS/2 + ispfilter_bq/2 2656 */ 2657 gdc_effective_input = 2658 input_config->effective_res.width + 2659 pipe_cfg->dvs_envelope.width; 2660 w_padding = roundup(gdc_effective_input, 128) - 2661 input_config->effective_res.width; 2662 w_padding = w_padding * 2663 pipe_cfg->bayer_ds_out_res.width / 2664 input_config->effective_res.width + 1; 2665 w_padding = roundup(w_padding / 2, 1); 2666 2667 bq_res->gdc_shift_bq.width_bq = bq_res->ispfilter_bq.width_bq / 2 2668 + w_padding; 2669 bq_res->gdc_shift_bq.height_bq = 4 / 2; 2670 } 2671 } else { 2672 unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max; 2673 2674 bq_res->ispfilter_bq.width_bq = 8 / 2; 2675 bq_res->ispfilter_bq.height_bq = 8 / 2; 2676 2677 if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) { 2678 /* No additional left padding for ISYS2401 */ 2679 bq_res->gdc_shift_bq.width_bq = 4 / 2; 2680 bq_res->gdc_shift_bq.height_bq = 4 / 2; 2681 } else { 2682 w_padding = 2683 roundup(input_config->effective_res.width, 128) - 2684 input_config->effective_res.width; 2685 if (w_padding < 12) 2686 w_padding = 12; 2687 bq_res->gdc_shift_bq.width_bq = 4 / 2 + 2688 ((w_padding - 12) * 2689 pipe_cfg->bayer_ds_out_res.width / 2690 input_config->effective_res.width + 1) / 2; 2691 bq_res->gdc_shift_bq.height_bq = 4 / 2; 2692 } 2693 2694 dvs_w = pipe_cfg->bayer_ds_out_res.width - 2695 pipe_cfg->output_info[0].res.width; 2696 dvs_h = pipe_cfg->bayer_ds_out_res.height - 2697 pipe_cfg->output_info[0].res.height; 2698 dvs_w_max = rounddown( 2699 pipe_cfg->output_info[0].res.width / 5, 2700 ATOM_ISP_STEP_WIDTH); 2701 dvs_h_max = rounddown( 2702 pipe_cfg->output_info[0].res.height / 5, 2703 ATOM_ISP_STEP_HEIGHT); 2704 bq_res->envelope_bq.width_bq = 2705 min((dvs_w / 2), (dvs_w_max / 2)) - 2706 bq_res->ispfilter_bq.width_bq; 2707 bq_res->envelope_bq.height_bq = 2708 min((dvs_h / 2), (dvs_h_max / 2)) - 2709 bq_res->ispfilter_bq.height_bq; 2710 } 2711 } 2712 2713 dev_dbg(asd->isp->dev, 2714 "source_bq.width_bq %d, source_bq.height_bq %d,\nispfilter_bq.width_bq %d, ispfilter_bq.height_bq %d,\ngdc_shift_bq.width_bq %d, gdc_shift_bq.height_bq %d,\nenvelope_bq.width_bq %d, envelope_bq.height_bq %d,\noutput_bq.width_bq %d, output_bq.height_bq %d\n", 2715 bq_res->source_bq.width_bq, bq_res->source_bq.height_bq, 2716 bq_res->ispfilter_bq.width_bq, bq_res->ispfilter_bq.height_bq, 2717 bq_res->gdc_shift_bq.width_bq, bq_res->gdc_shift_bq.height_bq, 2718 bq_res->envelope_bq.width_bq, bq_res->envelope_bq.height_bq, 2719 bq_res->output_bq.width_bq, bq_res->output_bq.height_bq); 2720 2721 return 0; 2722 } 2723 2724 int atomisp_set_dis_coefs(struct atomisp_sub_device *asd, 2725 struct atomisp_dis_coefficients *coefs) 2726 { 2727 return atomisp_css_set_dis_coefs(asd, coefs); 2728 } 2729 2730 /* 2731 * Function to set/get 3A stat from isp 2732 */ 2733 int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag, 2734 struct atomisp_3a_statistics *config) 2735 { 2736 struct atomisp_device *isp = asd->isp; 2737 struct atomisp_s3a_buf *s3a_buf; 2738 unsigned long ret; 2739 2740 if (flag != 0) 2741 return -EINVAL; 2742 2743 /* sanity check to avoid writing into unallocated memory. */ 2744 if (asd->params.s3a_output_bytes == 0) 2745 return -EINVAL; 2746 2747 if (atomisp_compare_grid(asd, &config->grid_info) != 0) { 2748 /* If the grid info in the argument differs from the current 2749 grid info, we tell the caller to reset the grid size and 2750 try again. */ 2751 return -EAGAIN; 2752 } 2753 2754 if (list_empty(&asd->s3a_stats_ready)) { 2755 dev_err(isp->dev, "3a statistics is not valid.\n"); 2756 return -EAGAIN; 2757 } 2758 2759 s3a_buf = list_entry(asd->s3a_stats_ready.next, 2760 struct atomisp_s3a_buf, list); 2761 if (s3a_buf->s3a_map) 2762 ia_css_translate_3a_statistics( 2763 asd->params.s3a_user_stat, s3a_buf->s3a_map); 2764 else 2765 ia_css_get_3a_statistics(asd->params.s3a_user_stat, 2766 s3a_buf->s3a_data); 2767 2768 config->exp_id = s3a_buf->s3a_data->exp_id; 2769 config->isp_config_id = s3a_buf->s3a_data->isp_config_id; 2770 2771 ret = copy_to_user(config->data, asd->params.s3a_user_stat->data, 2772 asd->params.s3a_output_bytes); 2773 if (ret) { 2774 dev_err(isp->dev, "copy to user failed: copied %lu bytes\n", 2775 ret); 2776 return -EFAULT; 2777 } 2778 2779 /* Move to free buffer list */ 2780 list_del_init(&s3a_buf->list); 2781 list_add_tail(&s3a_buf->list, &asd->s3a_stats); 2782 dev_dbg(isp->dev, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n", 2783 __func__, 2784 config->exp_id, config->isp_config_id); 2785 return 0; 2786 } 2787 2788 int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag, 2789 struct atomisp_metadata *md) 2790 { 2791 struct atomisp_device *isp = asd->isp; 2792 struct ia_css_stream_config *stream_config; 2793 struct ia_css_stream_info *stream_info; 2794 struct camera_mipi_info *mipi_info; 2795 struct atomisp_metadata_buf *md_buf; 2796 enum atomisp_metadata_type md_type = ATOMISP_MAIN_METADATA; 2797 int ret, i; 2798 2799 if (flag != 0) 2800 return -EINVAL; 2801 2802 stream_config = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 2803 stream_config; 2804 stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 2805 stream_info; 2806 2807 /* We always return the resolution and stride even if there is 2808 * no valid metadata. This allows the caller to get the information 2809 * needed to allocate user-space buffers. */ 2810 md->width = stream_info->metadata_info.resolution.width; 2811 md->height = stream_info->metadata_info.resolution.height; 2812 md->stride = stream_info->metadata_info.stride; 2813 2814 /* sanity check to avoid writing into unallocated memory. 2815 * This does not return an error because it is a valid way 2816 * for applications to detect that metadata is not enabled. */ 2817 if (md->width == 0 || md->height == 0 || !md->data) 2818 return 0; 2819 2820 /* This is done in the atomisp_buf_done() */ 2821 if (list_empty(&asd->metadata_ready[md_type])) { 2822 dev_warn(isp->dev, "Metadata queue is empty now!\n"); 2823 return -EAGAIN; 2824 } 2825 2826 mipi_info = atomisp_to_sensor_mipi_info( 2827 isp->inputs[asd->input_curr].camera); 2828 if (!mipi_info) 2829 return -EINVAL; 2830 2831 if (mipi_info->metadata_effective_width) { 2832 for (i = 0; i < md->height; i++) 2833 md->effective_width[i] = 2834 mipi_info->metadata_effective_width[i]; 2835 } 2836 2837 md_buf = list_entry(asd->metadata_ready[md_type].next, 2838 struct atomisp_metadata_buf, list); 2839 md->exp_id = md_buf->metadata->exp_id; 2840 if (md_buf->md_vptr) { 2841 ret = copy_to_user(md->data, 2842 md_buf->md_vptr, 2843 stream_info->metadata_info.size); 2844 } else { 2845 hmm_load(md_buf->metadata->address, 2846 asd->params.metadata_user[md_type], 2847 stream_info->metadata_info.size); 2848 2849 ret = copy_to_user(md->data, 2850 asd->params.metadata_user[md_type], 2851 stream_info->metadata_info.size); 2852 } 2853 if (ret) { 2854 dev_err(isp->dev, "copy to user failed: copied %d bytes\n", 2855 ret); 2856 return -EFAULT; 2857 } 2858 2859 list_del_init(&md_buf->list); 2860 list_add_tail(&md_buf->list, &asd->metadata[md_type]); 2861 2862 dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n", 2863 __func__, md_type, md->exp_id); 2864 return 0; 2865 } 2866 2867 int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag, 2868 struct atomisp_metadata_with_type *md) 2869 { 2870 struct atomisp_device *isp = asd->isp; 2871 struct ia_css_stream_config *stream_config; 2872 struct ia_css_stream_info *stream_info; 2873 struct camera_mipi_info *mipi_info; 2874 struct atomisp_metadata_buf *md_buf; 2875 enum atomisp_metadata_type md_type; 2876 int ret, i; 2877 2878 if (flag != 0) 2879 return -EINVAL; 2880 2881 stream_config = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 2882 stream_config; 2883 stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 2884 stream_info; 2885 2886 /* We always return the resolution and stride even if there is 2887 * no valid metadata. This allows the caller to get the information 2888 * needed to allocate user-space buffers. */ 2889 md->width = stream_info->metadata_info.resolution.width; 2890 md->height = stream_info->metadata_info.resolution.height; 2891 md->stride = stream_info->metadata_info.stride; 2892 2893 /* sanity check to avoid writing into unallocated memory. 2894 * This does not return an error because it is a valid way 2895 * for applications to detect that metadata is not enabled. */ 2896 if (md->width == 0 || md->height == 0 || !md->data) 2897 return 0; 2898 2899 md_type = md->type; 2900 if (md_type < 0 || md_type >= ATOMISP_METADATA_TYPE_NUM) 2901 return -EINVAL; 2902 2903 /* This is done in the atomisp_buf_done() */ 2904 if (list_empty(&asd->metadata_ready[md_type])) { 2905 dev_warn(isp->dev, "Metadata queue is empty now!\n"); 2906 return -EAGAIN; 2907 } 2908 2909 mipi_info = atomisp_to_sensor_mipi_info( 2910 isp->inputs[asd->input_curr].camera); 2911 if (!mipi_info) 2912 return -EINVAL; 2913 2914 if (mipi_info->metadata_effective_width) { 2915 for (i = 0; i < md->height; i++) 2916 md->effective_width[i] = 2917 mipi_info->metadata_effective_width[i]; 2918 } 2919 2920 md_buf = list_entry(asd->metadata_ready[md_type].next, 2921 struct atomisp_metadata_buf, list); 2922 md->exp_id = md_buf->metadata->exp_id; 2923 if (md_buf->md_vptr) { 2924 ret = copy_to_user(md->data, 2925 md_buf->md_vptr, 2926 stream_info->metadata_info.size); 2927 } else { 2928 hmm_load(md_buf->metadata->address, 2929 asd->params.metadata_user[md_type], 2930 stream_info->metadata_info.size); 2931 2932 ret = copy_to_user(md->data, 2933 asd->params.metadata_user[md_type], 2934 stream_info->metadata_info.size); 2935 } 2936 if (ret) { 2937 dev_err(isp->dev, "copy to user failed: copied %d bytes\n", 2938 ret); 2939 return -EFAULT; 2940 } else { 2941 list_del_init(&md_buf->list); 2942 list_add_tail(&md_buf->list, &asd->metadata[md_type]); 2943 } 2944 dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n", 2945 __func__, md_type, md->exp_id); 2946 return 0; 2947 } 2948 2949 /* 2950 * Function to calculate real zoom region for every pipe 2951 */ 2952 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd, 2953 struct ia_css_dz_config *dz_config, 2954 enum atomisp_css_pipe_id css_pipe_id) 2955 2956 { 2957 struct atomisp_stream_env *stream_env = 2958 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 2959 struct atomisp_resolution eff_res, out_res; 2960 int w_offset, h_offset; 2961 2962 memset(&eff_res, 0, sizeof(eff_res)); 2963 memset(&out_res, 0, sizeof(out_res)); 2964 2965 if (dz_config->dx || dz_config->dy) 2966 return 0; 2967 2968 if (css_pipe_id != IA_CSS_PIPE_ID_PREVIEW 2969 && css_pipe_id != IA_CSS_PIPE_ID_CAPTURE) { 2970 dev_err(asd->isp->dev, "%s the set pipe no support crop region" 2971 , __func__); 2972 return -EINVAL; 2973 } 2974 2975 eff_res.width = 2976 stream_env->stream_config.input_config.effective_res.width; 2977 eff_res.height = 2978 stream_env->stream_config.input_config.effective_res.height; 2979 if (eff_res.width == 0 || eff_res.height == 0) { 2980 dev_err(asd->isp->dev, "%s err effective resolution" 2981 , __func__); 2982 return -EINVAL; 2983 } 2984 2985 if (dz_config->zoom_region.resolution.width 2986 == asd->sensor_array_res.width 2987 || dz_config->zoom_region.resolution.height 2988 == asd->sensor_array_res.height) { 2989 /*no need crop region*/ 2990 dz_config->zoom_region.origin.x = 0; 2991 dz_config->zoom_region.origin.y = 0; 2992 dz_config->zoom_region.resolution.width = eff_res.width; 2993 dz_config->zoom_region.resolution.height = eff_res.height; 2994 return 0; 2995 } 2996 2997 /* FIXME: 2998 * This is not the correct implementation with Google's definition, due 2999 * to firmware limitation. 3000 * map real crop region base on above calculating base max crop region. 3001 */ 3002 3003 if (!atomisp_hw_is_isp2401) { 3004 dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x 3005 * eff_res.width 3006 / asd->sensor_array_res.width; 3007 dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y 3008 * eff_res.height 3009 / asd->sensor_array_res.height; 3010 dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width 3011 * eff_res.width 3012 / asd->sensor_array_res.width; 3013 dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height 3014 * eff_res.height 3015 / asd->sensor_array_res.height; 3016 /* 3017 * Set same ratio of crop region resolution and current pipe output 3018 * resolution 3019 */ 3020 out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width; 3021 out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height; 3022 if (out_res.width == 0 || out_res.height == 0) { 3023 dev_err(asd->isp->dev, "%s err current pipe output resolution" 3024 , __func__); 3025 return -EINVAL; 3026 } 3027 } else { 3028 out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width; 3029 out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height; 3030 if (out_res.width == 0 || out_res.height == 0) { 3031 dev_err(asd->isp->dev, "%s err current pipe output resolution" 3032 , __func__); 3033 return -EINVAL; 3034 } 3035 3036 if (asd->sensor_array_res.width * out_res.height 3037 < out_res.width * asd->sensor_array_res.height) { 3038 h_offset = asd->sensor_array_res.height 3039 - asd->sensor_array_res.width 3040 * out_res.height / out_res.width; 3041 h_offset = h_offset / 2; 3042 if (dz_config->zoom_region.origin.y < h_offset) 3043 dz_config->zoom_region.origin.y = 0; 3044 else 3045 dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y - h_offset; 3046 w_offset = 0; 3047 } else { 3048 w_offset = asd->sensor_array_res.width 3049 - asd->sensor_array_res.height 3050 * out_res.width / out_res.height; 3051 w_offset = w_offset / 2; 3052 if (dz_config->zoom_region.origin.x < w_offset) 3053 dz_config->zoom_region.origin.x = 0; 3054 else 3055 dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x - w_offset; 3056 h_offset = 0; 3057 } 3058 dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x 3059 * eff_res.width 3060 / (asd->sensor_array_res.width - 2 * w_offset); 3061 dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y 3062 * eff_res.height 3063 / (asd->sensor_array_res.height - 2 * h_offset); 3064 dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width 3065 * eff_res.width 3066 / (asd->sensor_array_res.width - 2 * w_offset); 3067 dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height 3068 * eff_res.height 3069 / (asd->sensor_array_res.height - 2 * h_offset); 3070 } 3071 3072 if (out_res.width * dz_config->zoom_region.resolution.height 3073 > dz_config->zoom_region.resolution.width * out_res.height) { 3074 dz_config->zoom_region.resolution.height = 3075 dz_config->zoom_region.resolution.width 3076 * out_res.height / out_res.width; 3077 } else { 3078 dz_config->zoom_region.resolution.width = 3079 dz_config->zoom_region.resolution.height 3080 * out_res.width / out_res.height; 3081 } 3082 dev_dbg(asd->isp->dev, 3083 "%s crop region:(%d,%d),(%d,%d) eff_res(%d, %d) array_size(%d,%d) out_res(%d, %d)\n", 3084 __func__, dz_config->zoom_region.origin.x, 3085 dz_config->zoom_region.origin.y, 3086 dz_config->zoom_region.resolution.width, 3087 dz_config->zoom_region.resolution.height, 3088 eff_res.width, eff_res.height, 3089 asd->sensor_array_res.width, 3090 asd->sensor_array_res.height, 3091 out_res.width, out_res.height); 3092 3093 if ((dz_config->zoom_region.origin.x + 3094 dz_config->zoom_region.resolution.width 3095 > eff_res.width) || 3096 (dz_config->zoom_region.origin.y + 3097 dz_config->zoom_region.resolution.height 3098 > eff_res.height)) 3099 return -EINVAL; 3100 3101 return 0; 3102 } 3103 3104 /* 3105 * Function to check the zoom region whether is effective 3106 */ 3107 static bool atomisp_check_zoom_region( 3108 struct atomisp_sub_device *asd, 3109 struct ia_css_dz_config *dz_config) 3110 { 3111 struct atomisp_resolution config; 3112 bool flag = false; 3113 unsigned int w, h; 3114 3115 memset(&config, 0, sizeof(struct atomisp_resolution)); 3116 3117 if (dz_config->dx && dz_config->dy) 3118 return true; 3119 3120 config.width = asd->sensor_array_res.width; 3121 config.height = asd->sensor_array_res.height; 3122 w = dz_config->zoom_region.origin.x + 3123 dz_config->zoom_region.resolution.width; 3124 h = dz_config->zoom_region.origin.y + 3125 dz_config->zoom_region.resolution.height; 3126 3127 if ((w <= config.width) && (h <= config.height) && w > 0 && h > 0) 3128 flag = true; 3129 else 3130 /* setting error zoom region */ 3131 dev_err(asd->isp->dev, 3132 "%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n", 3133 __func__, dz_config->zoom_region.origin.x, 3134 dz_config->zoom_region.origin.y, 3135 dz_config->zoom_region.resolution.width, 3136 dz_config->zoom_region.resolution.height, 3137 config.width, config.height); 3138 3139 return flag; 3140 } 3141 3142 void atomisp_apply_css_parameters( 3143 struct atomisp_sub_device *asd, 3144 struct atomisp_css_params *css_param) 3145 { 3146 if (css_param->update_flag.wb_config) 3147 atomisp_css_set_wb_config(asd, &css_param->wb_config); 3148 3149 if (css_param->update_flag.ob_config) 3150 atomisp_css_set_ob_config(asd, &css_param->ob_config); 3151 3152 if (css_param->update_flag.dp_config) 3153 atomisp_css_set_dp_config(asd, &css_param->dp_config); 3154 3155 if (css_param->update_flag.nr_config) 3156 atomisp_css_set_nr_config(asd, &css_param->nr_config); 3157 3158 if (css_param->update_flag.ee_config) 3159 atomisp_css_set_ee_config(asd, &css_param->ee_config); 3160 3161 if (css_param->update_flag.tnr_config) 3162 atomisp_css_set_tnr_config(asd, &css_param->tnr_config); 3163 3164 if (css_param->update_flag.a3a_config) 3165 atomisp_css_set_3a_config(asd, &css_param->s3a_config); 3166 3167 if (css_param->update_flag.ctc_config) 3168 atomisp_css_set_ctc_config(asd, &css_param->ctc_config); 3169 3170 if (css_param->update_flag.cnr_config) 3171 atomisp_css_set_cnr_config(asd, &css_param->cnr_config); 3172 3173 if (css_param->update_flag.ecd_config) 3174 atomisp_css_set_ecd_config(asd, &css_param->ecd_config); 3175 3176 if (css_param->update_flag.ynr_config) 3177 atomisp_css_set_ynr_config(asd, &css_param->ynr_config); 3178 3179 if (css_param->update_flag.fc_config) 3180 atomisp_css_set_fc_config(asd, &css_param->fc_config); 3181 3182 if (css_param->update_flag.macc_config) 3183 atomisp_css_set_macc_config(asd, &css_param->macc_config); 3184 3185 if (css_param->update_flag.aa_config) 3186 atomisp_css_set_aa_config(asd, &css_param->aa_config); 3187 3188 if (css_param->update_flag.anr_config) 3189 atomisp_css_set_anr_config(asd, &css_param->anr_config); 3190 3191 if (css_param->update_flag.xnr_config) 3192 atomisp_css_set_xnr_config(asd, &css_param->xnr_config); 3193 3194 if (css_param->update_flag.yuv2rgb_cc_config) 3195 atomisp_css_set_yuv2rgb_cc_config(asd, 3196 &css_param->yuv2rgb_cc_config); 3197 3198 if (css_param->update_flag.rgb2yuv_cc_config) 3199 atomisp_css_set_rgb2yuv_cc_config(asd, 3200 &css_param->rgb2yuv_cc_config); 3201 3202 if (css_param->update_flag.macc_table) 3203 atomisp_css_set_macc_table(asd, &css_param->macc_table); 3204 3205 if (css_param->update_flag.xnr_table) 3206 atomisp_css_set_xnr_table(asd, &css_param->xnr_table); 3207 3208 if (css_param->update_flag.r_gamma_table) 3209 atomisp_css_set_r_gamma_table(asd, &css_param->r_gamma_table); 3210 3211 if (css_param->update_flag.g_gamma_table) 3212 atomisp_css_set_g_gamma_table(asd, &css_param->g_gamma_table); 3213 3214 if (css_param->update_flag.b_gamma_table) 3215 atomisp_css_set_b_gamma_table(asd, &css_param->b_gamma_table); 3216 3217 if (css_param->update_flag.anr_thres) 3218 atomisp_css_set_anr_thres(asd, &css_param->anr_thres); 3219 3220 if (css_param->update_flag.shading_table) 3221 atomisp_css_set_shading_table(asd, css_param->shading_table); 3222 3223 if (css_param->update_flag.morph_table && asd->params.gdc_cac_en) 3224 atomisp_css_set_morph_table(asd, css_param->morph_table); 3225 3226 if (css_param->update_flag.dvs2_coefs) { 3227 struct atomisp_css_dvs_grid_info *dvs_grid_info = 3228 atomisp_css_get_dvs_grid_info( 3229 &asd->params.curr_grid_info); 3230 3231 if (dvs_grid_info && dvs_grid_info->enable) 3232 atomisp_css_set_dvs2_coefs(asd, css_param->dvs2_coeff); 3233 } 3234 3235 if (css_param->update_flag.dvs_6axis_config) 3236 atomisp_css_set_dvs_6axis(asd, css_param->dvs_6axis); 3237 3238 atomisp_css_set_isp_config_id(asd, css_param->isp_config_id); 3239 /* 3240 * These configurations are on used by ISP1.x, not for ISP2.x, 3241 * so do not handle them. see comments of ia_css_isp_config. 3242 * 1 cc_config 3243 * 2 ce_config 3244 * 3 de_config 3245 * 4 gc_config 3246 * 5 gamma_table 3247 * 6 ctc_table 3248 * 7 dvs_coefs 3249 */ 3250 } 3251 3252 static unsigned int long copy_from_compatible(void *to, const void *from, 3253 unsigned long n, bool from_user) 3254 { 3255 if (from_user) 3256 return copy_from_user(to, (void __user *)from, n); 3257 else 3258 memcpy(to, from, n); 3259 return 0; 3260 } 3261 3262 int atomisp_cp_general_isp_parameters(struct atomisp_sub_device *asd, 3263 struct atomisp_parameters *arg, 3264 struct atomisp_css_params *css_param, 3265 bool from_user) 3266 { 3267 struct atomisp_parameters *cur_config = &css_param->update_flag; 3268 3269 if (!arg || !asd || !css_param) 3270 return -EINVAL; 3271 3272 if (arg->wb_config && (from_user || !cur_config->wb_config)) { 3273 if (copy_from_compatible(&css_param->wb_config, arg->wb_config, 3274 sizeof(struct atomisp_css_wb_config), 3275 from_user)) 3276 return -EFAULT; 3277 css_param->update_flag.wb_config = 3278 (struct atomisp_wb_config *)&css_param->wb_config; 3279 } 3280 3281 if (arg->ob_config && (from_user || !cur_config->ob_config)) { 3282 if (copy_from_compatible(&css_param->ob_config, arg->ob_config, 3283 sizeof(struct atomisp_css_ob_config), 3284 from_user)) 3285 return -EFAULT; 3286 css_param->update_flag.ob_config = 3287 (struct atomisp_ob_config *)&css_param->ob_config; 3288 } 3289 3290 if (arg->dp_config && (from_user || !cur_config->dp_config)) { 3291 if (copy_from_compatible(&css_param->dp_config, arg->dp_config, 3292 sizeof(struct atomisp_css_dp_config), 3293 from_user)) 3294 return -EFAULT; 3295 css_param->update_flag.dp_config = 3296 (struct atomisp_dp_config *)&css_param->dp_config; 3297 } 3298 3299 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { 3300 if (arg->dz_config && (from_user || !cur_config->dz_config)) { 3301 if (copy_from_compatible(&css_param->dz_config, 3302 arg->dz_config, 3303 sizeof(struct atomisp_css_dz_config), 3304 from_user)) 3305 return -EFAULT; 3306 if (!atomisp_check_zoom_region(asd, 3307 &css_param->dz_config)) { 3308 dev_err(asd->isp->dev, "crop region error!"); 3309 return -EINVAL; 3310 } 3311 css_param->update_flag.dz_config = 3312 (struct atomisp_dz_config *) 3313 &css_param->dz_config; 3314 } 3315 } 3316 3317 if (arg->nr_config && (from_user || !cur_config->nr_config)) { 3318 if (copy_from_compatible(&css_param->nr_config, arg->nr_config, 3319 sizeof(struct atomisp_css_nr_config), 3320 from_user)) 3321 return -EFAULT; 3322 css_param->update_flag.nr_config = 3323 (struct atomisp_nr_config *)&css_param->nr_config; 3324 } 3325 3326 if (arg->ee_config && (from_user || !cur_config->ee_config)) { 3327 if (copy_from_compatible(&css_param->ee_config, arg->ee_config, 3328 sizeof(struct atomisp_css_ee_config), 3329 from_user)) 3330 return -EFAULT; 3331 css_param->update_flag.ee_config = 3332 (struct atomisp_ee_config *)&css_param->ee_config; 3333 } 3334 3335 if (arg->tnr_config && (from_user || !cur_config->tnr_config)) { 3336 if (copy_from_compatible(&css_param->tnr_config, 3337 arg->tnr_config, 3338 sizeof(struct atomisp_css_tnr_config), 3339 from_user)) 3340 return -EFAULT; 3341 css_param->update_flag.tnr_config = 3342 (struct atomisp_tnr_config *) 3343 &css_param->tnr_config; 3344 } 3345 3346 if (arg->a3a_config && (from_user || !cur_config->a3a_config)) { 3347 if (copy_from_compatible(&css_param->s3a_config, 3348 arg->a3a_config, 3349 sizeof(struct atomisp_css_3a_config), 3350 from_user)) 3351 return -EFAULT; 3352 css_param->update_flag.a3a_config = 3353 (struct atomisp_3a_config *)&css_param->s3a_config; 3354 } 3355 3356 if (arg->ctc_config && (from_user || !cur_config->ctc_config)) { 3357 if (copy_from_compatible(&css_param->ctc_config, 3358 arg->ctc_config, 3359 sizeof(struct atomisp_css_ctc_config), 3360 from_user)) 3361 return -EFAULT; 3362 css_param->update_flag.ctc_config = 3363 (struct atomisp_ctc_config *) 3364 &css_param->ctc_config; 3365 } 3366 3367 if (arg->cnr_config && (from_user || !cur_config->cnr_config)) { 3368 if (copy_from_compatible(&css_param->cnr_config, 3369 arg->cnr_config, 3370 sizeof(struct atomisp_css_cnr_config), 3371 from_user)) 3372 return -EFAULT; 3373 css_param->update_flag.cnr_config = 3374 (struct atomisp_cnr_config *) 3375 &css_param->cnr_config; 3376 } 3377 3378 if (arg->ecd_config && (from_user || !cur_config->ecd_config)) { 3379 if (copy_from_compatible(&css_param->ecd_config, 3380 arg->ecd_config, 3381 sizeof(struct atomisp_css_ecd_config), 3382 from_user)) 3383 return -EFAULT; 3384 css_param->update_flag.ecd_config = 3385 (struct atomisp_ecd_config *) 3386 &css_param->ecd_config; 3387 } 3388 3389 if (arg->ynr_config && (from_user || !cur_config->ynr_config)) { 3390 if (copy_from_compatible(&css_param->ynr_config, 3391 arg->ynr_config, 3392 sizeof(struct atomisp_css_ynr_config), 3393 from_user)) 3394 return -EFAULT; 3395 css_param->update_flag.ynr_config = 3396 (struct atomisp_ynr_config *) 3397 &css_param->ynr_config; 3398 } 3399 3400 if (arg->fc_config && (from_user || !cur_config->fc_config)) { 3401 if (copy_from_compatible(&css_param->fc_config, 3402 arg->fc_config, 3403 sizeof(struct atomisp_css_fc_config), 3404 from_user)) 3405 return -EFAULT; 3406 css_param->update_flag.fc_config = 3407 (struct atomisp_fc_config *)&css_param->fc_config; 3408 } 3409 3410 if (arg->macc_config && (from_user || !cur_config->macc_config)) { 3411 if (copy_from_compatible(&css_param->macc_config, 3412 arg->macc_config, 3413 sizeof(struct atomisp_css_macc_config), 3414 from_user)) 3415 return -EFAULT; 3416 css_param->update_flag.macc_config = 3417 (struct atomisp_macc_config *) 3418 &css_param->macc_config; 3419 } 3420 3421 if (arg->aa_config && (from_user || !cur_config->aa_config)) { 3422 if (copy_from_compatible(&css_param->aa_config, arg->aa_config, 3423 sizeof(struct atomisp_css_aa_config), 3424 from_user)) 3425 return -EFAULT; 3426 css_param->update_flag.aa_config = 3427 (struct atomisp_aa_config *)&css_param->aa_config; 3428 } 3429 3430 if (arg->anr_config && (from_user || !cur_config->anr_config)) { 3431 if (copy_from_compatible(&css_param->anr_config, 3432 arg->anr_config, 3433 sizeof(struct atomisp_css_anr_config), 3434 from_user)) 3435 return -EFAULT; 3436 css_param->update_flag.anr_config = 3437 (struct atomisp_anr_config *) 3438 &css_param->anr_config; 3439 } 3440 3441 if (arg->xnr_config && (from_user || !cur_config->xnr_config)) { 3442 if (copy_from_compatible(&css_param->xnr_config, 3443 arg->xnr_config, 3444 sizeof(struct atomisp_css_xnr_config), 3445 from_user)) 3446 return -EFAULT; 3447 css_param->update_flag.xnr_config = 3448 (struct atomisp_xnr_config *) 3449 &css_param->xnr_config; 3450 } 3451 3452 if (arg->yuv2rgb_cc_config && 3453 (from_user || !cur_config->yuv2rgb_cc_config)) { 3454 if (copy_from_compatible(&css_param->yuv2rgb_cc_config, 3455 arg->yuv2rgb_cc_config, 3456 sizeof(struct atomisp_css_cc_config), 3457 from_user)) 3458 return -EFAULT; 3459 css_param->update_flag.yuv2rgb_cc_config = 3460 (struct atomisp_cc_config *) 3461 &css_param->yuv2rgb_cc_config; 3462 } 3463 3464 if (arg->rgb2yuv_cc_config && 3465 (from_user || !cur_config->rgb2yuv_cc_config)) { 3466 if (copy_from_compatible(&css_param->rgb2yuv_cc_config, 3467 arg->rgb2yuv_cc_config, 3468 sizeof(struct atomisp_css_cc_config), 3469 from_user)) 3470 return -EFAULT; 3471 css_param->update_flag.rgb2yuv_cc_config = 3472 (struct atomisp_cc_config *) 3473 &css_param->rgb2yuv_cc_config; 3474 } 3475 3476 if (arg->macc_table && (from_user || !cur_config->macc_table)) { 3477 if (copy_from_compatible(&css_param->macc_table, 3478 arg->macc_table, 3479 sizeof(struct atomisp_css_macc_table), 3480 from_user)) 3481 return -EFAULT; 3482 css_param->update_flag.macc_table = 3483 (struct atomisp_macc_table *) 3484 &css_param->macc_table; 3485 } 3486 3487 if (arg->xnr_table && (from_user || !cur_config->xnr_table)) { 3488 if (copy_from_compatible(&css_param->xnr_table, 3489 arg->xnr_table, 3490 sizeof(struct atomisp_css_xnr_table), 3491 from_user)) 3492 return -EFAULT; 3493 css_param->update_flag.xnr_table = 3494 (struct atomisp_xnr_table *)&css_param->xnr_table; 3495 } 3496 3497 if (arg->r_gamma_table && (from_user || !cur_config->r_gamma_table)) { 3498 if (copy_from_compatible(&css_param->r_gamma_table, 3499 arg->r_gamma_table, 3500 sizeof(struct atomisp_css_rgb_gamma_table), 3501 from_user)) 3502 return -EFAULT; 3503 css_param->update_flag.r_gamma_table = 3504 (struct atomisp_rgb_gamma_table *) 3505 &css_param->r_gamma_table; 3506 } 3507 3508 if (arg->g_gamma_table && (from_user || !cur_config->g_gamma_table)) { 3509 if (copy_from_compatible(&css_param->g_gamma_table, 3510 arg->g_gamma_table, 3511 sizeof(struct atomisp_css_rgb_gamma_table), 3512 from_user)) 3513 return -EFAULT; 3514 css_param->update_flag.g_gamma_table = 3515 (struct atomisp_rgb_gamma_table *) 3516 &css_param->g_gamma_table; 3517 } 3518 3519 if (arg->b_gamma_table && (from_user || !cur_config->b_gamma_table)) { 3520 if (copy_from_compatible(&css_param->b_gamma_table, 3521 arg->b_gamma_table, 3522 sizeof(struct atomisp_css_rgb_gamma_table), 3523 from_user)) 3524 return -EFAULT; 3525 css_param->update_flag.b_gamma_table = 3526 (struct atomisp_rgb_gamma_table *) 3527 &css_param->b_gamma_table; 3528 } 3529 3530 if (arg->anr_thres && (from_user || !cur_config->anr_thres)) { 3531 if (copy_from_compatible(&css_param->anr_thres, arg->anr_thres, 3532 sizeof(struct atomisp_css_anr_thres), 3533 from_user)) 3534 return -EFAULT; 3535 css_param->update_flag.anr_thres = 3536 (struct atomisp_anr_thres *)&css_param->anr_thres; 3537 } 3538 3539 if (from_user) 3540 css_param->isp_config_id = arg->isp_config_id; 3541 /* 3542 * These configurations are on used by ISP1.x, not for ISP2.x, 3543 * so do not handle them. see comments of ia_css_isp_config. 3544 * 1 cc_config 3545 * 2 ce_config 3546 * 3 de_config 3547 * 4 gc_config 3548 * 5 gamma_table 3549 * 6 ctc_table 3550 * 7 dvs_coefs 3551 */ 3552 return 0; 3553 } 3554 3555 int atomisp_cp_lsc_table(struct atomisp_sub_device *asd, 3556 struct atomisp_shading_table *source_st, 3557 struct atomisp_css_params *css_param, 3558 bool from_user) 3559 { 3560 unsigned int i; 3561 unsigned int len_table; 3562 struct atomisp_css_shading_table *shading_table; 3563 struct atomisp_css_shading_table *old_table; 3564 struct atomisp_shading_table *st, dest_st; 3565 3566 if (!source_st) 3567 return 0; 3568 3569 if (!css_param) 3570 return -EINVAL; 3571 3572 if (!from_user && css_param->update_flag.shading_table) 3573 return 0; 3574 3575 if (atomisp_hw_is_isp2401) { 3576 if (copy_from_compatible(&dest_st, source_st, 3577 sizeof(struct atomisp_shading_table), 3578 from_user)) { 3579 dev_err(asd->isp->dev, "copy shading table failed!"); 3580 return -EFAULT; 3581 } 3582 st = &dest_st; 3583 } else { 3584 st = source_st; 3585 } 3586 3587 old_table = css_param->shading_table; 3588 3589 /* user config is to disable the shading table. */ 3590 if (!st->enable) { 3591 /* Generate a minimum table with enable = 0. */ 3592 shading_table = atomisp_css_shading_table_alloc(1, 1); 3593 if (!shading_table) 3594 return -ENOMEM; 3595 shading_table->enable = 0; 3596 goto set_lsc; 3597 } 3598 3599 /* Setting a new table. Validate first - all tables must be set */ 3600 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 3601 if (!st->data[i]) { 3602 dev_err(asd->isp->dev, "shading table validate failed"); 3603 return -EINVAL; 3604 } 3605 } 3606 3607 /* Shading table size per color */ 3608 if (!atomisp_hw_is_isp2401) { 3609 if (st->width > ISP2400_SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 3610 st->height > ISP2400_SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) { 3611 dev_err(asd->isp->dev, "shading table w/h validate failed!"); 3612 return -EINVAL; 3613 } 3614 } else { 3615 if (st->width > ISP2401_SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 3616 st->height > ISP2401_SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) { 3617 dev_err(asd->isp->dev, "shading table w/h validate failed!"); 3618 return -EINVAL; 3619 } 3620 } 3621 3622 shading_table = atomisp_css_shading_table_alloc(st->width, st->height); 3623 if (!shading_table) 3624 return -ENOMEM; 3625 3626 len_table = st->width * st->height * ATOMISP_SC_TYPE_SIZE; 3627 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 3628 if (copy_from_compatible(shading_table->data[i], 3629 st->data[i], len_table, from_user)) { 3630 atomisp_css_shading_table_free(shading_table); 3631 return -EFAULT; 3632 } 3633 } 3634 shading_table->sensor_width = st->sensor_width; 3635 shading_table->sensor_height = st->sensor_height; 3636 shading_table->fraction_bits = st->fraction_bits; 3637 shading_table->enable = st->enable; 3638 3639 /* No need to update shading table if it is the same */ 3640 if (old_table && 3641 old_table->sensor_width == shading_table->sensor_width && 3642 old_table->sensor_height == shading_table->sensor_height && 3643 old_table->width == shading_table->width && 3644 old_table->height == shading_table->height && 3645 old_table->fraction_bits == shading_table->fraction_bits && 3646 old_table->enable == shading_table->enable) { 3647 bool data_is_same = true; 3648 3649 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 3650 if (memcmp(shading_table->data[i], old_table->data[i], 3651 len_table) != 0) { 3652 data_is_same = false; 3653 break; 3654 } 3655 } 3656 3657 if (data_is_same) { 3658 atomisp_css_shading_table_free(shading_table); 3659 return 0; 3660 } 3661 } 3662 3663 set_lsc: 3664 /* set LSC to CSS */ 3665 css_param->shading_table = shading_table; 3666 css_param->update_flag.shading_table = (struct atomisp_shading_table *)shading_table; 3667 asd->params.sc_en = shading_table; 3668 3669 if (old_table) 3670 atomisp_css_shading_table_free(old_table); 3671 3672 return 0; 3673 } 3674 3675 int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd, 3676 struct ia_css_dvs2_coefficients *coefs, 3677 struct atomisp_css_params *css_param, 3678 bool from_user) 3679 { 3680 struct atomisp_css_dvs_grid_info *cur = 3681 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 3682 int dvs_hor_coef_bytes, dvs_ver_coef_bytes; 3683 struct ia_css_dvs2_coefficients dvs2_coefs; 3684 3685 if (!coefs || !cur) 3686 return 0; 3687 3688 if (!from_user && css_param->update_flag.dvs2_coefs) 3689 return 0; 3690 3691 if (!atomisp_hw_is_isp2401) { 3692 if (sizeof(*cur) != sizeof(coefs->grid) || 3693 memcmp(&coefs->grid, cur, sizeof(coefs->grid))) { 3694 dev_err(asd->isp->dev, "dvs grid mis-match!\n"); 3695 /* If the grid info in the argument differs from the current 3696 grid info, we tell the caller to reset the grid size and 3697 try again. */ 3698 return -EAGAIN; 3699 } 3700 3701 if (!coefs->hor_coefs.odd_real || 3702 !coefs->hor_coefs.odd_imag || 3703 !coefs->hor_coefs.even_real || 3704 !coefs->hor_coefs.even_imag || 3705 !coefs->ver_coefs.odd_real || 3706 !coefs->ver_coefs.odd_imag || 3707 !coefs->ver_coefs.even_real || 3708 !coefs->ver_coefs.even_imag) 3709 return -EINVAL; 3710 3711 if (!css_param->dvs2_coeff) { 3712 /* DIS coefficients. */ 3713 css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur); 3714 if (!css_param->dvs2_coeff) 3715 return -ENOMEM; 3716 } 3717 3718 dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes; 3719 dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes; 3720 if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real, 3721 coefs->hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) || 3722 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag, 3723 coefs->hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) || 3724 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real, 3725 coefs->hor_coefs.even_real, dvs_hor_coef_bytes, from_user) || 3726 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag, 3727 coefs->hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) || 3728 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real, 3729 coefs->ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) || 3730 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag, 3731 coefs->ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) || 3732 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real, 3733 coefs->ver_coefs.even_real, dvs_ver_coef_bytes, from_user) || 3734 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag, 3735 coefs->ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) { 3736 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 3737 css_param->dvs2_coeff = NULL; 3738 return -EFAULT; 3739 } 3740 } else { 3741 if (copy_from_compatible(&dvs2_coefs, coefs, 3742 sizeof(struct ia_css_dvs2_coefficients), 3743 from_user)) { 3744 dev_err(asd->isp->dev, "copy dvs2 coef failed"); 3745 return -EFAULT; 3746 } 3747 3748 if (sizeof(*cur) != sizeof(dvs2_coefs.grid) || 3749 memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) { 3750 dev_err(asd->isp->dev, "dvs grid mis-match!\n"); 3751 /* If the grid info in the argument differs from the current 3752 grid info, we tell the caller to reset the grid size and 3753 try again. */ 3754 return -EAGAIN; 3755 } 3756 3757 if (!dvs2_coefs.hor_coefs.odd_real || 3758 !dvs2_coefs.hor_coefs.odd_imag || 3759 !dvs2_coefs.hor_coefs.even_real || 3760 !dvs2_coefs.hor_coefs.even_imag || 3761 !dvs2_coefs.ver_coefs.odd_real || 3762 !dvs2_coefs.ver_coefs.odd_imag || 3763 !dvs2_coefs.ver_coefs.even_real || 3764 !dvs2_coefs.ver_coefs.even_imag) 3765 return -EINVAL; 3766 3767 if (!css_param->dvs2_coeff) { 3768 /* DIS coefficients. */ 3769 css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur); 3770 if (!css_param->dvs2_coeff) 3771 return -ENOMEM; 3772 } 3773 3774 dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes; 3775 dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes; 3776 if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real, 3777 dvs2_coefs.hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) || 3778 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag, 3779 dvs2_coefs.hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) || 3780 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real, 3781 dvs2_coefs.hor_coefs.even_real, dvs_hor_coef_bytes, from_user) || 3782 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag, 3783 dvs2_coefs.hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) || 3784 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real, 3785 dvs2_coefs.ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) || 3786 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag, 3787 dvs2_coefs.ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) || 3788 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real, 3789 dvs2_coefs.ver_coefs.even_real, dvs_ver_coef_bytes, from_user) || 3790 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag, 3791 dvs2_coefs.ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) { 3792 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 3793 css_param->dvs2_coeff = NULL; 3794 return -EFAULT; 3795 } 3796 } 3797 3798 css_param->update_flag.dvs2_coefs = 3799 (struct atomisp_dvs2_coefficients *)css_param->dvs2_coeff; 3800 return 0; 3801 } 3802 3803 int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd, 3804 struct atomisp_dvs_6axis_config *source_6axis_config, 3805 struct atomisp_css_params *css_param, 3806 bool from_user) 3807 { 3808 struct atomisp_css_dvs_6axis_config *dvs_6axis_config; 3809 struct atomisp_css_dvs_6axis_config *old_6axis_config; 3810 struct ia_css_stream *stream = 3811 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream; 3812 struct atomisp_css_dvs_grid_info *dvs_grid_info = 3813 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 3814 int ret = -EFAULT; 3815 3816 if (!stream) { 3817 dev_err(asd->isp->dev, "%s: internal error!", __func__); 3818 return -EINVAL; 3819 } 3820 3821 if (!source_6axis_config || !dvs_grid_info) 3822 return 0; 3823 3824 if (!dvs_grid_info->enable) 3825 return 0; 3826 3827 if (!from_user && css_param->update_flag.dvs_6axis_config) 3828 return 0; 3829 3830 /* check whether need to reallocate for 6 axis config */ 3831 old_6axis_config = css_param->dvs_6axis; 3832 dvs_6axis_config = old_6axis_config; 3833 3834 if (atomisp_hw_is_isp2401) { 3835 struct atomisp_css_dvs_6axis_config t_6axis_config; 3836 3837 if (copy_from_compatible(&t_6axis_config, source_6axis_config, 3838 sizeof(struct atomisp_dvs_6axis_config), 3839 from_user)) { 3840 dev_err(asd->isp->dev, "copy morph table failed!"); 3841 return -EFAULT; 3842 } 3843 3844 if (old_6axis_config && 3845 (old_6axis_config->width_y != t_6axis_config.width_y || 3846 old_6axis_config->height_y != t_6axis_config.height_y || 3847 old_6axis_config->width_uv != t_6axis_config.width_uv || 3848 old_6axis_config->height_uv != t_6axis_config.height_uv)) { 3849 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 3850 css_param->dvs_6axis = NULL; 3851 3852 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 3853 if (!dvs_6axis_config) 3854 return -ENOMEM; 3855 } else if (!dvs_6axis_config) { 3856 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 3857 if (!dvs_6axis_config) 3858 return -ENOMEM; 3859 } 3860 3861 dvs_6axis_config->exp_id = t_6axis_config.exp_id; 3862 3863 if (copy_from_compatible(dvs_6axis_config->xcoords_y, 3864 t_6axis_config.xcoords_y, 3865 t_6axis_config.width_y * 3866 t_6axis_config.height_y * 3867 sizeof(*dvs_6axis_config->xcoords_y), 3868 from_user)) 3869 goto error; 3870 if (copy_from_compatible(dvs_6axis_config->ycoords_y, 3871 t_6axis_config.ycoords_y, 3872 t_6axis_config.width_y * 3873 t_6axis_config.height_y * 3874 sizeof(*dvs_6axis_config->ycoords_y), 3875 from_user)) 3876 goto error; 3877 if (copy_from_compatible(dvs_6axis_config->xcoords_uv, 3878 t_6axis_config.xcoords_uv, 3879 t_6axis_config.width_uv * 3880 t_6axis_config.height_uv * 3881 sizeof(*dvs_6axis_config->xcoords_uv), 3882 from_user)) 3883 goto error; 3884 if (copy_from_compatible(dvs_6axis_config->ycoords_uv, 3885 t_6axis_config.ycoords_uv, 3886 t_6axis_config.width_uv * 3887 t_6axis_config.height_uv * 3888 sizeof(*dvs_6axis_config->ycoords_uv), 3889 from_user)) 3890 goto error; 3891 } else { 3892 if (old_6axis_config && 3893 (old_6axis_config->width_y != source_6axis_config->width_y || 3894 old_6axis_config->height_y != source_6axis_config->height_y || 3895 old_6axis_config->width_uv != source_6axis_config->width_uv || 3896 old_6axis_config->height_uv != source_6axis_config->height_uv)) { 3897 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 3898 css_param->dvs_6axis = NULL; 3899 3900 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 3901 if (!dvs_6axis_config) 3902 return -ENOMEM; 3903 } else if (!dvs_6axis_config) { 3904 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 3905 if (!dvs_6axis_config) 3906 return -ENOMEM; 3907 } 3908 3909 dvs_6axis_config->exp_id = source_6axis_config->exp_id; 3910 3911 if (copy_from_compatible(dvs_6axis_config->xcoords_y, 3912 source_6axis_config->xcoords_y, 3913 source_6axis_config->width_y * 3914 source_6axis_config->height_y * 3915 sizeof(*source_6axis_config->xcoords_y), 3916 from_user)) 3917 goto error; 3918 if (copy_from_compatible(dvs_6axis_config->ycoords_y, 3919 source_6axis_config->ycoords_y, 3920 source_6axis_config->width_y * 3921 source_6axis_config->height_y * 3922 sizeof(*source_6axis_config->ycoords_y), 3923 from_user)) 3924 goto error; 3925 if (copy_from_compatible(dvs_6axis_config->xcoords_uv, 3926 source_6axis_config->xcoords_uv, 3927 source_6axis_config->width_uv * 3928 source_6axis_config->height_uv * 3929 sizeof(*source_6axis_config->xcoords_uv), 3930 from_user)) 3931 goto error; 3932 if (copy_from_compatible(dvs_6axis_config->ycoords_uv, 3933 source_6axis_config->ycoords_uv, 3934 source_6axis_config->width_uv * 3935 source_6axis_config->height_uv * 3936 sizeof(*source_6axis_config->ycoords_uv), 3937 from_user)) 3938 goto error; 3939 } 3940 css_param->dvs_6axis = dvs_6axis_config; 3941 css_param->update_flag.dvs_6axis_config = 3942 (struct atomisp_dvs_6axis_config *)dvs_6axis_config; 3943 return 0; 3944 3945 error: 3946 if (dvs_6axis_config) 3947 ia_css_dvs2_6axis_config_free(dvs_6axis_config); 3948 return ret; 3949 } 3950 3951 int atomisp_cp_morph_table(struct atomisp_sub_device *asd, 3952 struct atomisp_morph_table *source_morph_table, 3953 struct atomisp_css_params *css_param, 3954 bool from_user) 3955 { 3956 int ret = -EFAULT; 3957 unsigned int i; 3958 struct atomisp_css_morph_table *morph_table; 3959 struct atomisp_css_morph_table *old_morph_table; 3960 3961 if (!source_morph_table) 3962 return 0; 3963 3964 if (!from_user && css_param->update_flag.morph_table) 3965 return 0; 3966 3967 old_morph_table = css_param->morph_table; 3968 3969 if (atomisp_hw_is_isp2401) { 3970 struct atomisp_css_morph_table mtbl; 3971 3972 if (copy_from_compatible(&mtbl, source_morph_table, 3973 sizeof(struct atomisp_morph_table), 3974 from_user)) { 3975 dev_err(asd->isp->dev, "copy morph table failed!"); 3976 return -EFAULT; 3977 } 3978 3979 morph_table = atomisp_css_morph_table_allocate( 3980 mtbl.width, 3981 mtbl.height); 3982 if (!morph_table) 3983 return -ENOMEM; 3984 3985 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) { 3986 if (copy_from_compatible(morph_table->coordinates_x[i], 3987 (__force void *)source_morph_table->coordinates_x[i], 3988 mtbl.height * mtbl.width * 3989 sizeof(*morph_table->coordinates_x[i]), 3990 from_user)) 3991 goto error; 3992 3993 if (copy_from_compatible(morph_table->coordinates_y[i], 3994 (__force void *)source_morph_table->coordinates_y[i], 3995 mtbl.height * mtbl.width * 3996 sizeof(*morph_table->coordinates_y[i]), 3997 from_user)) 3998 goto error; 3999 } 4000 } else { 4001 morph_table = atomisp_css_morph_table_allocate( 4002 source_morph_table->width, 4003 source_morph_table->height); 4004 if (!morph_table) 4005 return -ENOMEM; 4006 4007 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) { 4008 if (copy_from_compatible(morph_table->coordinates_x[i], 4009 (__force void *)source_morph_table->coordinates_x[i], 4010 source_morph_table->height * source_morph_table->width * 4011 sizeof(*source_morph_table->coordinates_x[i]), 4012 from_user)) 4013 goto error; 4014 4015 if (copy_from_compatible(morph_table->coordinates_y[i], 4016 (__force void *)source_morph_table->coordinates_y[i], 4017 source_morph_table->height * source_morph_table->width * 4018 sizeof(*source_morph_table->coordinates_y[i]), 4019 from_user)) 4020 goto error; 4021 } 4022 } 4023 4024 css_param->morph_table = morph_table; 4025 if (old_morph_table) 4026 atomisp_css_morph_table_free(old_morph_table); 4027 css_param->update_flag.morph_table = 4028 (struct atomisp_morph_table *)morph_table; 4029 return 0; 4030 4031 error: 4032 if (morph_table) 4033 atomisp_css_morph_table_free(morph_table); 4034 return ret; 4035 } 4036 4037 int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd, 4038 struct atomisp_parameters *arg, 4039 struct atomisp_css_params *css_param) 4040 { 4041 int ret; 4042 4043 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, false); 4044 if (ret) 4045 return ret; 4046 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, false); 4047 if (ret) 4048 return ret; 4049 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, false); 4050 if (ret) 4051 return ret; 4052 ret = atomisp_css_cp_dvs2_coefs(asd, 4053 (struct ia_css_dvs2_coefficients *)arg->dvs2_coefs, 4054 css_param, false); 4055 if (ret) 4056 return ret; 4057 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config, 4058 css_param, false); 4059 return ret; 4060 } 4061 4062 void atomisp_free_css_parameters(struct atomisp_css_params *css_param) 4063 { 4064 if (css_param->dvs_6axis) { 4065 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 4066 css_param->dvs_6axis = NULL; 4067 } 4068 if (css_param->dvs2_coeff) { 4069 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 4070 css_param->dvs2_coeff = NULL; 4071 } 4072 if (css_param->shading_table) { 4073 ia_css_shading_table_free(css_param->shading_table); 4074 css_param->shading_table = NULL; 4075 } 4076 if (css_param->morph_table) { 4077 ia_css_morph_table_free(css_param->morph_table); 4078 css_param->morph_table = NULL; 4079 } 4080 } 4081 4082 /* 4083 * Check parameter queue list and buffer queue list to find out if matched items 4084 * and then set parameter to CSS and enqueue buffer to CSS. 4085 * Of course, if the buffer in buffer waiting list is not bound to a per-frame 4086 * parameter, it will be enqueued into CSS as long as the per-frame setting 4087 * buffers before it get enqueued. 4088 */ 4089 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe) 4090 { 4091 struct atomisp_sub_device *asd = pipe->asd; 4092 struct videobuf_buffer *vb = NULL, *vb_tmp; 4093 struct atomisp_css_params_with_list *param = NULL, *param_tmp; 4094 struct videobuf_vmalloc_memory *vm_mem = NULL; 4095 unsigned long irqflags; 4096 bool need_to_enqueue_buffer = false; 4097 4098 if (atomisp_is_vf_pipe(pipe)) 4099 return; 4100 4101 /* 4102 * CSS/FW requires set parameter and enqueue buffer happen after ISP 4103 * is streamon. 4104 */ 4105 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 4106 return; 4107 4108 if (list_empty(&pipe->per_frame_params) || 4109 list_empty(&pipe->buffers_waiting_for_param)) 4110 return; 4111 4112 list_for_each_entry_safe(vb, vb_tmp, 4113 &pipe->buffers_waiting_for_param, queue) { 4114 if (pipe->frame_request_config_id[vb->i]) { 4115 list_for_each_entry_safe(param, param_tmp, 4116 &pipe->per_frame_params, list) { 4117 if (pipe->frame_request_config_id[vb->i] != 4118 param->params.isp_config_id) 4119 continue; 4120 4121 list_del(¶m->list); 4122 list_del(&vb->queue); 4123 /* 4124 * clear the request config id as the buffer 4125 * will be handled and enqueued into CSS soon 4126 */ 4127 pipe->frame_request_config_id[vb->i] = 0; 4128 pipe->frame_params[vb->i] = param; 4129 vm_mem = vb->priv; 4130 BUG_ON(!vm_mem); 4131 break; 4132 } 4133 4134 if (vm_mem) { 4135 spin_lock_irqsave(&pipe->irq_lock, irqflags); 4136 list_add_tail(&vb->queue, &pipe->activeq); 4137 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 4138 vm_mem = NULL; 4139 need_to_enqueue_buffer = true; 4140 } else { 4141 /* The is the end, stop further loop */ 4142 break; 4143 } 4144 } else { 4145 list_del(&vb->queue); 4146 pipe->frame_params[vb->i] = NULL; 4147 spin_lock_irqsave(&pipe->irq_lock, irqflags); 4148 list_add_tail(&vb->queue, &pipe->activeq); 4149 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 4150 need_to_enqueue_buffer = true; 4151 } 4152 } 4153 4154 if (!need_to_enqueue_buffer) 4155 return; 4156 4157 atomisp_qbuffers_to_css(asd); 4158 4159 if (!atomisp_hw_is_isp2401) { 4160 if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd)) 4161 atomisp_wdt_start(asd); 4162 } else { 4163 if (atomisp_buffers_queued_pipe(pipe)) { 4164 if (!atomisp_is_wdt_running(pipe)) 4165 atomisp_wdt_start_pipe(pipe); 4166 else 4167 atomisp_wdt_refresh_pipe(pipe, 4168 ATOMISP_WDT_KEEP_CURRENT_DELAY); 4169 } 4170 } 4171 } 4172 4173 /* 4174 * Function to configure ISP parameters 4175 */ 4176 int atomisp_set_parameters(struct video_device *vdev, 4177 struct atomisp_parameters *arg) 4178 { 4179 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 4180 struct atomisp_sub_device *asd = pipe->asd; 4181 struct atomisp_css_params_with_list *param = NULL; 4182 struct atomisp_css_params *css_param = &asd->params.css_param; 4183 int ret; 4184 4185 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 4186 dev_err(asd->isp->dev, "%s: internal error!\n", __func__); 4187 return -EINVAL; 4188 } 4189 4190 dev_dbg(asd->isp->dev, 4191 "%s: set parameter(per_frame_setting %d) for asd%d with isp_config_id %d of %s\n", 4192 __func__, arg->per_frame_setting, asd->index, 4193 arg->isp_config_id, vdev->name); 4194 4195 if (atomisp_hw_is_isp2401) { 4196 if (atomisp_is_vf_pipe(pipe) && arg->per_frame_setting) { 4197 dev_err(asd->isp->dev, "%s: vf pipe not support per_frame_setting", 4198 __func__); 4199 return -EINVAL; 4200 } 4201 } 4202 4203 if (arg->per_frame_setting && !atomisp_is_vf_pipe(pipe)) { 4204 /* 4205 * Per-frame setting enabled, we allocate a new parameter 4206 * buffer to cache the parameters and only when frame buffers 4207 * are ready, the parameters will be set to CSS. 4208 * per-frame setting only works for the main output frame. 4209 */ 4210 param = kvzalloc(sizeof(*param), GFP_KERNEL); 4211 if (!param) { 4212 dev_err(asd->isp->dev, "%s: failed to alloc params buffer\n", 4213 __func__); 4214 return -ENOMEM; 4215 } 4216 css_param = ¶m->params; 4217 } 4218 4219 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, true); 4220 if (ret) 4221 goto apply_parameter_failed; 4222 4223 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, true); 4224 if (ret) 4225 goto apply_parameter_failed; 4226 4227 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, true); 4228 if (ret) 4229 goto apply_parameter_failed; 4230 4231 ret = atomisp_css_cp_dvs2_coefs(asd, 4232 (struct ia_css_dvs2_coefficients *)arg->dvs2_coefs, 4233 css_param, true); 4234 if (ret) 4235 goto apply_parameter_failed; 4236 4237 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config, 4238 css_param, true); 4239 if (ret) 4240 goto apply_parameter_failed; 4241 4242 if (!(arg->per_frame_setting && !atomisp_is_vf_pipe(pipe))) { 4243 /* indicate to CSS that we have parameters to be updated */ 4244 asd->params.css_update_params_needed = true; 4245 } else { 4246 list_add_tail(¶m->list, &pipe->per_frame_params); 4247 atomisp_handle_parameter_and_buffer(pipe); 4248 } 4249 4250 return 0; 4251 4252 apply_parameter_failed: 4253 if (css_param) 4254 atomisp_free_css_parameters(css_param); 4255 if (param) 4256 kvfree(param); 4257 4258 return ret; 4259 } 4260 4261 /* 4262 * Function to set/get isp parameters to isp 4263 */ 4264 int atomisp_param(struct atomisp_sub_device *asd, int flag, 4265 struct atomisp_parm *config) 4266 { 4267 struct atomisp_device *isp = asd->isp; 4268 struct ia_css_pipe_config *vp_cfg = 4269 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 4270 pipe_configs[IA_CSS_PIPE_ID_VIDEO]; 4271 4272 /* Read parameter for 3A binary info */ 4273 if (flag == 0) { 4274 struct atomisp_css_dvs_grid_info *dvs_grid_info = 4275 atomisp_css_get_dvs_grid_info( 4276 &asd->params.curr_grid_info); 4277 4278 if (!&config->info) { 4279 dev_err(isp->dev, "ERROR: NULL pointer in grid_info\n"); 4280 return -EINVAL; 4281 } 4282 atomisp_curr_user_grid_info(asd, &config->info); 4283 4284 /* We always return the resolution and stride even if there is 4285 * no valid metadata. This allows the caller to get the 4286 * information needed to allocate user-space buffers. */ 4287 config->metadata_config.metadata_height = asd-> 4288 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. 4289 metadata_info.resolution.height; 4290 config->metadata_config.metadata_stride = asd-> 4291 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. 4292 metadata_info.stride; 4293 4294 /* update dvs grid info */ 4295 if (dvs_grid_info) 4296 memcpy(&config->dvs_grid, 4297 dvs_grid_info, 4298 sizeof(struct atomisp_css_dvs_grid_info)); 4299 4300 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { 4301 config->dvs_envelop.width = 0; 4302 config->dvs_envelop.height = 0; 4303 return 0; 4304 } 4305 4306 /* update dvs envelop info */ 4307 if (!asd->continuous_mode->val) { 4308 config->dvs_envelop.width = vp_cfg->dvs_envelope.width; 4309 config->dvs_envelop.height = 4310 vp_cfg->dvs_envelope.height; 4311 } else { 4312 unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max; 4313 4314 dvs_w = vp_cfg->bayer_ds_out_res.width - 4315 vp_cfg->output_info[0].res.width; 4316 dvs_h = vp_cfg->bayer_ds_out_res.height - 4317 vp_cfg->output_info[0].res.height; 4318 dvs_w_max = rounddown( 4319 vp_cfg->output_info[0].res.width / 5, 4320 ATOM_ISP_STEP_WIDTH); 4321 dvs_h_max = rounddown( 4322 vp_cfg->output_info[0].res.height / 5, 4323 ATOM_ISP_STEP_HEIGHT); 4324 4325 config->dvs_envelop.width = min(dvs_w, dvs_w_max); 4326 config->dvs_envelop.height = min(dvs_h, dvs_h_max); 4327 } 4328 4329 return 0; 4330 } 4331 4332 memcpy(&asd->params.css_param.wb_config, &config->wb_config, 4333 sizeof(struct atomisp_css_wb_config)); 4334 memcpy(&asd->params.css_param.ob_config, &config->ob_config, 4335 sizeof(struct atomisp_css_ob_config)); 4336 memcpy(&asd->params.css_param.dp_config, &config->dp_config, 4337 sizeof(struct atomisp_css_dp_config)); 4338 memcpy(&asd->params.css_param.de_config, &config->de_config, 4339 sizeof(struct atomisp_css_de_config)); 4340 memcpy(&asd->params.css_param.dz_config, &config->dz_config, 4341 sizeof(struct atomisp_css_dz_config)); 4342 memcpy(&asd->params.css_param.ce_config, &config->ce_config, 4343 sizeof(struct atomisp_css_ce_config)); 4344 memcpy(&asd->params.css_param.nr_config, &config->nr_config, 4345 sizeof(struct atomisp_css_nr_config)); 4346 memcpy(&asd->params.css_param.ee_config, &config->ee_config, 4347 sizeof(struct atomisp_css_ee_config)); 4348 memcpy(&asd->params.css_param.tnr_config, &config->tnr_config, 4349 sizeof(struct atomisp_css_tnr_config)); 4350 4351 if (asd->params.color_effect == V4L2_COLORFX_NEGATIVE) { 4352 asd->params.css_param.cc_config.matrix[3] = -config->cc_config.matrix[3]; 4353 asd->params.css_param.cc_config.matrix[4] = -config->cc_config.matrix[4]; 4354 asd->params.css_param.cc_config.matrix[5] = -config->cc_config.matrix[5]; 4355 asd->params.css_param.cc_config.matrix[6] = -config->cc_config.matrix[6]; 4356 asd->params.css_param.cc_config.matrix[7] = -config->cc_config.matrix[7]; 4357 asd->params.css_param.cc_config.matrix[8] = -config->cc_config.matrix[8]; 4358 } 4359 4360 if (asd->params.color_effect != V4L2_COLORFX_SEPIA && 4361 asd->params.color_effect != V4L2_COLORFX_BW) { 4362 memcpy(&asd->params.css_param.cc_config, &config->cc_config, 4363 sizeof(struct atomisp_css_cc_config)); 4364 atomisp_css_set_cc_config(asd, &asd->params.css_param.cc_config); 4365 } 4366 4367 atomisp_css_set_wb_config(asd, &asd->params.css_param.wb_config); 4368 atomisp_css_set_ob_config(asd, &asd->params.css_param.ob_config); 4369 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config); 4370 atomisp_css_set_dz_config(asd, &asd->params.css_param.dz_config); 4371 atomisp_css_set_ce_config(asd, &asd->params.css_param.ce_config); 4372 atomisp_css_set_dp_config(asd, &asd->params.css_param.dp_config); 4373 atomisp_css_set_nr_config(asd, &asd->params.css_param.nr_config); 4374 atomisp_css_set_ee_config(asd, &asd->params.css_param.ee_config); 4375 atomisp_css_set_tnr_config(asd, &asd->params.css_param.tnr_config); 4376 asd->params.css_update_params_needed = true; 4377 4378 return 0; 4379 } 4380 4381 /* 4382 * Function to configure color effect of the image 4383 */ 4384 int atomisp_color_effect(struct atomisp_sub_device *asd, int flag, 4385 __s32 *effect) 4386 { 4387 struct atomisp_css_cc_config *cc_config = NULL; 4388 struct atomisp_css_macc_table *macc_table = NULL; 4389 struct atomisp_css_ctc_table *ctc_table = NULL; 4390 int ret = 0; 4391 struct v4l2_control control; 4392 struct atomisp_device *isp = asd->isp; 4393 4394 if (flag == 0) { 4395 *effect = asd->params.color_effect; 4396 return 0; 4397 } 4398 4399 control.id = V4L2_CID_COLORFX; 4400 control.value = *effect; 4401 ret = 4402 v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].camera->ctrl_handler, 4403 &control); 4404 /* 4405 * if set color effect to sensor successfully, return 4406 * 0 directly. 4407 */ 4408 if (!ret) { 4409 asd->params.color_effect = (u32)*effect; 4410 return 0; 4411 } 4412 4413 if (*effect == asd->params.color_effect) 4414 return 0; 4415 4416 /* 4417 * isp_subdev->params.macc_en should be set to false. 4418 */ 4419 asd->params.macc_en = false; 4420 4421 switch (*effect) { 4422 case V4L2_COLORFX_NONE: 4423 macc_table = &asd->params.css_param.macc_table; 4424 asd->params.macc_en = true; 4425 break; 4426 case V4L2_COLORFX_SEPIA: 4427 cc_config = &sepia_cc_config; 4428 break; 4429 case V4L2_COLORFX_NEGATIVE: 4430 cc_config = &nega_cc_config; 4431 break; 4432 case V4L2_COLORFX_BW: 4433 cc_config = &mono_cc_config; 4434 break; 4435 case V4L2_COLORFX_SKY_BLUE: 4436 macc_table = &blue_macc_table; 4437 asd->params.macc_en = true; 4438 break; 4439 case V4L2_COLORFX_GRASS_GREEN: 4440 macc_table = &green_macc_table; 4441 asd->params.macc_en = true; 4442 break; 4443 case V4L2_COLORFX_SKIN_WHITEN_LOW: 4444 macc_table = &skin_low_macc_table; 4445 asd->params.macc_en = true; 4446 break; 4447 case V4L2_COLORFX_SKIN_WHITEN: 4448 macc_table = &skin_medium_macc_table; 4449 asd->params.macc_en = true; 4450 break; 4451 case V4L2_COLORFX_SKIN_WHITEN_HIGH: 4452 macc_table = &skin_high_macc_table; 4453 asd->params.macc_en = true; 4454 break; 4455 case V4L2_COLORFX_VIVID: 4456 ctc_table = &vivid_ctc_table; 4457 break; 4458 default: 4459 return -EINVAL; 4460 } 4461 atomisp_update_capture_mode(asd); 4462 4463 if (cc_config) 4464 atomisp_css_set_cc_config(asd, cc_config); 4465 if (macc_table) 4466 atomisp_css_set_macc_table(asd, macc_table); 4467 if (ctc_table) 4468 atomisp_css_set_ctc_table(asd, ctc_table); 4469 asd->params.color_effect = (u32)*effect; 4470 asd->params.css_update_params_needed = true; 4471 return 0; 4472 } 4473 4474 /* 4475 * Function to configure bad pixel correction 4476 */ 4477 int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag, 4478 __s32 *value) 4479 { 4480 if (flag == 0) { 4481 *value = asd->params.bad_pixel_en; 4482 return 0; 4483 } 4484 asd->params.bad_pixel_en = !!*value; 4485 4486 return 0; 4487 } 4488 4489 /* 4490 * Function to configure bad pixel correction params 4491 */ 4492 int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag, 4493 struct atomisp_dp_config *config) 4494 { 4495 if (flag == 0) { 4496 /* Get bad pixel from current setup */ 4497 if (atomisp_css_get_dp_config(asd, config)) 4498 return -EINVAL; 4499 } else { 4500 /* Set bad pixel to isp parameters */ 4501 memcpy(&asd->params.css_param.dp_config, config, 4502 sizeof(asd->params.css_param.dp_config)); 4503 atomisp_css_set_dp_config(asd, &asd->params.css_param.dp_config); 4504 asd->params.css_update_params_needed = true; 4505 } 4506 4507 return 0; 4508 } 4509 4510 /* 4511 * Function to enable/disable video image stablization 4512 */ 4513 int atomisp_video_stable(struct atomisp_sub_device *asd, int flag, 4514 __s32 *value) 4515 { 4516 if (flag == 0) 4517 *value = asd->params.video_dis_en; 4518 else 4519 asd->params.video_dis_en = !!*value; 4520 4521 return 0; 4522 } 4523 4524 /* 4525 * Function to configure fixed pattern noise 4526 */ 4527 int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag, 4528 __s32 *value) 4529 { 4530 if (flag == 0) { 4531 *value = asd->params.fpn_en; 4532 return 0; 4533 } 4534 4535 if (*value == 0) { 4536 asd->params.fpn_en = false; 4537 return 0; 4538 } 4539 4540 /* Add function to get black from from sensor with shutter off */ 4541 return 0; 4542 } 4543 4544 static unsigned int 4545 atomisp_bytesperline_to_padded_width(unsigned int bytesperline, 4546 enum atomisp_css_frame_format format) 4547 { 4548 switch (format) { 4549 case CSS_FRAME_FORMAT_UYVY: 4550 case CSS_FRAME_FORMAT_YUYV: 4551 case CSS_FRAME_FORMAT_RAW: 4552 case CSS_FRAME_FORMAT_RGB565: 4553 return bytesperline / 2; 4554 case CSS_FRAME_FORMAT_RGBA888: 4555 return bytesperline / 4; 4556 /* The following cases could be removed, but we leave them 4557 in to document the formats that are included. */ 4558 case CSS_FRAME_FORMAT_NV11: 4559 case CSS_FRAME_FORMAT_NV12: 4560 case CSS_FRAME_FORMAT_NV16: 4561 case CSS_FRAME_FORMAT_NV21: 4562 case CSS_FRAME_FORMAT_NV61: 4563 case CSS_FRAME_FORMAT_YV12: 4564 case CSS_FRAME_FORMAT_YV16: 4565 case CSS_FRAME_FORMAT_YUV420: 4566 case CSS_FRAME_FORMAT_YUV420_16: 4567 case CSS_FRAME_FORMAT_YUV422: 4568 case CSS_FRAME_FORMAT_YUV422_16: 4569 case CSS_FRAME_FORMAT_YUV444: 4570 case CSS_FRAME_FORMAT_YUV_LINE: 4571 case CSS_FRAME_FORMAT_PLANAR_RGB888: 4572 case CSS_FRAME_FORMAT_QPLANE6: 4573 case CSS_FRAME_FORMAT_BINARY_8: 4574 default: 4575 return bytesperline; 4576 } 4577 } 4578 4579 static int 4580 atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer *arg, 4581 struct atomisp_css_frame **result) 4582 { 4583 struct atomisp_css_frame *res = NULL; 4584 unsigned int padded_width; 4585 enum atomisp_css_frame_format sh_format; 4586 char *tmp_buf = NULL; 4587 int ret = 0; 4588 4589 sh_format = v4l2_fmt_to_sh_fmt(arg->fmt.pixelformat); 4590 padded_width = atomisp_bytesperline_to_padded_width( 4591 arg->fmt.bytesperline, sh_format); 4592 4593 /* Note: the padded width on an atomisp_css_frame is in elements, not in 4594 bytes. The RAW frame we use here should always be a 16bit RAW 4595 frame. This is why we bytesperline/2 is equal to the padded with */ 4596 if (atomisp_css_frame_allocate(&res, arg->fmt.width, arg->fmt.height, 4597 sh_format, padded_width, 0)) { 4598 ret = -ENOMEM; 4599 goto err; 4600 } 4601 4602 tmp_buf = vmalloc(arg->fmt.sizeimage); 4603 if (!tmp_buf) { 4604 ret = -ENOMEM; 4605 goto err; 4606 } 4607 if (copy_from_user(tmp_buf, (void __user __force *)arg->base, 4608 arg->fmt.sizeimage)) { 4609 ret = -EFAULT; 4610 goto err; 4611 } 4612 4613 if (hmm_store(res->data, tmp_buf, arg->fmt.sizeimage)) { 4614 ret = -EINVAL; 4615 goto err; 4616 } 4617 4618 err: 4619 if (ret && res) 4620 atomisp_css_frame_free(res); 4621 if (tmp_buf) 4622 vfree(tmp_buf); 4623 if (ret == 0) 4624 *result = res; 4625 return ret; 4626 } 4627 4628 /* 4629 * Function to configure fixed pattern noise table 4630 */ 4631 int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd, 4632 struct v4l2_framebuffer *arg) 4633 { 4634 struct atomisp_css_frame *raw_black_frame = NULL; 4635 int ret; 4636 4637 if (!arg) 4638 return -EINVAL; 4639 4640 ret = atomisp_v4l2_framebuffer_to_css_frame(arg, &raw_black_frame); 4641 if (ret) 4642 return ret; 4643 if (atomisp_css_set_black_frame(asd, raw_black_frame)) 4644 ret = -ENOMEM; 4645 4646 atomisp_css_frame_free(raw_black_frame); 4647 return ret; 4648 } 4649 4650 /* 4651 * Function to configure false color correction 4652 */ 4653 int atomisp_false_color(struct atomisp_sub_device *asd, int flag, 4654 __s32 *value) 4655 { 4656 /* Get nr config from current setup */ 4657 if (flag == 0) { 4658 *value = asd->params.false_color; 4659 return 0; 4660 } 4661 4662 /* Set nr config to isp parameters */ 4663 if (*value) { 4664 atomisp_css_set_default_de_config(asd); 4665 } else { 4666 asd->params.css_param.de_config.pixelnoise = 0; 4667 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config); 4668 } 4669 asd->params.css_update_params_needed = true; 4670 asd->params.false_color = *value; 4671 return 0; 4672 } 4673 4674 /* 4675 * Function to configure bad pixel correction params 4676 */ 4677 int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag, 4678 struct atomisp_de_config *config) 4679 { 4680 if (flag == 0) { 4681 /* Get false color from current setup */ 4682 if (atomisp_css_get_de_config(asd, config)) 4683 return -EINVAL; 4684 } else { 4685 /* Set false color to isp parameters */ 4686 memcpy(&asd->params.css_param.de_config, config, 4687 sizeof(asd->params.css_param.de_config)); 4688 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config); 4689 asd->params.css_update_params_needed = true; 4690 } 4691 4692 return 0; 4693 } 4694 4695 /* 4696 * Function to configure white balance params 4697 */ 4698 int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag, 4699 struct atomisp_wb_config *config) 4700 { 4701 if (flag == 0) { 4702 /* Get white balance from current setup */ 4703 if (atomisp_css_get_wb_config(asd, config)) 4704 return -EINVAL; 4705 } else { 4706 /* Set white balance to isp parameters */ 4707 memcpy(&asd->params.css_param.wb_config, config, 4708 sizeof(asd->params.css_param.wb_config)); 4709 atomisp_css_set_wb_config(asd, &asd->params.css_param.wb_config); 4710 asd->params.css_update_params_needed = true; 4711 } 4712 4713 return 0; 4714 } 4715 4716 int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag, 4717 struct atomisp_3a_config *config) 4718 { 4719 struct atomisp_device *isp = asd->isp; 4720 4721 dev_dbg(isp->dev, ">%s %d\n", __func__, flag); 4722 4723 if (flag == 0) { 4724 /* Get white balance from current setup */ 4725 if (atomisp_css_get_3a_config(asd, config)) 4726 return -EINVAL; 4727 } else { 4728 /* Set white balance to isp parameters */ 4729 memcpy(&asd->params.css_param.s3a_config, config, 4730 sizeof(asd->params.css_param.s3a_config)); 4731 atomisp_css_set_3a_config(asd, &asd->params.css_param.s3a_config); 4732 asd->params.css_update_params_needed = true; 4733 } 4734 4735 dev_dbg(isp->dev, "<%s %d\n", __func__, flag); 4736 return 0; 4737 } 4738 4739 /* 4740 * Function to setup digital zoom 4741 */ 4742 int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, 4743 __s32 *value) 4744 { 4745 u32 zoom; 4746 struct atomisp_device *isp = asd->isp; 4747 4748 unsigned int max_zoom = MRFLD_MAX_ZOOM_FACTOR; 4749 4750 if (flag == 0) { 4751 atomisp_css_get_zoom_factor(asd, &zoom); 4752 *value = max_zoom - zoom; 4753 } else { 4754 if (*value < 0) 4755 return -EINVAL; 4756 4757 zoom = max_zoom - min_t(u32, max_zoom - 1, *value); 4758 atomisp_css_set_zoom_factor(asd, zoom); 4759 4760 dev_dbg(isp->dev, "%s, zoom: %d\n", __func__, zoom); 4761 asd->params.css_update_params_needed = true; 4762 } 4763 4764 return 0; 4765 } 4766 4767 /* 4768 * Function to get sensor specific info for current resolution, 4769 * which will be used for auto exposure conversion. 4770 */ 4771 int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, 4772 struct atomisp_sensor_mode_data *config) 4773 { 4774 struct camera_mipi_info *mipi_info; 4775 struct atomisp_device *isp = asd->isp; 4776 4777 mipi_info = atomisp_to_sensor_mipi_info( 4778 isp->inputs[asd->input_curr].camera); 4779 if (!mipi_info) 4780 return -EINVAL; 4781 4782 memcpy(config, &mipi_info->data, sizeof(*config)); 4783 return 0; 4784 } 4785 4786 int atomisp_get_fmt(struct video_device *vdev, struct v4l2_format *f) 4787 { 4788 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 4789 4790 f->fmt.pix = pipe->pix; 4791 4792 return 0; 4793 } 4794 4795 static void __atomisp_update_stream_env(struct atomisp_sub_device *asd, 4796 u16 stream_index, struct atomisp_input_stream_info *stream_info) 4797 { 4798 int i; 4799 4800 /* assign virtual channel id return from sensor driver query */ 4801 asd->stream_env[stream_index].ch_id = stream_info->ch_id; 4802 asd->stream_env[stream_index].isys_configs = stream_info->isys_configs; 4803 for (i = 0; i < stream_info->isys_configs; i++) { 4804 asd->stream_env[stream_index].isys_info[i].input_format = 4805 stream_info->isys_info[i].input_format; 4806 asd->stream_env[stream_index].isys_info[i].width = 4807 stream_info->isys_info[i].width; 4808 asd->stream_env[stream_index].isys_info[i].height = 4809 stream_info->isys_info[i].height; 4810 } 4811 } 4812 4813 static void __atomisp_init_stream_info(u16 stream_index, 4814 struct atomisp_input_stream_info *stream_info) 4815 { 4816 int i; 4817 4818 stream_info->enable = 1; 4819 stream_info->stream = stream_index; 4820 stream_info->ch_id = 0; 4821 stream_info->isys_configs = 0; 4822 for (i = 0; i < MAX_STREAMS_PER_CHANNEL; i++) { 4823 stream_info->isys_info[i].input_format = 0; 4824 stream_info->isys_info[i].width = 0; 4825 stream_info->isys_info[i].height = 0; 4826 } 4827 } 4828 4829 /* This function looks up the closest available resolution. */ 4830 int atomisp_try_fmt(struct video_device *vdev, struct v4l2_format *f, 4831 bool *res_overflow) 4832 { 4833 struct atomisp_device *isp = video_get_drvdata(vdev); 4834 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; 4835 struct v4l2_subdev_pad_config pad_cfg; 4836 struct v4l2_subdev_format format = { 4837 .which = V4L2_SUBDEV_FORMAT_TRY, 4838 }; 4839 4840 struct v4l2_mbus_framefmt *snr_mbus_fmt = &format.format; 4841 const struct atomisp_format_bridge *fmt; 4842 struct atomisp_input_stream_info *stream_info = 4843 (struct atomisp_input_stream_info *)snr_mbus_fmt->reserved; 4844 u16 stream_index; 4845 int source_pad = atomisp_subdev_source_pad(vdev); 4846 int ret; 4847 4848 if (!isp->inputs[asd->input_curr].camera) 4849 return -EINVAL; 4850 4851 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); 4852 fmt = atomisp_get_format_bridge(f->fmt.pix.pixelformat); 4853 if (!fmt) { 4854 dev_err(isp->dev, "unsupported pixelformat!\n"); 4855 fmt = atomisp_output_fmts; 4856 } 4857 4858 if (f->fmt.pix.width <= 0 || f->fmt.pix.height <= 0) 4859 return -EINVAL; 4860 4861 snr_mbus_fmt->code = fmt->mbus_code; 4862 snr_mbus_fmt->width = f->fmt.pix.width; 4863 snr_mbus_fmt->height = f->fmt.pix.height; 4864 4865 __atomisp_init_stream_info(stream_index, stream_info); 4866 4867 dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n", 4868 snr_mbus_fmt->width, snr_mbus_fmt->height); 4869 4870 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 4871 pad, set_fmt, &pad_cfg, &format); 4872 if (ret) 4873 return ret; 4874 4875 dev_dbg(isp->dev, "try_mbus_fmt: got %ux%u\n", 4876 snr_mbus_fmt->width, snr_mbus_fmt->height); 4877 4878 fmt = atomisp_get_format_bridge_from_mbus(snr_mbus_fmt->code); 4879 if (!fmt) { 4880 dev_err(isp->dev, "unknown sensor format 0x%8.8x\n", 4881 snr_mbus_fmt->code); 4882 return -EINVAL; 4883 } 4884 4885 f->fmt.pix.pixelformat = fmt->pixelformat; 4886 4887 /* 4888 * If the format is jpeg or custom RAW, then the width and height will 4889 * not satisfy the normal atomisp requirements and no need to check 4890 * the below conditions. So just assign to what is being returned from 4891 * the sensor driver. 4892 */ 4893 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG || 4894 f->fmt.pix.pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) { 4895 f->fmt.pix.width = snr_mbus_fmt->width; 4896 f->fmt.pix.height = snr_mbus_fmt->height; 4897 return 0; 4898 } 4899 4900 if (snr_mbus_fmt->width < f->fmt.pix.width 4901 && snr_mbus_fmt->height < f->fmt.pix.height) { 4902 f->fmt.pix.width = snr_mbus_fmt->width; 4903 f->fmt.pix.height = snr_mbus_fmt->height; 4904 /* Set the flag when resolution requested is 4905 * beyond the max value supported by sensor 4906 */ 4907 if (res_overflow) 4908 *res_overflow = true; 4909 } 4910 4911 /* app vs isp */ 4912 f->fmt.pix.width = rounddown( 4913 clamp_t(u32, f->fmt.pix.width, ATOM_ISP_MIN_WIDTH, 4914 ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH); 4915 f->fmt.pix.height = rounddown( 4916 clamp_t(u32, f->fmt.pix.height, ATOM_ISP_MIN_HEIGHT, 4917 ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT); 4918 4919 return 0; 4920 } 4921 4922 static int 4923 atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f) 4924 { 4925 u32 width = f->fmt.pix.width; 4926 u32 height = f->fmt.pix.height; 4927 u32 pixelformat = f->fmt.pix.pixelformat; 4928 enum v4l2_field field = f->fmt.pix.field; 4929 u32 depth; 4930 4931 if (!atomisp_get_format_bridge(pixelformat)) { 4932 dev_err(isp->dev, "Wrong output pixelformat\n"); 4933 return -EINVAL; 4934 } 4935 4936 depth = get_pixel_depth(pixelformat); 4937 4938 if (field == V4L2_FIELD_ANY) 4939 field = V4L2_FIELD_NONE; 4940 else if (field != V4L2_FIELD_NONE) { 4941 dev_err(isp->dev, "Wrong output field\n"); 4942 return -EINVAL; 4943 } 4944 4945 f->fmt.pix.field = field; 4946 f->fmt.pix.width = clamp_t(u32, 4947 rounddown(width, (u32)ATOM_ISP_STEP_WIDTH), 4948 ATOM_ISP_MIN_WIDTH, ATOM_ISP_MAX_WIDTH); 4949 f->fmt.pix.height = clamp_t(u32, rounddown(height, 4950 (u32)ATOM_ISP_STEP_HEIGHT), 4951 ATOM_ISP_MIN_HEIGHT, ATOM_ISP_MAX_HEIGHT); 4952 f->fmt.pix.bytesperline = (width * depth) >> 3; 4953 4954 return 0; 4955 } 4956 4957 enum mipi_port_id __get_mipi_port(struct atomisp_device *isp, 4958 enum atomisp_camera_port port) 4959 { 4960 switch (port) { 4961 case ATOMISP_CAMERA_PORT_PRIMARY: 4962 return MIPI_PORT0_ID; 4963 case ATOMISP_CAMERA_PORT_SECONDARY: 4964 return MIPI_PORT1_ID; 4965 case ATOMISP_CAMERA_PORT_TERTIARY: 4966 if (MIPI_PORT1_ID + 1 != N_MIPI_PORT_ID) 4967 return MIPI_PORT1_ID + 1; 4968 /* go through down for else case */ 4969 default: 4970 dev_err(isp->dev, "unsupported port: %d\n", port); 4971 return MIPI_PORT0_ID; 4972 } 4973 } 4974 4975 static inline int atomisp_set_sensor_mipi_to_isp( 4976 struct atomisp_sub_device *asd, 4977 enum atomisp_input_stream_id stream_id, 4978 struct camera_mipi_info *mipi_info) 4979 { 4980 struct v4l2_control ctrl; 4981 struct atomisp_device *isp = asd->isp; 4982 const struct atomisp_in_fmt_conv *fc; 4983 int mipi_freq = 0; 4984 unsigned int input_format, bayer_order; 4985 4986 ctrl.id = V4L2_CID_LINK_FREQ; 4987 if (v4l2_g_ctrl 4988 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0) 4989 mipi_freq = ctrl.value; 4990 4991 if (asd->stream_env[stream_id].isys_configs == 1) { 4992 input_format = 4993 asd->stream_env[stream_id].isys_info[0].input_format; 4994 atomisp_css_isys_set_format(asd, stream_id, 4995 input_format, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 4996 } else if (asd->stream_env[stream_id].isys_configs == 2) { 4997 atomisp_css_isys_two_stream_cfg_update_stream1( 4998 asd, stream_id, 4999 asd->stream_env[stream_id].isys_info[0].input_format, 5000 asd->stream_env[stream_id].isys_info[0].width, 5001 asd->stream_env[stream_id].isys_info[0].height); 5002 5003 atomisp_css_isys_two_stream_cfg_update_stream2( 5004 asd, stream_id, 5005 asd->stream_env[stream_id].isys_info[1].input_format, 5006 asd->stream_env[stream_id].isys_info[1].width, 5007 asd->stream_env[stream_id].isys_info[1].height); 5008 } 5009 5010 /* Compatibility for sensors which provide no media bus code 5011 * in s_mbus_framefmt() nor support pad formats. */ 5012 if (mipi_info->input_format != -1) { 5013 bayer_order = mipi_info->raw_bayer_order; 5014 5015 /* Input stream config is still needs configured */ 5016 /* TODO: Check if this is necessary */ 5017 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 5018 mipi_info->input_format); 5019 if (!fc) 5020 return -EINVAL; 5021 input_format = fc->css_stream_fmt; 5022 } else { 5023 struct v4l2_mbus_framefmt *sink; 5024 5025 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 5026 V4L2_SUBDEV_FORMAT_ACTIVE, 5027 ATOMISP_SUBDEV_PAD_SINK); 5028 fc = atomisp_find_in_fmt_conv(sink->code); 5029 if (!fc) 5030 return -EINVAL; 5031 input_format = fc->css_stream_fmt; 5032 bayer_order = fc->bayer_order; 5033 } 5034 5035 atomisp_css_input_set_format(asd, stream_id, input_format); 5036 atomisp_css_input_set_bayer_order(asd, stream_id, bayer_order); 5037 5038 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 5039 mipi_info->metadata_format); 5040 if (!fc) 5041 return -EINVAL; 5042 input_format = fc->css_stream_fmt; 5043 atomisp_css_input_configure_port(asd, 5044 __get_mipi_port(asd->isp, mipi_info->port), 5045 mipi_info->num_lanes, 5046 0xffff4, mipi_freq, 5047 input_format, 5048 mipi_info->metadata_width, 5049 mipi_info->metadata_height); 5050 return 0; 5051 } 5052 5053 static int __enable_continuous_mode(struct atomisp_sub_device *asd, 5054 bool enable) 5055 { 5056 struct atomisp_device *isp = asd->isp; 5057 5058 dev_dbg(isp->dev, 5059 "continuous mode %d, raw buffers %d, stop preview %d\n", 5060 enable, asd->continuous_raw_buffer_size->val, 5061 !asd->continuous_viewfinder->val); 5062 5063 if (!atomisp_hw_is_isp2401) 5064 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_PRIMARY); 5065 else 5066 atomisp_update_capture_mode(asd); 5067 5068 /* in case of ANR, force capture pipe to offline mode */ 5069 atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, 5070 asd->params.low_light ? false : !enable); 5071 atomisp_css_preview_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, 5072 !enable); 5073 atomisp_css_enable_continuous(asd, enable); 5074 atomisp_css_enable_cvf(asd, asd->continuous_viewfinder->val); 5075 5076 if (atomisp_css_continuous_set_num_raw_frames(asd, 5077 asd->continuous_raw_buffer_size->val)) { 5078 dev_err(isp->dev, "css_continuous_set_num_raw_frames failed\n"); 5079 return -EINVAL; 5080 } 5081 5082 if (!enable) { 5083 atomisp_css_enable_raw_binning(asd, false); 5084 atomisp_css_input_set_two_pixels_per_clock(asd, false); 5085 } 5086 5087 if (isp->inputs[asd->input_curr].type != FILE_INPUT) 5088 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_SENSOR); 5089 5090 return atomisp_update_run_mode(asd); 5091 } 5092 5093 static int configure_pp_input_nop(struct atomisp_sub_device *asd, 5094 unsigned int width, unsigned int height) 5095 { 5096 return 0; 5097 } 5098 5099 static int configure_output_nop(struct atomisp_sub_device *asd, 5100 unsigned int width, unsigned int height, 5101 unsigned int min_width, 5102 enum atomisp_css_frame_format sh_fmt) 5103 { 5104 return 0; 5105 } 5106 5107 static int get_frame_info_nop(struct atomisp_sub_device *asd, 5108 struct atomisp_css_frame_info *finfo) 5109 { 5110 return 0; 5111 } 5112 5113 /* 5114 * Resets CSS parameters that depend on input resolution. 5115 * 5116 * Update params like CSS RAW binning, 2ppc mode and pp_input 5117 * which depend on input size, but are not automatically 5118 * handled in CSS when the input resolution is changed. 5119 */ 5120 static int css_input_resolution_changed(struct atomisp_sub_device *asd, 5121 struct v4l2_mbus_framefmt *ffmt) 5122 { 5123 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf; 5124 unsigned int i; 5125 5126 dev_dbg(asd->isp->dev, "css_input_resolution_changed to %ux%u\n", 5127 ffmt->width, ffmt->height); 5128 5129 #if defined(ISP2401_NEW_INPUT_SYSTEM) 5130 atomisp_css_input_set_two_pixels_per_clock(asd, false); 5131 #else 5132 atomisp_css_input_set_two_pixels_per_clock(asd, true); 5133 #endif 5134 if (asd->continuous_mode->val) { 5135 /* Note for all checks: ffmt includes pad_w+pad_h */ 5136 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO || 5137 (ffmt->width >= 2048 || ffmt->height >= 1536)) { 5138 /* 5139 * For preview pipe, enable only if resolution 5140 * is >= 3M for ISP2400. 5141 */ 5142 atomisp_css_enable_raw_binning(asd, true); 5143 } 5144 } 5145 /* 5146 * If sensor input changed, which means metadata resolution changed 5147 * together. Release all metadata buffers here to let it re-allocated 5148 * next time in reqbufs. 5149 */ 5150 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 5151 list_for_each_entry_safe(md_buf, _md_buf, &asd->metadata[i], 5152 list) { 5153 atomisp_css_free_metadata_buffer(md_buf); 5154 list_del(&md_buf->list); 5155 kfree(md_buf); 5156 } 5157 } 5158 return 0; 5159 5160 /* 5161 * TODO: atomisp_css_preview_configure_pp_input() not 5162 * reset due to CSS bug tracked as PSI BZ 115124 5163 */ 5164 } 5165 5166 static int atomisp_set_fmt_to_isp(struct video_device *vdev, 5167 struct atomisp_css_frame_info *output_info, 5168 struct atomisp_css_frame_info *raw_output_info, 5169 struct v4l2_pix_format *pix, 5170 unsigned int source_pad) 5171 { 5172 struct camera_mipi_info *mipi_info; 5173 struct atomisp_device *isp = video_get_drvdata(vdev); 5174 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; 5175 const struct atomisp_format_bridge *format; 5176 struct v4l2_rect *isp_sink_crop; 5177 enum atomisp_css_pipe_id pipe_id; 5178 struct v4l2_subdev_fh fh; 5179 int (*configure_output)(struct atomisp_sub_device *asd, 5180 unsigned int width, unsigned int height, 5181 unsigned int min_width, 5182 enum atomisp_css_frame_format sh_fmt) = 5183 configure_output_nop; 5184 int (*get_frame_info)(struct atomisp_sub_device *asd, 5185 struct atomisp_css_frame_info *finfo) = 5186 get_frame_info_nop; 5187 int (*configure_pp_input)(struct atomisp_sub_device *asd, 5188 unsigned int width, unsigned int height) = 5189 configure_pp_input_nop; 5190 u16 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); 5191 const struct atomisp_in_fmt_conv *fc; 5192 int ret; 5193 5194 v4l2_fh_init(&fh.vfh, vdev); 5195 5196 isp_sink_crop = atomisp_subdev_get_rect( 5197 &asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE, 5198 ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP); 5199 5200 format = atomisp_get_format_bridge(pix->pixelformat); 5201 if (!format) 5202 return -EINVAL; 5203 5204 if (isp->inputs[asd->input_curr].type != TEST_PATTERN && 5205 isp->inputs[asd->input_curr].type != FILE_INPUT) { 5206 mipi_info = atomisp_to_sensor_mipi_info( 5207 isp->inputs[asd->input_curr].camera); 5208 if (!mipi_info) { 5209 dev_err(isp->dev, "mipi_info is NULL\n"); 5210 return -EINVAL; 5211 } 5212 if (atomisp_set_sensor_mipi_to_isp(asd, stream_index, 5213 mipi_info)) 5214 return -EINVAL; 5215 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 5216 mipi_info->input_format); 5217 if (!fc) 5218 fc = atomisp_find_in_fmt_conv( 5219 atomisp_subdev_get_ffmt(&asd->subdev, 5220 NULL, V4L2_SUBDEV_FORMAT_ACTIVE, 5221 ATOMISP_SUBDEV_PAD_SINK)->code); 5222 if (!fc) 5223 return -EINVAL; 5224 if (format->sh_fmt == CSS_FRAME_FORMAT_RAW && 5225 raw_output_format_match_input(fc->css_stream_fmt, 5226 pix->pixelformat)) 5227 return -EINVAL; 5228 } 5229 5230 /* 5231 * Configure viewfinder also when vfpp is disabled: the 5232 * CSS still requires viewfinder configuration. 5233 */ 5234 if (asd->fmt_auto->val || 5235 asd->vfpp->val != ATOMISP_VFPP_ENABLE) { 5236 struct v4l2_rect vf_size = {0}; 5237 struct v4l2_mbus_framefmt vf_ffmt = {0}; 5238 5239 if (pix->width < 640 || pix->height < 480) { 5240 vf_size.width = pix->width; 5241 vf_size.height = pix->height; 5242 } else { 5243 vf_size.width = 640; 5244 vf_size.height = 480; 5245 } 5246 5247 /* FIXME: proper format name for this one. See 5248 atomisp_output_fmts[] in atomisp_v4l2.c */ 5249 vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420; 5250 5251 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5252 V4L2_SUBDEV_FORMAT_ACTIVE, 5253 ATOMISP_SUBDEV_PAD_SOURCE_VF, 5254 V4L2_SEL_TGT_COMPOSE, 0, &vf_size); 5255 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, 5256 V4L2_SUBDEV_FORMAT_ACTIVE, 5257 ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt); 5258 asd->video_out_vf.sh_fmt = CSS_FRAME_FORMAT_NV12; 5259 5260 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 5261 atomisp_css_video_configure_viewfinder(asd, 5262 vf_size.width, vf_size.height, 0, 5263 asd->video_out_vf.sh_fmt); 5264 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 5265 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW || 5266 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) 5267 atomisp_css_video_configure_viewfinder(asd, 5268 vf_size.width, vf_size.height, 0, 5269 asd->video_out_vf.sh_fmt); 5270 else 5271 atomisp_css_capture_configure_viewfinder(asd, 5272 vf_size.width, vf_size.height, 0, 5273 asd->video_out_vf.sh_fmt); 5274 } else if (source_pad != ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW || 5275 asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 5276 atomisp_css_capture_configure_viewfinder(asd, 5277 vf_size.width, vf_size.height, 0, 5278 asd->video_out_vf.sh_fmt); 5279 } 5280 } 5281 5282 if (asd->continuous_mode->val) { 5283 ret = __enable_continuous_mode(asd, true); 5284 if (ret) 5285 return -EINVAL; 5286 } 5287 5288 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_SENSOR); 5289 atomisp_css_disable_vf_pp(asd, 5290 asd->vfpp->val != ATOMISP_VFPP_ENABLE); 5291 5292 /* ISP2401 new input system need to use copy pipe */ 5293 if (asd->copy_mode) { 5294 pipe_id = CSS_PIPE_ID_COPY; 5295 atomisp_css_capture_enable_online(asd, stream_index, false); 5296 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 5297 /* video same in continuouscapture and online modes */ 5298 configure_output = atomisp_css_video_configure_output; 5299 get_frame_info = atomisp_css_video_get_output_frame_info; 5300 pipe_id = CSS_PIPE_ID_VIDEO; 5301 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 5302 if (!asd->continuous_mode->val) { 5303 configure_output = atomisp_css_video_configure_output; 5304 get_frame_info = 5305 atomisp_css_video_get_output_frame_info; 5306 pipe_id = CSS_PIPE_ID_VIDEO; 5307 } else { 5308 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW || 5309 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) { 5310 configure_output = 5311 atomisp_css_video_configure_output; 5312 get_frame_info = 5313 atomisp_css_video_get_output_frame_info; 5314 configure_pp_input = 5315 atomisp_css_video_configure_pp_input; 5316 pipe_id = CSS_PIPE_ID_VIDEO; 5317 } else { 5318 configure_output = 5319 atomisp_css_capture_configure_output; 5320 get_frame_info = 5321 atomisp_css_capture_get_output_frame_info; 5322 configure_pp_input = 5323 atomisp_css_capture_configure_pp_input; 5324 pipe_id = CSS_PIPE_ID_CAPTURE; 5325 5326 atomisp_update_capture_mode(asd); 5327 atomisp_css_capture_enable_online(asd, stream_index, false); 5328 } 5329 } 5330 } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) { 5331 configure_output = atomisp_css_preview_configure_output; 5332 get_frame_info = atomisp_css_preview_get_output_frame_info; 5333 configure_pp_input = atomisp_css_preview_configure_pp_input; 5334 pipe_id = CSS_PIPE_ID_PREVIEW; 5335 } else { 5336 /* CSS doesn't support low light mode on SOC cameras, so disable 5337 * it. FIXME: if this is done elsewhere, it gives corrupted 5338 * colors into thumbnail image. 5339 */ 5340 if (isp->inputs[asd->input_curr].type == SOC_CAMERA) 5341 asd->params.low_light = false; 5342 5343 if (format->sh_fmt == CSS_FRAME_FORMAT_RAW) { 5344 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_RAW); 5345 atomisp_css_enable_dz(asd, false); 5346 } else { 5347 atomisp_update_capture_mode(asd); 5348 } 5349 5350 if (!asd->continuous_mode->val) 5351 /* in case of ANR, force capture pipe to offline mode */ 5352 atomisp_css_capture_enable_online(asd, stream_index, 5353 asd->params.low_light ? 5354 false : asd->params.online_process); 5355 5356 configure_output = atomisp_css_capture_configure_output; 5357 get_frame_info = atomisp_css_capture_get_output_frame_info; 5358 configure_pp_input = atomisp_css_capture_configure_pp_input; 5359 pipe_id = CSS_PIPE_ID_CAPTURE; 5360 5361 if (!asd->params.online_process && 5362 !asd->continuous_mode->val) { 5363 ret = atomisp_css_capture_get_output_raw_frame_info(asd, 5364 raw_output_info); 5365 if (ret) 5366 return ret; 5367 } 5368 if (!asd->continuous_mode->val && asd->run_mode->val 5369 != ATOMISP_RUN_MODE_STILL_CAPTURE) { 5370 dev_err(isp->dev, 5371 "Need to set the running mode first\n"); 5372 asd->run_mode->val = ATOMISP_RUN_MODE_STILL_CAPTURE; 5373 } 5374 } 5375 5376 /* 5377 * to SOC camera, use yuvpp pipe. 5378 */ 5379 if (ATOMISP_USE_YUVPP(asd)) 5380 pipe_id = CSS_PIPE_ID_YUVPP; 5381 5382 if (asd->copy_mode) 5383 ret = atomisp_css_copy_configure_output(asd, stream_index, 5384 pix->width, pix->height, 5385 format->planar ? pix->bytesperline : 5386 pix->bytesperline * 8 / format->depth, 5387 format->sh_fmt); 5388 else 5389 ret = configure_output(asd, pix->width, pix->height, 5390 format->planar ? pix->bytesperline : 5391 pix->bytesperline * 8 / format->depth, 5392 format->sh_fmt); 5393 if (ret) { 5394 dev_err(isp->dev, "configure_output %ux%u, format %8.8x\n", 5395 pix->width, pix->height, format->sh_fmt); 5396 return -EINVAL; 5397 } 5398 5399 if (asd->continuous_mode->val && 5400 (configure_pp_input == atomisp_css_preview_configure_pp_input || 5401 configure_pp_input == atomisp_css_video_configure_pp_input)) { 5402 /* for isp 2.2, configure pp input is available for continuous 5403 * mode */ 5404 ret = configure_pp_input(asd, isp_sink_crop->width, 5405 isp_sink_crop->height); 5406 if (ret) { 5407 dev_err(isp->dev, "configure_pp_input %ux%u\n", 5408 isp_sink_crop->width, 5409 isp_sink_crop->height); 5410 return -EINVAL; 5411 } 5412 } else { 5413 ret = configure_pp_input(asd, isp_sink_crop->width, 5414 isp_sink_crop->height); 5415 if (ret) { 5416 dev_err(isp->dev, "configure_pp_input %ux%u\n", 5417 isp_sink_crop->width, isp_sink_crop->height); 5418 return -EINVAL; 5419 } 5420 } 5421 if (asd->copy_mode) 5422 ret = atomisp_css_copy_get_output_frame_info(asd, stream_index, 5423 output_info); 5424 else 5425 ret = get_frame_info(asd, output_info); 5426 if (ret) { 5427 dev_err(isp->dev, "get_frame_info %ux%u (padded to %u)\n", 5428 pix->width, pix->height, pix->bytesperline); 5429 return -EINVAL; 5430 } 5431 5432 atomisp_update_grid_info(asd, pipe_id, source_pad); 5433 5434 /* Free the raw_dump buffer first */ 5435 atomisp_css_frame_free(asd->raw_output_frame); 5436 asd->raw_output_frame = NULL; 5437 5438 if (!asd->continuous_mode->val && 5439 !asd->params.online_process && !isp->sw_contex.file_input && 5440 atomisp_css_frame_allocate_from_info(&asd->raw_output_frame, 5441 raw_output_info)) 5442 return -ENOMEM; 5443 5444 return 0; 5445 } 5446 5447 static void atomisp_get_dis_envelop(struct atomisp_sub_device *asd, 5448 unsigned int width, unsigned int height, 5449 unsigned int *dvs_env_w, unsigned int *dvs_env_h) 5450 { 5451 struct atomisp_device *isp = asd->isp; 5452 5453 /* if subdev type is SOC camera,we do not need to set DVS */ 5454 if (isp->inputs[asd->input_curr].type == SOC_CAMERA) 5455 asd->params.video_dis_en = false; 5456 5457 if (asd->params.video_dis_en && 5458 asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 5459 /* envelope is 20% of the output resolution */ 5460 /* 5461 * dvs envelope cannot be round up. 5462 * it would cause ISP timeout and color switch issue 5463 */ 5464 *dvs_env_w = rounddown(width / 5, ATOM_ISP_STEP_WIDTH); 5465 *dvs_env_h = rounddown(height / 5, ATOM_ISP_STEP_HEIGHT); 5466 } 5467 5468 asd->params.dis_proj_data_valid = false; 5469 asd->params.css_update_params_needed = true; 5470 } 5471 5472 static void atomisp_check_copy_mode(struct atomisp_sub_device *asd, 5473 int source_pad, struct v4l2_format *f) 5474 { 5475 #if defined(ISP2401_NEW_INPUT_SYSTEM) 5476 struct v4l2_mbus_framefmt *sink, *src; 5477 5478 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 5479 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK); 5480 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 5481 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad); 5482 5483 if ((sink->code == src->code && 5484 sink->width == f->fmt.pix.width && 5485 sink->height == f->fmt.pix.height) || 5486 ((asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) && 5487 (asd->isp->inputs[asd->input_curr].camera_caps-> 5488 sensor[asd->sensor_curr].stream_num > 1))) 5489 asd->copy_mode = true; 5490 else 5491 #endif 5492 /* Only used for the new input system */ 5493 asd->copy_mode = false; 5494 5495 dev_dbg(asd->isp->dev, "copy_mode: %d\n", asd->copy_mode); 5496 } 5497 5498 static int atomisp_set_fmt_to_snr(struct video_device *vdev, 5499 struct v4l2_format *f, unsigned int pixelformat, 5500 unsigned int padding_w, unsigned int padding_h, 5501 unsigned int dvs_env_w, unsigned int dvs_env_h) 5502 { 5503 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; 5504 const struct atomisp_format_bridge *format; 5505 struct v4l2_subdev_pad_config pad_cfg; 5506 struct v4l2_subdev_format vformat = { 5507 .which = V4L2_SUBDEV_FORMAT_TRY, 5508 }; 5509 struct v4l2_mbus_framefmt *ffmt = &vformat.format; 5510 struct v4l2_mbus_framefmt *req_ffmt; 5511 struct atomisp_device *isp = asd->isp; 5512 struct atomisp_input_stream_info *stream_info = 5513 (struct atomisp_input_stream_info *)ffmt->reserved; 5514 u16 stream_index = ATOMISP_INPUT_STREAM_GENERAL; 5515 int source_pad = atomisp_subdev_source_pad(vdev); 5516 struct v4l2_subdev_fh fh; 5517 int ret; 5518 5519 v4l2_fh_init(&fh.vfh, vdev); 5520 5521 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); 5522 5523 format = atomisp_get_format_bridge(pixelformat); 5524 if (!format) 5525 return -EINVAL; 5526 5527 v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format->mbus_code); 5528 ffmt->height += padding_h + dvs_env_h; 5529 ffmt->width += padding_w + dvs_env_w; 5530 5531 dev_dbg(isp->dev, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n", 5532 ffmt->width, ffmt->height, padding_w, padding_h, 5533 dvs_env_w, dvs_env_h); 5534 5535 __atomisp_init_stream_info(stream_index, stream_info); 5536 5537 req_ffmt = ffmt; 5538 5539 /* Disable dvs if resolution can't be supported by sensor */ 5540 if (asd->params.video_dis_en && 5541 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) { 5542 vformat.which = V4L2_SUBDEV_FORMAT_TRY; 5543 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 5544 pad, set_fmt, &pad_cfg, &vformat); 5545 if (ret) 5546 return ret; 5547 if (ffmt->width < req_ffmt->width || 5548 ffmt->height < req_ffmt->height) { 5549 req_ffmt->height -= dvs_env_h; 5550 req_ffmt->width -= dvs_env_w; 5551 ffmt = req_ffmt; 5552 dev_warn(isp->dev, 5553 "can not enable video dis due to sensor limitation."); 5554 asd->params.video_dis_en = false; 5555 } 5556 } 5557 dev_dbg(isp->dev, "sensor width: %d, height: %d\n", 5558 ffmt->width, ffmt->height); 5559 vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; 5560 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad, 5561 set_fmt, NULL, &vformat); 5562 if (ret) 5563 return ret; 5564 5565 __atomisp_update_stream_env(asd, stream_index, stream_info); 5566 5567 dev_dbg(isp->dev, "sensor width: %d, height: %d\n", 5568 ffmt->width, ffmt->height); 5569 5570 if (ffmt->width < ATOM_ISP_STEP_WIDTH || 5571 ffmt->height < ATOM_ISP_STEP_HEIGHT) 5572 return -EINVAL; 5573 5574 if (asd->params.video_dis_en && 5575 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO && 5576 (ffmt->width < req_ffmt->width || ffmt->height < req_ffmt->height)) { 5577 dev_warn(isp->dev, 5578 "can not enable video dis due to sensor limitation."); 5579 asd->params.video_dis_en = false; 5580 } 5581 5582 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, 5583 V4L2_SUBDEV_FORMAT_ACTIVE, 5584 ATOMISP_SUBDEV_PAD_SINK, ffmt); 5585 5586 return css_input_resolution_changed(asd, ffmt); 5587 } 5588 5589 int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) 5590 { 5591 struct atomisp_device *isp = video_get_drvdata(vdev); 5592 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 5593 struct atomisp_sub_device *asd = pipe->asd; 5594 const struct atomisp_format_bridge *format_bridge; 5595 const struct atomisp_format_bridge *snr_format_bridge; 5596 struct atomisp_css_frame_info output_info, raw_output_info; 5597 struct v4l2_format snr_fmt = *f; 5598 struct v4l2_format backup_fmt = *f, s_fmt = *f; 5599 unsigned int dvs_env_w = 0, dvs_env_h = 0; 5600 unsigned int padding_w = pad_w, padding_h = pad_h; 5601 bool res_overflow = false, crop_needs_override = false; 5602 struct v4l2_mbus_framefmt isp_sink_fmt; 5603 struct v4l2_mbus_framefmt isp_source_fmt = {0}; 5604 struct v4l2_rect isp_sink_crop; 5605 u16 source_pad = atomisp_subdev_source_pad(vdev); 5606 struct v4l2_subdev_fh fh; 5607 int ret; 5608 5609 dev_dbg(isp->dev, 5610 "setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n", 5611 f->fmt.pix.width, f->fmt.pix.height, source_pad, 5612 asd->index, f->fmt.pix.bytesperline); 5613 5614 if (source_pad >= ATOMISP_SUBDEV_PADS_NUM) 5615 return -EINVAL; 5616 5617 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { 5618 dev_warn(isp->dev, "ISP does not support set format while at streaming!\n"); 5619 return -EBUSY; 5620 } 5621 5622 v4l2_fh_init(&fh.vfh, vdev); 5623 5624 format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat); 5625 if (!format_bridge) 5626 return -EINVAL; 5627 5628 pipe->sh_fmt = format_bridge->sh_fmt; 5629 pipe->pix.pixelformat = f->fmt.pix.pixelformat; 5630 5631 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VF || 5632 (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW 5633 && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)) { 5634 if (asd->fmt_auto->val) { 5635 struct v4l2_rect *capture_comp; 5636 struct v4l2_rect r = {0}; 5637 5638 r.width = f->fmt.pix.width; 5639 r.height = f->fmt.pix.height; 5640 5641 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) 5642 capture_comp = atomisp_subdev_get_rect( 5643 &asd->subdev, NULL, 5644 V4L2_SUBDEV_FORMAT_ACTIVE, 5645 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO, 5646 V4L2_SEL_TGT_COMPOSE); 5647 else 5648 capture_comp = atomisp_subdev_get_rect( 5649 &asd->subdev, NULL, 5650 V4L2_SUBDEV_FORMAT_ACTIVE, 5651 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE, 5652 V4L2_SEL_TGT_COMPOSE); 5653 5654 if (capture_comp->width < r.width 5655 || capture_comp->height < r.height) { 5656 r.width = capture_comp->width; 5657 r.height = capture_comp->height; 5658 } 5659 5660 atomisp_subdev_set_selection( 5661 &asd->subdev, fh.pad, 5662 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, 5663 V4L2_SEL_TGT_COMPOSE, 0, &r); 5664 5665 f->fmt.pix.width = r.width; 5666 f->fmt.pix.height = r.height; 5667 } 5668 5669 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && 5670 (asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) && 5671 (asd->isp->inputs[asd->input_curr].camera_caps-> 5672 sensor[asd->sensor_curr].stream_num > 1)) { 5673 /* For M10MO outputing YUV preview images. */ 5674 u16 video_index = 5675 atomisp_source_pad_to_stream_id(asd, 5676 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO); 5677 5678 ret = atomisp_css_copy_get_output_frame_info(asd, 5679 video_index, &output_info); 5680 if (ret) { 5681 dev_err(isp->dev, 5682 "copy_get_output_frame_info ret %i", ret); 5683 return -EINVAL; 5684 } 5685 if (!asd->yuvpp_mode) { 5686 /* 5687 * If viewfinder was configured into copy_mode, 5688 * we switch to using yuvpp pipe instead. 5689 */ 5690 asd->yuvpp_mode = true; 5691 ret = atomisp_css_copy_configure_output( 5692 asd, video_index, 0, 0, 0, 0); 5693 if (ret) { 5694 dev_err(isp->dev, 5695 "failed to disable copy pipe"); 5696 return -EINVAL; 5697 } 5698 ret = atomisp_css_yuvpp_configure_output( 5699 asd, video_index, 5700 output_info.res.width, 5701 output_info.res.height, 5702 output_info.padded_width, 5703 output_info.format); 5704 if (ret) { 5705 dev_err(isp->dev, 5706 "failed to set up yuvpp pipe\n"); 5707 return -EINVAL; 5708 } 5709 atomisp_css_video_enable_online(asd, false); 5710 atomisp_css_preview_enable_online(asd, 5711 ATOMISP_INPUT_STREAM_GENERAL, false); 5712 } 5713 atomisp_css_yuvpp_configure_viewfinder(asd, video_index, 5714 f->fmt.pix.width, f->fmt.pix.height, 5715 format_bridge->planar ? f->fmt.pix.bytesperline 5716 : f->fmt.pix.bytesperline * 8 5717 / format_bridge->depth, format_bridge->sh_fmt); 5718 atomisp_css_yuvpp_get_viewfinder_frame_info( 5719 asd, video_index, &output_info); 5720 } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) { 5721 atomisp_css_video_configure_viewfinder(asd, 5722 f->fmt.pix.width, f->fmt.pix.height, 5723 format_bridge->planar ? f->fmt.pix.bytesperline 5724 : f->fmt.pix.bytesperline * 8 5725 / format_bridge->depth, format_bridge->sh_fmt); 5726 atomisp_css_video_get_viewfinder_frame_info(asd, 5727 &output_info); 5728 asd->copy_mode = false; 5729 } else { 5730 atomisp_css_capture_configure_viewfinder(asd, 5731 f->fmt.pix.width, f->fmt.pix.height, 5732 format_bridge->planar ? f->fmt.pix.bytesperline 5733 : f->fmt.pix.bytesperline * 8 5734 / format_bridge->depth, format_bridge->sh_fmt); 5735 atomisp_css_capture_get_viewfinder_frame_info(asd, 5736 &output_info); 5737 asd->copy_mode = false; 5738 } 5739 5740 goto done; 5741 } 5742 /* 5743 * Check whether main resolution configured smaller 5744 * than snapshot resolution. If so, force main resolution 5745 * to be the same as snapshot resolution 5746 */ 5747 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) { 5748 struct v4l2_rect *r; 5749 5750 r = atomisp_subdev_get_rect( 5751 &asd->subdev, NULL, 5752 V4L2_SUBDEV_FORMAT_ACTIVE, 5753 ATOMISP_SUBDEV_PAD_SOURCE_VF, V4L2_SEL_TGT_COMPOSE); 5754 5755 if (r->width && r->height 5756 && (r->width > f->fmt.pix.width 5757 || r->height > f->fmt.pix.height)) 5758 dev_warn(isp->dev, 5759 "Main Resolution config smaller then Vf Resolution. Force to be equal with Vf Resolution."); 5760 } 5761 5762 /* Pipeline configuration done through subdevs. Bail out now. */ 5763 if (!asd->fmt_auto->val) 5764 goto set_fmt_to_isp; 5765 5766 /* get sensor resolution and format */ 5767 ret = atomisp_try_fmt(vdev, &snr_fmt, &res_overflow); 5768 if (ret) 5769 return ret; 5770 f->fmt.pix.width = snr_fmt.fmt.pix.width; 5771 f->fmt.pix.height = snr_fmt.fmt.pix.height; 5772 5773 snr_format_bridge = 5774 atomisp_get_format_bridge(snr_fmt.fmt.pix.pixelformat); 5775 if (!snr_format_bridge) 5776 return -EINVAL; 5777 5778 atomisp_subdev_get_ffmt(&asd->subdev, NULL, 5779 V4L2_SUBDEV_FORMAT_ACTIVE, 5780 ATOMISP_SUBDEV_PAD_SINK)->code = 5781 snr_format_bridge->mbus_code; 5782 5783 isp_sink_fmt = *atomisp_subdev_get_ffmt(&asd->subdev, NULL, 5784 V4L2_SUBDEV_FORMAT_ACTIVE, 5785 ATOMISP_SUBDEV_PAD_SINK); 5786 5787 isp_source_fmt.code = format_bridge->mbus_code; 5788 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, 5789 V4L2_SUBDEV_FORMAT_ACTIVE, 5790 source_pad, &isp_source_fmt); 5791 5792 if (!atomisp_subdev_format_conversion(asd, source_pad)) { 5793 padding_w = 0; 5794 padding_h = 0; 5795 } else if (IS_BYT) { 5796 padding_w = 12; 5797 padding_h = 12; 5798 } 5799 5800 /* construct resolution supported by isp */ 5801 if (res_overflow && !asd->continuous_mode->val) { 5802 f->fmt.pix.width = rounddown( 5803 clamp_t(u32, f->fmt.pix.width - padding_w, 5804 ATOM_ISP_MIN_WIDTH, 5805 ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH); 5806 f->fmt.pix.height = rounddown( 5807 clamp_t(u32, f->fmt.pix.height - padding_h, 5808 ATOM_ISP_MIN_HEIGHT, 5809 ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT); 5810 } 5811 5812 atomisp_get_dis_envelop(asd, f->fmt.pix.width, f->fmt.pix.height, 5813 &dvs_env_w, &dvs_env_h); 5814 5815 if (asd->continuous_mode->val) { 5816 struct v4l2_rect *r; 5817 5818 r = atomisp_subdev_get_rect( 5819 &asd->subdev, NULL, 5820 V4L2_SUBDEV_FORMAT_ACTIVE, 5821 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE, 5822 V4L2_SEL_TGT_COMPOSE); 5823 /* 5824 * The ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE should get resolutions 5825 * properly set otherwise, it should not be the capture_pad. 5826 */ 5827 if (r->width && r->height) 5828 asd->capture_pad = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE; 5829 else 5830 asd->capture_pad = source_pad; 5831 } else { 5832 asd->capture_pad = source_pad; 5833 } 5834 /* 5835 * set format info to sensor 5836 * In continuous mode, resolution is set only if it is higher than 5837 * existing value. This because preview pipe will be configured after 5838 * capture pipe and usually has lower resolution than capture pipe. 5839 */ 5840 if (!asd->continuous_mode->val || 5841 isp_sink_fmt.width < (f->fmt.pix.width + padding_w + dvs_env_w) || 5842 isp_sink_fmt.height < (f->fmt.pix.height + padding_h + 5843 dvs_env_h)) { 5844 /* 5845 * For jpeg or custom raw format the sensor will return constant 5846 * width and height. Because we already had quried try_mbus_fmt, 5847 * f->fmt.pix.width and f->fmt.pix.height has been changed to 5848 * this fixed width and height. So we cannot select the correct 5849 * resolution with that information. So use the original width 5850 * and height while set_mbus_fmt() so actual resolutions are 5851 * being used in while set media bus format. 5852 */ 5853 s_fmt = *f; 5854 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG || 5855 f->fmt.pix.pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) { 5856 s_fmt.fmt.pix.width = backup_fmt.fmt.pix.width; 5857 s_fmt.fmt.pix.height = backup_fmt.fmt.pix.height; 5858 } 5859 ret = atomisp_set_fmt_to_snr(vdev, &s_fmt, 5860 f->fmt.pix.pixelformat, padding_w, 5861 padding_h, dvs_env_w, dvs_env_h); 5862 if (ret) 5863 return -EINVAL; 5864 5865 atomisp_csi_lane_config(isp); 5866 crop_needs_override = true; 5867 } 5868 5869 atomisp_check_copy_mode(asd, source_pad, &backup_fmt); 5870 asd->yuvpp_mode = false; /* Reset variable */ 5871 5872 isp_sink_crop = *atomisp_subdev_get_rect(&asd->subdev, NULL, 5873 V4L2_SUBDEV_FORMAT_ACTIVE, 5874 ATOMISP_SUBDEV_PAD_SINK, 5875 V4L2_SEL_TGT_CROP); 5876 5877 /* Try to enable YUV downscaling if ISP input is 10 % (either 5878 * width or height) bigger than the desired result. */ 5879 if (isp_sink_crop.width * 9 / 10 < f->fmt.pix.width || 5880 isp_sink_crop.height * 9 / 10 < f->fmt.pix.height || 5881 (atomisp_subdev_format_conversion(asd, source_pad) && 5882 ((asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 5883 !asd->continuous_mode->val) || 5884 asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER))) { 5885 /* for continuous mode, preview size might be smaller than 5886 * still capture size. if preview size still needs crop, 5887 * pick the larger one between crop size of preview and 5888 * still capture. 5889 */ 5890 if (asd->continuous_mode->val 5891 && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW 5892 && !crop_needs_override) { 5893 isp_sink_crop.width = 5894 max_t(unsigned int, f->fmt.pix.width, 5895 isp_sink_crop.width); 5896 isp_sink_crop.height = 5897 max_t(unsigned int, f->fmt.pix.height, 5898 isp_sink_crop.height); 5899 } else { 5900 isp_sink_crop.width = f->fmt.pix.width; 5901 isp_sink_crop.height = f->fmt.pix.height; 5902 } 5903 5904 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5905 V4L2_SUBDEV_FORMAT_ACTIVE, 5906 ATOMISP_SUBDEV_PAD_SINK, 5907 V4L2_SEL_TGT_CROP, 5908 V4L2_SEL_FLAG_KEEP_CONFIG, 5909 &isp_sink_crop); 5910 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5911 V4L2_SUBDEV_FORMAT_ACTIVE, 5912 source_pad, V4L2_SEL_TGT_COMPOSE, 5913 0, &isp_sink_crop); 5914 } else if (IS_MOFD) { 5915 struct v4l2_rect main_compose = {0}; 5916 5917 main_compose.width = isp_sink_crop.width; 5918 main_compose.height = 5919 DIV_ROUND_UP(main_compose.width * f->fmt.pix.height, 5920 f->fmt.pix.width); 5921 if (main_compose.height > isp_sink_crop.height) { 5922 main_compose.height = isp_sink_crop.height; 5923 main_compose.width = 5924 DIV_ROUND_UP(main_compose.height * 5925 f->fmt.pix.width, 5926 f->fmt.pix.height); 5927 } 5928 5929 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5930 V4L2_SUBDEV_FORMAT_ACTIVE, 5931 source_pad, 5932 V4L2_SEL_TGT_COMPOSE, 0, 5933 &main_compose); 5934 } else { 5935 struct v4l2_rect sink_crop = {0}; 5936 struct v4l2_rect main_compose = {0}; 5937 5938 main_compose.width = f->fmt.pix.width; 5939 main_compose.height = f->fmt.pix.height; 5940 5941 /* WORKAROUND: this override is universally enabled in 5942 * GMIN to work around a CTS failures (GMINL-539) 5943 * which appears to be related by a hardware 5944 * performance limitation. It's unclear why this 5945 * particular code triggers the issue. */ 5946 if (!atomisp_hw_is_isp2401 || crop_needs_override) { 5947 if (isp_sink_crop.width * main_compose.height > 5948 isp_sink_crop.height * main_compose.width) { 5949 sink_crop.height = isp_sink_crop.height; 5950 sink_crop.width = DIV_NEAREST_STEP( 5951 sink_crop.height * 5952 f->fmt.pix.width, 5953 f->fmt.pix.height, 5954 ATOM_ISP_STEP_WIDTH); 5955 } else { 5956 sink_crop.width = isp_sink_crop.width; 5957 sink_crop.height = DIV_NEAREST_STEP( 5958 sink_crop.width * 5959 f->fmt.pix.height, 5960 f->fmt.pix.width, 5961 ATOM_ISP_STEP_HEIGHT); 5962 } 5963 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5964 V4L2_SUBDEV_FORMAT_ACTIVE, 5965 ATOMISP_SUBDEV_PAD_SINK, 5966 V4L2_SEL_TGT_CROP, 5967 V4L2_SEL_FLAG_KEEP_CONFIG, 5968 &sink_crop); 5969 } 5970 atomisp_subdev_set_selection(&asd->subdev, fh.pad, 5971 V4L2_SUBDEV_FORMAT_ACTIVE, 5972 source_pad, 5973 V4L2_SEL_TGT_COMPOSE, 0, 5974 &main_compose); 5975 } 5976 5977 set_fmt_to_isp: 5978 ret = atomisp_set_fmt_to_isp(vdev, &output_info, &raw_output_info, 5979 &f->fmt.pix, source_pad); 5980 if (ret) 5981 return -EINVAL; 5982 done: 5983 pipe->pix.width = f->fmt.pix.width; 5984 pipe->pix.height = f->fmt.pix.height; 5985 pipe->pix.pixelformat = f->fmt.pix.pixelformat; 5986 if (format_bridge->planar) { 5987 pipe->pix.bytesperline = output_info.padded_width; 5988 pipe->pix.sizeimage = PAGE_ALIGN(f->fmt.pix.height * 5989 DIV_ROUND_UP(format_bridge->depth * 5990 output_info.padded_width, 8)); 5991 } else { 5992 pipe->pix.bytesperline = 5993 DIV_ROUND_UP(format_bridge->depth * 5994 output_info.padded_width, 8); 5995 pipe->pix.sizeimage = 5996 PAGE_ALIGN(f->fmt.pix.height * pipe->pix.bytesperline); 5997 } 5998 if (f->fmt.pix.field == V4L2_FIELD_ANY) 5999 f->fmt.pix.field = V4L2_FIELD_NONE; 6000 pipe->pix.field = f->fmt.pix.field; 6001 6002 f->fmt.pix = pipe->pix; 6003 f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width * 6004 pipe->pix.height * 2); 6005 6006 pipe->capq.field = f->fmt.pix.field; 6007 6008 /* 6009 * If in video 480P case, no GFX throttle 6010 */ 6011 if (asd->run_mode->val == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO && 6012 f->fmt.pix.width == 720 && f->fmt.pix.height == 480) 6013 isp->need_gfx_throttle = false; 6014 else 6015 isp->need_gfx_throttle = true; 6016 6017 return 0; 6018 } 6019 6020 int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f) 6021 { 6022 struct atomisp_device *isp = video_get_drvdata(vdev); 6023 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 6024 struct atomisp_sub_device *asd = pipe->asd; 6025 struct v4l2_mbus_framefmt ffmt = {0}; 6026 const struct atomisp_format_bridge *format_bridge; 6027 struct v4l2_subdev_fh fh; 6028 int ret; 6029 6030 v4l2_fh_init(&fh.vfh, vdev); 6031 6032 dev_dbg(isp->dev, "setting fmt %ux%u 0x%x for file inject\n", 6033 f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); 6034 ret = atomisp_try_fmt_file(isp, f); 6035 if (ret) { 6036 dev_err(isp->dev, "atomisp_try_fmt_file err: %d\n", ret); 6037 return ret; 6038 } 6039 6040 format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat); 6041 if (!format_bridge) { 6042 dev_dbg(isp->dev, "atomisp_get_format_bridge err! fmt:0x%x\n", 6043 f->fmt.pix.pixelformat); 6044 return -EINVAL; 6045 } 6046 6047 pipe->pix = f->fmt.pix; 6048 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_FIFO); 6049 atomisp_css_input_configure_port(asd, 6050 __get_mipi_port(isp, ATOMISP_CAMERA_PORT_PRIMARY), 2, 0xffff4, 6051 0, 0, 0, 0); 6052 ffmt.width = f->fmt.pix.width; 6053 ffmt.height = f->fmt.pix.height; 6054 ffmt.code = format_bridge->mbus_code; 6055 6056 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, V4L2_SUBDEV_FORMAT_ACTIVE, 6057 ATOMISP_SUBDEV_PAD_SINK, &ffmt); 6058 6059 return 0; 6060 } 6061 6062 int atomisp_set_shading_table(struct atomisp_sub_device *asd, 6063 struct atomisp_shading_table *user_shading_table) 6064 { 6065 struct atomisp_css_shading_table *shading_table; 6066 struct atomisp_css_shading_table *free_table; 6067 unsigned int len_table; 6068 int i; 6069 int ret = 0; 6070 6071 if (!user_shading_table) 6072 return -EINVAL; 6073 6074 if (!user_shading_table->enable) { 6075 atomisp_css_set_shading_table(asd, NULL); 6076 asd->params.sc_en = false; 6077 return 0; 6078 } 6079 6080 /* If enabling, all tables must be set */ 6081 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 6082 if (!user_shading_table->data[i]) 6083 return -EINVAL; 6084 } 6085 6086 /* Shading table size per color */ 6087 if (!atomisp_hw_is_isp2401) { 6088 if (user_shading_table->width > ISP2400_SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 6089 user_shading_table->height > ISP2400_SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) 6090 return -EINVAL; 6091 } else { 6092 if (user_shading_table->width > ISP2401_SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 6093 user_shading_table->height > ISP2401_SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) 6094 return -EINVAL; 6095 } 6096 6097 shading_table = atomisp_css_shading_table_alloc( 6098 user_shading_table->width, user_shading_table->height); 6099 if (!shading_table) 6100 return -ENOMEM; 6101 6102 len_table = user_shading_table->width * user_shading_table->height * 6103 ATOMISP_SC_TYPE_SIZE; 6104 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 6105 ret = copy_from_user(shading_table->data[i], 6106 (void __user *)user_shading_table->data[i], 6107 len_table); 6108 if (ret) { 6109 free_table = shading_table; 6110 ret = -EFAULT; 6111 goto out; 6112 } 6113 } 6114 shading_table->sensor_width = user_shading_table->sensor_width; 6115 shading_table->sensor_height = user_shading_table->sensor_height; 6116 shading_table->fraction_bits = user_shading_table->fraction_bits; 6117 6118 free_table = asd->params.css_param.shading_table; 6119 asd->params.css_param.shading_table = shading_table; 6120 atomisp_css_set_shading_table(asd, shading_table); 6121 asd->params.sc_en = true; 6122 6123 out: 6124 if (free_table) 6125 atomisp_css_shading_table_free(free_table); 6126 6127 return ret; 6128 } 6129 6130 /*Turn off ISP dphy */ 6131 int atomisp_ospm_dphy_down(struct atomisp_device *isp) 6132 { 6133 unsigned long flags; 6134 u32 reg; 6135 6136 dev_dbg(isp->dev, "%s\n", __func__); 6137 6138 /* if ISP timeout, we can force powerdown */ 6139 if (isp->isp_timeout) 6140 goto done; 6141 6142 if (!atomisp_dev_users(isp)) 6143 goto done; 6144 6145 spin_lock_irqsave(&isp->lock, flags); 6146 isp->sw_contex.power_state = ATOM_ISP_POWER_DOWN; 6147 spin_unlock_irqrestore(&isp->lock, flags); 6148 done: 6149 /* 6150 * MRFLD IUNIT DPHY is located in an always-power-on island 6151 * MRFLD HW design need all CSI ports are disabled before 6152 * powering down the IUNIT. 6153 */ 6154 pci_read_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, ®); 6155 reg |= MRFLD_ALL_CSI_PORTS_OFF_MASK; 6156 pci_write_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, reg); 6157 return 0; 6158 } 6159 6160 /*Turn on ISP dphy */ 6161 int atomisp_ospm_dphy_up(struct atomisp_device *isp) 6162 { 6163 unsigned long flags; 6164 6165 dev_dbg(isp->dev, "%s\n", __func__); 6166 6167 spin_lock_irqsave(&isp->lock, flags); 6168 isp->sw_contex.power_state = ATOM_ISP_POWER_UP; 6169 spin_unlock_irqrestore(&isp->lock, flags); 6170 6171 return 0; 6172 } 6173 6174 int atomisp_exif_makernote(struct atomisp_sub_device *asd, 6175 struct atomisp_makernote_info *config) 6176 { 6177 struct v4l2_control ctrl; 6178 struct atomisp_device *isp = asd->isp; 6179 6180 ctrl.id = V4L2_CID_FOCAL_ABSOLUTE; 6181 if (v4l2_g_ctrl 6182 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { 6183 dev_warn(isp->dev, "failed to g_ctrl for focal length\n"); 6184 return -EINVAL; 6185 } else { 6186 config->focal_length = ctrl.value; 6187 } 6188 6189 ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE; 6190 if (v4l2_g_ctrl 6191 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { 6192 dev_warn(isp->dev, "failed to g_ctrl for f-number\n"); 6193 return -EINVAL; 6194 } else { 6195 config->f_number_curr = ctrl.value; 6196 } 6197 6198 ctrl.id = V4L2_CID_FNUMBER_RANGE; 6199 if (v4l2_g_ctrl 6200 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { 6201 dev_warn(isp->dev, "failed to g_ctrl for f number range\n"); 6202 return -EINVAL; 6203 } else { 6204 config->f_number_range = ctrl.value; 6205 } 6206 6207 return 0; 6208 } 6209 6210 int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, 6211 struct atomisp_cont_capture_conf *cvf_config) 6212 { 6213 struct v4l2_ctrl *c; 6214 6215 /* 6216 * In case of M10MO ZSL capture case, we need to issue a separate 6217 * capture request to M10MO which will output captured jpeg image 6218 */ 6219 c = v4l2_ctrl_find( 6220 asd->isp->inputs[asd->input_curr].camera->ctrl_handler, 6221 V4L2_CID_START_ZSL_CAPTURE); 6222 if (c) { 6223 int ret; 6224 6225 dev_dbg(asd->isp->dev, "%s trigger ZSL capture request\n", 6226 __func__); 6227 /* TODO: use the cvf_config */ 6228 ret = v4l2_ctrl_s_ctrl(c, 1); 6229 if (ret) 6230 return ret; 6231 6232 return v4l2_ctrl_s_ctrl(c, 0); 6233 } 6234 6235 asd->params.offline_parm = *cvf_config; 6236 6237 if (asd->params.offline_parm.num_captures) { 6238 if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED) { 6239 unsigned int init_raw_num; 6240 6241 if (asd->enable_raw_buffer_lock->val) { 6242 init_raw_num = 6243 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN; 6244 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 6245 asd->params.video_dis_en) 6246 init_raw_num += 6247 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY; 6248 } else { 6249 init_raw_num = 6250 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES; 6251 } 6252 6253 /* TODO: this can be removed once user-space 6254 * has been updated to use control API */ 6255 asd->continuous_raw_buffer_size->val = 6256 max_t(int, 6257 asd->continuous_raw_buffer_size->val, 6258 asd->params.offline_parm. 6259 num_captures + init_raw_num); 6260 asd->continuous_raw_buffer_size->val = 6261 min_t(int, ATOMISP_CONT_RAW_FRAMES, 6262 asd->continuous_raw_buffer_size->val); 6263 } 6264 asd->continuous_mode->val = true; 6265 } else { 6266 asd->continuous_mode->val = false; 6267 __enable_continuous_mode(asd, false); 6268 } 6269 6270 return 0; 6271 } 6272 6273 /* 6274 * set auto exposure metering window to camera sensor 6275 */ 6276 int atomisp_s_ae_window(struct atomisp_sub_device *asd, 6277 struct atomisp_ae_window *arg) 6278 { 6279 struct atomisp_device *isp = asd->isp; 6280 /* Coverity CID 298071 - initialzize struct */ 6281 struct v4l2_subdev_selection sel = { 0 }; 6282 6283 sel.r.left = arg->x_left; 6284 sel.r.top = arg->y_top; 6285 sel.r.width = arg->x_right - arg->x_left + 1; 6286 sel.r.height = arg->y_bottom - arg->y_top + 1; 6287 6288 if (v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 6289 pad, set_selection, NULL, &sel)) { 6290 dev_err(isp->dev, "failed to call sensor set_selection.\n"); 6291 return -EINVAL; 6292 } 6293 6294 return 0; 6295 } 6296 6297 int atomisp_flash_enable(struct atomisp_sub_device *asd, int num_frames) 6298 { 6299 struct atomisp_device *isp = asd->isp; 6300 6301 if (num_frames < 0) { 6302 dev_dbg(isp->dev, "%s ERROR: num_frames: %d\n", __func__, 6303 num_frames); 6304 return -EINVAL; 6305 } 6306 /* a requested flash is still in progress. */ 6307 if (num_frames && asd->params.flash_state != ATOMISP_FLASH_IDLE) { 6308 dev_dbg(isp->dev, "%s flash busy: %d frames left: %d\n", 6309 __func__, asd->params.flash_state, 6310 asd->params.num_flash_frames); 6311 return -EBUSY; 6312 } 6313 6314 asd->params.num_flash_frames = num_frames; 6315 asd->params.flash_state = ATOMISP_FLASH_REQUESTED; 6316 return 0; 6317 } 6318 6319 int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd, 6320 uint16_t source_pad) 6321 { 6322 int stream_id; 6323 struct atomisp_device *isp = asd->isp; 6324 6325 if (isp->inputs[asd->input_curr].camera_caps-> 6326 sensor[asd->sensor_curr].stream_num == 1) 6327 return ATOMISP_INPUT_STREAM_GENERAL; 6328 6329 switch (source_pad) { 6330 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: 6331 stream_id = ATOMISP_INPUT_STREAM_CAPTURE; 6332 break; 6333 case ATOMISP_SUBDEV_PAD_SOURCE_VF: 6334 stream_id = ATOMISP_INPUT_STREAM_POSTVIEW; 6335 break; 6336 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: 6337 stream_id = ATOMISP_INPUT_STREAM_PREVIEW; 6338 break; 6339 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: 6340 stream_id = ATOMISP_INPUT_STREAM_VIDEO; 6341 break; 6342 default: 6343 stream_id = ATOMISP_INPUT_STREAM_GENERAL; 6344 } 6345 6346 return stream_id; 6347 } 6348 6349 bool atomisp_is_vf_pipe(struct atomisp_video_pipe *pipe) 6350 { 6351 struct atomisp_sub_device *asd = pipe->asd; 6352 6353 if (pipe == &asd->video_out_vf) 6354 return true; 6355 6356 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 6357 pipe == &asd->video_out_preview) 6358 return true; 6359 6360 return false; 6361 } 6362 6363 static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id) 6364 { 6365 struct atomisp_device *isp = asd->isp; 6366 6367 if (!asd->enable_raw_buffer_lock->val) { 6368 dev_warn(isp->dev, "%s Raw Buffer Lock is disable.\n", __func__); 6369 return -EINVAL; 6370 } 6371 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) { 6372 dev_err(isp->dev, "%s streaming %d invalid exp_id %d.\n", 6373 __func__, exp_id, asd->streaming); 6374 return -EINVAL; 6375 } 6376 if ((exp_id > ATOMISP_MAX_EXP_ID) || (exp_id <= 0)) { 6377 dev_err(isp->dev, "%s exp_id %d invalid.\n", __func__, exp_id); 6378 return -EINVAL; 6379 } 6380 return 0; 6381 } 6382 6383 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd) 6384 { 6385 unsigned long flags; 6386 6387 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 6388 memset(asd->raw_buffer_bitmap, 0, sizeof(asd->raw_buffer_bitmap)); 6389 asd->raw_buffer_locked_count = 0; 6390 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 6391 } 6392 6393 int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) 6394 { 6395 int *bitmap, bit; 6396 unsigned long flags; 6397 6398 if (__checking_exp_id(asd, exp_id)) 6399 return -EINVAL; 6400 6401 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 6402 bit = exp_id % 32; 6403 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 6404 (*bitmap) |= (1 << bit); 6405 asd->raw_buffer_locked_count++; 6406 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 6407 6408 dev_dbg(asd->isp->dev, "%s: exp_id %d, raw_buffer_locked_count %d\n", 6409 __func__, exp_id, asd->raw_buffer_locked_count); 6410 6411 /* Check if the raw buffer after next is still locked!!! */ 6412 exp_id += 2; 6413 if (exp_id > ATOMISP_MAX_EXP_ID) 6414 exp_id -= ATOMISP_MAX_EXP_ID; 6415 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 6416 bit = exp_id % 32; 6417 if ((*bitmap) & (1 << bit)) { 6418 int ret; 6419 6420 /* WORKAROUND unlock the raw buffer compulsively */ 6421 ret = atomisp_css_exp_id_unlock(asd, exp_id); 6422 if (ret) { 6423 dev_err(asd->isp->dev, 6424 "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n", 6425 __func__, exp_id, ret); 6426 return ret; 6427 } 6428 6429 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 6430 (*bitmap) &= ~(1 << bit); 6431 asd->raw_buffer_locked_count--; 6432 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 6433 dev_warn(asd->isp->dev, 6434 "%s exp_id is wrapping back to %d but it is still locked so force unlock it, raw_buffer_locked_count %d\n", 6435 __func__, exp_id, asd->raw_buffer_locked_count); 6436 } 6437 return 0; 6438 } 6439 6440 static int __is_raw_buffer_locked(struct atomisp_sub_device *asd, int exp_id) 6441 { 6442 int *bitmap, bit; 6443 unsigned long flags; 6444 int ret; 6445 6446 if (__checking_exp_id(asd, exp_id)) 6447 return -EINVAL; 6448 6449 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 6450 bit = exp_id % 32; 6451 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 6452 ret = ((*bitmap) & (1 << bit)); 6453 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 6454 return !ret; 6455 } 6456 6457 static int __clear_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) 6458 { 6459 int *bitmap, bit; 6460 unsigned long flags; 6461 6462 if (__is_raw_buffer_locked(asd, exp_id)) 6463 return -EINVAL; 6464 6465 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 6466 bit = exp_id % 32; 6467 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 6468 (*bitmap) &= ~(1 << bit); 6469 asd->raw_buffer_locked_count--; 6470 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 6471 6472 dev_dbg(asd->isp->dev, "%s: exp_id %d, raw_buffer_locked_count %d\n", 6473 __func__, exp_id, asd->raw_buffer_locked_count); 6474 return 0; 6475 } 6476 6477 int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id) 6478 { 6479 struct atomisp_device *isp = asd->isp; 6480 int value = *exp_id; 6481 int ret; 6482 6483 ret = __is_raw_buffer_locked(asd, value); 6484 if (ret) { 6485 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); 6486 return -EINVAL; 6487 } 6488 6489 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value); 6490 ret = atomisp_css_exp_id_capture(asd, value); 6491 if (ret) { 6492 dev_err(isp->dev, "%s exp_id %d failed.\n", __func__, value); 6493 return -EIO; 6494 } 6495 return 0; 6496 } 6497 6498 int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id) 6499 { 6500 struct atomisp_device *isp = asd->isp; 6501 int value = *exp_id; 6502 int ret; 6503 6504 ret = __clear_raw_buffer_bitmap(asd, value); 6505 if (ret) { 6506 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); 6507 return -EINVAL; 6508 } 6509 6510 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value); 6511 ret = atomisp_css_exp_id_unlock(asd, value); 6512 if (ret) 6513 dev_err(isp->dev, "%s exp_id %d failed, err %d.\n", 6514 __func__, value, ret); 6515 6516 return ret; 6517 } 6518 6519 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd, 6520 unsigned int *enable) 6521 { 6522 bool value; 6523 6524 if (!enable) 6525 return -EINVAL; 6526 6527 value = *enable > 0 ? true : false; 6528 6529 atomisp_en_dz_capt_pipe(asd, value); 6530 6531 return 0; 6532 } 6533 6534 int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event) 6535 { 6536 if (!event || asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) 6537 return -EINVAL; 6538 6539 dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n", 6540 __func__, *event); 6541 6542 switch (*event) { 6543 case V4L2_EVENT_FRAME_SYNC: 6544 atomisp_sof_event(asd); 6545 break; 6546 case V4L2_EVENT_FRAME_END: 6547 atomisp_eof_event(asd, 0); 6548 break; 6549 case V4L2_EVENT_ATOMISP_3A_STATS_READY: 6550 atomisp_3a_stats_ready_event(asd, 0); 6551 break; 6552 case V4L2_EVENT_ATOMISP_METADATA_READY: 6553 atomisp_metadata_ready_event(asd, 0); 6554 break; 6555 default: 6556 return -EINVAL; 6557 } 6558 6559 return 0; 6560 } 6561 6562 static int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe) 6563 { 6564 struct atomisp_sub_device *asd = pipe->asd; 6565 6566 if (ATOMISP_USE_YUVPP(asd)) 6567 return CSS_PIPE_ID_YUVPP; 6568 else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) 6569 return CSS_PIPE_ID_VIDEO; 6570 else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) 6571 return CSS_PIPE_ID_CAPTURE; 6572 else if (pipe == &asd->video_out_video_capture) 6573 return CSS_PIPE_ID_VIDEO; 6574 else if (pipe == &asd->video_out_vf) 6575 return CSS_PIPE_ID_CAPTURE; 6576 else if (pipe == &asd->video_out_preview) { 6577 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) 6578 return CSS_PIPE_ID_VIDEO; 6579 else 6580 return CSS_PIPE_ID_PREVIEW; 6581 } else if (pipe == &asd->video_out_capture) { 6582 if (asd->copy_mode) 6583 return IA_CSS_PIPE_ID_COPY; 6584 else 6585 return CSS_PIPE_ID_CAPTURE; 6586 } 6587 6588 /* fail through */ 6589 dev_warn(asd->isp->dev, "%s failed to find proper pipe\n", 6590 __func__); 6591 return CSS_PIPE_ID_CAPTURE; 6592 } 6593 6594 int atomisp_get_invalid_frame_num(struct video_device *vdev, 6595 int *invalid_frame_num) 6596 { 6597 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 6598 struct atomisp_sub_device *asd = pipe->asd; 6599 enum atomisp_css_pipe_id pipe_id; 6600 struct ia_css_pipe_info p_info; 6601 int ret; 6602 6603 if (asd->isp->inputs[asd->input_curr].camera_caps-> 6604 sensor[asd->sensor_curr].stream_num > 1) { 6605 /* External ISP */ 6606 *invalid_frame_num = 0; 6607 return 0; 6608 } 6609 6610 pipe_id = atomisp_get_pipe_id(pipe); 6611 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id]) { 6612 dev_warn(asd->isp->dev, 6613 "%s pipe %d has not been created yet, do SET_FMT first!\n", 6614 __func__, pipe_id); 6615 return -EINVAL; 6616 } 6617 6618 ret = ia_css_pipe_get_info( 6619 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 6620 .pipes[pipe_id], &p_info); 6621 if (ret == IA_CSS_SUCCESS) { 6622 *invalid_frame_num = p_info.num_invalid_frames; 6623 return 0; 6624 } else { 6625 dev_warn(asd->isp->dev, "%s get pipe infor failed %d\n", 6626 __func__, ret); 6627 return -EINVAL; 6628 } 6629 } 6630