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 #include <linux/errno.h> 10 #include <linux/firmware.h> 11 #include <linux/pci.h> 12 #include <linux/interrupt.h> 13 #include <linux/io.h> 14 #include <linux/kernel.h> 15 #include <linux/kfifo.h> 16 #include <linux/pm_runtime.h> 17 #include <linux/timer.h> 18 19 #include <asm/iosf_mbi.h> 20 21 #include <media/v4l2-event.h> 22 23 #define CREATE_TRACE_POINTS 24 #include "atomisp_trace_event.h" 25 26 #include "atomisp_cmd.h" 27 #include "atomisp_common.h" 28 #include "atomisp_fops.h" 29 #include "atomisp_internal.h" 30 #include "atomisp_ioctl.h" 31 #include "atomisp-regs.h" 32 #include "atomisp_tables.h" 33 #include "atomisp_compat.h" 34 #include "atomisp_subdev.h" 35 #include "atomisp_dfs_tables.h" 36 37 #include <hmm/hmm.h> 38 39 #include "sh_css_hrt.h" 40 #include "sh_css_defs.h" 41 #include "system_global.h" 42 #include "sh_css_internal.h" 43 #include "sh_css_sp.h" 44 #include "gp_device.h" 45 #include "device_access.h" 46 #include "irq.h" 47 48 #include "ia_css_types.h" 49 #include "ia_css_stream.h" 50 #include "ia_css_debug.h" 51 #include "bits.h" 52 53 union host { 54 struct { 55 void *kernel_ptr; 56 void __user *user_ptr; 57 int size; 58 } scalar; 59 struct { 60 void *hmm_ptr; 61 } ptr; 62 }; 63 64 /* 65 * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. 66 * subdev->priv is set in mrst.c 67 */ 68 struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd) 69 { 70 return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd); 71 } 72 73 /* 74 * get struct atomisp_video_pipe from v4l2 video_device 75 */ 76 struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev) 77 { 78 return (struct atomisp_video_pipe *) 79 container_of(dev, struct atomisp_video_pipe, vdev); 80 } 81 82 static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd) 83 { 84 struct v4l2_subdev_frame_interval fi = { 0 }; 85 struct atomisp_device *isp = asd->isp; 86 87 unsigned short fps = 0; 88 int ret; 89 90 ret = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].sensor, 91 pad, get_frame_interval, &fi); 92 93 if (!ret && fi.interval.numerator) 94 fps = fi.interval.denominator / fi.interval.numerator; 95 96 return fps; 97 } 98 99 /* 100 * DFS progress is shown as follows: 101 * 1. Target frequency is calculated according to FPS/Resolution/ISP running 102 * mode. 103 * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1 104 * with proper rounding. 105 * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40 106 * to 200MHz in ISPSSPM1. 107 * 4. Wait for FREQVALID to be cleared by P-Unit. 108 * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3. 109 */ 110 static int write_target_freq_to_hw(struct atomisp_device *isp, 111 unsigned int new_freq) 112 { 113 unsigned int ratio, timeout, guar_ratio; 114 u32 isp_sspm1 = 0; 115 int i; 116 117 if (!isp->hpll_freq) { 118 dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n"); 119 return -EINVAL; 120 } 121 122 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 123 if (isp_sspm1 & ISP_FREQ_VALID_MASK) { 124 dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n"); 125 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, 126 isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET)); 127 } 128 129 ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1; 130 guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1; 131 132 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 133 isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET); 134 135 for (i = 0; i < ISP_DFS_TRY_TIMES; i++) { 136 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, 137 isp_sspm1 138 | ratio << ISP_REQ_FREQ_OFFSET 139 | 1 << ISP_FREQ_VALID_OFFSET 140 | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET); 141 142 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 143 timeout = 20; 144 while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) { 145 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 146 dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n"); 147 udelay(100); 148 timeout--; 149 } 150 151 if (timeout != 0) 152 break; 153 } 154 155 if (timeout == 0) { 156 dev_err(isp->dev, "DFS failed due to HW error.\n"); 157 return -EINVAL; 158 } 159 160 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 161 timeout = 10; 162 while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) { 163 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); 164 dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n", 165 new_freq); 166 udelay(100); 167 timeout--; 168 } 169 if (timeout == 0) { 170 dev_err(isp->dev, "DFS target freq is rejected by HW.\n"); 171 return -EINVAL; 172 } 173 174 return 0; 175 } 176 177 int atomisp_freq_scaling(struct atomisp_device *isp, 178 enum atomisp_dfs_mode mode, 179 bool force) 180 { 181 const struct atomisp_dfs_config *dfs; 182 unsigned int new_freq; 183 struct atomisp_freq_scaling_rule curr_rules; 184 int i, ret; 185 unsigned short fps = 0; 186 187 dfs = isp->dfs; 188 189 if (dfs->lowest_freq == 0 || dfs->max_freq_at_vmin == 0 || 190 dfs->highest_freq == 0 || dfs->dfs_table_size == 0 || 191 !dfs->dfs_table) { 192 dev_err(isp->dev, "DFS configuration is invalid.\n"); 193 return -EINVAL; 194 } 195 196 if (mode == ATOMISP_DFS_MODE_LOW) { 197 new_freq = dfs->lowest_freq; 198 goto done; 199 } 200 201 if (mode == ATOMISP_DFS_MODE_MAX) { 202 new_freq = dfs->highest_freq; 203 goto done; 204 } 205 206 fps = atomisp_get_sensor_fps(&isp->asd); 207 if (fps == 0) { 208 dev_info(isp->dev, 209 "Sensor didn't report FPS. Using DFS max mode.\n"); 210 new_freq = dfs->highest_freq; 211 goto done; 212 } 213 214 curr_rules.width = isp->asd.fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.width; 215 curr_rules.height = isp->asd.fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.height; 216 curr_rules.fps = fps; 217 curr_rules.run_mode = isp->asd.run_mode->val; 218 219 /* search for the target frequency by looping freq rules*/ 220 for (i = 0; i < dfs->dfs_table_size; i++) { 221 if (curr_rules.width != dfs->dfs_table[i].width && 222 dfs->dfs_table[i].width != ISP_FREQ_RULE_ANY) 223 continue; 224 if (curr_rules.height != dfs->dfs_table[i].height && 225 dfs->dfs_table[i].height != ISP_FREQ_RULE_ANY) 226 continue; 227 if (curr_rules.fps != dfs->dfs_table[i].fps && 228 dfs->dfs_table[i].fps != ISP_FREQ_RULE_ANY) 229 continue; 230 if (curr_rules.run_mode != dfs->dfs_table[i].run_mode && 231 dfs->dfs_table[i].run_mode != ISP_FREQ_RULE_ANY) 232 continue; 233 break; 234 } 235 236 if (i == dfs->dfs_table_size) 237 new_freq = dfs->max_freq_at_vmin; 238 else 239 new_freq = dfs->dfs_table[i].isp_freq; 240 241 done: 242 dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq); 243 244 if ((new_freq == isp->running_freq) && !force) 245 return 0; 246 247 dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq); 248 249 ret = write_target_freq_to_hw(isp, new_freq); 250 if (!ret) { 251 isp->running_freq = new_freq; 252 trace_ipu_pstate(new_freq, -1); 253 } 254 return ret; 255 } 256 257 /* 258 * reset and restore ISP 259 */ 260 int atomisp_reset(struct atomisp_device *isp) 261 { 262 /* Reset ISP by power-cycling it */ 263 int ret = 0; 264 265 dev_dbg(isp->dev, "%s\n", __func__); 266 267 ret = atomisp_power_off(isp->dev); 268 if (ret < 0) 269 dev_err(isp->dev, "atomisp_power_off failed, %d\n", ret); 270 271 ret = atomisp_power_on(isp->dev); 272 if (ret < 0) { 273 dev_err(isp->dev, "atomisp_power_on failed, %d\n", ret); 274 isp->isp_fatal_error = true; 275 } 276 277 return ret; 278 } 279 280 /* 281 * interrupt disable functions 282 */ 283 static void disable_isp_irq(enum hrt_isp_css_irq irq) 284 { 285 irq_disable_channel(IRQ0_ID, irq); 286 287 if (irq != hrt_isp_css_irq_sp) 288 return; 289 290 cnd_sp_irq_enable(SP0_ID, false); 291 } 292 293 /* 294 * interrupt clean function 295 */ 296 static void clear_isp_irq(enum hrt_isp_css_irq irq) 297 { 298 irq_clear_all(IRQ0_ID); 299 } 300 301 void atomisp_msi_irq_init(struct atomisp_device *isp) 302 { 303 struct pci_dev *pdev = to_pci_dev(isp->dev); 304 u32 msg32; 305 u16 msg16; 306 307 pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32); 308 msg32 |= 1 << MSI_ENABLE_BIT; 309 pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32); 310 311 msg32 = (1 << INTR_IER) | (1 << INTR_IIR); 312 pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32); 313 314 pci_read_config_word(pdev, PCI_COMMAND, &msg16); 315 msg16 |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 316 PCI_COMMAND_INTX_DISABLE); 317 pci_write_config_word(pdev, PCI_COMMAND, msg16); 318 } 319 320 void atomisp_msi_irq_uninit(struct atomisp_device *isp) 321 { 322 struct pci_dev *pdev = to_pci_dev(isp->dev); 323 u32 msg32; 324 u16 msg16; 325 326 pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32); 327 msg32 &= ~(1 << MSI_ENABLE_BIT); 328 pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32); 329 330 msg32 = 0x0; 331 pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32); 332 333 pci_read_config_word(pdev, PCI_COMMAND, &msg16); 334 msg16 &= ~(PCI_COMMAND_MASTER); 335 pci_write_config_word(pdev, PCI_COMMAND, msg16); 336 } 337 338 static void atomisp_sof_event(struct atomisp_sub_device *asd) 339 { 340 struct v4l2_event event = {0}; 341 342 event.type = V4L2_EVENT_FRAME_SYNC; 343 event.u.frame_sync.frame_sequence = atomic_read(&asd->sof_count); 344 345 v4l2_event_queue(asd->subdev.devnode, &event); 346 } 347 348 void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id) 349 { 350 struct v4l2_event event = {0}; 351 352 event.type = V4L2_EVENT_FRAME_END; 353 event.u.frame_sync.frame_sequence = exp_id; 354 355 v4l2_event_queue(asd->subdev.devnode, &event); 356 } 357 358 static void atomisp_3a_stats_ready_event(struct atomisp_sub_device *asd, 359 uint8_t exp_id) 360 { 361 struct v4l2_event event = {0}; 362 363 event.type = V4L2_EVENT_ATOMISP_3A_STATS_READY; 364 event.u.frame_sync.frame_sequence = exp_id; 365 366 v4l2_event_queue(asd->subdev.devnode, &event); 367 } 368 369 static void atomisp_metadata_ready_event(struct atomisp_sub_device *asd, 370 enum atomisp_metadata_type md_type) 371 { 372 struct v4l2_event event = {0}; 373 374 event.type = V4L2_EVENT_ATOMISP_METADATA_READY; 375 event.u.data[0] = md_type; 376 377 v4l2_event_queue(asd->subdev.devnode, &event); 378 } 379 380 static void atomisp_reset_event(struct atomisp_sub_device *asd) 381 { 382 struct v4l2_event event = {0}; 383 384 event.type = V4L2_EVENT_ATOMISP_CSS_RESET; 385 386 v4l2_event_queue(asd->subdev.devnode, &event); 387 } 388 389 static void print_csi_rx_errors(enum mipi_port_id port, 390 struct atomisp_device *isp) 391 { 392 u32 infos = 0; 393 394 atomisp_css_rx_get_irq_info(port, &infos); 395 396 dev_err(isp->dev, "CSI Receiver port %d errors:\n", port); 397 if (infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) 398 dev_err(isp->dev, " buffer overrun"); 399 if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT) 400 dev_err(isp->dev, " start-of-transmission error"); 401 if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) 402 dev_err(isp->dev, " start-of-transmission sync error"); 403 if (infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL) 404 dev_err(isp->dev, " control error"); 405 if (infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) 406 dev_err(isp->dev, " 2 or more ECC errors"); 407 if (infos & IA_CSS_RX_IRQ_INFO_ERR_CRC) 408 dev_err(isp->dev, " CRC mismatch"); 409 if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) 410 dev_err(isp->dev, " unknown error"); 411 if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) 412 dev_err(isp->dev, " frame sync error"); 413 if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) 414 dev_err(isp->dev, " frame data error"); 415 if (infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) 416 dev_err(isp->dev, " data timeout"); 417 if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) 418 dev_err(isp->dev, " unknown escape command entry"); 419 if (infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) 420 dev_err(isp->dev, " line sync error"); 421 } 422 423 /* Clear irq reg */ 424 static void clear_irq_reg(struct atomisp_device *isp) 425 { 426 struct pci_dev *pdev = to_pci_dev(isp->dev); 427 u32 msg_ret; 428 429 pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &msg_ret); 430 msg_ret |= 1 << INTR_IIR; 431 pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg_ret); 432 } 433 434 /* interrupt handling function*/ 435 irqreturn_t atomisp_isr(int irq, void *dev) 436 { 437 struct atomisp_device *isp = (struct atomisp_device *)dev; 438 struct atomisp_css_event eof_event; 439 unsigned int irq_infos = 0; 440 unsigned long flags; 441 int err; 442 443 spin_lock_irqsave(&isp->lock, flags); 444 445 if (!isp->css_initialized) { 446 spin_unlock_irqrestore(&isp->lock, flags); 447 return IRQ_HANDLED; 448 } 449 err = atomisp_css_irq_translate(isp, &irq_infos); 450 if (err) { 451 spin_unlock_irqrestore(&isp->lock, flags); 452 return IRQ_NONE; 453 } 454 455 clear_irq_reg(isp); 456 457 if (!isp->asd.streaming) 458 goto out_nowake; 459 460 if (irq_infos & IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF) { 461 atomic_inc(&isp->asd.sof_count); 462 atomisp_sof_event(&isp->asd); 463 464 /* 465 * If sequence_temp and sequence are the same there where no frames 466 * lost so we can increase sequence_temp. 467 * If not then processing of frame is still in progress and driver 468 * needs to keep old sequence_temp value. 469 * NOTE: There is assumption here that ISP will not start processing 470 * next frame from sensor before old one is completely done. 471 */ 472 if (atomic_read(&isp->asd.sequence) == atomic_read(&isp->asd.sequence_temp)) 473 atomic_set(&isp->asd.sequence_temp, atomic_read(&isp->asd.sof_count)); 474 475 dev_dbg_ratelimited(isp->dev, "irq:0x%x (SOF)\n", irq_infos); 476 irq_infos &= ~IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF; 477 } 478 479 if (irq_infos & IA_CSS_IRQ_INFO_EVENTS_READY) 480 atomic_set(&isp->asd.sequence, atomic_read(&isp->asd.sequence_temp)); 481 482 if ((irq_infos & IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR) || 483 (irq_infos & IA_CSS_IRQ_INFO_IF_ERROR)) { 484 /* handle mipi receiver error */ 485 u32 rx_infos; 486 enum mipi_port_id port; 487 488 for (port = MIPI_PORT0_ID; port <= MIPI_PORT2_ID; 489 port++) { 490 print_csi_rx_errors(port, isp); 491 atomisp_css_rx_get_irq_info(port, &rx_infos); 492 atomisp_css_rx_clear_irq_info(port, rx_infos); 493 } 494 } 495 496 if (irq_infos & IA_CSS_IRQ_INFO_ISYS_EVENTS_READY) { 497 while (ia_css_dequeue_isys_event(&eof_event.event) == 0) { 498 atomisp_eof_event(&isp->asd, eof_event.event.exp_id); 499 dev_dbg_ratelimited(isp->dev, "ISYS event: EOF exp_id %d\n", 500 eof_event.event.exp_id); 501 } 502 503 irq_infos &= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY; 504 if (irq_infos == 0) 505 goto out_nowake; 506 } 507 508 spin_unlock_irqrestore(&isp->lock, flags); 509 510 dev_dbg_ratelimited(isp->dev, "irq:0x%x (unhandled)\n", irq_infos); 511 512 return IRQ_WAKE_THREAD; 513 514 out_nowake: 515 spin_unlock_irqrestore(&isp->lock, flags); 516 517 if (irq_infos) 518 dev_dbg_ratelimited(isp->dev, "irq:0x%x (ignored, as not streaming anymore)\n", 519 irq_infos); 520 521 return IRQ_HANDLED; 522 } 523 524 void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd) 525 { 526 int i; 527 528 memset(asd->s3a_bufs_in_css, 0, sizeof(asd->s3a_bufs_in_css)); 529 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) 530 memset(asd->metadata_bufs_in_css[i], 0, 531 sizeof(asd->metadata_bufs_in_css[i])); 532 asd->dis_bufs_in_css = 0; 533 } 534 535 /* 0x100000 is the start of dmem inside SP */ 536 #define SP_DMEM_BASE 0x100000 537 538 void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr, 539 unsigned int size) 540 { 541 unsigned int data = 0; 542 unsigned int size32 = DIV_ROUND_UP(size, sizeof(u32)); 543 544 dev_dbg(isp->dev, "atomisp mmio base: %p\n", isp->base); 545 dev_dbg(isp->dev, "%s, addr:0x%x, size: %d, size32: %d\n", __func__, 546 addr, size, size32); 547 if (size32 * 4 + addr > 0x4000) { 548 dev_err(isp->dev, "illegal size (%d) or addr (0x%x)\n", 549 size32, addr); 550 return; 551 } 552 addr += SP_DMEM_BASE; 553 addr &= 0x003FFFFF; 554 do { 555 data = readl(isp->base + addr); 556 dev_dbg(isp->dev, "%s, \t [0x%x]:0x%x\n", __func__, addr, data); 557 addr += sizeof(u32); 558 } while (--size32); 559 } 560 561 int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe) 562 { 563 unsigned long irqflags; 564 struct list_head *pos; 565 int buffers_in_css = 0; 566 567 spin_lock_irqsave(&pipe->irq_lock, irqflags); 568 569 list_for_each(pos, &pipe->buffers_in_css) 570 buffers_in_css++; 571 572 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 573 574 return buffers_in_css; 575 } 576 577 void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state) 578 { 579 struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf); 580 581 lockdep_assert_held(&pipe->irq_lock); 582 583 frame->vb.vb2_buf.timestamp = ktime_get_ns(); 584 frame->vb.field = pipe->pix.field; 585 frame->vb.sequence = atomic_read(&pipe->asd->sequence); 586 list_del(&frame->queue); 587 if (state == VB2_BUF_STATE_DONE) 588 vb2_set_plane_payload(&frame->vb.vb2_buf, 0, pipe->pix.sizeimage); 589 vb2_buffer_done(&frame->vb.vb2_buf, state); 590 } 591 592 void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, 593 bool warn_on_css_frames) 594 { 595 struct ia_css_frame *frame, *_frame; 596 unsigned long irqflags; 597 598 spin_lock_irqsave(&pipe->irq_lock, irqflags); 599 600 list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) { 601 if (warn_on_css_frames) 602 dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n"); 603 atomisp_buffer_done(frame, state); 604 } 605 606 list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue) 607 atomisp_buffer_done(frame, state); 608 609 list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) { 610 pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0; 611 atomisp_buffer_done(frame, state); 612 } 613 614 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 615 } 616 617 /* clean out the parameters that did not apply */ 618 void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe) 619 { 620 struct atomisp_css_params_with_list *param; 621 622 while (!list_empty(&pipe->per_frame_params)) { 623 param = list_entry(pipe->per_frame_params.next, 624 struct atomisp_css_params_with_list, list); 625 list_del(¶m->list); 626 atomisp_free_css_parameters(¶m->params); 627 kvfree(param); 628 } 629 } 630 631 /* Re-queue per-frame parameters */ 632 static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe) 633 { 634 struct atomisp_css_params_with_list *param; 635 int i; 636 637 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 638 param = pipe->frame_params[i]; 639 if (param) 640 list_add_tail(¶m->list, &pipe->per_frame_params); 641 pipe->frame_params[i] = NULL; 642 } 643 atomisp_handle_parameter_and_buffer(pipe); 644 } 645 646 void atomisp_buf_done(struct atomisp_sub_device *asd, int error, 647 enum ia_css_buffer_type buf_type, 648 enum ia_css_pipe_id css_pipe_id, 649 bool q_buffers, enum atomisp_input_stream_id stream_id) 650 { 651 struct atomisp_video_pipe *pipe = NULL; 652 struct atomisp_css_buffer buffer; 653 bool requeue = false; 654 unsigned long irqflags; 655 struct ia_css_frame *frame = NULL; 656 struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter; 657 struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp, *dis_iter; 658 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter; 659 enum atomisp_metadata_type md_type; 660 struct atomisp_device *isp = asd->isp; 661 int i, err; 662 663 lockdep_assert_held(&isp->mutex); 664 665 if ( 666 buf_type != IA_CSS_BUFFER_TYPE_METADATA && 667 buf_type != IA_CSS_BUFFER_TYPE_3A_STATISTICS && 668 buf_type != IA_CSS_BUFFER_TYPE_DIS_STATISTICS && 669 buf_type != IA_CSS_BUFFER_TYPE_OUTPUT_FRAME && 670 buf_type != IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME && 671 buf_type != IA_CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME && 672 buf_type != IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME && 673 buf_type != IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { 674 dev_err(isp->dev, "%s, unsupported buffer type: %d\n", 675 __func__, buf_type); 676 return; 677 } 678 679 memset(&buffer, 0, sizeof(struct atomisp_css_buffer)); 680 buffer.css_buffer.type = buf_type; 681 err = atomisp_css_dequeue_buffer(asd, stream_id, css_pipe_id, 682 buf_type, &buffer); 683 if (err) { 684 dev_err(isp->dev, 685 "atomisp_css_dequeue_buffer failed: 0x%x\n", err); 686 return; 687 } 688 689 switch (buf_type) { 690 case IA_CSS_BUFFER_TYPE_3A_STATISTICS: 691 list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp, 692 &asd->s3a_stats_in_css, list) { 693 if (s3a_iter->s3a_data == 694 buffer.css_buffer.data.stats_3a) { 695 list_del_init(&s3a_iter->list); 696 list_add_tail(&s3a_iter->list, 697 &asd->s3a_stats_ready); 698 s3a_buf = s3a_iter; 699 break; 700 } 701 } 702 703 asd->s3a_bufs_in_css[css_pipe_id]--; 704 atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id); 705 if (s3a_buf) 706 dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n", 707 __func__, s3a_buf->s3a_data->exp_id); 708 else 709 dev_dbg(isp->dev, "%s: s3a stat is ready with no exp_id found\n", 710 __func__); 711 break; 712 case IA_CSS_BUFFER_TYPE_METADATA: 713 if (error) 714 break; 715 716 md_type = ATOMISP_MAIN_METADATA; 717 list_for_each_entry_safe(md_iter, _md_buf_tmp, 718 &asd->metadata_in_css[md_type], list) { 719 if (md_iter->metadata == 720 buffer.css_buffer.data.metadata) { 721 list_del_init(&md_iter->list); 722 list_add_tail(&md_iter->list, 723 &asd->metadata_ready[md_type]); 724 md_buf = md_iter; 725 break; 726 } 727 } 728 asd->metadata_bufs_in_css[stream_id][css_pipe_id]--; 729 atomisp_metadata_ready_event(asd, md_type); 730 if (md_buf) 731 dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n", 732 __func__, md_buf->metadata->exp_id); 733 else 734 dev_dbg(isp->dev, "%s: metadata is ready with no exp_id found\n", 735 __func__); 736 break; 737 case IA_CSS_BUFFER_TYPE_DIS_STATISTICS: 738 list_for_each_entry_safe(dis_iter, _dis_buf_tmp, 739 &asd->dis_stats_in_css, list) { 740 if (dis_iter->dis_data == 741 buffer.css_buffer.data.stats_dvs) { 742 spin_lock_irqsave(&asd->dis_stats_lock, 743 irqflags); 744 list_del_init(&dis_iter->list); 745 list_add(&dis_iter->list, &asd->dis_stats); 746 asd->params.dis_proj_data_valid = true; 747 spin_unlock_irqrestore(&asd->dis_stats_lock, 748 irqflags); 749 dis_buf = dis_iter; 750 break; 751 } 752 } 753 asd->dis_bufs_in_css--; 754 if (dis_buf) 755 dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n", 756 __func__, dis_buf->dis_data->exp_id); 757 else 758 dev_dbg(isp->dev, "%s: dis stat is ready with no exp_id found\n", 759 __func__); 760 break; 761 case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: 762 case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: 763 frame = buffer.css_buffer.data.frame; 764 if (!frame) { 765 WARN_ON(1); 766 break; 767 } 768 if (!frame->valid) 769 error = true; 770 771 pipe = vb_to_pipe(&frame->vb.vb2_buf); 772 773 dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n", 774 __func__, frame->exp_id); 775 pipe->frame_config_id[frame->vb.vb2_buf.index] = frame->isp_config_id; 776 break; 777 case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: 778 case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: 779 frame = buffer.css_buffer.data.frame; 780 if (!frame) { 781 WARN_ON(1); 782 break; 783 } 784 785 if (!frame->valid) 786 error = true; 787 788 pipe = vb_to_pipe(&frame->vb.vb2_buf); 789 790 dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n", 791 __func__, frame->exp_id); 792 793 i = frame->vb.vb2_buf.index; 794 795 /* free the parameters */ 796 if (pipe->frame_params[i]) { 797 if (asd->params.dvs_6axis == pipe->frame_params[i]->params.dvs_6axis) 798 asd->params.dvs_6axis = NULL; 799 atomisp_free_css_parameters(&pipe->frame_params[i]->params); 800 kvfree(pipe->frame_params[i]); 801 pipe->frame_params[i] = NULL; 802 } 803 804 pipe->frame_config_id[i] = frame->isp_config_id; 805 806 if (asd->params.css_update_params_needed) { 807 atomisp_apply_css_parameters(asd, 808 &asd->params.css_param); 809 if (asd->params.css_param.update_flag.dz_config) 810 asd->params.config.dz_config = &asd->params.css_param.dz_config; 811 /* New global dvs 6axis config should be blocked 812 * here if there's a buffer with per-frame parameters 813 * pending in CSS frame buffer queue. 814 * This is to avoid zooming vibration since global 815 * parameters take effect immediately while 816 * per-frame parameters are taken after previous 817 * buffers in CSS got processed. 818 */ 819 if (asd->params.dvs_6axis) 820 atomisp_css_set_dvs_6axis(asd, 821 asd->params.dvs_6axis); 822 else 823 asd->params.css_update_params_needed = false; 824 /* The update flag should not be cleaned here 825 * since it is still going to be used to make up 826 * following per-frame parameters. 827 * This will introduce more copy work since each 828 * time when updating global parameters, the whole 829 * parameter set are applied. 830 * FIXME: A new set of parameter copy functions can 831 * be added to make up per-frame parameters based on 832 * solid structures stored in asd->params.css_param 833 * instead of using shadow pointers in update flag. 834 */ 835 atomisp_css_update_isp_params(asd); 836 } 837 break; 838 default: 839 break; 840 } 841 if (frame) { 842 spin_lock_irqsave(&pipe->irq_lock, irqflags); 843 atomisp_buffer_done(frame, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 844 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 845 } 846 847 /* 848 * Requeue should only be done for 3a and dis buffers. 849 * Queue/dequeue order will change if driver recycles image buffers. 850 */ 851 if (requeue) { 852 err = atomisp_css_queue_buffer(asd, 853 stream_id, css_pipe_id, 854 buf_type, &buffer); 855 if (err) 856 dev_err(isp->dev, "%s, q to css fails: %d\n", 857 __func__, err); 858 return; 859 } 860 if (!error && q_buffers) 861 atomisp_qbuffers_to_css(asd); 862 } 863 864 void atomisp_assert_recovery_work(struct work_struct *work) 865 { 866 struct atomisp_device *isp = container_of(work, struct atomisp_device, 867 assert_recovery_work); 868 struct pci_dev *pdev = to_pci_dev(isp->dev); 869 unsigned long flags; 870 int ret; 871 872 mutex_lock(&isp->mutex); 873 874 if (!isp->asd.streaming) 875 goto out_unlock; 876 877 atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); 878 879 spin_lock_irqsave(&isp->lock, flags); 880 isp->asd.streaming = false; 881 spin_unlock_irqrestore(&isp->lock, flags); 882 883 /* stream off sensor */ 884 ret = v4l2_subdev_call(isp->inputs[isp->asd.input_curr].csi_remote_source, 885 video, s_stream, 0); 886 if (ret) 887 dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret); 888 889 atomisp_clear_css_buffer_counters(&isp->asd); 890 891 atomisp_css_stop(&isp->asd, true); 892 893 isp->asd.preview_exp_id = 1; 894 isp->asd.postview_exp_id = 1; 895 /* notify HAL the CSS reset */ 896 dev_dbg(isp->dev, "send reset event to %s\n", isp->asd.subdev.devnode->name); 897 atomisp_reset_event(&isp->asd); 898 899 /* clear irq */ 900 disable_isp_irq(hrt_isp_css_irq_sp); 901 clear_isp_irq(hrt_isp_css_irq_sp); 902 903 /* Set the SRSE to 3 before resetting */ 904 pci_write_config_dword(pdev, PCI_I_CONTROL, 905 isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); 906 907 /* reset ISP and restore its state */ 908 atomisp_reset(isp); 909 910 atomisp_css_input_set_mode(&isp->asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 911 912 /* Recreate streams destroyed by atomisp_css_stop() */ 913 atomisp_create_pipes_stream(&isp->asd); 914 915 /* Invalidate caches. FIXME: should flush only necessary buffers */ 916 wbinvd(); 917 918 if (atomisp_css_start(&isp->asd)) { 919 dev_warn(isp->dev, "start SP failed, so do not set streaming to be enable!\n"); 920 } else { 921 spin_lock_irqsave(&isp->lock, flags); 922 isp->asd.streaming = true; 923 spin_unlock_irqrestore(&isp->lock, flags); 924 } 925 926 atomisp_csi2_configure(&isp->asd); 927 928 atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, 929 atomisp_css_valid_sof(isp)); 930 931 if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0) 932 dev_dbg(isp->dev, "DFS auto failed while recovering!\n"); 933 934 /* Dequeueing buffers is not needed, CSS will recycle buffers that it has */ 935 atomisp_flush_video_pipe(&isp->asd.video_out, VB2_BUF_STATE_ERROR, false); 936 937 /* Requeue unprocessed per-frame parameters. */ 938 atomisp_recover_params_queue(&isp->asd.video_out); 939 940 ret = v4l2_subdev_call(isp->inputs[isp->asd.input_curr].csi_remote_source, 941 video, s_stream, 1); 942 if (ret) 943 dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret); 944 945 out_unlock: 946 mutex_unlock(&isp->mutex); 947 } 948 949 irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) 950 { 951 struct atomisp_device *isp = isp_ptr; 952 unsigned long flags; 953 bool streaming; 954 955 spin_lock_irqsave(&isp->lock, flags); 956 streaming = isp->asd.streaming; 957 spin_unlock_irqrestore(&isp->lock, flags); 958 959 if (!streaming) 960 return IRQ_HANDLED; 961 962 /* 963 * The standard CSS2.0 API tells the following calling sequence of 964 * dequeue ready buffers: 965 * while (ia_css_dequeue_psys_event(...)) { 966 * switch (event.type) { 967 * ... 968 * ia_css_pipe_dequeue_buffer() 969 * } 970 * } 971 * That is, dequeue event and buffer are one after another. 972 * 973 * But the following implementation is to first deuque all the event 974 * to a FIFO, then process the event in the FIFO. 975 * This will not have issue in single stream mode, but it do have some 976 * issue in multiple stream case. The issue is that 977 * ia_css_pipe_dequeue_buffer() will not return the correct buffer in 978 * a specific pipe. 979 * 980 * This is due to ia_css_pipe_dequeue_buffer() does not take the 981 * ia_css_pipe parameter. 982 * 983 * So: 984 * For CSS2.0: we change the way to not dequeue all the event at one 985 * time, instead, dequue one and process one, then another 986 */ 987 mutex_lock(&isp->mutex); 988 atomisp_css_isr_thread(isp); 989 mutex_unlock(&isp->mutex); 990 991 return IRQ_HANDLED; 992 } 993 994 /* 995 * Get internal fmt according to V4L2 fmt 996 */ 997 static enum ia_css_frame_format 998 v4l2_fmt_to_sh_fmt(u32 fmt) 999 { 1000 switch (fmt) { 1001 case V4L2_PIX_FMT_YUV420: 1002 return IA_CSS_FRAME_FORMAT_YUV420; 1003 case V4L2_PIX_FMT_YVU420: 1004 return IA_CSS_FRAME_FORMAT_YV12; 1005 case V4L2_PIX_FMT_YUV422P: 1006 return IA_CSS_FRAME_FORMAT_YUV422; 1007 case V4L2_PIX_FMT_YUV444: 1008 return IA_CSS_FRAME_FORMAT_YUV444; 1009 case V4L2_PIX_FMT_NV12: 1010 return IA_CSS_FRAME_FORMAT_NV12; 1011 case V4L2_PIX_FMT_NV21: 1012 return IA_CSS_FRAME_FORMAT_NV21; 1013 case V4L2_PIX_FMT_NV16: 1014 return IA_CSS_FRAME_FORMAT_NV16; 1015 case V4L2_PIX_FMT_NV61: 1016 return IA_CSS_FRAME_FORMAT_NV61; 1017 case V4L2_PIX_FMT_UYVY: 1018 return IA_CSS_FRAME_FORMAT_UYVY; 1019 case V4L2_PIX_FMT_YUYV: 1020 return IA_CSS_FRAME_FORMAT_YUYV; 1021 case V4L2_PIX_FMT_RGB24: 1022 return IA_CSS_FRAME_FORMAT_PLANAR_RGB888; 1023 case V4L2_PIX_FMT_RGBX32: 1024 return IA_CSS_FRAME_FORMAT_RGBA888; 1025 case V4L2_PIX_FMT_RGB565: 1026 return IA_CSS_FRAME_FORMAT_RGB565; 1027 #if 0 1028 case V4L2_PIX_FMT_JPEG: 1029 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW: 1030 return IA_CSS_FRAME_FORMAT_BINARY_8; 1031 #endif 1032 case V4L2_PIX_FMT_SBGGR16: 1033 case V4L2_PIX_FMT_SBGGR10: 1034 case V4L2_PIX_FMT_SGBRG10: 1035 case V4L2_PIX_FMT_SGRBG10: 1036 case V4L2_PIX_FMT_SRGGB10: 1037 case V4L2_PIX_FMT_SBGGR12: 1038 case V4L2_PIX_FMT_SGBRG12: 1039 case V4L2_PIX_FMT_SGRBG12: 1040 case V4L2_PIX_FMT_SRGGB12: 1041 case V4L2_PIX_FMT_SBGGR8: 1042 case V4L2_PIX_FMT_SGBRG8: 1043 case V4L2_PIX_FMT_SGRBG8: 1044 case V4L2_PIX_FMT_SRGGB8: 1045 return IA_CSS_FRAME_FORMAT_RAW; 1046 default: 1047 return -EINVAL; 1048 } 1049 } 1050 1051 /* 1052 * raw format match between SH format and V4L2 format 1053 */ 1054 static int raw_output_format_match_input(u32 input, u32 output) 1055 { 1056 if ((input == ATOMISP_INPUT_FORMAT_RAW_12) && 1057 ((output == V4L2_PIX_FMT_SRGGB12) || 1058 (output == V4L2_PIX_FMT_SGRBG12) || 1059 (output == V4L2_PIX_FMT_SBGGR12) || 1060 (output == V4L2_PIX_FMT_SGBRG12))) 1061 return 0; 1062 1063 if ((input == ATOMISP_INPUT_FORMAT_RAW_10) && 1064 ((output == V4L2_PIX_FMT_SRGGB10) || 1065 (output == V4L2_PIX_FMT_SGRBG10) || 1066 (output == V4L2_PIX_FMT_SBGGR10) || 1067 (output == V4L2_PIX_FMT_SGBRG10))) 1068 return 0; 1069 1070 if ((input == ATOMISP_INPUT_FORMAT_RAW_8) && 1071 ((output == V4L2_PIX_FMT_SRGGB8) || 1072 (output == V4L2_PIX_FMT_SGRBG8) || 1073 (output == V4L2_PIX_FMT_SBGGR8) || 1074 (output == V4L2_PIX_FMT_SGBRG8))) 1075 return 0; 1076 1077 if ((input == ATOMISP_INPUT_FORMAT_RAW_16) && (output == V4L2_PIX_FMT_SBGGR16)) 1078 return 0; 1079 1080 return -EINVAL; 1081 } 1082 1083 u32 atomisp_get_pixel_depth(u32 pixelformat) 1084 { 1085 switch (pixelformat) { 1086 case V4L2_PIX_FMT_YUV420: 1087 case V4L2_PIX_FMT_NV12: 1088 case V4L2_PIX_FMT_NV21: 1089 case V4L2_PIX_FMT_YVU420: 1090 return 12; 1091 case V4L2_PIX_FMT_YUV422P: 1092 case V4L2_PIX_FMT_YUYV: 1093 case V4L2_PIX_FMT_UYVY: 1094 case V4L2_PIX_FMT_NV16: 1095 case V4L2_PIX_FMT_NV61: 1096 case V4L2_PIX_FMT_RGB565: 1097 case V4L2_PIX_FMT_SBGGR16: 1098 case V4L2_PIX_FMT_SBGGR12: 1099 case V4L2_PIX_FMT_SGBRG12: 1100 case V4L2_PIX_FMT_SGRBG12: 1101 case V4L2_PIX_FMT_SRGGB12: 1102 case V4L2_PIX_FMT_SBGGR10: 1103 case V4L2_PIX_FMT_SGBRG10: 1104 case V4L2_PIX_FMT_SGRBG10: 1105 case V4L2_PIX_FMT_SRGGB10: 1106 return 16; 1107 case V4L2_PIX_FMT_RGB24: 1108 case V4L2_PIX_FMT_YUV444: 1109 return 24; 1110 case V4L2_PIX_FMT_RGBX32: 1111 return 32; 1112 case V4L2_PIX_FMT_JPEG: 1113 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW: 1114 case V4L2_PIX_FMT_SBGGR8: 1115 case V4L2_PIX_FMT_SGBRG8: 1116 case V4L2_PIX_FMT_SGRBG8: 1117 case V4L2_PIX_FMT_SRGGB8: 1118 return 8; 1119 default: 1120 return 8 * 2; /* raw type now */ 1121 } 1122 } 1123 1124 bool atomisp_is_mbuscode_raw(uint32_t code) 1125 { 1126 return code >= 0x3000 && code < 0x4000; 1127 } 1128 1129 /* 1130 * ISP features control function 1131 */ 1132 1133 /* 1134 * Set ISP capture mode based on current settings 1135 */ 1136 static void atomisp_update_capture_mode(struct atomisp_sub_device *asd) 1137 { 1138 if (asd->params.gdc_cac_en) 1139 atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_ADVANCED); 1140 else if (asd->params.low_light) 1141 atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_LOW_LIGHT); 1142 else if (asd->video_out.sh_fmt == IA_CSS_FRAME_FORMAT_RAW) 1143 atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW); 1144 else 1145 atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_PRIMARY); 1146 } 1147 1148 /* 1149 * Function to enable/disable lens geometry distortion correction (GDC) and 1150 * chromatic aberration correction (CAC) 1151 */ 1152 int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag, 1153 __s32 *value) 1154 { 1155 if (flag == 0) { 1156 *value = asd->params.gdc_cac_en; 1157 return 0; 1158 } 1159 1160 asd->params.gdc_cac_en = !!*value; 1161 if (asd->params.gdc_cac_en) 1162 asd->params.config.morph_table = asd->params.css_param.morph_table; 1163 else 1164 asd->params.config.morph_table = NULL; 1165 1166 asd->params.css_update_params_needed = true; 1167 atomisp_update_capture_mode(asd); 1168 return 0; 1169 } 1170 1171 /* 1172 * Function to enable/disable low light mode including ANR 1173 */ 1174 int atomisp_low_light(struct atomisp_sub_device *asd, int flag, 1175 __s32 *value) 1176 { 1177 if (flag == 0) { 1178 *value = asd->params.low_light; 1179 return 0; 1180 } 1181 1182 asd->params.low_light = (*value != 0); 1183 atomisp_update_capture_mode(asd); 1184 return 0; 1185 } 1186 1187 /* 1188 * Function to enable/disable extra noise reduction (XNR) in low light 1189 * condition 1190 */ 1191 int atomisp_xnr(struct atomisp_sub_device *asd, int flag, 1192 int *xnr_enable) 1193 { 1194 if (flag == 0) { 1195 *xnr_enable = asd->params.xnr_en; 1196 return 0; 1197 } 1198 1199 atomisp_css_capture_enable_xnr(asd, !!*xnr_enable); 1200 1201 return 0; 1202 } 1203 1204 /* 1205 * Function to configure bayer noise reduction 1206 */ 1207 int atomisp_nr(struct atomisp_sub_device *asd, int flag, 1208 struct atomisp_nr_config *arg) 1209 { 1210 if (flag == 0) { 1211 /* Get nr config from current setup */ 1212 if (atomisp_css_get_nr_config(asd, arg)) 1213 return -EINVAL; 1214 } else { 1215 /* Set nr config to isp parameters */ 1216 memcpy(&asd->params.css_param.nr_config, arg, 1217 sizeof(struct ia_css_nr_config)); 1218 asd->params.config.nr_config = &asd->params.css_param.nr_config; 1219 asd->params.css_update_params_needed = true; 1220 } 1221 return 0; 1222 } 1223 1224 /* 1225 * Function to configure temporal noise reduction (TNR) 1226 */ 1227 int atomisp_tnr(struct atomisp_sub_device *asd, int flag, 1228 struct atomisp_tnr_config *config) 1229 { 1230 /* Get tnr config from current setup */ 1231 if (flag == 0) { 1232 /* Get tnr config from current setup */ 1233 if (atomisp_css_get_tnr_config(asd, config)) 1234 return -EINVAL; 1235 } else { 1236 /* Set tnr config to isp parameters */ 1237 memcpy(&asd->params.css_param.tnr_config, config, 1238 sizeof(struct ia_css_tnr_config)); 1239 asd->params.config.tnr_config = &asd->params.css_param.tnr_config; 1240 asd->params.css_update_params_needed = true; 1241 } 1242 1243 return 0; 1244 } 1245 1246 /* 1247 * Function to configure black level compensation 1248 */ 1249 int atomisp_black_level(struct atomisp_sub_device *asd, int flag, 1250 struct atomisp_ob_config *config) 1251 { 1252 if (flag == 0) { 1253 /* Get ob config from current setup */ 1254 if (atomisp_css_get_ob_config(asd, config)) 1255 return -EINVAL; 1256 } else { 1257 /* Set ob config to isp parameters */ 1258 memcpy(&asd->params.css_param.ob_config, config, 1259 sizeof(struct ia_css_ob_config)); 1260 asd->params.config.ob_config = &asd->params.css_param.ob_config; 1261 asd->params.css_update_params_needed = true; 1262 } 1263 1264 return 0; 1265 } 1266 1267 /* 1268 * Function to configure edge enhancement 1269 */ 1270 int atomisp_ee(struct atomisp_sub_device *asd, int flag, 1271 struct atomisp_ee_config *config) 1272 { 1273 if (flag == 0) { 1274 /* Get ee config from current setup */ 1275 if (atomisp_css_get_ee_config(asd, config)) 1276 return -EINVAL; 1277 } else { 1278 /* Set ee config to isp parameters */ 1279 memcpy(&asd->params.css_param.ee_config, config, 1280 sizeof(asd->params.css_param.ee_config)); 1281 asd->params.config.ee_config = &asd->params.css_param.ee_config; 1282 asd->params.css_update_params_needed = true; 1283 } 1284 1285 return 0; 1286 } 1287 1288 /* 1289 * Function to update Gamma table for gamma, brightness and contrast config 1290 */ 1291 int atomisp_gamma(struct atomisp_sub_device *asd, int flag, 1292 struct atomisp_gamma_table *config) 1293 { 1294 if (flag == 0) { 1295 /* Get gamma table from current setup */ 1296 if (atomisp_css_get_gamma_table(asd, config)) 1297 return -EINVAL; 1298 } else { 1299 /* Set gamma table to isp parameters */ 1300 memcpy(&asd->params.css_param.gamma_table, config, 1301 sizeof(asd->params.css_param.gamma_table)); 1302 asd->params.config.gamma_table = &asd->params.css_param.gamma_table; 1303 } 1304 1305 return 0; 1306 } 1307 1308 /* 1309 * Function to update Ctc table for Chroma Enhancement 1310 */ 1311 int atomisp_ctc(struct atomisp_sub_device *asd, int flag, 1312 struct atomisp_ctc_table *config) 1313 { 1314 if (flag == 0) { 1315 /* Get ctc table from current setup */ 1316 if (atomisp_css_get_ctc_table(asd, config)) 1317 return -EINVAL; 1318 } else { 1319 /* Set ctc table to isp parameters */ 1320 memcpy(&asd->params.css_param.ctc_table, config, 1321 sizeof(asd->params.css_param.ctc_table)); 1322 atomisp_css_set_ctc_table(asd, &asd->params.css_param.ctc_table); 1323 } 1324 1325 return 0; 1326 } 1327 1328 /* 1329 * Function to update gamma correction parameters 1330 */ 1331 int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag, 1332 struct atomisp_gc_config *config) 1333 { 1334 if (flag == 0) { 1335 /* Get gamma correction params from current setup */ 1336 if (atomisp_css_get_gc_config(asd, config)) 1337 return -EINVAL; 1338 } else { 1339 /* Set gamma correction params to isp parameters */ 1340 memcpy(&asd->params.css_param.gc_config, config, 1341 sizeof(asd->params.css_param.gc_config)); 1342 asd->params.config.gc_config = &asd->params.css_param.gc_config; 1343 asd->params.css_update_params_needed = true; 1344 } 1345 1346 return 0; 1347 } 1348 1349 /* 1350 * Function to update narrow gamma flag 1351 */ 1352 int atomisp_formats(struct atomisp_sub_device *asd, int flag, 1353 struct atomisp_formats_config *config) 1354 { 1355 if (flag == 0) { 1356 /* Get narrow gamma flag from current setup */ 1357 if (atomisp_css_get_formats_config(asd, config)) 1358 return -EINVAL; 1359 } else { 1360 /* Set narrow gamma flag to isp parameters */ 1361 memcpy(&asd->params.css_param.formats_config, config, 1362 sizeof(asd->params.css_param.formats_config)); 1363 asd->params.config.formats_config = &asd->params.css_param.formats_config; 1364 } 1365 1366 return 0; 1367 } 1368 1369 void atomisp_free_internal_buffers(struct atomisp_sub_device *asd) 1370 { 1371 atomisp_free_css_parameters(&asd->params.css_param); 1372 } 1373 1374 static void atomisp_update_grid_info(struct atomisp_sub_device *asd, 1375 enum ia_css_pipe_id pipe_id) 1376 { 1377 struct atomisp_device *isp = asd->isp; 1378 int err; 1379 1380 if (atomisp_css_get_grid_info(asd, pipe_id)) 1381 return; 1382 1383 /* 1384 * We must free all buffers because they no longer match 1385 * the grid size. 1386 */ 1387 atomisp_css_free_stat_buffers(asd); 1388 1389 err = atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL); 1390 if (err) { 1391 dev_err(isp->dev, "stat_buf allocate error\n"); 1392 goto err; 1393 } 1394 1395 if (atomisp_alloc_3a_output_buf(asd)) { 1396 /* Failure for 3A buffers does not influence DIS buffers */ 1397 if (asd->params.s3a_output_bytes != 0) { 1398 /* 1399 * For SOC sensor happens s3a_output_bytes == 0, 1400 * using if condition to exclude false error log 1401 */ 1402 dev_err(isp->dev, "Failed to allocate memory for 3A statistics\n"); 1403 } 1404 goto err; 1405 } 1406 1407 if (atomisp_alloc_dis_coef_buf(asd)) { 1408 dev_err(isp->dev, 1409 "Failed to allocate memory for DIS statistics\n"); 1410 goto err; 1411 } 1412 1413 if (atomisp_alloc_metadata_output_buf(asd)) { 1414 dev_err(isp->dev, "Failed to allocate memory for metadata\n"); 1415 goto err; 1416 } 1417 1418 return; 1419 1420 err: 1421 atomisp_css_free_stat_buffers(asd); 1422 return; 1423 } 1424 1425 static void atomisp_curr_user_grid_info(struct atomisp_sub_device *asd, 1426 struct atomisp_grid_info *info) 1427 { 1428 memcpy(info, &asd->params.curr_grid_info.s3a_grid, 1429 sizeof(struct ia_css_3a_grid_info)); 1430 } 1431 1432 int atomisp_compare_grid(struct atomisp_sub_device *asd, 1433 struct atomisp_grid_info *atomgrid) 1434 { 1435 struct atomisp_grid_info tmp = {0}; 1436 1437 atomisp_curr_user_grid_info(asd, &tmp); 1438 return memcmp(atomgrid, &tmp, sizeof(tmp)); 1439 } 1440 1441 /* 1442 * Function to update Gdc table for gdc 1443 */ 1444 int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag, 1445 struct atomisp_morph_table *config) 1446 { 1447 int ret; 1448 int i; 1449 struct atomisp_device *isp = asd->isp; 1450 1451 if (flag == 0) { 1452 /* Get gdc table from current setup */ 1453 struct ia_css_morph_table tab = {0}; 1454 1455 atomisp_css_get_morph_table(asd, &tab); 1456 1457 config->width = tab.width; 1458 config->height = tab.height; 1459 1460 for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { 1461 ret = copy_to_user(config->coordinates_x[i], 1462 tab.coordinates_x[i], tab.height * 1463 tab.width * sizeof(*tab.coordinates_x[i])); 1464 if (ret) { 1465 dev_err(isp->dev, 1466 "Failed to copy to User for x\n"); 1467 return -EFAULT; 1468 } 1469 ret = copy_to_user(config->coordinates_y[i], 1470 tab.coordinates_y[i], tab.height * 1471 tab.width * sizeof(*tab.coordinates_y[i])); 1472 if (ret) { 1473 dev_err(isp->dev, 1474 "Failed to copy to User for y\n"); 1475 return -EFAULT; 1476 } 1477 } 1478 } else { 1479 struct ia_css_morph_table *tab = 1480 asd->params.css_param.morph_table; 1481 1482 /* free first if we have one */ 1483 if (tab) { 1484 atomisp_css_morph_table_free(tab); 1485 asd->params.css_param.morph_table = NULL; 1486 } 1487 1488 /* allocate new one */ 1489 tab = atomisp_css_morph_table_allocate(config->width, 1490 config->height); 1491 1492 if (!tab) { 1493 dev_err(isp->dev, "out of memory\n"); 1494 return -EINVAL; 1495 } 1496 1497 for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { 1498 ret = copy_from_user(tab->coordinates_x[i], 1499 config->coordinates_x[i], 1500 config->height * config->width * 1501 sizeof(*config->coordinates_x[i])); 1502 if (ret) { 1503 dev_err(isp->dev, 1504 "Failed to copy from User for x, ret %d\n", 1505 ret); 1506 atomisp_css_morph_table_free(tab); 1507 return -EFAULT; 1508 } 1509 ret = copy_from_user(tab->coordinates_y[i], 1510 config->coordinates_y[i], 1511 config->height * config->width * 1512 sizeof(*config->coordinates_y[i])); 1513 if (ret) { 1514 dev_err(isp->dev, 1515 "Failed to copy from User for y, ret is %d\n", 1516 ret); 1517 atomisp_css_morph_table_free(tab); 1518 return -EFAULT; 1519 } 1520 } 1521 asd->params.css_param.morph_table = tab; 1522 if (asd->params.gdc_cac_en) 1523 asd->params.config.morph_table = tab; 1524 } 1525 1526 return 0; 1527 } 1528 1529 int atomisp_macc_table(struct atomisp_sub_device *asd, int flag, 1530 struct atomisp_macc_config *config) 1531 { 1532 struct ia_css_macc_table *macc_table; 1533 1534 switch (config->color_effect) { 1535 case V4L2_COLORFX_NONE: 1536 macc_table = &asd->params.css_param.macc_table; 1537 break; 1538 case V4L2_COLORFX_SKY_BLUE: 1539 macc_table = &blue_macc_table; 1540 break; 1541 case V4L2_COLORFX_GRASS_GREEN: 1542 macc_table = &green_macc_table; 1543 break; 1544 case V4L2_COLORFX_SKIN_WHITEN_LOW: 1545 macc_table = &skin_low_macc_table; 1546 break; 1547 case V4L2_COLORFX_SKIN_WHITEN: 1548 macc_table = &skin_medium_macc_table; 1549 break; 1550 case V4L2_COLORFX_SKIN_WHITEN_HIGH: 1551 macc_table = &skin_high_macc_table; 1552 break; 1553 default: 1554 return -EINVAL; 1555 } 1556 1557 if (flag == 0) { 1558 /* Get macc table from current setup */ 1559 memcpy(&config->table, macc_table, 1560 sizeof(struct ia_css_macc_table)); 1561 } else { 1562 memcpy(macc_table, &config->table, 1563 sizeof(struct ia_css_macc_table)); 1564 if (config->color_effect == asd->params.color_effect) 1565 asd->params.config.macc_table = macc_table; 1566 } 1567 1568 return 0; 1569 } 1570 1571 int atomisp_set_dis_vector(struct atomisp_sub_device *asd, 1572 struct atomisp_dis_vector *vector) 1573 { 1574 atomisp_css_video_set_dis_vector(asd, vector); 1575 1576 asd->params.dis_proj_data_valid = false; 1577 asd->params.css_update_params_needed = true; 1578 return 0; 1579 } 1580 1581 /* 1582 * Function to set/get image stabilization statistics 1583 */ 1584 int atomisp_get_dis_stat(struct atomisp_sub_device *asd, 1585 struct atomisp_dis_statistics *stats) 1586 { 1587 return atomisp_css_get_dis_stat(asd, stats); 1588 } 1589 1590 /* 1591 * Function set camrea_prefiles.xml current sensor pixel array size 1592 */ 1593 int atomisp_set_array_res(struct atomisp_sub_device *asd, 1594 struct atomisp_resolution *config) 1595 { 1596 dev_dbg(asd->isp->dev, ">%s start\n", __func__); 1597 if (!config) { 1598 dev_err(asd->isp->dev, "Set sensor array size is not valid\n"); 1599 return -EINVAL; 1600 } 1601 1602 asd->sensor_array_res.width = config->width; 1603 asd->sensor_array_res.height = config->height; 1604 return 0; 1605 } 1606 1607 /* 1608 * Function to get DVS2 BQ resolution settings 1609 */ 1610 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd, 1611 struct atomisp_dvs2_bq_resolutions *bq_res) 1612 { 1613 struct ia_css_pipe_config *pipe_cfg = NULL; 1614 1615 struct ia_css_stream *stream = 1616 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream; 1617 if (!stream) { 1618 dev_warn(asd->isp->dev, "stream is not created"); 1619 return -EAGAIN; 1620 } 1621 1622 pipe_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] 1623 .pipe_configs[IA_CSS_PIPE_ID_VIDEO]; 1624 1625 if (!bq_res) 1626 return -EINVAL; 1627 1628 /* the GDC output resolution */ 1629 bq_res->output_bq.width_bq = pipe_cfg->output_info[0].res.width / 2; 1630 bq_res->output_bq.height_bq = pipe_cfg->output_info[0].res.height / 2; 1631 1632 bq_res->envelope_bq.width_bq = 0; 1633 bq_res->envelope_bq.height_bq = 0; 1634 /* the GDC input resolution */ 1635 bq_res->source_bq.width_bq = bq_res->output_bq.width_bq + 1636 pipe_cfg->dvs_envelope.width / 2; 1637 bq_res->source_bq.height_bq = bq_res->output_bq.height_bq + 1638 pipe_cfg->dvs_envelope.height / 2; 1639 /* 1640 * Bad pixels caused by spatial filter processing 1641 * ISP filter resolution should be given by CSS/FW, but for now 1642 * there is not such API to query, and it is fixed value, so 1643 * hardcoded here. 1644 */ 1645 bq_res->ispfilter_bq.width_bq = 12 / 2; 1646 bq_res->ispfilter_bq.height_bq = 12 / 2; 1647 /* spatial filter shift, always 4 pixels */ 1648 bq_res->gdc_shift_bq.width_bq = 4 / 2; 1649 bq_res->gdc_shift_bq.height_bq = 4 / 2; 1650 1651 if (asd->params.video_dis_en) { 1652 bq_res->envelope_bq.width_bq = pipe_cfg->dvs_envelope.width / 2 - 1653 bq_res->ispfilter_bq.width_bq; 1654 bq_res->envelope_bq.height_bq = pipe_cfg->dvs_envelope.height / 2 - 1655 bq_res->ispfilter_bq.height_bq; 1656 } 1657 1658 dev_dbg(asd->isp->dev, 1659 "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", 1660 bq_res->source_bq.width_bq, bq_res->source_bq.height_bq, 1661 bq_res->ispfilter_bq.width_bq, bq_res->ispfilter_bq.height_bq, 1662 bq_res->gdc_shift_bq.width_bq, bq_res->gdc_shift_bq.height_bq, 1663 bq_res->envelope_bq.width_bq, bq_res->envelope_bq.height_bq, 1664 bq_res->output_bq.width_bq, bq_res->output_bq.height_bq); 1665 1666 return 0; 1667 } 1668 1669 int atomisp_set_dis_coefs(struct atomisp_sub_device *asd, 1670 struct atomisp_dis_coefficients *coefs) 1671 { 1672 return atomisp_css_set_dis_coefs(asd, coefs); 1673 } 1674 1675 /* 1676 * Function to set/get 3A stat from isp 1677 */ 1678 int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag, 1679 struct atomisp_3a_statistics *config) 1680 { 1681 struct atomisp_device *isp = asd->isp; 1682 struct atomisp_s3a_buf *s3a_buf; 1683 unsigned long ret; 1684 1685 if (flag != 0) 1686 return -EINVAL; 1687 1688 /* sanity check to avoid writing into unallocated memory. */ 1689 if (asd->params.s3a_output_bytes == 0) 1690 return -EINVAL; 1691 1692 if (atomisp_compare_grid(asd, &config->grid_info) != 0) { 1693 /* 1694 * If the grid info in the argument differs from the current 1695 * grid info, we tell the caller to reset the grid size and 1696 * try again. 1697 */ 1698 return -EAGAIN; 1699 } 1700 1701 if (list_empty(&asd->s3a_stats_ready)) { 1702 dev_err(isp->dev, "3a statistics is not valid.\n"); 1703 return -EAGAIN; 1704 } 1705 1706 s3a_buf = list_entry(asd->s3a_stats_ready.next, 1707 struct atomisp_s3a_buf, list); 1708 if (s3a_buf->s3a_map) 1709 ia_css_translate_3a_statistics( 1710 asd->params.s3a_user_stat, s3a_buf->s3a_map); 1711 else 1712 ia_css_get_3a_statistics(asd->params.s3a_user_stat, 1713 s3a_buf->s3a_data); 1714 1715 config->exp_id = s3a_buf->s3a_data->exp_id; 1716 config->isp_config_id = s3a_buf->s3a_data->isp_config_id; 1717 1718 ret = copy_to_user(config->data, asd->params.s3a_user_stat->data, 1719 asd->params.s3a_output_bytes); 1720 if (ret) { 1721 dev_err(isp->dev, "copy to user failed: copied %lu bytes\n", 1722 ret); 1723 return -EFAULT; 1724 } 1725 1726 /* Move to free buffer list */ 1727 list_del_init(&s3a_buf->list); 1728 list_add_tail(&s3a_buf->list, &asd->s3a_stats); 1729 dev_dbg(isp->dev, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n", 1730 __func__, 1731 config->exp_id, config->isp_config_id); 1732 return 0; 1733 } 1734 1735 /* 1736 * Function to calculate real zoom region for every pipe 1737 */ 1738 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd, 1739 struct ia_css_dz_config *dz_config, 1740 enum ia_css_pipe_id css_pipe_id) 1741 1742 { 1743 struct atomisp_stream_env *stream_env = 1744 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; 1745 struct atomisp_resolution eff_res, out_res; 1746 int w_offset, h_offset; 1747 1748 memset(&eff_res, 0, sizeof(eff_res)); 1749 memset(&out_res, 0, sizeof(out_res)); 1750 1751 if (dz_config->dx || dz_config->dy) 1752 return 0; 1753 1754 if (css_pipe_id != IA_CSS_PIPE_ID_PREVIEW 1755 && css_pipe_id != IA_CSS_PIPE_ID_CAPTURE) { 1756 dev_err(asd->isp->dev, "%s the set pipe no support crop region" 1757 , __func__); 1758 return -EINVAL; 1759 } 1760 1761 eff_res.width = 1762 stream_env->stream_config.input_config.effective_res.width; 1763 eff_res.height = 1764 stream_env->stream_config.input_config.effective_res.height; 1765 if (eff_res.width == 0 || eff_res.height == 0) { 1766 dev_err(asd->isp->dev, "%s err effective resolution" 1767 , __func__); 1768 return -EINVAL; 1769 } 1770 1771 if (dz_config->zoom_region.width == asd->sensor_array_res.width || 1772 dz_config->zoom_region.height == asd->sensor_array_res.height) { 1773 /*no need crop region*/ 1774 dz_config->zoom_region.left = 0; 1775 dz_config->zoom_region.top = 0; 1776 dz_config->zoom_region.width = eff_res.width; 1777 dz_config->zoom_region.height = eff_res.height; 1778 return 0; 1779 } 1780 1781 /* FIXME: 1782 * This is not the correct implementation with Google's definition, due 1783 * to firmware limitation. 1784 * map real crop region base on above calculating base max crop region. 1785 */ 1786 1787 if (!IS_ISP2401) { 1788 dz_config->zoom_region.left = dz_config->zoom_region.left * 1789 eff_res.width / asd->sensor_array_res.width; 1790 dz_config->zoom_region.top = dz_config->zoom_region.top * 1791 eff_res.height / asd->sensor_array_res.height; 1792 dz_config->zoom_region.width = dz_config->zoom_region.width * 1793 eff_res.width / asd->sensor_array_res.width; 1794 dz_config->zoom_region.height = dz_config->zoom_region.height * 1795 eff_res.height / asd->sensor_array_res.height; 1796 /* 1797 * Set same ratio of crop region resolution and current pipe output 1798 * resolution 1799 */ 1800 out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width; 1801 out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height; 1802 if (out_res.width == 0 || out_res.height == 0) { 1803 dev_err(asd->isp->dev, "%s err current pipe output resolution" 1804 , __func__); 1805 return -EINVAL; 1806 } 1807 } else { 1808 out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width; 1809 out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height; 1810 if (out_res.width == 0 || out_res.height == 0) { 1811 dev_err(asd->isp->dev, "%s err current pipe output resolution" 1812 , __func__); 1813 return -EINVAL; 1814 } 1815 1816 if (asd->sensor_array_res.width * out_res.height 1817 < out_res.width * asd->sensor_array_res.height) { 1818 h_offset = asd->sensor_array_res.height 1819 - asd->sensor_array_res.width 1820 * out_res.height / out_res.width; 1821 h_offset = h_offset / 2; 1822 if (dz_config->zoom_region.top < h_offset) 1823 dz_config->zoom_region.top = 0; 1824 else 1825 dz_config->zoom_region.top = 1826 dz_config->zoom_region.top - h_offset; 1827 w_offset = 0; 1828 } else { 1829 w_offset = asd->sensor_array_res.width 1830 - asd->sensor_array_res.height 1831 * out_res.width / out_res.height; 1832 w_offset = w_offset / 2; 1833 if (dz_config->zoom_region.left < w_offset) 1834 dz_config->zoom_region.left = 0; 1835 else 1836 dz_config->zoom_region.left = 1837 dz_config->zoom_region.left - w_offset; 1838 h_offset = 0; 1839 } 1840 dz_config->zoom_region.left = dz_config->zoom_region.left * 1841 eff_res.width / 1842 (asd->sensor_array_res.width - 2 * w_offset); 1843 dz_config->zoom_region.top = dz_config->zoom_region.top * 1844 eff_res.height / 1845 (asd->sensor_array_res.height - 2 * h_offset); 1846 dz_config->zoom_region.width = dz_config->zoom_region.width * 1847 eff_res.width / 1848 (asd->sensor_array_res.width - 2 * w_offset); 1849 dz_config->zoom_region.height = dz_config->zoom_region.height * 1850 eff_res.height / 1851 (asd->sensor_array_res.height - 2 * h_offset); 1852 } 1853 1854 if (out_res.width * dz_config->zoom_region.height > 1855 dz_config->zoom_region.width * out_res.height) { 1856 dz_config->zoom_region.height = dz_config->zoom_region.width * 1857 out_res.height / out_res.width; 1858 } else { 1859 dz_config->zoom_region.width = dz_config->zoom_region.height * 1860 out_res.width / out_res.height; 1861 } 1862 dev_dbg(asd->isp->dev, 1863 "%s crop region:(%d,%d),(%d,%d) eff_res(%d, %d) array_size(%d,%d) out_res(%d, %d)\n", 1864 __func__, dz_config->zoom_region.left, 1865 dz_config->zoom_region.top, 1866 dz_config->zoom_region.width, 1867 dz_config->zoom_region.height, 1868 eff_res.width, eff_res.height, 1869 asd->sensor_array_res.width, 1870 asd->sensor_array_res.height, 1871 out_res.width, out_res.height); 1872 1873 if ((dz_config->zoom_region.left + 1874 dz_config->zoom_region.width 1875 > eff_res.width) || 1876 (dz_config->zoom_region.top + 1877 dz_config->zoom_region.height 1878 > eff_res.height)) 1879 return -EINVAL; 1880 1881 return 0; 1882 } 1883 1884 /* 1885 * Function to check the zoom region whether is effective 1886 */ 1887 static bool atomisp_check_zoom_region( 1888 struct atomisp_sub_device *asd, 1889 struct ia_css_dz_config *dz_config) 1890 { 1891 struct atomisp_resolution config; 1892 bool flag = false; 1893 unsigned int w, h; 1894 1895 memset(&config, 0, sizeof(struct atomisp_resolution)); 1896 1897 if (dz_config->dx && dz_config->dy) 1898 return true; 1899 1900 config.width = asd->sensor_array_res.width; 1901 config.height = asd->sensor_array_res.height; 1902 w = dz_config->zoom_region.left + 1903 dz_config->zoom_region.width; 1904 h = dz_config->zoom_region.top + 1905 dz_config->zoom_region.height; 1906 1907 if ((w <= config.width) && (h <= config.height) && w > 0 && h > 0) 1908 flag = true; 1909 else 1910 /* setting error zoom region */ 1911 dev_err(asd->isp->dev, 1912 "%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n", 1913 __func__, dz_config->zoom_region.left, 1914 dz_config->zoom_region.top, 1915 dz_config->zoom_region.width, 1916 dz_config->zoom_region.height, 1917 config.width, config.height); 1918 1919 return flag; 1920 } 1921 1922 void atomisp_apply_css_parameters( 1923 struct atomisp_sub_device *asd, 1924 struct atomisp_css_params *css_param) 1925 { 1926 if (css_param->update_flag.wb_config) 1927 asd->params.config.wb_config = &css_param->wb_config; 1928 1929 if (css_param->update_flag.ob_config) 1930 asd->params.config.ob_config = &css_param->ob_config; 1931 1932 if (css_param->update_flag.dp_config) 1933 asd->params.config.dp_config = &css_param->dp_config; 1934 1935 if (css_param->update_flag.nr_config) 1936 asd->params.config.nr_config = &css_param->nr_config; 1937 1938 if (css_param->update_flag.ee_config) 1939 asd->params.config.ee_config = &css_param->ee_config; 1940 1941 if (css_param->update_flag.tnr_config) 1942 asd->params.config.tnr_config = &css_param->tnr_config; 1943 1944 if (css_param->update_flag.a3a_config) 1945 asd->params.config.s3a_config = &css_param->s3a_config; 1946 1947 if (css_param->update_flag.ctc_config) 1948 asd->params.config.ctc_config = &css_param->ctc_config; 1949 1950 if (css_param->update_flag.cnr_config) 1951 asd->params.config.cnr_config = &css_param->cnr_config; 1952 1953 if (css_param->update_flag.ecd_config) 1954 asd->params.config.ecd_config = &css_param->ecd_config; 1955 1956 if (css_param->update_flag.ynr_config) 1957 asd->params.config.ynr_config = &css_param->ynr_config; 1958 1959 if (css_param->update_flag.fc_config) 1960 asd->params.config.fc_config = &css_param->fc_config; 1961 1962 if (css_param->update_flag.macc_config) 1963 asd->params.config.macc_config = &css_param->macc_config; 1964 1965 if (css_param->update_flag.aa_config) 1966 asd->params.config.aa_config = &css_param->aa_config; 1967 1968 if (css_param->update_flag.anr_config) 1969 asd->params.config.anr_config = &css_param->anr_config; 1970 1971 if (css_param->update_flag.xnr_config) 1972 asd->params.config.xnr_config = &css_param->xnr_config; 1973 1974 if (css_param->update_flag.yuv2rgb_cc_config) 1975 asd->params.config.yuv2rgb_cc_config = &css_param->yuv2rgb_cc_config; 1976 1977 if (css_param->update_flag.rgb2yuv_cc_config) 1978 asd->params.config.rgb2yuv_cc_config = &css_param->rgb2yuv_cc_config; 1979 1980 if (css_param->update_flag.macc_table) 1981 asd->params.config.macc_table = &css_param->macc_table; 1982 1983 if (css_param->update_flag.xnr_table) 1984 asd->params.config.xnr_table = &css_param->xnr_table; 1985 1986 if (css_param->update_flag.r_gamma_table) 1987 asd->params.config.r_gamma_table = &css_param->r_gamma_table; 1988 1989 if (css_param->update_flag.g_gamma_table) 1990 asd->params.config.g_gamma_table = &css_param->g_gamma_table; 1991 1992 if (css_param->update_flag.b_gamma_table) 1993 asd->params.config.b_gamma_table = &css_param->b_gamma_table; 1994 1995 if (css_param->update_flag.anr_thres) 1996 atomisp_css_set_anr_thres(asd, &css_param->anr_thres); 1997 1998 if (css_param->update_flag.shading_table) 1999 asd->params.config.shading_table = css_param->shading_table; 2000 2001 if (css_param->update_flag.morph_table && asd->params.gdc_cac_en) 2002 asd->params.config.morph_table = css_param->morph_table; 2003 2004 if (css_param->update_flag.dvs2_coefs) { 2005 struct ia_css_dvs_grid_info *dvs_grid_info = 2006 atomisp_css_get_dvs_grid_info( 2007 &asd->params.curr_grid_info); 2008 2009 if (dvs_grid_info && dvs_grid_info->enable) 2010 atomisp_css_set_dvs2_coefs(asd, css_param->dvs2_coeff); 2011 } 2012 2013 if (css_param->update_flag.dvs_6axis_config) 2014 atomisp_css_set_dvs_6axis(asd, css_param->dvs_6axis); 2015 2016 atomisp_css_set_isp_config_id(asd, css_param->isp_config_id); 2017 /* 2018 * These configurations are on used by ISP1.x, not for ISP2.x, 2019 * so do not handle them. see comments of ia_css_isp_config. 2020 * 1 cc_config 2021 * 2 ce_config 2022 * 3 de_config 2023 * 4 gc_config 2024 * 5 gamma_table 2025 * 6 ctc_table 2026 * 7 dvs_coefs 2027 */ 2028 } 2029 2030 static unsigned int long copy_from_compatible(void *to, const void *from, 2031 unsigned long n, bool from_user) 2032 { 2033 if (from_user) 2034 return copy_from_user(to, (void __user *)from, n); 2035 2036 memcpy(to, from, n); 2037 return 0; 2038 } 2039 2040 int atomisp_cp_general_isp_parameters(struct atomisp_sub_device *asd, 2041 struct atomisp_parameters *arg, 2042 struct atomisp_css_params *css_param, 2043 bool from_user) 2044 { 2045 struct atomisp_parameters *cur_config = &css_param->update_flag; 2046 2047 if (!arg || !asd || !css_param) 2048 return -EINVAL; 2049 2050 if (arg->wb_config && (from_user || !cur_config->wb_config)) { 2051 if (copy_from_compatible(&css_param->wb_config, arg->wb_config, 2052 sizeof(struct ia_css_wb_config), 2053 from_user)) 2054 return -EFAULT; 2055 css_param->update_flag.wb_config = 2056 (struct atomisp_wb_config *)&css_param->wb_config; 2057 } 2058 2059 if (arg->ob_config && (from_user || !cur_config->ob_config)) { 2060 if (copy_from_compatible(&css_param->ob_config, arg->ob_config, 2061 sizeof(struct ia_css_ob_config), 2062 from_user)) 2063 return -EFAULT; 2064 css_param->update_flag.ob_config = 2065 (struct atomisp_ob_config *)&css_param->ob_config; 2066 } 2067 2068 if (arg->dp_config && (from_user || !cur_config->dp_config)) { 2069 if (copy_from_compatible(&css_param->dp_config, arg->dp_config, 2070 sizeof(struct ia_css_dp_config), 2071 from_user)) 2072 return -EFAULT; 2073 css_param->update_flag.dp_config = 2074 (struct atomisp_dp_config *)&css_param->dp_config; 2075 } 2076 2077 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { 2078 if (arg->dz_config && (from_user || !cur_config->dz_config)) { 2079 if (copy_from_compatible(&css_param->dz_config, 2080 arg->dz_config, 2081 sizeof(struct ia_css_dz_config), 2082 from_user)) 2083 return -EFAULT; 2084 if (!atomisp_check_zoom_region(asd, 2085 &css_param->dz_config)) { 2086 dev_err(asd->isp->dev, "crop region error!"); 2087 return -EINVAL; 2088 } 2089 css_param->update_flag.dz_config = 2090 (struct atomisp_dz_config *) 2091 &css_param->dz_config; 2092 } 2093 } 2094 2095 if (arg->nr_config && (from_user || !cur_config->nr_config)) { 2096 if (copy_from_compatible(&css_param->nr_config, arg->nr_config, 2097 sizeof(struct ia_css_nr_config), 2098 from_user)) 2099 return -EFAULT; 2100 css_param->update_flag.nr_config = 2101 (struct atomisp_nr_config *)&css_param->nr_config; 2102 } 2103 2104 if (arg->ee_config && (from_user || !cur_config->ee_config)) { 2105 if (copy_from_compatible(&css_param->ee_config, arg->ee_config, 2106 sizeof(struct ia_css_ee_config), 2107 from_user)) 2108 return -EFAULT; 2109 css_param->update_flag.ee_config = 2110 (struct atomisp_ee_config *)&css_param->ee_config; 2111 } 2112 2113 if (arg->tnr_config && (from_user || !cur_config->tnr_config)) { 2114 if (copy_from_compatible(&css_param->tnr_config, 2115 arg->tnr_config, 2116 sizeof(struct ia_css_tnr_config), 2117 from_user)) 2118 return -EFAULT; 2119 css_param->update_flag.tnr_config = 2120 (struct atomisp_tnr_config *) 2121 &css_param->tnr_config; 2122 } 2123 2124 if (arg->a3a_config && (from_user || !cur_config->a3a_config)) { 2125 if (copy_from_compatible(&css_param->s3a_config, 2126 arg->a3a_config, 2127 sizeof(struct ia_css_3a_config), 2128 from_user)) 2129 return -EFAULT; 2130 css_param->update_flag.a3a_config = 2131 (struct atomisp_3a_config *)&css_param->s3a_config; 2132 } 2133 2134 if (arg->ctc_config && (from_user || !cur_config->ctc_config)) { 2135 if (copy_from_compatible(&css_param->ctc_config, 2136 arg->ctc_config, 2137 sizeof(struct ia_css_ctc_config), 2138 from_user)) 2139 return -EFAULT; 2140 css_param->update_flag.ctc_config = 2141 (struct atomisp_ctc_config *) 2142 &css_param->ctc_config; 2143 } 2144 2145 if (arg->cnr_config && (from_user || !cur_config->cnr_config)) { 2146 if (copy_from_compatible(&css_param->cnr_config, 2147 arg->cnr_config, 2148 sizeof(struct ia_css_cnr_config), 2149 from_user)) 2150 return -EFAULT; 2151 css_param->update_flag.cnr_config = 2152 (struct atomisp_cnr_config *) 2153 &css_param->cnr_config; 2154 } 2155 2156 if (arg->ecd_config && (from_user || !cur_config->ecd_config)) { 2157 if (copy_from_compatible(&css_param->ecd_config, 2158 arg->ecd_config, 2159 sizeof(struct ia_css_ecd_config), 2160 from_user)) 2161 return -EFAULT; 2162 css_param->update_flag.ecd_config = 2163 (struct atomisp_ecd_config *) 2164 &css_param->ecd_config; 2165 } 2166 2167 if (arg->ynr_config && (from_user || !cur_config->ynr_config)) { 2168 if (copy_from_compatible(&css_param->ynr_config, 2169 arg->ynr_config, 2170 sizeof(struct ia_css_ynr_config), 2171 from_user)) 2172 return -EFAULT; 2173 css_param->update_flag.ynr_config = 2174 (struct atomisp_ynr_config *) 2175 &css_param->ynr_config; 2176 } 2177 2178 if (arg->fc_config && (from_user || !cur_config->fc_config)) { 2179 if (copy_from_compatible(&css_param->fc_config, 2180 arg->fc_config, 2181 sizeof(struct ia_css_fc_config), 2182 from_user)) 2183 return -EFAULT; 2184 css_param->update_flag.fc_config = 2185 (struct atomisp_fc_config *)&css_param->fc_config; 2186 } 2187 2188 if (arg->macc_config && (from_user || !cur_config->macc_config)) { 2189 if (copy_from_compatible(&css_param->macc_config, 2190 arg->macc_config, 2191 sizeof(struct ia_css_macc_config), 2192 from_user)) 2193 return -EFAULT; 2194 css_param->update_flag.macc_config = 2195 (struct atomisp_macc_config *) 2196 &css_param->macc_config; 2197 } 2198 2199 if (arg->aa_config && (from_user || !cur_config->aa_config)) { 2200 if (copy_from_compatible(&css_param->aa_config, arg->aa_config, 2201 sizeof(struct ia_css_aa_config), 2202 from_user)) 2203 return -EFAULT; 2204 css_param->update_flag.aa_config = 2205 (struct atomisp_aa_config *)&css_param->aa_config; 2206 } 2207 2208 if (arg->anr_config && (from_user || !cur_config->anr_config)) { 2209 if (copy_from_compatible(&css_param->anr_config, 2210 arg->anr_config, 2211 sizeof(struct ia_css_anr_config), 2212 from_user)) 2213 return -EFAULT; 2214 css_param->update_flag.anr_config = 2215 (struct atomisp_anr_config *) 2216 &css_param->anr_config; 2217 } 2218 2219 if (arg->xnr_config && (from_user || !cur_config->xnr_config)) { 2220 if (copy_from_compatible(&css_param->xnr_config, 2221 arg->xnr_config, 2222 sizeof(struct ia_css_xnr_config), 2223 from_user)) 2224 return -EFAULT; 2225 css_param->update_flag.xnr_config = 2226 (struct atomisp_xnr_config *) 2227 &css_param->xnr_config; 2228 } 2229 2230 if (arg->yuv2rgb_cc_config && 2231 (from_user || !cur_config->yuv2rgb_cc_config)) { 2232 if (copy_from_compatible(&css_param->yuv2rgb_cc_config, 2233 arg->yuv2rgb_cc_config, 2234 sizeof(struct ia_css_cc_config), 2235 from_user)) 2236 return -EFAULT; 2237 css_param->update_flag.yuv2rgb_cc_config = 2238 (struct atomisp_cc_config *) 2239 &css_param->yuv2rgb_cc_config; 2240 } 2241 2242 if (arg->rgb2yuv_cc_config && 2243 (from_user || !cur_config->rgb2yuv_cc_config)) { 2244 if (copy_from_compatible(&css_param->rgb2yuv_cc_config, 2245 arg->rgb2yuv_cc_config, 2246 sizeof(struct ia_css_cc_config), 2247 from_user)) 2248 return -EFAULT; 2249 css_param->update_flag.rgb2yuv_cc_config = 2250 (struct atomisp_cc_config *) 2251 &css_param->rgb2yuv_cc_config; 2252 } 2253 2254 if (arg->macc_table && (from_user || !cur_config->macc_table)) { 2255 if (copy_from_compatible(&css_param->macc_table, 2256 arg->macc_table, 2257 sizeof(struct ia_css_macc_table), 2258 from_user)) 2259 return -EFAULT; 2260 css_param->update_flag.macc_table = 2261 (struct atomisp_macc_table *) 2262 &css_param->macc_table; 2263 } 2264 2265 if (arg->xnr_table && (from_user || !cur_config->xnr_table)) { 2266 if (copy_from_compatible(&css_param->xnr_table, 2267 arg->xnr_table, 2268 sizeof(struct ia_css_xnr_table), 2269 from_user)) 2270 return -EFAULT; 2271 css_param->update_flag.xnr_table = 2272 (struct atomisp_xnr_table *)&css_param->xnr_table; 2273 } 2274 2275 if (arg->r_gamma_table && (from_user || !cur_config->r_gamma_table)) { 2276 if (copy_from_compatible(&css_param->r_gamma_table, 2277 arg->r_gamma_table, 2278 sizeof(struct ia_css_rgb_gamma_table), 2279 from_user)) 2280 return -EFAULT; 2281 css_param->update_flag.r_gamma_table = 2282 (struct atomisp_rgb_gamma_table *) 2283 &css_param->r_gamma_table; 2284 } 2285 2286 if (arg->g_gamma_table && (from_user || !cur_config->g_gamma_table)) { 2287 if (copy_from_compatible(&css_param->g_gamma_table, 2288 arg->g_gamma_table, 2289 sizeof(struct ia_css_rgb_gamma_table), 2290 from_user)) 2291 return -EFAULT; 2292 css_param->update_flag.g_gamma_table = 2293 (struct atomisp_rgb_gamma_table *) 2294 &css_param->g_gamma_table; 2295 } 2296 2297 if (arg->b_gamma_table && (from_user || !cur_config->b_gamma_table)) { 2298 if (copy_from_compatible(&css_param->b_gamma_table, 2299 arg->b_gamma_table, 2300 sizeof(struct ia_css_rgb_gamma_table), 2301 from_user)) 2302 return -EFAULT; 2303 css_param->update_flag.b_gamma_table = 2304 (struct atomisp_rgb_gamma_table *) 2305 &css_param->b_gamma_table; 2306 } 2307 2308 if (arg->anr_thres && (from_user || !cur_config->anr_thres)) { 2309 if (copy_from_compatible(&css_param->anr_thres, arg->anr_thres, 2310 sizeof(struct ia_css_anr_thres), 2311 from_user)) 2312 return -EFAULT; 2313 css_param->update_flag.anr_thres = 2314 (struct atomisp_anr_thres *)&css_param->anr_thres; 2315 } 2316 2317 if (from_user) 2318 css_param->isp_config_id = arg->isp_config_id; 2319 /* 2320 * These configurations are on used by ISP1.x, not for ISP2.x, 2321 * so do not handle them. see comments of ia_css_isp_config. 2322 * 1 cc_config 2323 * 2 ce_config 2324 * 3 de_config 2325 * 4 gc_config 2326 * 5 gamma_table 2327 * 6 ctc_table 2328 * 7 dvs_coefs 2329 */ 2330 return 0; 2331 } 2332 2333 int atomisp_cp_lsc_table(struct atomisp_sub_device *asd, 2334 struct atomisp_shading_table *source_st, 2335 struct atomisp_css_params *css_param, 2336 bool from_user) 2337 { 2338 unsigned int i; 2339 unsigned int len_table; 2340 struct ia_css_shading_table *shading_table; 2341 struct ia_css_shading_table *old_table; 2342 struct atomisp_shading_table *st, dest_st; 2343 2344 if (!source_st) 2345 return 0; 2346 2347 if (!css_param) 2348 return -EINVAL; 2349 2350 if (!from_user && css_param->update_flag.shading_table) 2351 return 0; 2352 2353 if (IS_ISP2401) { 2354 if (copy_from_compatible(&dest_st, source_st, 2355 sizeof(struct atomisp_shading_table), 2356 from_user)) { 2357 dev_err(asd->isp->dev, "copy shading table failed!"); 2358 return -EFAULT; 2359 } 2360 st = &dest_st; 2361 } else { 2362 st = source_st; 2363 } 2364 2365 old_table = css_param->shading_table; 2366 2367 /* user config is to disable the shading table. */ 2368 if (!st->enable) { 2369 /* Generate a minimum table with enable = 0. */ 2370 shading_table = atomisp_css_shading_table_alloc(1, 1); 2371 if (!shading_table) 2372 return -ENOMEM; 2373 shading_table->enable = 0; 2374 goto set_lsc; 2375 } 2376 2377 /* Setting a new table. Validate first - all tables must be set */ 2378 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 2379 if (!st->data[i]) { 2380 dev_err(asd->isp->dev, "shading table validate failed"); 2381 return -EINVAL; 2382 } 2383 } 2384 2385 /* Shading table size per color */ 2386 if (st->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 2387 st->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) { 2388 dev_err(asd->isp->dev, "shading table w/h validate failed!"); 2389 return -EINVAL; 2390 } 2391 2392 shading_table = atomisp_css_shading_table_alloc(st->width, st->height); 2393 if (!shading_table) 2394 return -ENOMEM; 2395 2396 len_table = st->width * st->height * ATOMISP_SC_TYPE_SIZE; 2397 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 2398 if (copy_from_compatible(shading_table->data[i], 2399 st->data[i], len_table, from_user)) { 2400 atomisp_css_shading_table_free(shading_table); 2401 return -EFAULT; 2402 } 2403 } 2404 shading_table->sensor_width = st->sensor_width; 2405 shading_table->sensor_height = st->sensor_height; 2406 shading_table->fraction_bits = st->fraction_bits; 2407 shading_table->enable = st->enable; 2408 2409 /* No need to update shading table if it is the same */ 2410 if (old_table && 2411 old_table->sensor_width == shading_table->sensor_width && 2412 old_table->sensor_height == shading_table->sensor_height && 2413 old_table->width == shading_table->width && 2414 old_table->height == shading_table->height && 2415 old_table->fraction_bits == shading_table->fraction_bits && 2416 old_table->enable == shading_table->enable) { 2417 bool data_is_same = true; 2418 2419 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 2420 if (memcmp(shading_table->data[i], old_table->data[i], 2421 len_table) != 0) { 2422 data_is_same = false; 2423 break; 2424 } 2425 } 2426 2427 if (data_is_same) { 2428 atomisp_css_shading_table_free(shading_table); 2429 return 0; 2430 } 2431 } 2432 2433 set_lsc: 2434 /* set LSC to CSS */ 2435 css_param->shading_table = shading_table; 2436 css_param->update_flag.shading_table = (struct atomisp_shading_table *)shading_table; 2437 asd->params.sc_en = shading_table; 2438 2439 if (old_table) 2440 atomisp_css_shading_table_free(old_table); 2441 2442 return 0; 2443 } 2444 2445 int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd, 2446 struct ia_css_dvs2_coefficients *coefs, 2447 struct atomisp_css_params *css_param, 2448 bool from_user) 2449 { 2450 struct ia_css_dvs_grid_info *cur = 2451 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 2452 int dvs_hor_coef_bytes, dvs_ver_coef_bytes; 2453 struct ia_css_dvs2_coefficients dvs2_coefs; 2454 2455 if (!coefs || !cur) 2456 return 0; 2457 2458 if (!from_user && css_param->update_flag.dvs2_coefs) 2459 return 0; 2460 2461 if (!IS_ISP2401) { 2462 if (sizeof(*cur) != sizeof(coefs->grid) || 2463 memcmp(&coefs->grid, cur, sizeof(coefs->grid))) { 2464 dev_err(asd->isp->dev, "dvs grid mismatch!\n"); 2465 /* 2466 * If the grid info in the argument differs from the current 2467 * grid info, we tell the caller to reset the grid size and 2468 * try again. 2469 */ 2470 return -EAGAIN; 2471 } 2472 2473 if (!coefs->hor_coefs.odd_real || 2474 !coefs->hor_coefs.odd_imag || 2475 !coefs->hor_coefs.even_real || 2476 !coefs->hor_coefs.even_imag || 2477 !coefs->ver_coefs.odd_real || 2478 !coefs->ver_coefs.odd_imag || 2479 !coefs->ver_coefs.even_real || 2480 !coefs->ver_coefs.even_imag) 2481 return -EINVAL; 2482 2483 if (!css_param->dvs2_coeff) { 2484 /* DIS coefficients. */ 2485 css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur); 2486 if (!css_param->dvs2_coeff) 2487 return -ENOMEM; 2488 } 2489 2490 dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes; 2491 dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes; 2492 if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real, 2493 coefs->hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) || 2494 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag, 2495 coefs->hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) || 2496 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real, 2497 coefs->hor_coefs.even_real, dvs_hor_coef_bytes, from_user) || 2498 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag, 2499 coefs->hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) || 2500 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real, 2501 coefs->ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) || 2502 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag, 2503 coefs->ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) || 2504 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real, 2505 coefs->ver_coefs.even_real, dvs_ver_coef_bytes, from_user) || 2506 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag, 2507 coefs->ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) { 2508 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 2509 css_param->dvs2_coeff = NULL; 2510 return -EFAULT; 2511 } 2512 } else { 2513 if (copy_from_compatible(&dvs2_coefs, coefs, 2514 sizeof(struct ia_css_dvs2_coefficients), 2515 from_user)) { 2516 dev_err(asd->isp->dev, "copy dvs2 coef failed"); 2517 return -EFAULT; 2518 } 2519 2520 if (sizeof(*cur) != sizeof(dvs2_coefs.grid) || 2521 memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) { 2522 dev_err(asd->isp->dev, "dvs grid mismatch!\n"); 2523 /* If the grid info in the argument differs from the current 2524 grid info, we tell the caller to reset the grid size and 2525 try again. */ 2526 return -EAGAIN; 2527 } 2528 2529 if (!dvs2_coefs.hor_coefs.odd_real || 2530 !dvs2_coefs.hor_coefs.odd_imag || 2531 !dvs2_coefs.hor_coefs.even_real || 2532 !dvs2_coefs.hor_coefs.even_imag || 2533 !dvs2_coefs.ver_coefs.odd_real || 2534 !dvs2_coefs.ver_coefs.odd_imag || 2535 !dvs2_coefs.ver_coefs.even_real || 2536 !dvs2_coefs.ver_coefs.even_imag) 2537 return -EINVAL; 2538 2539 if (!css_param->dvs2_coeff) { 2540 /* DIS coefficients. */ 2541 css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur); 2542 if (!css_param->dvs2_coeff) 2543 return -ENOMEM; 2544 } 2545 2546 dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes; 2547 dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes; 2548 if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real, 2549 dvs2_coefs.hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) || 2550 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag, 2551 dvs2_coefs.hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) || 2552 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real, 2553 dvs2_coefs.hor_coefs.even_real, dvs_hor_coef_bytes, from_user) || 2554 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag, 2555 dvs2_coefs.hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) || 2556 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real, 2557 dvs2_coefs.ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) || 2558 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag, 2559 dvs2_coefs.ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) || 2560 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real, 2561 dvs2_coefs.ver_coefs.even_real, dvs_ver_coef_bytes, from_user) || 2562 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag, 2563 dvs2_coefs.ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) { 2564 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 2565 css_param->dvs2_coeff = NULL; 2566 return -EFAULT; 2567 } 2568 } 2569 2570 css_param->update_flag.dvs2_coefs = 2571 (struct atomisp_dis_coefficients *)css_param->dvs2_coeff; 2572 return 0; 2573 } 2574 2575 int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd, 2576 struct atomisp_dvs_6axis_config *source_6axis_config, 2577 struct atomisp_css_params *css_param, 2578 bool from_user) 2579 { 2580 struct ia_css_dvs_6axis_config *dvs_6axis_config; 2581 struct ia_css_dvs_6axis_config *old_6axis_config; 2582 struct ia_css_stream *stream = 2583 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream; 2584 struct ia_css_dvs_grid_info *dvs_grid_info = 2585 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 2586 int ret = -EFAULT; 2587 2588 if (!stream) { 2589 dev_err(asd->isp->dev, "%s: internal error!", __func__); 2590 return -EINVAL; 2591 } 2592 2593 if (!source_6axis_config || !dvs_grid_info) 2594 return 0; 2595 2596 if (!dvs_grid_info->enable) 2597 return 0; 2598 2599 if (!from_user && css_param->update_flag.dvs_6axis_config) 2600 return 0; 2601 2602 /* check whether need to reallocate for 6 axis config */ 2603 old_6axis_config = css_param->dvs_6axis; 2604 dvs_6axis_config = old_6axis_config; 2605 2606 if (IS_ISP2401) { 2607 struct ia_css_dvs_6axis_config t_6axis_config; 2608 2609 if (copy_from_compatible(&t_6axis_config, source_6axis_config, 2610 sizeof(struct atomisp_dvs_6axis_config), 2611 from_user)) { 2612 dev_err(asd->isp->dev, "copy morph table failed!"); 2613 return -EFAULT; 2614 } 2615 2616 if (old_6axis_config && 2617 (old_6axis_config->width_y != t_6axis_config.width_y || 2618 old_6axis_config->height_y != t_6axis_config.height_y || 2619 old_6axis_config->width_uv != t_6axis_config.width_uv || 2620 old_6axis_config->height_uv != t_6axis_config.height_uv)) { 2621 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 2622 css_param->dvs_6axis = NULL; 2623 2624 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 2625 if (!dvs_6axis_config) 2626 return -ENOMEM; 2627 } else if (!dvs_6axis_config) { 2628 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 2629 if (!dvs_6axis_config) 2630 return -ENOMEM; 2631 } 2632 2633 dvs_6axis_config->exp_id = t_6axis_config.exp_id; 2634 2635 if (copy_from_compatible(dvs_6axis_config->xcoords_y, 2636 t_6axis_config.xcoords_y, 2637 t_6axis_config.width_y * 2638 t_6axis_config.height_y * 2639 sizeof(*dvs_6axis_config->xcoords_y), 2640 from_user)) 2641 goto error; 2642 if (copy_from_compatible(dvs_6axis_config->ycoords_y, 2643 t_6axis_config.ycoords_y, 2644 t_6axis_config.width_y * 2645 t_6axis_config.height_y * 2646 sizeof(*dvs_6axis_config->ycoords_y), 2647 from_user)) 2648 goto error; 2649 if (copy_from_compatible(dvs_6axis_config->xcoords_uv, 2650 t_6axis_config.xcoords_uv, 2651 t_6axis_config.width_uv * 2652 t_6axis_config.height_uv * 2653 sizeof(*dvs_6axis_config->xcoords_uv), 2654 from_user)) 2655 goto error; 2656 if (copy_from_compatible(dvs_6axis_config->ycoords_uv, 2657 t_6axis_config.ycoords_uv, 2658 t_6axis_config.width_uv * 2659 t_6axis_config.height_uv * 2660 sizeof(*dvs_6axis_config->ycoords_uv), 2661 from_user)) 2662 goto error; 2663 } else { 2664 if (old_6axis_config && 2665 (old_6axis_config->width_y != source_6axis_config->width_y || 2666 old_6axis_config->height_y != source_6axis_config->height_y || 2667 old_6axis_config->width_uv != source_6axis_config->width_uv || 2668 old_6axis_config->height_uv != source_6axis_config->height_uv)) { 2669 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 2670 css_param->dvs_6axis = NULL; 2671 2672 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 2673 if (!dvs_6axis_config) { 2674 ret = -ENOMEM; 2675 goto error; 2676 } 2677 } else if (!dvs_6axis_config) { 2678 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream); 2679 if (!dvs_6axis_config) { 2680 ret = -ENOMEM; 2681 goto error; 2682 } 2683 } 2684 2685 dvs_6axis_config->exp_id = source_6axis_config->exp_id; 2686 2687 if (copy_from_compatible(dvs_6axis_config->xcoords_y, 2688 source_6axis_config->xcoords_y, 2689 source_6axis_config->width_y * 2690 source_6axis_config->height_y * 2691 sizeof(*source_6axis_config->xcoords_y), 2692 from_user)) 2693 goto error; 2694 if (copy_from_compatible(dvs_6axis_config->ycoords_y, 2695 source_6axis_config->ycoords_y, 2696 source_6axis_config->width_y * 2697 source_6axis_config->height_y * 2698 sizeof(*source_6axis_config->ycoords_y), 2699 from_user)) 2700 goto error; 2701 if (copy_from_compatible(dvs_6axis_config->xcoords_uv, 2702 source_6axis_config->xcoords_uv, 2703 source_6axis_config->width_uv * 2704 source_6axis_config->height_uv * 2705 sizeof(*source_6axis_config->xcoords_uv), 2706 from_user)) 2707 goto error; 2708 if (copy_from_compatible(dvs_6axis_config->ycoords_uv, 2709 source_6axis_config->ycoords_uv, 2710 source_6axis_config->width_uv * 2711 source_6axis_config->height_uv * 2712 sizeof(*source_6axis_config->ycoords_uv), 2713 from_user)) 2714 goto error; 2715 } 2716 css_param->dvs_6axis = dvs_6axis_config; 2717 css_param->update_flag.dvs_6axis_config = 2718 (struct atomisp_dvs_6axis_config *)dvs_6axis_config; 2719 return 0; 2720 2721 error: 2722 if (dvs_6axis_config) 2723 ia_css_dvs2_6axis_config_free(dvs_6axis_config); 2724 return ret; 2725 } 2726 2727 int atomisp_cp_morph_table(struct atomisp_sub_device *asd, 2728 struct atomisp_morph_table *source_morph_table, 2729 struct atomisp_css_params *css_param, 2730 bool from_user) 2731 { 2732 int ret = -EFAULT; 2733 unsigned int i; 2734 struct ia_css_morph_table *morph_table; 2735 struct ia_css_morph_table *old_morph_table; 2736 2737 if (!source_morph_table) 2738 return 0; 2739 2740 if (!from_user && css_param->update_flag.morph_table) 2741 return 0; 2742 2743 old_morph_table = css_param->morph_table; 2744 2745 if (IS_ISP2401) { 2746 struct ia_css_morph_table mtbl; 2747 2748 if (copy_from_compatible(&mtbl, source_morph_table, 2749 sizeof(struct atomisp_morph_table), 2750 from_user)) { 2751 dev_err(asd->isp->dev, "copy morph table failed!"); 2752 return -EFAULT; 2753 } 2754 2755 morph_table = atomisp_css_morph_table_allocate( 2756 mtbl.width, 2757 mtbl.height); 2758 if (!morph_table) 2759 return -ENOMEM; 2760 2761 for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { 2762 if (copy_from_compatible(morph_table->coordinates_x[i], 2763 (__force void *)source_morph_table->coordinates_x[i], 2764 mtbl.height * mtbl.width * 2765 sizeof(*morph_table->coordinates_x[i]), 2766 from_user)) 2767 goto error; 2768 2769 if (copy_from_compatible(morph_table->coordinates_y[i], 2770 (__force void *)source_morph_table->coordinates_y[i], 2771 mtbl.height * mtbl.width * 2772 sizeof(*morph_table->coordinates_y[i]), 2773 from_user)) 2774 goto error; 2775 } 2776 } else { 2777 morph_table = atomisp_css_morph_table_allocate( 2778 source_morph_table->width, 2779 source_morph_table->height); 2780 if (!morph_table) { 2781 ret = -ENOMEM; 2782 goto error; 2783 } 2784 2785 for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { 2786 if (copy_from_compatible(morph_table->coordinates_x[i], 2787 (__force void *)source_morph_table->coordinates_x[i], 2788 source_morph_table->height * source_morph_table->width * 2789 sizeof(*source_morph_table->coordinates_x[i]), 2790 from_user)) 2791 goto error; 2792 2793 if (copy_from_compatible(morph_table->coordinates_y[i], 2794 (__force void *)source_morph_table->coordinates_y[i], 2795 source_morph_table->height * source_morph_table->width * 2796 sizeof(*source_morph_table->coordinates_y[i]), 2797 from_user)) 2798 goto error; 2799 } 2800 } 2801 2802 css_param->morph_table = morph_table; 2803 if (old_morph_table) 2804 atomisp_css_morph_table_free(old_morph_table); 2805 css_param->update_flag.morph_table = 2806 (struct atomisp_morph_table *)morph_table; 2807 return 0; 2808 2809 error: 2810 if (morph_table) 2811 atomisp_css_morph_table_free(morph_table); 2812 return ret; 2813 } 2814 2815 int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd, 2816 struct atomisp_parameters *arg, 2817 struct atomisp_css_params *css_param) 2818 { 2819 int ret; 2820 2821 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, false); 2822 if (ret) 2823 return ret; 2824 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, false); 2825 if (ret) 2826 return ret; 2827 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, false); 2828 if (ret) 2829 return ret; 2830 ret = atomisp_css_cp_dvs2_coefs(asd, 2831 (struct ia_css_dvs2_coefficients *)arg->dvs2_coefs, 2832 css_param, false); 2833 if (ret) 2834 return ret; 2835 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config, 2836 css_param, false); 2837 return ret; 2838 } 2839 2840 void atomisp_free_css_parameters(struct atomisp_css_params *css_param) 2841 { 2842 if (css_param->dvs_6axis) { 2843 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis); 2844 css_param->dvs_6axis = NULL; 2845 } 2846 if (css_param->dvs2_coeff) { 2847 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff); 2848 css_param->dvs2_coeff = NULL; 2849 } 2850 if (css_param->shading_table) { 2851 ia_css_shading_table_free(css_param->shading_table); 2852 css_param->shading_table = NULL; 2853 } 2854 if (css_param->morph_table) { 2855 ia_css_morph_table_free(css_param->morph_table); 2856 css_param->morph_table = NULL; 2857 } 2858 } 2859 2860 static void atomisp_move_frame_to_activeq(struct ia_css_frame *frame, 2861 struct atomisp_css_params_with_list *param) 2862 { 2863 struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf); 2864 unsigned long irqflags; 2865 2866 pipe->frame_params[frame->vb.vb2_buf.index] = param; 2867 spin_lock_irqsave(&pipe->irq_lock, irqflags); 2868 list_move_tail(&frame->queue, &pipe->activeq); 2869 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 2870 } 2871 2872 /* 2873 * Check parameter queue list and buffer queue list to find out if matched items 2874 * and then set parameter to CSS and enqueue buffer to CSS. 2875 * Of course, if the buffer in buffer waiting list is not bound to a per-frame 2876 * parameter, it will be enqueued into CSS as long as the per-frame setting 2877 * buffers before it get enqueued. 2878 */ 2879 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe) 2880 { 2881 struct atomisp_sub_device *asd = pipe->asd; 2882 struct ia_css_frame *frame = NULL, *frame_tmp; 2883 struct atomisp_css_params_with_list *param = NULL, *param_tmp; 2884 bool need_to_enqueue_buffer = false; 2885 int i; 2886 2887 lockdep_assert_held(&asd->isp->mutex); 2888 2889 /* 2890 * CSS/FW requires set parameter and enqueue buffer happen after ISP 2891 * is streamon. 2892 */ 2893 if (!asd->streaming) 2894 return; 2895 2896 if (list_empty(&pipe->per_frame_params) || 2897 list_empty(&pipe->buffers_waiting_for_param)) 2898 return; 2899 2900 list_for_each_entry_safe(frame, frame_tmp, 2901 &pipe->buffers_waiting_for_param, queue) { 2902 i = frame->vb.vb2_buf.index; 2903 if (pipe->frame_request_config_id[i]) { 2904 list_for_each_entry_safe(param, param_tmp, 2905 &pipe->per_frame_params, list) { 2906 if (pipe->frame_request_config_id[i] != param->params.isp_config_id) 2907 continue; 2908 2909 list_del(¶m->list); 2910 2911 /* 2912 * clear the request config id as the buffer 2913 * will be handled and enqueued into CSS soon 2914 */ 2915 pipe->frame_request_config_id[i] = 0; 2916 atomisp_move_frame_to_activeq(frame, param); 2917 need_to_enqueue_buffer = true; 2918 break; 2919 } 2920 2921 /* If this is the end, stop further loop */ 2922 if (list_entry_is_head(param, &pipe->per_frame_params, list)) 2923 break; 2924 } else { 2925 atomisp_move_frame_to_activeq(frame, NULL); 2926 need_to_enqueue_buffer = true; 2927 } 2928 } 2929 2930 if (!need_to_enqueue_buffer) 2931 return; 2932 2933 atomisp_qbuffers_to_css(asd); 2934 } 2935 2936 /* 2937 * Function to configure ISP parameters 2938 */ 2939 int atomisp_set_parameters(struct video_device *vdev, 2940 struct atomisp_parameters *arg) 2941 { 2942 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 2943 struct atomisp_sub_device *asd = pipe->asd; 2944 struct atomisp_css_params_with_list *param = NULL; 2945 struct atomisp_css_params *css_param = &asd->params.css_param; 2946 int ret; 2947 2948 lockdep_assert_held(&asd->isp->mutex); 2949 2950 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) { 2951 dev_err(asd->isp->dev, "%s: internal error!\n", __func__); 2952 return -EINVAL; 2953 } 2954 2955 dev_dbg(asd->isp->dev, "set parameter(per_frame_setting %d) isp_config_id %d of %s\n", 2956 arg->per_frame_setting, arg->isp_config_id, vdev->name); 2957 2958 if (arg->per_frame_setting) { 2959 /* 2960 * Per-frame setting enabled, we allocate a new parameter 2961 * buffer to cache the parameters and only when frame buffers 2962 * are ready, the parameters will be set to CSS. 2963 * per-frame setting only works for the main output frame. 2964 */ 2965 param = kvzalloc_obj(*param); 2966 if (!param) 2967 return -ENOMEM; 2968 css_param = ¶m->params; 2969 } 2970 2971 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, true); 2972 if (ret) 2973 goto apply_parameter_failed; 2974 2975 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, true); 2976 if (ret) 2977 goto apply_parameter_failed; 2978 2979 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, true); 2980 if (ret) 2981 goto apply_parameter_failed; 2982 2983 ret = atomisp_css_cp_dvs2_coefs(asd, 2984 (struct ia_css_dvs2_coefficients *)arg->dvs2_coefs, 2985 css_param, true); 2986 if (ret) 2987 goto apply_parameter_failed; 2988 2989 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config, 2990 css_param, true); 2991 if (ret) 2992 goto apply_parameter_failed; 2993 2994 if (!arg->per_frame_setting) { 2995 /* indicate to CSS that we have parameters to be updated */ 2996 asd->params.css_update_params_needed = true; 2997 } else { 2998 list_add_tail(¶m->list, &pipe->per_frame_params); 2999 atomisp_handle_parameter_and_buffer(pipe); 3000 } 3001 3002 return 0; 3003 3004 apply_parameter_failed: 3005 if (css_param) 3006 atomisp_free_css_parameters(css_param); 3007 kvfree(param); 3008 3009 return ret; 3010 } 3011 3012 /* 3013 * Function to set/get isp parameters to isp 3014 */ 3015 int atomisp_param(struct atomisp_sub_device *asd, int flag, 3016 struct atomisp_parm *config) 3017 { 3018 struct ia_css_pipe_config *vp_cfg = 3019 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. 3020 pipe_configs[IA_CSS_PIPE_ID_VIDEO]; 3021 3022 /* Read parameter for 3A binary info */ 3023 if (flag == 0) { 3024 struct ia_css_dvs_grid_info *dvs_grid_info = 3025 atomisp_css_get_dvs_grid_info( 3026 &asd->params.curr_grid_info); 3027 3028 atomisp_curr_user_grid_info(asd, &config->info); 3029 3030 /* 3031 * We always return the resolution and stride even if there is 3032 * no valid metadata. This allows the caller to get the 3033 * information needed to allocate user-space buffers. 3034 */ 3035 config->metadata_config.metadata_height = asd-> 3036 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. 3037 metadata_info.resolution.height; 3038 config->metadata_config.metadata_stride = asd-> 3039 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. 3040 metadata_info.stride; 3041 3042 /* update dvs grid info */ 3043 if (dvs_grid_info) 3044 memcpy(&config->dvs_grid, 3045 dvs_grid_info, 3046 sizeof(struct ia_css_dvs_grid_info)); 3047 3048 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { 3049 config->dvs_envelop.width = 0; 3050 config->dvs_envelop.height = 0; 3051 return 0; 3052 } 3053 3054 /* update dvs envelop info */ 3055 config->dvs_envelop.width = vp_cfg->dvs_envelope.width; 3056 config->dvs_envelop.height = vp_cfg->dvs_envelope.height; 3057 return 0; 3058 } 3059 3060 memcpy(&asd->params.css_param.wb_config, &config->wb_config, 3061 sizeof(struct ia_css_wb_config)); 3062 memcpy(&asd->params.css_param.ob_config, &config->ob_config, 3063 sizeof(struct ia_css_ob_config)); 3064 memcpy(&asd->params.css_param.dp_config, &config->dp_config, 3065 sizeof(struct ia_css_dp_config)); 3066 memcpy(&asd->params.css_param.de_config, &config->de_config, 3067 sizeof(struct ia_css_de_config)); 3068 memcpy(&asd->params.css_param.dz_config, &config->dz_config, 3069 sizeof(struct ia_css_dz_config)); 3070 memcpy(&asd->params.css_param.ce_config, &config->ce_config, 3071 sizeof(struct ia_css_ce_config)); 3072 memcpy(&asd->params.css_param.nr_config, &config->nr_config, 3073 sizeof(struct ia_css_nr_config)); 3074 memcpy(&asd->params.css_param.ee_config, &config->ee_config, 3075 sizeof(struct ia_css_ee_config)); 3076 memcpy(&asd->params.css_param.tnr_config, &config->tnr_config, 3077 sizeof(struct ia_css_tnr_config)); 3078 3079 if (asd->params.color_effect == V4L2_COLORFX_NEGATIVE) { 3080 asd->params.css_param.cc_config.matrix[3] = -config->cc_config.matrix[3]; 3081 asd->params.css_param.cc_config.matrix[4] = -config->cc_config.matrix[4]; 3082 asd->params.css_param.cc_config.matrix[5] = -config->cc_config.matrix[5]; 3083 asd->params.css_param.cc_config.matrix[6] = -config->cc_config.matrix[6]; 3084 asd->params.css_param.cc_config.matrix[7] = -config->cc_config.matrix[7]; 3085 asd->params.css_param.cc_config.matrix[8] = -config->cc_config.matrix[8]; 3086 } 3087 3088 if (asd->params.color_effect != V4L2_COLORFX_SEPIA && 3089 asd->params.color_effect != V4L2_COLORFX_BW) { 3090 memcpy(&asd->params.css_param.cc_config, &config->cc_config, 3091 sizeof(struct ia_css_cc_config)); 3092 asd->params.config.cc_config = &asd->params.css_param.cc_config; 3093 } 3094 3095 asd->params.config.wb_config = &asd->params.css_param.wb_config; 3096 asd->params.config.ob_config = &asd->params.css_param.ob_config; 3097 asd->params.config.de_config = &asd->params.css_param.de_config; 3098 asd->params.config.dz_config = &asd->params.css_param.dz_config; 3099 asd->params.config.ce_config = &asd->params.css_param.ce_config; 3100 asd->params.config.dp_config = &asd->params.css_param.dp_config; 3101 asd->params.config.nr_config = &asd->params.css_param.nr_config; 3102 asd->params.config.ee_config = &asd->params.css_param.ee_config; 3103 asd->params.config.tnr_config = &asd->params.css_param.tnr_config; 3104 asd->params.css_update_params_needed = true; 3105 3106 return 0; 3107 } 3108 3109 /* 3110 * Function to configure color effect of the image 3111 */ 3112 int atomisp_color_effect(struct atomisp_sub_device *asd, int flag, 3113 __s32 *effect) 3114 { 3115 struct ia_css_cc_config *cc_config = NULL; 3116 struct ia_css_macc_table *macc_table = NULL; 3117 struct ia_css_ctc_table *ctc_table = NULL; 3118 int ret = 0; 3119 struct v4l2_control control; 3120 struct atomisp_device *isp = asd->isp; 3121 3122 if (flag == 0) { 3123 *effect = asd->params.color_effect; 3124 return 0; 3125 } 3126 3127 control.id = V4L2_CID_COLORFX; 3128 control.value = *effect; 3129 ret = 3130 v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].sensor->ctrl_handler, 3131 &control); 3132 /* 3133 * if set color effect to sensor successfully, return 3134 * 0 directly. 3135 */ 3136 if (!ret) { 3137 asd->params.color_effect = (u32)*effect; 3138 return 0; 3139 } 3140 3141 if (*effect == asd->params.color_effect) 3142 return 0; 3143 3144 /* 3145 * isp_subdev->params.macc_en should be set to false. 3146 */ 3147 asd->params.macc_en = false; 3148 3149 switch (*effect) { 3150 case V4L2_COLORFX_NONE: 3151 macc_table = &asd->params.css_param.macc_table; 3152 asd->params.macc_en = true; 3153 break; 3154 case V4L2_COLORFX_SEPIA: 3155 cc_config = &sepia_cc_config; 3156 break; 3157 case V4L2_COLORFX_NEGATIVE: 3158 cc_config = &nega_cc_config; 3159 break; 3160 case V4L2_COLORFX_BW: 3161 cc_config = &mono_cc_config; 3162 break; 3163 case V4L2_COLORFX_SKY_BLUE: 3164 macc_table = &blue_macc_table; 3165 asd->params.macc_en = true; 3166 break; 3167 case V4L2_COLORFX_GRASS_GREEN: 3168 macc_table = &green_macc_table; 3169 asd->params.macc_en = true; 3170 break; 3171 case V4L2_COLORFX_SKIN_WHITEN_LOW: 3172 macc_table = &skin_low_macc_table; 3173 asd->params.macc_en = true; 3174 break; 3175 case V4L2_COLORFX_SKIN_WHITEN: 3176 macc_table = &skin_medium_macc_table; 3177 asd->params.macc_en = true; 3178 break; 3179 case V4L2_COLORFX_SKIN_WHITEN_HIGH: 3180 macc_table = &skin_high_macc_table; 3181 asd->params.macc_en = true; 3182 break; 3183 case V4L2_COLORFX_VIVID: 3184 ctc_table = &vivid_ctc_table; 3185 break; 3186 default: 3187 return -EINVAL; 3188 } 3189 atomisp_update_capture_mode(asd); 3190 3191 if (cc_config) 3192 asd->params.config.cc_config = cc_config; 3193 if (macc_table) 3194 asd->params.config.macc_table = macc_table; 3195 if (ctc_table) 3196 atomisp_css_set_ctc_table(asd, ctc_table); 3197 asd->params.color_effect = (u32)*effect; 3198 asd->params.css_update_params_needed = true; 3199 return 0; 3200 } 3201 3202 /* 3203 * Function to configure bad pixel correction 3204 */ 3205 int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag, 3206 __s32 *value) 3207 { 3208 if (flag == 0) { 3209 *value = asd->params.bad_pixel_en; 3210 return 0; 3211 } 3212 asd->params.bad_pixel_en = !!*value; 3213 3214 return 0; 3215 } 3216 3217 /* 3218 * Function to configure bad pixel correction params 3219 */ 3220 int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag, 3221 struct atomisp_dp_config *config) 3222 { 3223 if (flag == 0) { 3224 /* Get bad pixel from current setup */ 3225 if (atomisp_css_get_dp_config(asd, config)) 3226 return -EINVAL; 3227 } else { 3228 /* Set bad pixel to isp parameters */ 3229 memcpy(&asd->params.css_param.dp_config, config, 3230 sizeof(asd->params.css_param.dp_config)); 3231 asd->params.config.dp_config = &asd->params.css_param.dp_config; 3232 asd->params.css_update_params_needed = true; 3233 } 3234 3235 return 0; 3236 } 3237 3238 /* 3239 * Function to enable/disable video image stabilization 3240 */ 3241 int atomisp_video_stable(struct atomisp_sub_device *asd, int flag, 3242 __s32 *value) 3243 { 3244 if (flag == 0) 3245 *value = asd->params.video_dis_en; 3246 else 3247 asd->params.video_dis_en = !!*value; 3248 3249 return 0; 3250 } 3251 3252 /* 3253 * Function to configure fixed pattern noise 3254 */ 3255 int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag, 3256 __s32 *value) 3257 { 3258 if (flag == 0) { 3259 *value = asd->params.fpn_en; 3260 return 0; 3261 } 3262 3263 if (*value == 0) { 3264 asd->params.fpn_en = false; 3265 return 0; 3266 } 3267 3268 /* Add function to get black from sensor with shutter off */ 3269 return 0; 3270 } 3271 3272 static unsigned int 3273 atomisp_bytesperline_to_padded_width(unsigned int bytesperline, 3274 enum ia_css_frame_format format) 3275 { 3276 switch (format) { 3277 case IA_CSS_FRAME_FORMAT_UYVY: 3278 case IA_CSS_FRAME_FORMAT_YUYV: 3279 case IA_CSS_FRAME_FORMAT_RAW: 3280 case IA_CSS_FRAME_FORMAT_RGB565: 3281 return bytesperline / 2; 3282 case IA_CSS_FRAME_FORMAT_RGBA888: 3283 return bytesperline / 4; 3284 /* 3285 * The following cases could be removed, but we leave them 3286 * in to document the formats that are included. 3287 */ 3288 case IA_CSS_FRAME_FORMAT_NV11: 3289 case IA_CSS_FRAME_FORMAT_NV12: 3290 case IA_CSS_FRAME_FORMAT_NV16: 3291 case IA_CSS_FRAME_FORMAT_NV21: 3292 case IA_CSS_FRAME_FORMAT_NV61: 3293 case IA_CSS_FRAME_FORMAT_YV12: 3294 case IA_CSS_FRAME_FORMAT_YV16: 3295 case IA_CSS_FRAME_FORMAT_YUV420: 3296 case IA_CSS_FRAME_FORMAT_YUV420_16: 3297 case IA_CSS_FRAME_FORMAT_YUV422: 3298 case IA_CSS_FRAME_FORMAT_YUV422_16: 3299 case IA_CSS_FRAME_FORMAT_YUV444: 3300 case IA_CSS_FRAME_FORMAT_YUV_LINE: 3301 case IA_CSS_FRAME_FORMAT_PLANAR_RGB888: 3302 case IA_CSS_FRAME_FORMAT_QPLANE6: 3303 case IA_CSS_FRAME_FORMAT_BINARY_8: 3304 default: 3305 return bytesperline; 3306 } 3307 } 3308 3309 static int 3310 atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer *arg, 3311 struct ia_css_frame **result) 3312 { 3313 struct ia_css_frame *res = NULL; 3314 unsigned int padded_width; 3315 enum ia_css_frame_format sh_format; 3316 char *tmp_buf = NULL; 3317 int ret = 0; 3318 3319 sh_format = v4l2_fmt_to_sh_fmt(arg->fmt.pixelformat); 3320 padded_width = atomisp_bytesperline_to_padded_width( 3321 arg->fmt.bytesperline, sh_format); 3322 3323 /* 3324 * Note: the padded width on an ia_css_frame is in elements, not in 3325 * bytes. The RAW frame we use here should always be a 16bit RAW 3326 * frame. This is why we bytesperline/2 is equal to the padded with 3327 */ 3328 if (ia_css_frame_allocate(&res, arg->fmt.width, arg->fmt.height, 3329 sh_format, padded_width, 0)) { 3330 ret = -ENOMEM; 3331 goto err; 3332 } 3333 3334 tmp_buf = vmalloc(arg->fmt.sizeimage); 3335 if (!tmp_buf) { 3336 ret = -ENOMEM; 3337 goto err; 3338 } 3339 if (copy_from_user(tmp_buf, (void __user __force *)arg->base, 3340 arg->fmt.sizeimage)) { 3341 ret = -EFAULT; 3342 goto err; 3343 } 3344 3345 if (hmm_store(res->data, tmp_buf, arg->fmt.sizeimage)) { 3346 ret = -EINVAL; 3347 goto err; 3348 } 3349 3350 err: 3351 if (ret && res) 3352 ia_css_frame_free(res); 3353 vfree(tmp_buf); 3354 if (ret == 0) 3355 *result = res; 3356 return ret; 3357 } 3358 3359 /* 3360 * Function to configure fixed pattern noise table 3361 */ 3362 int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd, 3363 struct v4l2_framebuffer *arg) 3364 { 3365 struct ia_css_frame *raw_black_frame = NULL; 3366 int ret; 3367 3368 if (!arg) 3369 return -EINVAL; 3370 3371 ret = atomisp_v4l2_framebuffer_to_css_frame(arg, &raw_black_frame); 3372 if (ret) 3373 return ret; 3374 3375 ret = sh_css_set_black_frame(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, 3376 raw_black_frame); 3377 ia_css_frame_free(raw_black_frame); 3378 return ret; 3379 } 3380 3381 /* 3382 * Function to configure false color correction 3383 */ 3384 int atomisp_false_color(struct atomisp_sub_device *asd, int flag, 3385 __s32 *value) 3386 { 3387 /* Get nr config from current setup */ 3388 if (flag == 0) { 3389 *value = asd->params.false_color; 3390 return 0; 3391 } 3392 3393 /* Set nr config to isp parameters */ 3394 if (*value) { 3395 asd->params.config.de_config = NULL; 3396 } else { 3397 asd->params.css_param.de_config.pixelnoise = 0; 3398 asd->params.config.de_config = &asd->params.css_param.de_config; 3399 } 3400 asd->params.css_update_params_needed = true; 3401 asd->params.false_color = *value; 3402 return 0; 3403 } 3404 3405 /* 3406 * Function to configure bad pixel correction params 3407 */ 3408 int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag, 3409 struct atomisp_de_config *config) 3410 { 3411 if (flag == 0) { 3412 /* Get false color from current setup */ 3413 if (atomisp_css_get_de_config(asd, config)) 3414 return -EINVAL; 3415 } else { 3416 /* Set false color to isp parameters */ 3417 memcpy(&asd->params.css_param.de_config, config, 3418 sizeof(asd->params.css_param.de_config)); 3419 asd->params.config.de_config = &asd->params.css_param.de_config; 3420 asd->params.css_update_params_needed = true; 3421 } 3422 3423 return 0; 3424 } 3425 3426 /* 3427 * Function to configure white balance params 3428 */ 3429 int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag, 3430 struct atomisp_wb_config *config) 3431 { 3432 if (flag == 0) { 3433 /* Get white balance from current setup */ 3434 if (atomisp_css_get_wb_config(asd, config)) 3435 return -EINVAL; 3436 } else { 3437 /* Set white balance to isp parameters */ 3438 memcpy(&asd->params.css_param.wb_config, config, 3439 sizeof(asd->params.css_param.wb_config)); 3440 asd->params.config.wb_config = &asd->params.css_param.wb_config; 3441 asd->params.css_update_params_needed = true; 3442 } 3443 3444 return 0; 3445 } 3446 3447 int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag, 3448 struct atomisp_3a_config *config) 3449 { 3450 struct atomisp_device *isp = asd->isp; 3451 3452 dev_dbg(isp->dev, ">%s %d\n", __func__, flag); 3453 3454 if (flag == 0) { 3455 /* Get white balance from current setup */ 3456 if (atomisp_css_get_3a_config(asd, config)) 3457 return -EINVAL; 3458 } else { 3459 /* Set white balance to isp parameters */ 3460 memcpy(&asd->params.css_param.s3a_config, config, 3461 sizeof(asd->params.css_param.s3a_config)); 3462 asd->params.config.s3a_config = &asd->params.css_param.s3a_config; 3463 asd->params.css_update_params_needed = true; 3464 } 3465 3466 dev_dbg(isp->dev, "<%s %d\n", __func__, flag); 3467 return 0; 3468 } 3469 3470 /* 3471 * Function to setup digital zoom 3472 */ 3473 int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, 3474 __s32 *value) 3475 { 3476 u32 zoom; 3477 struct atomisp_device *isp = asd->isp; 3478 3479 unsigned int max_zoom = MRFLD_MAX_ZOOM_FACTOR; 3480 3481 if (flag == 0) { 3482 atomisp_css_get_zoom_factor(asd, &zoom); 3483 *value = max_zoom - zoom; 3484 } else { 3485 if (*value < 0) 3486 return -EINVAL; 3487 3488 zoom = max_zoom - min_t(u32, max_zoom - 1, *value); 3489 atomisp_css_set_zoom_factor(asd, zoom); 3490 3491 dev_dbg(isp->dev, "%s, zoom: %d\n", __func__, zoom); 3492 asd->params.css_update_params_needed = true; 3493 } 3494 3495 return 0; 3496 } 3497 3498 static void __atomisp_update_stream_env(struct atomisp_sub_device *asd, 3499 u16 stream_index, struct atomisp_input_stream_info *stream_info) 3500 { 3501 int i; 3502 3503 /* assign virtual channel id return from sensor driver query */ 3504 asd->stream_env[stream_index].ch_id = stream_info->ch_id; 3505 asd->stream_env[stream_index].isys_configs = stream_info->isys_configs; 3506 for (i = 0; i < stream_info->isys_configs; i++) { 3507 asd->stream_env[stream_index].isys_info[i].input_format = 3508 stream_info->isys_info[i].input_format; 3509 asd->stream_env[stream_index].isys_info[i].width = 3510 stream_info->isys_info[i].width; 3511 asd->stream_env[stream_index].isys_info[i].height = 3512 stream_info->isys_info[i].height; 3513 } 3514 } 3515 3516 static void __atomisp_init_stream_info(u16 stream_index, 3517 struct atomisp_input_stream_info *stream_info) 3518 { 3519 int i; 3520 3521 stream_info->enable = 1; 3522 stream_info->stream = stream_index; 3523 stream_info->ch_id = 0; 3524 stream_info->isys_configs = 0; 3525 for (i = 0; i < MAX_STREAMS_PER_CHANNEL; i++) { 3526 stream_info->isys_info[i].input_format = 0; 3527 stream_info->isys_info[i].width = 0; 3528 stream_info->isys_info[i].height = 0; 3529 } 3530 } 3531 3532 static void atomisp_fill_pix_format(struct v4l2_pix_format *f, 3533 u32 width, u32 height, 3534 const struct atomisp_format_bridge *br_fmt) 3535 { 3536 u32 bytes; 3537 3538 f->width = width; 3539 f->height = height; 3540 f->pixelformat = br_fmt->pixelformat; 3541 3542 /* Adding padding to width for bytesperline calculation */ 3543 width = ia_css_frame_pad_width(width, br_fmt->sh_fmt); 3544 bytes = BITS_TO_BYTES(br_fmt->depth * width); 3545 3546 if (br_fmt->planar) 3547 f->bytesperline = width; 3548 else 3549 f->bytesperline = bytes; 3550 3551 f->sizeimage = PAGE_ALIGN(height * bytes); 3552 3553 if (f->field == V4L2_FIELD_ANY) 3554 f->field = V4L2_FIELD_NONE; 3555 3556 /* 3557 * FIXME: do we need to set this up differently, depending on the 3558 * sensor or the pipeline? 3559 */ 3560 f->colorspace = V4L2_COLORSPACE_REC709; 3561 f->ycbcr_enc = V4L2_YCBCR_ENC_709; 3562 f->xfer_func = V4L2_XFER_FUNC_709; 3563 } 3564 3565 /* Get sensor padding values for the non padded width x height resolution */ 3566 void atomisp_get_padding(struct atomisp_device *isp, u32 width, u32 height, 3567 u32 *padding_w, u32 *padding_h) 3568 { 3569 struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr]; 3570 struct v4l2_rect native_rect = input->native_rect; 3571 const struct atomisp_in_fmt_conv *fc = NULL; 3572 u32 min_pad_w = ISP2400_MIN_PAD_W; 3573 u32 min_pad_h = ISP2400_MIN_PAD_H; 3574 struct v4l2_mbus_framefmt *sink; 3575 3576 if (!input->crop_support) { 3577 *padding_w = pad_w; 3578 *padding_h = pad_h; 3579 return; 3580 } 3581 3582 width = min(width, input->active_rect.width); 3583 height = min(height, input->active_rect.height); 3584 3585 if (input->binning_support && width <= (input->active_rect.width / 2) && 3586 height <= (input->active_rect.height / 2)) { 3587 native_rect.width /= 2; 3588 native_rect.height /= 2; 3589 } 3590 3591 *padding_w = min_t(u32, (native_rect.width - width) & ~1, pad_w); 3592 *padding_h = min_t(u32, (native_rect.height - height) & ~1, pad_h); 3593 3594 /* The below minimum padding requirements are for BYT / ISP2400 only */ 3595 if (IS_ISP2401) 3596 return; 3597 3598 sink = atomisp_subdev_get_ffmt(&isp->asd.subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE, 3599 ATOMISP_SUBDEV_PAD_SINK); 3600 if (sink) 3601 fc = atomisp_find_in_fmt_conv(sink->code); 3602 if (!fc) { 3603 dev_warn(isp->dev, "%s: Could not get sensor format\n", __func__); 3604 goto apply_min_padding; 3605 } 3606 3607 /* 3608 * The ISP only supports GRBG for other bayer-orders additional padding 3609 * is used so that the raw sensor data can be cropped to fix the order. 3610 */ 3611 if (fc->bayer_order == IA_CSS_BAYER_ORDER_RGGB || 3612 fc->bayer_order == IA_CSS_BAYER_ORDER_GBRG) 3613 min_pad_w += 2; 3614 3615 if (fc->bayer_order == IA_CSS_BAYER_ORDER_BGGR || 3616 fc->bayer_order == IA_CSS_BAYER_ORDER_GBRG) 3617 min_pad_h += 2; 3618 3619 apply_min_padding: 3620 *padding_w = max_t(u32, *padding_w, min_pad_w); 3621 *padding_h = max_t(u32, *padding_h, min_pad_h); 3622 } 3623 3624 int atomisp_s_sensor_power(struct atomisp_device *isp, unsigned int input, bool on) 3625 { 3626 int ret; 3627 3628 if (isp->inputs[input].sensor_on == on) 3629 return 0; 3630 3631 ret = v4l2_subdev_call(isp->inputs[input].sensor, core, s_power, on); 3632 if (ret && ret != -ENOIOCTLCMD) { 3633 dev_err(isp->dev, "Error setting sensor power %d: %d\n", on, ret); 3634 return ret; 3635 } 3636 3637 isp->inputs[input].sensor_on = on; 3638 return 0; 3639 } 3640 3641 int atomisp_select_input(struct atomisp_device *isp, unsigned int input) 3642 { 3643 unsigned int input_orig = isp->asd.input_curr; 3644 int ret; 3645 3646 /* Power on new sensor */ 3647 ret = atomisp_s_sensor_power(isp, input, 1); 3648 if (ret) 3649 return ret; 3650 3651 isp->asd.input_curr = input; 3652 3653 /* Power off previous sensor */ 3654 if (input != input_orig) 3655 atomisp_s_sensor_power(isp, input_orig, 0); 3656 3657 atomisp_setup_input_links(isp); 3658 return 0; 3659 } 3660 3661 /* 3662 * Ensure the CSI-receiver -> ISP link for input_curr is marked as enabled and 3663 * the other CSI-receiver -> ISP links are disabled. 3664 */ 3665 void atomisp_setup_input_links(struct atomisp_device *isp) 3666 { 3667 struct media_link *link; 3668 3669 lockdep_assert_held(&isp->media_dev.graph_mutex); 3670 3671 for (int i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { 3672 link = media_entity_find_link( 3673 &isp->csi2_port[i].subdev.entity.pads[CSI2_PAD_SOURCE], 3674 &isp->asd.subdev.entity.pads[ATOMISP_SUBDEV_PAD_SINK]); 3675 if (!link) { 3676 dev_err(isp->dev, "Error cannot find CSI2-port[%d] -> ISP link\n", i); 3677 continue; /* Should never happen */ 3678 } 3679 3680 /* 3681 * Modify the flags directly, calling media_entity_setup_link() 3682 * will end up calling atomisp_link_setup() which calls this 3683 * function again leading to endless recursion. 3684 */ 3685 if (isp->sensor_subdevs[i] == isp->inputs[isp->asd.input_curr].csi_remote_source) 3686 link->flags |= MEDIA_LNK_FL_ENABLED; 3687 else 3688 link->flags &= ~MEDIA_LNK_FL_ENABLED; 3689 3690 link->reverse->flags = link->flags; 3691 } 3692 } 3693 3694 static int atomisp_set_sensor_crop_and_fmt(struct atomisp_device *isp, 3695 struct v4l2_mbus_framefmt *ffmt, 3696 int which) 3697 { 3698 struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr]; 3699 struct v4l2_subdev_selection sel = { 3700 .which = which, 3701 .target = V4L2_SEL_TGT_CROP, 3702 .r.width = ffmt->width, 3703 .r.height = ffmt->height, 3704 }; 3705 struct v4l2_subdev_format format = { 3706 .which = which, 3707 .format = *ffmt, 3708 }; 3709 struct v4l2_subdev_state *sd_state; 3710 int ret = 0; 3711 3712 if (!input->sensor) 3713 return -EINVAL; 3714 3715 /* 3716 * Some old sensor drivers already write the registers on set_fmt 3717 * instead of on stream on, power on the sensor now (on newer 3718 * sensor drivers the s_power op is a no-op). 3719 */ 3720 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { 3721 ret = atomisp_s_sensor_power(isp, isp->asd.input_curr, 1); 3722 if (ret) 3723 return ret; 3724 } 3725 3726 sd_state = (which == V4L2_SUBDEV_FORMAT_TRY) ? input->try_sd_state : 3727 input->sensor->active_state; 3728 if (sd_state) 3729 v4l2_subdev_lock_state(sd_state); 3730 3731 if (!input->crop_support) 3732 goto set_fmt; 3733 3734 /* Cropping is done before binning, when binning double the crop rect */ 3735 if (input->binning_support && sel.r.width <= (input->native_rect.width / 2) && 3736 sel.r.height <= (input->native_rect.height / 2)) { 3737 sel.r.width *= 2; 3738 sel.r.height *= 2; 3739 } 3740 3741 /* Clamp to avoid top/left calculations overflowing */ 3742 sel.r.width = min(sel.r.width, input->native_rect.width); 3743 sel.r.height = min(sel.r.height, input->native_rect.height); 3744 3745 sel.r.left = ((input->native_rect.width - sel.r.width) / 2) & ~1; 3746 sel.r.top = ((input->native_rect.height - sel.r.height) / 2) & ~1; 3747 3748 ret = v4l2_subdev_call(input->sensor, pad, set_selection, sd_state, &sel); 3749 if (ret) 3750 dev_err(isp->dev, "Error setting crop to (%d,%d)/%ux%u: %d\n", 3751 sel.r.left, sel.r.top, sel.r.width, sel.r.height, ret); 3752 3753 set_fmt: 3754 if (ret == 0) { 3755 ret = v4l2_subdev_call(input->sensor, pad, set_fmt, sd_state, &format); 3756 dev_dbg(isp->dev, "Set sensor format ret: %d size %dx%d\n", 3757 ret, format.format.width, format.format.height); 3758 } 3759 3760 if (sd_state) 3761 v4l2_subdev_unlock_state(sd_state); 3762 3763 /* Propagate new fmt to sensor ISP */ 3764 if (ret == 0 && which == V4L2_SUBDEV_FORMAT_ACTIVE && input->sensor_isp) { 3765 sd_state = v4l2_subdev_lock_and_get_active_state(input->sensor_isp); 3766 3767 format.pad = SENSOR_ISP_PAD_SINK; 3768 ret = v4l2_subdev_call(input->sensor_isp, pad, set_fmt, sd_state, &format); 3769 dev_dbg(isp->dev, "Set sensor ISP sink format ret: %d size %dx%d\n", 3770 ret, format.format.width, format.format.height); 3771 3772 if (ret == 0) { 3773 format.pad = SENSOR_ISP_PAD_SOURCE; 3774 ret = v4l2_subdev_call(input->sensor_isp, pad, set_fmt, sd_state, &format); 3775 dev_dbg(isp->dev, "Set sensor ISP source format ret: %d size %dx%d\n", 3776 ret, format.format.width, format.format.height); 3777 } 3778 3779 if (sd_state) 3780 v4l2_subdev_unlock_state(sd_state); 3781 } 3782 3783 /* Propagate new fmt to CSI port */ 3784 if (ret == 0 && which == V4L2_SUBDEV_FORMAT_ACTIVE) { 3785 format.pad = CSI2_PAD_SINK; 3786 ret = v4l2_subdev_call(input->csi_port, pad, set_fmt, NULL, &format); 3787 if (ret) 3788 return ret; 3789 } 3790 3791 *ffmt = format.format; 3792 return ret; 3793 } 3794 3795 /* This function looks up the closest available resolution. */ 3796 int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f, 3797 const struct atomisp_format_bridge **fmt_ret, 3798 const struct atomisp_format_bridge **snr_fmt_ret) 3799 { 3800 const struct atomisp_format_bridge *fmt, *snr_fmt; 3801 struct atomisp_sub_device *asd = &isp->asd; 3802 struct v4l2_mbus_framefmt ffmt = { }; 3803 u32 padding_w, padding_h; 3804 int ret; 3805 3806 fmt = atomisp_get_format_bridge(f->pixelformat); 3807 /* Currently, raw formats are broken!!! */ 3808 if (!fmt || fmt->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) { 3809 f->pixelformat = V4L2_PIX_FMT_YUV420; 3810 3811 fmt = atomisp_get_format_bridge(f->pixelformat); 3812 if (!fmt) 3813 return -EINVAL; 3814 } 3815 3816 /* 3817 * The preview pipeline does not support width > 1920. Also limit height 3818 * to avoid sensor drivers still picking a too wide resolution. 3819 */ 3820 if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { 3821 f->width = min(f->width, 1920U); 3822 f->height = min(f->height, 1440U); 3823 } 3824 3825 /* 3826 * atomisp_set_fmt() will set the sensor resolution to the requested 3827 * resolution + padding. Add padding here and remove it again after 3828 * the set_fmt call, like atomisp_set_fmt_to_snr() does. 3829 */ 3830 atomisp_get_padding(isp, f->width, f->height, &padding_w, &padding_h); 3831 v4l2_fill_mbus_format(&ffmt, f, fmt->mbus_code); 3832 ffmt.width += padding_w; 3833 ffmt.height += padding_h; 3834 3835 dev_dbg(isp->dev, "try_mbus_fmt: try %ux%u\n", ffmt.width, ffmt.height); 3836 3837 ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY); 3838 if (ret) 3839 return ret; 3840 3841 dev_dbg(isp->dev, "try_mbus_fmt: got %ux%u\n", ffmt.width, ffmt.height); 3842 3843 snr_fmt = atomisp_get_format_bridge_from_mbus(ffmt.code); 3844 if (!snr_fmt) { 3845 dev_err(isp->dev, "unknown sensor format 0x%8.8x\n", 3846 ffmt.code); 3847 return -EINVAL; 3848 } 3849 3850 f->width = ffmt.width - padding_w; 3851 f->height = ffmt.height - padding_h; 3852 3853 /* 3854 * If the format is jpeg or custom RAW, then the width and height will 3855 * not satisfy the normal atomisp requirements and no need to check 3856 * the below conditions. So just assign to what is being returned from 3857 * the sensor driver. 3858 */ 3859 if (f->pixelformat == V4L2_PIX_FMT_JPEG || 3860 f->pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) 3861 goto out_fill_pix_format; 3862 3863 /* app vs isp */ 3864 f->width = rounddown(clamp_t(u32, f->width, ATOM_ISP_MIN_WIDTH, 3865 ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH); 3866 f->height = rounddown(clamp_t(u32, f->height, ATOM_ISP_MIN_HEIGHT, 3867 ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT); 3868 3869 out_fill_pix_format: 3870 atomisp_fill_pix_format(f, f->width, f->height, fmt); 3871 3872 if (fmt_ret) 3873 *fmt_ret = fmt; 3874 3875 if (snr_fmt_ret) 3876 *snr_fmt_ret = snr_fmt; 3877 3878 return 0; 3879 } 3880 3881 enum mipi_port_id atomisp_port_to_mipi_port(struct atomisp_device *isp, 3882 enum atomisp_camera_port port) 3883 { 3884 switch (port) { 3885 case ATOMISP_CAMERA_PORT_PRIMARY: 3886 return MIPI_PORT0_ID; 3887 case ATOMISP_CAMERA_PORT_SECONDARY: 3888 return MIPI_PORT1_ID; 3889 case ATOMISP_CAMERA_PORT_TERTIARY: 3890 return MIPI_PORT2_ID; 3891 default: 3892 dev_err(isp->dev, "unsupported port: %d\n", port); 3893 return MIPI_PORT0_ID; 3894 } 3895 } 3896 3897 static inline int atomisp_set_sensor_mipi_to_isp( 3898 struct atomisp_sub_device *asd, 3899 enum atomisp_input_stream_id stream_id, 3900 struct camera_mipi_info *mipi_info) 3901 { 3902 struct v4l2_control ctrl; 3903 struct atomisp_device *isp = asd->isp; 3904 struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; 3905 const struct atomisp_in_fmt_conv *fc; 3906 int mipi_freq = 0; 3907 unsigned int input_format, bayer_order; 3908 enum atomisp_input_format metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED; 3909 u32 mipi_port, metadata_width = 0, metadata_height = 0; 3910 3911 ctrl.id = V4L2_CID_LINK_FREQ; 3912 if (v4l2_g_ctrl(input->sensor->ctrl_handler, &ctrl) == 0) 3913 mipi_freq = ctrl.value; 3914 3915 if (asd->stream_env[stream_id].isys_configs == 1) { 3916 input_format = 3917 asd->stream_env[stream_id].isys_info[0].input_format; 3918 atomisp_css_isys_set_format(asd, stream_id, 3919 input_format, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX); 3920 } else if (asd->stream_env[stream_id].isys_configs == 2) { 3921 atomisp_css_isys_two_stream_cfg_update_stream1( 3922 asd, stream_id, 3923 asd->stream_env[stream_id].isys_info[0].input_format, 3924 asd->stream_env[stream_id].isys_info[0].width, 3925 asd->stream_env[stream_id].isys_info[0].height); 3926 3927 atomisp_css_isys_two_stream_cfg_update_stream2( 3928 asd, stream_id, 3929 asd->stream_env[stream_id].isys_info[1].input_format, 3930 asd->stream_env[stream_id].isys_info[1].width, 3931 asd->stream_env[stream_id].isys_info[1].height); 3932 } 3933 3934 /* 3935 * Compatibility for sensors which provide no media bus code 3936 * in s_mbus_framefmt() nor support pad formats. 3937 */ 3938 if (mipi_info && mipi_info->input_format != -1) { 3939 bayer_order = mipi_info->raw_bayer_order; 3940 3941 /* Input stream config is still needs configured */ 3942 /* TODO: Check if this is necessary */ 3943 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 3944 mipi_info->input_format); 3945 if (!fc) 3946 return -EINVAL; 3947 input_format = fc->atomisp_in_fmt; 3948 metadata_format = mipi_info->metadata_format; 3949 metadata_width = mipi_info->metadata_width; 3950 metadata_height = mipi_info->metadata_height; 3951 } else { 3952 struct v4l2_mbus_framefmt *sink; 3953 3954 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 3955 V4L2_SUBDEV_FORMAT_ACTIVE, 3956 ATOMISP_SUBDEV_PAD_SINK); 3957 fc = atomisp_find_in_fmt_conv(sink->code); 3958 if (!fc) 3959 return -EINVAL; 3960 input_format = fc->atomisp_in_fmt; 3961 bayer_order = fc->bayer_order; 3962 } 3963 3964 atomisp_css_input_set_format(asd, stream_id, input_format); 3965 atomisp_css_input_set_bayer_order(asd, stream_id, bayer_order); 3966 3967 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(metadata_format); 3968 if (!fc) 3969 return -EINVAL; 3970 3971 input_format = fc->atomisp_in_fmt; 3972 mipi_port = atomisp_port_to_mipi_port(isp, input->port); 3973 atomisp_css_input_configure_port(asd, mipi_port, 3974 isp->sensor_lanes[mipi_port], 3975 0xffff4, mipi_freq, 3976 input_format, 3977 metadata_width, metadata_height); 3978 return 0; 3979 } 3980 3981 static int configure_pp_input_nop(struct atomisp_sub_device *asd, 3982 unsigned int width, unsigned int height) 3983 { 3984 return 0; 3985 } 3986 3987 static int configure_output_nop(struct atomisp_sub_device *asd, 3988 unsigned int width, unsigned int height, 3989 unsigned int min_width, 3990 enum ia_css_frame_format sh_fmt) 3991 { 3992 return 0; 3993 } 3994 3995 static int get_frame_info_nop(struct atomisp_sub_device *asd, 3996 struct ia_css_frame_info *finfo) 3997 { 3998 return 0; 3999 } 4000 4001 /* 4002 * Resets CSS parameters that depend on input resolution. 4003 * 4004 * Update params like CSS RAW binning, 2ppc mode and pp_input 4005 * which depend on input size, but are not automatically 4006 * handled in CSS when the input resolution is changed. 4007 */ 4008 static int css_input_resolution_changed(struct atomisp_sub_device *asd, 4009 struct v4l2_mbus_framefmt *ffmt) 4010 { 4011 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf; 4012 unsigned int i; 4013 4014 dev_dbg(asd->isp->dev, "%s: to %ux%u\n", __func__, 4015 ffmt->width, ffmt->height); 4016 4017 if (IS_ISP2401) 4018 atomisp_css_input_set_two_pixels_per_clock(asd, false); 4019 else 4020 atomisp_css_input_set_two_pixels_per_clock(asd, true); 4021 4022 /* 4023 * If sensor input changed, which means metadata resolution changed 4024 * together. Release all metadata buffers here to let it re-allocated 4025 * next time in reqbufs. 4026 */ 4027 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 4028 list_for_each_entry_safe(md_buf, _md_buf, &asd->metadata[i], 4029 list) { 4030 atomisp_css_free_metadata_buffer(md_buf); 4031 list_del(&md_buf->list); 4032 kfree(md_buf); 4033 } 4034 } 4035 return 0; 4036 4037 /* 4038 * TODO: atomisp_css_preview_configure_pp_input() not 4039 * reset due to CSS bug tracked as PSI BZ 115124 4040 */ 4041 } 4042 4043 static int atomisp_set_fmt_to_isp(struct video_device *vdev, 4044 struct ia_css_frame_info *output_info, 4045 const struct v4l2_pix_format *pix) 4046 { 4047 struct camera_mipi_info *mipi_info; 4048 struct atomisp_device *isp = video_get_drvdata(vdev); 4049 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; 4050 struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr]; 4051 const struct atomisp_format_bridge *format; 4052 struct v4l2_rect *isp_sink_crop; 4053 enum ia_css_pipe_id pipe_id; 4054 int (*configure_output)(struct atomisp_sub_device *asd, 4055 unsigned int width, unsigned int height, 4056 unsigned int min_width, 4057 enum ia_css_frame_format sh_fmt) = 4058 configure_output_nop; 4059 int (*get_frame_info)(struct atomisp_sub_device *asd, 4060 struct ia_css_frame_info *finfo) = 4061 get_frame_info_nop; 4062 int (*configure_pp_input)(struct atomisp_sub_device *asd, 4063 unsigned int width, unsigned int height) = 4064 configure_pp_input_nop; 4065 const struct atomisp_in_fmt_conv *fc = NULL; 4066 struct v4l2_mbus_framefmt *ffmt; 4067 int ret, i; 4068 4069 isp_sink_crop = atomisp_subdev_get_rect( 4070 &asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE, 4071 ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP); 4072 4073 format = atomisp_get_format_bridge(pix->pixelformat); 4074 if (!format) 4075 return -EINVAL; 4076 4077 mipi_info = atomisp_to_sensor_mipi_info(input->sensor); 4078 4079 if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL, 4080 mipi_info)) 4081 return -EINVAL; 4082 4083 if (mipi_info) 4084 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(mipi_info->input_format); 4085 if (!fc) { 4086 ffmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 4087 V4L2_SUBDEV_FORMAT_ACTIVE, 4088 ATOMISP_SUBDEV_PAD_SINK); 4089 fc = atomisp_find_in_fmt_conv(ffmt->code); 4090 } 4091 if (!fc) 4092 return -EINVAL; 4093 4094 if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW && 4095 raw_output_format_match_input(fc->atomisp_in_fmt, pix->pixelformat)) 4096 return -EINVAL; 4097 4098 /* 4099 * Configure viewfinder also when vfpp is disabled: the 4100 * CSS still requires viewfinder configuration. 4101 */ 4102 { 4103 u32 width, height; 4104 4105 if (pix->width < 640 || pix->height < 480) { 4106 width = pix->width; 4107 height = pix->height; 4108 } else { 4109 width = 640; 4110 height = 480; 4111 } 4112 4113 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO || 4114 asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 4115 atomisp_css_video_configure_viewfinder(asd, width, height, 0, 4116 IA_CSS_FRAME_FORMAT_NV12); 4117 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_STILL_CAPTURE || 4118 asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 4119 atomisp_css_capture_configure_viewfinder(asd, width, height, 0, 4120 IA_CSS_FRAME_FORMAT_NV12); 4121 } 4122 } 4123 4124 atomisp_css_input_set_mode(asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR); 4125 4126 for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) 4127 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipe_extra_configs[i].disable_vf_pp = asd->vfpp->val != ATOMISP_VFPP_ENABLE; 4128 4129 /* ISP2401 new input system need to use copy pipe */ 4130 if (asd->copy_mode) { 4131 pipe_id = IA_CSS_PIPE_ID_COPY; 4132 atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, false); 4133 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 4134 /* video same in continuouscapture and online modes */ 4135 configure_output = atomisp_css_video_configure_output; 4136 get_frame_info = atomisp_css_video_get_output_frame_info; 4137 pipe_id = IA_CSS_PIPE_ID_VIDEO; 4138 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 4139 configure_output = atomisp_css_video_configure_output; 4140 get_frame_info = atomisp_css_video_get_output_frame_info; 4141 pipe_id = IA_CSS_PIPE_ID_VIDEO; 4142 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { 4143 configure_output = atomisp_css_preview_configure_output; 4144 get_frame_info = atomisp_css_preview_get_output_frame_info; 4145 configure_pp_input = atomisp_css_preview_configure_pp_input; 4146 pipe_id = IA_CSS_PIPE_ID_PREVIEW; 4147 } else { 4148 if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) { 4149 atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW); 4150 atomisp_css_enable_dz(asd, false); 4151 } else { 4152 atomisp_update_capture_mode(asd); 4153 } 4154 4155 /* in case of ANR, force capture pipe to offline mode */ 4156 atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, 4157 !asd->params.low_light); 4158 4159 configure_output = atomisp_css_capture_configure_output; 4160 get_frame_info = atomisp_css_capture_get_output_frame_info; 4161 configure_pp_input = atomisp_css_capture_configure_pp_input; 4162 pipe_id = IA_CSS_PIPE_ID_CAPTURE; 4163 4164 if (asd->run_mode->val != ATOMISP_RUN_MODE_STILL_CAPTURE) { 4165 dev_err(isp->dev, 4166 "Need to set the running mode first\n"); 4167 asd->run_mode->val = ATOMISP_RUN_MODE_STILL_CAPTURE; 4168 } 4169 } 4170 4171 if (asd->copy_mode) 4172 ret = atomisp_css_copy_configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, 4173 pix->width, pix->height, 4174 format->planar ? pix->bytesperline : 4175 pix->bytesperline * 8 / format->depth, 4176 format->sh_fmt); 4177 else 4178 ret = configure_output(asd, pix->width, pix->height, 4179 format->planar ? pix->bytesperline : 4180 pix->bytesperline * 8 / format->depth, 4181 format->sh_fmt); 4182 if (ret) { 4183 dev_err(isp->dev, "configure_output %ux%u, format %8.8x\n", 4184 pix->width, pix->height, format->sh_fmt); 4185 return -EINVAL; 4186 } 4187 4188 ret = configure_pp_input(asd, isp_sink_crop->width, isp_sink_crop->height); 4189 if (ret) { 4190 dev_err(isp->dev, "configure_pp_input %ux%u\n", 4191 isp_sink_crop->width, 4192 isp_sink_crop->height); 4193 return -EINVAL; 4194 } 4195 if (asd->copy_mode) 4196 ret = atomisp_css_copy_get_output_frame_info(asd, 4197 ATOMISP_INPUT_STREAM_GENERAL, 4198 output_info); 4199 else 4200 ret = get_frame_info(asd, output_info); 4201 if (ret) { 4202 dev_err(isp->dev, "__get_frame_info %ux%u (padded to %u) returned %d\n", 4203 pix->width, pix->height, pix->bytesperline, ret); 4204 return ret; 4205 } 4206 4207 atomisp_update_grid_info(asd, pipe_id); 4208 return 0; 4209 } 4210 4211 static void atomisp_get_dis_envelop(struct atomisp_sub_device *asd, 4212 unsigned int width, unsigned int height, 4213 unsigned int *dvs_env_w, unsigned int *dvs_env_h) 4214 { 4215 if (asd->params.video_dis_en && 4216 asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 4217 /* envelope is 20% of the output resolution */ 4218 /* 4219 * dvs envelope cannot be round up. 4220 * it would cause ISP timeout and color switch issue 4221 */ 4222 *dvs_env_w = rounddown(width / 5, ATOM_ISP_STEP_WIDTH); 4223 *dvs_env_h = rounddown(height / 5, ATOM_ISP_STEP_HEIGHT); 4224 } 4225 4226 asd->params.dis_proj_data_valid = false; 4227 asd->params.css_update_params_needed = true; 4228 } 4229 4230 static void atomisp_check_copy_mode(struct atomisp_sub_device *asd, 4231 const struct v4l2_pix_format *f) 4232 { 4233 struct v4l2_mbus_framefmt *sink, *src; 4234 4235 if (!IS_ISP2401) { 4236 /* Only used for the new input system */ 4237 asd->copy_mode = false; 4238 return; 4239 } 4240 4241 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 4242 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK); 4243 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 4244 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE); 4245 4246 if (sink->code == src->code && sink->width == f->width && sink->height == f->height) 4247 asd->copy_mode = true; 4248 else 4249 asd->copy_mode = false; 4250 4251 dev_dbg(asd->isp->dev, "copy_mode: %d\n", asd->copy_mode); 4252 } 4253 4254 static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_pix_format *f, 4255 unsigned int dvs_env_w, unsigned int dvs_env_h) 4256 { 4257 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 4258 struct atomisp_sub_device *asd = pipe->asd; 4259 struct atomisp_device *isp = asd->isp; 4260 const struct atomisp_format_bridge *format; 4261 struct v4l2_mbus_framefmt req_ffmt, ffmt = { }; 4262 struct atomisp_input_stream_info *stream_info = 4263 (struct atomisp_input_stream_info *)&ffmt.reserved; 4264 int ret; 4265 4266 format = atomisp_get_format_bridge(f->pixelformat); 4267 if (!format) 4268 return -EINVAL; 4269 4270 v4l2_fill_mbus_format(&ffmt, f, format->mbus_code); 4271 ffmt.height += asd->sink_pad_padding_h + dvs_env_h; 4272 ffmt.width += asd->sink_pad_padding_w + dvs_env_w; 4273 4274 dev_dbg(isp->dev, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n", 4275 ffmt.width, ffmt.height, asd->sink_pad_padding_w, asd->sink_pad_padding_h, 4276 dvs_env_w, dvs_env_h); 4277 4278 __atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info); 4279 4280 req_ffmt = ffmt; 4281 4282 /* Disable dvs if resolution can't be supported by sensor */ 4283 if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 4284 ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY); 4285 if (ret) 4286 return ret; 4287 4288 dev_dbg(isp->dev, "video dis: sensor width: %d, height: %d\n", 4289 ffmt.width, ffmt.height); 4290 4291 if (ffmt.width < req_ffmt.width || 4292 ffmt.height < req_ffmt.height) { 4293 req_ffmt.height -= dvs_env_h; 4294 req_ffmt.width -= dvs_env_w; 4295 ffmt = req_ffmt; 4296 dev_warn(isp->dev, 4297 "can not enable video dis due to sensor limitation."); 4298 asd->params.video_dis_en = false; 4299 } 4300 } 4301 4302 ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_ACTIVE); 4303 if (ret) 4304 return ret; 4305 4306 __atomisp_update_stream_env(asd, ATOMISP_INPUT_STREAM_GENERAL, stream_info); 4307 4308 dev_dbg(isp->dev, "sensor width: %d, height: %d\n", 4309 ffmt.width, ffmt.height); 4310 4311 if (ffmt.width < ATOM_ISP_STEP_WIDTH || 4312 ffmt.height < ATOM_ISP_STEP_HEIGHT) 4313 return -EINVAL; 4314 4315 if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO && 4316 (ffmt.width < req_ffmt.width || ffmt.height < req_ffmt.height)) { 4317 dev_warn(isp->dev, 4318 "can not enable video dis due to sensor limitation."); 4319 asd->params.video_dis_en = false; 4320 } 4321 4322 atomisp_subdev_set_ffmt(&asd->subdev, NULL, 4323 V4L2_SUBDEV_FORMAT_ACTIVE, 4324 ATOMISP_SUBDEV_PAD_SINK, &ffmt); 4325 4326 return css_input_resolution_changed(asd, &ffmt); 4327 } 4328 4329 int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) 4330 { 4331 struct atomisp_device *isp = video_get_drvdata(vdev); 4332 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 4333 struct atomisp_sub_device *asd = pipe->asd; 4334 const struct atomisp_format_bridge *format_bridge; 4335 const struct atomisp_format_bridge *snr_format_bridge; 4336 struct ia_css_frame_info output_info; 4337 unsigned int dvs_env_w = 0, dvs_env_h = 0; 4338 struct v4l2_mbus_framefmt isp_source_fmt = {0}; 4339 struct v4l2_rect isp_sink_crop; 4340 int ret; 4341 4342 ret = atomisp_pipe_check(pipe, true); 4343 if (ret) 4344 return ret; 4345 4346 dev_dbg(isp->dev, 4347 "setting resolution %ux%u bytesperline %u\n", 4348 f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.bytesperline); 4349 4350 /* Ensure that the resolution is equal or below the maximum supported */ 4351 ret = atomisp_try_fmt(isp, &f->fmt.pix, &format_bridge, &snr_format_bridge); 4352 if (ret) 4353 return ret; 4354 4355 pipe->sh_fmt = format_bridge->sh_fmt; 4356 pipe->pix.pixelformat = format_bridge->pixelformat; 4357 4358 atomisp_subdev_get_ffmt(&asd->subdev, NULL, 4359 V4L2_SUBDEV_FORMAT_ACTIVE, 4360 ATOMISP_SUBDEV_PAD_SINK)->code = 4361 snr_format_bridge->mbus_code; 4362 4363 isp_source_fmt.code = format_bridge->mbus_code; 4364 atomisp_subdev_set_ffmt(&asd->subdev, NULL, 4365 V4L2_SUBDEV_FORMAT_ACTIVE, 4366 ATOMISP_SUBDEV_PAD_SOURCE, &isp_source_fmt); 4367 4368 if (atomisp_subdev_format_conversion(asd)) { 4369 atomisp_get_padding(isp, f->fmt.pix.width, f->fmt.pix.height, 4370 &asd->sink_pad_padding_w, &asd->sink_pad_padding_h); 4371 } else { 4372 asd->sink_pad_padding_w = 0; 4373 asd->sink_pad_padding_h = 0; 4374 } 4375 4376 atomisp_get_dis_envelop(asd, f->fmt.pix.width, f->fmt.pix.height, 4377 &dvs_env_w, &dvs_env_h); 4378 4379 ret = atomisp_set_fmt_to_snr(vdev, &f->fmt.pix, dvs_env_w, dvs_env_h); 4380 if (ret) { 4381 dev_warn(isp->dev, 4382 "Set format to sensor failed with %d\n", ret); 4383 return -EINVAL; 4384 } 4385 4386 atomisp_csi_lane_config(isp); 4387 4388 atomisp_check_copy_mode(asd, &f->fmt.pix); 4389 4390 isp_sink_crop = *atomisp_subdev_get_rect(&asd->subdev, NULL, 4391 V4L2_SUBDEV_FORMAT_ACTIVE, 4392 ATOMISP_SUBDEV_PAD_SINK, 4393 V4L2_SEL_TGT_CROP); 4394 4395 /* 4396 * Try to enable YUV downscaling if ISP input is 10 % (either 4397 * width or height) bigger than the desired result. 4398 */ 4399 if (!IS_MOFD || 4400 isp_sink_crop.width * 9 / 10 < f->fmt.pix.width || 4401 isp_sink_crop.height * 9 / 10 < f->fmt.pix.height || 4402 (atomisp_subdev_format_conversion(asd) && 4403 (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO || 4404 asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER))) { 4405 isp_sink_crop.width = f->fmt.pix.width; 4406 isp_sink_crop.height = f->fmt.pix.height; 4407 4408 atomisp_subdev_set_selection(&asd->subdev, NULL, 4409 V4L2_SUBDEV_FORMAT_ACTIVE, 4410 ATOMISP_SUBDEV_PAD_SOURCE, V4L2_SEL_TGT_COMPOSE, 4411 0, &isp_sink_crop); 4412 } else { 4413 struct v4l2_rect main_compose = {0}; 4414 4415 main_compose.width = isp_sink_crop.width; 4416 main_compose.height = 4417 DIV_ROUND_UP(main_compose.width * f->fmt.pix.height, 4418 f->fmt.pix.width); 4419 if (main_compose.height > isp_sink_crop.height) { 4420 main_compose.height = isp_sink_crop.height; 4421 main_compose.width = 4422 DIV_ROUND_UP(main_compose.height * 4423 f->fmt.pix.width, 4424 f->fmt.pix.height); 4425 } 4426 4427 atomisp_subdev_set_selection(&asd->subdev, NULL, 4428 V4L2_SUBDEV_FORMAT_ACTIVE, 4429 ATOMISP_SUBDEV_PAD_SOURCE, 4430 V4L2_SEL_TGT_COMPOSE, 0, 4431 &main_compose); 4432 } 4433 4434 ret = atomisp_set_fmt_to_isp(vdev, &output_info, &f->fmt.pix); 4435 if (ret) { 4436 dev_warn(isp->dev, "Can't set format on ISP. Error %d\n", ret); 4437 return -EINVAL; 4438 } 4439 4440 atomisp_fill_pix_format(&pipe->pix, f->fmt.pix.width, f->fmt.pix.height, format_bridge); 4441 4442 f->fmt.pix = pipe->pix; 4443 4444 dev_dbg(isp->dev, "%s: %dx%d, image size: %d, %d bytes per line\n", 4445 __func__, 4446 f->fmt.pix.width, f->fmt.pix.height, 4447 f->fmt.pix.sizeimage, f->fmt.pix.bytesperline); 4448 4449 return 0; 4450 } 4451 4452 int atomisp_set_shading_table(struct atomisp_sub_device *asd, 4453 struct atomisp_shading_table *user_shading_table) 4454 { 4455 struct ia_css_shading_table *shading_table; 4456 struct ia_css_shading_table *free_table; 4457 unsigned int len_table; 4458 int i; 4459 int ret = 0; 4460 4461 if (!user_shading_table) 4462 return -EINVAL; 4463 4464 if (!user_shading_table->enable) { 4465 asd->params.config.shading_table = NULL; 4466 asd->params.sc_en = false; 4467 return 0; 4468 } 4469 4470 /* If enabling, all tables must be set */ 4471 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 4472 if (!user_shading_table->data[i]) 4473 return -EINVAL; 4474 } 4475 4476 /* Shading table size per color */ 4477 if (user_shading_table->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR || 4478 user_shading_table->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) 4479 return -EINVAL; 4480 4481 shading_table = atomisp_css_shading_table_alloc( 4482 user_shading_table->width, user_shading_table->height); 4483 if (!shading_table) 4484 return -ENOMEM; 4485 4486 len_table = user_shading_table->width * user_shading_table->height * 4487 ATOMISP_SC_TYPE_SIZE; 4488 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) { 4489 ret = copy_from_user(shading_table->data[i], 4490 (void __user *)user_shading_table->data[i], 4491 len_table); 4492 if (ret) { 4493 free_table = shading_table; 4494 ret = -EFAULT; 4495 goto out; 4496 } 4497 } 4498 shading_table->sensor_width = user_shading_table->sensor_width; 4499 shading_table->sensor_height = user_shading_table->sensor_height; 4500 shading_table->fraction_bits = user_shading_table->fraction_bits; 4501 4502 free_table = asd->params.css_param.shading_table; 4503 asd->params.css_param.shading_table = shading_table; 4504 asd->params.config.shading_table = shading_table; 4505 asd->params.sc_en = true; 4506 4507 out: 4508 if (free_table) 4509 atomisp_css_shading_table_free(free_table); 4510 4511 return ret; 4512 } 4513 4514 static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id) 4515 { 4516 struct atomisp_device *isp = asd->isp; 4517 4518 if (!asd->enable_raw_buffer_lock->val) { 4519 dev_warn(isp->dev, "%s Raw Buffer Lock is disable.\n", __func__); 4520 return -EINVAL; 4521 } 4522 if (!asd->streaming) { 4523 dev_err(isp->dev, "%s streaming %d invalid exp_id %d.\n", 4524 __func__, exp_id, asd->streaming); 4525 return -EINVAL; 4526 } 4527 if ((exp_id > ATOMISP_MAX_EXP_ID) || (exp_id <= 0)) { 4528 dev_err(isp->dev, "%s exp_id %d invalid.\n", __func__, exp_id); 4529 return -EINVAL; 4530 } 4531 return 0; 4532 } 4533 4534 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd) 4535 { 4536 unsigned long flags; 4537 4538 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 4539 memset(asd->raw_buffer_bitmap, 0, sizeof(asd->raw_buffer_bitmap)); 4540 asd->raw_buffer_locked_count = 0; 4541 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 4542 } 4543 4544 static int __is_raw_buffer_locked(struct atomisp_sub_device *asd, int exp_id) 4545 { 4546 int *bitmap, bit; 4547 unsigned long flags; 4548 int ret; 4549 4550 if (__checking_exp_id(asd, exp_id)) 4551 return -EINVAL; 4552 4553 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 4554 bit = exp_id % 32; 4555 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 4556 ret = ((*bitmap) & (1 << bit)); 4557 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 4558 return !ret; 4559 } 4560 4561 static int __clear_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) 4562 { 4563 int *bitmap, bit; 4564 unsigned long flags; 4565 4566 if (__is_raw_buffer_locked(asd, exp_id)) 4567 return -EINVAL; 4568 4569 bitmap = asd->raw_buffer_bitmap + exp_id / 32; 4570 bit = exp_id % 32; 4571 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags); 4572 (*bitmap) &= ~(1 << bit); 4573 asd->raw_buffer_locked_count--; 4574 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); 4575 4576 dev_dbg(asd->isp->dev, "%s: exp_id %d, raw_buffer_locked_count %d\n", 4577 __func__, exp_id, asd->raw_buffer_locked_count); 4578 return 0; 4579 } 4580 4581 int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id) 4582 { 4583 struct atomisp_device *isp = asd->isp; 4584 int value = *exp_id; 4585 int ret; 4586 4587 lockdep_assert_held(&isp->mutex); 4588 4589 ret = __is_raw_buffer_locked(asd, value); 4590 if (ret) { 4591 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); 4592 return -EINVAL; 4593 } 4594 4595 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value); 4596 ret = atomisp_css_exp_id_capture(asd, value); 4597 if (ret) { 4598 dev_err(isp->dev, "%s exp_id %d failed.\n", __func__, value); 4599 return -EIO; 4600 } 4601 return 0; 4602 } 4603 4604 int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id) 4605 { 4606 struct atomisp_device *isp = asd->isp; 4607 int value = *exp_id; 4608 int ret; 4609 4610 lockdep_assert_held(&isp->mutex); 4611 4612 ret = __clear_raw_buffer_bitmap(asd, value); 4613 if (ret) { 4614 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); 4615 return -EINVAL; 4616 } 4617 4618 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value); 4619 ret = atomisp_css_exp_id_unlock(asd, value); 4620 if (ret) 4621 dev_err(isp->dev, "%s exp_id %d failed, err %d.\n", 4622 __func__, value, ret); 4623 4624 return ret; 4625 } 4626 4627 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd, 4628 unsigned int *enable) 4629 { 4630 bool value; 4631 4632 if (!enable) 4633 return -EINVAL; 4634 4635 value = *enable > 0; 4636 4637 atomisp_en_dz_capt_pipe(asd, value); 4638 4639 return 0; 4640 } 4641 4642 int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event) 4643 { 4644 if (!event || !asd->streaming) 4645 return -EINVAL; 4646 4647 lockdep_assert_held(&asd->isp->mutex); 4648 4649 dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n", 4650 __func__, *event); 4651 4652 switch (*event) { 4653 case V4L2_EVENT_FRAME_SYNC: 4654 atomisp_sof_event(asd); 4655 break; 4656 case V4L2_EVENT_FRAME_END: 4657 atomisp_eof_event(asd, 0); 4658 break; 4659 case V4L2_EVENT_ATOMISP_3A_STATS_READY: 4660 atomisp_3a_stats_ready_event(asd, 0); 4661 break; 4662 case V4L2_EVENT_ATOMISP_METADATA_READY: 4663 atomisp_metadata_ready_event(asd, 0); 4664 break; 4665 default: 4666 return -EINVAL; 4667 } 4668 4669 return 0; 4670 } 4671