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
= &isp
->asd
[0];
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 p
.parm
.capture
.capturemode
= modes
[runmode
->mode
];
2112 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
2116 mutex_unlock(asd
->ctrl_handler
.lock
);
2122 * Function to enable/disable lens geometry distortion correction (GDC) and
2123 * chromatic aberration correction (CAC)
2125 int atomisp_gdc_cac(struct atomisp_sub_device
*asd
, int flag
,
2129 *value
= asd
->params
.gdc_cac_en
;
2133 asd
->params
.gdc_cac_en
= !!*value
;
2134 if (asd
->params
.gdc_cac_en
) {
2135 atomisp_css_set_morph_table(asd
,
2136 asd
->params
.css_param
.morph_table
);
2138 atomisp_css_set_morph_table(asd
, NULL
);
2140 asd
->params
.css_update_params_needed
= true;
2141 atomisp_update_capture_mode(asd
);
2146 * Function to enable/disable low light mode including ANR
2148 int atomisp_low_light(struct atomisp_sub_device
*asd
, int flag
,
2152 *value
= asd
->params
.low_light
;
2156 asd
->params
.low_light
= (*value
!= 0);
2157 atomisp_update_capture_mode(asd
);
2162 * Function to enable/disable extra noise reduction (XNR) in low light
2165 int atomisp_xnr(struct atomisp_sub_device
*asd
, int flag
,
2169 *xnr_enable
= asd
->params
.xnr_en
;
2173 atomisp_css_capture_enable_xnr(asd
, !!*xnr_enable
);
2179 * Function to configure bayer noise reduction
2181 int atomisp_nr(struct atomisp_sub_device
*asd
, int flag
,
2182 struct atomisp_nr_config
*arg
)
2185 /* Get nr config from current setup */
2186 if (atomisp_css_get_nr_config(asd
, arg
))
2189 /* Set nr config to isp parameters */
2190 memcpy(&asd
->params
.css_param
.nr_config
, arg
,
2191 sizeof(struct atomisp_css_nr_config
));
2192 atomisp_css_set_nr_config(asd
, &asd
->params
.css_param
.nr_config
);
2193 asd
->params
.css_update_params_needed
= true;
2199 * Function to configure temporal noise reduction (TNR)
2201 int atomisp_tnr(struct atomisp_sub_device
*asd
, int flag
,
2202 struct atomisp_tnr_config
*config
)
2204 /* Get tnr config from current setup */
2206 /* Get tnr config from current setup */
2207 if (atomisp_css_get_tnr_config(asd
, config
))
2210 /* Set tnr config to isp parameters */
2211 memcpy(&asd
->params
.css_param
.tnr_config
, config
,
2212 sizeof(struct atomisp_css_tnr_config
));
2213 atomisp_css_set_tnr_config(asd
, &asd
->params
.css_param
.tnr_config
);
2214 asd
->params
.css_update_params_needed
= true;
2221 * Function to configure black level compensation
2223 int atomisp_black_level(struct atomisp_sub_device
*asd
, int flag
,
2224 struct atomisp_ob_config
*config
)
2227 /* Get ob config from current setup */
2228 if (atomisp_css_get_ob_config(asd
, config
))
2231 /* Set ob config to isp parameters */
2232 memcpy(&asd
->params
.css_param
.ob_config
, config
,
2233 sizeof(struct atomisp_css_ob_config
));
2234 atomisp_css_set_ob_config(asd
, &asd
->params
.css_param
.ob_config
);
2235 asd
->params
.css_update_params_needed
= true;
2242 * Function to configure edge enhancement
2244 int atomisp_ee(struct atomisp_sub_device
*asd
, int flag
,
2245 struct atomisp_ee_config
*config
)
2248 /* Get ee config from current setup */
2249 if (atomisp_css_get_ee_config(asd
, config
))
2252 /* Set ee config to isp parameters */
2253 memcpy(&asd
->params
.css_param
.ee_config
, config
,
2254 sizeof(asd
->params
.css_param
.ee_config
));
2255 atomisp_css_set_ee_config(asd
, &asd
->params
.css_param
.ee_config
);
2256 asd
->params
.css_update_params_needed
= true;
2263 * Function to update Gamma table for gamma, brightness and contrast config
2265 int atomisp_gamma(struct atomisp_sub_device
*asd
, int flag
,
2266 struct atomisp_gamma_table
*config
)
2269 /* Get gamma table from current setup */
2270 if (atomisp_css_get_gamma_table(asd
, config
))
2273 /* Set gamma table to isp parameters */
2274 memcpy(&asd
->params
.css_param
.gamma_table
, config
,
2275 sizeof(asd
->params
.css_param
.gamma_table
));
2276 atomisp_css_set_gamma_table(asd
, &asd
->params
.css_param
.gamma_table
);
2283 * Function to update Ctc table for Chroma Enhancement
2285 int atomisp_ctc(struct atomisp_sub_device
*asd
, int flag
,
2286 struct atomisp_ctc_table
*config
)
2289 /* Get ctc table from current setup */
2290 if (atomisp_css_get_ctc_table(asd
, config
))
2293 /* Set ctc table to isp parameters */
2294 memcpy(&asd
->params
.css_param
.ctc_table
, config
,
2295 sizeof(asd
->params
.css_param
.ctc_table
));
2296 atomisp_css_set_ctc_table(asd
, &asd
->params
.css_param
.ctc_table
);
2303 * Function to update gamma correction parameters
2305 int atomisp_gamma_correction(struct atomisp_sub_device
*asd
, int flag
,
2306 struct atomisp_gc_config
*config
)
2309 /* Get gamma correction params from current setup */
2310 if (atomisp_css_get_gc_config(asd
, config
))
2313 /* Set gamma correction params to isp parameters */
2314 memcpy(&asd
->params
.css_param
.gc_config
, config
,
2315 sizeof(asd
->params
.css_param
.gc_config
));
2316 atomisp_css_set_gc_config(asd
, &asd
->params
.css_param
.gc_config
);
2317 asd
->params
.css_update_params_needed
= true;
2324 * Function to update narrow gamma flag
2326 int atomisp_formats(struct atomisp_sub_device
*asd
, int flag
,
2327 struct atomisp_formats_config
*config
)
2330 /* Get narrow gamma flag from current setup */
2331 if (atomisp_css_get_formats_config(asd
, config
))
2334 /* Set narrow gamma flag to isp parameters */
2335 memcpy(&asd
->params
.css_param
.formats_config
, config
,
2336 sizeof(asd
->params
.css_param
.formats_config
));
2337 atomisp_css_set_formats_config(asd
, &asd
->params
.css_param
.formats_config
);
2343 void atomisp_free_internal_buffers(struct atomisp_sub_device
*asd
)
2345 atomisp_free_css_parameters(&asd
->params
.css_param
);
2347 if (asd
->raw_output_frame
) {
2348 atomisp_css_frame_free(asd
->raw_output_frame
);
2349 asd
->raw_output_frame
= NULL
;
2353 static void atomisp_update_grid_info(struct atomisp_sub_device
*asd
,
2354 enum atomisp_css_pipe_id pipe_id
,
2357 struct atomisp_device
*isp
= asd
->isp
;
2359 uint16_t stream_id
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
2361 if (atomisp_css_get_grid_info(asd
, pipe_id
, source_pad
))
2364 /* We must free all buffers because they no longer match
2366 atomisp_css_free_stat_buffers(asd
);
2368 err
= atomisp_alloc_css_stat_bufs(asd
, stream_id
);
2370 dev_err(isp
->dev
, "stat_buf allocate error\n");
2374 if (atomisp_alloc_3a_output_buf(asd
)) {
2375 /* Failure for 3A buffers does not influence DIS buffers */
2376 if (asd
->params
.s3a_output_bytes
!= 0) {
2377 /* For SOC sensor happens s3a_output_bytes == 0,
2378 * using if condition to exclude false error log */
2379 dev_err(isp
->dev
, "Failed to allocate memory for 3A statistics\n");
2384 if (atomisp_alloc_dis_coef_buf(asd
)) {
2386 "Failed to allocate memory for DIS statistics\n");
2390 if (atomisp_alloc_metadata_output_buf(asd
)) {
2391 dev_err(isp
->dev
, "Failed to allocate memory for metadata\n");
2398 atomisp_css_free_stat_buffers(asd
);
2402 static void atomisp_curr_user_grid_info(struct atomisp_sub_device
*asd
,
2403 struct atomisp_grid_info
*info
)
2405 memcpy(info
, &asd
->params
.curr_grid_info
.s3a_grid
,
2406 sizeof(struct atomisp_css_3a_grid_info
));
2409 int atomisp_compare_grid(struct atomisp_sub_device
*asd
,
2410 struct atomisp_grid_info
*atomgrid
)
2412 struct atomisp_grid_info tmp
= {0};
2414 atomisp_curr_user_grid_info(asd
, &tmp
);
2415 return memcmp(atomgrid
, &tmp
, sizeof(tmp
));
2419 * Function to update Gdc table for gdc
2421 int atomisp_gdc_cac_table(struct atomisp_sub_device
*asd
, int flag
,
2422 struct atomisp_morph_table
*config
)
2426 struct atomisp_device
*isp
= asd
->isp
;
2429 /* Get gdc table from current setup */
2430 struct atomisp_css_morph_table tab
= {0};
2431 atomisp_css_get_morph_table(asd
, &tab
);
2433 config
->width
= tab
.width
;
2434 config
->height
= tab
.height
;
2436 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
2437 ret
= copy_to_user(config
->coordinates_x
[i
],
2438 tab
.coordinates_x
[i
], tab
.height
*
2439 tab
.width
* sizeof(*tab
.coordinates_x
[i
]));
2442 "Failed to copy to User for x\n");
2445 ret
= copy_to_user(config
->coordinates_y
[i
],
2446 tab
.coordinates_y
[i
], tab
.height
*
2447 tab
.width
* sizeof(*tab
.coordinates_y
[i
]));
2450 "Failed to copy to User for y\n");
2455 struct atomisp_css_morph_table
*tab
=
2456 asd
->params
.css_param
.morph_table
;
2458 /* free first if we have one */
2460 atomisp_css_morph_table_free(tab
);
2461 asd
->params
.css_param
.morph_table
= NULL
;
2464 /* allocate new one */
2465 tab
= atomisp_css_morph_table_allocate(config
->width
,
2469 dev_err(isp
->dev
, "out of memory\n");
2473 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
2474 ret
= copy_from_user(tab
->coordinates_x
[i
],
2475 config
->coordinates_x
[i
],
2476 config
->height
* config
->width
*
2477 sizeof(*config
->coordinates_x
[i
]));
2480 "Failed to copy from User for x, ret %d\n",
2482 atomisp_css_morph_table_free(tab
);
2485 ret
= copy_from_user(tab
->coordinates_y
[i
],
2486 config
->coordinates_y
[i
],
2487 config
->height
* config
->width
*
2488 sizeof(*config
->coordinates_y
[i
]));
2491 "Failed to copy from User for y, ret is %d\n",
2493 atomisp_css_morph_table_free(tab
);
2497 asd
->params
.css_param
.morph_table
= tab
;
2498 if (asd
->params
.gdc_cac_en
)
2499 atomisp_css_set_morph_table(asd
, tab
);
2505 int atomisp_macc_table(struct atomisp_sub_device
*asd
, int flag
,
2506 struct atomisp_macc_config
*config
)
2508 struct atomisp_css_macc_table
*macc_table
;
2510 switch (config
->color_effect
) {
2511 case V4L2_COLORFX_NONE
:
2512 macc_table
= &asd
->params
.css_param
.macc_table
;
2514 case V4L2_COLORFX_SKY_BLUE
:
2515 macc_table
= &blue_macc_table
;
2517 case V4L2_COLORFX_GRASS_GREEN
:
2518 macc_table
= &green_macc_table
;
2520 case V4L2_COLORFX_SKIN_WHITEN_LOW
:
2521 macc_table
= &skin_low_macc_table
;
2523 case V4L2_COLORFX_SKIN_WHITEN
:
2524 macc_table
= &skin_medium_macc_table
;
2526 case V4L2_COLORFX_SKIN_WHITEN_HIGH
:
2527 macc_table
= &skin_high_macc_table
;
2534 /* Get macc table from current setup */
2535 memcpy(&config
->table
, macc_table
,
2536 sizeof(struct atomisp_css_macc_table
));
2538 memcpy(macc_table
, &config
->table
,
2539 sizeof(struct atomisp_css_macc_table
));
2540 if (config
->color_effect
== asd
->params
.color_effect
)
2541 atomisp_css_set_macc_table(asd
, macc_table
);
2547 int atomisp_set_dis_vector(struct atomisp_sub_device
*asd
,
2548 struct atomisp_dis_vector
*vector
)
2550 atomisp_css_video_set_dis_vector(asd
, vector
);
2552 asd
->params
.dis_proj_data_valid
= false;
2553 asd
->params
.css_update_params_needed
= true;
2558 * Function to set/get image stablization statistics
2560 int atomisp_get_dis_stat(struct atomisp_sub_device
*asd
,
2561 struct atomisp_dis_statistics
*stats
)
2563 return atomisp_css_get_dis_stat(asd
, stats
);
2567 * Function set camrea_prefiles.xml current sensor pixel array size
2569 int atomisp_set_array_res(struct atomisp_sub_device
*asd
,
2570 struct atomisp_resolution
*config
)
2572 dev_dbg(asd
->isp
->dev
, ">%s start\n", __func__
);
2574 dev_err(asd
->isp
->dev
, "Set sensor array size is not valid\n");
2578 asd
->sensor_array_res
.width
= config
->width
;
2579 asd
->sensor_array_res
.height
= config
->height
;
2584 * Function to get DVS2 BQ resolution settings
2586 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device
*asd
,
2587 struct atomisp_dvs2_bq_resolutions
*bq_res
)
2589 struct ia_css_pipe_config
*pipe_cfg
= NULL
;
2590 struct ia_css_stream_config
*stream_cfg
= NULL
;
2591 struct ia_css_stream_input_config
*input_config
= NULL
;
2593 struct ia_css_stream
*stream
=
2594 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
;
2596 dev_warn(asd
->isp
->dev
, "stream is not created");
2600 pipe_cfg
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
2601 .pipe_configs
[CSS_PIPE_ID_VIDEO
];
2602 stream_cfg
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
2604 input_config
= &stream_cfg
->input_config
;
2609 /* the GDC output resolution */
2610 bq_res
->output_bq
.width_bq
= pipe_cfg
->output_info
[0].res
.width
/ 2;
2611 bq_res
->output_bq
.height_bq
= pipe_cfg
->output_info
[0].res
.height
/ 2;
2613 bq_res
->envelope_bq
.width_bq
= 0;
2614 bq_res
->envelope_bq
.height_bq
= 0;
2615 /* the GDC input resolution */
2616 if (!asd
->continuous_mode
->val
) {
2617 bq_res
->source_bq
.width_bq
= bq_res
->output_bq
.width_bq
+
2618 pipe_cfg
->dvs_envelope
.width
/ 2;
2619 bq_res
->source_bq
.height_bq
= bq_res
->output_bq
.height_bq
+
2620 pipe_cfg
->dvs_envelope
.height
/ 2;
2622 * Bad pixels caused by spatial filter processing
2623 * ISP filter resolution should be given by CSS/FW, but for now
2624 * there is not such API to query, and it is fixed value, so
2627 bq_res
->ispfilter_bq
.width_bq
= 12 / 2;
2628 bq_res
->ispfilter_bq
.height_bq
= 12 / 2;
2629 /* spatial filter shift, always 4 pixels */
2630 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2631 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2633 if (asd
->params
.video_dis_en
) {
2634 bq_res
->envelope_bq
.width_bq
= pipe_cfg
->dvs_envelope
.width
2635 / 2 - bq_res
->ispfilter_bq
.width_bq
;
2636 bq_res
->envelope_bq
.height_bq
= pipe_cfg
->dvs_envelope
.height
2637 / 2 - bq_res
->ispfilter_bq
.height_bq
;
2640 unsigned int w_padding
;
2641 unsigned int gdc_effective_input
= 0;
2644 * gdc_effective_input = effective_input + envelope
2646 * From the comment and formula in BZ1786,
2647 * we see the source_bq should be:
2648 * effective_input / bayer_ds_ratio
2650 bq_res
->source_bq
.width_bq
=
2651 (input_config
->effective_res
.width
*
2652 pipe_cfg
->bayer_ds_out_res
.width
/
2653 input_config
->effective_res
.width
+ 1) / 2;
2654 bq_res
->source_bq
.height_bq
=
2655 (input_config
->effective_res
.height
*
2656 pipe_cfg
->bayer_ds_out_res
.height
/
2657 input_config
->effective_res
.height
+ 1) / 2;
2660 if (!asd
->params
.video_dis_en
) {
2662 * We adjust the ispfilter_bq to:
2663 * ispfilter_bq = 128/BDS
2664 * we still need firmware team to provide an offical
2667 bq_res
->ispfilter_bq
.width_bq
= 128 *
2668 pipe_cfg
->bayer_ds_out_res
.width
/
2669 input_config
->effective_res
.width
/ 2;
2670 bq_res
->ispfilter_bq
.height_bq
= 128 *
2671 pipe_cfg
->bayer_ds_out_res
.width
/
2672 input_config
->effective_res
.width
/ 2;
2674 if (IS_HWREVISION(asd
->isp
, ATOMISP_HW_REVISION_ISP2401
)) {
2675 /* No additional left padding for ISYS2401 */
2676 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2677 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2680 * For the w_padding and gdc_shift_bq cacluation
2681 * Please see the BZ 1786 and 4358 for more info.
2682 * Just test that this formula can work now,
2683 * but we still have no offical formula.
2685 * w_padding = ceiling(gdc_effective_input
2686 * /128, 1) * 128 - effective_width
2687 * gdc_shift_bq = w_padding/BDS/2 + ispfilter_bq/2
2689 gdc_effective_input
=
2690 input_config
->effective_res
.width
+
2691 pipe_cfg
->dvs_envelope
.width
;
2692 w_padding
= roundup(gdc_effective_input
, 128) -
2693 input_config
->effective_res
.width
;
2694 w_padding
= w_padding
*
2695 pipe_cfg
->bayer_ds_out_res
.width
/
2696 input_config
->effective_res
.width
+ 1;
2697 w_padding
= roundup(w_padding
/2, 1);
2699 bq_res
->gdc_shift_bq
.width_bq
= bq_res
->ispfilter_bq
.width_bq
/ 2
2701 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2704 unsigned int dvs_w
, dvs_h
, dvs_w_max
, dvs_h_max
;
2706 bq_res
->ispfilter_bq
.width_bq
= 8 / 2;
2707 bq_res
->ispfilter_bq
.height_bq
= 8 / 2;
2709 if (IS_HWREVISION(asd
->isp
, ATOMISP_HW_REVISION_ISP2401
)) {
2710 /* No additional left padding for ISYS2401 */
2711 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2712 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2715 roundup(input_config
->effective_res
.width
, 128) -
2716 input_config
->effective_res
.width
;
2719 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2 +
2721 pipe_cfg
->bayer_ds_out_res
.width
/
2722 input_config
->effective_res
.width
+ 1) / 2;
2723 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2726 dvs_w
= pipe_cfg
->bayer_ds_out_res
.width
-
2727 pipe_cfg
->output_info
[0].res
.width
;
2728 dvs_h
= pipe_cfg
->bayer_ds_out_res
.height
-
2729 pipe_cfg
->output_info
[0].res
.height
;
2730 dvs_w_max
= rounddown(
2731 pipe_cfg
->output_info
[0].res
.width
/ 5,
2732 ATOM_ISP_STEP_WIDTH
);
2733 dvs_h_max
= rounddown(
2734 pipe_cfg
->output_info
[0].res
.height
/ 5,
2735 ATOM_ISP_STEP_HEIGHT
);
2736 bq_res
->envelope_bq
.width_bq
=
2737 min((dvs_w
/ 2), (dvs_w_max
/ 2)) -
2738 bq_res
->ispfilter_bq
.width_bq
;
2739 bq_res
->envelope_bq
.height_bq
=
2740 min((dvs_h
/ 2), (dvs_h_max
/ 2)) -
2741 bq_res
->ispfilter_bq
.height_bq
;
2745 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",
2746 bq_res
->source_bq
.width_bq
, bq_res
->source_bq
.height_bq
,
2747 bq_res
->ispfilter_bq
.width_bq
, bq_res
->ispfilter_bq
.height_bq
,
2748 bq_res
->gdc_shift_bq
.width_bq
, bq_res
->gdc_shift_bq
.height_bq
,
2749 bq_res
->envelope_bq
.width_bq
, bq_res
->envelope_bq
.height_bq
,
2750 bq_res
->output_bq
.width_bq
, bq_res
->output_bq
.height_bq
);
2755 int atomisp_set_dis_coefs(struct atomisp_sub_device
*asd
,
2756 struct atomisp_dis_coefficients
*coefs
)
2758 return atomisp_css_set_dis_coefs(asd
, coefs
);
2762 * Function to set/get 3A stat from isp
2764 int atomisp_3a_stat(struct atomisp_sub_device
*asd
, int flag
,
2765 struct atomisp_3a_statistics
*config
)
2767 struct atomisp_device
*isp
= asd
->isp
;
2768 struct atomisp_s3a_buf
*s3a_buf
;
2774 /* sanity check to avoid writing into unallocated memory. */
2775 if (asd
->params
.s3a_output_bytes
== 0)
2778 if (atomisp_compare_grid(asd
, &config
->grid_info
) != 0) {
2779 /* If the grid info in the argument differs from the current
2780 grid info, we tell the caller to reset the grid size and
2785 if (list_empty(&asd
->s3a_stats_ready
)) {
2786 dev_err(isp
->dev
, "3a statistics is not valid.\n");
2790 s3a_buf
= list_entry(asd
->s3a_stats_ready
.next
,
2791 struct atomisp_s3a_buf
, list
);
2792 if (s3a_buf
->s3a_map
)
2793 ia_css_translate_3a_statistics(
2794 asd
->params
.s3a_user_stat
, s3a_buf
->s3a_map
);
2796 ia_css_get_3a_statistics(asd
->params
.s3a_user_stat
,
2799 config
->exp_id
= s3a_buf
->s3a_data
->exp_id
;
2800 config
->isp_config_id
= s3a_buf
->s3a_data
->isp_config_id
;
2802 ret
= copy_to_user(config
->data
, asd
->params
.s3a_user_stat
->data
,
2803 asd
->params
.s3a_output_bytes
);
2805 dev_err(isp
->dev
, "copy to user failed: copied %lu bytes\n",
2810 /* Move to free buffer list */
2811 list_del_init(&s3a_buf
->list
);
2812 list_add_tail(&s3a_buf
->list
, &asd
->s3a_stats
);
2813 dev_dbg(isp
->dev
, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n", __func__
,
2814 config
->exp_id
, config
->isp_config_id
);
2818 int atomisp_get_metadata(struct atomisp_sub_device
*asd
, int flag
,
2819 struct atomisp_metadata
*md
)
2821 struct atomisp_device
*isp
= asd
->isp
;
2822 struct ia_css_stream_config
*stream_config
;
2823 struct ia_css_stream_info
*stream_info
;
2824 struct camera_mipi_info
*mipi_info
;
2825 struct atomisp_metadata_buf
*md_buf
;
2826 enum atomisp_metadata_type md_type
= ATOMISP_MAIN_METADATA
;
2832 stream_config
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2834 stream_info
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2837 /* We always return the resolution and stride even if there is
2838 * no valid metadata. This allows the caller to get the information
2839 * needed to allocate user-space buffers. */
2840 md
->width
= stream_info
->metadata_info
.resolution
.width
;
2841 md
->height
= stream_info
->metadata_info
.resolution
.height
;
2842 md
->stride
= stream_info
->metadata_info
.stride
;
2844 /* sanity check to avoid writing into unallocated memory.
2845 * This does not return an error because it is a valid way
2846 * for applications to detect that metadata is not enabled. */
2847 if (md
->width
== 0 || md
->height
== 0 || !md
->data
)
2850 /* This is done in the atomisp_buf_done() */
2851 if (list_empty(&asd
->metadata_ready
[md_type
])) {
2852 dev_warn(isp
->dev
, "Metadata queue is empty now!\n");
2856 mipi_info
= atomisp_to_sensor_mipi_info(
2857 isp
->inputs
[asd
->input_curr
].camera
);
2858 if (mipi_info
== NULL
)
2861 if (mipi_info
->metadata_effective_width
!= NULL
) {
2862 for (i
= 0; i
< md
->height
; i
++)
2863 md
->effective_width
[i
] =
2864 mipi_info
->metadata_effective_width
[i
];
2867 md_buf
= list_entry(asd
->metadata_ready
[md_type
].next
,
2868 struct atomisp_metadata_buf
, list
);
2869 md
->exp_id
= md_buf
->metadata
->exp_id
;
2870 if (md_buf
->md_vptr
) {
2871 ret
= copy_to_user(md
->data
,
2873 stream_info
->metadata_info
.size
);
2875 hmm_load(md_buf
->metadata
->address
,
2876 asd
->params
.metadata_user
[md_type
],
2877 stream_info
->metadata_info
.size
);
2879 ret
= copy_to_user(md
->data
,
2880 asd
->params
.metadata_user
[md_type
],
2881 stream_info
->metadata_info
.size
);
2884 dev_err(isp
->dev
, "copy to user failed: copied %d bytes\n",
2889 list_del_init(&md_buf
->list
);
2890 list_add_tail(&md_buf
->list
, &asd
->metadata
[md_type
]);
2892 dev_dbg(isp
->dev
, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2893 __func__
, md_type
, md
->exp_id
);
2897 int atomisp_get_metadata_by_type(struct atomisp_sub_device
*asd
, int flag
,
2898 struct atomisp_metadata_with_type
*md
)
2900 struct atomisp_device
*isp
= asd
->isp
;
2901 struct ia_css_stream_config
*stream_config
;
2902 struct ia_css_stream_info
*stream_info
;
2903 struct camera_mipi_info
*mipi_info
;
2904 struct atomisp_metadata_buf
*md_buf
;
2905 enum atomisp_metadata_type md_type
;
2911 stream_config
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2913 stream_info
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2916 /* We always return the resolution and stride even if there is
2917 * no valid metadata. This allows the caller to get the information
2918 * needed to allocate user-space buffers. */
2919 md
->width
= stream_info
->metadata_info
.resolution
.width
;
2920 md
->height
= stream_info
->metadata_info
.resolution
.height
;
2921 md
->stride
= stream_info
->metadata_info
.stride
;
2923 /* sanity check to avoid writing into unallocated memory.
2924 * This does not return an error because it is a valid way
2925 * for applications to detect that metadata is not enabled. */
2926 if (md
->width
== 0 || md
->height
== 0 || !md
->data
)
2930 if (md_type
< 0 || md_type
>= ATOMISP_METADATA_TYPE_NUM
)
2933 /* This is done in the atomisp_buf_done() */
2934 if (list_empty(&asd
->metadata_ready
[md_type
])) {
2935 dev_warn(isp
->dev
, "Metadata queue is empty now!\n");
2939 mipi_info
= atomisp_to_sensor_mipi_info(
2940 isp
->inputs
[asd
->input_curr
].camera
);
2941 if (mipi_info
== NULL
)
2944 if (mipi_info
->metadata_effective_width
!= NULL
) {
2945 for (i
= 0; i
< md
->height
; i
++)
2946 md
->effective_width
[i
] =
2947 mipi_info
->metadata_effective_width
[i
];
2950 md_buf
= list_entry(asd
->metadata_ready
[md_type
].next
,
2951 struct atomisp_metadata_buf
, list
);
2952 md
->exp_id
= md_buf
->metadata
->exp_id
;
2953 if (md_buf
->md_vptr
) {
2954 ret
= copy_to_user(md
->data
,
2956 stream_info
->metadata_info
.size
);
2958 hmm_load(md_buf
->metadata
->address
,
2959 asd
->params
.metadata_user
[md_type
],
2960 stream_info
->metadata_info
.size
);
2962 ret
= copy_to_user(md
->data
,
2963 asd
->params
.metadata_user
[md_type
],
2964 stream_info
->metadata_info
.size
);
2967 dev_err(isp
->dev
, "copy to user failed: copied %d bytes\n",
2971 list_del_init(&md_buf
->list
);
2972 list_add_tail(&md_buf
->list
, &asd
->metadata
[md_type
]);
2974 dev_dbg(isp
->dev
, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2975 __func__
, md_type
, md
->exp_id
);
2980 * Function to calculate real zoom region for every pipe
2982 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device
*asd
,
2983 struct ia_css_dz_config
*dz_config
,
2984 enum atomisp_css_pipe_id css_pipe_id
)
2987 struct atomisp_stream_env
*stream_env
=
2988 &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
];
2989 struct atomisp_resolution eff_res
, out_res
;
2991 int w_offset
, h_offset
;
2994 memset(&eff_res
, 0, sizeof(eff_res
));
2995 memset(&out_res
, 0, sizeof(out_res
));
2997 if (dz_config
->dx
|| dz_config
->dy
)
3000 if (css_pipe_id
!= IA_CSS_PIPE_ID_PREVIEW
3001 && css_pipe_id
!= IA_CSS_PIPE_ID_CAPTURE
) {
3002 dev_err(asd
->isp
->dev
, "%s the set pipe no support crop region"
3008 stream_env
->stream_config
.input_config
.effective_res
.width
;
3010 stream_env
->stream_config
.input_config
.effective_res
.height
;
3011 if (eff_res
.width
== 0 || eff_res
.height
== 0) {
3012 dev_err(asd
->isp
->dev
, "%s err effective resolution"
3017 if (dz_config
->zoom_region
.resolution
.width
3018 == asd
->sensor_array_res
.width
3019 || dz_config
->zoom_region
.resolution
.height
3020 == asd
->sensor_array_res
.height
) {
3021 /*no need crop region*/
3022 dz_config
->zoom_region
.origin
.x
= 0;
3023 dz_config
->zoom_region
.origin
.y
= 0;
3024 dz_config
->zoom_region
.resolution
.width
= eff_res
.width
;
3025 dz_config
->zoom_region
.resolution
.height
= eff_res
.height
;
3030 * This is not the correct implementation with Google's definition, due
3031 * to firmware limitation.
3032 * map real crop region base on above calculating base max crop region.
3036 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.width
;
3038 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.height
;
3039 if (out_res
.width
== 0 || out_res
.height
== 0) {
3040 dev_err(asd
->isp
->dev
, "%s err current pipe output resolution"
3045 if (asd
->sensor_array_res
.width
* out_res
.height
3046 < out_res
.width
* asd
->sensor_array_res
.height
) {
3047 h_offset
= asd
->sensor_array_res
.height
-
3048 asd
->sensor_array_res
.width
3049 * out_res
.height
/ out_res
.width
;
3050 h_offset
= h_offset
/ 2;
3051 if (dz_config
->zoom_region
.origin
.y
< h_offset
)
3052 dz_config
->zoom_region
.origin
.y
= 0;
3054 dz_config
->zoom_region
.origin
.y
=
3055 dz_config
->zoom_region
.origin
.y
- h_offset
;
3058 w_offset
= asd
->sensor_array_res
.width
-
3059 asd
->sensor_array_res
.height
3060 * out_res
.width
/ out_res
.height
;
3061 w_offset
= w_offset
/ 2;
3062 if (dz_config
->zoom_region
.origin
.x
< w_offset
)
3063 dz_config
->zoom_region
.origin
.x
= 0;
3065 dz_config
->zoom_region
.origin
.x
=
3066 dz_config
->zoom_region
.origin
.x
- w_offset
;
3070 dz_config
->zoom_region
.origin
.x
=
3071 dz_config
->zoom_region
.origin
.x
3074 / asd
->sensor_array_res
.width
;
3076 / (asd
->sensor_array_res
.width
-
3079 dz_config
->zoom_region
.origin
.y
=
3080 dz_config
->zoom_region
.origin
.y
3083 / asd
->sensor_array_res
.height
;
3085 / (asd
->sensor_array_res
.height
-
3088 dz_config
->zoom_region
.resolution
.width
=
3089 dz_config
->zoom_region
.resolution
.width
3092 / asd
->sensor_array_res
.width
;
3094 / (asd
->sensor_array_res
.width
-
3097 dz_config
->zoom_region
.resolution
.height
=
3098 dz_config
->zoom_region
.resolution
.height
3101 / asd
->sensor_array_res
.height
;
3103 / (asd
->sensor_array_res
.height
-
3108 * Set same ratio of crop region resolution and current pipe output
3113 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.width
;
3115 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.height
;
3116 if (out_res
.width
== 0 || out_res
.height
== 0) {
3117 dev_err(asd
->isp
->dev
, "%s err current pipe output resolution"
3123 if (out_res
.width
* dz_config
->zoom_region
.resolution
.height
3124 > dz_config
->zoom_region
.resolution
.width
* out_res
.height
) {
3125 dz_config
->zoom_region
.resolution
.height
=
3126 dz_config
->zoom_region
.resolution
.width
3127 * out_res
.height
/ out_res
.width
;
3129 dz_config
->zoom_region
.resolution
.width
=
3130 dz_config
->zoom_region
.resolution
.height
3131 * out_res
.width
/ out_res
.height
;
3133 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",
3134 __func__
, dz_config
->zoom_region
.origin
.x
,
3135 dz_config
->zoom_region
.origin
.y
,
3136 dz_config
->zoom_region
.resolution
.width
,
3137 dz_config
->zoom_region
.resolution
.height
,
3138 eff_res
.width
, eff_res
.height
,
3139 asd
->sensor_array_res
.width
,
3140 asd
->sensor_array_res
.height
,
3141 out_res
.width
, out_res
.height
);
3144 if ((dz_config
->zoom_region
.origin
.x
+
3145 dz_config
->zoom_region
.resolution
.width
3147 (dz_config
->zoom_region
.origin
.y
+
3148 dz_config
->zoom_region
.resolution
.height
3157 * Function to check the zoom region whether is effective
3159 static bool atomisp_check_zoom_region(
3160 struct atomisp_sub_device
*asd
,
3161 struct ia_css_dz_config
*dz_config
)
3163 struct atomisp_resolution config
;
3167 memset(&config
, 0, sizeof(struct atomisp_resolution
));
3169 if (dz_config
->dx
&& dz_config
->dy
)
3172 config
.width
= asd
->sensor_array_res
.width
;
3173 config
.height
= asd
->sensor_array_res
.height
;
3174 w
= dz_config
->zoom_region
.origin
.x
+
3175 dz_config
->zoom_region
.resolution
.width
;
3176 h
= dz_config
->zoom_region
.origin
.y
+
3177 dz_config
->zoom_region
.resolution
.height
;
3179 if ((w
<= config
.width
) && (h
<= config
.height
) && w
> 0 && h
> 0)
3182 /* setting error zoom region */
3183 dev_err(asd
->isp
->dev
, "%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n",
3184 __func__
, dz_config
->zoom_region
.origin
.x
,
3185 dz_config
->zoom_region
.origin
.y
,
3186 dz_config
->zoom_region
.resolution
.width
,
3187 dz_config
->zoom_region
.resolution
.height
,
3188 config
.width
, config
.height
);
3193 void atomisp_apply_css_parameters(
3194 struct atomisp_sub_device
*asd
,
3195 struct atomisp_css_params
*css_param
)
3197 if (css_param
->update_flag
.wb_config
)
3198 atomisp_css_set_wb_config(asd
, &css_param
->wb_config
);
3200 if (css_param
->update_flag
.ob_config
)
3201 atomisp_css_set_ob_config(asd
, &css_param
->ob_config
);
3203 if (css_param
->update_flag
.dp_config
)
3204 atomisp_css_set_dp_config(asd
, &css_param
->dp_config
);
3206 if (css_param
->update_flag
.nr_config
)
3207 atomisp_css_set_nr_config(asd
, &css_param
->nr_config
);
3209 if (css_param
->update_flag
.ee_config
)
3210 atomisp_css_set_ee_config(asd
, &css_param
->ee_config
);
3212 if (css_param
->update_flag
.tnr_config
)
3213 atomisp_css_set_tnr_config(asd
, &css_param
->tnr_config
);
3215 if (css_param
->update_flag
.a3a_config
)
3216 atomisp_css_set_3a_config(asd
, &css_param
->s3a_config
);
3218 if (css_param
->update_flag
.ctc_config
)
3219 atomisp_css_set_ctc_config(asd
, &css_param
->ctc_config
);
3221 if (css_param
->update_flag
.cnr_config
)
3222 atomisp_css_set_cnr_config(asd
, &css_param
->cnr_config
);
3224 if (css_param
->update_flag
.ecd_config
)
3225 atomisp_css_set_ecd_config(asd
, &css_param
->ecd_config
);
3227 if (css_param
->update_flag
.ynr_config
)
3228 atomisp_css_set_ynr_config(asd
, &css_param
->ynr_config
);
3230 if (css_param
->update_flag
.fc_config
)
3231 atomisp_css_set_fc_config(asd
, &css_param
->fc_config
);
3233 if (css_param
->update_flag
.macc_config
)
3234 atomisp_css_set_macc_config(asd
, &css_param
->macc_config
);
3236 if (css_param
->update_flag
.aa_config
)
3237 atomisp_css_set_aa_config(asd
, &css_param
->aa_config
);
3239 if (css_param
->update_flag
.anr_config
)
3240 atomisp_css_set_anr_config(asd
, &css_param
->anr_config
);
3242 if (css_param
->update_flag
.xnr_config
)
3243 atomisp_css_set_xnr_config(asd
, &css_param
->xnr_config
);
3245 if (css_param
->update_flag
.yuv2rgb_cc_config
)
3246 atomisp_css_set_yuv2rgb_cc_config(asd
,
3247 &css_param
->yuv2rgb_cc_config
);
3249 if (css_param
->update_flag
.rgb2yuv_cc_config
)
3250 atomisp_css_set_rgb2yuv_cc_config(asd
,
3251 &css_param
->rgb2yuv_cc_config
);
3253 if (css_param
->update_flag
.macc_table
)
3254 atomisp_css_set_macc_table(asd
, &css_param
->macc_table
);
3256 if (css_param
->update_flag
.xnr_table
)
3257 atomisp_css_set_xnr_table(asd
, &css_param
->xnr_table
);
3259 if (css_param
->update_flag
.r_gamma_table
)
3260 atomisp_css_set_r_gamma_table(asd
, &css_param
->r_gamma_table
);
3262 if (css_param
->update_flag
.g_gamma_table
)
3263 atomisp_css_set_g_gamma_table(asd
, &css_param
->g_gamma_table
);
3265 if (css_param
->update_flag
.b_gamma_table
)
3266 atomisp_css_set_b_gamma_table(asd
, &css_param
->b_gamma_table
);
3268 if (css_param
->update_flag
.anr_thres
)
3269 atomisp_css_set_anr_thres(asd
, &css_param
->anr_thres
);
3271 if (css_param
->update_flag
.shading_table
)
3272 atomisp_css_set_shading_table(asd
, css_param
->shading_table
);
3274 if (css_param
->update_flag
.morph_table
&& asd
->params
.gdc_cac_en
)
3275 atomisp_css_set_morph_table(asd
, css_param
->morph_table
);
3277 if (css_param
->update_flag
.dvs2_coefs
) {
3278 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
3279 atomisp_css_get_dvs_grid_info(
3280 &asd
->params
.curr_grid_info
);
3282 if (dvs_grid_info
&& dvs_grid_info
->enable
)
3283 atomisp_css_set_dvs2_coefs(asd
, css_param
->dvs2_coeff
);
3286 if (css_param
->update_flag
.dvs_6axis_config
)
3287 atomisp_css_set_dvs_6axis(asd
, css_param
->dvs_6axis
);
3289 atomisp_css_set_isp_config_id(asd
, css_param
->isp_config_id
);
3291 * These configurations are on used by ISP1.x, not for ISP2.x,
3292 * so do not handle them. see comments of ia_css_isp_config.
3303 static unsigned int long copy_from_compatible(void *to
, const void *from
,
3304 unsigned long n
, bool from_user
)
3307 return copy_from_user(to
, from
, n
);
3309 memcpy(to
, from
, n
);
3313 int atomisp_cp_general_isp_parameters(struct atomisp_sub_device
*asd
,
3314 struct atomisp_parameters
*arg
,
3315 struct atomisp_css_params
*css_param
,
3318 struct atomisp_parameters
*cur_config
= &css_param
->update_flag
;
3320 if (!arg
|| !asd
|| !css_param
)
3323 if (arg
->wb_config
&& (from_user
|| !cur_config
->wb_config
)) {
3324 if (copy_from_compatible(&css_param
->wb_config
, arg
->wb_config
,
3325 sizeof(struct atomisp_css_wb_config
),
3328 css_param
->update_flag
.wb_config
=
3329 (struct atomisp_wb_config
*) &css_param
->wb_config
;
3332 if (arg
->ob_config
&& (from_user
|| !cur_config
->ob_config
)) {
3333 if (copy_from_compatible(&css_param
->ob_config
, arg
->ob_config
,
3334 sizeof(struct atomisp_css_ob_config
),
3337 css_param
->update_flag
.ob_config
=
3338 (struct atomisp_ob_config
*) &css_param
->ob_config
;
3341 if (arg
->dp_config
&& (from_user
|| !cur_config
->dp_config
)) {
3342 if (copy_from_compatible(&css_param
->dp_config
, arg
->dp_config
,
3343 sizeof(struct atomisp_css_dp_config
),
3346 css_param
->update_flag
.dp_config
=
3347 (struct atomisp_dp_config
*) &css_param
->dp_config
;
3350 if (asd
->run_mode
->val
!= ATOMISP_RUN_MODE_VIDEO
) {
3351 if (arg
->dz_config
&& (from_user
|| !cur_config
->dz_config
)) {
3352 if (copy_from_compatible(&css_param
->dz_config
,
3354 sizeof(struct atomisp_css_dz_config
),
3357 if (!atomisp_check_zoom_region(asd
,
3358 &css_param
->dz_config
)) {
3359 dev_err(asd
->isp
->dev
, "crop region error!");
3362 css_param
->update_flag
.dz_config
=
3363 (struct atomisp_dz_config
*)
3364 &css_param
->dz_config
;
3368 if (arg
->nr_config
&& (from_user
|| !cur_config
->nr_config
)) {
3369 if (copy_from_compatible(&css_param
->nr_config
, arg
->nr_config
,
3370 sizeof(struct atomisp_css_nr_config
),
3373 css_param
->update_flag
.nr_config
=
3374 (struct atomisp_nr_config
*) &css_param
->nr_config
;
3377 if (arg
->ee_config
&& (from_user
|| !cur_config
->ee_config
)) {
3378 if (copy_from_compatible(&css_param
->ee_config
, arg
->ee_config
,
3379 sizeof(struct atomisp_css_ee_config
),
3382 css_param
->update_flag
.ee_config
=
3383 (struct atomisp_ee_config
*) &css_param
->ee_config
;
3386 if (arg
->tnr_config
&& (from_user
|| !cur_config
->tnr_config
)) {
3387 if (copy_from_compatible(&css_param
->tnr_config
,
3389 sizeof(struct atomisp_css_tnr_config
),
3392 css_param
->update_flag
.tnr_config
=
3393 (struct atomisp_tnr_config
*)
3394 &css_param
->tnr_config
;
3397 if (arg
->a3a_config
&& (from_user
|| !cur_config
->a3a_config
)) {
3398 if (copy_from_compatible(&css_param
->s3a_config
,
3400 sizeof(struct atomisp_css_3a_config
),
3403 css_param
->update_flag
.a3a_config
=
3404 (struct atomisp_3a_config
*) &css_param
->s3a_config
;
3407 if (arg
->ctc_config
&& (from_user
|| !cur_config
->ctc_config
)) {
3408 if (copy_from_compatible(&css_param
->ctc_config
,
3410 sizeof(struct atomisp_css_ctc_config
),
3413 css_param
->update_flag
.ctc_config
=
3414 (struct atomisp_ctc_config
*)
3415 &css_param
->ctc_config
;
3418 if (arg
->cnr_config
&& (from_user
|| !cur_config
->cnr_config
)) {
3419 if (copy_from_compatible(&css_param
->cnr_config
,
3421 sizeof(struct atomisp_css_cnr_config
),
3424 css_param
->update_flag
.cnr_config
=
3425 (struct atomisp_cnr_config
*)
3426 &css_param
->cnr_config
;
3429 if (arg
->ecd_config
&& (from_user
|| !cur_config
->ecd_config
)) {
3430 if (copy_from_compatible(&css_param
->ecd_config
,
3432 sizeof(struct atomisp_css_ecd_config
),
3435 css_param
->update_flag
.ecd_config
=
3436 (struct atomisp_ecd_config
*)
3437 &css_param
->ecd_config
;
3440 if (arg
->ynr_config
&& (from_user
|| !cur_config
->ynr_config
)) {
3441 if (copy_from_compatible(&css_param
->ynr_config
,
3443 sizeof(struct atomisp_css_ynr_config
),
3446 css_param
->update_flag
.ynr_config
=
3447 (struct atomisp_ynr_config
*)
3448 &css_param
->ynr_config
;
3451 if (arg
->fc_config
&& (from_user
|| !cur_config
->fc_config
)) {
3452 if (copy_from_compatible(&css_param
->fc_config
,
3454 sizeof(struct atomisp_css_fc_config
),
3457 css_param
->update_flag
.fc_config
=
3458 (struct atomisp_fc_config
*) &css_param
->fc_config
;
3461 if (arg
->macc_config
&& (from_user
|| !cur_config
->macc_config
)) {
3462 if (copy_from_compatible(&css_param
->macc_config
,
3464 sizeof(struct atomisp_css_macc_config
),
3467 css_param
->update_flag
.macc_config
=
3468 (struct atomisp_macc_config
*)
3469 &css_param
->macc_config
;
3472 if (arg
->aa_config
&& (from_user
|| !cur_config
->aa_config
)) {
3473 if (copy_from_compatible(&css_param
->aa_config
, arg
->aa_config
,
3474 sizeof(struct atomisp_css_aa_config
),
3477 css_param
->update_flag
.aa_config
=
3478 (struct atomisp_aa_config
*) &css_param
->aa_config
;
3481 if (arg
->anr_config
&& (from_user
|| !cur_config
->anr_config
)) {
3482 if (copy_from_compatible(&css_param
->anr_config
,
3484 sizeof(struct atomisp_css_anr_config
),
3487 css_param
->update_flag
.anr_config
=
3488 (struct atomisp_anr_config
*)
3489 &css_param
->anr_config
;
3492 if (arg
->xnr_config
&& (from_user
|| !cur_config
->xnr_config
)) {
3493 if (copy_from_compatible(&css_param
->xnr_config
,
3495 sizeof(struct atomisp_css_xnr_config
),
3498 css_param
->update_flag
.xnr_config
=
3499 (struct atomisp_xnr_config
*)
3500 &css_param
->xnr_config
;
3503 if (arg
->yuv2rgb_cc_config
&&
3504 (from_user
|| !cur_config
->yuv2rgb_cc_config
)) {
3505 if (copy_from_compatible(&css_param
->yuv2rgb_cc_config
,
3506 arg
->yuv2rgb_cc_config
,
3507 sizeof(struct atomisp_css_cc_config
),
3510 css_param
->update_flag
.yuv2rgb_cc_config
=
3511 (struct atomisp_cc_config
*)
3512 &css_param
->yuv2rgb_cc_config
;
3515 if (arg
->rgb2yuv_cc_config
&&
3516 (from_user
|| !cur_config
->rgb2yuv_cc_config
)) {
3517 if (copy_from_compatible(&css_param
->rgb2yuv_cc_config
,
3518 arg
->rgb2yuv_cc_config
,
3519 sizeof(struct atomisp_css_cc_config
),
3522 css_param
->update_flag
.rgb2yuv_cc_config
=
3523 (struct atomisp_cc_config
*)
3524 &css_param
->rgb2yuv_cc_config
;
3527 if (arg
->macc_table
&& (from_user
|| !cur_config
->macc_table
)) {
3528 if (copy_from_compatible(&css_param
->macc_table
,
3530 sizeof(struct atomisp_css_macc_table
),
3533 css_param
->update_flag
.macc_table
=
3534 (struct atomisp_macc_table
*)
3535 &css_param
->macc_table
;
3538 if (arg
->xnr_table
&& (from_user
|| !cur_config
->xnr_table
)) {
3539 if (copy_from_compatible(&css_param
->xnr_table
,
3541 sizeof(struct atomisp_css_xnr_table
),
3544 css_param
->update_flag
.xnr_table
=
3545 (struct atomisp_xnr_table
*) &css_param
->xnr_table
;
3548 if (arg
->r_gamma_table
&& (from_user
|| !cur_config
->r_gamma_table
)) {
3549 if (copy_from_compatible(&css_param
->r_gamma_table
,
3551 sizeof(struct atomisp_css_rgb_gamma_table
),
3554 css_param
->update_flag
.r_gamma_table
=
3555 (struct atomisp_rgb_gamma_table
*)
3556 &css_param
->r_gamma_table
;
3559 if (arg
->g_gamma_table
&& (from_user
|| !cur_config
->g_gamma_table
)) {
3560 if (copy_from_compatible(&css_param
->g_gamma_table
,
3562 sizeof(struct atomisp_css_rgb_gamma_table
),
3565 css_param
->update_flag
.g_gamma_table
=
3566 (struct atomisp_rgb_gamma_table
*)
3567 &css_param
->g_gamma_table
;
3570 if (arg
->b_gamma_table
&& (from_user
|| !cur_config
->b_gamma_table
)) {
3571 if (copy_from_compatible(&css_param
->b_gamma_table
,
3573 sizeof(struct atomisp_css_rgb_gamma_table
),
3576 css_param
->update_flag
.b_gamma_table
=
3577 (struct atomisp_rgb_gamma_table
*)
3578 &css_param
->b_gamma_table
;
3581 if (arg
->anr_thres
&& (from_user
|| !cur_config
->anr_thres
)) {
3582 if (copy_from_compatible(&css_param
->anr_thres
, arg
->anr_thres
,
3583 sizeof(struct atomisp_css_anr_thres
),
3586 css_param
->update_flag
.anr_thres
=
3587 (struct atomisp_anr_thres
*) &css_param
->anr_thres
;
3591 css_param
->isp_config_id
= arg
->isp_config_id
;
3593 * These configurations are on used by ISP1.x, not for ISP2.x,
3594 * so do not handle them. see comments of ia_css_isp_config.
3606 int atomisp_cp_lsc_table(struct atomisp_sub_device
*asd
,
3607 struct atomisp_shading_table
*source_st
,
3608 struct atomisp_css_params
*css_param
,
3612 unsigned int len_table
;
3613 struct atomisp_css_shading_table
*shading_table
;
3614 struct atomisp_css_shading_table
*old_table
;
3616 struct atomisp_shading_table st
;
3625 if (!from_user
&& css_param
->update_flag
.shading_table
)
3629 if (copy_from_compatible(&st
, source_st
,
3630 sizeof(struct atomisp_shading_table
),
3632 dev_err(asd
->isp
->dev
, "copy shading table failed!");
3637 old_table
= css_param
->shading_table
;
3642 /* user config is to disable the shading table. */
3644 if (!source_st
->enable
) {
3648 /* Generate a minimum table with enable = 0. */
3649 shading_table
= atomisp_css_shading_table_alloc(1, 1);
3652 shading_table
->enable
= 0;
3656 /* Setting a new table. Validate first - all tables must be set */
3657 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3659 if (!source_st
->data
[i
])
3662 dev_err(asd
->isp
->dev
, "shading table validate failed");
3670 /* Shading table size per color */
3672 if (source_st
->width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
3673 source_st
->height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
)
3675 if (st
.width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
3676 st
.height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
) {
3677 dev_err(asd
->isp
->dev
, "shading table w/h validate failed!");
3685 shading_table
= atomisp_css_shading_table_alloc(source_st
->width
,
3690 shading_table
= atomisp_css_shading_table_alloc(st
.width
,
3692 if (!shading_table
) {
3693 dev_err(asd
->isp
->dev
, "shading table alloc failed!");
3699 len_table
= source_st
->width
* source_st
->height
* ATOMISP_SC_TYPE_SIZE
;
3701 len_table
= st
.width
* st
.height
* ATOMISP_SC_TYPE_SIZE
;
3703 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3704 if (copy_from_compatible(shading_table
->data
[i
],
3706 source_st
->data
[i
], len_table
, from_user
)) {
3708 st
.data
[i
], len_table
, from_user
)) {
3710 atomisp_css_shading_table_free(shading_table
);
3716 shading_table
->sensor_width
= source_st
->sensor_width
;
3717 shading_table
->sensor_height
= source_st
->sensor_height
;
3718 shading_table
->fraction_bits
= source_st
->fraction_bits
;
3719 shading_table
->enable
= source_st
->enable
;
3721 shading_table
->sensor_width
= st
.sensor_width
;
3722 shading_table
->sensor_height
= st
.sensor_height
;
3723 shading_table
->fraction_bits
= st
.fraction_bits
;
3724 shading_table
->enable
= st
.enable
;
3727 /* No need to update shading table if it is the same */
3728 if (old_table
!= NULL
&&
3729 old_table
->sensor_width
== shading_table
->sensor_width
&&
3730 old_table
->sensor_height
== shading_table
->sensor_height
&&
3731 old_table
->width
== shading_table
->width
&&
3732 old_table
->height
== shading_table
->height
&&
3733 old_table
->fraction_bits
== shading_table
->fraction_bits
&&
3734 old_table
->enable
== shading_table
->enable
) {
3735 bool data_is_same
= true;
3737 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3738 if (memcmp(shading_table
->data
[i
], old_table
->data
[i
],
3740 data_is_same
= false;
3746 atomisp_css_shading_table_free(shading_table
);
3752 /* set LSC to CSS */
3753 css_param
->shading_table
= shading_table
;
3754 css_param
->update_flag
.shading_table
=
3755 (struct atomisp_shading_table
*) shading_table
;
3756 asd
->params
.sc_en
= shading_table
!= NULL
;
3759 atomisp_css_shading_table_free(old_table
);
3764 int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device
*asd
,
3765 struct ia_css_dvs2_coefficients
*coefs
,
3766 struct atomisp_css_params
*css_param
,
3769 struct atomisp_css_dvs_grid_info
*cur
=
3770 atomisp_css_get_dvs_grid_info(&asd
->params
.curr_grid_info
);
3771 int dvs_hor_coef_bytes
, dvs_ver_coef_bytes
;
3773 struct ia_css_dvs2_coefficients dvs2_coefs
;
3779 if (!from_user
&& css_param
->update_flag
.dvs2_coefs
)
3783 if (sizeof(*cur
) != sizeof(coefs
->grid
) ||
3784 memcmp(&coefs
->grid
, cur
, sizeof(coefs
->grid
))) {
3786 if (copy_from_compatible(&dvs2_coefs
, coefs
,
3787 sizeof(struct ia_css_dvs2_coefficients
),
3789 dev_err(asd
->isp
->dev
, "copy dvs2 coef failed");
3793 if (sizeof(*cur
) != sizeof(dvs2_coefs
.grid
) ||
3794 memcmp(&dvs2_coefs
.grid
, cur
, sizeof(dvs2_coefs
.grid
))) {
3796 dev_err(asd
->isp
->dev
, "dvs grid mis-match!\n");
3797 /* If the grid info in the argument differs from the current
3798 grid info, we tell the caller to reset the grid size and
3804 if (coefs
->hor_coefs
.odd_real
== NULL
||
3805 coefs
->hor_coefs
.odd_imag
== NULL
||
3806 coefs
->hor_coefs
.even_real
== NULL
||
3807 coefs
->hor_coefs
.even_imag
== NULL
||
3808 coefs
->ver_coefs
.odd_real
== NULL
||
3809 coefs
->ver_coefs
.odd_imag
== NULL
||
3810 coefs
->ver_coefs
.even_real
== NULL
||
3811 coefs
->ver_coefs
.even_imag
== NULL
)
3813 if (dvs2_coefs
.hor_coefs
.odd_real
== NULL
||
3814 dvs2_coefs
.hor_coefs
.odd_imag
== NULL
||
3815 dvs2_coefs
.hor_coefs
.even_real
== NULL
||
3816 dvs2_coefs
.hor_coefs
.even_imag
== NULL
||
3817 dvs2_coefs
.ver_coefs
.odd_real
== NULL
||
3818 dvs2_coefs
.ver_coefs
.odd_imag
== NULL
||
3819 dvs2_coefs
.ver_coefs
.even_real
== NULL
||
3820 dvs2_coefs
.ver_coefs
.even_imag
== NULL
)
3824 if (!css_param
->dvs2_coeff
) {
3825 /* DIS coefficients. */
3826 css_param
->dvs2_coeff
= ia_css_dvs2_coefficients_allocate(cur
);
3827 if (!css_param
->dvs2_coeff
)
3831 dvs_hor_coef_bytes
= asd
->params
.dvs_hor_coef_bytes
;
3832 dvs_ver_coef_bytes
= asd
->params
.dvs_ver_coef_bytes
;
3833 if (copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.odd_real
,
3835 coefs
->hor_coefs
.odd_real
, dvs_hor_coef_bytes
, from_user
) ||
3837 dvs2_coefs
.hor_coefs
.odd_real
, dvs_hor_coef_bytes
, from_user
) ||
3839 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.odd_imag
,
3841 coefs
->hor_coefs
.odd_imag
, dvs_hor_coef_bytes
, from_user
) ||
3843 dvs2_coefs
.hor_coefs
.odd_imag
, dvs_hor_coef_bytes
, from_user
) ||
3845 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.even_real
,
3847 coefs
->hor_coefs
.even_real
, dvs_hor_coef_bytes
, from_user
) ||
3849 dvs2_coefs
.hor_coefs
.even_real
, dvs_hor_coef_bytes
, from_user
) ||
3851 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.even_imag
,
3853 coefs
->hor_coefs
.even_imag
, dvs_hor_coef_bytes
, from_user
) ||
3855 dvs2_coefs
.hor_coefs
.even_imag
, dvs_hor_coef_bytes
, from_user
) ||
3857 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.odd_real
,
3859 coefs
->ver_coefs
.odd_real
, dvs_ver_coef_bytes
, from_user
) ||
3861 dvs2_coefs
.ver_coefs
.odd_real
, dvs_ver_coef_bytes
, from_user
) ||
3863 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.odd_imag
,
3865 coefs
->ver_coefs
.odd_imag
, dvs_ver_coef_bytes
, from_user
) ||
3867 dvs2_coefs
.ver_coefs
.odd_imag
, dvs_ver_coef_bytes
, from_user
) ||
3869 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.even_real
,
3871 coefs
->ver_coefs
.even_real
, dvs_ver_coef_bytes
, from_user
) ||
3873 dvs2_coefs
.ver_coefs
.even_real
, dvs_ver_coef_bytes
, from_user
) ||
3875 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.even_imag
,
3877 coefs
->ver_coefs
.even_imag
, dvs_ver_coef_bytes
, from_user
)) {
3879 dvs2_coefs
.ver_coefs
.even_imag
, dvs_ver_coef_bytes
, from_user
)) {
3881 ia_css_dvs2_coefficients_free(css_param
->dvs2_coeff
);
3882 css_param
->dvs2_coeff
= NULL
;
3886 css_param
->update_flag
.dvs2_coefs
=
3887 (struct atomisp_dvs2_coefficients
*)css_param
->dvs2_coeff
;
3891 int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device
*asd
,
3892 struct atomisp_dvs_6axis_config
*source_6axis_config
,
3893 struct atomisp_css_params
*css_param
,
3896 struct atomisp_css_dvs_6axis_config
*dvs_6axis_config
;
3897 struct atomisp_css_dvs_6axis_config
*old_6axis_config
;
3899 struct atomisp_css_dvs_6axis_config t_6axis_config
;
3901 struct ia_css_stream
*stream
=
3902 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
;
3903 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
3904 atomisp_css_get_dvs_grid_info(&asd
->params
.curr_grid_info
);
3907 if (stream
== NULL
) {
3908 dev_err(asd
->isp
->dev
, "%s: internal error!", __func__
);
3912 if (!source_6axis_config
|| !dvs_grid_info
)
3915 if (!dvs_grid_info
->enable
)
3918 if (!from_user
&& css_param
->update_flag
.dvs_6axis_config
)
3921 /* check whether need to reallocate for 6 axis config */
3922 old_6axis_config
= css_param
->dvs_6axis
;
3923 dvs_6axis_config
= old_6axis_config
;
3926 if (copy_from_compatible(&t_6axis_config
, source_6axis_config
,
3927 sizeof(struct atomisp_dvs_6axis_config
),
3929 dev_err(asd
->isp
->dev
, "copy morph table failed!");
3934 if (old_6axis_config
&&
3936 (old_6axis_config
->width_y
!= source_6axis_config
->width_y
||
3937 old_6axis_config
->height_y
!= source_6axis_config
->height_y
||
3938 old_6axis_config
->width_uv
!= source_6axis_config
->width_uv
||
3939 old_6axis_config
->height_uv
!= source_6axis_config
->height_uv
)) {
3941 (old_6axis_config
->width_y
!= t_6axis_config
.width_y
||
3942 old_6axis_config
->height_y
!= t_6axis_config
.height_y
||
3943 old_6axis_config
->width_uv
!= t_6axis_config
.width_uv
||
3944 old_6axis_config
->height_uv
!= t_6axis_config
.height_uv
)) {
3946 ia_css_dvs2_6axis_config_free(css_param
->dvs_6axis
);
3947 css_param
->dvs_6axis
= NULL
;
3949 dvs_6axis_config
= ia_css_dvs2_6axis_config_allocate(stream
);
3950 if (!dvs_6axis_config
)
3952 } else if (!dvs_6axis_config
) {
3953 dvs_6axis_config
= ia_css_dvs2_6axis_config_allocate(stream
);
3954 if (!dvs_6axis_config
)
3959 dvs_6axis_config
->exp_id
= source_6axis_config
->exp_id
;
3961 dvs_6axis_config
->exp_id
= t_6axis_config
.exp_id
;
3964 if (copy_from_compatible(dvs_6axis_config
->xcoords_y
,
3966 source_6axis_config
->xcoords_y
,
3967 source_6axis_config
->width_y
*
3968 source_6axis_config
->height_y
*
3969 sizeof(*source_6axis_config
->xcoords_y
),
3971 t_6axis_config
.xcoords_y
,
3972 t_6axis_config
.width_y
*
3973 t_6axis_config
.height_y
*
3974 sizeof(*dvs_6axis_config
->xcoords_y
),
3978 if (copy_from_compatible(dvs_6axis_config
->ycoords_y
,
3980 source_6axis_config
->ycoords_y
,
3981 source_6axis_config
->width_y
*
3982 source_6axis_config
->height_y
*
3983 sizeof(*source_6axis_config
->ycoords_y
),
3985 t_6axis_config
.ycoords_y
,
3986 t_6axis_config
.width_y
*
3987 t_6axis_config
.height_y
*
3988 sizeof(*dvs_6axis_config
->ycoords_y
),
3992 if (copy_from_compatible(dvs_6axis_config
->xcoords_uv
,
3994 source_6axis_config
->xcoords_uv
,
3995 source_6axis_config
->width_uv
*
3996 source_6axis_config
->height_uv
*
3997 sizeof(*source_6axis_config
->xcoords_uv
),
3999 t_6axis_config
.xcoords_uv
,
4000 t_6axis_config
.width_uv
*
4001 t_6axis_config
.height_uv
*
4002 sizeof(*dvs_6axis_config
->xcoords_uv
),
4006 if (copy_from_compatible(dvs_6axis_config
->ycoords_uv
,
4008 source_6axis_config
->ycoords_uv
,
4009 source_6axis_config
->width_uv
*
4010 source_6axis_config
->height_uv
*
4011 sizeof(*source_6axis_config
->ycoords_uv
),
4013 t_6axis_config
.ycoords_uv
,
4014 t_6axis_config
.width_uv
*
4015 t_6axis_config
.height_uv
*
4016 sizeof(*dvs_6axis_config
->ycoords_uv
),
4021 css_param
->dvs_6axis
= dvs_6axis_config
;
4022 css_param
->update_flag
.dvs_6axis_config
=
4023 (struct atomisp_dvs_6axis_config
*) dvs_6axis_config
;
4027 if (dvs_6axis_config
)
4028 ia_css_dvs2_6axis_config_free(dvs_6axis_config
);
4032 int atomisp_cp_morph_table(struct atomisp_sub_device
*asd
,
4033 struct atomisp_morph_table
*source_morph_table
,
4034 struct atomisp_css_params
*css_param
,
4039 struct atomisp_css_morph_table
*morph_table
;
4041 struct atomisp_css_morph_table mtbl
;
4043 struct atomisp_css_morph_table
*old_morph_table
;
4045 if (!source_morph_table
)
4048 if (!from_user
&& css_param
->update_flag
.morph_table
)
4051 old_morph_table
= css_param
->morph_table
;
4054 if (copy_from_compatible(&mtbl
, source_morph_table
,
4055 sizeof(struct atomisp_morph_table
),
4057 dev_err(asd
->isp
->dev
, "copy morph table failed!");
4062 morph_table
= atomisp_css_morph_table_allocate(
4064 source_morph_table
->width
,
4065 source_morph_table
->height
);
4073 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
4074 if (copy_from_compatible(morph_table
->coordinates_x
[i
],
4075 source_morph_table
->coordinates_x
[i
],
4077 source_morph_table
->height
* source_morph_table
->width
*
4078 sizeof(*source_morph_table
->coordinates_x
[i
]),
4080 mtbl
.height
* mtbl
.width
*
4081 sizeof(*morph_table
->coordinates_x
[i
]),
4086 if (copy_from_compatible(morph_table
->coordinates_y
[i
],
4087 source_morph_table
->coordinates_y
[i
],
4089 source_morph_table
->height
* source_morph_table
->width
*
4090 sizeof(*source_morph_table
->coordinates_y
[i
]),
4092 mtbl
.height
* mtbl
.width
*
4093 sizeof(*morph_table
->coordinates_y
[i
]),
4099 css_param
->morph_table
= morph_table
;
4100 if (old_morph_table
)
4101 atomisp_css_morph_table_free(old_morph_table
);
4102 css_param
->update_flag
.morph_table
=
4103 (struct atomisp_morph_table
*) morph_table
;
4108 atomisp_css_morph_table_free(morph_table
);
4112 int atomisp_makeup_css_parameters(struct atomisp_sub_device
*asd
,
4113 struct atomisp_parameters
*arg
,
4114 struct atomisp_css_params
*css_param
)
4118 ret
= atomisp_cp_general_isp_parameters(asd
, arg
, css_param
, false);
4121 ret
= atomisp_cp_lsc_table(asd
, arg
->shading_table
, css_param
, false);
4124 ret
= atomisp_cp_morph_table(asd
, arg
->morph_table
, css_param
, false);
4127 ret
= atomisp_css_cp_dvs2_coefs(asd
,
4128 (struct ia_css_dvs2_coefficients
*) arg
->dvs2_coefs
,
4132 ret
= atomisp_cp_dvs_6axis_config(asd
, arg
->dvs_6axis_config
,
4137 void atomisp_free_css_parameters(struct atomisp_css_params
*css_param
)
4139 if (css_param
->dvs_6axis
) {
4140 ia_css_dvs2_6axis_config_free(css_param
->dvs_6axis
);
4141 css_param
->dvs_6axis
= NULL
;
4143 if (css_param
->dvs2_coeff
) {
4144 ia_css_dvs2_coefficients_free(css_param
->dvs2_coeff
);
4145 css_param
->dvs2_coeff
= NULL
;
4147 if (css_param
->shading_table
) {
4148 ia_css_shading_table_free(css_param
->shading_table
);
4149 css_param
->shading_table
= NULL
;
4151 if (css_param
->morph_table
) {
4152 ia_css_morph_table_free(css_param
->morph_table
);
4153 css_param
->morph_table
= NULL
;
4158 * Check parameter queue list and buffer queue list to find out if matched items
4159 * and then set parameter to CSS and enqueue buffer to CSS.
4160 * Of course, if the buffer in buffer waiting list is not bound to a per-frame
4161 * parameter, it will be enqueued into CSS as long as the per-frame setting
4162 * buffers before it get enqueued.
4164 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe
*pipe
)
4166 struct atomisp_sub_device
*asd
= pipe
->asd
;
4167 struct videobuf_buffer
*vb
= NULL
, *vb_tmp
;
4168 struct atomisp_css_params_with_list
*param
= NULL
, *param_tmp
;
4169 struct videobuf_vmalloc_memory
*vm_mem
= NULL
;
4170 unsigned long irqflags
;
4171 bool need_to_enqueue_buffer
= false;
4173 if (atomisp_is_vf_pipe(pipe
))
4177 * CSS/FW requires set parameter and enqueue buffer happen after ISP
4180 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
4183 if (list_empty(&pipe
->per_frame_params
) ||
4184 list_empty(&pipe
->buffers_waiting_for_param
))
4187 list_for_each_entry_safe(vb
, vb_tmp
,
4188 &pipe
->buffers_waiting_for_param
, queue
) {
4189 if (pipe
->frame_request_config_id
[vb
->i
]) {
4190 list_for_each_entry_safe(param
, param_tmp
,
4191 &pipe
->per_frame_params
, list
) {
4192 if (pipe
->frame_request_config_id
[vb
->i
] !=
4193 param
->params
.isp_config_id
)
4196 list_del(¶m
->list
);
4197 list_del(&vb
->queue
);
4199 * clear the request config id as the buffer
4200 * will be handled and enqueued into CSS soon
4202 pipe
->frame_request_config_id
[vb
->i
] = 0;
4203 pipe
->frame_params
[vb
->i
] = param
;
4210 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
4211 list_add_tail(&vb
->queue
, &pipe
->activeq
);
4212 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
4214 need_to_enqueue_buffer
= true;
4216 /* The is the end, stop further loop */
4220 list_del(&vb
->queue
);
4221 pipe
->frame_params
[vb
->i
] = NULL
;
4222 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
4223 list_add_tail(&vb
->queue
, &pipe
->activeq
);
4224 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
4225 need_to_enqueue_buffer
= true;
4229 if (need_to_enqueue_buffer
) {
4230 atomisp_qbuffers_to_css(asd
);
4232 if (!atomisp_is_wdt_running(asd
) && atomisp_buffers_queued(asd
))
4233 atomisp_wdt_start(asd
);
4235 if (atomisp_buffers_queued_pipe(pipe
)) {
4236 if (!atomisp_is_wdt_running(pipe
))
4237 atomisp_wdt_start(pipe
);
4239 atomisp_wdt_refresh_pipe(pipe
,
4240 ATOMISP_WDT_KEEP_CURRENT_DELAY
);
4247 * Function to configure ISP parameters
4249 int atomisp_set_parameters(struct video_device
*vdev
,
4250 struct atomisp_parameters
*arg
)
4252 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
4253 struct atomisp_sub_device
*asd
= pipe
->asd
;
4254 struct atomisp_css_params_with_list
*param
= NULL
;
4255 struct atomisp_css_params
*css_param
= &asd
->params
.css_param
;
4258 if (asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
== NULL
) {
4259 dev_err(asd
->isp
->dev
, "%s: internal error!\n", __func__
);
4263 dev_dbg(asd
->isp
->dev
, "%s: set parameter(per_frame_setting %d) for asd%d with isp_config_id %d of %s\n",
4264 __func__
, arg
->per_frame_setting
, asd
->index
,
4265 arg
->isp_config_id
, vdev
->name
);
4268 if (atomisp_is_vf_pipe(pipe
) && arg
->per_frame_setting
) {
4269 dev_err(asd
->isp
->dev
, "%s: vf pipe not support per_frame_setting",
4275 if (arg
->per_frame_setting
&& !atomisp_is_vf_pipe(pipe
)) {
4277 * Per-frame setting enabled, we allocate a new paramter
4278 * buffer to cache the parameters and only when frame buffers
4279 * are ready, the parameters will be set to CSS.
4280 * per-frame setting only works for the main output frame.
4282 param
= kvzalloc(sizeof(*param
), GFP_KERNEL
);
4284 dev_err(asd
->isp
->dev
, "%s: failed to alloc params buffer\n",
4288 css_param
= ¶m
->params
;
4291 ret
= atomisp_cp_general_isp_parameters(asd
, arg
, css_param
, true);
4293 goto apply_parameter_failed
;
4295 ret
= atomisp_cp_lsc_table(asd
, arg
->shading_table
, css_param
, true);
4297 goto apply_parameter_failed
;
4299 ret
= atomisp_cp_morph_table(asd
, arg
->morph_table
, css_param
, true);
4301 goto apply_parameter_failed
;
4303 ret
= atomisp_css_cp_dvs2_coefs(asd
,
4304 (struct ia_css_dvs2_coefficients
*) arg
->dvs2_coefs
,
4307 goto apply_parameter_failed
;
4309 ret
= atomisp_cp_dvs_6axis_config(asd
, arg
->dvs_6axis_config
,
4312 goto apply_parameter_failed
;
4314 if (!(arg
->per_frame_setting
&& !atomisp_is_vf_pipe(pipe
))) {
4315 /* indicate to CSS that we have parameters to be updated */
4316 asd
->params
.css_update_params_needed
= true;
4318 list_add_tail(¶m
->list
, &pipe
->per_frame_params
);
4319 atomisp_handle_parameter_and_buffer(pipe
);
4324 apply_parameter_failed
:
4326 atomisp_free_css_parameters(css_param
);
4334 * Function to set/get isp parameters to isp
4336 int atomisp_param(struct atomisp_sub_device
*asd
, int flag
,
4337 struct atomisp_parm
*config
)
4339 struct atomisp_device
*isp
= asd
->isp
;
4340 struct ia_css_pipe_config
*vp_cfg
=
4341 &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
4342 pipe_configs
[IA_CSS_PIPE_ID_VIDEO
];
4344 /* Read parameter for 3A binary info */
4346 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
4347 atomisp_css_get_dvs_grid_info(
4348 &asd
->params
.curr_grid_info
);
4350 if (&config
->info
== NULL
) {
4351 dev_err(isp
->dev
, "ERROR: NULL pointer in grid_info\n");
4354 atomisp_curr_user_grid_info(asd
, &config
->info
);
4356 /* We always return the resolution and stride even if there is
4357 * no valid metadata. This allows the caller to get the
4358 * information needed to allocate user-space buffers. */
4359 config
->metadata_config
.metadata_height
= asd
->
4360 stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream_info
.
4361 metadata_info
.resolution
.height
;
4362 config
->metadata_config
.metadata_stride
= asd
->
4363 stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream_info
.
4364 metadata_info
.stride
;
4366 /* update dvs grid info */
4368 memcpy(&config
->dvs_grid
,
4370 sizeof(struct atomisp_css_dvs_grid_info
));
4372 if (asd
->run_mode
->val
!= ATOMISP_RUN_MODE_VIDEO
) {
4373 config
->dvs_envelop
.width
= 0;
4374 config
->dvs_envelop
.height
= 0;
4378 /* update dvs envelop info */
4379 if (!asd
->continuous_mode
->val
) {
4380 config
->dvs_envelop
.width
= vp_cfg
->dvs_envelope
.width
;
4381 config
->dvs_envelop
.height
=
4382 vp_cfg
->dvs_envelope
.height
;
4384 unsigned int dvs_w
, dvs_h
, dvs_w_max
, dvs_h_max
;
4386 dvs_w
= vp_cfg
->bayer_ds_out_res
.width
-
4387 vp_cfg
->output_info
[0].res
.width
;
4388 dvs_h
= vp_cfg
->bayer_ds_out_res
.height
-
4389 vp_cfg
->output_info
[0].res
.height
;
4390 dvs_w_max
= rounddown(
4391 vp_cfg
->output_info
[0].res
.width
/ 5,
4392 ATOM_ISP_STEP_WIDTH
);
4393 dvs_h_max
= rounddown(
4394 vp_cfg
->output_info
[0].res
.height
/ 5,
4395 ATOM_ISP_STEP_HEIGHT
);
4397 config
->dvs_envelop
.width
= min(dvs_w
, dvs_w_max
);
4398 config
->dvs_envelop
.height
= min(dvs_h
, dvs_h_max
);
4404 memcpy(&asd
->params
.css_param
.wb_config
, &config
->wb_config
,
4405 sizeof(struct atomisp_css_wb_config
));
4406 memcpy(&asd
->params
.css_param
.ob_config
, &config
->ob_config
,
4407 sizeof(struct atomisp_css_ob_config
));
4408 memcpy(&asd
->params
.css_param
.dp_config
, &config
->dp_config
,
4409 sizeof(struct atomisp_css_dp_config
));
4410 memcpy(&asd
->params
.css_param
.de_config
, &config
->de_config
,
4411 sizeof(struct atomisp_css_de_config
));
4412 memcpy(&asd
->params
.css_param
.dz_config
, &config
->dz_config
,
4413 sizeof(struct atomisp_css_dz_config
));
4414 memcpy(&asd
->params
.css_param
.ce_config
, &config
->ce_config
,
4415 sizeof(struct atomisp_css_ce_config
));
4416 memcpy(&asd
->params
.css_param
.nr_config
, &config
->nr_config
,
4417 sizeof(struct atomisp_css_nr_config
));
4418 memcpy(&asd
->params
.css_param
.ee_config
, &config
->ee_config
,
4419 sizeof(struct atomisp_css_ee_config
));
4420 memcpy(&asd
->params
.css_param
.tnr_config
, &config
->tnr_config
,
4421 sizeof(struct atomisp_css_tnr_config
));
4423 if (asd
->params
.color_effect
== V4L2_COLORFX_NEGATIVE
) {
4424 asd
->params
.css_param
.cc_config
.matrix
[3] = -config
->cc_config
.matrix
[3];
4425 asd
->params
.css_param
.cc_config
.matrix
[4] = -config
->cc_config
.matrix
[4];
4426 asd
->params
.css_param
.cc_config
.matrix
[5] = -config
->cc_config
.matrix
[5];
4427 asd
->params
.css_param
.cc_config
.matrix
[6] = -config
->cc_config
.matrix
[6];
4428 asd
->params
.css_param
.cc_config
.matrix
[7] = -config
->cc_config
.matrix
[7];
4429 asd
->params
.css_param
.cc_config
.matrix
[8] = -config
->cc_config
.matrix
[8];
4432 if (asd
->params
.color_effect
!= V4L2_COLORFX_SEPIA
&&
4433 asd
->params
.color_effect
!= V4L2_COLORFX_BW
) {
4434 memcpy(&asd
->params
.css_param
.cc_config
, &config
->cc_config
,
4435 sizeof(struct atomisp_css_cc_config
));
4436 atomisp_css_set_cc_config(asd
, &asd
->params
.css_param
.cc_config
);
4439 atomisp_css_set_wb_config(asd
, &asd
->params
.css_param
.wb_config
);
4440 atomisp_css_set_ob_config(asd
, &asd
->params
.css_param
.ob_config
);
4441 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4442 atomisp_css_set_dz_config(asd
, &asd
->params
.css_param
.dz_config
);
4443 atomisp_css_set_ce_config(asd
, &asd
->params
.css_param
.ce_config
);
4444 atomisp_css_set_dp_config(asd
, &asd
->params
.css_param
.dp_config
);
4445 atomisp_css_set_nr_config(asd
, &asd
->params
.css_param
.nr_config
);
4446 atomisp_css_set_ee_config(asd
, &asd
->params
.css_param
.ee_config
);
4447 atomisp_css_set_tnr_config(asd
, &asd
->params
.css_param
.tnr_config
);
4448 asd
->params
.css_update_params_needed
= true;
4454 * Function to configure color effect of the image
4456 int atomisp_color_effect(struct atomisp_sub_device
*asd
, int flag
,
4459 struct atomisp_css_cc_config
*cc_config
= NULL
;
4460 struct atomisp_css_macc_table
*macc_table
= NULL
;
4461 struct atomisp_css_ctc_table
*ctc_table
= NULL
;
4463 struct v4l2_control control
;
4464 struct atomisp_device
*isp
= asd
->isp
;
4467 *effect
= asd
->params
.color_effect
;
4472 control
.id
= V4L2_CID_COLORFX
;
4473 control
.value
= *effect
;
4475 v4l2_s_ctrl(NULL
, isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
,
4478 * if set color effect to sensor successfully, return
4482 asd
->params
.color_effect
= (u32
)*effect
;
4486 if (*effect
== asd
->params
.color_effect
)
4490 * isp_subdev->params.macc_en should be set to false.
4492 asd
->params
.macc_en
= false;
4495 case V4L2_COLORFX_NONE
:
4496 macc_table
= &asd
->params
.css_param
.macc_table
;
4497 asd
->params
.macc_en
= true;
4499 case V4L2_COLORFX_SEPIA
:
4500 cc_config
= &sepia_cc_config
;
4502 case V4L2_COLORFX_NEGATIVE
:
4503 cc_config
= &nega_cc_config
;
4505 case V4L2_COLORFX_BW
:
4506 cc_config
= &mono_cc_config
;
4508 case V4L2_COLORFX_SKY_BLUE
:
4509 macc_table
= &blue_macc_table
;
4510 asd
->params
.macc_en
= true;
4512 case V4L2_COLORFX_GRASS_GREEN
:
4513 macc_table
= &green_macc_table
;
4514 asd
->params
.macc_en
= true;
4516 case V4L2_COLORFX_SKIN_WHITEN_LOW
:
4517 macc_table
= &skin_low_macc_table
;
4518 asd
->params
.macc_en
= true;
4520 case V4L2_COLORFX_SKIN_WHITEN
:
4521 macc_table
= &skin_medium_macc_table
;
4522 asd
->params
.macc_en
= true;
4524 case V4L2_COLORFX_SKIN_WHITEN_HIGH
:
4525 macc_table
= &skin_high_macc_table
;
4526 asd
->params
.macc_en
= true;
4528 case V4L2_COLORFX_VIVID
:
4529 ctc_table
= &vivid_ctc_table
;
4534 atomisp_update_capture_mode(asd
);
4537 atomisp_css_set_cc_config(asd
, cc_config
);
4539 atomisp_css_set_macc_table(asd
, macc_table
);
4541 atomisp_css_set_ctc_table(asd
, ctc_table
);
4542 asd
->params
.color_effect
= (u32
)*effect
;
4543 asd
->params
.css_update_params_needed
= true;
4548 * Function to configure bad pixel correction
4550 int atomisp_bad_pixel(struct atomisp_sub_device
*asd
, int flag
,
4555 *value
= asd
->params
.bad_pixel_en
;
4558 asd
->params
.bad_pixel_en
= !!*value
;
4564 * Function to configure bad pixel correction params
4566 int atomisp_bad_pixel_param(struct atomisp_sub_device
*asd
, int flag
,
4567 struct atomisp_dp_config
*config
)
4570 /* Get bad pixel from current setup */
4571 if (atomisp_css_get_dp_config(asd
, config
))
4574 /* Set bad pixel to isp parameters */
4575 memcpy(&asd
->params
.css_param
.dp_config
, config
,
4576 sizeof(asd
->params
.css_param
.dp_config
));
4577 atomisp_css_set_dp_config(asd
, &asd
->params
.css_param
.dp_config
);
4578 asd
->params
.css_update_params_needed
= true;
4585 * Function to enable/disable video image stablization
4587 int atomisp_video_stable(struct atomisp_sub_device
*asd
, int flag
,
4591 *value
= asd
->params
.video_dis_en
;
4593 asd
->params
.video_dis_en
= !!*value
;
4599 * Function to configure fixed pattern noise
4601 int atomisp_fixed_pattern(struct atomisp_sub_device
*asd
, int flag
,
4606 *value
= asd
->params
.fpn_en
;
4611 asd
->params
.fpn_en
= 0;
4615 /* Add function to get black from from sensor with shutter off */
4620 atomisp_bytesperline_to_padded_width(unsigned int bytesperline
,
4621 enum atomisp_css_frame_format format
)
4624 case CSS_FRAME_FORMAT_UYVY
:
4625 case CSS_FRAME_FORMAT_YUYV
:
4626 case CSS_FRAME_FORMAT_RAW
:
4627 case CSS_FRAME_FORMAT_RGB565
:
4628 return bytesperline
/2;
4629 case CSS_FRAME_FORMAT_RGBA888
:
4630 return bytesperline
/4;
4631 /* The following cases could be removed, but we leave them
4632 in to document the formats that are included. */
4633 case CSS_FRAME_FORMAT_NV11
:
4634 case CSS_FRAME_FORMAT_NV12
:
4635 case CSS_FRAME_FORMAT_NV16
:
4636 case CSS_FRAME_FORMAT_NV21
:
4637 case CSS_FRAME_FORMAT_NV61
:
4638 case CSS_FRAME_FORMAT_YV12
:
4639 case CSS_FRAME_FORMAT_YV16
:
4640 case CSS_FRAME_FORMAT_YUV420
:
4641 case CSS_FRAME_FORMAT_YUV420_16
:
4642 case CSS_FRAME_FORMAT_YUV422
:
4643 case CSS_FRAME_FORMAT_YUV422_16
:
4644 case CSS_FRAME_FORMAT_YUV444
:
4645 case CSS_FRAME_FORMAT_YUV_LINE
:
4646 case CSS_FRAME_FORMAT_PLANAR_RGB888
:
4647 case CSS_FRAME_FORMAT_QPLANE6
:
4648 case CSS_FRAME_FORMAT_BINARY_8
:
4650 return bytesperline
;
4655 atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer
*arg
,
4656 struct atomisp_css_frame
**result
)
4658 struct atomisp_css_frame
*res
= NULL
;
4659 unsigned int padded_width
;
4660 enum atomisp_css_frame_format sh_format
;
4661 char *tmp_buf
= NULL
;
4664 sh_format
= v4l2_fmt_to_sh_fmt(arg
->fmt
.pixelformat
);
4665 padded_width
= atomisp_bytesperline_to_padded_width(
4666 arg
->fmt
.bytesperline
, sh_format
);
4668 /* Note: the padded width on an atomisp_css_frame is in elements, not in
4669 bytes. The RAW frame we use here should always be a 16bit RAW
4670 frame. This is why we bytesperline/2 is equal to the padded with */
4671 if (atomisp_css_frame_allocate(&res
, arg
->fmt
.width
, arg
->fmt
.height
,
4672 sh_format
, padded_width
, 0)) {
4677 tmp_buf
= vmalloc(arg
->fmt
.sizeimage
);
4682 if (copy_from_user(tmp_buf
, (void __user __force
*)arg
->base
,
4683 arg
->fmt
.sizeimage
)) {
4688 if (hmm_store(res
->data
, tmp_buf
, arg
->fmt
.sizeimage
)) {
4695 atomisp_css_frame_free(res
);
4704 * Function to configure fixed pattern noise table
4706 int atomisp_fixed_pattern_table(struct atomisp_sub_device
*asd
,
4707 struct v4l2_framebuffer
*arg
)
4709 struct atomisp_css_frame
*raw_black_frame
= NULL
;
4715 ret
= atomisp_v4l2_framebuffer_to_css_frame(arg
, &raw_black_frame
);
4718 if (atomisp_css_set_black_frame(asd
, raw_black_frame
))
4721 atomisp_css_frame_free(raw_black_frame
);
4726 * Function to configure false color correction
4728 int atomisp_false_color(struct atomisp_sub_device
*asd
, int flag
,
4731 /* Get nr config from current setup */
4733 *value
= asd
->params
.false_color
;
4737 /* Set nr config to isp parameters */
4739 atomisp_css_set_default_de_config(asd
);
4741 asd
->params
.css_param
.de_config
.pixelnoise
= 0;
4742 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4744 asd
->params
.css_update_params_needed
= true;
4745 asd
->params
.false_color
= *value
;
4750 * Function to configure bad pixel correction params
4752 int atomisp_false_color_param(struct atomisp_sub_device
*asd
, int flag
,
4753 struct atomisp_de_config
*config
)
4756 /* Get false color from current setup */
4757 if (atomisp_css_get_de_config(asd
, config
))
4760 /* Set false color to isp parameters */
4761 memcpy(&asd
->params
.css_param
.de_config
, config
,
4762 sizeof(asd
->params
.css_param
.de_config
));
4763 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4764 asd
->params
.css_update_params_needed
= true;
4771 * Function to configure white balance params
4773 int atomisp_white_balance_param(struct atomisp_sub_device
*asd
, int flag
,
4774 struct atomisp_wb_config
*config
)
4777 /* Get white balance from current setup */
4778 if (atomisp_css_get_wb_config(asd
, config
))
4781 /* Set white balance to isp parameters */
4782 memcpy(&asd
->params
.css_param
.wb_config
, config
,
4783 sizeof(asd
->params
.css_param
.wb_config
));
4784 atomisp_css_set_wb_config(asd
, &asd
->params
.css_param
.wb_config
);
4785 asd
->params
.css_update_params_needed
= true;
4791 int atomisp_3a_config_param(struct atomisp_sub_device
*asd
, int flag
,
4792 struct atomisp_3a_config
*config
)
4794 struct atomisp_device
*isp
= asd
->isp
;
4796 dev_dbg(isp
->dev
, ">%s %d\n", __func__
, flag
);
4799 /* Get white balance from current setup */
4800 if (atomisp_css_get_3a_config(asd
, config
))
4803 /* Set white balance to isp parameters */
4804 memcpy(&asd
->params
.css_param
.s3a_config
, config
,
4805 sizeof(asd
->params
.css_param
.s3a_config
));
4806 atomisp_css_set_3a_config(asd
, &asd
->params
.css_param
.s3a_config
);
4807 asd
->params
.css_update_params_needed
= true;
4810 dev_dbg(isp
->dev
, "<%s %d\n", __func__
, flag
);
4815 * Function to setup digital zoom
4817 int atomisp_digital_zoom(struct atomisp_sub_device
*asd
, int flag
,
4821 struct atomisp_device
*isp
= asd
->isp
;
4823 unsigned int max_zoom
= MRFLD_MAX_ZOOM_FACTOR
;
4826 atomisp_css_get_zoom_factor(asd
, &zoom
);
4827 *value
= max_zoom
- zoom
;
4832 zoom
= max_zoom
- min_t(u32
, max_zoom
- 1, *value
);
4833 atomisp_css_set_zoom_factor(asd
, zoom
);
4835 dev_dbg(isp
->dev
, "%s, zoom: %d\n", __func__
, zoom
);
4836 asd
->params
.css_update_params_needed
= true;
4843 * Function to get sensor specific info for current resolution,
4844 * which will be used for auto exposure conversion.
4846 int atomisp_get_sensor_mode_data(struct atomisp_sub_device
*asd
,
4847 struct atomisp_sensor_mode_data
*config
)
4849 struct camera_mipi_info
*mipi_info
;
4850 struct atomisp_device
*isp
= asd
->isp
;
4852 mipi_info
= atomisp_to_sensor_mipi_info(
4853 isp
->inputs
[asd
->input_curr
].camera
);
4854 if (mipi_info
== NULL
)
4857 memcpy(config
, &mipi_info
->data
, sizeof(*config
));
4861 int atomisp_get_fmt(struct video_device
*vdev
, struct v4l2_format
*f
)
4863 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
4865 f
->fmt
.pix
= pipe
->pix
;
4870 static void __atomisp_update_stream_env(struct atomisp_sub_device
*asd
,
4871 uint16_t stream_index
, struct atomisp_input_stream_info
*stream_info
)
4875 #if defined(ISP2401_NEW_INPUT_SYSTEM)
4876 /* assign virtual channel id return from sensor driver query */
4877 asd
->stream_env
[stream_index
].ch_id
= stream_info
->ch_id
;
4879 asd
->stream_env
[stream_index
].isys_configs
= stream_info
->isys_configs
;
4880 for (i
= 0; i
< stream_info
->isys_configs
; i
++) {
4881 asd
->stream_env
[stream_index
].isys_info
[i
].input_format
=
4882 stream_info
->isys_info
[i
].input_format
;
4883 asd
->stream_env
[stream_index
].isys_info
[i
].width
=
4884 stream_info
->isys_info
[i
].width
;
4885 asd
->stream_env
[stream_index
].isys_info
[i
].height
=
4886 stream_info
->isys_info
[i
].height
;
4890 static void __atomisp_init_stream_info(uint16_t stream_index
,
4891 struct atomisp_input_stream_info
*stream_info
)
4895 stream_info
->enable
= 1;
4896 stream_info
->stream
= stream_index
;
4897 stream_info
->ch_id
= 0;
4898 stream_info
->isys_configs
= 0;
4899 for (i
= 0; i
< MAX_STREAMS_PER_CHANNEL
; i
++) {
4900 stream_info
->isys_info
[i
].input_format
= 0;
4901 stream_info
->isys_info
[i
].width
= 0;
4902 stream_info
->isys_info
[i
].height
= 0;
4906 /* This function looks up the closest available resolution. */
4907 int atomisp_try_fmt(struct video_device
*vdev
, struct v4l2_format
*f
,
4910 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
4911 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
4912 struct v4l2_subdev_pad_config pad_cfg
;
4913 struct v4l2_subdev_format format
= {
4914 .which
= V4L2_SUBDEV_FORMAT_TRY
,
4917 struct v4l2_mbus_framefmt
*snr_mbus_fmt
= &format
.format
;
4918 const struct atomisp_format_bridge
*fmt
;
4919 struct atomisp_input_stream_info
*stream_info
=
4920 (struct atomisp_input_stream_info
*)snr_mbus_fmt
->reserved
;
4921 uint16_t stream_index
;
4922 int source_pad
= atomisp_subdev_source_pad(vdev
);
4925 if (isp
->inputs
[asd
->input_curr
].camera
== NULL
)
4928 stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
4929 fmt
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
4931 dev_err(isp
->dev
, "unsupported pixelformat!\n");
4932 fmt
= atomisp_output_fmts
;
4936 if (f
->fmt
.pix
.width
<= 0 || f
->fmt
.pix
.height
<= 0)
4940 snr_mbus_fmt
->code
= fmt
->mbus_code
;
4941 snr_mbus_fmt
->width
= f
->fmt
.pix
.width
;
4942 snr_mbus_fmt
->height
= f
->fmt
.pix
.height
;
4944 __atomisp_init_stream_info(stream_index
, stream_info
);
4946 dev_dbg(isp
->dev
, "try_mbus_fmt: asking for %ux%u\n",
4947 snr_mbus_fmt
->width
, snr_mbus_fmt
->height
);
4949 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
4950 pad
, set_fmt
, &pad_cfg
, &format
);
4954 dev_dbg(isp
->dev
, "try_mbus_fmt: got %ux%u\n",
4955 snr_mbus_fmt
->width
, snr_mbus_fmt
->height
);
4957 fmt
= atomisp_get_format_bridge_from_mbus(snr_mbus_fmt
->code
);
4959 dev_err(isp
->dev
, "unknown sensor format 0x%8.8x\n",
4960 snr_mbus_fmt
->code
);
4964 f
->fmt
.pix
.pixelformat
= fmt
->pixelformat
;
4967 * If the format is jpeg or custom RAW, then the width and height will
4968 * not satisfy the normal atomisp requirements and no need to check
4969 * the below conditions. So just assign to what is being returned from
4970 * the sensor driver.
4972 if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_JPEG
||
4973 f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_CUSTOM_M10MO_RAW
) {
4974 f
->fmt
.pix
.width
= snr_mbus_fmt
->width
;
4975 f
->fmt
.pix
.height
= snr_mbus_fmt
->height
;
4979 if (snr_mbus_fmt
->width
< f
->fmt
.pix
.width
4980 && snr_mbus_fmt
->height
< f
->fmt
.pix
.height
) {
4981 f
->fmt
.pix
.width
= snr_mbus_fmt
->width
;
4982 f
->fmt
.pix
.height
= snr_mbus_fmt
->height
;
4983 /* Set the flag when resolution requested is
4984 * beyond the max value supported by sensor
4986 if (res_overflow
!= NULL
)
4987 *res_overflow
= true;
4991 f
->fmt
.pix
.width
= rounddown(
4992 clamp_t(u32
, f
->fmt
.pix
.width
, ATOM_ISP_MIN_WIDTH
,
4993 ATOM_ISP_MAX_WIDTH
), ATOM_ISP_STEP_WIDTH
);
4994 f
->fmt
.pix
.height
= rounddown(
4995 clamp_t(u32
, f
->fmt
.pix
.height
, ATOM_ISP_MIN_HEIGHT
,
4996 ATOM_ISP_MAX_HEIGHT
), ATOM_ISP_STEP_HEIGHT
);
5002 atomisp_try_fmt_file(struct atomisp_device
*isp
, struct v4l2_format
*f
)
5004 u32 width
= f
->fmt
.pix
.width
;
5005 u32 height
= f
->fmt
.pix
.height
;
5006 u32 pixelformat
= f
->fmt
.pix
.pixelformat
;
5007 enum v4l2_field field
= f
->fmt
.pix
.field
;
5010 if (!atomisp_get_format_bridge(pixelformat
)) {
5011 dev_err(isp
->dev
, "Wrong output pixelformat\n");
5015 depth
= get_pixel_depth(pixelformat
);
5017 if (field
== V4L2_FIELD_ANY
)
5018 field
= V4L2_FIELD_NONE
;
5019 else if (field
!= V4L2_FIELD_NONE
) {
5020 dev_err(isp
->dev
, "Wrong output field\n");
5024 f
->fmt
.pix
.field
= field
;
5025 f
->fmt
.pix
.width
= clamp_t(u32
,
5026 rounddown(width
, (u32
)ATOM_ISP_STEP_WIDTH
),
5027 ATOM_ISP_MIN_WIDTH
, ATOM_ISP_MAX_WIDTH
);
5028 f
->fmt
.pix
.height
= clamp_t(u32
, rounddown(height
,
5029 (u32
)ATOM_ISP_STEP_HEIGHT
),
5030 ATOM_ISP_MIN_HEIGHT
, ATOM_ISP_MAX_HEIGHT
);
5031 f
->fmt
.pix
.bytesperline
= (width
* depth
) >> 3;
5036 mipi_port_ID_t
__get_mipi_port(struct atomisp_device
*isp
,
5037 enum atomisp_camera_port port
)
5040 case ATOMISP_CAMERA_PORT_PRIMARY
:
5041 return MIPI_PORT0_ID
;
5042 case ATOMISP_CAMERA_PORT_SECONDARY
:
5043 return MIPI_PORT1_ID
;
5044 case ATOMISP_CAMERA_PORT_TERTIARY
:
5045 if (MIPI_PORT1_ID
+ 1 != N_MIPI_PORT_ID
)
5046 return MIPI_PORT1_ID
+ 1;
5047 /* go through down for else case */
5049 dev_err(isp
->dev
, "unsupported port: %d\n", port
);
5050 return MIPI_PORT0_ID
;
5054 static inline int atomisp_set_sensor_mipi_to_isp(
5055 struct atomisp_sub_device
*asd
,
5056 enum atomisp_input_stream_id stream_id
,
5057 struct camera_mipi_info
*mipi_info
)
5059 struct v4l2_control ctrl
;
5060 struct atomisp_device
*isp
= asd
->isp
;
5061 const struct atomisp_in_fmt_conv
*fc
;
5063 unsigned int input_format
, bayer_order
;
5065 ctrl
.id
= V4L2_CID_LINK_FREQ
;
5067 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
) == 0)
5068 mipi_freq
= ctrl
.value
;
5070 if (asd
->stream_env
[stream_id
].isys_configs
== 1) {
5072 asd
->stream_env
[stream_id
].isys_info
[0].input_format
;
5073 atomisp_css_isys_set_format(asd
, stream_id
,
5074 input_format
, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX
);
5075 } else if (asd
->stream_env
[stream_id
].isys_configs
== 2) {
5076 atomisp_css_isys_two_stream_cfg_update_stream1(
5078 asd
->stream_env
[stream_id
].isys_info
[0].input_format
,
5079 asd
->stream_env
[stream_id
].isys_info
[0].width
,
5080 asd
->stream_env
[stream_id
].isys_info
[0].height
);
5082 atomisp_css_isys_two_stream_cfg_update_stream2(
5084 asd
->stream_env
[stream_id
].isys_info
[1].input_format
,
5085 asd
->stream_env
[stream_id
].isys_info
[1].width
,
5086 asd
->stream_env
[stream_id
].isys_info
[1].height
);
5089 /* Compatibility for sensors which provide no media bus code
5090 * in s_mbus_framefmt() nor support pad formats. */
5091 if (mipi_info
->input_format
!= -1) {
5092 bayer_order
= mipi_info
->raw_bayer_order
;
5094 /* Input stream config is still needs configured */
5095 /* TODO: Check if this is necessary */
5096 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5097 mipi_info
->input_format
);
5100 input_format
= fc
->css_stream_fmt
;
5102 struct v4l2_mbus_framefmt
*sink
;
5103 sink
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5104 V4L2_SUBDEV_FORMAT_ACTIVE
,
5105 ATOMISP_SUBDEV_PAD_SINK
);
5106 fc
= atomisp_find_in_fmt_conv(sink
->code
);
5109 input_format
= fc
->css_stream_fmt
;
5110 bayer_order
= fc
->bayer_order
;
5113 atomisp_css_input_set_format(asd
, stream_id
, input_format
);
5114 atomisp_css_input_set_bayer_order(asd
, stream_id
, bayer_order
);
5116 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5117 mipi_info
->metadata_format
);
5120 input_format
= fc
->css_stream_fmt
;
5121 atomisp_css_input_configure_port(asd
,
5122 __get_mipi_port(asd
->isp
, mipi_info
->port
),
5123 mipi_info
->num_lanes
,
5126 mipi_info
->metadata_width
,
5127 mipi_info
->metadata_height
);
5131 static int __enable_continuous_mode(struct atomisp_sub_device
*asd
,
5134 struct atomisp_device
*isp
= asd
->isp
;
5137 "continuous mode %d, raw buffers %d, stop preview %d\n",
5138 enable
, asd
->continuous_raw_buffer_size
->val
,
5139 !asd
->continuous_viewfinder
->val
);
5141 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_PRIMARY
);
5143 atomisp_update_capture_mode(asd
);
5145 /* in case of ANR, force capture pipe to offline mode */
5146 atomisp_css_capture_enable_online(asd
, ATOMISP_INPUT_STREAM_GENERAL
,
5147 asd
->params
.low_light
? false : !enable
);
5148 atomisp_css_preview_enable_online(asd
, ATOMISP_INPUT_STREAM_GENERAL
,
5150 atomisp_css_enable_continuous(asd
, enable
);
5151 atomisp_css_enable_cvf(asd
, asd
->continuous_viewfinder
->val
);
5153 if (atomisp_css_continuous_set_num_raw_frames(asd
,
5154 asd
->continuous_raw_buffer_size
->val
)) {
5155 dev_err(isp
->dev
, "css_continuous_set_num_raw_frames failed\n");
5160 atomisp_css_enable_raw_binning(asd
, false);
5161 atomisp_css_input_set_two_pixels_per_clock(asd
, false);
5164 if (isp
->inputs
[asd
->input_curr
].type
!= FILE_INPUT
)
5165 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_SENSOR
);
5167 return atomisp_update_run_mode(asd
);
5170 int configure_pp_input_nop(struct atomisp_sub_device
*asd
,
5171 unsigned int width
, unsigned int height
)
5176 int configure_output_nop(struct atomisp_sub_device
*asd
,
5177 unsigned int width
, unsigned int height
,
5178 unsigned int min_width
,
5179 enum atomisp_css_frame_format sh_fmt
)
5184 int get_frame_info_nop(struct atomisp_sub_device
*asd
,
5185 struct atomisp_css_frame_info
*finfo
)
5191 * Resets CSS parameters that depend on input resolution.
5193 * Update params like CSS RAW binning, 2ppc mode and pp_input
5194 * which depend on input size, but are not automatically
5195 * handled in CSS when the input resolution is changed.
5197 static int css_input_resolution_changed(struct atomisp_sub_device
*asd
,
5198 struct v4l2_mbus_framefmt
*ffmt
)
5200 struct atomisp_metadata_buf
*md_buf
= NULL
, *_md_buf
;
5203 dev_dbg(asd
->isp
->dev
, "css_input_resolution_changed to %ux%u\n",
5204 ffmt
->width
, ffmt
->height
);
5206 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5207 atomisp_css_input_set_two_pixels_per_clock(asd
, false);
5209 atomisp_css_input_set_two_pixels_per_clock(asd
, true);
5211 if (asd
->continuous_mode
->val
) {
5212 /* Note for all checks: ffmt includes pad_w+pad_h */
5213 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
||
5214 (ffmt
->width
>= 2048 || ffmt
->height
>= 1536)) {
5216 * For preview pipe, enable only if resolution
5217 * is >= 3M for ISP2400.
5219 atomisp_css_enable_raw_binning(asd
, true);
5223 * If sensor input changed, which means metadata resolution changed
5224 * together. Release all metadata buffers here to let it re-allocated
5225 * next time in reqbufs.
5227 for (i
= 0; i
< ATOMISP_METADATA_TYPE_NUM
; i
++) {
5228 list_for_each_entry_safe(md_buf
, _md_buf
, &asd
->metadata
[i
],
5230 atomisp_css_free_metadata_buffer(md_buf
);
5231 list_del(&md_buf
->list
);
5238 * TODO: atomisp_css_preview_configure_pp_input() not
5239 * reset due to CSS bug tracked as PSI BZ 115124
5243 static int atomisp_set_fmt_to_isp(struct video_device
*vdev
,
5244 struct atomisp_css_frame_info
*output_info
,
5245 struct atomisp_css_frame_info
*raw_output_info
,
5246 struct v4l2_pix_format
*pix
,
5247 unsigned int source_pad
)
5249 struct camera_mipi_info
*mipi_info
;
5250 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
5251 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
5252 const struct atomisp_format_bridge
*format
;
5253 struct v4l2_rect
*isp_sink_crop
;
5254 enum atomisp_css_pipe_id pipe_id
;
5255 struct v4l2_subdev_fh fh
;
5256 int (*configure_output
)(struct atomisp_sub_device
*asd
,
5257 unsigned int width
, unsigned int height
,
5258 unsigned int min_width
,
5259 enum atomisp_css_frame_format sh_fmt
) =
5260 configure_output_nop
;
5261 int (*get_frame_info
)(struct atomisp_sub_device
*asd
,
5262 struct atomisp_css_frame_info
*finfo
) =
5264 int (*configure_pp_input
)(struct atomisp_sub_device
*asd
,
5265 unsigned int width
, unsigned int height
) =
5266 configure_pp_input_nop
;
5267 uint16_t stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
5268 const struct atomisp_in_fmt_conv
*fc
;
5271 v4l2_fh_init(&fh
.vfh
, vdev
);
5273 isp_sink_crop
= atomisp_subdev_get_rect(
5274 &asd
->subdev
, NULL
, V4L2_SUBDEV_FORMAT_ACTIVE
,
5275 ATOMISP_SUBDEV_PAD_SINK
, V4L2_SEL_TGT_CROP
);
5277 format
= atomisp_get_format_bridge(pix
->pixelformat
);
5281 if (isp
->inputs
[asd
->input_curr
].type
!= TEST_PATTERN
&&
5282 isp
->inputs
[asd
->input_curr
].type
!= FILE_INPUT
) {
5283 mipi_info
= atomisp_to_sensor_mipi_info(
5284 isp
->inputs
[asd
->input_curr
].camera
);
5286 dev_err(isp
->dev
, "mipi_info is NULL\n");
5289 if (atomisp_set_sensor_mipi_to_isp(asd
, stream_index
,
5292 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5293 mipi_info
->input_format
);
5295 fc
= atomisp_find_in_fmt_conv(
5296 atomisp_subdev_get_ffmt(&asd
->subdev
,
5297 NULL
, V4L2_SUBDEV_FORMAT_ACTIVE
,
5298 ATOMISP_SUBDEV_PAD_SINK
)->code
);
5301 if (format
->sh_fmt
== CSS_FRAME_FORMAT_RAW
&&
5302 raw_output_format_match_input(fc
->css_stream_fmt
,
5308 * Configure viewfinder also when vfpp is disabled: the
5309 * CSS still requires viewfinder configuration.
5311 if (asd
->fmt_auto
->val
||
5312 asd
->vfpp
->val
!= ATOMISP_VFPP_ENABLE
) {
5313 struct v4l2_rect vf_size
= {0};
5314 struct v4l2_mbus_framefmt vf_ffmt
= {0};
5316 if (pix
->width
< 640 || pix
->height
< 480) {
5317 vf_size
.width
= pix
->width
;
5318 vf_size
.height
= pix
->height
;
5320 vf_size
.width
= 640;
5321 vf_size
.height
= 480;
5324 /* FIXME: proper format name for this one. See
5325 atomisp_output_fmts[] in atomisp_v4l2.c */
5326 vf_ffmt
.code
= V4L2_MBUS_FMT_CUSTOM_YUV420
;
5328 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
5329 V4L2_SUBDEV_FORMAT_ACTIVE
,
5330 ATOMISP_SUBDEV_PAD_SOURCE_VF
,
5331 V4L2_SEL_TGT_COMPOSE
, 0, &vf_size
);
5332 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5333 V4L2_SUBDEV_FORMAT_ACTIVE
,
5334 ATOMISP_SUBDEV_PAD_SOURCE_VF
, &vf_ffmt
);
5335 asd
->video_out_vf
.sh_fmt
= CSS_FRAME_FORMAT_NV12
;
5337 if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
) {
5338 atomisp_css_video_configure_viewfinder(asd
,
5339 vf_size
.width
, vf_size
.height
, 0,
5340 asd
->video_out_vf
.sh_fmt
);
5341 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5342 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5343 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
)
5344 atomisp_css_video_configure_viewfinder(asd
,
5345 vf_size
.width
, vf_size
.height
, 0,
5346 asd
->video_out_vf
.sh_fmt
);
5348 atomisp_css_capture_configure_viewfinder(asd
,
5349 vf_size
.width
, vf_size
.height
, 0,
5350 asd
->video_out_vf
.sh_fmt
);
5351 } else if (source_pad
!= ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5352 asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_LOWLAT
) {
5353 atomisp_css_capture_configure_viewfinder(asd
,
5354 vf_size
.width
, vf_size
.height
, 0,
5355 asd
->video_out_vf
.sh_fmt
);
5359 if (asd
->continuous_mode
->val
) {
5360 ret
= __enable_continuous_mode(asd
, true);
5365 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_SENSOR
);
5366 atomisp_css_disable_vf_pp(asd
,
5367 asd
->vfpp
->val
!= ATOMISP_VFPP_ENABLE
);
5369 /* ISP2401 new input system need to use copy pipe */
5370 if (asd
->copy_mode
) {
5371 pipe_id
= CSS_PIPE_ID_COPY
;
5372 atomisp_css_capture_enable_online(asd
, stream_index
, false);
5373 } else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
) {
5374 /* video same in continuouscapture and online modes */
5375 configure_output
= atomisp_css_video_configure_output
;
5376 get_frame_info
= atomisp_css_video_get_output_frame_info
;
5377 pipe_id
= CSS_PIPE_ID_VIDEO
;
5378 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5379 if (!asd
->continuous_mode
->val
) {
5380 configure_output
= atomisp_css_video_configure_output
;
5382 atomisp_css_video_get_output_frame_info
;
5383 pipe_id
= CSS_PIPE_ID_VIDEO
;
5385 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5386 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
) {
5388 atomisp_css_video_configure_output
;
5390 atomisp_css_video_get_output_frame_info
;
5391 configure_pp_input
=
5392 atomisp_css_video_configure_pp_input
;
5393 pipe_id
= CSS_PIPE_ID_VIDEO
;
5396 atomisp_css_capture_configure_output
;
5398 atomisp_css_capture_get_output_frame_info
;
5399 configure_pp_input
=
5400 atomisp_css_capture_configure_pp_input
;
5401 pipe_id
= CSS_PIPE_ID_CAPTURE
;
5403 atomisp_update_capture_mode(asd
);
5404 atomisp_css_capture_enable_online(asd
, stream_index
, false);
5407 } else if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
) {
5408 configure_output
= atomisp_css_preview_configure_output
;
5409 get_frame_info
= atomisp_css_preview_get_output_frame_info
;
5410 configure_pp_input
= atomisp_css_preview_configure_pp_input
;
5411 pipe_id
= CSS_PIPE_ID_PREVIEW
;
5413 /* CSS doesn't support low light mode on SOC cameras, so disable
5414 * it. FIXME: if this is done elsewhere, it gives corrupted
5415 * colors into thumbnail image.
5417 if (isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
)
5418 asd
->params
.low_light
= false;
5420 if (format
->sh_fmt
== CSS_FRAME_FORMAT_RAW
) {
5421 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_RAW
);
5422 atomisp_css_enable_dz(asd
, false);
5424 atomisp_update_capture_mode(asd
);
5427 if (!asd
->continuous_mode
->val
)
5428 /* in case of ANR, force capture pipe to offline mode */
5429 atomisp_css_capture_enable_online(asd
, stream_index
,
5430 asd
->params
.low_light
?
5431 false : asd
->params
.online_process
);
5433 configure_output
= atomisp_css_capture_configure_output
;
5434 get_frame_info
= atomisp_css_capture_get_output_frame_info
;
5435 configure_pp_input
= atomisp_css_capture_configure_pp_input
;
5436 pipe_id
= CSS_PIPE_ID_CAPTURE
;
5438 if (!asd
->params
.online_process
&&
5439 !asd
->continuous_mode
->val
) {
5440 ret
= atomisp_css_capture_get_output_raw_frame_info(asd
,
5445 if (!asd
->continuous_mode
->val
&& asd
->run_mode
->val
5446 != ATOMISP_RUN_MODE_STILL_CAPTURE
) {
5448 "Need to set the running mode first\n");
5449 asd
->run_mode
->val
= ATOMISP_RUN_MODE_STILL_CAPTURE
;
5454 * to SOC camera, use yuvpp pipe.
5456 if (ATOMISP_USE_YUVPP(asd
))
5457 pipe_id
= CSS_PIPE_ID_YUVPP
;
5460 ret
= atomisp_css_copy_configure_output(asd
, stream_index
,
5461 pix
->width
, pix
->height
,
5462 format
->planar
? pix
->bytesperline
:
5463 pix
->bytesperline
* 8 / format
->depth
,
5466 ret
= configure_output(asd
, pix
->width
, pix
->height
,
5467 format
->planar
? pix
->bytesperline
:
5468 pix
->bytesperline
* 8 / format
->depth
,
5471 dev_err(isp
->dev
, "configure_output %ux%u, format %8.8x\n",
5472 pix
->width
, pix
->height
, format
->sh_fmt
);
5476 if (asd
->continuous_mode
->val
&&
5477 (configure_pp_input
== atomisp_css_preview_configure_pp_input
||
5478 configure_pp_input
== atomisp_css_video_configure_pp_input
)) {
5479 /* for isp 2.2, configure pp input is available for continuous
5481 ret
= configure_pp_input(asd
, isp_sink_crop
->width
,
5482 isp_sink_crop
->height
);
5484 dev_err(isp
->dev
, "configure_pp_input %ux%u\n",
5485 isp_sink_crop
->width
,
5486 isp_sink_crop
->height
);
5490 ret
= configure_pp_input(asd
, isp_sink_crop
->width
,
5491 isp_sink_crop
->height
);
5493 dev_err(isp
->dev
, "configure_pp_input %ux%u\n",
5494 isp_sink_crop
->width
, isp_sink_crop
->height
);
5499 ret
= atomisp_css_copy_get_output_frame_info(asd
, stream_index
,
5502 ret
= get_frame_info(asd
, output_info
);
5504 dev_err(isp
->dev
, "get_frame_info %ux%u (padded to %u)\n",
5505 pix
->width
, pix
->height
, pix
->bytesperline
);
5509 atomisp_update_grid_info(asd
, pipe_id
, source_pad
);
5511 /* Free the raw_dump buffer first */
5512 atomisp_css_frame_free(asd
->raw_output_frame
);
5513 asd
->raw_output_frame
= NULL
;
5515 if (!asd
->continuous_mode
->val
&&
5516 !asd
->params
.online_process
&& !isp
->sw_contex
.file_input
&&
5517 atomisp_css_frame_allocate_from_info(&asd
->raw_output_frame
,
5524 static void atomisp_get_dis_envelop(struct atomisp_sub_device
*asd
,
5525 unsigned int width
, unsigned int height
,
5526 unsigned int *dvs_env_w
, unsigned int *dvs_env_h
)
5528 struct atomisp_device
*isp
= asd
->isp
;
5530 /* if subdev type is SOC camera,we do not need to set DVS */
5531 if (isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
)
5532 asd
->params
.video_dis_en
= 0;
5534 if (asd
->params
.video_dis_en
&&
5535 asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5536 /* envelope is 20% of the output resolution */
5538 * dvs envelope cannot be round up.
5539 * it would cause ISP timeout and color switch issue
5541 *dvs_env_w
= rounddown(width
/ 5, ATOM_ISP_STEP_WIDTH
);
5542 *dvs_env_h
= rounddown(height
/ 5, ATOM_ISP_STEP_HEIGHT
);
5545 asd
->params
.dis_proj_data_valid
= false;
5546 asd
->params
.css_update_params_needed
= true;
5549 static void atomisp_check_copy_mode(struct atomisp_sub_device
*asd
,
5550 int source_pad
, struct v4l2_format
*f
)
5552 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5553 struct v4l2_mbus_framefmt
*sink
, *src
;
5555 sink
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5556 V4L2_SUBDEV_FORMAT_ACTIVE
, ATOMISP_SUBDEV_PAD_SINK
);
5557 src
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5558 V4L2_SUBDEV_FORMAT_ACTIVE
, source_pad
);
5560 if ((sink
->code
== src
->code
&&
5561 sink
->width
== f
->fmt
.pix
.width
&&
5562 sink
->height
== f
->fmt
.pix
.height
) ||
5563 ((asd
->isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
) &&
5564 (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
5565 sensor
[asd
->sensor_curr
].stream_num
> 1)))
5566 asd
->copy_mode
= true;
5569 /* Only used for the new input system */
5570 asd
->copy_mode
= false;
5572 dev_dbg(asd
->isp
->dev
, "copy_mode: %d\n", asd
->copy_mode
);
5576 static int atomisp_set_fmt_to_snr(struct video_device
*vdev
,
5577 struct v4l2_format
*f
, unsigned int pixelformat
,
5578 unsigned int padding_w
, unsigned int padding_h
,
5579 unsigned int dvs_env_w
, unsigned int dvs_env_h
)
5581 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
5582 const struct atomisp_format_bridge
*format
;
5583 struct v4l2_subdev_pad_config pad_cfg
;
5584 struct v4l2_subdev_format vformat
= {
5585 .which
= V4L2_SUBDEV_FORMAT_TRY
,
5587 struct v4l2_mbus_framefmt
*ffmt
= &vformat
.format
;
5588 struct v4l2_mbus_framefmt
*req_ffmt
;
5589 struct atomisp_device
*isp
= asd
->isp
;
5590 struct atomisp_input_stream_info
*stream_info
=
5591 (struct atomisp_input_stream_info
*)ffmt
->reserved
;
5592 uint16_t stream_index
= ATOMISP_INPUT_STREAM_GENERAL
;
5593 int source_pad
= atomisp_subdev_source_pad(vdev
);
5594 struct v4l2_subdev_fh fh
;
5597 v4l2_fh_init(&fh
.vfh
, vdev
);
5599 stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
5601 format
= atomisp_get_format_bridge(pixelformat
);
5605 v4l2_fill_mbus_format(ffmt
, &f
->fmt
.pix
, format
->mbus_code
);
5606 ffmt
->height
+= padding_h
+ dvs_env_h
;
5607 ffmt
->width
+= padding_w
+ dvs_env_w
;
5609 dev_dbg(isp
->dev
, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n",
5610 ffmt
->width
, ffmt
->height
, padding_w
, padding_h
,
5611 dvs_env_w
, dvs_env_h
);
5613 __atomisp_init_stream_info(stream_index
, stream_info
);
5617 /* Disable dvs if resolution can't be supported by sensor */
5618 if (asd
->params
.video_dis_en
&&
5619 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
) {
5620 vformat
.which
= V4L2_SUBDEV_FORMAT_TRY
;
5621 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
5622 pad
, set_fmt
, &pad_cfg
, &vformat
);
5625 if (ffmt
->width
< req_ffmt
->width
||
5626 ffmt
->height
< req_ffmt
->height
) {
5627 req_ffmt
->height
-= dvs_env_h
;
5628 req_ffmt
->width
-= dvs_env_w
;
5631 "can not enable video dis due to sensor limitation.");
5632 asd
->params
.video_dis_en
= 0;
5635 dev_dbg(isp
->dev
, "sensor width: %d, height: %d\n",
5636 ffmt
->width
, ffmt
->height
);
5637 vformat
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
5638 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
, pad
,
5639 set_fmt
, NULL
, &vformat
);
5643 __atomisp_update_stream_env(asd
, stream_index
, stream_info
);
5645 dev_dbg(isp
->dev
, "sensor width: %d, height: %d\n",
5646 ffmt
->width
, ffmt
->height
);
5648 if (ffmt
->width
< ATOM_ISP_STEP_WIDTH
||
5649 ffmt
->height
< ATOM_ISP_STEP_HEIGHT
)
5652 if (asd
->params
.video_dis_en
&&
5653 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
&&
5654 (ffmt
->width
< req_ffmt
->width
|| ffmt
->height
< req_ffmt
->height
)) {
5656 "can not enable video dis due to sensor limitation.");
5657 asd
->params
.video_dis_en
= 0;
5660 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5661 V4L2_SUBDEV_FORMAT_ACTIVE
,
5662 ATOMISP_SUBDEV_PAD_SINK
, ffmt
);
5664 return css_input_resolution_changed(asd
, ffmt
);
5667 int atomisp_set_fmt(struct video_device
*vdev
, struct v4l2_format
*f
)
5669 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
5670 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
5671 struct atomisp_sub_device
*asd
= pipe
->asd
;
5672 const struct atomisp_format_bridge
*format_bridge
;
5673 const struct atomisp_format_bridge
*snr_format_bridge
;
5674 struct atomisp_css_frame_info output_info
, raw_output_info
;
5675 struct v4l2_format snr_fmt
= *f
;
5676 struct v4l2_format backup_fmt
= *f
, s_fmt
= *f
;
5677 unsigned int dvs_env_w
= 0, dvs_env_h
= 0;
5678 unsigned int padding_w
= pad_w
, padding_h
= pad_h
;
5679 bool res_overflow
= false, crop_needs_override
= false;
5680 struct v4l2_mbus_framefmt isp_sink_fmt
;
5681 struct v4l2_mbus_framefmt isp_source_fmt
= {0};
5682 struct v4l2_rect isp_sink_crop
;
5683 uint16_t source_pad
= atomisp_subdev_source_pad(vdev
);
5684 struct v4l2_subdev_fh fh
;
5688 "setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n",
5689 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
, source_pad
,
5690 asd
->index
, f
->fmt
.pix
.bytesperline
);
5692 if (source_pad
>= ATOMISP_SUBDEV_PADS_NUM
)
5695 if (asd
->streaming
== ATOMISP_DEVICE_STREAMING_ENABLED
) {
5696 dev_warn(isp
->dev
, "ISP does not support set format while at streaming!\n");
5700 v4l2_fh_init(&fh
.vfh
, vdev
);
5702 format_bridge
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
5703 if (format_bridge
== NULL
)
5706 pipe
->sh_fmt
= format_bridge
->sh_fmt
;
5707 pipe
->pix
.pixelformat
= f
->fmt
.pix
.pixelformat
;
5709 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VF
||
5710 (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5711 && asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)) {
5712 if (asd
->fmt_auto
->val
) {
5713 struct v4l2_rect
*capture_comp
;
5714 struct v4l2_rect r
= {0};
5716 r
.width
= f
->fmt
.pix
.width
;
5717 r
.height
= f
->fmt
.pix
.height
;
5719 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
)
5720 capture_comp
= atomisp_subdev_get_rect(
5722 V4L2_SUBDEV_FORMAT_ACTIVE
,
5723 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
,
5724 V4L2_SEL_TGT_COMPOSE
);
5726 capture_comp
= atomisp_subdev_get_rect(
5728 V4L2_SUBDEV_FORMAT_ACTIVE
,
5729 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
,
5730 V4L2_SEL_TGT_COMPOSE
);
5732 if (capture_comp
->width
< r
.width
5733 || capture_comp
->height
< r
.height
) {
5734 r
.width
= capture_comp
->width
;
5735 r
.height
= capture_comp
->height
;
5738 atomisp_subdev_set_selection(
5739 &asd
->subdev
, fh
.pad
,
5740 V4L2_SUBDEV_FORMAT_ACTIVE
, source_pad
,
5741 V4L2_SEL_TGT_COMPOSE
, 0, &r
);
5743 f
->fmt
.pix
.width
= r
.width
;
5744 f
->fmt
.pix
.height
= r
.height
;
5747 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
&&
5748 (asd
->isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
) &&
5749 (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
5750 sensor
[asd
->sensor_curr
].stream_num
> 1)) {
5751 /* For M10MO outputing YUV preview images. */
5752 uint16_t video_index
=
5753 atomisp_source_pad_to_stream_id(asd
,
5754 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
);
5756 ret
= atomisp_css_copy_get_output_frame_info(asd
,
5757 video_index
, &output_info
);
5760 "copy_get_output_frame_info ret %i", ret
);
5763 if (!asd
->yuvpp_mode
) {
5765 * If viewfinder was configured into copy_mode,
5766 * we switch to using yuvpp pipe instead.
5768 asd
->yuvpp_mode
= true;
5769 ret
= atomisp_css_copy_configure_output(
5770 asd
, video_index
, 0, 0, 0, 0);
5773 "failed to disable copy pipe");
5776 ret
= atomisp_css_yuvpp_configure_output(
5778 output_info
.res
.width
,
5779 output_info
.res
.height
,
5780 output_info
.padded_width
,
5781 output_info
.format
);
5784 "failed to set up yuvpp pipe\n");
5787 atomisp_css_video_enable_online(asd
, false);
5788 atomisp_css_preview_enable_online(asd
,
5789 ATOMISP_INPUT_STREAM_GENERAL
, false);
5791 atomisp_css_yuvpp_configure_viewfinder(asd
, video_index
,
5792 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5793 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5794 : f
->fmt
.pix
.bytesperline
* 8
5795 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5796 atomisp_css_yuvpp_get_viewfinder_frame_info(
5797 asd
, video_index
, &output_info
);
5798 } else if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
) {
5799 atomisp_css_video_configure_viewfinder(asd
,
5800 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5801 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5802 : f
->fmt
.pix
.bytesperline
* 8
5803 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5804 atomisp_css_video_get_viewfinder_frame_info(asd
,
5806 asd
->copy_mode
= false;
5808 atomisp_css_capture_configure_viewfinder(asd
,
5809 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5810 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5811 : f
->fmt
.pix
.bytesperline
* 8
5812 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5813 atomisp_css_capture_get_viewfinder_frame_info(asd
,
5815 asd
->copy_mode
= false;
5821 * Check whether main resolution configured smaller
5822 * than snapshot resolution. If so, force main resolution
5823 * to be the same as snapshot resolution
5825 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
) {
5826 struct v4l2_rect
*r
;
5828 r
= atomisp_subdev_get_rect(
5830 V4L2_SUBDEV_FORMAT_ACTIVE
,
5831 ATOMISP_SUBDEV_PAD_SOURCE_VF
, V4L2_SEL_TGT_COMPOSE
);
5833 if (r
->width
&& r
->height
5834 && (r
->width
> f
->fmt
.pix
.width
5835 || r
->height
> f
->fmt
.pix
.height
))
5837 "Main Resolution config smaller then Vf Resolution. Force to be equal with Vf Resolution.");
5840 /* Pipeline configuration done through subdevs. Bail out now. */
5841 if (!asd
->fmt_auto
->val
)
5842 goto set_fmt_to_isp
;
5844 /* get sensor resolution and format */
5845 ret
= atomisp_try_fmt(vdev
, &snr_fmt
, &res_overflow
);
5848 f
->fmt
.pix
.width
= snr_fmt
.fmt
.pix
.width
;
5849 f
->fmt
.pix
.height
= snr_fmt
.fmt
.pix
.height
;
5852 atomisp_get_format_bridge(snr_fmt
.fmt
.pix
.pixelformat
);
5853 if (!snr_format_bridge
)
5856 atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5857 V4L2_SUBDEV_FORMAT_ACTIVE
,
5858 ATOMISP_SUBDEV_PAD_SINK
)->code
=
5859 snr_format_bridge
->mbus_code
;
5861 isp_sink_fmt
= *atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5862 V4L2_SUBDEV_FORMAT_ACTIVE
,
5863 ATOMISP_SUBDEV_PAD_SINK
);
5865 isp_source_fmt
.code
= format_bridge
->mbus_code
;
5866 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5867 V4L2_SUBDEV_FORMAT_ACTIVE
,
5868 source_pad
, &isp_source_fmt
);
5870 if (!atomisp_subdev_format_conversion(asd
, source_pad
)) {
5873 } else if (IS_BYT
) {
5878 /* construct resolution supported by isp */
5879 if (res_overflow
&& !asd
->continuous_mode
->val
) {
5880 f
->fmt
.pix
.width
= rounddown(
5881 clamp_t(u32
, f
->fmt
.pix
.width
- padding_w
,
5883 ATOM_ISP_MAX_WIDTH
), ATOM_ISP_STEP_WIDTH
);
5884 f
->fmt
.pix
.height
= rounddown(
5885 clamp_t(u32
, f
->fmt
.pix
.height
- padding_h
,
5886 ATOM_ISP_MIN_HEIGHT
,
5887 ATOM_ISP_MAX_HEIGHT
), ATOM_ISP_STEP_HEIGHT
);
5890 atomisp_get_dis_envelop(asd
, f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5891 &dvs_env_w
, &dvs_env_h
);
5893 if (asd
->continuous_mode
->val
) {
5894 struct v4l2_rect
*r
;
5896 r
= atomisp_subdev_get_rect(
5898 V4L2_SUBDEV_FORMAT_ACTIVE
,
5899 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
,
5900 V4L2_SEL_TGT_COMPOSE
);
5902 * The ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE should get resolutions
5903 * properly set otherwise, it should not be the capture_pad.
5905 if (r
->width
&& r
->height
)
5906 asd
->capture_pad
= ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
;
5908 asd
->capture_pad
= source_pad
;
5910 asd
->capture_pad
= source_pad
;
5913 * set format info to sensor
5914 * In continuous mode, resolution is set only if it is higher than
5915 * existing value. This because preview pipe will be configured after
5916 * capture pipe and usually has lower resolution than capture pipe.
5918 if (!asd
->continuous_mode
->val
||
5919 isp_sink_fmt
.width
< (f
->fmt
.pix
.width
+ padding_w
+ dvs_env_w
) ||
5920 isp_sink_fmt
.height
< (f
->fmt
.pix
.height
+ padding_h
+
5923 * For jpeg or custom raw format the sensor will return constant
5924 * width and height. Because we already had quried try_mbus_fmt,
5925 * f->fmt.pix.width and f->fmt.pix.height has been changed to
5926 * this fixed width and height. So we cannot select the correct
5927 * resolution with that information. So use the original width
5928 * and height while set_mbus_fmt() so actual resolutions are
5929 * being used in while set media bus format.
5932 if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_JPEG
||
5933 f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_CUSTOM_M10MO_RAW
) {
5934 s_fmt
.fmt
.pix
.width
= backup_fmt
.fmt
.pix
.width
;
5935 s_fmt
.fmt
.pix
.height
= backup_fmt
.fmt
.pix
.height
;
5937 ret
= atomisp_set_fmt_to_snr(vdev
, &s_fmt
,
5938 f
->fmt
.pix
.pixelformat
, padding_w
,
5939 padding_h
, dvs_env_w
, dvs_env_h
);
5943 atomisp_csi_lane_config(isp
);
5944 crop_needs_override
= true;
5947 atomisp_check_copy_mode(asd
, source_pad
, &backup_fmt
);
5948 asd
->yuvpp_mode
= false; /* Reset variable */
5950 isp_sink_crop
= *atomisp_subdev_get_rect(&asd
->subdev
, NULL
,
5951 V4L2_SUBDEV_FORMAT_ACTIVE
,
5952 ATOMISP_SUBDEV_PAD_SINK
,
5955 /* Try to enable YUV downscaling if ISP input is 10 % (either
5956 * width or height) bigger than the desired result. */
5957 if (isp_sink_crop
.width
* 9 / 10 < f
->fmt
.pix
.width
||
5958 isp_sink_crop
.height
* 9 / 10 < f
->fmt
.pix
.height
||
5959 (atomisp_subdev_format_conversion(asd
, source_pad
) &&
5960 ((asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
5961 !asd
->continuous_mode
->val
) ||
5962 asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
))) {
5963 /* for continuous mode, preview size might be smaller than
5964 * still capture size. if preview size still needs crop,
5965 * pick the larger one between crop size of preview and
5968 if (asd
->continuous_mode
->val
5969 && source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5970 && !crop_needs_override
) {
5971 isp_sink_crop
.width
=
5972 max_t(unsigned int, f
->fmt
.pix
.width
,
5973 isp_sink_crop
.width
);
5974 isp_sink_crop
.height
=
5975 max_t(unsigned int, f
->fmt
.pix
.height
,
5976 isp_sink_crop
.height
);
5978 isp_sink_crop
.width
= f
->fmt
.pix
.width
;
5979 isp_sink_crop
.height
= f
->fmt
.pix
.height
;
5982 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
5983 V4L2_SUBDEV_FORMAT_ACTIVE
,
5984 ATOMISP_SUBDEV_PAD_SINK
,
5986 V4L2_SEL_FLAG_KEEP_CONFIG
,
5988 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
5989 V4L2_SUBDEV_FORMAT_ACTIVE
,
5990 source_pad
, V4L2_SEL_TGT_COMPOSE
,
5992 } else if (IS_MOFD
) {
5993 struct v4l2_rect main_compose
= {0};
5995 main_compose
.width
= isp_sink_crop
.width
;
5996 main_compose
.height
=
5997 DIV_ROUND_UP(main_compose
.width
* f
->fmt
.pix
.height
,
5999 if (main_compose
.height
> isp_sink_crop
.height
) {
6000 main_compose
.height
= isp_sink_crop
.height
;
6001 main_compose
.width
=
6002 DIV_ROUND_UP(main_compose
.height
*
6007 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6008 V4L2_SUBDEV_FORMAT_ACTIVE
,
6010 V4L2_SEL_TGT_COMPOSE
, 0,
6013 struct v4l2_rect sink_crop
= {0};
6014 struct v4l2_rect main_compose
= {0};
6016 main_compose
.width
= f
->fmt
.pix
.width
;
6017 main_compose
.height
= f
->fmt
.pix
.height
;
6020 /* WORKAROUND: this override is universally enabled in
6021 * GMIN to work around a CTS failures (GMINL-539)
6022 * which appears to be related by a hardware
6023 * performance limitation. It's unclear why this
6024 * particular code triggers the issue. */
6026 crop_needs_override
) {
6028 if (crop_needs_override
) {
6030 if (isp_sink_crop
.width
* main_compose
.height
>
6031 isp_sink_crop
.height
* main_compose
.width
) {
6032 sink_crop
.height
= isp_sink_crop
.height
;
6033 sink_crop
.width
= DIV_NEAREST_STEP(
6037 ATOM_ISP_STEP_WIDTH
);
6039 sink_crop
.width
= isp_sink_crop
.width
;
6040 sink_crop
.height
= DIV_NEAREST_STEP(
6044 ATOM_ISP_STEP_HEIGHT
);
6046 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6047 V4L2_SUBDEV_FORMAT_ACTIVE
,
6048 ATOMISP_SUBDEV_PAD_SINK
,
6050 V4L2_SEL_FLAG_KEEP_CONFIG
,
6053 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6054 V4L2_SUBDEV_FORMAT_ACTIVE
,
6056 V4L2_SEL_TGT_COMPOSE
, 0,
6061 ret
= atomisp_set_fmt_to_isp(vdev
, &output_info
, &raw_output_info
,
6062 &f
->fmt
.pix
, source_pad
);
6066 pipe
->pix
.width
= f
->fmt
.pix
.width
;
6067 pipe
->pix
.height
= f
->fmt
.pix
.height
;
6068 pipe
->pix
.pixelformat
= f
->fmt
.pix
.pixelformat
;
6069 if (format_bridge
->planar
) {
6070 pipe
->pix
.bytesperline
= output_info
.padded_width
;
6071 pipe
->pix
.sizeimage
= PAGE_ALIGN(f
->fmt
.pix
.height
*
6072 DIV_ROUND_UP(format_bridge
->depth
*
6073 output_info
.padded_width
, 8));
6075 pipe
->pix
.bytesperline
=
6076 DIV_ROUND_UP(format_bridge
->depth
*
6077 output_info
.padded_width
, 8);
6078 pipe
->pix
.sizeimage
=
6079 PAGE_ALIGN(f
->fmt
.pix
.height
* pipe
->pix
.bytesperline
);
6082 if (f
->fmt
.pix
.field
== V4L2_FIELD_ANY
)
6083 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
6084 pipe
->pix
.field
= f
->fmt
.pix
.field
;
6086 f
->fmt
.pix
= pipe
->pix
;
6087 f
->fmt
.pix
.priv
= PAGE_ALIGN(pipe
->pix
.width
*
6088 pipe
->pix
.height
* 2);
6090 pipe
->capq
.field
= f
->fmt
.pix
.field
;
6093 * If in video 480P case, no GFX throttle
6095 if (asd
->run_mode
->val
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
&&
6096 f
->fmt
.pix
.width
== 720 && f
->fmt
.pix
.height
== 480)
6097 isp
->need_gfx_throttle
= false;
6099 isp
->need_gfx_throttle
= true;
6104 int atomisp_set_fmt_file(struct video_device
*vdev
, struct v4l2_format
*f
)
6106 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
6107 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
6108 struct atomisp_sub_device
*asd
= pipe
->asd
;
6109 struct v4l2_mbus_framefmt ffmt
= {0};
6110 const struct atomisp_format_bridge
*format_bridge
;
6111 struct v4l2_subdev_fh fh
;
6114 v4l2_fh_init(&fh
.vfh
, vdev
);
6116 dev_dbg(isp
->dev
, "setting fmt %ux%u 0x%x for file inject\n",
6117 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
, f
->fmt
.pix
.pixelformat
);
6118 ret
= atomisp_try_fmt_file(isp
, f
);
6120 dev_err(isp
->dev
, "atomisp_try_fmt_file err: %d\n", ret
);
6124 format_bridge
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
6125 if (format_bridge
== NULL
) {
6126 dev_dbg(isp
->dev
, "atomisp_get_format_bridge err! fmt:0x%x\n",
6127 f
->fmt
.pix
.pixelformat
);
6131 pipe
->pix
= f
->fmt
.pix
;
6132 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_FIFO
);
6133 atomisp_css_input_configure_port(asd
,
6134 __get_mipi_port(isp
, ATOMISP_CAMERA_PORT_PRIMARY
), 2, 0xffff4,
6136 ffmt
.width
= f
->fmt
.pix
.width
;
6137 ffmt
.height
= f
->fmt
.pix
.height
;
6138 ffmt
.code
= format_bridge
->mbus_code
;
6140 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
, V4L2_SUBDEV_FORMAT_ACTIVE
,
6141 ATOMISP_SUBDEV_PAD_SINK
, &ffmt
);
6146 int atomisp_set_shading_table(struct atomisp_sub_device
*asd
,
6147 struct atomisp_shading_table
*user_shading_table
)
6149 struct atomisp_css_shading_table
*shading_table
;
6150 struct atomisp_css_shading_table
*free_table
;
6151 unsigned int len_table
;
6155 if (!user_shading_table
)
6158 if (!user_shading_table
->enable
) {
6159 atomisp_css_set_shading_table(asd
, NULL
);
6160 asd
->params
.sc_en
= 0;
6164 /* If enabling, all tables must be set */
6165 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
6166 if (!user_shading_table
->data
[i
])
6170 /* Shading table size per color */
6171 if (user_shading_table
->width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
6172 user_shading_table
->height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
)
6175 shading_table
= atomisp_css_shading_table_alloc(
6176 user_shading_table
->width
, user_shading_table
->height
);
6180 len_table
= user_shading_table
->width
* user_shading_table
->height
*
6181 ATOMISP_SC_TYPE_SIZE
;
6182 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
6183 ret
= copy_from_user(shading_table
->data
[i
],
6184 user_shading_table
->data
[i
], len_table
);
6186 free_table
= shading_table
;
6191 shading_table
->sensor_width
= user_shading_table
->sensor_width
;
6192 shading_table
->sensor_height
= user_shading_table
->sensor_height
;
6193 shading_table
->fraction_bits
= user_shading_table
->fraction_bits
;
6195 free_table
= asd
->params
.css_param
.shading_table
;
6196 asd
->params
.css_param
.shading_table
= shading_table
;
6197 atomisp_css_set_shading_table(asd
, shading_table
);
6198 asd
->params
.sc_en
= 1;
6201 if (free_table
!= NULL
)
6202 atomisp_css_shading_table_free(free_table
);
6207 /*Turn off ISP dphy */
6208 int atomisp_ospm_dphy_down(struct atomisp_device
*isp
)
6210 unsigned long flags
;
6213 dev_dbg(isp
->dev
, "%s\n", __func__
);
6215 /* if ISP timeout, we can force powerdown */
6216 if (isp
->isp_timeout
)
6219 if (!atomisp_dev_users(isp
))
6222 spin_lock_irqsave(&isp
->lock
, flags
);
6223 isp
->sw_contex
.power_state
= ATOM_ISP_POWER_DOWN
;
6224 spin_unlock_irqrestore(&isp
->lock
, flags
);
6227 * MRFLD IUNIT DPHY is located in an always-power-on island
6228 * MRFLD HW design need all CSI ports are disabled before
6229 * powering down the IUNIT.
6231 pci_read_config_dword(isp
->pdev
, MRFLD_PCI_CSI_CONTROL
, ®
);
6232 reg
|= MRFLD_ALL_CSI_PORTS_OFF_MASK
;
6233 pci_write_config_dword(isp
->pdev
, MRFLD_PCI_CSI_CONTROL
, reg
);
6237 /*Turn on ISP dphy */
6238 int atomisp_ospm_dphy_up(struct atomisp_device
*isp
)
6240 unsigned long flags
;
6241 dev_dbg(isp
->dev
, "%s\n", __func__
);
6243 spin_lock_irqsave(&isp
->lock
, flags
);
6244 isp
->sw_contex
.power_state
= ATOM_ISP_POWER_UP
;
6245 spin_unlock_irqrestore(&isp
->lock
, flags
);
6251 int atomisp_exif_makernote(struct atomisp_sub_device
*asd
,
6252 struct atomisp_makernote_info
*config
)
6254 struct v4l2_control ctrl
;
6255 struct atomisp_device
*isp
= asd
->isp
;
6257 ctrl
.id
= V4L2_CID_FOCAL_ABSOLUTE
;
6259 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6260 dev_warn(isp
->dev
, "failed to g_ctrl for focal length\n");
6263 config
->focal_length
= ctrl
.value
;
6266 ctrl
.id
= V4L2_CID_FNUMBER_ABSOLUTE
;
6268 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6269 dev_warn(isp
->dev
, "failed to g_ctrl for f-number\n");
6272 config
->f_number_curr
= ctrl
.value
;
6275 ctrl
.id
= V4L2_CID_FNUMBER_RANGE
;
6277 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6278 dev_warn(isp
->dev
, "failed to g_ctrl for f number range\n");
6281 config
->f_number_range
= ctrl
.value
;
6287 int atomisp_offline_capture_configure(struct atomisp_sub_device
*asd
,
6288 struct atomisp_cont_capture_conf
*cvf_config
)
6290 struct v4l2_ctrl
*c
;
6293 * In case of M10MO ZSL capture case, we need to issue a separate
6294 * capture request to M10MO which will output captured jpeg image
6297 asd
->isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
,
6298 V4L2_CID_START_ZSL_CAPTURE
);
6301 dev_dbg(asd
->isp
->dev
, "%s trigger ZSL capture request\n",
6303 /* TODO: use the cvf_config */
6304 ret
= v4l2_ctrl_s_ctrl(c
, 1);
6308 return v4l2_ctrl_s_ctrl(c
, 0);
6311 asd
->params
.offline_parm
= *cvf_config
;
6313 if (asd
->params
.offline_parm
.num_captures
) {
6314 if (asd
->streaming
== ATOMISP_DEVICE_STREAMING_DISABLED
) {
6315 unsigned int init_raw_num
;
6317 if (asd
->enable_raw_buffer_lock
->val
) {
6319 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN
;
6320 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
6321 asd
->params
.video_dis_en
)
6323 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY
;
6326 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES
;
6329 /* TODO: this can be removed once user-space
6330 * has been updated to use control API */
6331 asd
->continuous_raw_buffer_size
->val
=
6333 asd
->continuous_raw_buffer_size
->val
,
6334 asd
->params
.offline_parm
.
6335 num_captures
+ init_raw_num
);
6336 asd
->continuous_raw_buffer_size
->val
=
6337 min_t(int, ATOMISP_CONT_RAW_FRAMES
,
6338 asd
->continuous_raw_buffer_size
->val
);
6340 asd
->continuous_mode
->val
= true;
6342 asd
->continuous_mode
->val
= false;
6343 __enable_continuous_mode(asd
, false);
6350 * set auto exposure metering window to camera sensor
6352 int atomisp_s_ae_window(struct atomisp_sub_device
*asd
,
6353 struct atomisp_ae_window
*arg
)
6355 struct atomisp_device
*isp
= asd
->isp
;
6356 /* Coverity CID 298071 - initialzize struct */
6357 struct v4l2_subdev_selection sel
= { 0 };
6359 sel
.r
.left
= arg
->x_left
;
6360 sel
.r
.top
= arg
->y_top
;
6361 sel
.r
.width
= arg
->x_right
- arg
->x_left
+ 1;
6362 sel
.r
.height
= arg
->y_bottom
- arg
->y_top
+ 1;
6364 if (v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
6365 pad
, set_selection
, NULL
, &sel
)) {
6366 dev_err(isp
->dev
, "failed to call sensor set_selection.\n");
6373 int atomisp_flash_enable(struct atomisp_sub_device
*asd
, int num_frames
)
6375 struct atomisp_device
*isp
= asd
->isp
;
6377 if (num_frames
< 0) {
6378 dev_dbg(isp
->dev
, "%s ERROR: num_frames: %d\n", __func__
,
6382 /* a requested flash is still in progress. */
6383 if (num_frames
&& asd
->params
.flash_state
!= ATOMISP_FLASH_IDLE
) {
6384 dev_dbg(isp
->dev
, "%s flash busy: %d frames left: %d\n",
6385 __func__
, asd
->params
.flash_state
,
6386 asd
->params
.num_flash_frames
);
6390 asd
->params
.num_flash_frames
= num_frames
;
6391 asd
->params
.flash_state
= ATOMISP_FLASH_REQUESTED
;
6395 int atomisp_source_pad_to_stream_id(struct atomisp_sub_device
*asd
,
6396 uint16_t source_pad
)
6399 struct atomisp_device
*isp
= asd
->isp
;
6401 if (isp
->inputs
[asd
->input_curr
].camera_caps
->
6402 sensor
[asd
->sensor_curr
].stream_num
== 1)
6403 return ATOMISP_INPUT_STREAM_GENERAL
;
6405 switch (source_pad
) {
6406 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
:
6407 stream_id
= ATOMISP_INPUT_STREAM_CAPTURE
;
6409 case ATOMISP_SUBDEV_PAD_SOURCE_VF
:
6410 stream_id
= ATOMISP_INPUT_STREAM_POSTVIEW
;
6412 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
:
6413 stream_id
= ATOMISP_INPUT_STREAM_PREVIEW
;
6415 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
:
6416 stream_id
= ATOMISP_INPUT_STREAM_VIDEO
;
6419 stream_id
= ATOMISP_INPUT_STREAM_GENERAL
;
6425 bool atomisp_is_vf_pipe(struct atomisp_video_pipe
*pipe
)
6427 struct atomisp_sub_device
*asd
= pipe
->asd
;
6429 if (pipe
== &asd
->video_out_vf
)
6432 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
6433 pipe
== &asd
->video_out_preview
)
6439 static int __checking_exp_id(struct atomisp_sub_device
*asd
, int exp_id
)
6441 struct atomisp_device
*isp
= asd
->isp
;
6443 if (!asd
->enable_raw_buffer_lock
->val
) {
6444 dev_warn(isp
->dev
, "%s Raw Buffer Lock is disable.\n", __func__
);
6447 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
) {
6448 dev_err(isp
->dev
, "%s streaming %d invalid exp_id %d.\n",
6449 __func__
, exp_id
, asd
->streaming
);
6452 if ((exp_id
> ATOMISP_MAX_EXP_ID
) || (exp_id
<= 0)) {
6453 dev_err(isp
->dev
, "%s exp_id %d invalid.\n", __func__
, exp_id
);
6459 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device
*asd
)
6461 unsigned long flags
;
6462 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6463 memset(asd
->raw_buffer_bitmap
, 0, sizeof(asd
->raw_buffer_bitmap
));
6464 asd
->raw_buffer_locked_count
= 0;
6465 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6468 int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device
*asd
, int exp_id
)
6471 unsigned long flags
;
6473 if (__checking_exp_id(asd
, exp_id
))
6476 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6478 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6479 (*bitmap
) |= (1 << bit
);
6480 asd
->raw_buffer_locked_count
++;
6481 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6483 dev_dbg(asd
->isp
->dev
, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6484 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6486 /* Check if the raw buffer after next is still locked!!! */
6488 if (exp_id
> ATOMISP_MAX_EXP_ID
)
6489 exp_id
-= ATOMISP_MAX_EXP_ID
;
6490 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6492 if ((*bitmap
) & (1 << bit
)) {
6495 /* WORKAROUND unlock the raw buffer compulsively */
6496 ret
= atomisp_css_exp_id_unlock(asd
, exp_id
);
6498 dev_err(asd
->isp
->dev
, "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n",
6499 __func__
, exp_id
, ret
);
6503 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6504 (*bitmap
) &= ~(1 << bit
);
6505 asd
->raw_buffer_locked_count
--;
6506 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6507 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",
6508 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6513 static int __is_raw_buffer_locked(struct atomisp_sub_device
*asd
, int exp_id
)
6516 unsigned long flags
;
6519 if (__checking_exp_id(asd
, exp_id
))
6522 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6524 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6525 ret
= ((*bitmap
) & (1 << bit
));
6526 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6530 static int __clear_raw_buffer_bitmap(struct atomisp_sub_device
*asd
, int exp_id
)
6533 unsigned long flags
;
6535 if (__is_raw_buffer_locked(asd
, exp_id
))
6538 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6540 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6541 (*bitmap
) &= ~(1 << bit
);
6542 asd
->raw_buffer_locked_count
--;
6543 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6545 dev_dbg(asd
->isp
->dev
, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6546 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6550 int atomisp_exp_id_capture(struct atomisp_sub_device
*asd
, int *exp_id
)
6552 struct atomisp_device
*isp
= asd
->isp
;
6553 int value
= *exp_id
;
6556 ret
= __is_raw_buffer_locked(asd
, value
);
6558 dev_err(isp
->dev
, "%s exp_id %d invalid %d.\n", __func__
, value
, ret
);
6562 dev_dbg(isp
->dev
, "%s exp_id %d\n", __func__
, value
);
6563 ret
= atomisp_css_exp_id_capture(asd
, value
);
6565 dev_err(isp
->dev
, "%s exp_id %d failed.\n", __func__
, value
);
6571 int atomisp_exp_id_unlock(struct atomisp_sub_device
*asd
, int *exp_id
)
6573 struct atomisp_device
*isp
= asd
->isp
;
6574 int value
= *exp_id
;
6577 ret
= __clear_raw_buffer_bitmap(asd
, value
);
6579 dev_err(isp
->dev
, "%s exp_id %d invalid %d.\n", __func__
, value
, ret
);
6583 dev_dbg(isp
->dev
, "%s exp_id %d\n", __func__
, value
);
6584 ret
= atomisp_css_exp_id_unlock(asd
, value
);
6586 dev_err(isp
->dev
, "%s exp_id %d failed, err %d.\n",
6587 __func__
, value
, ret
);
6592 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device
*asd
,
6593 unsigned int *enable
)
6600 value
= *enable
> 0 ? true : false;
6602 atomisp_en_dz_capt_pipe(asd
, value
);
6607 int atomisp_inject_a_fake_event(struct atomisp_sub_device
*asd
, int *event
)
6609 if (!event
|| asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
6612 dev_dbg(asd
->isp
->dev
, "%s: trying to inject a fake event 0x%x\n",
6616 case V4L2_EVENT_FRAME_SYNC
:
6617 atomisp_sof_event(asd
);
6619 case V4L2_EVENT_FRAME_END
:
6620 atomisp_eof_event(asd
, 0);
6622 case V4L2_EVENT_ATOMISP_3A_STATS_READY
:
6623 atomisp_3a_stats_ready_event(asd
, 0);
6625 case V4L2_EVENT_ATOMISP_METADATA_READY
:
6626 atomisp_metadata_ready_event(asd
, 0);
6635 int atomisp_get_pipe_id(struct atomisp_video_pipe
*pipe
)
6637 struct atomisp_sub_device
*asd
= pipe
->asd
;
6639 if (ATOMISP_USE_YUVPP(asd
))
6640 return CSS_PIPE_ID_YUVPP
;
6641 else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
)
6642 return CSS_PIPE_ID_VIDEO
;
6643 else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_LOWLAT
)
6644 return CSS_PIPE_ID_CAPTURE
;
6645 else if (pipe
== &asd
->video_out_video_capture
)
6646 return CSS_PIPE_ID_VIDEO
;
6647 else if (pipe
== &asd
->video_out_vf
)
6648 return CSS_PIPE_ID_CAPTURE
;
6649 else if (pipe
== &asd
->video_out_preview
) {
6650 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)
6651 return CSS_PIPE_ID_VIDEO
;
6653 return CSS_PIPE_ID_PREVIEW
;
6654 } else if (pipe
== &asd
->video_out_capture
) {
6656 return IA_CSS_PIPE_ID_COPY
;
6658 return CSS_PIPE_ID_CAPTURE
;
6662 dev_warn(asd
->isp
->dev
, "%s failed to find proper pipe\n",
6664 return CSS_PIPE_ID_CAPTURE
;
6667 int atomisp_get_invalid_frame_num(struct video_device
*vdev
,
6668 int *invalid_frame_num
)
6670 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
6671 struct atomisp_sub_device
*asd
= pipe
->asd
;
6672 enum atomisp_css_pipe_id pipe_id
;
6673 struct ia_css_pipe_info p_info
;
6676 if (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
6677 sensor
[asd
->sensor_curr
].stream_num
> 1) {
6679 *invalid_frame_num
= 0;
6683 pipe_id
= atomisp_get_pipe_id(pipe
);
6684 if (!asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].pipes
[pipe_id
]) {
6685 dev_warn(asd
->isp
->dev
, "%s pipe %d has not been created yet, do SET_FMT first!\n",
6690 ret
= ia_css_pipe_get_info(
6691 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
6692 .pipes
[pipe_id
], &p_info
);
6693 if (ret
== IA_CSS_SUCCESS
) {
6694 *invalid_frame_num
= p_info
.num_invalid_frames
;
6697 dev_warn(asd
->isp
->dev
, "%s get pipe infor failed %d\n",