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