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