2 * Support for Medifield PNW Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
19 #include <linux/firmware.h>
20 #include <linux/pci.h>
21 #include <linux/interrupt.h>
22 #include <linux/kernel.h>
23 #include <linux/kfifo.h>
24 #include <linux/pm_runtime.h>
25 #include <linux/timer.h>
27 #include <asm/iosf_mbi.h>
29 #include <media/v4l2-event.h>
30 #include <media/videobuf-vmalloc.h>
32 #define CREATE_TRACE_POINTS
33 #include "atomisp_trace_event.h"
35 #include "atomisp_cmd.h"
36 #include "atomisp_common.h"
37 #include "atomisp_fops.h"
38 #include "atomisp_internal.h"
39 #include "atomisp_ioctl.h"
40 #include "atomisp-regs.h"
41 #include "atomisp_tables.h"
42 #include "atomisp_acc.h"
43 #include "atomisp_compat.h"
44 #include "atomisp_subdev.h"
45 #include "atomisp_dfs_tables.h"
47 #include "hrt/hive_isp_css_mm_hrt.h"
49 #include "sh_css_hrt.h"
50 #include "sh_css_defs.h"
51 #include "system_global.h"
52 #include "sh_css_internal.h"
53 #include "sh_css_sp.h"
54 #include "gp_device.h"
55 #include "device_access.h"
58 #include "ia_css_types.h"
59 #include "ia_css_stream.h"
60 #include "error_support.h"
64 /* We should never need to run the flash for more than 2 frames.
65 * At 15fps this means 133ms. We set the timeout a bit longer.
66 * Each flash driver is supposed to set its own timeout, but
67 * just in case someone else changed the timeout, we set it
68 * here to make sure we don't damage the flash hardware. */
69 #define FLASH_TIMEOUT 800 /* ms */
74 void __user *user_ptr;
83 * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field.
84 * subdev->priv is set in mrst.c
86 struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd)
88 return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd);
92 * get struct atomisp_video_pipe from v4l2 video_device
94 struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev)
96 return (struct atomisp_video_pipe *)
97 container_of(dev, struct atomisp_video_pipe, vdev);
101 * get struct atomisp_acc_pipe from v4l2 video_device
103 struct atomisp_acc_pipe *atomisp_to_acc_pipe(struct video_device *dev)
105 return (struct atomisp_acc_pipe *)
106 container_of(dev, struct atomisp_acc_pipe, vdev);
109 static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
111 struct v4l2_subdev_frame_interval fi;
112 struct atomisp_device *isp = asd->isp;
114 unsigned short fps = 0;
117 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
118 video, g_frame_interval, &fi);
120 if (!ret && fi.interval.numerator)
121 fps = fi.interval.denominator / fi.interval.numerator;
127 * DFS progress is shown as follows:
128 * 1. Target frequency is calculated according to FPS/Resolution/ISP running
130 * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1
131 * with proper rounding.
132 * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40
133 * to 200MHz in ISPSSPM1.
134 * 4. Wait for FREQVALID to be cleared by P-Unit.
135 * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3.
137 static int write_target_freq_to_hw(struct atomisp_device *isp,
138 unsigned int new_freq)
140 unsigned int ratio, timeout, guar_ratio;
144 if (!isp->hpll_freq) {
145 dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n");
149 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
150 if (isp_sspm1 & ISP_FREQ_VALID_MASK) {
151 dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n");
152 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
153 isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET));
156 ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1;
157 guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1;
159 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
160 isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET);
162 for (i = 0; i < ISP_DFS_TRY_TIMES; i++) {
163 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
165 | ratio << ISP_REQ_FREQ_OFFSET
166 | 1 << ISP_FREQ_VALID_OFFSET
167 | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET);
169 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
171 while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) {
172 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
173 dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n");
183 dev_err(isp->dev, "DFS failed due to HW error.\n");
187 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
189 while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) {
190 iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
191 dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n",
197 dev_err(isp->dev, "DFS target freq is rejected by HW.\n");
203 int atomisp_freq_scaling(struct atomisp_device *isp,
204 enum atomisp_dfs_mode mode,
207 /* FIXME! Only use subdev[0] status yet */
208 struct atomisp_sub_device *asd = &isp->asd[0];
209 const struct atomisp_dfs_config *dfs;
210 unsigned int new_freq;
211 struct atomisp_freq_scaling_rule curr_rules;
213 unsigned short fps = 0;
215 if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP) {
216 dev_err(isp->dev, "DFS cannot proceed due to no power.\n");
220 if ((isp->pdev->device & ATOMISP_PCI_DEVICE_SOC_MASK) ==
221 ATOMISP_PCI_DEVICE_SOC_CHT && ATOMISP_USE_YUVPP(asd))
222 isp->dfs = &dfs_config_cht_soc;
226 if (dfs->lowest_freq == 0 || dfs->max_freq_at_vmin == 0 ||
227 dfs->highest_freq == 0 || dfs->dfs_table_size == 0 ||
229 dev_err(isp->dev, "DFS configuration is invalid.\n");
233 if (mode == ATOMISP_DFS_MODE_LOW) {
234 new_freq = dfs->lowest_freq;
238 if (mode == ATOMISP_DFS_MODE_MAX) {
239 new_freq = dfs->highest_freq;
243 fps = atomisp_get_sensor_fps(asd);
247 curr_rules.width = asd->fmt[asd->capture_pad].fmt.width;
248 curr_rules.height = asd->fmt[asd->capture_pad].fmt.height;
249 curr_rules.fps = fps;
250 curr_rules.run_mode = asd->run_mode->val;
252 * For continuous mode, we need to make the capture setting applied
253 * since preview mode, because there is no chance to do this when
254 * starting image capture.
256 if (asd->continuous_mode->val) {
257 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
258 curr_rules.run_mode = ATOMISP_RUN_MODE_SDV;
260 curr_rules.run_mode =
261 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE;
264 /* search for the target frequency by looping freq rules*/
265 for (i = 0; i < dfs->dfs_table_size; i++) {
266 if (curr_rules.width != dfs->dfs_table[i].width &&
267 dfs->dfs_table[i].width != ISP_FREQ_RULE_ANY)
269 if (curr_rules.height != dfs->dfs_table[i].height &&
270 dfs->dfs_table[i].height != ISP_FREQ_RULE_ANY)
272 if (curr_rules.fps != dfs->dfs_table[i].fps &&
273 dfs->dfs_table[i].fps != ISP_FREQ_RULE_ANY)
275 if (curr_rules.run_mode != dfs->dfs_table[i].run_mode &&
276 dfs->dfs_table[i].run_mode != ISP_FREQ_RULE_ANY)
281 if (i == dfs->dfs_table_size)
282 new_freq = dfs->max_freq_at_vmin;
284 new_freq = dfs->dfs_table[i].isp_freq;
287 dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq);
289 if ((new_freq == isp->sw_contex.running_freq) && !force)
292 dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq);
294 ret = write_target_freq_to_hw(isp, new_freq);
296 isp->sw_contex.running_freq = new_freq;
297 trace_ipu_pstate(new_freq, -1);
303 * reset and restore ISP
305 int atomisp_reset(struct atomisp_device *isp)
307 /* Reset ISP by power-cycling it */
310 dev_dbg(isp->dev, "%s\n", __func__);
311 atomisp_css_suspend(isp);
312 ret = atomisp_runtime_suspend(isp->dev);
314 dev_err(isp->dev, "atomisp_runtime_suspend failed, %d\n", ret);
315 ret = atomisp_mrfld_power_down(isp);
317 dev_err(isp->dev, "can not disable ISP power\n");
319 ret = atomisp_mrfld_power_up(isp);
321 dev_err(isp->dev, "can not enable ISP power\n");
322 ret = atomisp_runtime_resume(isp->dev);
324 dev_err(isp->dev, "atomisp_runtime_resume failed, %d\n", ret);
326 ret = atomisp_css_resume(isp);
328 isp->isp_fatal_error = true;
334 * interrupt disable functions
336 static void disable_isp_irq(enum hrt_isp_css_irq irq)
338 irq_disable_channel(IRQ0_ID, irq);
340 if (irq != hrt_isp_css_irq_sp)
343 cnd_sp_irq_enable(SP0_ID, false);
347 * interrupt clean function
349 static void clear_isp_irq(enum hrt_isp_css_irq irq)
351 irq_clear_all(IRQ0_ID);
354 void atomisp_msi_irq_init(struct atomisp_device *isp, struct pci_dev *dev)
359 pci_read_config_dword(dev, PCI_MSI_CAPID, &msg32);
360 msg32 |= 1 << MSI_ENABLE_BIT;
361 pci_write_config_dword(dev, PCI_MSI_CAPID, msg32);
363 msg32 = (1 << INTR_IER) | (1 << INTR_IIR);
364 pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, msg32);
366 pci_read_config_word(dev, PCI_COMMAND, &msg16);
367 msg16 |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
368 PCI_COMMAND_INTX_DISABLE);
369 pci_write_config_word(dev, PCI_COMMAND, msg16);
372 void atomisp_msi_irq_uninit(struct atomisp_device *isp, struct pci_dev *dev)
377 pci_read_config_dword(dev, PCI_MSI_CAPID, &msg32);
378 msg32 &= ~(1 << MSI_ENABLE_BIT);
379 pci_write_config_dword(dev, PCI_MSI_CAPID, msg32);
382 pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, msg32);
384 pci_read_config_word(dev, PCI_COMMAND, &msg16);
385 msg16 &= ~(PCI_COMMAND_MASTER);
386 pci_write_config_word(dev, PCI_COMMAND, msg16);
389 static void atomisp_sof_event(struct atomisp_sub_device *asd)
391 struct v4l2_event event = {0};
393 event.type = V4L2_EVENT_FRAME_SYNC;
394 event.u.frame_sync.frame_sequence = atomic_read(&asd->sof_count);
396 v4l2_event_queue(asd->subdev.devnode, &event);
399 void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id)
401 struct v4l2_event event = {0};
403 event.type = V4L2_EVENT_FRAME_END;
404 event.u.frame_sync.frame_sequence = exp_id;
406 v4l2_event_queue(asd->subdev.devnode, &event);
409 static void atomisp_3a_stats_ready_event(struct atomisp_sub_device *asd, uint8_t exp_id)
411 struct v4l2_event event = {0};
413 event.type = V4L2_EVENT_ATOMISP_3A_STATS_READY;
414 event.u.frame_sync.frame_sequence = exp_id;
416 v4l2_event_queue(asd->subdev.devnode, &event);
419 static void atomisp_metadata_ready_event(struct atomisp_sub_device *asd,
420 enum atomisp_metadata_type md_type)
422 struct v4l2_event event = {0};
424 event.type = V4L2_EVENT_ATOMISP_METADATA_READY;
425 event.u.data[0] = md_type;
427 v4l2_event_queue(asd->subdev.devnode, &event);
430 static void atomisp_reset_event(struct atomisp_sub_device *asd)
432 struct v4l2_event event = {0};
434 event.type = V4L2_EVENT_ATOMISP_CSS_RESET;
436 v4l2_event_queue(asd->subdev.devnode, &event);
440 static void print_csi_rx_errors(enum ia_css_csi2_port port,
441 struct atomisp_device *isp)
445 atomisp_css_rx_get_irq_info(port, &infos);
447 dev_err(isp->dev, "CSI Receiver port %d errors:\n", port);
448 if (infos & CSS_RX_IRQ_INFO_BUFFER_OVERRUN)
449 dev_err(isp->dev, " buffer overrun");
450 if (infos & CSS_RX_IRQ_INFO_ERR_SOT)
451 dev_err(isp->dev, " start-of-transmission error");
452 if (infos & CSS_RX_IRQ_INFO_ERR_SOT_SYNC)
453 dev_err(isp->dev, " start-of-transmission sync error");
454 if (infos & CSS_RX_IRQ_INFO_ERR_CONTROL)
455 dev_err(isp->dev, " control error");
456 if (infos & CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE)
457 dev_err(isp->dev, " 2 or more ECC errors");
458 if (infos & CSS_RX_IRQ_INFO_ERR_CRC)
459 dev_err(isp->dev, " CRC mismatch");
460 if (infos & CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID)
461 dev_err(isp->dev, " unknown error");
462 if (infos & CSS_RX_IRQ_INFO_ERR_FRAME_SYNC)
463 dev_err(isp->dev, " frame sync error");
464 if (infos & CSS_RX_IRQ_INFO_ERR_FRAME_DATA)
465 dev_err(isp->dev, " frame data error");
466 if (infos & CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT)
467 dev_err(isp->dev, " data timeout");
468 if (infos & CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC)
469 dev_err(isp->dev, " unknown escape command entry");
470 if (infos & CSS_RX_IRQ_INFO_ERR_LINE_SYNC)
471 dev_err(isp->dev, " line sync error");
475 static void clear_irq_reg(struct atomisp_device *isp)
478 pci_read_config_dword(isp->pdev, PCI_INTERRUPT_CTRL, &msg_ret);
479 msg_ret |= 1 << INTR_IIR;
480 pci_write_config_dword(isp->pdev, PCI_INTERRUPT_CTRL, msg_ret);
483 static struct atomisp_sub_device *
484 __get_asd_from_port(struct atomisp_device *isp, mipi_port_ID_t port)
488 /* Check which isp subdev to send eof */
489 for (i = 0; i < isp->num_of_streams; i++) {
490 struct atomisp_sub_device *asd = &isp->asd[i];
491 struct camera_mipi_info *mipi_info;
493 mipi_info = atomisp_to_sensor_mipi_info(
494 isp->inputs[asd->input_curr].camera);
496 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED &&
497 __get_mipi_port(isp, mipi_info->port) == port) {
505 /* interrupt handling function*/
506 irqreturn_t atomisp_isr(int irq, void *dev)
508 struct atomisp_device *isp = (struct atomisp_device *)dev;
509 struct atomisp_sub_device *asd;
510 struct atomisp_css_event eof_event;
511 unsigned int irq_infos = 0;
516 spin_lock_irqsave(&isp->lock, flags);
517 if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP ||
518 isp->css_initialized == false) {
519 spin_unlock_irqrestore(&isp->lock, flags);
522 err = atomisp_css_irq_translate(isp, &irq_infos);
524 spin_unlock_irqrestore(&isp->lock, flags);
528 dev_dbg(isp->dev, "irq:0x%x\n", irq_infos);
532 if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp))
535 for (i = 0; i < isp->num_of_streams; i++) {
538 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
541 * Current SOF only support one stream, so the SOF only valid
542 * either solely one stream is running
544 if (irq_infos & CSS_IRQ_INFO_CSS_RECEIVER_SOF) {
545 atomic_inc(&asd->sof_count);
546 atomisp_sof_event(asd);
548 /* If sequence_temp and sequence are the same
549 * there where no frames lost so we can increase
551 * If not then processing of frame is still in progress
552 * and driver needs to keep old sequence_temp value.
553 * NOTE: There is assumption here that ISP will not
554 * start processing next frame from sensor before old
555 * one is completely done. */
556 if (atomic_read(&asd->sequence) == atomic_read(
557 &asd->sequence_temp))
558 atomic_set(&asd->sequence_temp,
559 atomic_read(&asd->sof_count));
561 if (irq_infos & CSS_IRQ_INFO_EVENTS_READY)
562 atomic_set(&asd->sequence,
563 atomic_read(&asd->sequence_temp));
566 if (irq_infos & CSS_IRQ_INFO_CSS_RECEIVER_SOF)
567 irq_infos &= ~CSS_IRQ_INFO_CSS_RECEIVER_SOF;
569 if ((irq_infos & CSS_IRQ_INFO_INPUT_SYSTEM_ERROR) ||
570 (irq_infos & CSS_IRQ_INFO_IF_ERROR)) {
571 /* handle mipi receiver error */
573 enum ia_css_csi2_port port;
575 for (port = IA_CSS_CSI2_PORT0; port <= IA_CSS_CSI2_PORT2;
577 print_csi_rx_errors(port, isp);
578 atomisp_css_rx_get_irq_info(port, &rx_infos);
579 atomisp_css_rx_clear_irq_info(port, rx_infos);
583 if (irq_infos & IA_CSS_IRQ_INFO_ISYS_EVENTS_READY) {
584 while (ia_css_dequeue_isys_event(&(eof_event.event)) ==
586 /* EOF Event does not have the css_pipe returned */
587 asd = __get_asd_from_port(isp, eof_event.event.port);
589 dev_err(isp->dev, "%s:no subdev.event:%d", __func__,
590 eof_event.event.type);
594 atomisp_eof_event(asd, eof_event.event.exp_id);
595 dev_dbg(isp->dev, "%s EOF exp_id %d, asd %d\n",
596 __func__, eof_event.event.exp_id, asd->index);
599 irq_infos &= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY;
604 spin_unlock_irqrestore(&isp->lock, flags);
606 return IRQ_WAKE_THREAD;
609 spin_unlock_irqrestore(&isp->lock, flags);
614 void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd)
617 memset(asd->s3a_bufs_in_css, 0, sizeof(asd->s3a_bufs_in_css));
618 for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++)
619 memset(asd->metadata_bufs_in_css[i], 0,
620 sizeof(asd->metadata_bufs_in_css[i]));
621 asd->dis_bufs_in_css = 0;
622 asd->video_out_capture.buffers_in_css = 0;
623 asd->video_out_vf.buffers_in_css = 0;
624 asd->video_out_preview.buffers_in_css = 0;
625 asd->video_out_video_capture.buffers_in_css = 0;
629 bool atomisp_buffers_queued(struct atomisp_sub_device *asd)
631 bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe)
635 return asd->video_out_capture.buffers_in_css ||
636 asd->video_out_vf.buffers_in_css ||
637 asd->video_out_preview.buffers_in_css ||
638 asd->video_out_video_capture.buffers_in_css ?
641 return pipe->buffers_in_css ? true : false;
645 /* 0x100000 is the start of dmem inside SP */
646 #define SP_DMEM_BASE 0x100000
648 void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
651 unsigned int data = 0;
652 unsigned int size32 = DIV_ROUND_UP(size, sizeof(u32));
654 dev_dbg(isp->dev, "atomisp_io_base:%p\n", atomisp_io_base);
655 dev_dbg(isp->dev, "%s, addr:0x%x, size: %d, size32: %d\n", __func__,
657 if (size32 * 4 + addr > 0x4000) {
658 dev_err(isp->dev, "illegal size (%d) or addr (0x%x)\n",
662 addr += SP_DMEM_BASE;
664 data = _hrt_master_port_uload_32(addr);
666 dev_dbg(isp->dev, "%s, \t [0x%x]:0x%x\n", __func__, addr, data);
667 addr += sizeof(unsigned int);
669 } while (size32 > 0);
672 static struct videobuf_buffer *atomisp_css_frame_to_vbuf(
673 struct atomisp_video_pipe *pipe, struct atomisp_css_frame *frame)
675 struct videobuf_vmalloc_memory *vm_mem;
676 struct atomisp_css_frame *handle;
679 for (i = 0; pipe->capq.bufs[i]; i++) {
680 vm_mem = pipe->capq.bufs[i]->priv;
681 handle = vm_mem->vaddr;
682 if (handle && handle->data == frame->data)
683 return pipe->capq.bufs[i];
689 static void get_buf_timestamp(struct timeval *tv)
693 tv->tv_sec = ts.tv_sec;
694 tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
697 static void atomisp_flush_video_pipe(struct atomisp_sub_device *asd,
698 struct atomisp_video_pipe *pipe)
700 unsigned long irqflags;
706 for (i = 0; pipe->capq.bufs[i]; i++) {
707 spin_lock_irqsave(&pipe->irq_lock, irqflags);
708 if (pipe->capq.bufs[i]->state == VIDEOBUF_ACTIVE ||
709 pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED) {
710 get_buf_timestamp(&pipe->capq.bufs[i]->ts);
711 pipe->capq.bufs[i]->field_count =
712 atomic_read(&asd->sequence) << 1;
713 dev_dbg(asd->isp->dev, "release buffers on device %s\n",
715 if (pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED)
716 list_del_init(&pipe->capq.bufs[i]->queue);
717 pipe->capq.bufs[i]->state = VIDEOBUF_ERROR;
718 wake_up(&pipe->capq.bufs[i]->done);
720 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
724 /* Returns queued buffers back to video-core */
725 void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd)
727 atomisp_flush_video_pipe(asd, &asd->video_out_capture);
728 atomisp_flush_video_pipe(asd, &asd->video_out_vf);
729 atomisp_flush_video_pipe(asd, &asd->video_out_preview);
730 atomisp_flush_video_pipe(asd, &asd->video_out_video_capture);
733 /* clean out the parameters that did not apply */
734 void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe)
736 struct atomisp_css_params_with_list *param;
738 while (!list_empty(&pipe->per_frame_params)) {
739 param = list_entry(pipe->per_frame_params.next,
740 struct atomisp_css_params_with_list, list);
741 list_del(¶m->list);
742 atomisp_free_css_parameters(¶m->params);
747 /* Re-queue per-frame parameters */
748 static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe)
750 struct atomisp_css_params_with_list *param;
753 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
754 param = pipe->frame_params[i];
756 list_add_tail(¶m->list, &pipe->per_frame_params);
757 pipe->frame_params[i] = NULL;
759 atomisp_handle_parameter_and_buffer(pipe);
762 /* find atomisp_video_pipe with css pipe id, buffer type and atomisp run_mode */
763 static struct atomisp_video_pipe *__atomisp_get_pipe(
764 struct atomisp_sub_device *asd,
765 enum atomisp_input_stream_id stream_id,
766 enum atomisp_css_pipe_id css_pipe_id,
767 enum atomisp_css_buffer_type buf_type)
769 struct atomisp_device *isp = asd->isp;
771 if (css_pipe_id == CSS_PIPE_ID_COPY &&
772 isp->inputs[asd->input_curr].camera_caps->
773 sensor[asd->sensor_curr].stream_num > 1) {
775 case ATOMISP_INPUT_STREAM_PREVIEW:
776 return &asd->video_out_preview;
777 case ATOMISP_INPUT_STREAM_POSTVIEW:
778 return &asd->video_out_vf;
779 case ATOMISP_INPUT_STREAM_VIDEO:
780 return &asd->video_out_video_capture;
781 case ATOMISP_INPUT_STREAM_CAPTURE:
783 return &asd->video_out_capture;
787 /* video is same in online as in continuouscapture mode */
788 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
790 * Disable vf_pp and run CSS in still capture mode. In this
791 * mode, CSS does not cause extra latency with buffering, but
792 * scaling is not available.
794 return &asd->video_out_capture;
795 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
797 * Disable vf_pp and run CSS in video mode. This allows using
798 * ISP scaling but it has one frame delay due to CSS internal
801 return &asd->video_out_video_capture;
802 } else if (css_pipe_id == CSS_PIPE_ID_YUVPP) {
804 * to SOC camera, yuvpp pipe is run for capture/video/SDV/ZSL.
806 if (asd->continuous_mode->val) {
807 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
810 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
811 return &asd->video_out_video_capture;
812 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
813 return &asd->video_out_preview;
814 case CSS_BUFFER_TYPE_OUTPUT_FRAME:
815 return &asd->video_out_capture;
817 return &asd->video_out_vf;
819 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
822 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
823 return &asd->video_out_preview;
824 case CSS_BUFFER_TYPE_OUTPUT_FRAME:
825 return &asd->video_out_capture;
827 return &asd->video_out_vf;
830 } else if (buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME) {
831 switch (asd->run_mode->val) {
832 case ATOMISP_RUN_MODE_VIDEO:
833 return &asd->video_out_video_capture;
834 case ATOMISP_RUN_MODE_PREVIEW:
835 return &asd->video_out_preview;
837 return &asd->video_out_capture;
839 } else if (buf_type == CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
840 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
841 return &asd->video_out_preview;
843 return &asd->video_out_vf;
845 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
846 /* For online video or SDV video pipe. */
847 if (css_pipe_id == CSS_PIPE_ID_VIDEO ||
848 css_pipe_id == CSS_PIPE_ID_COPY) {
849 if (buf_type == CSS_BUFFER_TYPE_OUTPUT_FRAME)
850 return &asd->video_out_video_capture;
851 return &asd->video_out_preview;
853 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
854 /* For online preview or ZSL preview pipe. */
855 if (css_pipe_id == CSS_PIPE_ID_PREVIEW ||
856 css_pipe_id == CSS_PIPE_ID_COPY)
857 return &asd->video_out_preview;
859 /* For capture pipe. */
860 if (buf_type == CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
861 return &asd->video_out_vf;
862 return &asd->video_out_capture;
865 enum atomisp_metadata_type
866 atomisp_get_metadata_type(struct atomisp_sub_device *asd,
867 enum ia_css_pipe_id pipe_id)
869 if (!asd->continuous_mode->val)
870 return ATOMISP_MAIN_METADATA;
872 if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) /* online capture pipe */
873 return ATOMISP_SEC_METADATA;
875 return ATOMISP_MAIN_METADATA;
878 void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
879 enum atomisp_css_buffer_type buf_type,
880 enum atomisp_css_pipe_id css_pipe_id,
881 bool q_buffers, enum atomisp_input_stream_id stream_id)
883 struct videobuf_buffer *vb = NULL;
884 struct atomisp_video_pipe *pipe = NULL;
885 struct atomisp_css_buffer buffer;
886 bool requeue = false;
888 unsigned long irqflags;
889 struct atomisp_css_frame *frame = NULL;
890 struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp;
891 struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp;
892 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp;
893 enum atomisp_metadata_type md_type;
894 struct atomisp_device *isp = asd->isp;
895 struct v4l2_control ctrl;
897 bool reset_wdt_timer = false;
901 buf_type != CSS_BUFFER_TYPE_METADATA &&
902 buf_type != CSS_BUFFER_TYPE_3A_STATISTICS &&
903 buf_type != CSS_BUFFER_TYPE_DIS_STATISTICS &&
904 buf_type != CSS_BUFFER_TYPE_OUTPUT_FRAME &&
905 buf_type != CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME &&
906 buf_type != CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME &&
907 buf_type != CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME &&
908 buf_type != CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
909 dev_err(isp->dev, "%s, unsupported buffer type: %d\n",
914 memset(&buffer, 0, sizeof(struct atomisp_css_buffer));
915 buffer.css_buffer.type = buf_type;
916 err = atomisp_css_dequeue_buffer(asd, stream_id, css_pipe_id,
920 "atomisp_css_dequeue_buffer failed: 0x%x\n", err);
924 /* need to know the atomisp pipe for frame buffers */
925 pipe = __atomisp_get_pipe(asd, stream_id, css_pipe_id, buf_type);
927 dev_err(isp->dev, "error getting atomisp pipe\n");
932 case CSS_BUFFER_TYPE_3A_STATISTICS:
933 list_for_each_entry_safe(s3a_buf, _s3a_buf_tmp,
934 &asd->s3a_stats_in_css, list) {
935 if (s3a_buf->s3a_data ==
936 buffer.css_buffer.data.stats_3a) {
937 list_del_init(&s3a_buf->list);
938 list_add_tail(&s3a_buf->list,
939 &asd->s3a_stats_ready);
944 asd->s3a_bufs_in_css[css_pipe_id]--;
945 atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id);
946 dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n",
947 __func__, s3a_buf->s3a_data->exp_id);
949 case CSS_BUFFER_TYPE_METADATA:
953 md_type = atomisp_get_metadata_type(asd, css_pipe_id);
954 list_for_each_entry_safe(md_buf, _md_buf_tmp,
955 &asd->metadata_in_css[md_type], list) {
956 if (md_buf->metadata ==
957 buffer.css_buffer.data.metadata) {
958 list_del_init(&md_buf->list);
959 list_add_tail(&md_buf->list,
960 &asd->metadata_ready[md_type]);
964 asd->metadata_bufs_in_css[stream_id][css_pipe_id]--;
965 atomisp_metadata_ready_event(asd, md_type);
966 dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n",
967 __func__, md_buf->metadata->exp_id);
969 case CSS_BUFFER_TYPE_DIS_STATISTICS:
970 list_for_each_entry_safe(dis_buf, _dis_buf_tmp,
971 &asd->dis_stats_in_css, list) {
972 if (dis_buf->dis_data ==
973 buffer.css_buffer.data.stats_dvs) {
974 spin_lock_irqsave(&asd->dis_stats_lock,
976 list_del_init(&dis_buf->list);
977 list_add(&dis_buf->list, &asd->dis_stats);
978 asd->params.dis_proj_data_valid = true;
979 spin_unlock_irqrestore(&asd->dis_stats_lock,
984 asd->dis_bufs_in_css--;
985 dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n",
986 __func__, dis_buf->dis_data->exp_id);
988 case CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
989 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
991 reset_wdt_timer = true;
993 pipe->buffers_in_css--;
994 frame = buffer.css_buffer.data.frame;
1003 * YUVPP doesn't set postview exp_id correctlly in SDV mode.
1004 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1006 if (IS_BYT && buf_type == CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME &&
1007 asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd))
1008 frame->exp_id = (asd->postview_exp_id++) %
1009 (ATOMISP_MAX_EXP_ID + 1);
1011 dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n",
1012 __func__, frame->exp_id);
1013 if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
1014 if (frame->flash_state
1015 == CSS_FRAME_FLASH_STATE_PARTIAL)
1016 dev_dbg(isp->dev, "%s thumb partially flashed\n",
1018 else if (frame->flash_state
1019 == CSS_FRAME_FLASH_STATE_FULL)
1020 dev_dbg(isp->dev, "%s thumb completely flashed\n",
1023 dev_dbg(isp->dev, "%s thumb no flash in this frame\n",
1026 vb = atomisp_css_frame_to_vbuf(pipe, frame);
1029 pipe->frame_config_id[vb->i] = frame->isp_config_id;
1030 if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE &&
1031 asd->pending_capture_request > 0) {
1032 err = atomisp_css_offline_capture_configure(asd,
1033 asd->params.offline_parm.num_captures,
1034 asd->params.offline_parm.skip_frames,
1035 asd->params.offline_parm.offset);
1037 asd->pending_capture_request--;
1038 dev_dbg(isp->dev, "Trigger capture again for new buffer. err=%d\n",
1041 asd->pending_capture_request--;
1042 asd->re_trigger_capture = false;
1043 dev_dbg(isp->dev, "Trigger capture again for new buffer. err=%d\n",
1046 asd->re_trigger_capture = true;
1051 case CSS_BUFFER_TYPE_OUTPUT_FRAME:
1052 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
1054 reset_wdt_timer = true;
1056 pipe->buffers_in_css--;
1057 frame = buffer.css_buffer.data.frame;
1067 * YUVPP doesn't set preview exp_id correctlly in ZSL mode.
1068 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1070 if (IS_BYT && buf_type == CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME &&
1071 asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd))
1072 frame->exp_id = (asd->preview_exp_id++) %
1073 (ATOMISP_MAX_EXP_ID + 1);
1075 dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n",
1076 __func__, frame->exp_id);
1077 vb = atomisp_css_frame_to_vbuf(pipe, frame);
1083 /* free the parameters */
1084 if (pipe->frame_params[vb->i]) {
1085 if (asd->params.dvs_6axis ==
1086 pipe->frame_params[vb->i]->params.dvs_6axis)
1087 asd->params.dvs_6axis = NULL;
1088 atomisp_free_css_parameters(
1089 &pipe->frame_params[vb->i]->params);
1090 kvfree(pipe->frame_params[vb->i]);
1091 pipe->frame_params[vb->i] = NULL;
1094 pipe->frame_config_id[vb->i] = frame->isp_config_id;
1095 ctrl.id = V4L2_CID_FLASH_MODE;
1096 if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
1097 if (frame->flash_state
1098 == CSS_FRAME_FLASH_STATE_PARTIAL) {
1099 asd->frame_status[vb->i] =
1100 ATOMISP_FRAME_STATUS_FLASH_PARTIAL;
1101 dev_dbg(isp->dev, "%s partially flashed\n",
1103 } else if (frame->flash_state
1104 == CSS_FRAME_FLASH_STATE_FULL) {
1105 asd->frame_status[vb->i] =
1106 ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
1107 asd->params.num_flash_frames--;
1108 dev_dbg(isp->dev, "%s completely flashed\n",
1111 asd->frame_status[vb->i] =
1112 ATOMISP_FRAME_STATUS_OK;
1114 "%s no flash in this frame\n",
1118 /* Check if flashing sequence is done */
1119 if (asd->frame_status[vb->i] ==
1120 ATOMISP_FRAME_STATUS_FLASH_EXPOSED)
1121 asd->params.flash_state = ATOMISP_FLASH_DONE;
1122 } else if (isp->flash) {
1123 if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) ==
1124 0 && ctrl.value == ATOMISP_FLASH_MODE_TORCH) {
1125 ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY;
1126 if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl)
1127 == 0 && ctrl.value > 0) {
1128 asd->frame_status[vb->i] =
1129 ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
1131 asd->frame_status[vb->i] =
1132 ATOMISP_FRAME_STATUS_OK;
1135 asd->frame_status[vb->i] =
1136 ATOMISP_FRAME_STATUS_OK;
1138 asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK;
1141 asd->params.last_frame_status = asd->frame_status[vb->i];
1143 if (asd->continuous_mode->val) {
1144 if (css_pipe_id == CSS_PIPE_ID_PREVIEW ||
1145 css_pipe_id == CSS_PIPE_ID_VIDEO) {
1146 asd->latest_preview_exp_id = frame->exp_id;
1147 } else if (css_pipe_id ==
1148 CSS_PIPE_ID_CAPTURE) {
1149 if (asd->run_mode->val ==
1150 ATOMISP_RUN_MODE_VIDEO)
1151 dev_dbg(isp->dev, "SDV capture raw buffer id: %u\n",
1154 dev_dbg(isp->dev, "ZSL capture raw buffer id: %u\n",
1159 * Only after enabled the raw buffer lock
1160 * and in continuous mode.
1161 * in preview/video pipe, each buffer will
1162 * be locked automatically, so record it here.
1164 if (((css_pipe_id == CSS_PIPE_ID_PREVIEW) ||
1165 (css_pipe_id == CSS_PIPE_ID_VIDEO)) &&
1166 asd->enable_raw_buffer_lock->val &&
1167 asd->continuous_mode->val) {
1168 atomisp_set_raw_buffer_bitmap(asd, frame->exp_id);
1169 WARN_ON(frame->exp_id > ATOMISP_MAX_EXP_ID);
1172 if (asd->params.css_update_params_needed) {
1173 atomisp_apply_css_parameters(asd,
1174 &asd->params.css_param);
1175 if (asd->params.css_param.update_flag.dz_config)
1176 atomisp_css_set_dz_config(asd,
1177 &asd->params.css_param.dz_config);
1178 /* New global dvs 6axis config should be blocked
1179 * here if there's a buffer with per-frame parameters
1180 * pending in CSS frame buffer queue.
1181 * This is to aviod zooming vibration since global
1182 * parameters take effect immediately while
1183 * per-frame parameters are taken after previous
1184 * buffers in CSS got processed.
1186 if (asd->params.dvs_6axis)
1187 atomisp_css_set_dvs_6axis(asd,
1188 asd->params.dvs_6axis);
1190 asd->params.css_update_params_needed = false;
1191 /* The update flag should not be cleaned here
1192 * since it is still going to be used to make up
1193 * following per-frame parameters.
1194 * This will introduce more copy work since each
1195 * time when updating global parameters, the whole
1196 * parameter set are applied.
1197 * FIXME: A new set of parameter copy functions can
1198 * be added to make up per-frame parameters based on
1199 * solid structures stored in asd->params.css_param
1200 * instead of using shadow pointers in update flag.
1202 atomisp_css_update_isp_params(asd);
1209 get_buf_timestamp(&vb->ts);
1210 vb->field_count = atomic_read(&asd->sequence) << 1;
1211 /*mark videobuffer done for dequeue*/
1212 spin_lock_irqsave(&pipe->irq_lock, irqflags);
1213 vb->state = !error ? VIDEOBUF_DONE : VIDEOBUF_ERROR;
1214 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
1217 * Frame capture done, wake up any process block on
1218 * current active buffer
1219 * possibly hold by videobuf_dqbuf()
1224 atomic_set(&pipe->wdt_count, 0);
1227 * Requeue should only be done for 3a and dis buffers.
1228 * Queue/dequeue order will change if driver recycles image buffers.
1231 err = atomisp_css_queue_buffer(asd,
1232 stream_id, css_pipe_id,
1235 dev_err(isp->dev, "%s, q to css fails: %d\n",
1239 if (!error && q_buffers)
1240 atomisp_qbuffers_to_css(asd);
1243 /* If there are no buffers queued then
1244 * delete wdt timer. */
1245 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
1247 if (!atomisp_buffers_queued_pipe(pipe))
1248 atomisp_wdt_stop_pipe(pipe, false);
1249 else if (reset_wdt_timer)
1250 /* SOF irq should not reset wdt timer. */
1251 atomisp_wdt_refresh_pipe(pipe,
1252 ATOMISP_WDT_KEEP_CURRENT_DELAY);
1256 void atomisp_delayed_init_work(struct work_struct *work)
1258 struct atomisp_sub_device *asd = container_of(work,
1259 struct atomisp_sub_device,
1262 * to SOC camera, use yuvpp pipe and no support continuous mode.
1264 if (!ATOMISP_USE_YUVPP(asd)) {
1265 struct v4l2_event event = {0};
1267 atomisp_css_allocate_continuous_frames(false, asd);
1268 atomisp_css_update_continuous_frames(asd);
1270 event.type = V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE;
1271 v4l2_event_queue(asd->subdev.devnode, &event);
1274 /* signal streamon after delayed init is done */
1275 asd->delayed_init = ATOMISP_DELAYED_INIT_DONE;
1276 complete(&asd->init_done);
1279 static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout)
1281 enum atomisp_css_pipe_id css_pipe_id;
1282 bool stream_restart[MAX_STREAM_NUM] = {0};
1283 bool depth_mode = false;
1284 int i, ret, depth_cnt = 0;
1286 if (!isp->sw_contex.file_input)
1287 atomisp_css_irq_enable(isp,
1288 CSS_IRQ_INFO_CSS_RECEIVER_SOF, false);
1290 BUG_ON(isp->num_of_streams > MAX_STREAM_NUM);
1292 for (i = 0; i < isp->num_of_streams; i++) {
1293 struct atomisp_sub_device *asd = &isp->asd[i];
1294 struct ia_css_pipeline *acc_pipeline;
1295 struct ia_css_pipe *acc_pipe = NULL;
1297 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED &&
1298 !asd->stream_prepared)
1302 * AtomISP::waitStageUpdate is blocked when WDT happens.
1303 * By calling acc_done() for all loaded fw_handles,
1304 * HAL will be unblocked.
1306 acc_pipe = asd->stream_env[i].pipes[CSS_PIPE_ID_ACC];
1307 if (acc_pipe != NULL) {
1308 acc_pipeline = ia_css_pipe_get_pipeline(acc_pipe);
1310 struct ia_css_pipeline_stage *stage;
1311 for (stage = acc_pipeline->stages; stage;
1312 stage = stage->next) {
1313 const struct ia_css_fw_info *fw;
1314 fw = stage->firmware;
1315 atomisp_acc_done(asd, fw->handle);
1322 if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED)
1323 cancel_work_sync(&asd->delayed_init_work);
1325 complete(&asd->init_done);
1326 asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED;
1328 stream_restart[asd->index] = true;
1330 asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING;
1332 /* stream off sensor */
1333 ret = v4l2_subdev_call(
1334 isp->inputs[asd->input_curr].
1335 camera, video, s_stream, 0);
1338 "can't stop streaming on sensor!\n");
1340 atomisp_acc_unload_extensions(asd);
1342 atomisp_clear_css_buffer_counters(asd);
1344 css_pipe_id = atomisp_get_css_pipe_id(asd);
1345 atomisp_css_stop(asd, css_pipe_id, true);
1347 asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
1349 asd->preview_exp_id = 1;
1350 asd->postview_exp_id = 1;
1351 /* notify HAL the CSS reset */
1353 "send reset event to %s\n", asd->subdev.devnode->name);
1354 atomisp_reset_event(asd);
1358 disable_isp_irq(hrt_isp_css_irq_sp);
1359 clear_isp_irq(hrt_isp_css_irq_sp);
1361 /* Set the SRSE to 3 before resetting */
1362 pci_write_config_dword(isp->pdev, PCI_I_CONTROL, isp->saved_regs.i_control |
1363 MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK);
1365 /* reset ISP and restore its state */
1366 isp->isp_timeout = true;
1368 isp->isp_timeout = false;
1371 for (i = 0; i < isp->num_of_streams; i++) {
1372 if (isp->asd[i].depth_mode->val)
1377 for (i = 0; i < isp->num_of_streams; i++) {
1378 struct atomisp_sub_device *asd = &isp->asd[i];
1380 if (!stream_restart[i])
1383 if (isp->inputs[asd->input_curr].type != FILE_INPUT)
1384 atomisp_css_input_set_mode(asd,
1385 CSS_INPUT_MODE_SENSOR);
1387 css_pipe_id = atomisp_get_css_pipe_id(asd);
1388 if (atomisp_css_start(asd, css_pipe_id, true))
1390 "start SP failed, so do not set streaming to be enable!\n");
1392 asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED;
1394 atomisp_csi2_configure(asd);
1397 if (!isp->sw_contex.file_input) {
1398 atomisp_css_irq_enable(isp, CSS_IRQ_INFO_CSS_RECEIVER_SOF,
1399 atomisp_css_valid_sof(isp));
1401 if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0)
1402 dev_dbg(isp->dev, "dfs failed!\n");
1404 if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, true) < 0)
1405 dev_dbg(isp->dev, "dfs failed!\n");
1408 for (i = 0; i < isp->num_of_streams; i++) {
1409 struct atomisp_sub_device *asd;
1413 if (!stream_restart[i])
1416 if (asd->continuous_mode->val &&
1417 asd->delayed_init == ATOMISP_DELAYED_INIT_NOT_QUEUED) {
1418 reinit_completion(&asd->init_done);
1419 asd->delayed_init = ATOMISP_DELAYED_INIT_QUEUED;
1420 queue_work(asd->delayed_init_workq,
1421 &asd->delayed_init_work);
1424 * dequeueing buffers is not needed. CSS will recycle
1425 * buffers that it has.
1427 atomisp_flush_bufs_and_wakeup(asd);
1429 /* Requeue unprocessed per-frame parameters. */
1430 atomisp_recover_params_queue(&asd->video_out_capture);
1431 atomisp_recover_params_queue(&asd->video_out_preview);
1432 atomisp_recover_params_queue(&asd->video_out_video_capture);
1434 if ((asd->depth_mode->val) &&
1435 (depth_cnt == ATOMISP_DEPTH_SENSOR_STREAMON_COUNT)) {
1440 ret = v4l2_subdev_call(
1441 isp->inputs[asd->input_curr].camera, video,
1445 "can't start streaming on sensor!\n");
1450 if (atomisp_stream_on_master_slave_sensor(isp, true))
1452 "master slave sensor stream on failed!\n");
1456 void atomisp_wdt_work(struct work_struct *work)
1458 struct atomisp_device *isp = container_of(work, struct atomisp_device,
1462 unsigned int pipe_wdt_cnt[MAX_STREAM_NUM][4] = { {0} };
1463 bool css_recover = true;
1466 rt_mutex_lock(&isp->mutex);
1467 if (!atomisp_streaming_count(isp)) {
1468 atomic_set(&isp->wdt_work_queued, 0);
1469 rt_mutex_unlock(&isp->mutex);
1474 dev_err(isp->dev, "timeout %d of %d\n",
1475 atomic_read(&isp->wdt_count) + 1,
1476 ATOMISP_ISP_MAX_TIMEOUT_COUNT);
1478 for (i = 0; i < isp->num_of_streams; i++) {
1479 struct atomisp_sub_device *asd = &isp->asd[i];
1480 pipe_wdt_cnt[i][0] +=
1481 atomic_read(&asd->video_out_capture.wdt_count);
1482 pipe_wdt_cnt[i][1] +=
1483 atomic_read(&asd->video_out_vf.wdt_count);
1484 pipe_wdt_cnt[i][2] +=
1485 atomic_read(&asd->video_out_preview.wdt_count);
1486 pipe_wdt_cnt[i][3] +=
1487 atomic_read(&asd->video_out_video_capture.wdt_count);
1489 (pipe_wdt_cnt[i][0] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
1490 pipe_wdt_cnt[i][1] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
1491 pipe_wdt_cnt[i][2] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
1492 pipe_wdt_cnt[i][3] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT)
1494 dev_err(isp->dev, "pipe on asd%d timeout cnt: (%d, %d, %d, %d) of %d, recover = %d\n",
1495 asd->index, pipe_wdt_cnt[i][0], pipe_wdt_cnt[i][1],
1496 pipe_wdt_cnt[i][2], pipe_wdt_cnt[i][3],
1497 ATOMISP_ISP_MAX_TIMEOUT_COUNT, css_recover);
1502 if (atomic_inc_return(&isp->wdt_count) <
1503 ATOMISP_ISP_MAX_TIMEOUT_COUNT) {
1507 unsigned int old_dbglevel = dbg_level;
1508 atomisp_css_debug_dump_sp_sw_debug_info();
1509 atomisp_css_debug_dump_debug_info(__func__);
1510 dbg_level = old_dbglevel;
1511 for (i = 0; i < isp->num_of_streams; i++) {
1512 struct atomisp_sub_device *asd = &isp->asd[i];
1514 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
1516 dev_err(isp->dev, "%s, vdev %s buffers in css: %d\n",
1518 asd->video_out_capture.vdev.name,
1519 asd->video_out_capture.
1522 "%s, vdev %s buffers in css: %d\n",
1524 asd->video_out_vf.vdev.name,
1528 "%s, vdev %s buffers in css: %d\n",
1530 asd->video_out_preview.vdev.name,
1531 asd->video_out_preview.
1534 "%s, vdev %s buffers in css: %d\n",
1536 asd->video_out_video_capture.vdev.name,
1537 asd->video_out_video_capture.
1540 "%s, s3a buffers in css preview pipe:%d\n",
1542 asd->s3a_bufs_in_css[CSS_PIPE_ID_PREVIEW]);
1544 "%s, s3a buffers in css capture pipe:%d\n",
1546 asd->s3a_bufs_in_css[CSS_PIPE_ID_CAPTURE]);
1548 "%s, s3a buffers in css video pipe:%d\n",
1550 asd->s3a_bufs_in_css[CSS_PIPE_ID_VIDEO]);
1552 "%s, dis buffers in css: %d\n",
1553 __func__, asd->dis_bufs_in_css);
1555 "%s, metadata buffers in css preview pipe:%d\n",
1557 asd->metadata_bufs_in_css
1558 [ATOMISP_INPUT_STREAM_GENERAL]
1559 [CSS_PIPE_ID_PREVIEW]);
1561 "%s, metadata buffers in css capture pipe:%d\n",
1563 asd->metadata_bufs_in_css
1564 [ATOMISP_INPUT_STREAM_GENERAL]
1565 [CSS_PIPE_ID_CAPTURE]);
1567 "%s, metadata buffers in css video pipe:%d\n",
1569 asd->metadata_bufs_in_css
1570 [ATOMISP_INPUT_STREAM_GENERAL]
1571 [CSS_PIPE_ID_VIDEO]);
1572 if (asd->enable_raw_buffer_lock->val) {
1575 dev_err(isp->dev, "%s, raw_buffer_locked_count %d\n",
1576 __func__, asd->raw_buffer_locked_count);
1577 for (j = 0; j <= ATOMISP_MAX_EXP_ID/32; j++)
1578 dev_err(isp->dev, "%s, raw_buffer_bitmap[%d]: 0x%x\n",
1580 asd->raw_buffer_bitmap[j]);
1584 /*sh_css_dump_sp_state();*/
1585 /*sh_css_dump_isp_state();*/
1587 for (i = 0; i < isp->num_of_streams; i++) {
1588 struct atomisp_sub_device *asd = &isp->asd[i];
1589 if (asd->streaming ==
1590 ATOMISP_DEVICE_STREAMING_ENABLED) {
1591 atomisp_clear_css_buffer_counters(asd);
1592 atomisp_flush_bufs_and_wakeup(asd);
1593 complete(&asd->init_done);
1596 atomisp_wdt_stop(asd, false);
1601 atomic_set(&isp->wdt_count, 0);
1603 isp->isp_fatal_error = true;
1604 atomic_set(&isp->wdt_work_queued, 0);
1606 rt_mutex_unlock(&isp->mutex);
1610 __atomisp_css_recover(isp, true);
1612 for (i = 0; i < isp->num_of_streams; i++) {
1613 struct atomisp_sub_device *asd = &isp->asd[i];
1614 if (asd->streaming ==
1615 ATOMISP_DEVICE_STREAMING_ENABLED) {
1616 atomisp_wdt_refresh(asd,
1617 isp->sw_contex.file_input ?
1618 ATOMISP_ISP_FILE_TIMEOUT_DURATION :
1619 ATOMISP_ISP_TIMEOUT_DURATION);
1623 dev_err(isp->dev, "timeout recovery handling done\n");
1624 atomic_set(&isp->wdt_work_queued, 0);
1626 rt_mutex_unlock(&isp->mutex);
1629 void atomisp_css_flush(struct atomisp_device *isp)
1633 if (!atomisp_streaming_count(isp))
1637 for (i = 0; i < isp->num_of_streams; i++) {
1638 struct atomisp_sub_device *asd = &isp->asd[i];
1639 atomisp_wdt_stop(asd, true);
1643 __atomisp_css_recover(isp, false);
1645 for (i = 0; i < isp->num_of_streams; i++) {
1646 struct atomisp_sub_device *asd = &isp->asd[i];
1648 if (asd->streaming !=
1649 ATOMISP_DEVICE_STREAMING_ENABLED)
1652 atomisp_wdt_refresh(asd,
1653 isp->sw_contex.file_input ?
1654 ATOMISP_ISP_FILE_TIMEOUT_DURATION :
1655 ATOMISP_ISP_TIMEOUT_DURATION);
1657 dev_dbg(isp->dev, "atomisp css flush done\n");
1660 void atomisp_wdt(struct timer_list *t)
1663 struct atomisp_sub_device *asd = from_timer(asd, t, wdt);
1665 struct atomisp_video_pipe *pipe = from_timer(pipe, t, wdt);
1666 struct atomisp_sub_device *asd = pipe->asd;
1668 struct atomisp_device *isp = asd->isp;
1671 atomic_inc(&pipe->wdt_count);
1673 "[WARNING]asd %d pipe %s ISP timeout %d!\n",
1674 asd->index, pipe->vdev.name,
1675 atomic_read(&pipe->wdt_count));
1677 if (atomic_read(&isp->wdt_work_queued)) {
1678 dev_dbg(isp->dev, "ISP watchdog was put into workqueue\n");
1681 atomic_set(&isp->wdt_work_queued, 1);
1682 queue_work(isp->wdt_work_queue, &isp->wdt_work);
1686 void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay)
1688 void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe,
1694 if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY)
1696 asd->wdt_duration = delay;
1698 pipe->wdt_duration = delay;
1702 next = jiffies + asd->wdt_duration;
1704 next = jiffies + pipe->wdt_duration;
1707 /* Override next if it has been pushed beyon the "next" time */
1709 if (atomisp_is_wdt_running(asd) && time_after(asd->wdt_expires, next))
1710 next = asd->wdt_expires;
1712 if (atomisp_is_wdt_running(pipe) && time_after(pipe->wdt_expires, next))
1713 next = pipe->wdt_expires;
1717 asd->wdt_expires = next;
1719 pipe->wdt_expires = next;
1723 if (atomisp_is_wdt_running(asd))
1724 dev_dbg(asd->isp->dev, "WDT will hit after %d ms\n",
1725 ((int)(next - jiffies) * 1000 / HZ));
1727 if (atomisp_is_wdt_running(pipe))
1728 dev_dbg(pipe->asd->isp->dev, "WDT will hit after %d ms (%s)\n",
1729 ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name);
1733 dev_dbg(asd->isp->dev, "WDT starts with %d ms period\n",
1734 ((int)(next - jiffies) * 1000 / HZ));
1736 dev_dbg(pipe->asd->isp->dev, "WDT starts with %d ms period (%s)\n",
1737 ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name);
1741 mod_timer(&asd->wdt, next);
1742 atomic_set(&asd->isp->wdt_count, 0);
1744 mod_timer(&pipe->wdt, next);
1749 void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync)
1751 void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay)
1753 dev_dbg(asd->isp->dev, "WDT refresh all:\n");
1754 if (atomisp_is_wdt_running(&asd->video_out_capture))
1755 atomisp_wdt_refresh_pipe(&asd->video_out_capture, delay);
1756 if (atomisp_is_wdt_running(&asd->video_out_preview))
1757 atomisp_wdt_refresh_pipe(&asd->video_out_preview, delay);
1758 if (atomisp_is_wdt_running(&asd->video_out_vf))
1759 atomisp_wdt_refresh_pipe(&asd->video_out_vf, delay);
1760 if (atomisp_is_wdt_running(&asd->video_out_video_capture))
1761 atomisp_wdt_refresh_pipe(&asd->video_out_video_capture, delay);
1765 void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync)
1769 dev_dbg(asd->isp->dev, "WDT stop\n");
1771 if (!atomisp_is_wdt_running(pipe))
1774 dev_dbg(pipe->asd->isp->dev,
1775 "WDT stop asd %d (%s)\n", pipe->asd->index, pipe->vdev.name);
1780 del_timer_sync(&asd->wdt);
1781 cancel_work_sync(&asd->isp->wdt_work);
1783 del_timer_sync(&pipe->wdt);
1784 cancel_work_sync(&pipe->asd->isp->wdt_work);
1788 del_timer(&asd->wdt);
1790 del_timer(&pipe->wdt);
1796 void atomisp_wdt_start(struct atomisp_sub_device *asd)
1798 void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync)
1800 dev_dbg(asd->isp->dev, "WDT stop all:\n");
1801 atomisp_wdt_stop_pipe(&asd->video_out_capture, sync);
1802 atomisp_wdt_stop_pipe(&asd->video_out_preview, sync);
1803 atomisp_wdt_stop_pipe(&asd->video_out_vf, sync);
1804 atomisp_wdt_stop_pipe(&asd->video_out_video_capture, sync);
1807 void atomisp_wdt_start(struct atomisp_video_pipe *pipe)
1811 atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION);
1813 atomisp_wdt_refresh_pipe(pipe, ATOMISP_ISP_TIMEOUT_DURATION);
1817 void atomisp_setup_flash(struct atomisp_sub_device *asd)
1819 struct atomisp_device *isp = asd->isp;
1820 struct v4l2_control ctrl;
1822 if (isp->flash == NULL)
1825 if (asd->params.flash_state != ATOMISP_FLASH_REQUESTED &&
1826 asd->params.flash_state != ATOMISP_FLASH_DONE)
1829 if (asd->params.num_flash_frames) {
1830 /* make sure the timeout is set before setting flash mode */
1831 ctrl.id = V4L2_CID_FLASH_TIMEOUT;
1832 ctrl.value = FLASH_TIMEOUT;
1834 if (v4l2_s_ctrl(NULL, isp->flash->ctrl_handler, &ctrl)) {
1835 dev_err(isp->dev, "flash timeout configure failed\n");
1839 atomisp_css_request_flash(asd);
1840 asd->params.flash_state = ATOMISP_FLASH_ONGOING;
1842 asd->params.flash_state = ATOMISP_FLASH_IDLE;
1846 irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
1848 struct atomisp_device *isp = isp_ptr;
1849 unsigned long flags;
1850 bool frame_done_found[MAX_STREAM_NUM] = {0};
1851 bool css_pipe_done[MAX_STREAM_NUM] = {0};
1853 struct atomisp_sub_device *asd;
1855 dev_dbg(isp->dev, ">%s\n", __func__);
1857 spin_lock_irqsave(&isp->lock, flags);
1859 if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) {
1860 spin_unlock_irqrestore(&isp->lock, flags);
1864 spin_unlock_irqrestore(&isp->lock, flags);
1867 * The standard CSS2.0 API tells the following calling sequence of
1868 * dequeue ready buffers:
1869 * while (ia_css_dequeue_event(...)) {
1870 * switch (event.type) {
1872 * ia_css_pipe_dequeue_buffer()
1875 * That is, dequeue event and buffer are one after another.
1877 * But the following implementation is to first deuque all the event
1878 * to a FIFO, then process the event in the FIFO.
1879 * This will not have issue in single stream mode, but it do have some
1880 * issue in multiple stream case. The issue is that
1881 * ia_css_pipe_dequeue_buffer() will not return the corrent buffer in
1884 * This is due to ia_css_pipe_dequeue_buffer() does not take the
1885 * ia_css_pipe parameter.
1888 * For CSS2.0: we change the way to not dequeue all the event at one
1889 * time, instead, dequue one and process one, then another
1891 rt_mutex_lock(&isp->mutex);
1892 if (atomisp_css_isr_thread(isp, frame_done_found, css_pipe_done))
1895 for (i = 0; i < isp->num_of_streams; i++) {
1897 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
1899 atomisp_setup_flash(asd);
1903 rt_mutex_unlock(&isp->mutex);
1904 for (i = 0; i < isp->num_of_streams; i++) {
1906 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED
1907 && css_pipe_done[asd->index]
1908 && isp->sw_contex.file_input)
1909 v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
1910 video, s_stream, 1);
1911 /* FIXME! FIX ACC implementation */
1912 if (asd->acc.pipeline && css_pipe_done[asd->index])
1913 atomisp_css_acc_done(asd);
1915 dev_dbg(isp->dev, "<%s\n", __func__);
1921 * utils for buffer allocation/free
1924 int atomisp_get_frame_pgnr(struct atomisp_device *isp,
1925 const struct atomisp_css_frame *frame, u32 *p_pgnr)
1928 dev_err(isp->dev, "%s: NULL frame pointer ERROR.\n", __func__);
1932 *p_pgnr = DIV_ROUND_UP(frame->data_bytes, PAGE_SIZE);
1937 * Get internal fmt according to V4L2 fmt
1939 static enum atomisp_css_frame_format
1940 v4l2_fmt_to_sh_fmt(u32 fmt)
1943 case V4L2_PIX_FMT_YUV420:
1944 return CSS_FRAME_FORMAT_YUV420;
1945 case V4L2_PIX_FMT_YVU420:
1946 return CSS_FRAME_FORMAT_YV12;
1947 case V4L2_PIX_FMT_YUV422P:
1948 return CSS_FRAME_FORMAT_YUV422;
1949 case V4L2_PIX_FMT_YUV444:
1950 return CSS_FRAME_FORMAT_YUV444;
1951 case V4L2_PIX_FMT_NV12:
1952 return CSS_FRAME_FORMAT_NV12;
1953 case V4L2_PIX_FMT_NV21:
1954 return CSS_FRAME_FORMAT_NV21;
1955 case V4L2_PIX_FMT_NV16:
1956 return CSS_FRAME_FORMAT_NV16;
1957 case V4L2_PIX_FMT_NV61:
1958 return CSS_FRAME_FORMAT_NV61;
1959 case V4L2_PIX_FMT_UYVY:
1960 return CSS_FRAME_FORMAT_UYVY;
1961 case V4L2_PIX_FMT_YUYV:
1962 return CSS_FRAME_FORMAT_YUYV;
1963 case V4L2_PIX_FMT_RGB24:
1964 return CSS_FRAME_FORMAT_PLANAR_RGB888;
1965 case V4L2_PIX_FMT_RGB32:
1966 return CSS_FRAME_FORMAT_RGBA888;
1967 case V4L2_PIX_FMT_RGB565:
1968 return CSS_FRAME_FORMAT_RGB565;
1969 case V4L2_PIX_FMT_JPEG:
1970 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
1971 return CSS_FRAME_FORMAT_BINARY_8;
1972 case V4L2_PIX_FMT_SBGGR16:
1973 case V4L2_PIX_FMT_SBGGR10:
1974 case V4L2_PIX_FMT_SGBRG10:
1975 case V4L2_PIX_FMT_SGRBG10:
1976 case V4L2_PIX_FMT_SRGGB10:
1977 case V4L2_PIX_FMT_SBGGR12:
1978 case V4L2_PIX_FMT_SGBRG12:
1979 case V4L2_PIX_FMT_SGRBG12:
1980 case V4L2_PIX_FMT_SRGGB12:
1981 case V4L2_PIX_FMT_SBGGR8:
1982 case V4L2_PIX_FMT_SGBRG8:
1983 case V4L2_PIX_FMT_SGRBG8:
1984 case V4L2_PIX_FMT_SRGGB8:
1985 return CSS_FRAME_FORMAT_RAW;
1991 * raw format match between SH format and V4L2 format
1993 static int raw_output_format_match_input(u32 input, u32 output)
1995 if ((input == CSS_FORMAT_RAW_12) &&
1996 ((output == V4L2_PIX_FMT_SRGGB12) ||
1997 (output == V4L2_PIX_FMT_SGRBG12) ||
1998 (output == V4L2_PIX_FMT_SBGGR12) ||
1999 (output == V4L2_PIX_FMT_SGBRG12)))
2002 if ((input == CSS_FORMAT_RAW_10) &&
2003 ((output == V4L2_PIX_FMT_SRGGB10) ||
2004 (output == V4L2_PIX_FMT_SGRBG10) ||
2005 (output == V4L2_PIX_FMT_SBGGR10) ||
2006 (output == V4L2_PIX_FMT_SGBRG10)))
2009 if ((input == CSS_FORMAT_RAW_8) &&
2010 ((output == V4L2_PIX_FMT_SRGGB8) ||
2011 (output == V4L2_PIX_FMT_SGRBG8) ||
2012 (output == V4L2_PIX_FMT_SBGGR8) ||
2013 (output == V4L2_PIX_FMT_SGBRG8)))
2016 if ((input == CSS_FORMAT_RAW_16) && (output == V4L2_PIX_FMT_SBGGR16))
2022 static u32 get_pixel_depth(u32 pixelformat)
2024 switch (pixelformat) {
2025 case V4L2_PIX_FMT_YUV420:
2026 case V4L2_PIX_FMT_NV12:
2027 case V4L2_PIX_FMT_NV21:
2028 case V4L2_PIX_FMT_YVU420:
2030 case V4L2_PIX_FMT_YUV422P:
2031 case V4L2_PIX_FMT_YUYV:
2032 case V4L2_PIX_FMT_UYVY:
2033 case V4L2_PIX_FMT_NV16:
2034 case V4L2_PIX_FMT_NV61:
2035 case V4L2_PIX_FMT_RGB565:
2036 case V4L2_PIX_FMT_SBGGR16:
2037 case V4L2_PIX_FMT_SBGGR12:
2038 case V4L2_PIX_FMT_SGBRG12:
2039 case V4L2_PIX_FMT_SGRBG12:
2040 case V4L2_PIX_FMT_SRGGB12:
2041 case V4L2_PIX_FMT_SBGGR10:
2042 case V4L2_PIX_FMT_SGBRG10:
2043 case V4L2_PIX_FMT_SGRBG10:
2044 case V4L2_PIX_FMT_SRGGB10:
2046 case V4L2_PIX_FMT_RGB24:
2047 case V4L2_PIX_FMT_YUV444:
2049 case V4L2_PIX_FMT_RGB32:
2051 case V4L2_PIX_FMT_JPEG:
2052 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
2053 case V4L2_PIX_FMT_SBGGR8:
2054 case V4L2_PIX_FMT_SGBRG8:
2055 case V4L2_PIX_FMT_SGRBG8:
2056 case V4L2_PIX_FMT_SRGGB8:
2059 return 8 * 2; /* raw type now */
2063 bool atomisp_is_mbuscode_raw(uint32_t code)
2065 return code >= 0x3000 && code < 0x4000;
2069 * ISP features control function
2073 * Set ISP capture mode based on current settings
2075 static void atomisp_update_capture_mode(struct atomisp_sub_device *asd)
2077 if (asd->params.gdc_cac_en)
2078 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_ADVANCED);
2079 else if (asd->params.low_light)
2080 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_LOW_LIGHT);
2081 else if (asd->video_out_capture.sh_fmt == CSS_FRAME_FORMAT_RAW)
2082 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_RAW);
2084 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_PRIMARY);
2088 int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
2089 struct atomisp_s_runmode *runmode)
2091 struct atomisp_device *isp = asd->isp;
2092 struct v4l2_ctrl *c;
2093 struct v4l2_streamparm p = {0};
2095 int modes[] = { CI_MODE_NONE,
2097 CI_MODE_STILL_CAPTURE,
2101 if (!(runmode && (runmode->mode & RUNMODE_MASK)))
2104 mutex_lock(asd->ctrl_handler.lock);
2105 c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler,
2109 ret = v4l2_ctrl_s_ctrl(c, runmode->mode);
2111 mutex_unlock(asd->ctrl_handler.lock);
2117 * Function to enable/disable lens geometry distortion correction (GDC) and
2118 * chromatic aberration correction (CAC)
2120 int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
2124 *value = asd->params.gdc_cac_en;
2128 asd->params.gdc_cac_en = !!*value;
2129 if (asd->params.gdc_cac_en) {
2130 atomisp_css_set_morph_table(asd,
2131 asd->params.css_param.morph_table);
2133 atomisp_css_set_morph_table(asd, NULL);
2135 asd->params.css_update_params_needed = true;
2136 atomisp_update_capture_mode(asd);
2141 * Function to enable/disable low light mode including ANR
2143 int atomisp_low_light(struct atomisp_sub_device *asd, int flag,
2147 *value = asd->params.low_light;
2151 asd->params.low_light = (*value != 0);
2152 atomisp_update_capture_mode(asd);
2157 * Function to enable/disable extra noise reduction (XNR) in low light
2160 int atomisp_xnr(struct atomisp_sub_device *asd, int flag,
2164 *xnr_enable = asd->params.xnr_en;
2168 atomisp_css_capture_enable_xnr(asd, !!*xnr_enable);
2174 * Function to configure bayer noise reduction
2176 int atomisp_nr(struct atomisp_sub_device *asd, int flag,
2177 struct atomisp_nr_config *arg)
2180 /* Get nr config from current setup */
2181 if (atomisp_css_get_nr_config(asd, arg))
2184 /* Set nr config to isp parameters */
2185 memcpy(&asd->params.css_param.nr_config, arg,
2186 sizeof(struct atomisp_css_nr_config));
2187 atomisp_css_set_nr_config(asd, &asd->params.css_param.nr_config);
2188 asd->params.css_update_params_needed = true;
2194 * Function to configure temporal noise reduction (TNR)
2196 int atomisp_tnr(struct atomisp_sub_device *asd, int flag,
2197 struct atomisp_tnr_config *config)
2199 /* Get tnr config from current setup */
2201 /* Get tnr config from current setup */
2202 if (atomisp_css_get_tnr_config(asd, config))
2205 /* Set tnr config to isp parameters */
2206 memcpy(&asd->params.css_param.tnr_config, config,
2207 sizeof(struct atomisp_css_tnr_config));
2208 atomisp_css_set_tnr_config(asd, &asd->params.css_param.tnr_config);
2209 asd->params.css_update_params_needed = true;
2216 * Function to configure black level compensation
2218 int atomisp_black_level(struct atomisp_sub_device *asd, int flag,
2219 struct atomisp_ob_config *config)
2222 /* Get ob config from current setup */
2223 if (atomisp_css_get_ob_config(asd, config))
2226 /* Set ob config to isp parameters */
2227 memcpy(&asd->params.css_param.ob_config, config,
2228 sizeof(struct atomisp_css_ob_config));
2229 atomisp_css_set_ob_config(asd, &asd->params.css_param.ob_config);
2230 asd->params.css_update_params_needed = true;
2237 * Function to configure edge enhancement
2239 int atomisp_ee(struct atomisp_sub_device *asd, int flag,
2240 struct atomisp_ee_config *config)
2243 /* Get ee config from current setup */
2244 if (atomisp_css_get_ee_config(asd, config))
2247 /* Set ee config to isp parameters */
2248 memcpy(&asd->params.css_param.ee_config, config,
2249 sizeof(asd->params.css_param.ee_config));
2250 atomisp_css_set_ee_config(asd, &asd->params.css_param.ee_config);
2251 asd->params.css_update_params_needed = true;
2258 * Function to update Gamma table for gamma, brightness and contrast config
2260 int atomisp_gamma(struct atomisp_sub_device *asd, int flag,
2261 struct atomisp_gamma_table *config)
2264 /* Get gamma table from current setup */
2265 if (atomisp_css_get_gamma_table(asd, config))
2268 /* Set gamma table to isp parameters */
2269 memcpy(&asd->params.css_param.gamma_table, config,
2270 sizeof(asd->params.css_param.gamma_table));
2271 atomisp_css_set_gamma_table(asd, &asd->params.css_param.gamma_table);
2278 * Function to update Ctc table for Chroma Enhancement
2280 int atomisp_ctc(struct atomisp_sub_device *asd, int flag,
2281 struct atomisp_ctc_table *config)
2284 /* Get ctc table from current setup */
2285 if (atomisp_css_get_ctc_table(asd, config))
2288 /* Set ctc table to isp parameters */
2289 memcpy(&asd->params.css_param.ctc_table, config,
2290 sizeof(asd->params.css_param.ctc_table));
2291 atomisp_css_set_ctc_table(asd, &asd->params.css_param.ctc_table);
2298 * Function to update gamma correction parameters
2300 int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag,
2301 struct atomisp_gc_config *config)
2304 /* Get gamma correction params from current setup */
2305 if (atomisp_css_get_gc_config(asd, config))
2308 /* Set gamma correction params to isp parameters */
2309 memcpy(&asd->params.css_param.gc_config, config,
2310 sizeof(asd->params.css_param.gc_config));
2311 atomisp_css_set_gc_config(asd, &asd->params.css_param.gc_config);
2312 asd->params.css_update_params_needed = true;
2319 * Function to update narrow gamma flag
2321 int atomisp_formats(struct atomisp_sub_device *asd, int flag,
2322 struct atomisp_formats_config *config)
2325 /* Get narrow gamma flag from current setup */
2326 if (atomisp_css_get_formats_config(asd, config))
2329 /* Set narrow gamma flag to isp parameters */
2330 memcpy(&asd->params.css_param.formats_config, config,
2331 sizeof(asd->params.css_param.formats_config));
2332 atomisp_css_set_formats_config(asd, &asd->params.css_param.formats_config);
2338 void atomisp_free_internal_buffers(struct atomisp_sub_device *asd)
2340 atomisp_free_css_parameters(&asd->params.css_param);
2342 if (asd->raw_output_frame) {
2343 atomisp_css_frame_free(asd->raw_output_frame);
2344 asd->raw_output_frame = NULL;
2348 static void atomisp_update_grid_info(struct atomisp_sub_device *asd,
2349 enum atomisp_css_pipe_id pipe_id,
2352 struct atomisp_device *isp = asd->isp;
2354 uint16_t stream_id = atomisp_source_pad_to_stream_id(asd, source_pad);
2356 if (atomisp_css_get_grid_info(asd, pipe_id, source_pad))
2359 /* We must free all buffers because they no longer match
2361 atomisp_css_free_stat_buffers(asd);
2363 err = atomisp_alloc_css_stat_bufs(asd, stream_id);
2365 dev_err(isp->dev, "stat_buf allocate error\n");
2369 if (atomisp_alloc_3a_output_buf(asd)) {
2370 /* Failure for 3A buffers does not influence DIS buffers */
2371 if (asd->params.s3a_output_bytes != 0) {
2372 /* For SOC sensor happens s3a_output_bytes == 0,
2373 * using if condition to exclude false error log */
2374 dev_err(isp->dev, "Failed to allocate memory for 3A statistics\n");
2379 if (atomisp_alloc_dis_coef_buf(asd)) {
2381 "Failed to allocate memory for DIS statistics\n");
2385 if (atomisp_alloc_metadata_output_buf(asd)) {
2386 dev_err(isp->dev, "Failed to allocate memory for metadata\n");
2393 atomisp_css_free_stat_buffers(asd);
2397 static void atomisp_curr_user_grid_info(struct atomisp_sub_device *asd,
2398 struct atomisp_grid_info *info)
2400 memcpy(info, &asd->params.curr_grid_info.s3a_grid,
2401 sizeof(struct atomisp_css_3a_grid_info));
2404 int atomisp_compare_grid(struct atomisp_sub_device *asd,
2405 struct atomisp_grid_info *atomgrid)
2407 struct atomisp_grid_info tmp = {0};
2409 atomisp_curr_user_grid_info(asd, &tmp);
2410 return memcmp(atomgrid, &tmp, sizeof(tmp));
2414 * Function to update Gdc table for gdc
2416 int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag,
2417 struct atomisp_morph_table *config)
2421 struct atomisp_device *isp = asd->isp;
2424 /* Get gdc table from current setup */
2425 struct atomisp_css_morph_table tab = {0};
2426 atomisp_css_get_morph_table(asd, &tab);
2428 config->width = tab.width;
2429 config->height = tab.height;
2431 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) {
2432 ret = copy_to_user(config->coordinates_x[i],
2433 tab.coordinates_x[i], tab.height *
2434 tab.width * sizeof(*tab.coordinates_x[i]));
2437 "Failed to copy to User for x\n");
2440 ret = copy_to_user(config->coordinates_y[i],
2441 tab.coordinates_y[i], tab.height *
2442 tab.width * sizeof(*tab.coordinates_y[i]));
2445 "Failed to copy to User for y\n");
2450 struct atomisp_css_morph_table *tab =
2451 asd->params.css_param.morph_table;
2453 /* free first if we have one */
2455 atomisp_css_morph_table_free(tab);
2456 asd->params.css_param.morph_table = NULL;
2459 /* allocate new one */
2460 tab = atomisp_css_morph_table_allocate(config->width,
2464 dev_err(isp->dev, "out of memory\n");
2468 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) {
2469 ret = copy_from_user(tab->coordinates_x[i],
2470 config->coordinates_x[i],
2471 config->height * config->width *
2472 sizeof(*config->coordinates_x[i]));
2475 "Failed to copy from User for x, ret %d\n",
2477 atomisp_css_morph_table_free(tab);
2480 ret = copy_from_user(tab->coordinates_y[i],
2481 config->coordinates_y[i],
2482 config->height * config->width *
2483 sizeof(*config->coordinates_y[i]));
2486 "Failed to copy from User for y, ret is %d\n",
2488 atomisp_css_morph_table_free(tab);
2492 asd->params.css_param.morph_table = tab;
2493 if (asd->params.gdc_cac_en)
2494 atomisp_css_set_morph_table(asd, tab);
2500 int atomisp_macc_table(struct atomisp_sub_device *asd, int flag,
2501 struct atomisp_macc_config *config)
2503 struct atomisp_css_macc_table *macc_table;
2505 switch (config->color_effect) {
2506 case V4L2_COLORFX_NONE:
2507 macc_table = &asd->params.css_param.macc_table;
2509 case V4L2_COLORFX_SKY_BLUE:
2510 macc_table = &blue_macc_table;
2512 case V4L2_COLORFX_GRASS_GREEN:
2513 macc_table = &green_macc_table;
2515 case V4L2_COLORFX_SKIN_WHITEN_LOW:
2516 macc_table = &skin_low_macc_table;
2518 case V4L2_COLORFX_SKIN_WHITEN:
2519 macc_table = &skin_medium_macc_table;
2521 case V4L2_COLORFX_SKIN_WHITEN_HIGH:
2522 macc_table = &skin_high_macc_table;
2529 /* Get macc table from current setup */
2530 memcpy(&config->table, macc_table,
2531 sizeof(struct atomisp_css_macc_table));
2533 memcpy(macc_table, &config->table,
2534 sizeof(struct atomisp_css_macc_table));
2535 if (config->color_effect == asd->params.color_effect)
2536 atomisp_css_set_macc_table(asd, macc_table);
2542 int atomisp_set_dis_vector(struct atomisp_sub_device *asd,
2543 struct atomisp_dis_vector *vector)
2545 atomisp_css_video_set_dis_vector(asd, vector);
2547 asd->params.dis_proj_data_valid = false;
2548 asd->params.css_update_params_needed = true;
2553 * Function to set/get image stablization statistics
2555 int atomisp_get_dis_stat(struct atomisp_sub_device *asd,
2556 struct atomisp_dis_statistics *stats)
2558 return atomisp_css_get_dis_stat(asd, stats);
2562 * Function set camrea_prefiles.xml current sensor pixel array size
2564 int atomisp_set_array_res(struct atomisp_sub_device *asd,
2565 struct atomisp_resolution *config)
2567 dev_dbg(asd->isp->dev, ">%s start\n", __func__);
2569 dev_err(asd->isp->dev, "Set sensor array size is not valid\n");
2573 asd->sensor_array_res.width = config->width;
2574 asd->sensor_array_res.height = config->height;
2579 * Function to get DVS2 BQ resolution settings
2581 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd,
2582 struct atomisp_dvs2_bq_resolutions *bq_res)
2584 struct ia_css_pipe_config *pipe_cfg = NULL;
2585 struct ia_css_stream_config *stream_cfg = NULL;
2586 struct ia_css_stream_input_config *input_config = NULL;
2588 struct ia_css_stream *stream =
2589 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
2591 dev_warn(asd->isp->dev, "stream is not created");
2595 pipe_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2596 .pipe_configs[CSS_PIPE_ID_VIDEO];
2597 stream_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2599 input_config = &stream_cfg->input_config;
2604 /* the GDC output resolution */
2605 bq_res->output_bq.width_bq = pipe_cfg->output_info[0].res.width / 2;
2606 bq_res->output_bq.height_bq = pipe_cfg->output_info[0].res.height / 2;
2608 bq_res->envelope_bq.width_bq = 0;
2609 bq_res->envelope_bq.height_bq = 0;
2610 /* the GDC input resolution */
2611 if (!asd->continuous_mode->val) {
2612 bq_res->source_bq.width_bq = bq_res->output_bq.width_bq +
2613 pipe_cfg->dvs_envelope.width / 2;
2614 bq_res->source_bq.height_bq = bq_res->output_bq.height_bq +
2615 pipe_cfg->dvs_envelope.height / 2;
2617 * Bad pixels caused by spatial filter processing
2618 * ISP filter resolution should be given by CSS/FW, but for now
2619 * there is not such API to query, and it is fixed value, so
2622 bq_res->ispfilter_bq.width_bq = 12 / 2;
2623 bq_res->ispfilter_bq.height_bq = 12 / 2;
2624 /* spatial filter shift, always 4 pixels */
2625 bq_res->gdc_shift_bq.width_bq = 4 / 2;
2626 bq_res->gdc_shift_bq.height_bq = 4 / 2;
2628 if (asd->params.video_dis_en) {
2629 bq_res->envelope_bq.width_bq = pipe_cfg->dvs_envelope.width
2630 / 2 - bq_res->ispfilter_bq.width_bq;
2631 bq_res->envelope_bq.height_bq = pipe_cfg->dvs_envelope.height
2632 / 2 - bq_res->ispfilter_bq.height_bq;
2635 unsigned int w_padding;
2636 unsigned int gdc_effective_input = 0;
2639 * gdc_effective_input = effective_input + envelope
2641 * From the comment and formula in BZ1786,
2642 * we see the source_bq should be:
2643 * effective_input / bayer_ds_ratio
2645 bq_res->source_bq.width_bq =
2646 (input_config->effective_res.width *
2647 pipe_cfg->bayer_ds_out_res.width /
2648 input_config->effective_res.width + 1) / 2;
2649 bq_res->source_bq.height_bq =
2650 (input_config->effective_res.height *
2651 pipe_cfg->bayer_ds_out_res.height /
2652 input_config->effective_res.height + 1) / 2;
2655 if (!asd->params.video_dis_en) {
2657 * We adjust the ispfilter_bq to:
2658 * ispfilter_bq = 128/BDS
2659 * we still need firmware team to provide an offical
2662 bq_res->ispfilter_bq.width_bq = 128 *
2663 pipe_cfg->bayer_ds_out_res.width /
2664 input_config->effective_res.width / 2;
2665 bq_res->ispfilter_bq.height_bq = 128 *
2666 pipe_cfg->bayer_ds_out_res.width /
2667 input_config->effective_res.width / 2;
2669 if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) {
2670 /* No additional left padding for ISYS2401 */
2671 bq_res->gdc_shift_bq.width_bq = 4 / 2;
2672 bq_res->gdc_shift_bq.height_bq = 4 / 2;
2675 * For the w_padding and gdc_shift_bq cacluation
2676 * Please see the BZ 1786 and 4358 for more info.
2677 * Just test that this formula can work now,
2678 * but we still have no offical formula.
2680 * w_padding = ceiling(gdc_effective_input
2681 * /128, 1) * 128 - effective_width
2682 * gdc_shift_bq = w_padding/BDS/2 + ispfilter_bq/2
2684 gdc_effective_input =
2685 input_config->effective_res.width +
2686 pipe_cfg->dvs_envelope.width;
2687 w_padding = roundup(gdc_effective_input, 128) -
2688 input_config->effective_res.width;
2689 w_padding = w_padding *
2690 pipe_cfg->bayer_ds_out_res.width /
2691 input_config->effective_res.width + 1;
2692 w_padding = roundup(w_padding/2, 1);
2694 bq_res->gdc_shift_bq.width_bq = bq_res->ispfilter_bq.width_bq / 2
2696 bq_res->gdc_shift_bq.height_bq = 4 / 2;
2699 unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max;
2701 bq_res->ispfilter_bq.width_bq = 8 / 2;
2702 bq_res->ispfilter_bq.height_bq = 8 / 2;
2704 if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) {
2705 /* No additional left padding for ISYS2401 */
2706 bq_res->gdc_shift_bq.width_bq = 4 / 2;
2707 bq_res->gdc_shift_bq.height_bq = 4 / 2;
2710 roundup(input_config->effective_res.width, 128) -
2711 input_config->effective_res.width;
2714 bq_res->gdc_shift_bq.width_bq = 4 / 2 +
2716 pipe_cfg->bayer_ds_out_res.width /
2717 input_config->effective_res.width + 1) / 2;
2718 bq_res->gdc_shift_bq.height_bq = 4 / 2;
2721 dvs_w = pipe_cfg->bayer_ds_out_res.width -
2722 pipe_cfg->output_info[0].res.width;
2723 dvs_h = pipe_cfg->bayer_ds_out_res.height -
2724 pipe_cfg->output_info[0].res.height;
2725 dvs_w_max = rounddown(
2726 pipe_cfg->output_info[0].res.width / 5,
2727 ATOM_ISP_STEP_WIDTH);
2728 dvs_h_max = rounddown(
2729 pipe_cfg->output_info[0].res.height / 5,
2730 ATOM_ISP_STEP_HEIGHT);
2731 bq_res->envelope_bq.width_bq =
2732 min((dvs_w / 2), (dvs_w_max / 2)) -
2733 bq_res->ispfilter_bq.width_bq;
2734 bq_res->envelope_bq.height_bq =
2735 min((dvs_h / 2), (dvs_h_max / 2)) -
2736 bq_res->ispfilter_bq.height_bq;
2740 dev_dbg(asd->isp->dev, "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",
2741 bq_res->source_bq.width_bq, bq_res->source_bq.height_bq,
2742 bq_res->ispfilter_bq.width_bq, bq_res->ispfilter_bq.height_bq,
2743 bq_res->gdc_shift_bq.width_bq, bq_res->gdc_shift_bq.height_bq,
2744 bq_res->envelope_bq.width_bq, bq_res->envelope_bq.height_bq,
2745 bq_res->output_bq.width_bq, bq_res->output_bq.height_bq);
2750 int atomisp_set_dis_coefs(struct atomisp_sub_device *asd,
2751 struct atomisp_dis_coefficients *coefs)
2753 return atomisp_css_set_dis_coefs(asd, coefs);
2757 * Function to set/get 3A stat from isp
2759 int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag,
2760 struct atomisp_3a_statistics *config)
2762 struct atomisp_device *isp = asd->isp;
2763 struct atomisp_s3a_buf *s3a_buf;
2769 /* sanity check to avoid writing into unallocated memory. */
2770 if (asd->params.s3a_output_bytes == 0)
2773 if (atomisp_compare_grid(asd, &config->grid_info) != 0) {
2774 /* If the grid info in the argument differs from the current
2775 grid info, we tell the caller to reset the grid size and
2780 if (list_empty(&asd->s3a_stats_ready)) {
2781 dev_err(isp->dev, "3a statistics is not valid.\n");
2785 s3a_buf = list_entry(asd->s3a_stats_ready.next,
2786 struct atomisp_s3a_buf, list);
2787 if (s3a_buf->s3a_map)
2788 ia_css_translate_3a_statistics(
2789 asd->params.s3a_user_stat, s3a_buf->s3a_map);
2791 ia_css_get_3a_statistics(asd->params.s3a_user_stat,
2794 config->exp_id = s3a_buf->s3a_data->exp_id;
2795 config->isp_config_id = s3a_buf->s3a_data->isp_config_id;
2797 ret = copy_to_user(config->data, asd->params.s3a_user_stat->data,
2798 asd->params.s3a_output_bytes);
2800 dev_err(isp->dev, "copy to user failed: copied %lu bytes\n",
2805 /* Move to free buffer list */
2806 list_del_init(&s3a_buf->list);
2807 list_add_tail(&s3a_buf->list, &asd->s3a_stats);
2808 dev_dbg(isp->dev, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n", __func__,
2809 config->exp_id, config->isp_config_id);
2813 int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag,
2814 struct atomisp_metadata *md)
2816 struct atomisp_device *isp = asd->isp;
2817 struct ia_css_stream_config *stream_config;
2818 struct ia_css_stream_info *stream_info;
2819 struct camera_mipi_info *mipi_info;
2820 struct atomisp_metadata_buf *md_buf;
2821 enum atomisp_metadata_type md_type = ATOMISP_MAIN_METADATA;
2827 stream_config = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2829 stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2832 /* We always return the resolution and stride even if there is
2833 * no valid metadata. This allows the caller to get the information
2834 * needed to allocate user-space buffers. */
2835 md->width = stream_info->metadata_info.resolution.width;
2836 md->height = stream_info->metadata_info.resolution.height;
2837 md->stride = stream_info->metadata_info.stride;
2839 /* sanity check to avoid writing into unallocated memory.
2840 * This does not return an error because it is a valid way
2841 * for applications to detect that metadata is not enabled. */
2842 if (md->width == 0 || md->height == 0 || !md->data)
2845 /* This is done in the atomisp_buf_done() */
2846 if (list_empty(&asd->metadata_ready[md_type])) {
2847 dev_warn(isp->dev, "Metadata queue is empty now!\n");
2851 mipi_info = atomisp_to_sensor_mipi_info(
2852 isp->inputs[asd->input_curr].camera);
2853 if (mipi_info == NULL)
2856 if (mipi_info->metadata_effective_width != NULL) {
2857 for (i = 0; i < md->height; i++)
2858 md->effective_width[i] =
2859 mipi_info->metadata_effective_width[i];
2862 md_buf = list_entry(asd->metadata_ready[md_type].next,
2863 struct atomisp_metadata_buf, list);
2864 md->exp_id = md_buf->metadata->exp_id;
2865 if (md_buf->md_vptr) {
2866 ret = copy_to_user(md->data,
2868 stream_info->metadata_info.size);
2870 hmm_load(md_buf->metadata->address,
2871 asd->params.metadata_user[md_type],
2872 stream_info->metadata_info.size);
2874 ret = copy_to_user(md->data,
2875 asd->params.metadata_user[md_type],
2876 stream_info->metadata_info.size);
2879 dev_err(isp->dev, "copy to user failed: copied %d bytes\n",
2884 list_del_init(&md_buf->list);
2885 list_add_tail(&md_buf->list, &asd->metadata[md_type]);
2887 dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2888 __func__, md_type, md->exp_id);
2892 int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag,
2893 struct atomisp_metadata_with_type *md)
2895 struct atomisp_device *isp = asd->isp;
2896 struct ia_css_stream_config *stream_config;
2897 struct ia_css_stream_info *stream_info;
2898 struct camera_mipi_info *mipi_info;
2899 struct atomisp_metadata_buf *md_buf;
2900 enum atomisp_metadata_type md_type;
2906 stream_config = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2908 stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2911 /* We always return the resolution and stride even if there is
2912 * no valid metadata. This allows the caller to get the information
2913 * needed to allocate user-space buffers. */
2914 md->width = stream_info->metadata_info.resolution.width;
2915 md->height = stream_info->metadata_info.resolution.height;
2916 md->stride = stream_info->metadata_info.stride;
2918 /* sanity check to avoid writing into unallocated memory.
2919 * This does not return an error because it is a valid way
2920 * for applications to detect that metadata is not enabled. */
2921 if (md->width == 0 || md->height == 0 || !md->data)
2925 if (md_type < 0 || md_type >= ATOMISP_METADATA_TYPE_NUM)
2928 /* This is done in the atomisp_buf_done() */
2929 if (list_empty(&asd->metadata_ready[md_type])) {
2930 dev_warn(isp->dev, "Metadata queue is empty now!\n");
2934 mipi_info = atomisp_to_sensor_mipi_info(
2935 isp->inputs[asd->input_curr].camera);
2936 if (mipi_info == NULL)
2939 if (mipi_info->metadata_effective_width != NULL) {
2940 for (i = 0; i < md->height; i++)
2941 md->effective_width[i] =
2942 mipi_info->metadata_effective_width[i];
2945 md_buf = list_entry(asd->metadata_ready[md_type].next,
2946 struct atomisp_metadata_buf, list);
2947 md->exp_id = md_buf->metadata->exp_id;
2948 if (md_buf->md_vptr) {
2949 ret = copy_to_user(md->data,
2951 stream_info->metadata_info.size);
2953 hmm_load(md_buf->metadata->address,
2954 asd->params.metadata_user[md_type],
2955 stream_info->metadata_info.size);
2957 ret = copy_to_user(md->data,
2958 asd->params.metadata_user[md_type],
2959 stream_info->metadata_info.size);
2962 dev_err(isp->dev, "copy to user failed: copied %d bytes\n",
2966 list_del_init(&md_buf->list);
2967 list_add_tail(&md_buf->list, &asd->metadata[md_type]);
2969 dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2970 __func__, md_type, md->exp_id);
2975 * Function to calculate real zoom region for every pipe
2977 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd,
2978 struct ia_css_dz_config *dz_config,
2979 enum atomisp_css_pipe_id css_pipe_id)
2982 struct atomisp_stream_env *stream_env =
2983 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2984 struct atomisp_resolution eff_res, out_res;
2986 int w_offset, h_offset;
2989 memset(&eff_res, 0, sizeof(eff_res));
2990 memset(&out_res, 0, sizeof(out_res));
2992 if (dz_config->dx || dz_config->dy)
2995 if (css_pipe_id != IA_CSS_PIPE_ID_PREVIEW
2996 && css_pipe_id != IA_CSS_PIPE_ID_CAPTURE) {
2997 dev_err(asd->isp->dev, "%s the set pipe no support crop region"
3003 stream_env->stream_config.input_config.effective_res.width;
3005 stream_env->stream_config.input_config.effective_res.height;
3006 if (eff_res.width == 0 || eff_res.height == 0) {
3007 dev_err(asd->isp->dev, "%s err effective resolution"
3012 if (dz_config->zoom_region.resolution.width
3013 == asd->sensor_array_res.width
3014 || dz_config->zoom_region.resolution.height
3015 == asd->sensor_array_res.height) {
3016 /*no need crop region*/
3017 dz_config->zoom_region.origin.x = 0;
3018 dz_config->zoom_region.origin.y = 0;
3019 dz_config->zoom_region.resolution.width = eff_res.width;
3020 dz_config->zoom_region.resolution.height = eff_res.height;
3025 * This is not the correct implementation with Google's definition, due
3026 * to firmware limitation.
3027 * map real crop region base on above calculating base max crop region.
3031 stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
3033 stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
3034 if (out_res.width == 0 || out_res.height == 0) {
3035 dev_err(asd->isp->dev, "%s err current pipe output resolution"
3040 if (asd->sensor_array_res.width * out_res.height
3041 < out_res.width * asd->sensor_array_res.height) {
3042 h_offset = asd->sensor_array_res.height -
3043 asd->sensor_array_res.width
3044 * out_res.height / out_res.width;
3045 h_offset = h_offset / 2;
3046 if (dz_config->zoom_region.origin.y < h_offset)
3047 dz_config->zoom_region.origin.y = 0;
3049 dz_config->zoom_region.origin.y =
3050 dz_config->zoom_region.origin.y - h_offset;
3053 w_offset = asd->sensor_array_res.width -
3054 asd->sensor_array_res.height
3055 * out_res.width / out_res.height;
3056 w_offset = w_offset / 2;
3057 if (dz_config->zoom_region.origin.x < w_offset)
3058 dz_config->zoom_region.origin.x = 0;
3060 dz_config->zoom_region.origin.x =
3061 dz_config->zoom_region.origin.x - w_offset;
3065 dz_config->zoom_region.origin.x =
3066 dz_config->zoom_region.origin.x
3069 / asd->sensor_array_res.width;
3071 / (asd->sensor_array_res.width -
3074 dz_config->zoom_region.origin.y =
3075 dz_config->zoom_region.origin.y
3078 / asd->sensor_array_res.height;
3080 / (asd->sensor_array_res.height -
3083 dz_config->zoom_region.resolution.width =
3084 dz_config->zoom_region.resolution.width
3087 / asd->sensor_array_res.width;
3089 / (asd->sensor_array_res.width -
3092 dz_config->zoom_region.resolution.height =
3093 dz_config->zoom_region.resolution.height
3096 / asd->sensor_array_res.height;
3098 / (asd->sensor_array_res.height -
3103 * Set same ratio of crop region resolution and current pipe output
3108 stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
3110 stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
3111 if (out_res.width == 0 || out_res.height == 0) {
3112 dev_err(asd->isp->dev, "%s err current pipe output resolution"
3118 if (out_res.width * dz_config->zoom_region.resolution.height
3119 > dz_config->zoom_region.resolution.width * out_res.height) {
3120 dz_config->zoom_region.resolution.height =
3121 dz_config->zoom_region.resolution.width
3122 * out_res.height / out_res.width;
3124 dz_config->zoom_region.resolution.width =
3125 dz_config->zoom_region.resolution.height
3126 * out_res.width / out_res.height;
3128 dev_dbg(asd->isp->dev, "%s crop region:(%d,%d),(%d,%d) eff_res(%d, %d) array_size(%d,%d) out_res(%d, %d)\n",
3129 __func__, dz_config->zoom_region.origin.x,
3130 dz_config->zoom_region.origin.y,
3131 dz_config->zoom_region.resolution.width,
3132 dz_config->zoom_region.resolution.height,
3133 eff_res.width, eff_res.height,
3134 asd->sensor_array_res.width,
3135 asd->sensor_array_res.height,
3136 out_res.width, out_res.height);
3139 if ((dz_config->zoom_region.origin.x +
3140 dz_config->zoom_region.resolution.width
3142 (dz_config->zoom_region.origin.y +
3143 dz_config->zoom_region.resolution.height
3152 * Function to check the zoom region whether is effective
3154 static bool atomisp_check_zoom_region(
3155 struct atomisp_sub_device *asd,
3156 struct ia_css_dz_config *dz_config)
3158 struct atomisp_resolution config;
3162 memset(&config, 0, sizeof(struct atomisp_resolution));
3164 if (dz_config->dx && dz_config->dy)
3167 config.width = asd->sensor_array_res.width;
3168 config.height = asd->sensor_array_res.height;
3169 w = dz_config->zoom_region.origin.x +
3170 dz_config->zoom_region.resolution.width;
3171 h = dz_config->zoom_region.origin.y +
3172 dz_config->zoom_region.resolution.height;
3174 if ((w <= config.width) && (h <= config.height) && w > 0 && h > 0)
3177 /* setting error zoom region */
3178 dev_err(asd->isp->dev, "%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n",
3179 __func__, dz_config->zoom_region.origin.x,
3180 dz_config->zoom_region.origin.y,
3181 dz_config->zoom_region.resolution.width,
3182 dz_config->zoom_region.resolution.height,
3183 config.width, config.height);
3188 void atomisp_apply_css_parameters(
3189 struct atomisp_sub_device *asd,
3190 struct atomisp_css_params *css_param)
3192 if (css_param->update_flag.wb_config)
3193 atomisp_css_set_wb_config(asd, &css_param->wb_config);
3195 if (css_param->update_flag.ob_config)
3196 atomisp_css_set_ob_config(asd, &css_param->ob_config);
3198 if (css_param->update_flag.dp_config)
3199 atomisp_css_set_dp_config(asd, &css_param->dp_config);
3201 if (css_param->update_flag.nr_config)
3202 atomisp_css_set_nr_config(asd, &css_param->nr_config);
3204 if (css_param->update_flag.ee_config)
3205 atomisp_css_set_ee_config(asd, &css_param->ee_config);
3207 if (css_param->update_flag.tnr_config)
3208 atomisp_css_set_tnr_config(asd, &css_param->tnr_config);
3210 if (css_param->update_flag.a3a_config)
3211 atomisp_css_set_3a_config(asd, &css_param->s3a_config);
3213 if (css_param->update_flag.ctc_config)
3214 atomisp_css_set_ctc_config(asd, &css_param->ctc_config);
3216 if (css_param->update_flag.cnr_config)
3217 atomisp_css_set_cnr_config(asd, &css_param->cnr_config);
3219 if (css_param->update_flag.ecd_config)
3220 atomisp_css_set_ecd_config(asd, &css_param->ecd_config);
3222 if (css_param->update_flag.ynr_config)
3223 atomisp_css_set_ynr_config(asd, &css_param->ynr_config);
3225 if (css_param->update_flag.fc_config)
3226 atomisp_css_set_fc_config(asd, &css_param->fc_config);
3228 if (css_param->update_flag.macc_config)
3229 atomisp_css_set_macc_config(asd, &css_param->macc_config);
3231 if (css_param->update_flag.aa_config)
3232 atomisp_css_set_aa_config(asd, &css_param->aa_config);
3234 if (css_param->update_flag.anr_config)
3235 atomisp_css_set_anr_config(asd, &css_param->anr_config);
3237 if (css_param->update_flag.xnr_config)
3238 atomisp_css_set_xnr_config(asd, &css_param->xnr_config);
3240 if (css_param->update_flag.yuv2rgb_cc_config)
3241 atomisp_css_set_yuv2rgb_cc_config(asd,
3242 &css_param->yuv2rgb_cc_config);
3244 if (css_param->update_flag.rgb2yuv_cc_config)
3245 atomisp_css_set_rgb2yuv_cc_config(asd,
3246 &css_param->rgb2yuv_cc_config);
3248 if (css_param->update_flag.macc_table)
3249 atomisp_css_set_macc_table(asd, &css_param->macc_table);
3251 if (css_param->update_flag.xnr_table)
3252 atomisp_css_set_xnr_table(asd, &css_param->xnr_table);
3254 if (css_param->update_flag.r_gamma_table)
3255 atomisp_css_set_r_gamma_table(asd, &css_param->r_gamma_table);
3257 if (css_param->update_flag.g_gamma_table)
3258 atomisp_css_set_g_gamma_table(asd, &css_param->g_gamma_table);
3260 if (css_param->update_flag.b_gamma_table)
3261 atomisp_css_set_b_gamma_table(asd, &css_param->b_gamma_table);
3263 if (css_param->update_flag.anr_thres)
3264 atomisp_css_set_anr_thres(asd, &css_param->anr_thres);
3266 if (css_param->update_flag.shading_table)
3267 atomisp_css_set_shading_table(asd, css_param->shading_table);
3269 if (css_param->update_flag.morph_table && asd->params.gdc_cac_en)
3270 atomisp_css_set_morph_table(asd, css_param->morph_table);
3272 if (css_param->update_flag.dvs2_coefs) {
3273 struct atomisp_css_dvs_grid_info *dvs_grid_info =
3274 atomisp_css_get_dvs_grid_info(
3275 &asd->params.curr_grid_info);
3277 if (dvs_grid_info && dvs_grid_info->enable)
3278 atomisp_css_set_dvs2_coefs(asd, css_param->dvs2_coeff);
3281 if (css_param->update_flag.dvs_6axis_config)
3282 atomisp_css_set_dvs_6axis(asd, css_param->dvs_6axis);
3284 atomisp_css_set_isp_config_id(asd, css_param->isp_config_id);
3286 * These configurations are on used by ISP1.x, not for ISP2.x,
3287 * so do not handle them. see comments of ia_css_isp_config.
3298 static unsigned int long copy_from_compatible(void *to, const void *from,
3299 unsigned long n, bool from_user)
3302 return copy_from_user(to, from, n);
3304 memcpy(to, from, n);
3308 int atomisp_cp_general_isp_parameters(struct atomisp_sub_device *asd,
3309 struct atomisp_parameters *arg,
3310 struct atomisp_css_params *css_param,
3313 struct atomisp_parameters *cur_config = &css_param->update_flag;
3315 if (!arg || !asd || !css_param)
3318 if (arg->wb_config && (from_user || !cur_config->wb_config)) {
3319 if (copy_from_compatible(&css_param->wb_config, arg->wb_config,
3320 sizeof(struct atomisp_css_wb_config),
3323 css_param->update_flag.wb_config =
3324 (struct atomisp_wb_config *) &css_param->wb_config;
3327 if (arg->ob_config && (from_user || !cur_config->ob_config)) {
3328 if (copy_from_compatible(&css_param->ob_config, arg->ob_config,
3329 sizeof(struct atomisp_css_ob_config),
3332 css_param->update_flag.ob_config =
3333 (struct atomisp_ob_config *) &css_param->ob_config;
3336 if (arg->dp_config && (from_user || !cur_config->dp_config)) {
3337 if (copy_from_compatible(&css_param->dp_config, arg->dp_config,
3338 sizeof(struct atomisp_css_dp_config),
3341 css_param->update_flag.dp_config =
3342 (struct atomisp_dp_config *) &css_param->dp_config;
3345 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
3346 if (arg->dz_config && (from_user || !cur_config->dz_config)) {
3347 if (copy_from_compatible(&css_param->dz_config,
3349 sizeof(struct atomisp_css_dz_config),
3352 if (!atomisp_check_zoom_region(asd,
3353 &css_param->dz_config)) {
3354 dev_err(asd->isp->dev, "crop region error!");
3357 css_param->update_flag.dz_config =
3358 (struct atomisp_dz_config *)
3359 &css_param->dz_config;
3363 if (arg->nr_config && (from_user || !cur_config->nr_config)) {
3364 if (copy_from_compatible(&css_param->nr_config, arg->nr_config,
3365 sizeof(struct atomisp_css_nr_config),
3368 css_param->update_flag.nr_config =
3369 (struct atomisp_nr_config *) &css_param->nr_config;
3372 if (arg->ee_config && (from_user || !cur_config->ee_config)) {
3373 if (copy_from_compatible(&css_param->ee_config, arg->ee_config,
3374 sizeof(struct atomisp_css_ee_config),
3377 css_param->update_flag.ee_config =
3378 (struct atomisp_ee_config *) &css_param->ee_config;
3381 if (arg->tnr_config && (from_user || !cur_config->tnr_config)) {
3382 if (copy_from_compatible(&css_param->tnr_config,
3384 sizeof(struct atomisp_css_tnr_config),
3387 css_param->update_flag.tnr_config =
3388 (struct atomisp_tnr_config *)
3389 &css_param->tnr_config;
3392 if (arg->a3a_config && (from_user || !cur_config->a3a_config)) {
3393 if (copy_from_compatible(&css_param->s3a_config,
3395 sizeof(struct atomisp_css_3a_config),
3398 css_param->update_flag.a3a_config =
3399 (struct atomisp_3a_config *) &css_param->s3a_config;
3402 if (arg->ctc_config && (from_user || !cur_config->ctc_config)) {
3403 if (copy_from_compatible(&css_param->ctc_config,
3405 sizeof(struct atomisp_css_ctc_config),
3408 css_param->update_flag.ctc_config =
3409 (struct atomisp_ctc_config *)
3410 &css_param->ctc_config;
3413 if (arg->cnr_config && (from_user || !cur_config->cnr_config)) {
3414 if (copy_from_compatible(&css_param->cnr_config,
3416 sizeof(struct atomisp_css_cnr_config),
3419 css_param->update_flag.cnr_config =
3420 (struct atomisp_cnr_config *)
3421 &css_param->cnr_config;
3424 if (arg->ecd_config && (from_user || !cur_config->ecd_config)) {
3425 if (copy_from_compatible(&css_param->ecd_config,
3427 sizeof(struct atomisp_css_ecd_config),
3430 css_param->update_flag.ecd_config =
3431 (struct atomisp_ecd_config *)
3432 &css_param->ecd_config;
3435 if (arg->ynr_config && (from_user || !cur_config->ynr_config)) {
3436 if (copy_from_compatible(&css_param->ynr_config,
3438 sizeof(struct atomisp_css_ynr_config),
3441 css_param->update_flag.ynr_config =
3442 (struct atomisp_ynr_config *)
3443 &css_param->ynr_config;
3446 if (arg->fc_config && (from_user || !cur_config->fc_config)) {
3447 if (copy_from_compatible(&css_param->fc_config,
3449 sizeof(struct atomisp_css_fc_config),
3452 css_param->update_flag.fc_config =
3453 (struct atomisp_fc_config *) &css_param->fc_config;
3456 if (arg->macc_config && (from_user || !cur_config->macc_config)) {
3457 if (copy_from_compatible(&css_param->macc_config,
3459 sizeof(struct atomisp_css_macc_config),
3462 css_param->update_flag.macc_config =
3463 (struct atomisp_macc_config *)
3464 &css_param->macc_config;
3467 if (arg->aa_config && (from_user || !cur_config->aa_config)) {
3468 if (copy_from_compatible(&css_param->aa_config, arg->aa_config,
3469 sizeof(struct atomisp_css_aa_config),
3472 css_param->update_flag.aa_config =
3473 (struct atomisp_aa_config *) &css_param->aa_config;
3476 if (arg->anr_config && (from_user || !cur_config->anr_config)) {
3477 if (copy_from_compatible(&css_param->anr_config,
3479 sizeof(struct atomisp_css_anr_config),
3482 css_param->update_flag.anr_config =
3483 (struct atomisp_anr_config *)
3484 &css_param->anr_config;
3487 if (arg->xnr_config && (from_user || !cur_config->xnr_config)) {
3488 if (copy_from_compatible(&css_param->xnr_config,
3490 sizeof(struct atomisp_css_xnr_config),
3493 css_param->update_flag.xnr_config =
3494 (struct atomisp_xnr_config *)
3495 &css_param->xnr_config;
3498 if (arg->yuv2rgb_cc_config &&
3499 (from_user || !cur_config->yuv2rgb_cc_config)) {
3500 if (copy_from_compatible(&css_param->yuv2rgb_cc_config,
3501 arg->yuv2rgb_cc_config,
3502 sizeof(struct atomisp_css_cc_config),
3505 css_param->update_flag.yuv2rgb_cc_config =
3506 (struct atomisp_cc_config *)
3507 &css_param->yuv2rgb_cc_config;
3510 if (arg->rgb2yuv_cc_config &&
3511 (from_user || !cur_config->rgb2yuv_cc_config)) {
3512 if (copy_from_compatible(&css_param->rgb2yuv_cc_config,
3513 arg->rgb2yuv_cc_config,
3514 sizeof(struct atomisp_css_cc_config),
3517 css_param->update_flag.rgb2yuv_cc_config =
3518 (struct atomisp_cc_config *)
3519 &css_param->rgb2yuv_cc_config;
3522 if (arg->macc_table && (from_user || !cur_config->macc_table)) {
3523 if (copy_from_compatible(&css_param->macc_table,
3525 sizeof(struct atomisp_css_macc_table),
3528 css_param->update_flag.macc_table =
3529 (struct atomisp_macc_table *)
3530 &css_param->macc_table;
3533 if (arg->xnr_table && (from_user || !cur_config->xnr_table)) {
3534 if (copy_from_compatible(&css_param->xnr_table,
3536 sizeof(struct atomisp_css_xnr_table),
3539 css_param->update_flag.xnr_table =
3540 (struct atomisp_xnr_table *) &css_param->xnr_table;
3543 if (arg->r_gamma_table && (from_user || !cur_config->r_gamma_table)) {
3544 if (copy_from_compatible(&css_param->r_gamma_table,
3546 sizeof(struct atomisp_css_rgb_gamma_table),
3549 css_param->update_flag.r_gamma_table =
3550 (struct atomisp_rgb_gamma_table *)
3551 &css_param->r_gamma_table;
3554 if (arg->g_gamma_table && (from_user || !cur_config->g_gamma_table)) {
3555 if (copy_from_compatible(&css_param->g_gamma_table,
3557 sizeof(struct atomisp_css_rgb_gamma_table),
3560 css_param->update_flag.g_gamma_table =
3561 (struct atomisp_rgb_gamma_table *)
3562 &css_param->g_gamma_table;
3565 if (arg->b_gamma_table && (from_user || !cur_config->b_gamma_table)) {
3566 if (copy_from_compatible(&css_param->b_gamma_table,
3568 sizeof(struct atomisp_css_rgb_gamma_table),
3571 css_param->update_flag.b_gamma_table =
3572 (struct atomisp_rgb_gamma_table *)
3573 &css_param->b_gamma_table;
3576 if (arg->anr_thres && (from_user || !cur_config->anr_thres)) {
3577 if (copy_from_compatible(&css_param->anr_thres, arg->anr_thres,
3578 sizeof(struct atomisp_css_anr_thres),
3581 css_param->update_flag.anr_thres =
3582 (struct atomisp_anr_thres *) &css_param->anr_thres;
3586 css_param->isp_config_id = arg->isp_config_id;
3588 * These configurations are on used by ISP1.x, not for ISP2.x,
3589 * so do not handle them. see comments of ia_css_isp_config.
3601 int atomisp_cp_lsc_table(struct atomisp_sub_device *asd,
3602 struct atomisp_shading_table *source_st,
3603 struct atomisp_css_params *css_param,
3607 unsigned int len_table;
3608 struct atomisp_css_shading_table *shading_table;
3609 struct atomisp_css_shading_table *old_table;
3611 struct atomisp_shading_table st;
3620 if (!from_user && css_param->update_flag.shading_table)
3624 if (copy_from_compatible(&st, source_st,
3625 sizeof(struct atomisp_shading_table),
3627 dev_err(asd->isp->dev, "copy shading table failed!");
3632 old_table = css_param->shading_table;
3637 /* user config is to disable the shading table. */
3639 if (!source_st->enable) {
3643 /* Generate a minimum table with enable = 0. */
3644 shading_table = atomisp_css_shading_table_alloc(1, 1);
3647 shading_table->enable = 0;
3651 /* Setting a new table. Validate first - all tables must be set */
3652 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3654 if (!source_st->data[i])
3657 dev_err(asd->isp->dev, "shading table validate failed");
3665 /* Shading table size per color */
3667 if (source_st->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
3668 source_st->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR)
3670 if (st.width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
3671 st.height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) {
3672 dev_err(asd->isp->dev, "shading table w/h validate failed!");
3680 shading_table = atomisp_css_shading_table_alloc(source_st->width,
3685 shading_table = atomisp_css_shading_table_alloc(st.width,
3687 if (!shading_table) {
3688 dev_err(asd->isp->dev, "shading table alloc failed!");
3694 len_table = source_st->width * source_st->height * ATOMISP_SC_TYPE_SIZE;
3696 len_table = st.width * st.height * ATOMISP_SC_TYPE_SIZE;
3698 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3699 if (copy_from_compatible(shading_table->data[i],
3701 source_st->data[i], len_table, from_user)) {
3703 st.data[i], len_table, from_user)) {
3705 atomisp_css_shading_table_free(shading_table);
3711 shading_table->sensor_width = source_st->sensor_width;
3712 shading_table->sensor_height = source_st->sensor_height;
3713 shading_table->fraction_bits = source_st->fraction_bits;
3714 shading_table->enable = source_st->enable;
3716 shading_table->sensor_width = st.sensor_width;
3717 shading_table->sensor_height = st.sensor_height;
3718 shading_table->fraction_bits = st.fraction_bits;
3719 shading_table->enable = st.enable;
3722 /* No need to update shading table if it is the same */
3723 if (old_table != NULL &&
3724 old_table->sensor_width == shading_table->sensor_width &&
3725 old_table->sensor_height == shading_table->sensor_height &&
3726 old_table->width == shading_table->width &&
3727 old_table->height == shading_table->height &&
3728 old_table->fraction_bits == shading_table->fraction_bits &&
3729 old_table->enable == shading_table->enable) {
3730 bool data_is_same = true;
3732 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3733 if (memcmp(shading_table->data[i], old_table->data[i],
3735 data_is_same = false;
3741 atomisp_css_shading_table_free(shading_table);
3747 /* set LSC to CSS */
3748 css_param->shading_table = shading_table;
3749 css_param->update_flag.shading_table =
3750 (struct atomisp_shading_table *) shading_table;
3751 asd->params.sc_en = shading_table != NULL;
3754 atomisp_css_shading_table_free(old_table);
3759 int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd,
3760 struct ia_css_dvs2_coefficients *coefs,
3761 struct atomisp_css_params *css_param,
3764 struct atomisp_css_dvs_grid_info *cur =
3765 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
3766 int dvs_hor_coef_bytes, dvs_ver_coef_bytes;
3768 struct ia_css_dvs2_coefficients dvs2_coefs;
3774 if (!from_user && css_param->update_flag.dvs2_coefs)
3778 if (sizeof(*cur) != sizeof(coefs->grid) ||
3779 memcmp(&coefs->grid, cur, sizeof(coefs->grid))) {
3781 if (copy_from_compatible(&dvs2_coefs, coefs,
3782 sizeof(struct ia_css_dvs2_coefficients),
3784 dev_err(asd->isp->dev, "copy dvs2 coef failed");
3788 if (sizeof(*cur) != sizeof(dvs2_coefs.grid) ||
3789 memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) {
3791 dev_err(asd->isp->dev, "dvs grid mis-match!\n");
3792 /* If the grid info in the argument differs from the current
3793 grid info, we tell the caller to reset the grid size and
3799 if (coefs->hor_coefs.odd_real == NULL ||
3800 coefs->hor_coefs.odd_imag == NULL ||
3801 coefs->hor_coefs.even_real == NULL ||
3802 coefs->hor_coefs.even_imag == NULL ||
3803 coefs->ver_coefs.odd_real == NULL ||
3804 coefs->ver_coefs.odd_imag == NULL ||
3805 coefs->ver_coefs.even_real == NULL ||
3806 coefs->ver_coefs.even_imag == NULL)
3808 if (dvs2_coefs.hor_coefs.odd_real == NULL ||
3809 dvs2_coefs.hor_coefs.odd_imag == NULL ||
3810 dvs2_coefs.hor_coefs.even_real == NULL ||
3811 dvs2_coefs.hor_coefs.even_imag == NULL ||
3812 dvs2_coefs.ver_coefs.odd_real == NULL ||
3813 dvs2_coefs.ver_coefs.odd_imag == NULL ||
3814 dvs2_coefs.ver_coefs.even_real == NULL ||
3815 dvs2_coefs.ver_coefs.even_imag == NULL)
3819 if (!css_param->dvs2_coeff) {
3820 /* DIS coefficients. */
3821 css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur);
3822 if (!css_param->dvs2_coeff)
3826 dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes;
3827 dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes;
3828 if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real,
3830 coefs->hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
3832 dvs2_coefs.hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
3834 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag,
3836 coefs->hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
3838 dvs2_coefs.hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
3840 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real,
3842 coefs->hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
3844 dvs2_coefs.hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
3846 copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag,
3848 coefs->hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
3850 dvs2_coefs.hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
3852 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real,
3854 coefs->ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
3856 dvs2_coefs.ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
3858 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag,
3860 coefs->ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
3862 dvs2_coefs.ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
3864 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real,
3866 coefs->ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
3868 dvs2_coefs.ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
3870 copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag,
3872 coefs->ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
3874 dvs2_coefs.ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
3876 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
3877 css_param->dvs2_coeff = NULL;
3881 css_param->update_flag.dvs2_coefs =
3882 (struct atomisp_dvs2_coefficients *)css_param->dvs2_coeff;
3886 int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd,
3887 struct atomisp_dvs_6axis_config *source_6axis_config,
3888 struct atomisp_css_params *css_param,
3891 struct atomisp_css_dvs_6axis_config *dvs_6axis_config;
3892 struct atomisp_css_dvs_6axis_config *old_6axis_config;
3894 struct atomisp_css_dvs_6axis_config t_6axis_config;
3896 struct ia_css_stream *stream =
3897 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
3898 struct atomisp_css_dvs_grid_info *dvs_grid_info =
3899 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
3902 if (stream == NULL) {
3903 dev_err(asd->isp->dev, "%s: internal error!", __func__);
3907 if (!source_6axis_config || !dvs_grid_info)
3910 if (!dvs_grid_info->enable)
3913 if (!from_user && css_param->update_flag.dvs_6axis_config)
3916 /* check whether need to reallocate for 6 axis config */
3917 old_6axis_config = css_param->dvs_6axis;
3918 dvs_6axis_config = old_6axis_config;
3921 if (copy_from_compatible(&t_6axis_config, source_6axis_config,
3922 sizeof(struct atomisp_dvs_6axis_config),
3924 dev_err(asd->isp->dev, "copy morph table failed!");
3929 if (old_6axis_config &&
3931 (old_6axis_config->width_y != source_6axis_config->width_y ||
3932 old_6axis_config->height_y != source_6axis_config->height_y ||
3933 old_6axis_config->width_uv != source_6axis_config->width_uv ||
3934 old_6axis_config->height_uv != source_6axis_config->height_uv)) {
3936 (old_6axis_config->width_y != t_6axis_config.width_y ||
3937 old_6axis_config->height_y != t_6axis_config.height_y ||
3938 old_6axis_config->width_uv != t_6axis_config.width_uv ||
3939 old_6axis_config->height_uv != t_6axis_config.height_uv)) {
3941 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
3942 css_param->dvs_6axis = NULL;
3944 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3945 if (!dvs_6axis_config)
3947 } else if (!dvs_6axis_config) {
3948 dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3949 if (!dvs_6axis_config)
3954 dvs_6axis_config->exp_id = source_6axis_config->exp_id;
3956 dvs_6axis_config->exp_id = t_6axis_config.exp_id;
3959 if (copy_from_compatible(dvs_6axis_config->xcoords_y,
3961 source_6axis_config->xcoords_y,
3962 source_6axis_config->width_y *
3963 source_6axis_config->height_y *
3964 sizeof(*source_6axis_config->xcoords_y),
3966 t_6axis_config.xcoords_y,
3967 t_6axis_config.width_y *
3968 t_6axis_config.height_y *
3969 sizeof(*dvs_6axis_config->xcoords_y),
3973 if (copy_from_compatible(dvs_6axis_config->ycoords_y,
3975 source_6axis_config->ycoords_y,
3976 source_6axis_config->width_y *
3977 source_6axis_config->height_y *
3978 sizeof(*source_6axis_config->ycoords_y),
3980 t_6axis_config.ycoords_y,
3981 t_6axis_config.width_y *
3982 t_6axis_config.height_y *
3983 sizeof(*dvs_6axis_config->ycoords_y),
3987 if (copy_from_compatible(dvs_6axis_config->xcoords_uv,
3989 source_6axis_config->xcoords_uv,
3990 source_6axis_config->width_uv *
3991 source_6axis_config->height_uv *
3992 sizeof(*source_6axis_config->xcoords_uv),
3994 t_6axis_config.xcoords_uv,
3995 t_6axis_config.width_uv *
3996 t_6axis_config.height_uv *
3997 sizeof(*dvs_6axis_config->xcoords_uv),
4001 if (copy_from_compatible(dvs_6axis_config->ycoords_uv,
4003 source_6axis_config->ycoords_uv,
4004 source_6axis_config->width_uv *
4005 source_6axis_config->height_uv *
4006 sizeof(*source_6axis_config->ycoords_uv),
4008 t_6axis_config.ycoords_uv,
4009 t_6axis_config.width_uv *
4010 t_6axis_config.height_uv *
4011 sizeof(*dvs_6axis_config->ycoords_uv),
4016 css_param->dvs_6axis = dvs_6axis_config;
4017 css_param->update_flag.dvs_6axis_config =
4018 (struct atomisp_dvs_6axis_config *) dvs_6axis_config;
4022 if (dvs_6axis_config)
4023 ia_css_dvs2_6axis_config_free(dvs_6axis_config);
4027 int atomisp_cp_morph_table(struct atomisp_sub_device *asd,
4028 struct atomisp_morph_table *source_morph_table,
4029 struct atomisp_css_params *css_param,
4034 struct atomisp_css_morph_table *morph_table;
4036 struct atomisp_css_morph_table mtbl;
4038 struct atomisp_css_morph_table *old_morph_table;
4040 if (!source_morph_table)
4043 if (!from_user && css_param->update_flag.morph_table)
4046 old_morph_table = css_param->morph_table;
4049 if (copy_from_compatible(&mtbl, source_morph_table,
4050 sizeof(struct atomisp_morph_table),
4052 dev_err(asd->isp->dev, "copy morph table failed!");
4057 morph_table = atomisp_css_morph_table_allocate(
4059 source_morph_table->width,
4060 source_morph_table->height);
4068 for (i = 0; i < CSS_MORPH_TABLE_NUM_PLANES; i++) {
4069 if (copy_from_compatible(morph_table->coordinates_x[i],
4070 source_morph_table->coordinates_x[i],
4072 source_morph_table->height * source_morph_table->width *
4073 sizeof(*source_morph_table->coordinates_x[i]),
4075 mtbl.height * mtbl.width *
4076 sizeof(*morph_table->coordinates_x[i]),
4081 if (copy_from_compatible(morph_table->coordinates_y[i],
4082 source_morph_table->coordinates_y[i],
4084 source_morph_table->height * source_morph_table->width *
4085 sizeof(*source_morph_table->coordinates_y[i]),
4087 mtbl.height * mtbl.width *
4088 sizeof(*morph_table->coordinates_y[i]),
4094 css_param->morph_table = morph_table;
4095 if (old_morph_table)
4096 atomisp_css_morph_table_free(old_morph_table);
4097 css_param->update_flag.morph_table =
4098 (struct atomisp_morph_table *) morph_table;
4103 atomisp_css_morph_table_free(morph_table);
4107 int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd,
4108 struct atomisp_parameters *arg,
4109 struct atomisp_css_params *css_param)
4113 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, false);
4116 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, false);
4119 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, false);
4122 ret = atomisp_css_cp_dvs2_coefs(asd,
4123 (struct ia_css_dvs2_coefficients *) arg->dvs2_coefs,
4127 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
4132 void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
4134 if (css_param->dvs_6axis) {
4135 ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
4136 css_param->dvs_6axis = NULL;
4138 if (css_param->dvs2_coeff) {
4139 ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
4140 css_param->dvs2_coeff = NULL;
4142 if (css_param->shading_table) {
4143 ia_css_shading_table_free(css_param->shading_table);
4144 css_param->shading_table = NULL;
4146 if (css_param->morph_table) {
4147 ia_css_morph_table_free(css_param->morph_table);
4148 css_param->morph_table = NULL;
4153 * Check parameter queue list and buffer queue list to find out if matched items
4154 * and then set parameter to CSS and enqueue buffer to CSS.
4155 * Of course, if the buffer in buffer waiting list is not bound to a per-frame
4156 * parameter, it will be enqueued into CSS as long as the per-frame setting
4157 * buffers before it get enqueued.
4159 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
4161 struct atomisp_sub_device *asd = pipe->asd;
4162 struct videobuf_buffer *vb = NULL, *vb_tmp;
4163 struct atomisp_css_params_with_list *param = NULL, *param_tmp;
4164 struct videobuf_vmalloc_memory *vm_mem = NULL;
4165 unsigned long irqflags;
4166 bool need_to_enqueue_buffer = false;
4168 if (atomisp_is_vf_pipe(pipe))
4172 * CSS/FW requires set parameter and enqueue buffer happen after ISP
4175 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
4178 if (list_empty(&pipe->per_frame_params) ||
4179 list_empty(&pipe->buffers_waiting_for_param))
4182 list_for_each_entry_safe(vb, vb_tmp,
4183 &pipe->buffers_waiting_for_param, queue) {
4184 if (pipe->frame_request_config_id[vb->i]) {
4185 list_for_each_entry_safe(param, param_tmp,
4186 &pipe->per_frame_params, list) {
4187 if (pipe->frame_request_config_id[vb->i] !=
4188 param->params.isp_config_id)
4191 list_del(¶m->list);
4192 list_del(&vb->queue);
4194 * clear the request config id as the buffer
4195 * will be handled and enqueued into CSS soon
4197 pipe->frame_request_config_id[vb->i] = 0;
4198 pipe->frame_params[vb->i] = param;
4205 spin_lock_irqsave(&pipe->irq_lock, irqflags);
4206 list_add_tail(&vb->queue, &pipe->activeq);
4207 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
4209 need_to_enqueue_buffer = true;
4211 /* The is the end, stop further loop */
4215 list_del(&vb->queue);
4216 pipe->frame_params[vb->i] = NULL;
4217 spin_lock_irqsave(&pipe->irq_lock, irqflags);
4218 list_add_tail(&vb->queue, &pipe->activeq);
4219 spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
4220 need_to_enqueue_buffer = true;
4224 if (need_to_enqueue_buffer) {
4225 atomisp_qbuffers_to_css(asd);
4227 if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd))
4228 atomisp_wdt_start(asd);
4230 if (atomisp_buffers_queued_pipe(pipe)) {
4231 if (!atomisp_is_wdt_running(pipe))
4232 atomisp_wdt_start(pipe);
4234 atomisp_wdt_refresh_pipe(pipe,
4235 ATOMISP_WDT_KEEP_CURRENT_DELAY);
4242 * Function to configure ISP parameters
4244 int atomisp_set_parameters(struct video_device *vdev,
4245 struct atomisp_parameters *arg)
4247 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
4248 struct atomisp_sub_device *asd = pipe->asd;
4249 struct atomisp_css_params_with_list *param = NULL;
4250 struct atomisp_css_params *css_param = &asd->params.css_param;
4253 if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream == NULL) {
4254 dev_err(asd->isp->dev, "%s: internal error!\n", __func__);
4258 dev_dbg(asd->isp->dev, "%s: set parameter(per_frame_setting %d) for asd%d with isp_config_id %d of %s\n",
4259 __func__, arg->per_frame_setting, asd->index,
4260 arg->isp_config_id, vdev->name);
4263 if (atomisp_is_vf_pipe(pipe) && arg->per_frame_setting) {
4264 dev_err(asd->isp->dev, "%s: vf pipe not support per_frame_setting",
4270 if (arg->per_frame_setting && !atomisp_is_vf_pipe(pipe)) {
4272 * Per-frame setting enabled, we allocate a new paramter
4273 * buffer to cache the parameters and only when frame buffers
4274 * are ready, the parameters will be set to CSS.
4275 * per-frame setting only works for the main output frame.
4277 param = kvzalloc(sizeof(*param), GFP_KERNEL);
4279 dev_err(asd->isp->dev, "%s: failed to alloc params buffer\n",
4283 css_param = ¶m->params;
4286 ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, true);
4288 goto apply_parameter_failed;
4290 ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, true);
4292 goto apply_parameter_failed;
4294 ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, true);
4296 goto apply_parameter_failed;
4298 ret = atomisp_css_cp_dvs2_coefs(asd,
4299 (struct ia_css_dvs2_coefficients *) arg->dvs2_coefs,
4302 goto apply_parameter_failed;
4304 ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
4307 goto apply_parameter_failed;
4309 if (!(arg->per_frame_setting && !atomisp_is_vf_pipe(pipe))) {
4310 /* indicate to CSS that we have parameters to be updated */
4311 asd->params.css_update_params_needed = true;
4313 list_add_tail(¶m->list, &pipe->per_frame_params);
4314 atomisp_handle_parameter_and_buffer(pipe);
4319 apply_parameter_failed:
4321 atomisp_free_css_parameters(css_param);
4329 * Function to set/get isp parameters to isp
4331 int atomisp_param(struct atomisp_sub_device *asd, int flag,
4332 struct atomisp_parm *config)
4334 struct atomisp_device *isp = asd->isp;
4335 struct ia_css_pipe_config *vp_cfg =
4336 &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
4337 pipe_configs[IA_CSS_PIPE_ID_VIDEO];
4339 /* Read parameter for 3A binary info */
4341 struct atomisp_css_dvs_grid_info *dvs_grid_info =
4342 atomisp_css_get_dvs_grid_info(
4343 &asd->params.curr_grid_info);
4345 if (&config->info == NULL) {
4346 dev_err(isp->dev, "ERROR: NULL pointer in grid_info\n");
4349 atomisp_curr_user_grid_info(asd, &config->info);
4351 /* We always return the resolution and stride even if there is
4352 * no valid metadata. This allows the caller to get the
4353 * information needed to allocate user-space buffers. */
4354 config->metadata_config.metadata_height = asd->
4355 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
4356 metadata_info.resolution.height;
4357 config->metadata_config.metadata_stride = asd->
4358 stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
4359 metadata_info.stride;
4361 /* update dvs grid info */
4363 memcpy(&config->dvs_grid,
4365 sizeof(struct atomisp_css_dvs_grid_info));
4367 if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
4368 config->dvs_envelop.width = 0;
4369 config->dvs_envelop.height = 0;
4373 /* update dvs envelop info */
4374 if (!asd->continuous_mode->val) {
4375 config->dvs_envelop.width = vp_cfg->dvs_envelope.width;
4376 config->dvs_envelop.height =
4377 vp_cfg->dvs_envelope.height;
4379 unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max;
4381 dvs_w = vp_cfg->bayer_ds_out_res.width -
4382 vp_cfg->output_info[0].res.width;
4383 dvs_h = vp_cfg->bayer_ds_out_res.height -
4384 vp_cfg->output_info[0].res.height;
4385 dvs_w_max = rounddown(
4386 vp_cfg->output_info[0].res.width / 5,
4387 ATOM_ISP_STEP_WIDTH);
4388 dvs_h_max = rounddown(
4389 vp_cfg->output_info[0].res.height / 5,
4390 ATOM_ISP_STEP_HEIGHT);
4392 config->dvs_envelop.width = min(dvs_w, dvs_w_max);
4393 config->dvs_envelop.height = min(dvs_h, dvs_h_max);
4399 memcpy(&asd->params.css_param.wb_config, &config->wb_config,
4400 sizeof(struct atomisp_css_wb_config));
4401 memcpy(&asd->params.css_param.ob_config, &config->ob_config,
4402 sizeof(struct atomisp_css_ob_config));
4403 memcpy(&asd->params.css_param.dp_config, &config->dp_config,
4404 sizeof(struct atomisp_css_dp_config));
4405 memcpy(&asd->params.css_param.de_config, &config->de_config,
4406 sizeof(struct atomisp_css_de_config));
4407 memcpy(&asd->params.css_param.dz_config, &config->dz_config,
4408 sizeof(struct atomisp_css_dz_config));
4409 memcpy(&asd->params.css_param.ce_config, &config->ce_config,
4410 sizeof(struct atomisp_css_ce_config));
4411 memcpy(&asd->params.css_param.nr_config, &config->nr_config,
4412 sizeof(struct atomisp_css_nr_config));
4413 memcpy(&asd->params.css_param.ee_config, &config->ee_config,
4414 sizeof(struct atomisp_css_ee_config));
4415 memcpy(&asd->params.css_param.tnr_config, &config->tnr_config,
4416 sizeof(struct atomisp_css_tnr_config));
4418 if (asd->params.color_effect == V4L2_COLORFX_NEGATIVE) {
4419 asd->params.css_param.cc_config.matrix[3] = -config->cc_config.matrix[3];
4420 asd->params.css_param.cc_config.matrix[4] = -config->cc_config.matrix[4];
4421 asd->params.css_param.cc_config.matrix[5] = -config->cc_config.matrix[5];
4422 asd->params.css_param.cc_config.matrix[6] = -config->cc_config.matrix[6];
4423 asd->params.css_param.cc_config.matrix[7] = -config->cc_config.matrix[7];
4424 asd->params.css_param.cc_config.matrix[8] = -config->cc_config.matrix[8];
4427 if (asd->params.color_effect != V4L2_COLORFX_SEPIA &&
4428 asd->params.color_effect != V4L2_COLORFX_BW) {
4429 memcpy(&asd->params.css_param.cc_config, &config->cc_config,
4430 sizeof(struct atomisp_css_cc_config));
4431 atomisp_css_set_cc_config(asd, &asd->params.css_param.cc_config);
4434 atomisp_css_set_wb_config(asd, &asd->params.css_param.wb_config);
4435 atomisp_css_set_ob_config(asd, &asd->params.css_param.ob_config);
4436 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config);
4437 atomisp_css_set_dz_config(asd, &asd->params.css_param.dz_config);
4438 atomisp_css_set_ce_config(asd, &asd->params.css_param.ce_config);
4439 atomisp_css_set_dp_config(asd, &asd->params.css_param.dp_config);
4440 atomisp_css_set_nr_config(asd, &asd->params.css_param.nr_config);
4441 atomisp_css_set_ee_config(asd, &asd->params.css_param.ee_config);
4442 atomisp_css_set_tnr_config(asd, &asd->params.css_param.tnr_config);
4443 asd->params.css_update_params_needed = true;
4449 * Function to configure color effect of the image
4451 int atomisp_color_effect(struct atomisp_sub_device *asd, int flag,
4454 struct atomisp_css_cc_config *cc_config = NULL;
4455 struct atomisp_css_macc_table *macc_table = NULL;
4456 struct atomisp_css_ctc_table *ctc_table = NULL;
4458 struct v4l2_control control;
4459 struct atomisp_device *isp = asd->isp;
4462 *effect = asd->params.color_effect;
4467 control.id = V4L2_CID_COLORFX;
4468 control.value = *effect;
4470 v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].camera->ctrl_handler,
4473 * if set color effect to sensor successfully, return
4477 asd->params.color_effect = (u32)*effect;
4481 if (*effect == asd->params.color_effect)
4485 * isp_subdev->params.macc_en should be set to false.
4487 asd->params.macc_en = false;
4490 case V4L2_COLORFX_NONE:
4491 macc_table = &asd->params.css_param.macc_table;
4492 asd->params.macc_en = true;
4494 case V4L2_COLORFX_SEPIA:
4495 cc_config = &sepia_cc_config;
4497 case V4L2_COLORFX_NEGATIVE:
4498 cc_config = &nega_cc_config;
4500 case V4L2_COLORFX_BW:
4501 cc_config = &mono_cc_config;
4503 case V4L2_COLORFX_SKY_BLUE:
4504 macc_table = &blue_macc_table;
4505 asd->params.macc_en = true;
4507 case V4L2_COLORFX_GRASS_GREEN:
4508 macc_table = &green_macc_table;
4509 asd->params.macc_en = true;
4511 case V4L2_COLORFX_SKIN_WHITEN_LOW:
4512 macc_table = &skin_low_macc_table;
4513 asd->params.macc_en = true;
4515 case V4L2_COLORFX_SKIN_WHITEN:
4516 macc_table = &skin_medium_macc_table;
4517 asd->params.macc_en = true;
4519 case V4L2_COLORFX_SKIN_WHITEN_HIGH:
4520 macc_table = &skin_high_macc_table;
4521 asd->params.macc_en = true;
4523 case V4L2_COLORFX_VIVID:
4524 ctc_table = &vivid_ctc_table;
4529 atomisp_update_capture_mode(asd);
4532 atomisp_css_set_cc_config(asd, cc_config);
4534 atomisp_css_set_macc_table(asd, macc_table);
4536 atomisp_css_set_ctc_table(asd, ctc_table);
4537 asd->params.color_effect = (u32)*effect;
4538 asd->params.css_update_params_needed = true;
4543 * Function to configure bad pixel correction
4545 int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag,
4550 *value = asd->params.bad_pixel_en;
4553 asd->params.bad_pixel_en = !!*value;
4559 * Function to configure bad pixel correction params
4561 int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag,
4562 struct atomisp_dp_config *config)
4565 /* Get bad pixel from current setup */
4566 if (atomisp_css_get_dp_config(asd, config))
4569 /* Set bad pixel to isp parameters */
4570 memcpy(&asd->params.css_param.dp_config, config,
4571 sizeof(asd->params.css_param.dp_config));
4572 atomisp_css_set_dp_config(asd, &asd->params.css_param.dp_config);
4573 asd->params.css_update_params_needed = true;
4580 * Function to enable/disable video image stablization
4582 int atomisp_video_stable(struct atomisp_sub_device *asd, int flag,
4586 *value = asd->params.video_dis_en;
4588 asd->params.video_dis_en = !!*value;
4594 * Function to configure fixed pattern noise
4596 int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
4601 *value = asd->params.fpn_en;
4606 asd->params.fpn_en = 0;
4610 /* Add function to get black from from sensor with shutter off */
4615 atomisp_bytesperline_to_padded_width(unsigned int bytesperline,
4616 enum atomisp_css_frame_format format)
4619 case CSS_FRAME_FORMAT_UYVY:
4620 case CSS_FRAME_FORMAT_YUYV:
4621 case CSS_FRAME_FORMAT_RAW:
4622 case CSS_FRAME_FORMAT_RGB565:
4623 return bytesperline/2;
4624 case CSS_FRAME_FORMAT_RGBA888:
4625 return bytesperline/4;
4626 /* The following cases could be removed, but we leave them
4627 in to document the formats that are included. */
4628 case CSS_FRAME_FORMAT_NV11:
4629 case CSS_FRAME_FORMAT_NV12:
4630 case CSS_FRAME_FORMAT_NV16:
4631 case CSS_FRAME_FORMAT_NV21:
4632 case CSS_FRAME_FORMAT_NV61:
4633 case CSS_FRAME_FORMAT_YV12:
4634 case CSS_FRAME_FORMAT_YV16:
4635 case CSS_FRAME_FORMAT_YUV420:
4636 case CSS_FRAME_FORMAT_YUV420_16:
4637 case CSS_FRAME_FORMAT_YUV422:
4638 case CSS_FRAME_FORMAT_YUV422_16:
4639 case CSS_FRAME_FORMAT_YUV444:
4640 case CSS_FRAME_FORMAT_YUV_LINE:
4641 case CSS_FRAME_FORMAT_PLANAR_RGB888:
4642 case CSS_FRAME_FORMAT_QPLANE6:
4643 case CSS_FRAME_FORMAT_BINARY_8:
4645 return bytesperline;
4650 atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer *arg,
4651 struct atomisp_css_frame **result)
4653 struct atomisp_css_frame *res = NULL;
4654 unsigned int padded_width;
4655 enum atomisp_css_frame_format sh_format;
4656 char *tmp_buf = NULL;
4659 sh_format = v4l2_fmt_to_sh_fmt(arg->fmt.pixelformat);
4660 padded_width = atomisp_bytesperline_to_padded_width(
4661 arg->fmt.bytesperline, sh_format);
4663 /* Note: the padded width on an atomisp_css_frame is in elements, not in
4664 bytes. The RAW frame we use here should always be a 16bit RAW
4665 frame. This is why we bytesperline/2 is equal to the padded with */
4666 if (atomisp_css_frame_allocate(&res, arg->fmt.width, arg->fmt.height,
4667 sh_format, padded_width, 0)) {
4672 tmp_buf = vmalloc(arg->fmt.sizeimage);
4677 if (copy_from_user(tmp_buf, (void __user __force *)arg->base,
4678 arg->fmt.sizeimage)) {
4683 if (hmm_store(res->data, tmp_buf, arg->fmt.sizeimage)) {
4690 atomisp_css_frame_free(res);
4699 * Function to configure fixed pattern noise table
4701 int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd,
4702 struct v4l2_framebuffer *arg)
4704 struct atomisp_css_frame *raw_black_frame = NULL;
4710 ret = atomisp_v4l2_framebuffer_to_css_frame(arg, &raw_black_frame);
4713 if (atomisp_css_set_black_frame(asd, raw_black_frame))
4716 atomisp_css_frame_free(raw_black_frame);
4721 * Function to configure false color correction
4723 int atomisp_false_color(struct atomisp_sub_device *asd, int flag,
4726 /* Get nr config from current setup */
4728 *value = asd->params.false_color;
4732 /* Set nr config to isp parameters */
4734 atomisp_css_set_default_de_config(asd);
4736 asd->params.css_param.de_config.pixelnoise = 0;
4737 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config);
4739 asd->params.css_update_params_needed = true;
4740 asd->params.false_color = *value;
4745 * Function to configure bad pixel correction params
4747 int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag,
4748 struct atomisp_de_config *config)
4751 /* Get false color from current setup */
4752 if (atomisp_css_get_de_config(asd, config))
4755 /* Set false color to isp parameters */
4756 memcpy(&asd->params.css_param.de_config, config,
4757 sizeof(asd->params.css_param.de_config));
4758 atomisp_css_set_de_config(asd, &asd->params.css_param.de_config);
4759 asd->params.css_update_params_needed = true;
4766 * Function to configure white balance params
4768 int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag,
4769 struct atomisp_wb_config *config)
4772 /* Get white balance from current setup */
4773 if (atomisp_css_get_wb_config(asd, config))
4776 /* Set white balance to isp parameters */
4777 memcpy(&asd->params.css_param.wb_config, config,
4778 sizeof(asd->params.css_param.wb_config));
4779 atomisp_css_set_wb_config(asd, &asd->params.css_param.wb_config);
4780 asd->params.css_update_params_needed = true;
4786 int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag,
4787 struct atomisp_3a_config *config)
4789 struct atomisp_device *isp = asd->isp;
4791 dev_dbg(isp->dev, ">%s %d\n", __func__, flag);
4794 /* Get white balance from current setup */
4795 if (atomisp_css_get_3a_config(asd, config))
4798 /* Set white balance to isp parameters */
4799 memcpy(&asd->params.css_param.s3a_config, config,
4800 sizeof(asd->params.css_param.s3a_config));
4801 atomisp_css_set_3a_config(asd, &asd->params.css_param.s3a_config);
4802 asd->params.css_update_params_needed = true;
4805 dev_dbg(isp->dev, "<%s %d\n", __func__, flag);
4810 * Function to setup digital zoom
4812 int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
4816 struct atomisp_device *isp = asd->isp;
4818 unsigned int max_zoom = MRFLD_MAX_ZOOM_FACTOR;
4821 atomisp_css_get_zoom_factor(asd, &zoom);
4822 *value = max_zoom - zoom;
4827 zoom = max_zoom - min_t(u32, max_zoom - 1, *value);
4828 atomisp_css_set_zoom_factor(asd, zoom);
4830 dev_dbg(isp->dev, "%s, zoom: %d\n", __func__, zoom);
4831 asd->params.css_update_params_needed = true;
4838 * Function to get sensor specific info for current resolution,
4839 * which will be used for auto exposure conversion.
4841 int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
4842 struct atomisp_sensor_mode_data *config)
4844 struct camera_mipi_info *mipi_info;
4845 struct atomisp_device *isp = asd->isp;
4847 mipi_info = atomisp_to_sensor_mipi_info(
4848 isp->inputs[asd->input_curr].camera);
4849 if (mipi_info == NULL)
4852 memcpy(config, &mipi_info->data, sizeof(*config));
4856 int atomisp_get_fmt(struct video_device *vdev, struct v4l2_format *f)
4858 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
4860 f->fmt.pix = pipe->pix;
4865 static void __atomisp_update_stream_env(struct atomisp_sub_device *asd,
4866 uint16_t stream_index, struct atomisp_input_stream_info *stream_info)
4870 #if defined(ISP2401_NEW_INPUT_SYSTEM)
4871 /* assign virtual channel id return from sensor driver query */
4872 asd->stream_env[stream_index].ch_id = stream_info->ch_id;
4874 asd->stream_env[stream_index].isys_configs = stream_info->isys_configs;
4875 for (i = 0; i < stream_info->isys_configs; i++) {
4876 asd->stream_env[stream_index].isys_info[i].input_format =
4877 stream_info->isys_info[i].input_format;
4878 asd->stream_env[stream_index].isys_info[i].width =
4879 stream_info->isys_info[i].width;
4880 asd->stream_env[stream_index].isys_info[i].height =
4881 stream_info->isys_info[i].height;
4885 static void __atomisp_init_stream_info(uint16_t stream_index,
4886 struct atomisp_input_stream_info *stream_info)
4890 stream_info->enable = 1;
4891 stream_info->stream = stream_index;
4892 stream_info->ch_id = 0;
4893 stream_info->isys_configs = 0;
4894 for (i = 0; i < MAX_STREAMS_PER_CHANNEL; i++) {
4895 stream_info->isys_info[i].input_format = 0;
4896 stream_info->isys_info[i].width = 0;
4897 stream_info->isys_info[i].height = 0;
4901 /* This function looks up the closest available resolution. */
4902 int atomisp_try_fmt(struct video_device *vdev, struct v4l2_format *f,
4905 struct atomisp_device *isp = video_get_drvdata(vdev);
4906 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
4907 struct v4l2_subdev_pad_config pad_cfg;
4908 struct v4l2_subdev_format format = {
4909 .which = V4L2_SUBDEV_FORMAT_TRY,
4912 struct v4l2_mbus_framefmt *snr_mbus_fmt = &format.format;
4913 const struct atomisp_format_bridge *fmt;
4914 struct atomisp_input_stream_info *stream_info =
4915 (struct atomisp_input_stream_info *)snr_mbus_fmt->reserved;
4916 uint16_t stream_index;
4917 int source_pad = atomisp_subdev_source_pad(vdev);
4920 if (isp->inputs[asd->input_curr].camera == NULL)
4923 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
4924 fmt = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
4926 dev_err(isp->dev, "unsupported pixelformat!\n");
4927 fmt = atomisp_output_fmts;
4931 if (f->fmt.pix.width <= 0 || f->fmt.pix.height <= 0)
4935 snr_mbus_fmt->code = fmt->mbus_code;
4936 snr_mbus_fmt->width = f->fmt.pix.width;
4937 snr_mbus_fmt->height = f->fmt.pix.height;
4939 __atomisp_init_stream_info(stream_index, stream_info);
4941 dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n",
4942 snr_mbus_fmt->width, snr_mbus_fmt->height);
4944 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
4945 pad, set_fmt, &pad_cfg, &format);
4949 dev_dbg(isp->dev, "try_mbus_fmt: got %ux%u\n",
4950 snr_mbus_fmt->width, snr_mbus_fmt->height);
4952 fmt = atomisp_get_format_bridge_from_mbus(snr_mbus_fmt->code);
4954 dev_err(isp->dev, "unknown sensor format 0x%8.8x\n",
4955 snr_mbus_fmt->code);
4959 f->fmt.pix.pixelformat = fmt->pixelformat;
4962 * If the format is jpeg or custom RAW, then the width and height will
4963 * not satisfy the normal atomisp requirements and no need to check
4964 * the below conditions. So just assign to what is being returned from
4965 * the sensor driver.
4967 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG ||
4968 f->fmt.pix.pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) {
4969 f->fmt.pix.width = snr_mbus_fmt->width;
4970 f->fmt.pix.height = snr_mbus_fmt->height;
4974 if (snr_mbus_fmt->width < f->fmt.pix.width
4975 && snr_mbus_fmt->height < f->fmt.pix.height) {
4976 f->fmt.pix.width = snr_mbus_fmt->width;
4977 f->fmt.pix.height = snr_mbus_fmt->height;
4978 /* Set the flag when resolution requested is
4979 * beyond the max value supported by sensor
4981 if (res_overflow != NULL)
4982 *res_overflow = true;
4986 f->fmt.pix.width = rounddown(
4987 clamp_t(u32, f->fmt.pix.width, ATOM_ISP_MIN_WIDTH,
4988 ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH);
4989 f->fmt.pix.height = rounddown(
4990 clamp_t(u32, f->fmt.pix.height, ATOM_ISP_MIN_HEIGHT,
4991 ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT);
4997 atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f)
4999 u32 width = f->fmt.pix.width;
5000 u32 height = f->fmt.pix.height;
5001 u32 pixelformat = f->fmt.pix.pixelformat;
5002 enum v4l2_field field = f->fmt.pix.field;
5005 if (!atomisp_get_format_bridge(pixelformat)) {
5006 dev_err(isp->dev, "Wrong output pixelformat\n");
5010 depth = get_pixel_depth(pixelformat);
5012 if (field == V4L2_FIELD_ANY)
5013 field = V4L2_FIELD_NONE;
5014 else if (field != V4L2_FIELD_NONE) {
5015 dev_err(isp->dev, "Wrong output field\n");
5019 f->fmt.pix.field = field;
5020 f->fmt.pix.width = clamp_t(u32,
5021 rounddown(width, (u32)ATOM_ISP_STEP_WIDTH),
5022 ATOM_ISP_MIN_WIDTH, ATOM_ISP_MAX_WIDTH);
5023 f->fmt.pix.height = clamp_t(u32, rounddown(height,
5024 (u32)ATOM_ISP_STEP_HEIGHT),
5025 ATOM_ISP_MIN_HEIGHT, ATOM_ISP_MAX_HEIGHT);
5026 f->fmt.pix.bytesperline = (width * depth) >> 3;
5031 mipi_port_ID_t __get_mipi_port(struct atomisp_device *isp,
5032 enum atomisp_camera_port port)
5035 case ATOMISP_CAMERA_PORT_PRIMARY:
5036 return MIPI_PORT0_ID;
5037 case ATOMISP_CAMERA_PORT_SECONDARY:
5038 return MIPI_PORT1_ID;
5039 case ATOMISP_CAMERA_PORT_TERTIARY:
5040 if (MIPI_PORT1_ID + 1 != N_MIPI_PORT_ID)
5041 return MIPI_PORT1_ID + 1;
5042 /* go through down for else case */
5044 dev_err(isp->dev, "unsupported port: %d\n", port);
5045 return MIPI_PORT0_ID;
5049 static inline int atomisp_set_sensor_mipi_to_isp(
5050 struct atomisp_sub_device *asd,
5051 enum atomisp_input_stream_id stream_id,
5052 struct camera_mipi_info *mipi_info)
5054 struct v4l2_control ctrl;
5055 struct atomisp_device *isp = asd->isp;
5056 const struct atomisp_in_fmt_conv *fc;
5058 unsigned int input_format, bayer_order;
5060 ctrl.id = V4L2_CID_LINK_FREQ;
5062 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0)
5063 mipi_freq = ctrl.value;
5065 if (asd->stream_env[stream_id].isys_configs == 1) {
5067 asd->stream_env[stream_id].isys_info[0].input_format;
5068 atomisp_css_isys_set_format(asd, stream_id,
5069 input_format, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
5070 } else if (asd->stream_env[stream_id].isys_configs == 2) {
5071 atomisp_css_isys_two_stream_cfg_update_stream1(
5073 asd->stream_env[stream_id].isys_info[0].input_format,
5074 asd->stream_env[stream_id].isys_info[0].width,
5075 asd->stream_env[stream_id].isys_info[0].height);
5077 atomisp_css_isys_two_stream_cfg_update_stream2(
5079 asd->stream_env[stream_id].isys_info[1].input_format,
5080 asd->stream_env[stream_id].isys_info[1].width,
5081 asd->stream_env[stream_id].isys_info[1].height);
5084 /* Compatibility for sensors which provide no media bus code
5085 * in s_mbus_framefmt() nor support pad formats. */
5086 if (mipi_info->input_format != -1) {
5087 bayer_order = mipi_info->raw_bayer_order;
5089 /* Input stream config is still needs configured */
5090 /* TODO: Check if this is necessary */
5091 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5092 mipi_info->input_format);
5095 input_format = fc->css_stream_fmt;
5097 struct v4l2_mbus_framefmt *sink;
5098 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5099 V4L2_SUBDEV_FORMAT_ACTIVE,
5100 ATOMISP_SUBDEV_PAD_SINK);
5101 fc = atomisp_find_in_fmt_conv(sink->code);
5104 input_format = fc->css_stream_fmt;
5105 bayer_order = fc->bayer_order;
5108 atomisp_css_input_set_format(asd, stream_id, input_format);
5109 atomisp_css_input_set_bayer_order(asd, stream_id, bayer_order);
5111 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5112 mipi_info->metadata_format);
5115 input_format = fc->css_stream_fmt;
5116 atomisp_css_input_configure_port(asd,
5117 __get_mipi_port(asd->isp, mipi_info->port),
5118 mipi_info->num_lanes,
5121 mipi_info->metadata_width,
5122 mipi_info->metadata_height);
5126 static int __enable_continuous_mode(struct atomisp_sub_device *asd,
5129 struct atomisp_device *isp = asd->isp;
5132 "continuous mode %d, raw buffers %d, stop preview %d\n",
5133 enable, asd->continuous_raw_buffer_size->val,
5134 !asd->continuous_viewfinder->val);
5136 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_PRIMARY);
5138 atomisp_update_capture_mode(asd);
5140 /* in case of ANR, force capture pipe to offline mode */
5141 atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
5142 asd->params.low_light ? false : !enable);
5143 atomisp_css_preview_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
5145 atomisp_css_enable_continuous(asd, enable);
5146 atomisp_css_enable_cvf(asd, asd->continuous_viewfinder->val);
5148 if (atomisp_css_continuous_set_num_raw_frames(asd,
5149 asd->continuous_raw_buffer_size->val)) {
5150 dev_err(isp->dev, "css_continuous_set_num_raw_frames failed\n");
5155 atomisp_css_enable_raw_binning(asd, false);
5156 atomisp_css_input_set_two_pixels_per_clock(asd, false);
5159 if (isp->inputs[asd->input_curr].type != FILE_INPUT)
5160 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_SENSOR);
5162 return atomisp_update_run_mode(asd);
5165 int configure_pp_input_nop(struct atomisp_sub_device *asd,
5166 unsigned int width, unsigned int height)
5171 int configure_output_nop(struct atomisp_sub_device *asd,
5172 unsigned int width, unsigned int height,
5173 unsigned int min_width,
5174 enum atomisp_css_frame_format sh_fmt)
5179 int get_frame_info_nop(struct atomisp_sub_device *asd,
5180 struct atomisp_css_frame_info *finfo)
5186 * Resets CSS parameters that depend on input resolution.
5188 * Update params like CSS RAW binning, 2ppc mode and pp_input
5189 * which depend on input size, but are not automatically
5190 * handled in CSS when the input resolution is changed.
5192 static int css_input_resolution_changed(struct atomisp_sub_device *asd,
5193 struct v4l2_mbus_framefmt *ffmt)
5195 struct atomisp_metadata_buf *md_buf = NULL, *_md_buf;
5198 dev_dbg(asd->isp->dev, "css_input_resolution_changed to %ux%u\n",
5199 ffmt->width, ffmt->height);
5201 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5202 atomisp_css_input_set_two_pixels_per_clock(asd, false);
5204 atomisp_css_input_set_two_pixels_per_clock(asd, true);
5206 if (asd->continuous_mode->val) {
5207 /* Note for all checks: ffmt includes pad_w+pad_h */
5208 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO ||
5209 (ffmt->width >= 2048 || ffmt->height >= 1536)) {
5211 * For preview pipe, enable only if resolution
5212 * is >= 3M for ISP2400.
5214 atomisp_css_enable_raw_binning(asd, true);
5218 * If sensor input changed, which means metadata resolution changed
5219 * together. Release all metadata buffers here to let it re-allocated
5220 * next time in reqbufs.
5222 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
5223 list_for_each_entry_safe(md_buf, _md_buf, &asd->metadata[i],
5225 atomisp_css_free_metadata_buffer(md_buf);
5226 list_del(&md_buf->list);
5233 * TODO: atomisp_css_preview_configure_pp_input() not
5234 * reset due to CSS bug tracked as PSI BZ 115124
5238 static int atomisp_set_fmt_to_isp(struct video_device *vdev,
5239 struct atomisp_css_frame_info *output_info,
5240 struct atomisp_css_frame_info *raw_output_info,
5241 struct v4l2_pix_format *pix,
5242 unsigned int source_pad)
5244 struct camera_mipi_info *mipi_info;
5245 struct atomisp_device *isp = video_get_drvdata(vdev);
5246 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
5247 const struct atomisp_format_bridge *format;
5248 struct v4l2_rect *isp_sink_crop;
5249 enum atomisp_css_pipe_id pipe_id;
5250 struct v4l2_subdev_fh fh;
5251 int (*configure_output)(struct atomisp_sub_device *asd,
5252 unsigned int width, unsigned int height,
5253 unsigned int min_width,
5254 enum atomisp_css_frame_format sh_fmt) =
5255 configure_output_nop;
5256 int (*get_frame_info)(struct atomisp_sub_device *asd,
5257 struct atomisp_css_frame_info *finfo) =
5259 int (*configure_pp_input)(struct atomisp_sub_device *asd,
5260 unsigned int width, unsigned int height) =
5261 configure_pp_input_nop;
5262 uint16_t stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
5263 const struct atomisp_in_fmt_conv *fc;
5266 v4l2_fh_init(&fh.vfh, vdev);
5268 isp_sink_crop = atomisp_subdev_get_rect(
5269 &asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
5270 ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP);
5272 format = atomisp_get_format_bridge(pix->pixelformat);
5276 if (isp->inputs[asd->input_curr].type != TEST_PATTERN &&
5277 isp->inputs[asd->input_curr].type != FILE_INPUT) {
5278 mipi_info = atomisp_to_sensor_mipi_info(
5279 isp->inputs[asd->input_curr].camera);
5281 dev_err(isp->dev, "mipi_info is NULL\n");
5284 if (atomisp_set_sensor_mipi_to_isp(asd, stream_index,
5287 fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5288 mipi_info->input_format);
5290 fc = atomisp_find_in_fmt_conv(
5291 atomisp_subdev_get_ffmt(&asd->subdev,
5292 NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
5293 ATOMISP_SUBDEV_PAD_SINK)->code);
5296 if (format->sh_fmt == CSS_FRAME_FORMAT_RAW &&
5297 raw_output_format_match_input(fc->css_stream_fmt,
5303 * Configure viewfinder also when vfpp is disabled: the
5304 * CSS still requires viewfinder configuration.
5306 if (asd->fmt_auto->val ||
5307 asd->vfpp->val != ATOMISP_VFPP_ENABLE) {
5308 struct v4l2_rect vf_size = {0};
5309 struct v4l2_mbus_framefmt vf_ffmt = {0};
5311 if (pix->width < 640 || pix->height < 480) {
5312 vf_size.width = pix->width;
5313 vf_size.height = pix->height;
5315 vf_size.width = 640;
5316 vf_size.height = 480;
5319 /* FIXME: proper format name for this one. See
5320 atomisp_output_fmts[] in atomisp_v4l2.c */
5321 vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420;
5323 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
5324 V4L2_SUBDEV_FORMAT_ACTIVE,
5325 ATOMISP_SUBDEV_PAD_SOURCE_VF,
5326 V4L2_SEL_TGT_COMPOSE, 0, &vf_size);
5327 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
5328 V4L2_SUBDEV_FORMAT_ACTIVE,
5329 ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt);
5330 asd->video_out_vf.sh_fmt = CSS_FRAME_FORMAT_NV12;
5332 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
5333 atomisp_css_video_configure_viewfinder(asd,
5334 vf_size.width, vf_size.height, 0,
5335 asd->video_out_vf.sh_fmt);
5336 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
5337 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
5338 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO)
5339 atomisp_css_video_configure_viewfinder(asd,
5340 vf_size.width, vf_size.height, 0,
5341 asd->video_out_vf.sh_fmt);
5343 atomisp_css_capture_configure_viewfinder(asd,
5344 vf_size.width, vf_size.height, 0,
5345 asd->video_out_vf.sh_fmt);
5346 } else if (source_pad != ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
5347 asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
5348 atomisp_css_capture_configure_viewfinder(asd,
5349 vf_size.width, vf_size.height, 0,
5350 asd->video_out_vf.sh_fmt);
5354 if (asd->continuous_mode->val) {
5355 ret = __enable_continuous_mode(asd, true);
5360 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_SENSOR);
5361 atomisp_css_disable_vf_pp(asd,
5362 asd->vfpp->val != ATOMISP_VFPP_ENABLE);
5364 /* ISP2401 new input system need to use copy pipe */
5365 if (asd->copy_mode) {
5366 pipe_id = CSS_PIPE_ID_COPY;
5367 atomisp_css_capture_enable_online(asd, stream_index, false);
5368 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
5369 /* video same in continuouscapture and online modes */
5370 configure_output = atomisp_css_video_configure_output;
5371 get_frame_info = atomisp_css_video_get_output_frame_info;
5372 pipe_id = CSS_PIPE_ID_VIDEO;
5373 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
5374 if (!asd->continuous_mode->val) {
5375 configure_output = atomisp_css_video_configure_output;
5377 atomisp_css_video_get_output_frame_info;
5378 pipe_id = CSS_PIPE_ID_VIDEO;
5380 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
5381 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
5383 atomisp_css_video_configure_output;
5385 atomisp_css_video_get_output_frame_info;
5386 configure_pp_input =
5387 atomisp_css_video_configure_pp_input;
5388 pipe_id = CSS_PIPE_ID_VIDEO;
5391 atomisp_css_capture_configure_output;
5393 atomisp_css_capture_get_output_frame_info;
5394 configure_pp_input =
5395 atomisp_css_capture_configure_pp_input;
5396 pipe_id = CSS_PIPE_ID_CAPTURE;
5398 atomisp_update_capture_mode(asd);
5399 atomisp_css_capture_enable_online(asd, stream_index, false);
5402 } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) {
5403 configure_output = atomisp_css_preview_configure_output;
5404 get_frame_info = atomisp_css_preview_get_output_frame_info;
5405 configure_pp_input = atomisp_css_preview_configure_pp_input;
5406 pipe_id = CSS_PIPE_ID_PREVIEW;
5408 /* CSS doesn't support low light mode on SOC cameras, so disable
5409 * it. FIXME: if this is done elsewhere, it gives corrupted
5410 * colors into thumbnail image.
5412 if (isp->inputs[asd->input_curr].type == SOC_CAMERA)
5413 asd->params.low_light = false;
5415 if (format->sh_fmt == CSS_FRAME_FORMAT_RAW) {
5416 atomisp_css_capture_set_mode(asd, CSS_CAPTURE_MODE_RAW);
5417 atomisp_css_enable_dz(asd, false);
5419 atomisp_update_capture_mode(asd);
5422 if (!asd->continuous_mode->val)
5423 /* in case of ANR, force capture pipe to offline mode */
5424 atomisp_css_capture_enable_online(asd, stream_index,
5425 asd->params.low_light ?
5426 false : asd->params.online_process);
5428 configure_output = atomisp_css_capture_configure_output;
5429 get_frame_info = atomisp_css_capture_get_output_frame_info;
5430 configure_pp_input = atomisp_css_capture_configure_pp_input;
5431 pipe_id = CSS_PIPE_ID_CAPTURE;
5433 if (!asd->params.online_process &&
5434 !asd->continuous_mode->val) {
5435 ret = atomisp_css_capture_get_output_raw_frame_info(asd,
5440 if (!asd->continuous_mode->val && asd->run_mode->val
5441 != ATOMISP_RUN_MODE_STILL_CAPTURE) {
5443 "Need to set the running mode first\n");
5444 asd->run_mode->val = ATOMISP_RUN_MODE_STILL_CAPTURE;
5449 * to SOC camera, use yuvpp pipe.
5451 if (ATOMISP_USE_YUVPP(asd))
5452 pipe_id = CSS_PIPE_ID_YUVPP;
5455 ret = atomisp_css_copy_configure_output(asd, stream_index,
5456 pix->width, pix->height,
5457 format->planar ? pix->bytesperline :
5458 pix->bytesperline * 8 / format->depth,
5461 ret = configure_output(asd, pix->width, pix->height,
5462 format->planar ? pix->bytesperline :
5463 pix->bytesperline * 8 / format->depth,
5466 dev_err(isp->dev, "configure_output %ux%u, format %8.8x\n",
5467 pix->width, pix->height, format->sh_fmt);
5471 if (asd->continuous_mode->val &&
5472 (configure_pp_input == atomisp_css_preview_configure_pp_input ||
5473 configure_pp_input == atomisp_css_video_configure_pp_input)) {
5474 /* for isp 2.2, configure pp input is available for continuous
5476 ret = configure_pp_input(asd, isp_sink_crop->width,
5477 isp_sink_crop->height);
5479 dev_err(isp->dev, "configure_pp_input %ux%u\n",
5480 isp_sink_crop->width,
5481 isp_sink_crop->height);
5485 ret = configure_pp_input(asd, isp_sink_crop->width,
5486 isp_sink_crop->height);
5488 dev_err(isp->dev, "configure_pp_input %ux%u\n",
5489 isp_sink_crop->width, isp_sink_crop->height);
5494 ret = atomisp_css_copy_get_output_frame_info(asd, stream_index,
5497 ret = get_frame_info(asd, output_info);
5499 dev_err(isp->dev, "get_frame_info %ux%u (padded to %u)\n",
5500 pix->width, pix->height, pix->bytesperline);
5504 atomisp_update_grid_info(asd, pipe_id, source_pad);
5506 /* Free the raw_dump buffer first */
5507 atomisp_css_frame_free(asd->raw_output_frame);
5508 asd->raw_output_frame = NULL;
5510 if (!asd->continuous_mode->val &&
5511 !asd->params.online_process && !isp->sw_contex.file_input &&
5512 atomisp_css_frame_allocate_from_info(&asd->raw_output_frame,
5519 static void atomisp_get_dis_envelop(struct atomisp_sub_device *asd,
5520 unsigned int width, unsigned int height,
5521 unsigned int *dvs_env_w, unsigned int *dvs_env_h)
5523 struct atomisp_device *isp = asd->isp;
5525 /* if subdev type is SOC camera,we do not need to set DVS */
5526 if (isp->inputs[asd->input_curr].type == SOC_CAMERA)
5527 asd->params.video_dis_en = 0;
5529 if (asd->params.video_dis_en &&
5530 asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
5531 /* envelope is 20% of the output resolution */
5533 * dvs envelope cannot be round up.
5534 * it would cause ISP timeout and color switch issue
5536 *dvs_env_w = rounddown(width / 5, ATOM_ISP_STEP_WIDTH);
5537 *dvs_env_h = rounddown(height / 5, ATOM_ISP_STEP_HEIGHT);
5540 asd->params.dis_proj_data_valid = false;
5541 asd->params.css_update_params_needed = true;
5544 static void atomisp_check_copy_mode(struct atomisp_sub_device *asd,
5545 int source_pad, struct v4l2_format *f)
5547 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5548 struct v4l2_mbus_framefmt *sink, *src;
5550 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5551 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK);
5552 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5553 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
5555 if ((sink->code == src->code &&
5556 sink->width == f->fmt.pix.width &&
5557 sink->height == f->fmt.pix.height) ||
5558 ((asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) &&
5559 (asd->isp->inputs[asd->input_curr].camera_caps->
5560 sensor[asd->sensor_curr].stream_num > 1)))
5561 asd->copy_mode = true;
5564 /* Only used for the new input system */
5565 asd->copy_mode = false;
5567 dev_dbg(asd->isp->dev, "copy_mode: %d\n", asd->copy_mode);
5571 static int atomisp_set_fmt_to_snr(struct video_device *vdev,
5572 struct v4l2_format *f, unsigned int pixelformat,
5573 unsigned int padding_w, unsigned int padding_h,
5574 unsigned int dvs_env_w, unsigned int dvs_env_h)
5576 struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
5577 const struct atomisp_format_bridge *format;
5578 struct v4l2_subdev_pad_config pad_cfg;
5579 struct v4l2_subdev_format vformat = {
5580 .which = V4L2_SUBDEV_FORMAT_TRY,
5582 struct v4l2_mbus_framefmt *ffmt = &vformat.format;
5583 struct v4l2_mbus_framefmt *req_ffmt;
5584 struct atomisp_device *isp = asd->isp;
5585 struct atomisp_input_stream_info *stream_info =
5586 (struct atomisp_input_stream_info *)ffmt->reserved;
5587 uint16_t stream_index = ATOMISP_INPUT_STREAM_GENERAL;
5588 int source_pad = atomisp_subdev_source_pad(vdev);
5589 struct v4l2_subdev_fh fh;
5592 v4l2_fh_init(&fh.vfh, vdev);
5594 stream_index = atomisp_source_pad_to_stream_id(asd, source_pad);
5596 format = atomisp_get_format_bridge(pixelformat);
5600 v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format->mbus_code);
5601 ffmt->height += padding_h + dvs_env_h;
5602 ffmt->width += padding_w + dvs_env_w;
5604 dev_dbg(isp->dev, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n",
5605 ffmt->width, ffmt->height, padding_w, padding_h,
5606 dvs_env_w, dvs_env_h);
5608 __atomisp_init_stream_info(stream_index, stream_info);
5612 /* Disable dvs if resolution can't be supported by sensor */
5613 if (asd->params.video_dis_en &&
5614 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
5615 vformat.which = V4L2_SUBDEV_FORMAT_TRY;
5616 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
5617 pad, set_fmt, &pad_cfg, &vformat);
5620 if (ffmt->width < req_ffmt->width ||
5621 ffmt->height < req_ffmt->height) {
5622 req_ffmt->height -= dvs_env_h;
5623 req_ffmt->width -= dvs_env_w;
5626 "can not enable video dis due to sensor limitation.");
5627 asd->params.video_dis_en = 0;
5630 dev_dbg(isp->dev, "sensor width: %d, height: %d\n",
5631 ffmt->width, ffmt->height);
5632 vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
5633 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad,
5634 set_fmt, NULL, &vformat);
5638 __atomisp_update_stream_env(asd, stream_index, stream_info);
5640 dev_dbg(isp->dev, "sensor width: %d, height: %d\n",
5641 ffmt->width, ffmt->height);
5643 if (ffmt->width < ATOM_ISP_STEP_WIDTH ||
5644 ffmt->height < ATOM_ISP_STEP_HEIGHT)
5647 if (asd->params.video_dis_en &&
5648 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO &&
5649 (ffmt->width < req_ffmt->width || ffmt->height < req_ffmt->height)) {
5651 "can not enable video dis due to sensor limitation.");
5652 asd->params.video_dis_en = 0;
5655 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
5656 V4L2_SUBDEV_FORMAT_ACTIVE,
5657 ATOMISP_SUBDEV_PAD_SINK, ffmt);
5659 return css_input_resolution_changed(asd, ffmt);
5662 int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
5664 struct atomisp_device *isp = video_get_drvdata(vdev);
5665 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
5666 struct atomisp_sub_device *asd = pipe->asd;
5667 const struct atomisp_format_bridge *format_bridge;
5668 const struct atomisp_format_bridge *snr_format_bridge;
5669 struct atomisp_css_frame_info output_info, raw_output_info;
5670 struct v4l2_format snr_fmt = *f;
5671 struct v4l2_format backup_fmt = *f, s_fmt = *f;
5672 unsigned int dvs_env_w = 0, dvs_env_h = 0;
5673 unsigned int padding_w = pad_w, padding_h = pad_h;
5674 bool res_overflow = false, crop_needs_override = false;
5675 struct v4l2_mbus_framefmt isp_sink_fmt;
5676 struct v4l2_mbus_framefmt isp_source_fmt = {0};
5677 struct v4l2_rect isp_sink_crop;
5678 uint16_t source_pad = atomisp_subdev_source_pad(vdev);
5679 struct v4l2_subdev_fh fh;
5683 "setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n",
5684 f->fmt.pix.width, f->fmt.pix.height, source_pad,
5685 asd->index, f->fmt.pix.bytesperline);
5687 if (source_pad >= ATOMISP_SUBDEV_PADS_NUM)
5690 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
5691 dev_warn(isp->dev, "ISP does not support set format while at streaming!\n");
5695 v4l2_fh_init(&fh.vfh, vdev);
5697 format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
5698 if (format_bridge == NULL)
5701 pipe->sh_fmt = format_bridge->sh_fmt;
5702 pipe->pix.pixelformat = f->fmt.pix.pixelformat;
5704 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VF ||
5705 (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5706 && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)) {
5707 if (asd->fmt_auto->val) {
5708 struct v4l2_rect *capture_comp;
5709 struct v4l2_rect r = {0};
5711 r.width = f->fmt.pix.width;
5712 r.height = f->fmt.pix.height;
5714 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW)
5715 capture_comp = atomisp_subdev_get_rect(
5717 V4L2_SUBDEV_FORMAT_ACTIVE,
5718 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
5719 V4L2_SEL_TGT_COMPOSE);
5721 capture_comp = atomisp_subdev_get_rect(
5723 V4L2_SUBDEV_FORMAT_ACTIVE,
5724 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
5725 V4L2_SEL_TGT_COMPOSE);
5727 if (capture_comp->width < r.width
5728 || capture_comp->height < r.height) {
5729 r.width = capture_comp->width;
5730 r.height = capture_comp->height;
5733 atomisp_subdev_set_selection(
5734 &asd->subdev, fh.pad,
5735 V4L2_SUBDEV_FORMAT_ACTIVE, source_pad,
5736 V4L2_SEL_TGT_COMPOSE, 0, &r);
5738 f->fmt.pix.width = r.width;
5739 f->fmt.pix.height = r.height;
5742 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW &&
5743 (asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) &&
5744 (asd->isp->inputs[asd->input_curr].camera_caps->
5745 sensor[asd->sensor_curr].stream_num > 1)) {
5746 /* For M10MO outputing YUV preview images. */
5747 uint16_t video_index =
5748 atomisp_source_pad_to_stream_id(asd,
5749 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO);
5751 ret = atomisp_css_copy_get_output_frame_info(asd,
5752 video_index, &output_info);
5755 "copy_get_output_frame_info ret %i", ret);
5758 if (!asd->yuvpp_mode) {
5760 * If viewfinder was configured into copy_mode,
5761 * we switch to using yuvpp pipe instead.
5763 asd->yuvpp_mode = true;
5764 ret = atomisp_css_copy_configure_output(
5765 asd, video_index, 0, 0, 0, 0);
5768 "failed to disable copy pipe");
5771 ret = atomisp_css_yuvpp_configure_output(
5773 output_info.res.width,
5774 output_info.res.height,
5775 output_info.padded_width,
5776 output_info.format);
5779 "failed to set up yuvpp pipe\n");
5782 atomisp_css_video_enable_online(asd, false);
5783 atomisp_css_preview_enable_online(asd,
5784 ATOMISP_INPUT_STREAM_GENERAL, false);
5786 atomisp_css_yuvpp_configure_viewfinder(asd, video_index,
5787 f->fmt.pix.width, f->fmt.pix.height,
5788 format_bridge->planar ? f->fmt.pix.bytesperline
5789 : f->fmt.pix.bytesperline * 8
5790 / format_bridge->depth, format_bridge->sh_fmt);
5791 atomisp_css_yuvpp_get_viewfinder_frame_info(
5792 asd, video_index, &output_info);
5793 } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) {
5794 atomisp_css_video_configure_viewfinder(asd,
5795 f->fmt.pix.width, f->fmt.pix.height,
5796 format_bridge->planar ? f->fmt.pix.bytesperline
5797 : f->fmt.pix.bytesperline * 8
5798 / format_bridge->depth, format_bridge->sh_fmt);
5799 atomisp_css_video_get_viewfinder_frame_info(asd,
5801 asd->copy_mode = false;
5803 atomisp_css_capture_configure_viewfinder(asd,
5804 f->fmt.pix.width, f->fmt.pix.height,
5805 format_bridge->planar ? f->fmt.pix.bytesperline
5806 : f->fmt.pix.bytesperline * 8
5807 / format_bridge->depth, format_bridge->sh_fmt);
5808 atomisp_css_capture_get_viewfinder_frame_info(asd,
5810 asd->copy_mode = false;
5816 * Check whether main resolution configured smaller
5817 * than snapshot resolution. If so, force main resolution
5818 * to be the same as snapshot resolution
5820 if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) {
5821 struct v4l2_rect *r;
5823 r = atomisp_subdev_get_rect(
5825 V4L2_SUBDEV_FORMAT_ACTIVE,
5826 ATOMISP_SUBDEV_PAD_SOURCE_VF, V4L2_SEL_TGT_COMPOSE);
5828 if (r->width && r->height
5829 && (r->width > f->fmt.pix.width
5830 || r->height > f->fmt.pix.height))
5832 "Main Resolution config smaller then Vf Resolution. Force to be equal with Vf Resolution.");
5835 /* Pipeline configuration done through subdevs. Bail out now. */
5836 if (!asd->fmt_auto->val)
5837 goto set_fmt_to_isp;
5839 /* get sensor resolution and format */
5840 ret = atomisp_try_fmt(vdev, &snr_fmt, &res_overflow);
5843 f->fmt.pix.width = snr_fmt.fmt.pix.width;
5844 f->fmt.pix.height = snr_fmt.fmt.pix.height;
5847 atomisp_get_format_bridge(snr_fmt.fmt.pix.pixelformat);
5848 if (!snr_format_bridge)
5851 atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5852 V4L2_SUBDEV_FORMAT_ACTIVE,
5853 ATOMISP_SUBDEV_PAD_SINK)->code =
5854 snr_format_bridge->mbus_code;
5856 isp_sink_fmt = *atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5857 V4L2_SUBDEV_FORMAT_ACTIVE,
5858 ATOMISP_SUBDEV_PAD_SINK);
5860 isp_source_fmt.code = format_bridge->mbus_code;
5861 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad,
5862 V4L2_SUBDEV_FORMAT_ACTIVE,
5863 source_pad, &isp_source_fmt);
5865 if (!atomisp_subdev_format_conversion(asd, source_pad)) {
5868 } else if (IS_BYT) {
5873 /* construct resolution supported by isp */
5874 if (res_overflow && !asd->continuous_mode->val) {
5875 f->fmt.pix.width = rounddown(
5876 clamp_t(u32, f->fmt.pix.width - padding_w,
5878 ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH);
5879 f->fmt.pix.height = rounddown(
5880 clamp_t(u32, f->fmt.pix.height - padding_h,
5881 ATOM_ISP_MIN_HEIGHT,
5882 ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT);
5885 atomisp_get_dis_envelop(asd, f->fmt.pix.width, f->fmt.pix.height,
5886 &dvs_env_w, &dvs_env_h);
5888 if (asd->continuous_mode->val) {
5889 struct v4l2_rect *r;
5891 r = atomisp_subdev_get_rect(
5893 V4L2_SUBDEV_FORMAT_ACTIVE,
5894 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
5895 V4L2_SEL_TGT_COMPOSE);
5897 * The ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE should get resolutions
5898 * properly set otherwise, it should not be the capture_pad.
5900 if (r->width && r->height)
5901 asd->capture_pad = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
5903 asd->capture_pad = source_pad;
5905 asd->capture_pad = source_pad;
5908 * set format info to sensor
5909 * In continuous mode, resolution is set only if it is higher than
5910 * existing value. This because preview pipe will be configured after
5911 * capture pipe and usually has lower resolution than capture pipe.
5913 if (!asd->continuous_mode->val ||
5914 isp_sink_fmt.width < (f->fmt.pix.width + padding_w + dvs_env_w) ||
5915 isp_sink_fmt.height < (f->fmt.pix.height + padding_h +
5918 * For jpeg or custom raw format the sensor will return constant
5919 * width and height. Because we already had quried try_mbus_fmt,
5920 * f->fmt.pix.width and f->fmt.pix.height has been changed to
5921 * this fixed width and height. So we cannot select the correct
5922 * resolution with that information. So use the original width
5923 * and height while set_mbus_fmt() so actual resolutions are
5924 * being used in while set media bus format.
5927 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG ||
5928 f->fmt.pix.pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) {
5929 s_fmt.fmt.pix.width = backup_fmt.fmt.pix.width;
5930 s_fmt.fmt.pix.height = backup_fmt.fmt.pix.height;
5932 ret = atomisp_set_fmt_to_snr(vdev, &s_fmt,
5933 f->fmt.pix.pixelformat, padding_w,
5934 padding_h, dvs_env_w, dvs_env_h);
5938 atomisp_csi_lane_config(isp);
5939 crop_needs_override = true;
5942 atomisp_check_copy_mode(asd, source_pad, &backup_fmt);
5943 asd->yuvpp_mode = false; /* Reset variable */
5945 isp_sink_crop = *atomisp_subdev_get_rect(&asd->subdev, NULL,
5946 V4L2_SUBDEV_FORMAT_ACTIVE,
5947 ATOMISP_SUBDEV_PAD_SINK,
5950 /* Try to enable YUV downscaling if ISP input is 10 % (either
5951 * width or height) bigger than the desired result. */
5952 if (isp_sink_crop.width * 9 / 10 < f->fmt.pix.width ||
5953 isp_sink_crop.height * 9 / 10 < f->fmt.pix.height ||
5954 (atomisp_subdev_format_conversion(asd, source_pad) &&
5955 ((asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
5956 !asd->continuous_mode->val) ||
5957 asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER))) {
5958 /* for continuous mode, preview size might be smaller than
5959 * still capture size. if preview size still needs crop,
5960 * pick the larger one between crop size of preview and
5963 if (asd->continuous_mode->val
5964 && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5965 && !crop_needs_override) {
5966 isp_sink_crop.width =
5967 max_t(unsigned int, f->fmt.pix.width,
5968 isp_sink_crop.width);
5969 isp_sink_crop.height =
5970 max_t(unsigned int, f->fmt.pix.height,
5971 isp_sink_crop.height);
5973 isp_sink_crop.width = f->fmt.pix.width;
5974 isp_sink_crop.height = f->fmt.pix.height;
5977 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
5978 V4L2_SUBDEV_FORMAT_ACTIVE,
5979 ATOMISP_SUBDEV_PAD_SINK,
5981 V4L2_SEL_FLAG_KEEP_CONFIG,
5983 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
5984 V4L2_SUBDEV_FORMAT_ACTIVE,
5985 source_pad, V4L2_SEL_TGT_COMPOSE,
5987 } else if (IS_MOFD) {
5988 struct v4l2_rect main_compose = {0};
5990 main_compose.width = isp_sink_crop.width;
5991 main_compose.height =
5992 DIV_ROUND_UP(main_compose.width * f->fmt.pix.height,
5994 if (main_compose.height > isp_sink_crop.height) {
5995 main_compose.height = isp_sink_crop.height;
5996 main_compose.width =
5997 DIV_ROUND_UP(main_compose.height *
6002 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
6003 V4L2_SUBDEV_FORMAT_ACTIVE,
6005 V4L2_SEL_TGT_COMPOSE, 0,
6008 struct v4l2_rect sink_crop = {0};
6009 struct v4l2_rect main_compose = {0};
6011 main_compose.width = f->fmt.pix.width;
6012 main_compose.height = f->fmt.pix.height;
6015 /* WORKAROUND: this override is universally enabled in
6016 * GMIN to work around a CTS failures (GMINL-539)
6017 * which appears to be related by a hardware
6018 * performance limitation. It's unclear why this
6019 * particular code triggers the issue. */
6021 crop_needs_override) {
6023 if (crop_needs_override) {
6025 if (isp_sink_crop.width * main_compose.height >
6026 isp_sink_crop.height * main_compose.width) {
6027 sink_crop.height = isp_sink_crop.height;
6028 sink_crop.width = DIV_NEAREST_STEP(
6032 ATOM_ISP_STEP_WIDTH);
6034 sink_crop.width = isp_sink_crop.width;
6035 sink_crop.height = DIV_NEAREST_STEP(
6039 ATOM_ISP_STEP_HEIGHT);
6041 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
6042 V4L2_SUBDEV_FORMAT_ACTIVE,
6043 ATOMISP_SUBDEV_PAD_SINK,
6045 V4L2_SEL_FLAG_KEEP_CONFIG,
6048 atomisp_subdev_set_selection(&asd->subdev, fh.pad,
6049 V4L2_SUBDEV_FORMAT_ACTIVE,
6051 V4L2_SEL_TGT_COMPOSE, 0,
6056 ret = atomisp_set_fmt_to_isp(vdev, &output_info, &raw_output_info,
6057 &f->fmt.pix, source_pad);
6061 pipe->pix.width = f->fmt.pix.width;
6062 pipe->pix.height = f->fmt.pix.height;
6063 pipe->pix.pixelformat = f->fmt.pix.pixelformat;
6064 if (format_bridge->planar) {
6065 pipe->pix.bytesperline = output_info.padded_width;
6066 pipe->pix.sizeimage = PAGE_ALIGN(f->fmt.pix.height *
6067 DIV_ROUND_UP(format_bridge->depth *
6068 output_info.padded_width, 8));
6070 pipe->pix.bytesperline =
6071 DIV_ROUND_UP(format_bridge->depth *
6072 output_info.padded_width, 8);
6073 pipe->pix.sizeimage =
6074 PAGE_ALIGN(f->fmt.pix.height * pipe->pix.bytesperline);
6077 if (f->fmt.pix.field == V4L2_FIELD_ANY)
6078 f->fmt.pix.field = V4L2_FIELD_NONE;
6079 pipe->pix.field = f->fmt.pix.field;
6081 f->fmt.pix = pipe->pix;
6082 f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width *
6083 pipe->pix.height * 2);
6085 pipe->capq.field = f->fmt.pix.field;
6088 * If in video 480P case, no GFX throttle
6090 if (asd->run_mode->val == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO &&
6091 f->fmt.pix.width == 720 && f->fmt.pix.height == 480)
6092 isp->need_gfx_throttle = false;
6094 isp->need_gfx_throttle = true;
6099 int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f)
6101 struct atomisp_device *isp = video_get_drvdata(vdev);
6102 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
6103 struct atomisp_sub_device *asd = pipe->asd;
6104 struct v4l2_mbus_framefmt ffmt = {0};
6105 const struct atomisp_format_bridge *format_bridge;
6106 struct v4l2_subdev_fh fh;
6109 v4l2_fh_init(&fh.vfh, vdev);
6111 dev_dbg(isp->dev, "setting fmt %ux%u 0x%x for file inject\n",
6112 f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
6113 ret = atomisp_try_fmt_file(isp, f);
6115 dev_err(isp->dev, "atomisp_try_fmt_file err: %d\n", ret);
6119 format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
6120 if (format_bridge == NULL) {
6121 dev_dbg(isp->dev, "atomisp_get_format_bridge err! fmt:0x%x\n",
6122 f->fmt.pix.pixelformat);
6126 pipe->pix = f->fmt.pix;
6127 atomisp_css_input_set_mode(asd, CSS_INPUT_MODE_FIFO);
6128 atomisp_css_input_configure_port(asd,
6129 __get_mipi_port(isp, ATOMISP_CAMERA_PORT_PRIMARY), 2, 0xffff4,
6131 ffmt.width = f->fmt.pix.width;
6132 ffmt.height = f->fmt.pix.height;
6133 ffmt.code = format_bridge->mbus_code;
6135 atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, V4L2_SUBDEV_FORMAT_ACTIVE,
6136 ATOMISP_SUBDEV_PAD_SINK, &ffmt);
6141 int atomisp_set_shading_table(struct atomisp_sub_device *asd,
6142 struct atomisp_shading_table *user_shading_table)
6144 struct atomisp_css_shading_table *shading_table;
6145 struct atomisp_css_shading_table *free_table;
6146 unsigned int len_table;
6150 if (!user_shading_table)
6153 if (!user_shading_table->enable) {
6154 atomisp_css_set_shading_table(asd, NULL);
6155 asd->params.sc_en = 0;
6159 /* If enabling, all tables must be set */
6160 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
6161 if (!user_shading_table->data[i])
6165 /* Shading table size per color */
6166 if (user_shading_table->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
6167 user_shading_table->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR)
6170 shading_table = atomisp_css_shading_table_alloc(
6171 user_shading_table->width, user_shading_table->height);
6175 len_table = user_shading_table->width * user_shading_table->height *
6176 ATOMISP_SC_TYPE_SIZE;
6177 for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
6178 ret = copy_from_user(shading_table->data[i],
6179 user_shading_table->data[i], len_table);
6181 free_table = shading_table;
6186 shading_table->sensor_width = user_shading_table->sensor_width;
6187 shading_table->sensor_height = user_shading_table->sensor_height;
6188 shading_table->fraction_bits = user_shading_table->fraction_bits;
6190 free_table = asd->params.css_param.shading_table;
6191 asd->params.css_param.shading_table = shading_table;
6192 atomisp_css_set_shading_table(asd, shading_table);
6193 asd->params.sc_en = 1;
6196 if (free_table != NULL)
6197 atomisp_css_shading_table_free(free_table);
6202 /*Turn off ISP dphy */
6203 int atomisp_ospm_dphy_down(struct atomisp_device *isp)
6205 unsigned long flags;
6208 dev_dbg(isp->dev, "%s\n", __func__);
6210 /* if ISP timeout, we can force powerdown */
6211 if (isp->isp_timeout)
6214 if (!atomisp_dev_users(isp))
6217 spin_lock_irqsave(&isp->lock, flags);
6218 isp->sw_contex.power_state = ATOM_ISP_POWER_DOWN;
6219 spin_unlock_irqrestore(&isp->lock, flags);
6222 * MRFLD IUNIT DPHY is located in an always-power-on island
6223 * MRFLD HW design need all CSI ports are disabled before
6224 * powering down the IUNIT.
6226 pci_read_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, ®);
6227 reg |= MRFLD_ALL_CSI_PORTS_OFF_MASK;
6228 pci_write_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, reg);
6232 /*Turn on ISP dphy */
6233 int atomisp_ospm_dphy_up(struct atomisp_device *isp)
6235 unsigned long flags;
6236 dev_dbg(isp->dev, "%s\n", __func__);
6238 spin_lock_irqsave(&isp->lock, flags);
6239 isp->sw_contex.power_state = ATOM_ISP_POWER_UP;
6240 spin_unlock_irqrestore(&isp->lock, flags);
6246 int atomisp_exif_makernote(struct atomisp_sub_device *asd,
6247 struct atomisp_makernote_info *config)
6249 struct v4l2_control ctrl;
6250 struct atomisp_device *isp = asd->isp;
6252 ctrl.id = V4L2_CID_FOCAL_ABSOLUTE;
6254 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
6255 dev_warn(isp->dev, "failed to g_ctrl for focal length\n");
6258 config->focal_length = ctrl.value;
6261 ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE;
6263 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
6264 dev_warn(isp->dev, "failed to g_ctrl for f-number\n");
6267 config->f_number_curr = ctrl.value;
6270 ctrl.id = V4L2_CID_FNUMBER_RANGE;
6272 (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
6273 dev_warn(isp->dev, "failed to g_ctrl for f number range\n");
6276 config->f_number_range = ctrl.value;
6282 int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
6283 struct atomisp_cont_capture_conf *cvf_config)
6285 struct v4l2_ctrl *c;
6288 * In case of M10MO ZSL capture case, we need to issue a separate
6289 * capture request to M10MO which will output captured jpeg image
6292 asd->isp->inputs[asd->input_curr].camera->ctrl_handler,
6293 V4L2_CID_START_ZSL_CAPTURE);
6296 dev_dbg(asd->isp->dev, "%s trigger ZSL capture request\n",
6298 /* TODO: use the cvf_config */
6299 ret = v4l2_ctrl_s_ctrl(c, 1);
6303 return v4l2_ctrl_s_ctrl(c, 0);
6306 asd->params.offline_parm = *cvf_config;
6308 if (asd->params.offline_parm.num_captures) {
6309 if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED) {
6310 unsigned int init_raw_num;
6312 if (asd->enable_raw_buffer_lock->val) {
6314 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN;
6315 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
6316 asd->params.video_dis_en)
6318 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
6321 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES;
6324 /* TODO: this can be removed once user-space
6325 * has been updated to use control API */
6326 asd->continuous_raw_buffer_size->val =
6328 asd->continuous_raw_buffer_size->val,
6329 asd->params.offline_parm.
6330 num_captures + init_raw_num);
6331 asd->continuous_raw_buffer_size->val =
6332 min_t(int, ATOMISP_CONT_RAW_FRAMES,
6333 asd->continuous_raw_buffer_size->val);
6335 asd->continuous_mode->val = true;
6337 asd->continuous_mode->val = false;
6338 __enable_continuous_mode(asd, false);
6345 * set auto exposure metering window to camera sensor
6347 int atomisp_s_ae_window(struct atomisp_sub_device *asd,
6348 struct atomisp_ae_window *arg)
6350 struct atomisp_device *isp = asd->isp;
6351 /* Coverity CID 298071 - initialzize struct */
6352 struct v4l2_subdev_selection sel = { 0 };
6354 sel.r.left = arg->x_left;
6355 sel.r.top = arg->y_top;
6356 sel.r.width = arg->x_right - arg->x_left + 1;
6357 sel.r.height = arg->y_bottom - arg->y_top + 1;
6359 if (v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
6360 pad, set_selection, NULL, &sel)) {
6361 dev_err(isp->dev, "failed to call sensor set_selection.\n");
6368 int atomisp_flash_enable(struct atomisp_sub_device *asd, int num_frames)
6370 struct atomisp_device *isp = asd->isp;
6372 if (num_frames < 0) {
6373 dev_dbg(isp->dev, "%s ERROR: num_frames: %d\n", __func__,
6377 /* a requested flash is still in progress. */
6378 if (num_frames && asd->params.flash_state != ATOMISP_FLASH_IDLE) {
6379 dev_dbg(isp->dev, "%s flash busy: %d frames left: %d\n",
6380 __func__, asd->params.flash_state,
6381 asd->params.num_flash_frames);
6385 asd->params.num_flash_frames = num_frames;
6386 asd->params.flash_state = ATOMISP_FLASH_REQUESTED;
6390 int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd,
6391 uint16_t source_pad)
6394 struct atomisp_device *isp = asd->isp;
6396 if (isp->inputs[asd->input_curr].camera_caps->
6397 sensor[asd->sensor_curr].stream_num == 1)
6398 return ATOMISP_INPUT_STREAM_GENERAL;
6400 switch (source_pad) {
6401 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
6402 stream_id = ATOMISP_INPUT_STREAM_CAPTURE;
6404 case ATOMISP_SUBDEV_PAD_SOURCE_VF:
6405 stream_id = ATOMISP_INPUT_STREAM_POSTVIEW;
6407 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
6408 stream_id = ATOMISP_INPUT_STREAM_PREVIEW;
6410 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
6411 stream_id = ATOMISP_INPUT_STREAM_VIDEO;
6414 stream_id = ATOMISP_INPUT_STREAM_GENERAL;
6420 bool atomisp_is_vf_pipe(struct atomisp_video_pipe *pipe)
6422 struct atomisp_sub_device *asd = pipe->asd;
6424 if (pipe == &asd->video_out_vf)
6427 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
6428 pipe == &asd->video_out_preview)
6434 static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id)
6436 struct atomisp_device *isp = asd->isp;
6438 if (!asd->enable_raw_buffer_lock->val) {
6439 dev_warn(isp->dev, "%s Raw Buffer Lock is disable.\n", __func__);
6442 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) {
6443 dev_err(isp->dev, "%s streaming %d invalid exp_id %d.\n",
6444 __func__, exp_id, asd->streaming);
6447 if ((exp_id > ATOMISP_MAX_EXP_ID) || (exp_id <= 0)) {
6448 dev_err(isp->dev, "%s exp_id %d invalid.\n", __func__, exp_id);
6454 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd)
6456 unsigned long flags;
6457 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
6458 memset(asd->raw_buffer_bitmap, 0, sizeof(asd->raw_buffer_bitmap));
6459 asd->raw_buffer_locked_count = 0;
6460 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
6463 int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
6466 unsigned long flags;
6468 if (__checking_exp_id(asd, exp_id))
6471 bitmap = asd->raw_buffer_bitmap + exp_id / 32;
6473 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
6474 (*bitmap) |= (1 << bit);
6475 asd->raw_buffer_locked_count++;
6476 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
6478 dev_dbg(asd->isp->dev, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6479 __func__, exp_id, asd->raw_buffer_locked_count);
6481 /* Check if the raw buffer after next is still locked!!! */
6483 if (exp_id > ATOMISP_MAX_EXP_ID)
6484 exp_id -= ATOMISP_MAX_EXP_ID;
6485 bitmap = asd->raw_buffer_bitmap + exp_id / 32;
6487 if ((*bitmap) & (1 << bit)) {
6490 /* WORKAROUND unlock the raw buffer compulsively */
6491 ret = atomisp_css_exp_id_unlock(asd, exp_id);
6493 dev_err(asd->isp->dev, "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n",
6494 __func__, exp_id, ret);
6498 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
6499 (*bitmap) &= ~(1 << bit);
6500 asd->raw_buffer_locked_count--;
6501 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
6502 dev_warn(asd->isp->dev, "%s exp_id is wrapping back to %d but it is still locked so force unlock it, raw_buffer_locked_count %d\n",
6503 __func__, exp_id, asd->raw_buffer_locked_count);
6508 static int __is_raw_buffer_locked(struct atomisp_sub_device *asd, int exp_id)
6511 unsigned long flags;
6514 if (__checking_exp_id(asd, exp_id))
6517 bitmap = asd->raw_buffer_bitmap + exp_id / 32;
6519 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
6520 ret = ((*bitmap) & (1 << bit));
6521 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
6525 static int __clear_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
6528 unsigned long flags;
6530 if (__is_raw_buffer_locked(asd, exp_id))
6533 bitmap = asd->raw_buffer_bitmap + exp_id / 32;
6535 spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
6536 (*bitmap) &= ~(1 << bit);
6537 asd->raw_buffer_locked_count--;
6538 spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
6540 dev_dbg(asd->isp->dev, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6541 __func__, exp_id, asd->raw_buffer_locked_count);
6545 int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id)
6547 struct atomisp_device *isp = asd->isp;
6548 int value = *exp_id;
6551 ret = __is_raw_buffer_locked(asd, value);
6553 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
6557 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
6558 ret = atomisp_css_exp_id_capture(asd, value);
6560 dev_err(isp->dev, "%s exp_id %d failed.\n", __func__, value);
6566 int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id)
6568 struct atomisp_device *isp = asd->isp;
6569 int value = *exp_id;
6572 ret = __clear_raw_buffer_bitmap(asd, value);
6574 dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
6578 dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
6579 ret = atomisp_css_exp_id_unlock(asd, value);
6581 dev_err(isp->dev, "%s exp_id %d failed, err %d.\n",
6582 __func__, value, ret);
6587 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd,
6588 unsigned int *enable)
6595 value = *enable > 0 ? true : false;
6597 atomisp_en_dz_capt_pipe(asd, value);
6602 int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event)
6604 if (!event || asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
6607 dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n",
6611 case V4L2_EVENT_FRAME_SYNC:
6612 atomisp_sof_event(asd);
6614 case V4L2_EVENT_FRAME_END:
6615 atomisp_eof_event(asd, 0);
6617 case V4L2_EVENT_ATOMISP_3A_STATS_READY:
6618 atomisp_3a_stats_ready_event(asd, 0);
6620 case V4L2_EVENT_ATOMISP_METADATA_READY:
6621 atomisp_metadata_ready_event(asd, 0);
6630 int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe)
6632 struct atomisp_sub_device *asd = pipe->asd;
6634 if (ATOMISP_USE_YUVPP(asd))
6635 return CSS_PIPE_ID_YUVPP;
6636 else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER)
6637 return CSS_PIPE_ID_VIDEO;
6638 else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT)
6639 return CSS_PIPE_ID_CAPTURE;
6640 else if (pipe == &asd->video_out_video_capture)
6641 return CSS_PIPE_ID_VIDEO;
6642 else if (pipe == &asd->video_out_vf)
6643 return CSS_PIPE_ID_CAPTURE;
6644 else if (pipe == &asd->video_out_preview) {
6645 if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
6646 return CSS_PIPE_ID_VIDEO;
6648 return CSS_PIPE_ID_PREVIEW;
6649 } else if (pipe == &asd->video_out_capture) {
6651 return IA_CSS_PIPE_ID_COPY;
6653 return CSS_PIPE_ID_CAPTURE;
6657 dev_warn(asd->isp->dev, "%s failed to find proper pipe\n",
6659 return CSS_PIPE_ID_CAPTURE;
6662 int atomisp_get_invalid_frame_num(struct video_device *vdev,
6663 int *invalid_frame_num)
6665 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
6666 struct atomisp_sub_device *asd = pipe->asd;
6667 enum atomisp_css_pipe_id pipe_id;
6668 struct ia_css_pipe_info p_info;
6671 if (asd->isp->inputs[asd->input_curr].camera_caps->
6672 sensor[asd->sensor_curr].stream_num > 1) {
6674 *invalid_frame_num = 0;
6678 pipe_id = atomisp_get_pipe_id(pipe);
6679 if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id]) {
6680 dev_warn(asd->isp->dev, "%s pipe %d has not been created yet, do SET_FMT first!\n",
6685 ret = ia_css_pipe_get_info(
6686 asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
6687 .pipes[pipe_id], &p_info);
6688 if (ret == IA_CSS_SUCCESS) {
6689 *invalid_frame_num = p_info.num_invalid_frames;
6692 dev_warn(asd->isp->dev, "%s get pipe infor failed %d\n",