5 * Support for Medifield PNW Camera Imaging ISP subsystem.
7 * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
9 * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License version
13 * 2 as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include <linux/firmware.h>
27 #include <linux/pci.h>
28 #include <linux/interrupt.h>
29 #include <linux/kernel.h>
30 #include <linux/kfifo.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/timer.h>
33 #include <asm/intel-mid.h>
35 #include <media/v4l2-event.h>
36 #include <media/videobuf-vmalloc.h>
38 #define CREATE_TRACE_POINTS
39 #include "atomisp_trace_event.h"
41 #include "atomisp_cmd.h"
42 #include "atomisp_common.h"
43 #include "atomisp_fops.h"
44 #include "atomisp_internal.h"
45 #include "atomisp_ioctl.h"
46 #include "atomisp-regs.h"
47 #include "atomisp_tables.h"
48 #include "atomisp_acc.h"
49 #include "atomisp_compat.h"
50 #include "atomisp_subdev.h"
51 #include "atomisp_dfs_tables.h"
53 #include "hrt/hive_isp_css_mm_hrt.h"
55 #include "sh_css_hrt.h"
56 #include "sh_css_defs.h"
57 #include "system_global.h"
58 #include "sh_css_internal.h"
59 #include "sh_css_sp.h"
60 #include "gp_device.h"
61 #include "device_access.h"
64 #include "ia_css_types.h"
65 #include "ia_css_stream.h"
66 #include "error_support.h"
70 /* We should never need to run the flash for more than 2 frames.
71 * At 15fps this means 133ms. We set the timeout a bit longer.
72 * Each flash driver is supposed to set its own timeout, but
73 * just in case someone else changed the timeout, we set it
74 * here to make sure we don't damage the flash hardware. */
75 #define FLASH_TIMEOUT 800 /* ms */
80 void __user
*user_ptr
;
89 * atomisp_kernel_malloc: chooses whether kmalloc() or vmalloc() is preferable.
91 * It is also a wrap functions to pass into css framework.
93 void *atomisp_kernel_malloc(size_t bytes
)
95 /* vmalloc() is preferable if allocating more than 1 page */
96 if (bytes
> PAGE_SIZE
)
97 return vmalloc(bytes
);
99 return kmalloc(bytes
, GFP_KERNEL
);
103 * atomisp_kernel_zalloc: chooses whether set 0 to the allocated memory.
105 * It is also a wrap functions to pass into css framework.
107 void *atomisp_kernel_zalloc(size_t bytes
, bool zero_mem
)
109 void *ptr
= atomisp_kernel_malloc(bytes
);
112 memset(ptr
, 0, bytes
);
118 * Free buffer allocated with atomisp_kernel_malloc()/atomisp_kernel_zalloc
121 void atomisp_kernel_free(void *ptr
)
123 /* Verify if buffer was allocated by vmalloc() or kmalloc() */
124 if (is_vmalloc_addr(ptr
))
131 * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field.
132 * subdev->priv is set in mrst.c
134 struct camera_mipi_info
*atomisp_to_sensor_mipi_info(struct v4l2_subdev
*sd
)
136 return (struct camera_mipi_info
*)v4l2_get_subdev_hostdata(sd
);
140 * get struct atomisp_video_pipe from v4l2 video_device
142 struct atomisp_video_pipe
*atomisp_to_video_pipe(struct video_device
*dev
)
144 return (struct atomisp_video_pipe
*)
145 container_of(dev
, struct atomisp_video_pipe
, vdev
);
149 * get struct atomisp_acc_pipe from v4l2 video_device
151 struct atomisp_acc_pipe
*atomisp_to_acc_pipe(struct video_device
*dev
)
153 return (struct atomisp_acc_pipe
*)
154 container_of(dev
, struct atomisp_acc_pipe
, vdev
);
157 static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device
*asd
)
159 struct v4l2_subdev_frame_interval frame_interval
;
160 struct atomisp_device
*isp
= asd
->isp
;
163 if (v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
164 video
, g_frame_interval
, &frame_interval
)) {
167 if (frame_interval
.interval
.numerator
)
168 fps
= frame_interval
.interval
.denominator
/
169 frame_interval
.interval
.numerator
;
177 * DFS progress is shown as follows:
178 * 1. Target frequency is calculated according to FPS/Resolution/ISP running
180 * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1
181 * with proper rounding.
182 * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40
183 * to 200MHz in ISPSSPM1.
184 * 4. Wait for FREQVALID to be cleared by P-Unit.
185 * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3.
187 static int write_target_freq_to_hw(struct atomisp_device
*isp
,
188 unsigned int new_freq
)
190 unsigned int ratio
, timeout
, guar_ratio
;
193 if (!isp
->hpll_freq
) {
194 dev_err(isp
->dev
, "failed to get hpll_freq. no change to freq\n");
198 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
199 if (isp_sspm1
& ISP_FREQ_VALID_MASK
) {
200 dev_dbg(isp
->dev
, "clearing ISPSSPM1 valid bit.\n");
201 intel_mid_msgbus_write32(PUNIT_PORT
, ISPSSPM1
,
202 isp_sspm1
& ~(1 << ISP_FREQ_VALID_OFFSET
));
205 ratio
= (2 * isp
->hpll_freq
+ new_freq
/ 2) / new_freq
- 1;
206 guar_ratio
= (2 * isp
->hpll_freq
+ 200 / 2) / 200 - 1;
208 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
209 isp_sspm1
&= ~(0x1F << ISP_REQ_FREQ_OFFSET
);
211 for (i
= 0; i
< ISP_DFS_TRY_TIMES
; i
++) {
212 intel_mid_msgbus_write32(PUNIT_PORT
, ISPSSPM1
,
214 | ratio
<< ISP_REQ_FREQ_OFFSET
215 | 1 << ISP_FREQ_VALID_OFFSET
216 | guar_ratio
<< ISP_REQ_GUAR_FREQ_OFFSET
);
218 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
221 while ((isp_sspm1
& ISP_FREQ_VALID_MASK
) && timeout
) {
222 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
223 dev_dbg(isp
->dev
, "waiting for ISPSSPM1 valid bit to be 0.\n");
233 dev_err(isp
->dev
, "DFS failed due to HW error.\n");
237 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
239 while (((isp_sspm1
>> ISP_FREQ_STAT_OFFSET
) != ratio
) && timeout
) {
240 isp_sspm1
= intel_mid_msgbus_read32(PUNIT_PORT
, ISPSSPM1
);
241 dev_dbg(isp
->dev
, "waiting for ISPSSPM1 status bit to be 0x%x.\n",
247 dev_err(isp
->dev
, "DFS target freq is rejected by HW.\n");
253 int atomisp_freq_scaling(struct atomisp_device
*isp
,
254 enum atomisp_dfs_mode mode
,
257 /* FIXME! Only use subdev[0] status yet */
258 struct atomisp_sub_device
*asd
= &isp
->asd
[0];
259 unsigned int new_freq
;
260 struct atomisp_freq_scaling_rule curr_rules
;
262 unsigned short fps
= 0;
264 if (isp
->sw_contex
.power_state
!= ATOM_ISP_POWER_UP
) {
265 dev_err(isp
->dev
, "DFS cannot proceed due to no power.\n");
270 if ((isp
->pdev
->device
& ATOMISP_PCI_DEVICE_SOC_MASK
) ==
271 ATOMISP_PCI_DEVICE_SOC_CHT
&& ATOMISP_USE_YUVPP(asd
))
272 isp
->dfs
= &dfs_config_cht_soc
;
275 if (isp
->dfs
->lowest_freq
== 0 || isp
->dfs
->max_freq_at_vmin
== 0 ||
276 isp
->dfs
->highest_freq
== 0 || isp
->dfs
->dfs_table_size
== 0 ||
277 !isp
->dfs
->dfs_table
) {
278 dev_err(isp
->dev
, "DFS configuration is invalid.\n");
282 if (mode
== ATOMISP_DFS_MODE_LOW
) {
283 new_freq
= isp
->dfs
->lowest_freq
;
287 if (mode
== ATOMISP_DFS_MODE_MAX
) {
288 new_freq
= isp
->dfs
->highest_freq
;
292 fps
= atomisp_get_sensor_fps(asd
);
296 curr_rules
.width
= asd
->fmt
[asd
->capture_pad
].fmt
.width
;
297 curr_rules
.height
= asd
->fmt
[asd
->capture_pad
].fmt
.height
;
298 curr_rules
.fps
= fps
;
299 curr_rules
.run_mode
= asd
->run_mode
->val
;
301 * For continuous mode, we need to make the capture setting applied
302 * since preview mode, because there is no chance to do this when
303 * starting image capture.
305 if (asd
->continuous_mode
->val
) {
306 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)
307 curr_rules
.run_mode
= ATOMISP_RUN_MODE_SDV
;
309 curr_rules
.run_mode
=
310 ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE
;
313 /* search for the target frequency by looping freq rules*/
314 for (i
= 0; i
< isp
->dfs
->dfs_table_size
; i
++) {
315 if (curr_rules
.width
!= isp
->dfs
->dfs_table
[i
].width
&&
316 isp
->dfs
->dfs_table
[i
].width
!= ISP_FREQ_RULE_ANY
)
318 if (curr_rules
.height
!= isp
->dfs
->dfs_table
[i
].height
&&
319 isp
->dfs
->dfs_table
[i
].height
!= ISP_FREQ_RULE_ANY
)
321 if (curr_rules
.fps
!= isp
->dfs
->dfs_table
[i
].fps
&&
322 isp
->dfs
->dfs_table
[i
].fps
!= ISP_FREQ_RULE_ANY
)
324 if (curr_rules
.run_mode
!= isp
->dfs
->dfs_table
[i
].run_mode
&&
325 isp
->dfs
->dfs_table
[i
].run_mode
!= ISP_FREQ_RULE_ANY
)
330 if (i
== isp
->dfs
->dfs_table_size
)
331 new_freq
= isp
->dfs
->max_freq_at_vmin
;
333 new_freq
= isp
->dfs
->dfs_table
[i
].isp_freq
;
336 dev_dbg(isp
->dev
, "DFS target frequency=%d.\n", new_freq
);
338 if ((new_freq
== isp
->sw_contex
.running_freq
) && !force
)
341 dev_dbg(isp
->dev
, "Programming DFS frequency to %d\n", new_freq
);
343 ret
= write_target_freq_to_hw(isp
, new_freq
);
345 isp
->sw_contex
.running_freq
= new_freq
;
346 trace_ipu_pstate(new_freq
, -1);
352 * reset and restore ISP
354 int atomisp_reset(struct atomisp_device
*isp
)
356 /* Reset ISP by power-cycling it */
359 dev_dbg(isp
->dev
, "%s\n", __func__
);
360 atomisp_css_suspend(isp
);
361 ret
= atomisp_runtime_suspend(isp
->dev
);
363 dev_err(isp
->dev
, "atomisp_runtime_suspend failed, %d\n", ret
);
364 ret
= atomisp_mrfld_power_down(isp
);
366 dev_err(isp
->dev
, "can not disable ISP power\n");
368 ret
= atomisp_mrfld_power_up(isp
);
370 dev_err(isp
->dev
, "can not enable ISP power\n");
371 ret
= atomisp_runtime_resume(isp
->dev
);
373 dev_err(isp
->dev
, "atomisp_runtime_resume failed, %d\n", ret
);
375 ret
= atomisp_css_resume(isp
);
377 isp
->isp_fatal_error
= true;
383 * interrupt enable/disable functions
385 static void enable_isp_irq(enum hrt_isp_css_irq irq
, bool enable
)
388 irq_enable_channel(IRQ0_ID
, irq
);
389 /*sh_css_hrt_irq_enable(irq, true, false);*/
390 switch (irq
) { /*We only have sp interrupt right now*/
391 case hrt_isp_css_irq_sp
:
392 /*sh_css_hrt_irq_enable_sp(true);*/
393 cnd_sp_irq_enable(SP0_ID
, true);
400 /*sh_css_hrt_irq_disable(irq);*/
401 irq_disable_channel(IRQ0_ID
, irq
);
403 case hrt_isp_css_irq_sp
:
404 /*sh_css_hrt_irq_enable_sp(false);*/
405 cnd_sp_irq_enable(SP0_ID
, false);
414 * interrupt clean function
416 static void clear_isp_irq(enum hrt_isp_css_irq irq
)
418 irq_clear_all(IRQ0_ID
);
421 void atomisp_msi_irq_init(struct atomisp_device
*isp
, struct pci_dev
*dev
)
426 pci_read_config_dword(dev
, PCI_MSI_CAPID
, &msg32
);
427 msg32
|= 1 << MSI_ENABLE_BIT
;
428 pci_write_config_dword(dev
, PCI_MSI_CAPID
, msg32
);
430 msg32
= (1 << INTR_IER
) | (1 << INTR_IIR
);
431 pci_write_config_dword(dev
, PCI_INTERRUPT_CTRL
, msg32
);
433 pci_read_config_word(dev
, PCI_COMMAND
, &msg16
);
434 msg16
|= (PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
435 PCI_COMMAND_INTX_DISABLE
);
436 pci_write_config_word(dev
, PCI_COMMAND
, msg16
);
439 void atomisp_msi_irq_uninit(struct atomisp_device
*isp
, struct pci_dev
*dev
)
444 pci_read_config_dword(dev
, PCI_MSI_CAPID
, &msg32
);
445 msg32
&= ~(1 << MSI_ENABLE_BIT
);
446 pci_write_config_dword(dev
, PCI_MSI_CAPID
, msg32
);
449 pci_write_config_dword(dev
, PCI_INTERRUPT_CTRL
, msg32
);
451 pci_read_config_word(dev
, PCI_COMMAND
, &msg16
);
452 msg16
&= ~(PCI_COMMAND_MASTER
);
453 pci_write_config_word(dev
, PCI_COMMAND
, msg16
);
456 static void atomisp_sof_event(struct atomisp_sub_device
*asd
)
458 struct v4l2_event event
= {0};
460 event
.type
= V4L2_EVENT_FRAME_SYNC
;
461 event
.u
.frame_sync
.frame_sequence
= atomic_read(&asd
->sof_count
);
463 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
466 void atomisp_eof_event(struct atomisp_sub_device
*asd
, uint8_t exp_id
)
468 struct v4l2_event event
= {0};
470 event
.type
= V4L2_EVENT_FRAME_END
;
471 event
.u
.frame_sync
.frame_sequence
= exp_id
;
473 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
476 static void atomisp_3a_stats_ready_event(struct atomisp_sub_device
*asd
, uint8_t exp_id
)
478 struct v4l2_event event
= {0};
480 event
.type
= V4L2_EVENT_ATOMISP_3A_STATS_READY
;
481 event
.u
.frame_sync
.frame_sequence
= exp_id
;
483 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
486 static void atomisp_metadata_ready_event(struct atomisp_sub_device
*asd
,
487 enum atomisp_metadata_type md_type
)
489 struct v4l2_event event
= {0};
491 event
.type
= V4L2_EVENT_ATOMISP_METADATA_READY
;
492 event
.u
.data
[0] = md_type
;
494 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
497 static void atomisp_reset_event(struct atomisp_sub_device
*asd
)
499 struct v4l2_event event
= {0};
501 event
.type
= V4L2_EVENT_ATOMISP_CSS_RESET
;
503 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
507 static void print_csi_rx_errors(enum ia_css_csi2_port port
,
508 struct atomisp_device
*isp
)
512 atomisp_css_rx_get_irq_info(port
, &infos
);
514 dev_err(isp
->dev
, "CSI Receiver port %d errors:\n", port
);
515 if (infos
& CSS_RX_IRQ_INFO_BUFFER_OVERRUN
)
516 dev_err(isp
->dev
, " buffer overrun");
517 if (infos
& CSS_RX_IRQ_INFO_ERR_SOT
)
518 dev_err(isp
->dev
, " start-of-transmission error");
519 if (infos
& CSS_RX_IRQ_INFO_ERR_SOT_SYNC
)
520 dev_err(isp
->dev
, " start-of-transmission sync error");
521 if (infos
& CSS_RX_IRQ_INFO_ERR_CONTROL
)
522 dev_err(isp
->dev
, " control error");
523 if (infos
& CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE
)
524 dev_err(isp
->dev
, " 2 or more ECC errors");
525 if (infos
& CSS_RX_IRQ_INFO_ERR_CRC
)
526 dev_err(isp
->dev
, " CRC mismatch");
527 if (infos
& CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID
)
528 dev_err(isp
->dev
, " unknown error");
529 if (infos
& CSS_RX_IRQ_INFO_ERR_FRAME_SYNC
)
530 dev_err(isp
->dev
, " frame sync error");
531 if (infos
& CSS_RX_IRQ_INFO_ERR_FRAME_DATA
)
532 dev_err(isp
->dev
, " frame data error");
533 if (infos
& CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT
)
534 dev_err(isp
->dev
, " data timeout");
535 if (infos
& CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC
)
536 dev_err(isp
->dev
, " unknown escape command entry");
537 if (infos
& CSS_RX_IRQ_INFO_ERR_LINE_SYNC
)
538 dev_err(isp
->dev
, " line sync error");
542 static void clear_irq_reg(struct atomisp_device
*isp
)
545 pci_read_config_dword(isp
->pdev
, PCI_INTERRUPT_CTRL
, &msg_ret
);
546 msg_ret
|= 1 << INTR_IIR
;
547 pci_write_config_dword(isp
->pdev
, PCI_INTERRUPT_CTRL
, msg_ret
);
550 static struct atomisp_sub_device
*
551 __get_asd_from_port(struct atomisp_device
*isp
, mipi_port_ID_t port
)
555 /* Check which isp subdev to send eof */
556 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
557 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
558 struct camera_mipi_info
*mipi_info
=
559 atomisp_to_sensor_mipi_info(
560 isp
->inputs
[asd
->input_curr
].camera
);
561 if (isp
->asd
[i
].streaming
== ATOMISP_DEVICE_STREAMING_ENABLED
&&
562 __get_mipi_port(isp
, mipi_info
->port
) == port
) {
570 /* interrupt handling function*/
571 irqreturn_t
atomisp_isr(int irq
, void *dev
)
573 struct atomisp_device
*isp
= (struct atomisp_device
*)dev
;
574 struct atomisp_sub_device
*asd
;
575 struct atomisp_css_event eof_event
;
576 unsigned int irq_infos
= 0;
581 spin_lock_irqsave(&isp
->lock
, flags
);
582 if (isp
->sw_contex
.power_state
!= ATOM_ISP_POWER_UP
||
583 isp
->css_initialized
== false) {
584 spin_unlock_irqrestore(&isp
->lock
, flags
);
587 err
= atomisp_css_irq_translate(isp
, &irq_infos
);
589 spin_unlock_irqrestore(&isp
->lock
, flags
);
593 dev_dbg(isp
->dev
, "irq:0x%x\n", irq_infos
);
597 if (!atomisp_streaming_count(isp
) && !atomisp_is_acc_enabled(isp
))
600 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
603 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
606 * Current SOF only support one stream, so the SOF only valid
607 * either solely one stream is running
609 if (irq_infos
& CSS_IRQ_INFO_CSS_RECEIVER_SOF
) {
610 atomic_inc(&asd
->sof_count
);
611 atomisp_sof_event(asd
);
613 /* If sequence_temp and sequence are the same
614 * there where no frames lost so we can increase
616 * If not then processing of frame is still in progress
617 * and driver needs to keep old sequence_temp value.
618 * NOTE: There is assumption here that ISP will not
619 * start processing next frame from sensor before old
620 * one is completely done. */
621 if (atomic_read(&asd
->sequence
) == atomic_read(
622 &asd
->sequence_temp
))
623 atomic_set(&asd
->sequence_temp
,
624 atomic_read(&asd
->sof_count
));
626 if (irq_infos
& CSS_IRQ_INFO_EVENTS_READY
)
627 atomic_set(&asd
->sequence
,
628 atomic_read(&asd
->sequence_temp
));
631 if (irq_infos
& CSS_IRQ_INFO_CSS_RECEIVER_SOF
)
632 irq_infos
&= ~CSS_IRQ_INFO_CSS_RECEIVER_SOF
;
634 if ((irq_infos
& CSS_IRQ_INFO_INPUT_SYSTEM_ERROR
) ||
635 (irq_infos
& CSS_IRQ_INFO_IF_ERROR
)) {
636 /* handle mipi receiver error */
638 enum ia_css_csi2_port port
;
640 for (port
= IA_CSS_CSI2_PORT0
; port
<= IA_CSS_CSI2_PORT2
;
642 print_csi_rx_errors(port
, isp
);
643 atomisp_css_rx_get_irq_info(port
, &rx_infos
);
644 atomisp_css_rx_clear_irq_info(port
, rx_infos
);
648 if (irq_infos
& IA_CSS_IRQ_INFO_ISYS_EVENTS_READY
) {
649 while (ia_css_dequeue_isys_event(&(eof_event
.event
)) ==
651 /* EOF Event does not have the css_pipe returned */
652 asd
= __get_asd_from_port(isp
, eof_event
.event
.port
);
654 dev_err(isp
->dev
, "%s:no subdev.event:%d", __func__
,
655 eof_event
.event
.type
);
659 atomisp_eof_event(asd
, eof_event
.event
.exp_id
);
661 dev_dbg(isp
->dev
, "%s EOF exp_id %d\n", __func__
,
662 eof_event
.event
.exp_id
);
664 dev_dbg(isp
->dev
, "%s EOF exp_id %d, asd %d\n",
665 __func__
, eof_event
.event
.exp_id
, asd
->index
);
669 irq_infos
&= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY
;
674 spin_unlock_irqrestore(&isp
->lock
, flags
);
676 return IRQ_WAKE_THREAD
;
679 spin_unlock_irqrestore(&isp
->lock
, flags
);
684 void atomisp_clear_css_buffer_counters(struct atomisp_sub_device
*asd
)
687 memset(asd
->s3a_bufs_in_css
, 0, sizeof(asd
->s3a_bufs_in_css
));
688 for (i
= 0; i
< ATOMISP_INPUT_STREAM_NUM
; i
++)
689 memset(asd
->metadata_bufs_in_css
[i
], 0,
690 sizeof(asd
->metadata_bufs_in_css
[i
]));
691 asd
->dis_bufs_in_css
= 0;
692 asd
->video_out_capture
.buffers_in_css
= 0;
693 asd
->video_out_vf
.buffers_in_css
= 0;
694 asd
->video_out_preview
.buffers_in_css
= 0;
695 asd
->video_out_video_capture
.buffers_in_css
= 0;
699 bool atomisp_buffers_queued(struct atomisp_sub_device
*asd
)
701 bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe
*pipe
)
705 return asd
->video_out_capture
.buffers_in_css
||
706 asd
->video_out_vf
.buffers_in_css
||
707 asd
->video_out_preview
.buffers_in_css
||
708 asd
->video_out_video_capture
.buffers_in_css
?
711 return pipe
->buffers_in_css
? true : false;
715 /* 0x100000 is the start of dmem inside SP */
716 #define SP_DMEM_BASE 0x100000
718 void dump_sp_dmem(struct atomisp_device
*isp
, unsigned int addr
,
721 unsigned int data
= 0;
722 unsigned int size32
= DIV_ROUND_UP(size
, sizeof(u32
));
724 dev_dbg(isp
->dev
, "atomisp_io_base:%p\n", atomisp_io_base
);
725 dev_dbg(isp
->dev
, "%s, addr:0x%x, size: %d, size32: %d\n", __func__
,
727 if (size32
* 4 + addr
> 0x4000) {
728 dev_err(isp
->dev
, "illegal size (%d) or addr (0x%x)\n",
732 addr
+= SP_DMEM_BASE
;
734 data
= _hrt_master_port_uload_32(addr
);
736 dev_dbg(isp
->dev
, "%s, \t [0x%x]:0x%x\n", __func__
, addr
, data
);
737 addr
+= sizeof(unsigned int);
739 } while (size32
> 0);
742 static struct videobuf_buffer
*atomisp_css_frame_to_vbuf(
743 struct atomisp_video_pipe
*pipe
, struct atomisp_css_frame
*frame
)
745 struct videobuf_vmalloc_memory
*vm_mem
;
746 struct atomisp_css_frame
*handle
;
749 for (i
= 0; pipe
->capq
.bufs
[i
]; i
++) {
750 vm_mem
= pipe
->capq
.bufs
[i
]->priv
;
751 handle
= vm_mem
->vaddr
;
752 if (handle
&& handle
->data
== frame
->data
)
753 return pipe
->capq
.bufs
[i
];
759 static void get_buf_timestamp(struct timeval
*tv
)
763 tv
->tv_sec
= ts
.tv_sec
;
764 tv
->tv_usec
= ts
.tv_nsec
/ NSEC_PER_USEC
;
767 static void atomisp_flush_video_pipe(struct atomisp_sub_device
*asd
,
768 struct atomisp_video_pipe
*pipe
)
770 unsigned long irqflags
;
776 for (i
= 0; pipe
->capq
.bufs
[i
]; i
++) {
777 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
778 if (pipe
->capq
.bufs
[i
]->state
== VIDEOBUF_ACTIVE
||
779 pipe
->capq
.bufs
[i
]->state
== VIDEOBUF_QUEUED
) {
780 get_buf_timestamp(&pipe
->capq
.bufs
[i
]->ts
);
781 pipe
->capq
.bufs
[i
]->field_count
=
782 atomic_read(&asd
->sequence
) << 1;
783 dev_dbg(asd
->isp
->dev
, "release buffers on device %s\n",
785 if (pipe
->capq
.bufs
[i
]->state
== VIDEOBUF_QUEUED
)
786 list_del_init(&pipe
->capq
.bufs
[i
]->queue
);
787 pipe
->capq
.bufs
[i
]->state
= VIDEOBUF_ERROR
;
788 wake_up(&pipe
->capq
.bufs
[i
]->done
);
790 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
794 /* Returns queued buffers back to video-core */
795 void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device
*asd
)
797 atomisp_flush_video_pipe(asd
, &asd
->video_out_capture
);
798 atomisp_flush_video_pipe(asd
, &asd
->video_out_vf
);
799 atomisp_flush_video_pipe(asd
, &asd
->video_out_preview
);
800 atomisp_flush_video_pipe(asd
, &asd
->video_out_video_capture
);
803 /* clean out the parameters that did not apply */
804 void atomisp_flush_params_queue(struct atomisp_video_pipe
*pipe
)
806 struct atomisp_css_params_with_list
*param
;
808 while (!list_empty(&pipe
->per_frame_params
)) {
809 param
= list_entry(pipe
->per_frame_params
.next
,
810 struct atomisp_css_params_with_list
, list
);
811 list_del(¶m
->list
);
812 atomisp_free_css_parameters(¶m
->params
);
813 atomisp_kernel_free(param
);
817 /* Re-queue per-frame parameters */
818 static void atomisp_recover_params_queue(struct atomisp_video_pipe
*pipe
)
820 struct atomisp_css_params_with_list
*param
;
823 for (i
= 0; i
< VIDEO_MAX_FRAME
; i
++) {
824 param
= pipe
->frame_params
[i
];
826 list_add_tail(¶m
->list
, &pipe
->per_frame_params
);
827 pipe
->frame_params
[i
] = NULL
;
829 atomisp_handle_parameter_and_buffer(pipe
);
832 /* find atomisp_video_pipe with css pipe id, buffer type and atomisp run_mode */
833 static struct atomisp_video_pipe
*__atomisp_get_pipe(
834 struct atomisp_sub_device
*asd
,
835 enum atomisp_input_stream_id stream_id
,
836 enum atomisp_css_pipe_id css_pipe_id
,
837 enum atomisp_css_buffer_type buf_type
)
839 struct atomisp_device
*isp
= asd
->isp
;
841 if (css_pipe_id
== CSS_PIPE_ID_COPY
&&
842 isp
->inputs
[asd
->input_curr
].camera_caps
->
843 sensor
[asd
->sensor_curr
].stream_num
> 1) {
845 case ATOMISP_INPUT_STREAM_PREVIEW
:
846 return &asd
->video_out_preview
;
847 case ATOMISP_INPUT_STREAM_POSTVIEW
:
848 return &asd
->video_out_vf
;
849 case ATOMISP_INPUT_STREAM_VIDEO
:
850 return &asd
->video_out_video_capture
;
851 case ATOMISP_INPUT_STREAM_CAPTURE
:
853 return &asd
->video_out_capture
;
857 /* video is same in online as in continuouscapture mode */
858 if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_LOWLAT
) {
860 * Disable vf_pp and run CSS in still capture mode. In this
861 * mode, CSS does not cause extra latency with buffering, but
862 * scaling is not available.
864 return &asd
->video_out_capture
;
865 } else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
) {
867 * Disable vf_pp and run CSS in video mode. This allows using
868 * ISP scaling but it has one frame delay due to CSS internal
871 return &asd
->video_out_video_capture
;
872 } else if (css_pipe_id
== CSS_PIPE_ID_YUVPP
) {
874 * to SOC camera, yuvpp pipe is run for capture/video/SDV/ZSL.
876 if (asd
->continuous_mode
->val
) {
877 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
880 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
:
881 return &asd
->video_out_video_capture
;
882 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME
:
883 return &asd
->video_out_preview
;
884 case CSS_BUFFER_TYPE_OUTPUT_FRAME
:
885 return &asd
->video_out_capture
;
887 return &asd
->video_out_vf
;
889 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_PREVIEW
) {
892 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
:
893 return &asd
->video_out_preview
;
894 case CSS_BUFFER_TYPE_OUTPUT_FRAME
:
895 return &asd
->video_out_capture
;
897 return &asd
->video_out_vf
;
900 } else if (buf_type
== CSS_BUFFER_TYPE_OUTPUT_FRAME
) {
901 switch (asd
->run_mode
->val
) {
902 case ATOMISP_RUN_MODE_VIDEO
:
903 return &asd
->video_out_video_capture
;
904 case ATOMISP_RUN_MODE_PREVIEW
:
905 return &asd
->video_out_preview
;
907 return &asd
->video_out_capture
;
909 } else if (buf_type
== CSS_BUFFER_TYPE_VF_OUTPUT_FRAME
) {
910 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)
911 return &asd
->video_out_preview
;
913 return &asd
->video_out_vf
;
915 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
916 /* For online video or SDV video pipe. */
917 if (css_pipe_id
== CSS_PIPE_ID_VIDEO
||
918 css_pipe_id
== CSS_PIPE_ID_COPY
||
919 css_pipe_id
== CSS_PIPE_ID_YUVPP
) {
920 if (buf_type
== CSS_BUFFER_TYPE_OUTPUT_FRAME
)
921 return &asd
->video_out_video_capture
;
922 return &asd
->video_out_preview
;
924 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_PREVIEW
) {
925 /* For online preview or ZSL preview pipe. */
926 if (css_pipe_id
== CSS_PIPE_ID_PREVIEW
||
927 css_pipe_id
== CSS_PIPE_ID_COPY
||
928 css_pipe_id
== CSS_PIPE_ID_YUVPP
)
929 return &asd
->video_out_preview
;
931 /* For capture pipe. */
932 if (buf_type
== CSS_BUFFER_TYPE_VF_OUTPUT_FRAME
)
933 return &asd
->video_out_vf
;
934 return &asd
->video_out_capture
;
937 enum atomisp_metadata_type
938 atomisp_get_metadata_type(struct atomisp_sub_device
*asd
,
939 enum ia_css_pipe_id pipe_id
)
941 if (!asd
->continuous_mode
->val
)
942 return ATOMISP_MAIN_METADATA
;
944 if (pipe_id
== IA_CSS_PIPE_ID_CAPTURE
) /* online capture pipe */
945 return ATOMISP_SEC_METADATA
;
947 return ATOMISP_MAIN_METADATA
;
950 void atomisp_buf_done(struct atomisp_sub_device
*asd
, int error
,
951 enum atomisp_css_buffer_type buf_type
,
952 enum atomisp_css_pipe_id css_pipe_id
,
953 bool q_buffers
, enum atomisp_input_stream_id stream_id
)
955 struct videobuf_buffer
*vb
= NULL
;
956 struct atomisp_video_pipe
*pipe
= NULL
;
957 struct atomisp_css_buffer buffer
;
958 bool requeue
= false;
960 unsigned long irqflags
;
961 struct atomisp_css_frame
*frame
= NULL
;
962 struct atomisp_s3a_buf
*s3a_buf
= NULL
, *_s3a_buf_tmp
;
963 struct atomisp_dis_buf
*dis_buf
= NULL
, *_dis_buf_tmp
;
964 struct atomisp_metadata_buf
*md_buf
= NULL
, *_md_buf_tmp
;
965 enum atomisp_metadata_type md_type
;
966 struct atomisp_device
*isp
= asd
->isp
;
967 struct v4l2_control ctrl
;
969 bool reset_wdt_timer
= false;
973 buf_type
!= CSS_BUFFER_TYPE_METADATA
&&
974 buf_type
!= CSS_BUFFER_TYPE_3A_STATISTICS
&&
975 buf_type
!= CSS_BUFFER_TYPE_DIS_STATISTICS
&&
976 buf_type
!= CSS_BUFFER_TYPE_OUTPUT_FRAME
&&
977 buf_type
!= CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
&&
978 buf_type
!= CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME
&&
979 buf_type
!= CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME
&&
980 buf_type
!= CSS_BUFFER_TYPE_VF_OUTPUT_FRAME
) {
981 dev_err(isp
->dev
, "%s, unsupported buffer type: %d\n",
986 memset(&buffer
, 0, sizeof(struct atomisp_css_buffer
));
987 buffer
.css_buffer
.type
= buf_type
;
988 err
= atomisp_css_dequeue_buffer(asd
, stream_id
, css_pipe_id
,
992 "atomisp_css_dequeue_buffer failed: 0x%x\n", err
);
996 /* need to know the atomisp pipe for frame buffers */
997 pipe
= __atomisp_get_pipe(asd
, stream_id
, css_pipe_id
, buf_type
);
999 dev_err(isp
->dev
, "error getting atomisp pipe\n");
1004 case CSS_BUFFER_TYPE_3A_STATISTICS
:
1005 list_for_each_entry_safe(s3a_buf
, _s3a_buf_tmp
,
1006 &asd
->s3a_stats_in_css
, list
) {
1007 if (s3a_buf
->s3a_data
==
1008 buffer
.css_buffer
.data
.stats_3a
) {
1009 list_del_init(&s3a_buf
->list
);
1010 list_add_tail(&s3a_buf
->list
,
1011 &asd
->s3a_stats_ready
);
1016 asd
->s3a_bufs_in_css
[css_pipe_id
]--;
1017 atomisp_3a_stats_ready_event(asd
, buffer
.css_buffer
.exp_id
);
1018 dev_dbg(isp
->dev
, "%s: s3a stat with exp_id %d is ready\n",
1019 __func__
, s3a_buf
->s3a_data
->exp_id
);
1021 case CSS_BUFFER_TYPE_METADATA
:
1025 md_type
= atomisp_get_metadata_type(asd
, css_pipe_id
);
1026 list_for_each_entry_safe(md_buf
, _md_buf_tmp
,
1027 &asd
->metadata_in_css
[md_type
], list
) {
1028 if (md_buf
->metadata
==
1029 buffer
.css_buffer
.data
.metadata
) {
1030 list_del_init(&md_buf
->list
);
1031 list_add_tail(&md_buf
->list
,
1032 &asd
->metadata_ready
[md_type
]);
1036 asd
->metadata_bufs_in_css
[stream_id
][css_pipe_id
]--;
1037 atomisp_metadata_ready_event(asd
, md_type
);
1038 dev_dbg(isp
->dev
, "%s: metadata with exp_id %d is ready\n",
1039 __func__
, md_buf
->metadata
->exp_id
);
1041 case CSS_BUFFER_TYPE_DIS_STATISTICS
:
1042 list_for_each_entry_safe(dis_buf
, _dis_buf_tmp
,
1043 &asd
->dis_stats_in_css
, list
) {
1044 if (dis_buf
->dis_data
==
1045 buffer
.css_buffer
.data
.stats_dvs
) {
1046 spin_lock_irqsave(&asd
->dis_stats_lock
,
1048 list_del_init(&dis_buf
->list
);
1049 list_add(&dis_buf
->list
, &asd
->dis_stats
);
1050 asd
->params
.dis_proj_data_valid
= true;
1051 spin_unlock_irqrestore(&asd
->dis_stats_lock
,
1056 asd
->dis_bufs_in_css
--;
1057 dev_dbg(isp
->dev
, "%s: dis stat with exp_id %d is ready\n",
1058 __func__
, dis_buf
->dis_data
->exp_id
);
1060 case CSS_BUFFER_TYPE_VF_OUTPUT_FRAME
:
1061 case CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME
:
1063 reset_wdt_timer
= true;
1065 pipe
->buffers_in_css
--;
1066 frame
= buffer
.css_buffer
.data
.frame
;
1075 * YUVPP doesn't set postview exp_id correctlly in SDV mode.
1076 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1078 if (IS_BYT
&& buf_type
== CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME
&&
1079 asd
->continuous_mode
->val
&& ATOMISP_USE_YUVPP(asd
))
1080 frame
->exp_id
= (asd
->postview_exp_id
++) %
1081 (ATOMISP_MAX_EXP_ID
+ 1);
1083 dev_dbg(isp
->dev
, "%s: vf frame with exp_id %d is ready\n",
1084 __func__
, frame
->exp_id
);
1085 if (asd
->params
.flash_state
== ATOMISP_FLASH_ONGOING
) {
1086 if (frame
->flash_state
1087 == CSS_FRAME_FLASH_STATE_PARTIAL
)
1088 dev_dbg(isp
->dev
, "%s thumb partially flashed\n",
1090 else if (frame
->flash_state
1091 == CSS_FRAME_FLASH_STATE_FULL
)
1092 dev_dbg(isp
->dev
, "%s thumb completely flashed\n",
1095 dev_dbg(isp
->dev
, "%s thumb no flash in this frame\n",
1098 vb
= atomisp_css_frame_to_vbuf(pipe
, frame
);
1101 pipe
->frame_config_id
[vb
->i
] = frame
->isp_config_id
;
1103 if (css_pipe_id
== IA_CSS_PIPE_ID_CAPTURE
&&
1104 asd
->pending_capture_request
> 0) {
1105 err
= atomisp_css_offline_capture_configure(asd
,
1107 if (css_pipe_id
== IA_CSS_PIPE_ID_CAPTURE
) {
1108 if (asd
->pending_capture_request
> 0) {
1109 err
= atomisp_css_offline_capture_configure(asd
,
1111 asd
->params
.offline_parm
.num_captures
,
1112 asd
->params
.offline_parm
.skip_frames
,
1113 asd
->params
.offline_parm
.offset
);
1115 asd
->pending_capture_request
--;
1116 dev_dbg(isp
->dev
, "Trigger capture again for new buffer. err=%d\n",
1119 asd
->pending_capture_request
--;
1120 asd
->re_trigger_capture
= false;
1121 dev_dbg(isp
->dev
, "Trigger capture again for new buffer. err=%d\n",
1124 asd
->re_trigger_capture
= true;
1129 case CSS_BUFFER_TYPE_OUTPUT_FRAME
:
1130 case CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
:
1132 reset_wdt_timer
= true;
1134 pipe
->buffers_in_css
--;
1135 frame
= buffer
.css_buffer
.data
.frame
;
1145 * YUVPP doesn't set preview exp_id correctlly in ZSL mode.
1146 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1148 if (IS_BYT
&& buf_type
== CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
&&
1149 asd
->continuous_mode
->val
&& ATOMISP_USE_YUVPP(asd
))
1150 frame
->exp_id
= (asd
->preview_exp_id
++) %
1151 (ATOMISP_MAX_EXP_ID
+ 1);
1153 dev_dbg(isp
->dev
, "%s: main frame with exp_id %d is ready\n",
1154 __func__
, frame
->exp_id
);
1155 vb
= atomisp_css_frame_to_vbuf(pipe
, frame
);
1161 /* free the parameters */
1162 if (pipe
->frame_params
[vb
->i
]) {
1163 if (asd
->params
.dvs_6axis
==
1164 pipe
->frame_params
[vb
->i
]->params
.dvs_6axis
)
1165 asd
->params
.dvs_6axis
= NULL
;
1166 atomisp_free_css_parameters(
1167 &pipe
->frame_params
[vb
->i
]->params
);
1168 atomisp_kernel_free(pipe
->frame_params
[vb
->i
]);
1169 pipe
->frame_params
[vb
->i
] = NULL
;
1172 pipe
->frame_config_id
[vb
->i
] = frame
->isp_config_id
;
1173 ctrl
.id
= V4L2_CID_FLASH_MODE
;
1174 if (asd
->params
.flash_state
== ATOMISP_FLASH_ONGOING
) {
1175 if (frame
->flash_state
1176 == CSS_FRAME_FLASH_STATE_PARTIAL
) {
1177 asd
->frame_status
[vb
->i
] =
1178 ATOMISP_FRAME_STATUS_FLASH_PARTIAL
;
1179 dev_dbg(isp
->dev
, "%s partially flashed\n",
1181 } else if (frame
->flash_state
1182 == CSS_FRAME_FLASH_STATE_FULL
) {
1183 asd
->frame_status
[vb
->i
] =
1184 ATOMISP_FRAME_STATUS_FLASH_EXPOSED
;
1185 asd
->params
.num_flash_frames
--;
1186 dev_dbg(isp
->dev
, "%s completely flashed\n",
1189 asd
->frame_status
[vb
->i
] =
1190 ATOMISP_FRAME_STATUS_OK
;
1192 "%s no flash in this frame\n",
1196 /* Check if flashing sequence is done */
1197 if (asd
->frame_status
[vb
->i
] ==
1198 ATOMISP_FRAME_STATUS_FLASH_EXPOSED
)
1199 asd
->params
.flash_state
= ATOMISP_FLASH_DONE
;
1200 } else if (isp
->flash
) {
1201 if (v4l2_g_ctrl(isp
->flash
->ctrl_handler
, &ctrl
) ==
1202 0 && ctrl
.value
== ATOMISP_FLASH_MODE_TORCH
) {
1203 ctrl
.id
= V4L2_CID_FLASH_TORCH_INTENSITY
;
1204 if (v4l2_g_ctrl(isp
->flash
->ctrl_handler
, &ctrl
)
1205 == 0 && ctrl
.value
> 0) {
1206 asd
->frame_status
[vb
->i
] =
1207 ATOMISP_FRAME_STATUS_FLASH_EXPOSED
;
1209 asd
->frame_status
[vb
->i
] =
1210 ATOMISP_FRAME_STATUS_OK
;
1213 asd
->frame_status
[vb
->i
] =
1214 ATOMISP_FRAME_STATUS_OK
;
1216 asd
->frame_status
[vb
->i
] = ATOMISP_FRAME_STATUS_OK
;
1219 asd
->params
.last_frame_status
= asd
->frame_status
[vb
->i
];
1221 if (asd
->continuous_mode
->val
) {
1222 if (css_pipe_id
== CSS_PIPE_ID_PREVIEW
||
1223 css_pipe_id
== CSS_PIPE_ID_VIDEO
) {
1224 asd
->latest_preview_exp_id
= frame
->exp_id
;
1225 } else if (css_pipe_id
==
1226 CSS_PIPE_ID_CAPTURE
) {
1227 if (asd
->run_mode
->val
==
1228 ATOMISP_RUN_MODE_VIDEO
)
1229 dev_dbg(isp
->dev
, "SDV capture raw buffer id: %u\n",
1232 dev_dbg(isp
->dev
, "ZSL capture raw buffer id: %u\n",
1237 * Only after enabled the raw buffer lock
1238 * and in continuous mode.
1239 * in preview/video pipe, each buffer will
1240 * be locked automatically, so record it here.
1242 if (((css_pipe_id
== CSS_PIPE_ID_PREVIEW
) ||
1243 (css_pipe_id
== CSS_PIPE_ID_VIDEO
)) &&
1244 asd
->enable_raw_buffer_lock
->val
&&
1245 asd
->continuous_mode
->val
) {
1246 atomisp_set_raw_buffer_bitmap(asd
, frame
->exp_id
);
1247 WARN_ON(frame
->exp_id
> ATOMISP_MAX_EXP_ID
);
1250 if (asd
->params
.css_update_params_needed
) {
1251 atomisp_apply_css_parameters(asd
,
1252 &asd
->params
.css_param
);
1253 if (asd
->params
.css_param
.update_flag
.dz_config
)
1254 atomisp_css_set_dz_config(asd
,
1255 &asd
->params
.css_param
.dz_config
);
1256 /* New global dvs 6axis config should be blocked
1257 * here if there's a buffer with per-frame parameters
1258 * pending in CSS frame buffer queue.
1259 * This is to aviod zooming vibration since global
1260 * parameters take effect immediately while
1261 * per-frame parameters are taken after previous
1262 * buffers in CSS got processed.
1264 if (asd
->params
.dvs_6axis
)
1265 atomisp_css_set_dvs_6axis(asd
,
1266 asd
->params
.dvs_6axis
);
1268 asd
->params
.css_update_params_needed
= false;
1269 /* The update flag should not be cleaned here
1270 * since it is still going to be used to make up
1271 * following per-frame parameters.
1272 * This will introduce more copy work since each
1273 * time when updating global parameters, the whole
1274 * parameter set are applied.
1275 * FIXME: A new set of parameter copy functions can
1276 * be added to make up per-frame parameters based on
1277 * solid structures stored in asd->params.css_param
1278 * instead of using shadow pointers in update flag.
1280 atomisp_css_update_isp_params(asd
);
1287 get_buf_timestamp(&vb
->ts
);
1288 vb
->field_count
= atomic_read(&asd
->sequence
) << 1;
1289 /*mark videobuffer done for dequeue*/
1290 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
1291 vb
->state
= !error
? VIDEOBUF_DONE
: VIDEOBUF_ERROR
;
1292 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
1295 * Frame capture done, wake up any process block on
1296 * current active buffer
1297 * possibly hold by videobuf_dqbuf()
1304 atomic_set(&pipe
->wdt_count
, 0);
1307 * Requeue should only be done for 3a and dis buffers.
1308 * Queue/dequeue order will change if driver recycles image buffers.
1311 err
= atomisp_css_queue_buffer(asd
,
1312 stream_id
, css_pipe_id
,
1315 dev_err(isp
->dev
, "%s, q to css fails: %d\n",
1319 if (!error
&& q_buffers
)
1320 atomisp_qbuffers_to_css(asd
);
1323 /* If there are no buffers queued then
1324 * delete wdt timer. */
1325 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
1327 if (!atomisp_buffers_queued_pipe(pipe
))
1328 atomisp_wdt_stop_pipe(pipe
, false);
1329 else if (reset_wdt_timer
)
1330 /* SOF irq should not reset wdt timer. */
1331 atomisp_wdt_refresh_pipe(pipe
,
1332 ATOMISP_WDT_KEEP_CURRENT_DELAY
);
1336 void atomisp_delayed_init_work(struct work_struct
*work
)
1338 struct atomisp_sub_device
*asd
= container_of(work
,
1339 struct atomisp_sub_device
,
1342 * to SOC camera, use yuvpp pipe and no support continuous mode.
1344 if (!ATOMISP_USE_YUVPP(asd
)) {
1345 struct v4l2_event event
= {0};
1347 atomisp_css_allocate_continuous_frames(false, asd
);
1348 atomisp_css_update_continuous_frames(asd
);
1350 event
.type
= V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE
;
1351 v4l2_event_queue(asd
->subdev
.devnode
, &event
);
1354 /* signal streamon after delayed init is done */
1355 asd
->delayed_init
= ATOMISP_DELAYED_INIT_DONE
;
1356 complete(&asd
->init_done
);
1359 static void __atomisp_css_recover(struct atomisp_device
*isp
, bool isp_timeout
)
1361 enum atomisp_css_pipe_id css_pipe_id
;
1362 bool stream_restart
[MAX_STREAM_NUM
] = {0};
1363 bool depth_mode
= false;
1364 int i
, ret
, depth_cnt
= 0;
1366 if (!isp
->sw_contex
.file_input
)
1367 atomisp_css_irq_enable(isp
,
1368 CSS_IRQ_INFO_CSS_RECEIVER_SOF
, false);
1370 BUG_ON(isp
->num_of_streams
> MAX_STREAM_NUM
);
1372 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1373 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1374 struct ia_css_pipeline
*acc_pipeline
;
1375 struct ia_css_pipe
*acc_pipe
= NULL
;
1377 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
&&
1378 !asd
->stream_prepared
)
1382 * AtomISP::waitStageUpdate is blocked when WDT happens.
1383 * By calling acc_done() for all loaded fw_handles,
1384 * HAL will be unblocked.
1386 acc_pipe
= asd
->stream_env
[i
].pipes
[CSS_PIPE_ID_ACC
];
1387 if (acc_pipe
!= NULL
) {
1388 acc_pipeline
= ia_css_pipe_get_pipeline(acc_pipe
);
1390 struct ia_css_pipeline_stage
*stage
;
1391 for (stage
= acc_pipeline
->stages
; stage
;
1392 stage
= stage
->next
) {
1393 const struct ia_css_fw_info
*fw
;
1394 fw
= stage
->firmware
;
1395 atomisp_acc_done(asd
, fw
->handle
);
1402 if (asd
->delayed_init
== ATOMISP_DELAYED_INIT_QUEUED
)
1403 cancel_work_sync(&asd
->delayed_init_work
);
1405 complete(&asd
->init_done
);
1406 asd
->delayed_init
= ATOMISP_DELAYED_INIT_NOT_QUEUED
;
1408 stream_restart
[asd
->index
] = true;
1410 asd
->streaming
= ATOMISP_DEVICE_STREAMING_STOPPING
;
1412 /* stream off sensor */
1413 ret
= v4l2_subdev_call(
1414 isp
->inputs
[asd
->input_curr
].
1415 camera
, video
, s_stream
, 0);
1418 "can't stop streaming on sensor!\n");
1420 atomisp_acc_unload_extensions(asd
);
1422 atomisp_clear_css_buffer_counters(asd
);
1424 css_pipe_id
= atomisp_get_css_pipe_id(asd
);
1425 atomisp_css_stop(asd
, css_pipe_id
, true);
1427 asd
->streaming
= ATOMISP_DEVICE_STREAMING_DISABLED
;
1429 asd
->preview_exp_id
= 1;
1430 asd
->postview_exp_id
= 1;
1431 /* notify HAL the CSS reset */
1433 "send reset event to %s\n", asd
->subdev
.devnode
->name
);
1434 atomisp_reset_event(asd
);
1438 enable_isp_irq(hrt_isp_css_irq_sp
, false);
1439 clear_isp_irq(hrt_isp_css_irq_sp
);
1441 /* Set the SRSE to 3 before resetting */
1442 pci_write_config_dword(isp
->pdev
, PCI_I_CONTROL
, isp
->saved_regs
.i_control
|
1443 MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK
);
1445 /* reset ISP and restore its state */
1446 isp
->isp_timeout
= true;
1448 isp
->isp_timeout
= false;
1451 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1452 if (isp
->asd
[i
].depth_mode
->val
)
1457 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1458 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1460 if (!stream_restart
[i
])
1463 if (isp
->inputs
[asd
->input_curr
].type
!= FILE_INPUT
)
1464 atomisp_css_input_set_mode(asd
,
1465 CSS_INPUT_MODE_SENSOR
);
1467 css_pipe_id
= atomisp_get_css_pipe_id(asd
);
1468 if (atomisp_css_start(asd
, css_pipe_id
, true))
1470 "start SP failed, so do not set streaming to be enable!\n");
1472 asd
->streaming
= ATOMISP_DEVICE_STREAMING_ENABLED
;
1474 atomisp_csi2_configure(asd
);
1477 if (!isp
->sw_contex
.file_input
) {
1478 atomisp_css_irq_enable(isp
, CSS_IRQ_INFO_CSS_RECEIVER_SOF
,
1479 atomisp_css_valid_sof(isp
));
1481 if (atomisp_freq_scaling(isp
, ATOMISP_DFS_MODE_AUTO
, true) < 0)
1482 dev_dbg(isp
->dev
, "dfs failed!\n");
1484 if (atomisp_freq_scaling(isp
, ATOMISP_DFS_MODE_MAX
, true) < 0)
1485 dev_dbg(isp
->dev
, "dfs failed!\n");
1488 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1489 struct atomisp_sub_device
*asd
;
1493 if (!stream_restart
[i
])
1496 if (asd
->continuous_mode
->val
&&
1497 asd
->delayed_init
== ATOMISP_DELAYED_INIT_NOT_QUEUED
) {
1498 reinit_completion(&asd
->init_done
);
1499 asd
->delayed_init
= ATOMISP_DELAYED_INIT_QUEUED
;
1500 queue_work(asd
->delayed_init_workq
,
1501 &asd
->delayed_init_work
);
1504 * dequeueing buffers is not needed. CSS will recycle
1505 * buffers that it has.
1507 atomisp_flush_bufs_and_wakeup(asd
);
1509 /* Requeue unprocessed per-frame parameters. */
1510 atomisp_recover_params_queue(&asd
->video_out_capture
);
1511 atomisp_recover_params_queue(&asd
->video_out_preview
);
1512 atomisp_recover_params_queue(&asd
->video_out_video_capture
);
1514 if ((asd
->depth_mode
->val
) &&
1515 (depth_cnt
== ATOMISP_DEPTH_SENSOR_STREAMON_COUNT
)) {
1520 ret
= v4l2_subdev_call(
1521 isp
->inputs
[asd
->input_curr
].camera
, video
,
1525 "can't start streaming on sensor!\n");
1530 if (atomisp_stream_on_master_slave_sensor(isp
, true))
1532 "master slave sensor stream on failed!\n");
1536 void atomisp_wdt_work(struct work_struct
*work
)
1538 struct atomisp_device
*isp
= container_of(work
, struct atomisp_device
,
1542 unsigned int pipe_wdt_cnt
[MAX_STREAM_NUM
][4] = { {0} };
1543 bool css_recover
= true;
1546 rt_mutex_lock(&isp
->mutex
);
1547 if (!atomisp_streaming_count(isp
)) {
1548 atomic_set(&isp
->wdt_work_queued
, 0);
1549 rt_mutex_unlock(&isp
->mutex
);
1554 dev_err(isp
->dev
, "timeout %d of %d\n",
1555 atomic_read(&isp
->wdt_count
) + 1,
1556 ATOMISP_ISP_MAX_TIMEOUT_COUNT
);
1558 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1559 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1560 pipe_wdt_cnt
[i
][0] +=
1561 atomic_read(&asd
->video_out_capture
.wdt_count
);
1562 pipe_wdt_cnt
[i
][1] +=
1563 atomic_read(&asd
->video_out_vf
.wdt_count
);
1564 pipe_wdt_cnt
[i
][2] +=
1565 atomic_read(&asd
->video_out_preview
.wdt_count
);
1566 pipe_wdt_cnt
[i
][3] +=
1567 atomic_read(&asd
->video_out_video_capture
.wdt_count
);
1569 (pipe_wdt_cnt
[i
][0] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT
&&
1570 pipe_wdt_cnt
[i
][1] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT
&&
1571 pipe_wdt_cnt
[i
][2] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT
&&
1572 pipe_wdt_cnt
[i
][3] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT
)
1574 dev_err(isp
->dev
, "pipe on asd%d timeout cnt: (%d, %d, %d, %d) of %d, recover = %d\n",
1575 asd
->index
, pipe_wdt_cnt
[i
][0], pipe_wdt_cnt
[i
][1],
1576 pipe_wdt_cnt
[i
][2], pipe_wdt_cnt
[i
][3],
1577 ATOMISP_ISP_MAX_TIMEOUT_COUNT
, css_recover
);
1582 if (atomic_inc_return(&isp
->wdt_count
) <
1583 ATOMISP_ISP_MAX_TIMEOUT_COUNT
) {
1587 unsigned int old_dbglevel
= dbg_level
;
1588 atomisp_css_debug_dump_sp_sw_debug_info();
1589 atomisp_css_debug_dump_debug_info(__func__
);
1590 dbg_level
= old_dbglevel
;
1591 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1592 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1594 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
1596 dev_err(isp
->dev
, "%s, vdev %s buffers in css: %d\n",
1598 asd
->video_out_capture
.vdev
.name
,
1599 asd
->video_out_capture
.
1602 "%s, vdev %s buffers in css: %d\n",
1604 asd
->video_out_vf
.vdev
.name
,
1608 "%s, vdev %s buffers in css: %d\n",
1610 asd
->video_out_preview
.vdev
.name
,
1611 asd
->video_out_preview
.
1614 "%s, vdev %s buffers in css: %d\n",
1616 asd
->video_out_video_capture
.vdev
.name
,
1617 asd
->video_out_video_capture
.
1620 "%s, s3a buffers in css preview pipe:%d\n",
1622 asd
->s3a_bufs_in_css
[CSS_PIPE_ID_PREVIEW
]);
1624 "%s, s3a buffers in css capture pipe:%d\n",
1626 asd
->s3a_bufs_in_css
[CSS_PIPE_ID_CAPTURE
]);
1628 "%s, s3a buffers in css video pipe:%d\n",
1630 asd
->s3a_bufs_in_css
[CSS_PIPE_ID_VIDEO
]);
1632 "%s, dis buffers in css: %d\n",
1633 __func__
, asd
->dis_bufs_in_css
);
1635 "%s, metadata buffers in css preview pipe:%d\n",
1637 asd
->metadata_bufs_in_css
1638 [ATOMISP_INPUT_STREAM_GENERAL
]
1639 [CSS_PIPE_ID_PREVIEW
]);
1641 "%s, metadata buffers in css capture pipe:%d\n",
1643 asd
->metadata_bufs_in_css
1644 [ATOMISP_INPUT_STREAM_GENERAL
]
1645 [CSS_PIPE_ID_CAPTURE
]);
1647 "%s, metadata buffers in css video pipe:%d\n",
1649 asd
->metadata_bufs_in_css
1650 [ATOMISP_INPUT_STREAM_GENERAL
]
1651 [CSS_PIPE_ID_VIDEO
]);
1652 if (asd
->enable_raw_buffer_lock
->val
) {
1655 dev_err(isp
->dev
, "%s, raw_buffer_locked_count %d\n",
1656 __func__
, asd
->raw_buffer_locked_count
);
1657 for (j
= 0; j
<= ATOMISP_MAX_EXP_ID
/32; j
++)
1658 dev_err(isp
->dev
, "%s, raw_buffer_bitmap[%d]: 0x%x\n",
1660 asd
->raw_buffer_bitmap
[j
]);
1664 /*sh_css_dump_sp_state();*/
1665 /*sh_css_dump_isp_state();*/
1667 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1668 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1669 if (asd
->streaming
==
1670 ATOMISP_DEVICE_STREAMING_ENABLED
) {
1671 atomisp_clear_css_buffer_counters(asd
);
1672 atomisp_flush_bufs_and_wakeup(asd
);
1673 complete(&asd
->init_done
);
1676 atomisp_wdt_stop(asd
, false);
1681 atomic_set(&isp
->wdt_count
, 0);
1683 isp
->isp_fatal_error
= true;
1684 atomic_set(&isp
->wdt_work_queued
, 0);
1686 rt_mutex_unlock(&isp
->mutex
);
1690 __atomisp_css_recover(isp
, true);
1692 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1693 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1694 if (asd
->streaming
==
1695 ATOMISP_DEVICE_STREAMING_ENABLED
) {
1696 atomisp_wdt_refresh(asd
,
1697 isp
->sw_contex
.file_input
?
1698 ATOMISP_ISP_FILE_TIMEOUT_DURATION
:
1699 ATOMISP_ISP_TIMEOUT_DURATION
);
1703 atomisp_set_stop_timeout(ATOMISP_CSS_STOP_TIMEOUT_US
);
1704 dev_err(isp
->dev
, "timeout recovery handling done\n");
1705 atomic_set(&isp
->wdt_work_queued
, 0);
1707 rt_mutex_unlock(&isp
->mutex
);
1710 void atomisp_css_flush(struct atomisp_device
*isp
)
1714 if (!atomisp_streaming_count(isp
))
1718 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1719 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1720 atomisp_wdt_stop(asd
, true);
1724 __atomisp_css_recover(isp
, false);
1726 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1727 struct atomisp_sub_device
*asd
= &isp
->asd
[i
];
1729 if (asd
->streaming
!=
1730 ATOMISP_DEVICE_STREAMING_ENABLED
)
1733 atomisp_wdt_refresh(asd
,
1734 isp
->sw_contex
.file_input
?
1735 ATOMISP_ISP_FILE_TIMEOUT_DURATION
:
1736 ATOMISP_ISP_TIMEOUT_DURATION
);
1738 dev_dbg(isp
->dev
, "atomisp css flush done\n");
1742 void atomisp_wdt(unsigned long isp_addr
)
1744 void atomisp_wdt(unsigned long pipe_addr
)
1748 struct atomisp_device
*isp
= (struct atomisp_device
*)isp_addr
;
1750 struct atomisp_video_pipe
*pipe
=
1751 (struct atomisp_video_pipe
*)pipe_addr
;
1752 struct atomisp_sub_device
*asd
= pipe
->asd
;
1753 struct atomisp_device
*isp
= asd
->isp
;
1757 atomic_inc(&pipe
->wdt_count
);
1759 "[WARNING]asd %d pipe %s ISP timeout %d!\n",
1760 asd
->index
, pipe
->vdev
.name
,
1761 atomic_read(&pipe
->wdt_count
));
1763 if (atomic_read(&isp
->wdt_work_queued
)) {
1764 dev_dbg(isp
->dev
, "ISP watchdog was put into workqueue\n");
1767 atomic_set(&isp
->wdt_work_queued
, 1);
1768 queue_work(isp
->wdt_work_queue
, &isp
->wdt_work
);
1772 void atomisp_wdt_refresh(struct atomisp_sub_device
*asd
, unsigned int delay
)
1774 void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe
*pipe
,
1780 if (delay
!= ATOMISP_WDT_KEEP_CURRENT_DELAY
)
1782 asd
->wdt_duration
= delay
;
1784 pipe
->wdt_duration
= delay
;
1788 next
= jiffies
+ asd
->wdt_duration
;
1790 next
= jiffies
+ pipe
->wdt_duration
;
1793 /* Override next if it has been pushed beyon the "next" time */
1795 if (atomisp_is_wdt_running(asd
) && time_after(asd
->wdt_expires
, next
))
1796 next
= asd
->wdt_expires
;
1798 if (atomisp_is_wdt_running(pipe
) && time_after(pipe
->wdt_expires
, next
))
1799 next
= pipe
->wdt_expires
;
1803 asd
->wdt_expires
= next
;
1805 pipe
->wdt_expires
= next
;
1809 if (atomisp_is_wdt_running(asd
))
1810 dev_dbg(asd
->isp
->dev
, "WDT will hit after %d ms\n",
1811 ((int)(next
- jiffies
) * 1000 / HZ
));
1813 if (atomisp_is_wdt_running(pipe
))
1814 dev_dbg(pipe
->asd
->isp
->dev
, "WDT will hit after %d ms (%s)\n",
1815 ((int)(next
- jiffies
) * 1000 / HZ
), pipe
->vdev
.name
);
1819 dev_dbg(asd
->isp
->dev
, "WDT starts with %d ms period\n",
1820 ((int)(next
- jiffies
) * 1000 / HZ
));
1822 dev_dbg(pipe
->asd
->isp
->dev
, "WDT starts with %d ms period (%s)\n",
1823 ((int)(next
- jiffies
) * 1000 / HZ
), pipe
->vdev
.name
);
1827 mod_timer(&asd
->wdt
, next
);
1828 atomic_set(&asd
->isp
->wdt_count
, 0);
1830 mod_timer(&pipe
->wdt
, next
);
1835 void atomisp_wdt_stop(struct atomisp_sub_device
*asd
, bool sync
)
1837 void atomisp_wdt_refresh(struct atomisp_sub_device
*asd
, unsigned int delay
)
1839 dev_dbg(asd
->isp
->dev
, "WDT refresh all:\n");
1840 if (atomisp_is_wdt_running(&asd
->video_out_capture
))
1841 atomisp_wdt_refresh_pipe(&asd
->video_out_capture
, delay
);
1842 if (atomisp_is_wdt_running(&asd
->video_out_preview
))
1843 atomisp_wdt_refresh_pipe(&asd
->video_out_preview
, delay
);
1844 if (atomisp_is_wdt_running(&asd
->video_out_vf
))
1845 atomisp_wdt_refresh_pipe(&asd
->video_out_vf
, delay
);
1846 if (atomisp_is_wdt_running(&asd
->video_out_video_capture
))
1847 atomisp_wdt_refresh_pipe(&asd
->video_out_video_capture
, delay
);
1851 void atomisp_wdt_stop_pipe(struct atomisp_video_pipe
*pipe
, bool sync
)
1855 dev_dbg(asd
->isp
->dev
, "WDT stop\n");
1857 if (!atomisp_is_wdt_running(pipe
))
1860 dev_dbg(pipe
->asd
->isp
->dev
,
1861 "WDT stop asd %d (%s)\n", pipe
->asd
->index
, pipe
->vdev
.name
);
1866 del_timer_sync(&asd
->wdt
);
1867 cancel_work_sync(&asd
->isp
->wdt_work
);
1869 del_timer_sync(&pipe
->wdt
);
1870 cancel_work_sync(&pipe
->asd
->isp
->wdt_work
);
1874 del_timer(&asd
->wdt
);
1876 del_timer(&pipe
->wdt
);
1882 void atomisp_wdt_start(struct atomisp_sub_device
*asd
)
1884 void atomisp_wdt_stop(struct atomisp_sub_device
*asd
, bool sync
)
1886 dev_dbg(asd
->isp
->dev
, "WDT stop all:\n");
1887 atomisp_wdt_stop_pipe(&asd
->video_out_capture
, sync
);
1888 atomisp_wdt_stop_pipe(&asd
->video_out_preview
, sync
);
1889 atomisp_wdt_stop_pipe(&asd
->video_out_vf
, sync
);
1890 atomisp_wdt_stop_pipe(&asd
->video_out_video_capture
, sync
);
1893 void atomisp_wdt_start(struct atomisp_video_pipe
*pipe
)
1897 atomisp_wdt_refresh(asd
, ATOMISP_ISP_TIMEOUT_DURATION
);
1899 atomisp_wdt_refresh_pipe(pipe
, ATOMISP_ISP_TIMEOUT_DURATION
);
1903 void atomisp_setup_flash(struct atomisp_sub_device
*asd
)
1905 struct atomisp_device
*isp
= asd
->isp
;
1906 struct v4l2_control ctrl
;
1908 if (isp
->flash
== NULL
)
1911 if (asd
->params
.flash_state
!= ATOMISP_FLASH_REQUESTED
&&
1912 asd
->params
.flash_state
!= ATOMISP_FLASH_DONE
)
1915 if (asd
->params
.num_flash_frames
) {
1916 /* make sure the timeout is set before setting flash mode */
1917 ctrl
.id
= V4L2_CID_FLASH_TIMEOUT
;
1918 ctrl
.value
= FLASH_TIMEOUT
;
1920 if (v4l2_s_ctrl(NULL
, isp
->flash
->ctrl_handler
, &ctrl
)) {
1921 dev_err(isp
->dev
, "flash timeout configure failed\n");
1925 atomisp_css_request_flash(asd
);
1926 asd
->params
.flash_state
= ATOMISP_FLASH_ONGOING
;
1928 asd
->params
.flash_state
= ATOMISP_FLASH_IDLE
;
1932 irqreturn_t
atomisp_isr_thread(int irq
, void *isp_ptr
)
1934 struct atomisp_device
*isp
= isp_ptr
;
1935 unsigned long flags
;
1936 bool frame_done_found
[MAX_STREAM_NUM
] = {0};
1937 bool css_pipe_done
[MAX_STREAM_NUM
] = {0};
1939 struct atomisp_sub_device
*asd
= &isp
->asd
[0];
1941 dev_dbg(isp
->dev
, ">%s\n", __func__
);
1943 spin_lock_irqsave(&isp
->lock
, flags
);
1945 if (!atomisp_streaming_count(isp
) && !atomisp_is_acc_enabled(isp
)) {
1946 spin_unlock_irqrestore(&isp
->lock
, flags
);
1950 spin_unlock_irqrestore(&isp
->lock
, flags
);
1953 * The standard CSS2.0 API tells the following calling sequence of
1954 * dequeue ready buffers:
1955 * while (ia_css_dequeue_event(...)) {
1956 * switch (event.type) {
1958 * ia_css_pipe_dequeue_buffer()
1961 * That is, dequeue event and buffer are one after another.
1963 * But the following implementation is to first deuque all the event
1964 * to a FIFO, then process the event in the FIFO.
1965 * This will not have issue in single stream mode, but it do have some
1966 * issue in multiple stream case. The issue is that
1967 * ia_css_pipe_dequeue_buffer() will not return the corrent buffer in
1970 * This is due to ia_css_pipe_dequeue_buffer() does not take the
1971 * ia_css_pipe parameter.
1974 * For CSS2.0: we change the way to not dequeue all the event at one
1975 * time, instead, dequue one and process one, then another
1977 rt_mutex_lock(&isp
->mutex
);
1978 if (atomisp_css_isr_thread(isp
, frame_done_found
, css_pipe_done
))
1981 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1983 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
1985 atomisp_setup_flash(asd
);
1989 rt_mutex_unlock(&isp
->mutex
);
1990 for (i
= 0; i
< isp
->num_of_streams
; i
++) {
1992 if (asd
->streaming
== ATOMISP_DEVICE_STREAMING_ENABLED
1993 && css_pipe_done
[asd
->index
]
1994 && isp
->sw_contex
.file_input
)
1995 v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
1996 video
, s_stream
, 1);
1997 /* FIXME! FIX ACC implementation */
1998 if (asd
->acc
.pipeline
&& css_pipe_done
[asd
->index
])
1999 atomisp_css_acc_done(asd
);
2001 dev_dbg(isp
->dev
, "<%s\n", __func__
);
2007 * utils for buffer allocation/free
2010 int atomisp_get_frame_pgnr(struct atomisp_device
*isp
,
2011 const struct atomisp_css_frame
*frame
, u32
*p_pgnr
)
2014 dev_err(isp
->dev
, "%s: NULL frame pointer ERROR.\n", __func__
);
2018 *p_pgnr
= DIV_ROUND_UP(frame
->data_bytes
, PAGE_SIZE
);
2023 * Get internal fmt according to V4L2 fmt
2025 static enum atomisp_css_frame_format
2026 v4l2_fmt_to_sh_fmt(u32 fmt
)
2029 case V4L2_PIX_FMT_YUV420
:
2030 return CSS_FRAME_FORMAT_YUV420
;
2031 case V4L2_PIX_FMT_YVU420
:
2032 return CSS_FRAME_FORMAT_YV12
;
2033 case V4L2_PIX_FMT_YUV422P
:
2034 return CSS_FRAME_FORMAT_YUV422
;
2035 case V4L2_PIX_FMT_YUV444
:
2036 return CSS_FRAME_FORMAT_YUV444
;
2037 case V4L2_PIX_FMT_NV12
:
2038 return CSS_FRAME_FORMAT_NV12
;
2039 case V4L2_PIX_FMT_NV21
:
2040 return CSS_FRAME_FORMAT_NV21
;
2041 case V4L2_PIX_FMT_NV16
:
2042 return CSS_FRAME_FORMAT_NV16
;
2043 case V4L2_PIX_FMT_NV61
:
2044 return CSS_FRAME_FORMAT_NV61
;
2045 case V4L2_PIX_FMT_UYVY
:
2046 return CSS_FRAME_FORMAT_UYVY
;
2047 case V4L2_PIX_FMT_YUYV
:
2048 return CSS_FRAME_FORMAT_YUYV
;
2049 case V4L2_PIX_FMT_RGB24
:
2050 return CSS_FRAME_FORMAT_PLANAR_RGB888
;
2051 case V4L2_PIX_FMT_RGB32
:
2052 return CSS_FRAME_FORMAT_RGBA888
;
2053 case V4L2_PIX_FMT_RGB565
:
2054 return CSS_FRAME_FORMAT_RGB565
;
2055 case V4L2_PIX_FMT_JPEG
:
2056 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW
:
2057 return CSS_FRAME_FORMAT_BINARY_8
;
2058 case V4L2_PIX_FMT_SBGGR16
:
2059 case V4L2_PIX_FMT_SBGGR10
:
2060 case V4L2_PIX_FMT_SGBRG10
:
2061 case V4L2_PIX_FMT_SGRBG10
:
2062 case V4L2_PIX_FMT_SRGGB10
:
2063 case V4L2_PIX_FMT_SBGGR12
:
2064 case V4L2_PIX_FMT_SGBRG12
:
2065 case V4L2_PIX_FMT_SGRBG12
:
2066 case V4L2_PIX_FMT_SRGGB12
:
2067 case V4L2_PIX_FMT_SBGGR8
:
2068 case V4L2_PIX_FMT_SGBRG8
:
2069 case V4L2_PIX_FMT_SGRBG8
:
2070 case V4L2_PIX_FMT_SRGGB8
:
2071 return CSS_FRAME_FORMAT_RAW
;
2077 * raw format match between SH format and V4L2 format
2079 static int raw_output_format_match_input(u32 input
, u32 output
)
2081 if ((input
== CSS_FORMAT_RAW_12
) &&
2082 ((output
== V4L2_PIX_FMT_SRGGB12
) ||
2083 (output
== V4L2_PIX_FMT_SGRBG12
) ||
2084 (output
== V4L2_PIX_FMT_SBGGR12
) ||
2085 (output
== V4L2_PIX_FMT_SGBRG12
)))
2088 if ((input
== CSS_FORMAT_RAW_10
) &&
2089 ((output
== V4L2_PIX_FMT_SRGGB10
) ||
2090 (output
== V4L2_PIX_FMT_SGRBG10
) ||
2091 (output
== V4L2_PIX_FMT_SBGGR10
) ||
2092 (output
== V4L2_PIX_FMT_SGBRG10
)))
2095 if ((input
== CSS_FORMAT_RAW_8
) &&
2096 ((output
== V4L2_PIX_FMT_SRGGB8
) ||
2097 (output
== V4L2_PIX_FMT_SGRBG8
) ||
2098 (output
== V4L2_PIX_FMT_SBGGR8
) ||
2099 (output
== V4L2_PIX_FMT_SGBRG8
)))
2102 if ((input
== CSS_FORMAT_RAW_16
) && (output
== V4L2_PIX_FMT_SBGGR16
))
2108 static u32
get_pixel_depth(u32 pixelformat
)
2110 switch (pixelformat
) {
2111 case V4L2_PIX_FMT_YUV420
:
2112 case V4L2_PIX_FMT_NV12
:
2113 case V4L2_PIX_FMT_NV21
:
2114 case V4L2_PIX_FMT_YVU420
:
2116 case V4L2_PIX_FMT_YUV422P
:
2117 case V4L2_PIX_FMT_YUYV
:
2118 case V4L2_PIX_FMT_UYVY
:
2119 case V4L2_PIX_FMT_NV16
:
2120 case V4L2_PIX_FMT_NV61
:
2121 case V4L2_PIX_FMT_RGB565
:
2122 case V4L2_PIX_FMT_SBGGR16
:
2123 case V4L2_PIX_FMT_SBGGR12
:
2124 case V4L2_PIX_FMT_SGBRG12
:
2125 case V4L2_PIX_FMT_SGRBG12
:
2126 case V4L2_PIX_FMT_SRGGB12
:
2127 case V4L2_PIX_FMT_SBGGR10
:
2128 case V4L2_PIX_FMT_SGBRG10
:
2129 case V4L2_PIX_FMT_SGRBG10
:
2130 case V4L2_PIX_FMT_SRGGB10
:
2132 case V4L2_PIX_FMT_RGB24
:
2133 case V4L2_PIX_FMT_YUV444
:
2135 case V4L2_PIX_FMT_RGB32
:
2137 case V4L2_PIX_FMT_JPEG
:
2138 case V4L2_PIX_FMT_CUSTOM_M10MO_RAW
:
2139 case V4L2_PIX_FMT_SBGGR8
:
2140 case V4L2_PIX_FMT_SGBRG8
:
2141 case V4L2_PIX_FMT_SGRBG8
:
2142 case V4L2_PIX_FMT_SRGGB8
:
2145 return 8 * 2; /* raw type now */
2149 bool atomisp_is_mbuscode_raw(uint32_t code
)
2151 return code
>= 0x3000 && code
< 0x4000;
2155 * ISP features control function
2159 * Set ISP capture mode based on current settings
2161 static void atomisp_update_capture_mode(struct atomisp_sub_device
*asd
)
2163 if (asd
->params
.gdc_cac_en
)
2164 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_ADVANCED
);
2165 else if (asd
->params
.low_light
)
2166 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_LOW_LIGHT
);
2167 else if (asd
->video_out_capture
.sh_fmt
== CSS_FRAME_FORMAT_RAW
)
2168 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_RAW
);
2170 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_PRIMARY
);
2174 int atomisp_set_sensor_runmode(struct atomisp_sub_device
*asd
,
2175 struct atomisp_s_runmode
*runmode
)
2177 struct atomisp_device
*isp
= asd
->isp
;
2178 struct v4l2_ctrl
*c
;
2179 struct v4l2_streamparm p
= {0};
2181 int modes
[] = { CI_MODE_NONE
,
2183 CI_MODE_STILL_CAPTURE
,
2187 if (!(runmode
&& (runmode
->mode
& RUNMODE_MASK
)))
2190 mutex_lock(asd
->ctrl_handler
.lock
);
2191 c
= v4l2_ctrl_find(isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
,
2195 ret
= v4l2_ctrl_s_ctrl(c
, runmode
->mode
);
2197 p
.parm
.capture
.capturemode
= modes
[runmode
->mode
];
2198 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
2202 mutex_unlock(asd
->ctrl_handler
.lock
);
2208 * Function to enable/disable lens geometry distortion correction (GDC) and
2209 * chromatic aberration correction (CAC)
2211 int atomisp_gdc_cac(struct atomisp_sub_device
*asd
, int flag
,
2215 *value
= asd
->params
.gdc_cac_en
;
2219 asd
->params
.gdc_cac_en
= !!*value
;
2220 if (asd
->params
.gdc_cac_en
) {
2221 atomisp_css_set_morph_table(asd
,
2222 asd
->params
.css_param
.morph_table
);
2224 atomisp_css_set_morph_table(asd
, NULL
);
2226 asd
->params
.css_update_params_needed
= true;
2227 atomisp_update_capture_mode(asd
);
2232 * Function to enable/disable low light mode including ANR
2234 int atomisp_low_light(struct atomisp_sub_device
*asd
, int flag
,
2238 *value
= asd
->params
.low_light
;
2242 asd
->params
.low_light
= (*value
!= 0);
2243 atomisp_update_capture_mode(asd
);
2248 * Function to enable/disable extra noise reduction (XNR) in low light
2251 int atomisp_xnr(struct atomisp_sub_device
*asd
, int flag
,
2255 *xnr_enable
= asd
->params
.xnr_en
;
2259 atomisp_css_capture_enable_xnr(asd
, !!*xnr_enable
);
2265 * Function to configure bayer noise reduction
2267 int atomisp_nr(struct atomisp_sub_device
*asd
, int flag
,
2268 struct atomisp_nr_config
*arg
)
2271 /* Get nr config from current setup */
2272 if (atomisp_css_get_nr_config(asd
, arg
))
2275 /* Set nr config to isp parameters */
2276 memcpy(&asd
->params
.css_param
.nr_config
, arg
,
2277 sizeof(struct atomisp_css_nr_config
));
2278 atomisp_css_set_nr_config(asd
, &asd
->params
.css_param
.nr_config
);
2279 asd
->params
.css_update_params_needed
= true;
2285 * Function to configure temporal noise reduction (TNR)
2287 int atomisp_tnr(struct atomisp_sub_device
*asd
, int flag
,
2288 struct atomisp_tnr_config
*config
)
2290 /* Get tnr config from current setup */
2292 /* Get tnr config from current setup */
2293 if (atomisp_css_get_tnr_config(asd
, config
))
2296 /* Set tnr config to isp parameters */
2297 memcpy(&asd
->params
.css_param
.tnr_config
, config
,
2298 sizeof(struct atomisp_css_tnr_config
));
2299 atomisp_css_set_tnr_config(asd
, &asd
->params
.css_param
.tnr_config
);
2300 asd
->params
.css_update_params_needed
= true;
2307 * Function to configure black level compensation
2309 int atomisp_black_level(struct atomisp_sub_device
*asd
, int flag
,
2310 struct atomisp_ob_config
*config
)
2313 /* Get ob config from current setup */
2314 if (atomisp_css_get_ob_config(asd
, config
))
2317 /* Set ob config to isp parameters */
2318 memcpy(&asd
->params
.css_param
.ob_config
, config
,
2319 sizeof(struct atomisp_css_ob_config
));
2320 atomisp_css_set_ob_config(asd
, &asd
->params
.css_param
.ob_config
);
2321 asd
->params
.css_update_params_needed
= true;
2328 * Function to configure edge enhancement
2330 int atomisp_ee(struct atomisp_sub_device
*asd
, int flag
,
2331 struct atomisp_ee_config
*config
)
2334 /* Get ee config from current setup */
2335 if (atomisp_css_get_ee_config(asd
, config
))
2338 /* Set ee config to isp parameters */
2339 memcpy(&asd
->params
.css_param
.ee_config
, config
,
2340 sizeof(asd
->params
.css_param
.ee_config
));
2341 atomisp_css_set_ee_config(asd
, &asd
->params
.css_param
.ee_config
);
2342 asd
->params
.css_update_params_needed
= true;
2349 * Function to update Gamma table for gamma, brightness and contrast config
2351 int atomisp_gamma(struct atomisp_sub_device
*asd
, int flag
,
2352 struct atomisp_gamma_table
*config
)
2355 /* Get gamma table from current setup */
2356 if (atomisp_css_get_gamma_table(asd
, config
))
2359 /* Set gamma table to isp parameters */
2360 memcpy(&asd
->params
.css_param
.gamma_table
, config
,
2361 sizeof(asd
->params
.css_param
.gamma_table
));
2362 atomisp_css_set_gamma_table(asd
, &asd
->params
.css_param
.gamma_table
);
2369 * Function to update Ctc table for Chroma Enhancement
2371 int atomisp_ctc(struct atomisp_sub_device
*asd
, int flag
,
2372 struct atomisp_ctc_table
*config
)
2375 /* Get ctc table from current setup */
2376 if (atomisp_css_get_ctc_table(asd
, config
))
2379 /* Set ctc table to isp parameters */
2380 memcpy(&asd
->params
.css_param
.ctc_table
, config
,
2381 sizeof(asd
->params
.css_param
.ctc_table
));
2382 atomisp_css_set_ctc_table(asd
, &asd
->params
.css_param
.ctc_table
);
2389 * Function to update gamma correction parameters
2391 int atomisp_gamma_correction(struct atomisp_sub_device
*asd
, int flag
,
2392 struct atomisp_gc_config
*config
)
2395 /* Get gamma correction params from current setup */
2396 if (atomisp_css_get_gc_config(asd
, config
))
2399 /* Set gamma correction params to isp parameters */
2400 memcpy(&asd
->params
.css_param
.gc_config
, config
,
2401 sizeof(asd
->params
.css_param
.gc_config
));
2402 atomisp_css_set_gc_config(asd
, &asd
->params
.css_param
.gc_config
);
2403 asd
->params
.css_update_params_needed
= true;
2410 * Function to update narrow gamma flag
2412 int atomisp_formats(struct atomisp_sub_device
*asd
, int flag
,
2413 struct atomisp_formats_config
*config
)
2416 /* Get narrow gamma flag from current setup */
2417 if (atomisp_css_get_formats_config(asd
, config
))
2420 /* Set narrow gamma flag to isp parameters */
2421 memcpy(&asd
->params
.css_param
.formats_config
, config
,
2422 sizeof(asd
->params
.css_param
.formats_config
));
2423 atomisp_css_set_formats_config(asd
, &asd
->params
.css_param
.formats_config
);
2429 void atomisp_free_internal_buffers(struct atomisp_sub_device
*asd
)
2431 atomisp_free_css_parameters(&asd
->params
.css_param
);
2433 if (asd
->raw_output_frame
) {
2434 atomisp_css_frame_free(asd
->raw_output_frame
);
2435 asd
->raw_output_frame
= NULL
;
2439 static void atomisp_update_grid_info(struct atomisp_sub_device
*asd
,
2440 enum atomisp_css_pipe_id pipe_id
, int source_pad
)
2442 struct atomisp_device
*isp
= asd
->isp
;
2444 uint16_t stream_id
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
2446 if (atomisp_css_get_grid_info(asd
, pipe_id
, source_pad
))
2449 /* We must free all buffers because they no longer match
2451 atomisp_css_free_stat_buffers(asd
);
2453 err
= atomisp_alloc_css_stat_bufs(asd
, stream_id
);
2455 dev_err(isp
->dev
, "stat_buf allocate error\n");
2459 if (atomisp_alloc_3a_output_buf(asd
)) {
2460 /* Failure for 3A buffers does not influence DIS buffers */
2461 if (asd
->params
.s3a_output_bytes
!= 0) {
2462 /* For SOC sensor happens s3a_output_bytes == 0,
2463 * using if condition to exclude false error log */
2464 dev_err(isp
->dev
, "Failed to allocate memory for 3A statistics\n");
2469 if (atomisp_alloc_dis_coef_buf(asd
)) {
2471 "Failed to allocate memory for DIS statistics\n");
2475 if (atomisp_alloc_metadata_output_buf(asd
)) {
2476 dev_err(isp
->dev
, "Failed to allocate memory for metadata\n");
2483 atomisp_css_free_stat_buffers(asd
);
2487 static void atomisp_curr_user_grid_info(struct atomisp_sub_device
*asd
,
2488 struct atomisp_grid_info
*info
)
2490 memcpy(info
, &asd
->params
.curr_grid_info
.s3a_grid
,
2491 sizeof(struct atomisp_css_3a_grid_info
));
2494 int atomisp_compare_grid(struct atomisp_sub_device
*asd
,
2495 struct atomisp_grid_info
*atomgrid
)
2497 struct atomisp_grid_info tmp
= {0};
2499 atomisp_curr_user_grid_info(asd
, &tmp
);
2500 return memcmp(atomgrid
, &tmp
, sizeof(tmp
));
2504 * Function to update Gdc table for gdc
2506 int atomisp_gdc_cac_table(struct atomisp_sub_device
*asd
, int flag
,
2507 struct atomisp_morph_table
*config
)
2511 struct atomisp_device
*isp
= asd
->isp
;
2514 /* Get gdc table from current setup */
2515 struct atomisp_css_morph_table tab
= {0};
2516 atomisp_css_get_morph_table(asd
, &tab
);
2518 config
->width
= tab
.width
;
2519 config
->height
= tab
.height
;
2521 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
2522 ret
= copy_to_user(config
->coordinates_x
[i
],
2523 tab
.coordinates_x
[i
], tab
.height
*
2524 tab
.width
* sizeof(*tab
.coordinates_x
[i
]));
2527 "Failed to copy to User for x\n");
2530 ret
= copy_to_user(config
->coordinates_y
[i
],
2531 tab
.coordinates_y
[i
], tab
.height
*
2532 tab
.width
* sizeof(*tab
.coordinates_y
[i
]));
2535 "Failed to copy to User for y\n");
2540 struct atomisp_css_morph_table
*tab
=
2541 asd
->params
.css_param
.morph_table
;
2543 /* free first if we have one */
2545 atomisp_css_morph_table_free(tab
);
2546 asd
->params
.css_param
.morph_table
= NULL
;
2549 /* allocate new one */
2550 tab
= atomisp_css_morph_table_allocate(config
->width
,
2554 dev_err(isp
->dev
, "out of memory\n");
2558 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
2559 ret
= copy_from_user(tab
->coordinates_x
[i
],
2560 config
->coordinates_x
[i
],
2561 config
->height
* config
->width
*
2562 sizeof(*config
->coordinates_x
[i
]));
2565 "Failed to copy from User for x, ret %d\n",
2567 atomisp_css_morph_table_free(tab
);
2570 ret
= copy_from_user(tab
->coordinates_y
[i
],
2571 config
->coordinates_y
[i
],
2572 config
->height
* config
->width
*
2573 sizeof(*config
->coordinates_y
[i
]));
2576 "Failed to copy from User for y, ret is %d\n",
2578 atomisp_css_morph_table_free(tab
);
2582 asd
->params
.css_param
.morph_table
= tab
;
2583 if (asd
->params
.gdc_cac_en
)
2584 atomisp_css_set_morph_table(asd
, tab
);
2590 int atomisp_macc_table(struct atomisp_sub_device
*asd
, int flag
,
2591 struct atomisp_macc_config
*config
)
2593 struct atomisp_css_macc_table
*macc_table
;
2595 switch (config
->color_effect
) {
2596 case V4L2_COLORFX_NONE
:
2597 macc_table
= &asd
->params
.css_param
.macc_table
;
2599 case V4L2_COLORFX_SKY_BLUE
:
2600 macc_table
= &blue_macc_table
;
2602 case V4L2_COLORFX_GRASS_GREEN
:
2603 macc_table
= &green_macc_table
;
2605 case V4L2_COLORFX_SKIN_WHITEN_LOW
:
2606 macc_table
= &skin_low_macc_table
;
2608 case V4L2_COLORFX_SKIN_WHITEN
:
2609 macc_table
= &skin_medium_macc_table
;
2611 case V4L2_COLORFX_SKIN_WHITEN_HIGH
:
2612 macc_table
= &skin_high_macc_table
;
2619 /* Get macc table from current setup */
2620 memcpy(&config
->table
, macc_table
,
2621 sizeof(struct atomisp_css_macc_table
));
2623 memcpy(macc_table
, &config
->table
,
2624 sizeof(struct atomisp_css_macc_table
));
2625 if (config
->color_effect
== asd
->params
.color_effect
)
2626 atomisp_css_set_macc_table(asd
, macc_table
);
2632 int atomisp_set_dis_vector(struct atomisp_sub_device
*asd
,
2633 struct atomisp_dis_vector
*vector
)
2635 atomisp_css_video_set_dis_vector(asd
, vector
);
2637 asd
->params
.dis_proj_data_valid
= false;
2638 asd
->params
.css_update_params_needed
= true;
2643 * Function to set/get image stablization statistics
2645 int atomisp_get_dis_stat(struct atomisp_sub_device
*asd
,
2646 struct atomisp_dis_statistics
*stats
)
2648 return atomisp_css_get_dis_stat(asd
, stats
);
2652 * Function set camrea_prefiles.xml current sensor pixel array size
2654 int atomisp_set_array_res(struct atomisp_sub_device
*asd
,
2655 struct atomisp_resolution
*config
)
2657 dev_dbg(asd
->isp
->dev
, ">%s start\n", __func__
);
2658 if (config
== NULL
|| config
->width
< 0
2659 || config
->height
< 0) {
2660 dev_err(asd
->isp
->dev
, "Set sensor array size is not valid\n");
2664 asd
->sensor_array_res
.width
= config
->width
;
2665 asd
->sensor_array_res
.height
= config
->height
;
2670 * Function to get DVS2 BQ resolution settings
2672 int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device
*asd
,
2673 struct atomisp_dvs2_bq_resolutions
*bq_res
)
2675 struct ia_css_pipe_config
*pipe_cfg
= NULL
;
2676 struct ia_css_stream_config
*stream_cfg
= NULL
;
2677 struct ia_css_stream_input_config
*input_config
= NULL
;
2679 struct ia_css_stream
*stream
=
2680 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
;
2682 dev_warn(asd
->isp
->dev
, "stream is not created");
2686 pipe_cfg
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
2687 .pipe_configs
[CSS_PIPE_ID_VIDEO
];
2688 stream_cfg
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
2690 input_config
= &stream_cfg
->input_config
;
2695 /* the GDC output resolution */
2696 bq_res
->output_bq
.width_bq
= pipe_cfg
->output_info
[0].res
.width
/ 2;
2697 bq_res
->output_bq
.height_bq
= pipe_cfg
->output_info
[0].res
.height
/ 2;
2699 bq_res
->envelope_bq
.width_bq
= 0;
2700 bq_res
->envelope_bq
.height_bq
= 0;
2701 /* the GDC input resolution */
2702 if (!asd
->continuous_mode
->val
) {
2703 bq_res
->source_bq
.width_bq
= bq_res
->output_bq
.width_bq
+
2704 pipe_cfg
->dvs_envelope
.width
/ 2;
2705 bq_res
->source_bq
.height_bq
= bq_res
->output_bq
.height_bq
+
2706 pipe_cfg
->dvs_envelope
.height
/ 2;
2708 * Bad pixels caused by spatial filter processing
2709 * ISP filter resolution should be given by CSS/FW, but for now
2710 * there is not such API to query, and it is fixed value, so
2713 bq_res
->ispfilter_bq
.width_bq
= 12 / 2;
2714 bq_res
->ispfilter_bq
.height_bq
= 12 / 2;
2715 /* spatial filter shift, always 4 pixels */
2716 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2717 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2719 if (asd
->params
.video_dis_en
) {
2720 bq_res
->envelope_bq
.width_bq
= pipe_cfg
->dvs_envelope
.width
2721 / 2 - bq_res
->ispfilter_bq
.width_bq
;
2722 bq_res
->envelope_bq
.height_bq
= pipe_cfg
->dvs_envelope
.height
2723 / 2 - bq_res
->ispfilter_bq
.height_bq
;
2726 unsigned int w_padding
;
2727 unsigned int gdc_effective_input
= 0;
2730 * gdc_effective_input = effective_input + envelope
2732 * From the comment and formula in BZ1786,
2733 * we see the source_bq should be:
2734 * effective_input / bayer_ds_ratio
2736 bq_res
->source_bq
.width_bq
=
2737 (input_config
->effective_res
.width
*
2738 pipe_cfg
->bayer_ds_out_res
.width
/
2739 input_config
->effective_res
.width
+ 1) / 2;
2740 bq_res
->source_bq
.height_bq
=
2741 (input_config
->effective_res
.height
*
2742 pipe_cfg
->bayer_ds_out_res
.height
/
2743 input_config
->effective_res
.height
+ 1) / 2;
2746 if (!asd
->params
.video_dis_en
) {
2748 * We adjust the ispfilter_bq to:
2749 * ispfilter_bq = 128/BDS
2750 * we still need firmware team to provide an offical
2753 bq_res
->ispfilter_bq
.width_bq
= 128 *
2754 pipe_cfg
->bayer_ds_out_res
.width
/
2755 input_config
->effective_res
.width
/ 2;
2756 bq_res
->ispfilter_bq
.height_bq
= 128 *
2757 pipe_cfg
->bayer_ds_out_res
.width
/
2758 input_config
->effective_res
.width
/ 2;
2760 if (IS_HWREVISION(asd
->isp
, ATOMISP_HW_REVISION_ISP2401
)) {
2761 /* No additional left padding for ISYS2401 */
2762 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2763 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2766 * For the w_padding and gdc_shift_bq cacluation
2767 * Please see the BZ 1786 and 4358 for more info.
2768 * Just test that this formula can work now,
2769 * but we still have no offical formula.
2771 * w_padding = ceiling(gdc_effective_input
2772 * /128, 1) * 128 - effective_width
2773 * gdc_shift_bq = w_padding/BDS/2 + ispfilter_bq/2
2775 gdc_effective_input
=
2776 input_config
->effective_res
.width
+
2777 pipe_cfg
->dvs_envelope
.width
;
2778 w_padding
= roundup(gdc_effective_input
, 128) -
2779 input_config
->effective_res
.width
;
2780 w_padding
= w_padding
*
2781 pipe_cfg
->bayer_ds_out_res
.width
/
2782 input_config
->effective_res
.width
+ 1;
2783 w_padding
= roundup(w_padding
/2, 1);
2785 bq_res
->gdc_shift_bq
.width_bq
= bq_res
->ispfilter_bq
.width_bq
/ 2
2787 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2790 unsigned int dvs_w
, dvs_h
, dvs_w_max
, dvs_h_max
;
2792 bq_res
->ispfilter_bq
.width_bq
= 8 / 2;
2793 bq_res
->ispfilter_bq
.height_bq
= 8 / 2;
2795 if (IS_HWREVISION(asd
->isp
, ATOMISP_HW_REVISION_ISP2401
)) {
2796 /* No additional left padding for ISYS2401 */
2797 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2;
2798 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2801 roundup(input_config
->effective_res
.width
, 128) -
2802 input_config
->effective_res
.width
;
2805 bq_res
->gdc_shift_bq
.width_bq
= 4 / 2 +
2807 pipe_cfg
->bayer_ds_out_res
.width
/
2808 input_config
->effective_res
.width
+ 1) / 2;
2809 bq_res
->gdc_shift_bq
.height_bq
= 4 / 2;
2812 dvs_w
= pipe_cfg
->bayer_ds_out_res
.width
-
2813 pipe_cfg
->output_info
[0].res
.width
;
2814 dvs_h
= pipe_cfg
->bayer_ds_out_res
.height
-
2815 pipe_cfg
->output_info
[0].res
.height
;
2816 dvs_w_max
= rounddown(
2817 pipe_cfg
->output_info
[0].res
.width
/ 5,
2818 ATOM_ISP_STEP_WIDTH
);
2819 dvs_h_max
= rounddown(
2820 pipe_cfg
->output_info
[0].res
.height
/ 5,
2821 ATOM_ISP_STEP_HEIGHT
);
2822 bq_res
->envelope_bq
.width_bq
=
2823 min((dvs_w
/ 2), (dvs_w_max
/ 2)) -
2824 bq_res
->ispfilter_bq
.width_bq
;
2825 bq_res
->envelope_bq
.height_bq
=
2826 min((dvs_h
/ 2), (dvs_h_max
/ 2)) -
2827 bq_res
->ispfilter_bq
.height_bq
;
2831 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",
2832 bq_res
->source_bq
.width_bq
, bq_res
->source_bq
.height_bq
,
2833 bq_res
->ispfilter_bq
.width_bq
, bq_res
->ispfilter_bq
.height_bq
,
2834 bq_res
->gdc_shift_bq
.width_bq
, bq_res
->gdc_shift_bq
.height_bq
,
2835 bq_res
->envelope_bq
.width_bq
, bq_res
->envelope_bq
.height_bq
,
2836 bq_res
->output_bq
.width_bq
, bq_res
->output_bq
.height_bq
);
2841 int atomisp_set_dis_coefs(struct atomisp_sub_device
*asd
,
2842 struct atomisp_dis_coefficients
*coefs
)
2844 return atomisp_css_set_dis_coefs(asd
, coefs
);
2848 * Function to set/get 3A stat from isp
2850 int atomisp_3a_stat(struct atomisp_sub_device
*asd
, int flag
,
2851 struct atomisp_3a_statistics
*config
)
2853 struct atomisp_device
*isp
= asd
->isp
;
2854 struct atomisp_s3a_buf
*s3a_buf
;
2860 /* sanity check to avoid writing into unallocated memory. */
2861 if (asd
->params
.s3a_output_bytes
== 0)
2864 if (atomisp_compare_grid(asd
, &config
->grid_info
) != 0) {
2865 /* If the grid info in the argument differs from the current
2866 grid info, we tell the caller to reset the grid size and
2871 if (list_empty(&asd
->s3a_stats_ready
)) {
2872 dev_err(isp
->dev
, "3a statistics is not valid.\n");
2876 s3a_buf
= list_entry(asd
->s3a_stats_ready
.next
,
2877 struct atomisp_s3a_buf
, list
);
2878 if (s3a_buf
->s3a_map
)
2879 ia_css_translate_3a_statistics(
2880 asd
->params
.s3a_user_stat
, s3a_buf
->s3a_map
);
2882 ia_css_get_3a_statistics(asd
->params
.s3a_user_stat
,
2885 config
->exp_id
= s3a_buf
->s3a_data
->exp_id
;
2886 config
->isp_config_id
= s3a_buf
->s3a_data
->isp_config_id
;
2888 ret
= copy_to_user(config
->data
, asd
->params
.s3a_user_stat
->data
,
2889 asd
->params
.s3a_output_bytes
);
2891 dev_err(isp
->dev
, "copy to user failed: copied %lu bytes\n",
2896 /* Move to free buffer list */
2897 list_del_init(&s3a_buf
->list
);
2898 list_add_tail(&s3a_buf
->list
, &asd
->s3a_stats
);
2899 dev_dbg(isp
->dev
, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n", __func__
,
2900 config
->exp_id
, config
->isp_config_id
);
2904 int atomisp_get_metadata(struct atomisp_sub_device
*asd
, int flag
,
2905 struct atomisp_metadata
*md
)
2907 struct atomisp_device
*isp
= asd
->isp
;
2908 struct ia_css_stream_config
*stream_config
;
2909 struct ia_css_stream_info
*stream_info
;
2910 struct camera_mipi_info
*mipi_info
;
2911 struct atomisp_metadata_buf
*md_buf
;
2912 enum atomisp_metadata_type md_type
= ATOMISP_MAIN_METADATA
;
2918 stream_config
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2920 stream_info
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2923 /* We always return the resolution and stride even if there is
2924 * no valid metadata. This allows the caller to get the information
2925 * needed to allocate user-space buffers. */
2926 md
->width
= stream_info
->metadata_info
.resolution
.width
;
2927 md
->height
= stream_info
->metadata_info
.resolution
.height
;
2928 md
->stride
= stream_info
->metadata_info
.stride
;
2930 /* sanity check to avoid writing into unallocated memory.
2931 * This does not return an error because it is a valid way
2932 * for applications to detect that metadata is not enabled. */
2933 if (md
->width
== 0 || md
->height
== 0 || !md
->data
)
2936 /* This is done in the atomisp_buf_done() */
2937 if (list_empty(&asd
->metadata_ready
[md_type
])) {
2938 dev_warn(isp
->dev
, "Metadata queue is empty now!\n");
2942 mipi_info
= atomisp_to_sensor_mipi_info(
2943 isp
->inputs
[asd
->input_curr
].camera
);
2944 if (mipi_info
== NULL
)
2947 if (mipi_info
->metadata_effective_width
!= NULL
) {
2948 for (i
= 0; i
< md
->height
; i
++)
2949 md
->effective_width
[i
] =
2950 mipi_info
->metadata_effective_width
[i
];
2953 md_buf
= list_entry(asd
->metadata_ready
[md_type
].next
,
2954 struct atomisp_metadata_buf
, list
);
2955 md
->exp_id
= md_buf
->metadata
->exp_id
;
2956 if (md_buf
->md_vptr
) {
2957 ret
= copy_to_user(md
->data
,
2959 stream_info
->metadata_info
.size
);
2961 hrt_isp_css_mm_load(md_buf
->metadata
->address
,
2962 asd
->params
.metadata_user
[md_type
],
2963 stream_info
->metadata_info
.size
);
2965 ret
= copy_to_user(md
->data
,
2966 asd
->params
.metadata_user
[md_type
],
2967 stream_info
->metadata_info
.size
);
2970 dev_err(isp
->dev
, "copy to user failed: copied %d bytes\n",
2974 list_del_init(&md_buf
->list
);
2975 list_add_tail(&md_buf
->list
, &asd
->metadata
[md_type
]);
2978 dev_dbg(isp
->dev
, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2979 __func__
, md_type
, md
->exp_id
);
2983 int atomisp_get_metadata_by_type(struct atomisp_sub_device
*asd
, int flag
,
2984 struct atomisp_metadata_with_type
*md
)
2986 struct atomisp_device
*isp
= asd
->isp
;
2987 struct ia_css_stream_config
*stream_config
;
2988 struct ia_css_stream_info
*stream_info
;
2989 struct camera_mipi_info
*mipi_info
;
2990 struct atomisp_metadata_buf
*md_buf
;
2991 enum atomisp_metadata_type md_type
;
2997 stream_config
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
2999 stream_info
= &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
3002 /* We always return the resolution and stride even if there is
3003 * no valid metadata. This allows the caller to get the information
3004 * needed to allocate user-space buffers. */
3005 md
->width
= stream_info
->metadata_info
.resolution
.width
;
3006 md
->height
= stream_info
->metadata_info
.resolution
.height
;
3007 md
->stride
= stream_info
->metadata_info
.stride
;
3009 /* sanity check to avoid writing into unallocated memory.
3010 * This does not return an error because it is a valid way
3011 * for applications to detect that metadata is not enabled. */
3012 if (md
->width
== 0 || md
->height
== 0 || !md
->data
)
3016 if (md_type
>= ATOMISP_METADATA_TYPE_NUM
)
3019 /* This is done in the atomisp_buf_done() */
3020 if (list_empty(&asd
->metadata_ready
[md_type
])) {
3021 dev_warn(isp
->dev
, "Metadata queue is empty now!\n");
3025 mipi_info
= atomisp_to_sensor_mipi_info(
3026 isp
->inputs
[asd
->input_curr
].camera
);
3027 if (mipi_info
== NULL
)
3030 if (mipi_info
->metadata_effective_width
!= NULL
) {
3031 for (i
= 0; i
< md
->height
; i
++)
3032 md
->effective_width
[i
] =
3033 mipi_info
->metadata_effective_width
[i
];
3036 md_buf
= list_entry(asd
->metadata_ready
[md_type
].next
,
3037 struct atomisp_metadata_buf
, list
);
3038 md
->exp_id
= md_buf
->metadata
->exp_id
;
3039 if (md_buf
->md_vptr
) {
3040 ret
= copy_to_user(md
->data
,
3042 stream_info
->metadata_info
.size
);
3044 hrt_isp_css_mm_load(md_buf
->metadata
->address
,
3045 asd
->params
.metadata_user
[md_type
],
3046 stream_info
->metadata_info
.size
);
3048 ret
= copy_to_user(md
->data
,
3049 asd
->params
.metadata_user
[md_type
],
3050 stream_info
->metadata_info
.size
);
3053 dev_err(isp
->dev
, "copy to user failed: copied %d bytes\n",
3057 list_del_init(&md_buf
->list
);
3058 list_add_tail(&md_buf
->list
, &asd
->metadata
[md_type
]);
3060 dev_dbg(isp
->dev
, "%s: HAL de-queued metadata type %d with exp_id %d\n",
3061 __func__
, md_type
, md
->exp_id
);
3066 * Function to calculate real zoom region for every pipe
3068 int atomisp_calculate_real_zoom_region(struct atomisp_sub_device
*asd
,
3069 struct ia_css_dz_config
*dz_config
,
3070 enum atomisp_css_pipe_id css_pipe_id
)
3073 struct atomisp_stream_env
*stream_env
=
3074 &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
];
3075 struct atomisp_resolution eff_res
, out_res
;
3077 int w_offset
, h_offset
;
3080 memset(&eff_res
, 0, sizeof(eff_res
));
3081 memset(&out_res
, 0, sizeof(out_res
));
3083 if (dz_config
->dx
|| dz_config
->dy
)
3086 if (css_pipe_id
!= IA_CSS_PIPE_ID_PREVIEW
3087 && css_pipe_id
!= IA_CSS_PIPE_ID_CAPTURE
) {
3088 dev_err(asd
->isp
->dev
, "%s the set pipe no support crop region"
3094 stream_env
->stream_config
.input_config
.effective_res
.width
;
3096 stream_env
->stream_config
.input_config
.effective_res
.height
;
3097 if (eff_res
.width
== 0 || eff_res
.height
== 0) {
3098 dev_err(asd
->isp
->dev
, "%s err effective resolution"
3103 if (dz_config
->zoom_region
.resolution
.width
3104 == asd
->sensor_array_res
.width
3105 || dz_config
->zoom_region
.resolution
.height
3106 == asd
->sensor_array_res
.height
) {
3107 /*no need crop region*/
3108 dz_config
->zoom_region
.origin
.x
= 0;
3109 dz_config
->zoom_region
.origin
.y
= 0;
3110 dz_config
->zoom_region
.resolution
.width
= eff_res
.width
;
3111 dz_config
->zoom_region
.resolution
.height
= eff_res
.height
;
3116 * This is not the correct implementation with Google's definition, due
3117 * to firmware limitation.
3118 * map real crop region base on above calculating base max crop region.
3122 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.width
;
3124 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.height
;
3125 if (out_res
.width
== 0 || out_res
.height
== 0) {
3126 dev_err(asd
->isp
->dev
, "%s err current pipe output resolution"
3131 if (asd
->sensor_array_res
.width
* out_res
.height
3132 < out_res
.width
* asd
->sensor_array_res
.height
) {
3133 h_offset
= asd
->sensor_array_res
.height
-
3134 asd
->sensor_array_res
.width
3135 * out_res
.height
/ out_res
.width
;
3136 h_offset
= h_offset
/ 2;
3137 if (dz_config
->zoom_region
.origin
.y
< h_offset
)
3138 dz_config
->zoom_region
.origin
.y
= 0;
3140 dz_config
->zoom_region
.origin
.y
=
3141 dz_config
->zoom_region
.origin
.y
- h_offset
;
3144 w_offset
= asd
->sensor_array_res
.width
-
3145 asd
->sensor_array_res
.height
3146 * out_res
.width
/ out_res
.height
;
3147 w_offset
= w_offset
/ 2;
3148 if (dz_config
->zoom_region
.origin
.x
< w_offset
)
3149 dz_config
->zoom_region
.origin
.x
= 0;
3151 dz_config
->zoom_region
.origin
.x
=
3152 dz_config
->zoom_region
.origin
.x
- w_offset
;
3156 dz_config
->zoom_region
.origin
.x
=
3157 dz_config
->zoom_region
.origin
.x
3160 / asd
->sensor_array_res
.width
;
3162 / (asd
->sensor_array_res
.width
-
3165 dz_config
->zoom_region
.origin
.y
=
3166 dz_config
->zoom_region
.origin
.y
3169 / asd
->sensor_array_res
.height
;
3171 / (asd
->sensor_array_res
.height
-
3174 dz_config
->zoom_region
.resolution
.width
=
3175 dz_config
->zoom_region
.resolution
.width
3178 / asd
->sensor_array_res
.width
;
3180 / (asd
->sensor_array_res
.width
-
3183 dz_config
->zoom_region
.resolution
.height
=
3184 dz_config
->zoom_region
.resolution
.height
3187 / asd
->sensor_array_res
.height
;
3189 / (asd
->sensor_array_res
.height
-
3194 * Set same ratio of crop region resolution and current pipe output
3199 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.width
;
3201 stream_env
->pipe_configs
[css_pipe_id
].output_info
[0].res
.height
;
3202 if (out_res
.width
== 0 || out_res
.height
== 0) {
3203 dev_err(asd
->isp
->dev
, "%s err current pipe output resolution"
3209 if (out_res
.width
* dz_config
->zoom_region
.resolution
.height
3210 > dz_config
->zoom_region
.resolution
.width
* out_res
.height
) {
3211 dz_config
->zoom_region
.resolution
.height
=
3212 dz_config
->zoom_region
.resolution
.width
3213 * out_res
.height
/ out_res
.width
;
3215 dz_config
->zoom_region
.resolution
.width
=
3216 dz_config
->zoom_region
.resolution
.height
3217 * out_res
.width
/ out_res
.height
;
3219 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",
3220 __func__
, dz_config
->zoom_region
.origin
.x
,
3221 dz_config
->zoom_region
.origin
.y
,
3222 dz_config
->zoom_region
.resolution
.width
,
3223 dz_config
->zoom_region
.resolution
.height
,
3224 eff_res
.width
, eff_res
.height
,
3225 asd
->sensor_array_res
.width
,
3226 asd
->sensor_array_res
.height
,
3227 out_res
.width
, out_res
.height
);
3230 if ((dz_config
->zoom_region
.origin
.x
+
3231 dz_config
->zoom_region
.resolution
.width
3233 (dz_config
->zoom_region
.origin
.y
+
3234 dz_config
->zoom_region
.resolution
.height
3243 * Function to check the zoom region whether is effective
3245 static bool atomisp_check_zoom_region(
3246 struct atomisp_sub_device
*asd
,
3247 struct ia_css_dz_config
*dz_config
)
3249 struct atomisp_resolution config
;
3253 memset(&config
, 0, sizeof(struct atomisp_resolution
));
3255 if (dz_config
->dx
&& dz_config
->dy
)
3258 config
.width
= asd
->sensor_array_res
.width
;
3259 config
.height
= asd
->sensor_array_res
.height
;
3260 w
= dz_config
->zoom_region
.origin
.x
+
3261 dz_config
->zoom_region
.resolution
.width
;
3262 h
= dz_config
->zoom_region
.origin
.y
+
3263 dz_config
->zoom_region
.resolution
.height
;
3265 if ((w
<= config
.width
) && (h
<= config
.height
) && w
> 0 && h
> 0)
3268 /* setting error zoom region */
3269 dev_err(asd
->isp
->dev
, "%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n",
3270 __func__
, dz_config
->zoom_region
.origin
.x
,
3271 dz_config
->zoom_region
.origin
.y
,
3272 dz_config
->zoom_region
.resolution
.width
,
3273 dz_config
->zoom_region
.resolution
.height
,
3274 config
.width
, config
.height
);
3279 void atomisp_apply_css_parameters(
3280 struct atomisp_sub_device
*asd
,
3281 struct atomisp_css_params
*css_param
)
3283 if (css_param
->update_flag
.wb_config
)
3284 atomisp_css_set_wb_config(asd
, &css_param
->wb_config
);
3286 if (css_param
->update_flag
.ob_config
)
3287 atomisp_css_set_ob_config(asd
, &css_param
->ob_config
);
3289 if (css_param
->update_flag
.dp_config
)
3290 atomisp_css_set_dp_config(asd
, &css_param
->dp_config
);
3292 if (css_param
->update_flag
.nr_config
)
3293 atomisp_css_set_nr_config(asd
, &css_param
->nr_config
);
3295 if (css_param
->update_flag
.ee_config
)
3296 atomisp_css_set_ee_config(asd
, &css_param
->ee_config
);
3298 if (css_param
->update_flag
.tnr_config
)
3299 atomisp_css_set_tnr_config(asd
, &css_param
->tnr_config
);
3301 if (css_param
->update_flag
.a3a_config
)
3302 atomisp_css_set_3a_config(asd
, &css_param
->s3a_config
);
3304 if (css_param
->update_flag
.ctc_config
)
3305 atomisp_css_set_ctc_config(asd
, &css_param
->ctc_config
);
3307 if (css_param
->update_flag
.cnr_config
)
3308 atomisp_css_set_cnr_config(asd
, &css_param
->cnr_config
);
3310 if (css_param
->update_flag
.ecd_config
)
3311 atomisp_css_set_ecd_config(asd
, &css_param
->ecd_config
);
3313 if (css_param
->update_flag
.ynr_config
)
3314 atomisp_css_set_ynr_config(asd
, &css_param
->ynr_config
);
3316 if (css_param
->update_flag
.fc_config
)
3317 atomisp_css_set_fc_config(asd
, &css_param
->fc_config
);
3319 if (css_param
->update_flag
.macc_config
)
3320 atomisp_css_set_macc_config(asd
, &css_param
->macc_config
);
3322 if (css_param
->update_flag
.aa_config
)
3323 atomisp_css_set_aa_config(asd
, &css_param
->aa_config
);
3325 if (css_param
->update_flag
.anr_config
)
3326 atomisp_css_set_anr_config(asd
, &css_param
->anr_config
);
3328 if (css_param
->update_flag
.xnr_config
)
3329 atomisp_css_set_xnr_config(asd
, &css_param
->xnr_config
);
3331 if (css_param
->update_flag
.yuv2rgb_cc_config
)
3332 atomisp_css_set_yuv2rgb_cc_config(asd
,
3333 &css_param
->yuv2rgb_cc_config
);
3335 if (css_param
->update_flag
.rgb2yuv_cc_config
)
3336 atomisp_css_set_rgb2yuv_cc_config(asd
,
3337 &css_param
->rgb2yuv_cc_config
);
3339 if (css_param
->update_flag
.macc_table
)
3340 atomisp_css_set_macc_table(asd
, &css_param
->macc_table
);
3342 if (css_param
->update_flag
.xnr_table
)
3343 atomisp_css_set_xnr_table(asd
, &css_param
->xnr_table
);
3345 if (css_param
->update_flag
.r_gamma_table
)
3346 atomisp_css_set_r_gamma_table(asd
, &css_param
->r_gamma_table
);
3348 if (css_param
->update_flag
.g_gamma_table
)
3349 atomisp_css_set_g_gamma_table(asd
, &css_param
->g_gamma_table
);
3351 if (css_param
->update_flag
.b_gamma_table
)
3352 atomisp_css_set_b_gamma_table(asd
, &css_param
->b_gamma_table
);
3354 if (css_param
->update_flag
.anr_thres
)
3355 atomisp_css_set_anr_thres(asd
, &css_param
->anr_thres
);
3357 if (css_param
->update_flag
.shading_table
)
3358 atomisp_css_set_shading_table(asd
, css_param
->shading_table
);
3360 if (css_param
->update_flag
.morph_table
&& asd
->params
.gdc_cac_en
)
3361 atomisp_css_set_morph_table(asd
, css_param
->morph_table
);
3363 if (css_param
->update_flag
.dvs2_coefs
) {
3364 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
3365 atomisp_css_get_dvs_grid_info(
3366 &asd
->params
.curr_grid_info
);
3368 if (dvs_grid_info
&& dvs_grid_info
->enable
)
3369 atomisp_css_set_dvs2_coefs(asd
, css_param
->dvs2_coeff
);
3372 if (css_param
->update_flag
.dvs_6axis_config
)
3373 atomisp_css_set_dvs_6axis(asd
, css_param
->dvs_6axis
);
3375 atomisp_css_set_isp_config_id(asd
, css_param
->isp_config_id
);
3377 * These configurations are on used by ISP1.x, not for ISP2.x,
3378 * so do not handle them. see comments of ia_css_isp_config.
3389 static unsigned int long copy_from_compatible(void *to
, const void *from
,
3390 unsigned long n
, bool from_user
)
3393 return copy_from_user(to
, from
, n
);
3395 memcpy(to
, from
, n
);
3399 int atomisp_cp_general_isp_parameters(struct atomisp_sub_device
*asd
,
3400 struct atomisp_parameters
*arg
,
3401 struct atomisp_css_params
*css_param
,
3404 struct atomisp_parameters
*cur_config
= &css_param
->update_flag
;
3406 if (!arg
|| !asd
|| !css_param
)
3409 if (arg
->wb_config
&& (from_user
|| !cur_config
->wb_config
)) {
3410 if (copy_from_compatible(&css_param
->wb_config
, arg
->wb_config
,
3411 sizeof(struct atomisp_css_wb_config
),
3414 css_param
->update_flag
.wb_config
=
3415 (struct atomisp_wb_config
*) &css_param
->wb_config
;
3418 if (arg
->ob_config
&& (from_user
|| !cur_config
->ob_config
)) {
3419 if (copy_from_compatible(&css_param
->ob_config
, arg
->ob_config
,
3420 sizeof(struct atomisp_css_ob_config
),
3423 css_param
->update_flag
.ob_config
=
3424 (struct atomisp_ob_config
*) &css_param
->ob_config
;
3427 if (arg
->dp_config
&& (from_user
|| !cur_config
->dp_config
)) {
3428 if (copy_from_compatible(&css_param
->dp_config
, arg
->dp_config
,
3429 sizeof(struct atomisp_css_dp_config
),
3432 css_param
->update_flag
.dp_config
=
3433 (struct atomisp_dp_config
*) &css_param
->dp_config
;
3436 if (asd
->run_mode
->val
!= ATOMISP_RUN_MODE_VIDEO
) {
3437 if (arg
->dz_config
&& (from_user
|| !cur_config
->dz_config
)) {
3438 if (copy_from_compatible(&css_param
->dz_config
,
3440 sizeof(struct atomisp_css_dz_config
),
3443 if (!atomisp_check_zoom_region(asd
,
3444 &css_param
->dz_config
)) {
3445 dev_err(asd
->isp
->dev
, "crop region error!");
3448 css_param
->update_flag
.dz_config
=
3449 (struct atomisp_dz_config
*)
3450 &css_param
->dz_config
;
3454 if (arg
->nr_config
&& (from_user
|| !cur_config
->nr_config
)) {
3455 if (copy_from_compatible(&css_param
->nr_config
, arg
->nr_config
,
3456 sizeof(struct atomisp_css_nr_config
),
3459 css_param
->update_flag
.nr_config
=
3460 (struct atomisp_nr_config
*) &css_param
->nr_config
;
3463 if (arg
->ee_config
&& (from_user
|| !cur_config
->ee_config
)) {
3464 if (copy_from_compatible(&css_param
->ee_config
, arg
->ee_config
,
3465 sizeof(struct atomisp_css_ee_config
),
3468 css_param
->update_flag
.ee_config
=
3469 (struct atomisp_ee_config
*) &css_param
->ee_config
;
3472 if (arg
->tnr_config
&& (from_user
|| !cur_config
->tnr_config
)) {
3473 if (copy_from_compatible(&css_param
->tnr_config
,
3475 sizeof(struct atomisp_css_tnr_config
),
3478 css_param
->update_flag
.tnr_config
=
3479 (struct atomisp_tnr_config
*)
3480 &css_param
->tnr_config
;
3483 if (arg
->a3a_config
&& (from_user
|| !cur_config
->a3a_config
)) {
3484 if (copy_from_compatible(&css_param
->s3a_config
,
3486 sizeof(struct atomisp_css_3a_config
),
3489 css_param
->update_flag
.a3a_config
=
3490 (struct atomisp_3a_config
*) &css_param
->s3a_config
;
3493 if (arg
->ctc_config
&& (from_user
|| !cur_config
->ctc_config
)) {
3494 if (copy_from_compatible(&css_param
->ctc_config
,
3496 sizeof(struct atomisp_css_ctc_config
),
3499 css_param
->update_flag
.ctc_config
=
3500 (struct atomisp_ctc_config
*)
3501 &css_param
->ctc_config
;
3504 if (arg
->cnr_config
&& (from_user
|| !cur_config
->cnr_config
)) {
3505 if (copy_from_compatible(&css_param
->cnr_config
,
3507 sizeof(struct atomisp_css_cnr_config
),
3510 css_param
->update_flag
.cnr_config
=
3511 (struct atomisp_cnr_config
*)
3512 &css_param
->cnr_config
;
3515 if (arg
->ecd_config
&& (from_user
|| !cur_config
->ecd_config
)) {
3516 if (copy_from_compatible(&css_param
->ecd_config
,
3518 sizeof(struct atomisp_css_ecd_config
),
3521 css_param
->update_flag
.ecd_config
=
3522 (struct atomisp_ecd_config
*)
3523 &css_param
->ecd_config
;
3526 if (arg
->ynr_config
&& (from_user
|| !cur_config
->ynr_config
)) {
3527 if (copy_from_compatible(&css_param
->ynr_config
,
3529 sizeof(struct atomisp_css_ynr_config
),
3532 css_param
->update_flag
.ynr_config
=
3533 (struct atomisp_ynr_config
*)
3534 &css_param
->ynr_config
;
3537 if (arg
->fc_config
&& (from_user
|| !cur_config
->fc_config
)) {
3538 if (copy_from_compatible(&css_param
->fc_config
,
3540 sizeof(struct atomisp_css_fc_config
),
3543 css_param
->update_flag
.fc_config
=
3544 (struct atomisp_fc_config
*) &css_param
->fc_config
;
3547 if (arg
->macc_config
&& (from_user
|| !cur_config
->macc_config
)) {
3548 if (copy_from_compatible(&css_param
->macc_config
,
3550 sizeof(struct atomisp_css_macc_config
),
3553 css_param
->update_flag
.macc_config
=
3554 (struct atomisp_macc_config
*)
3555 &css_param
->macc_config
;
3558 if (arg
->aa_config
&& (from_user
|| !cur_config
->aa_config
)) {
3559 if (copy_from_compatible(&css_param
->aa_config
, arg
->aa_config
,
3560 sizeof(struct atomisp_css_aa_config
),
3563 css_param
->update_flag
.aa_config
=
3564 (struct atomisp_aa_config
*) &css_param
->aa_config
;
3567 if (arg
->anr_config
&& (from_user
|| !cur_config
->anr_config
)) {
3568 if (copy_from_compatible(&css_param
->anr_config
,
3570 sizeof(struct atomisp_css_anr_config
),
3573 css_param
->update_flag
.anr_config
=
3574 (struct atomisp_anr_config
*)
3575 &css_param
->anr_config
;
3578 if (arg
->xnr_config
&& (from_user
|| !cur_config
->xnr_config
)) {
3579 if (copy_from_compatible(&css_param
->xnr_config
,
3581 sizeof(struct atomisp_css_xnr_config
),
3584 css_param
->update_flag
.xnr_config
=
3585 (struct atomisp_xnr_config
*)
3586 &css_param
->xnr_config
;
3589 if (arg
->yuv2rgb_cc_config
&&
3590 (from_user
|| !cur_config
->yuv2rgb_cc_config
)) {
3591 if (copy_from_compatible(&css_param
->yuv2rgb_cc_config
,
3592 arg
->yuv2rgb_cc_config
,
3593 sizeof(struct atomisp_css_cc_config
),
3596 css_param
->update_flag
.yuv2rgb_cc_config
=
3597 (struct atomisp_cc_config
*)
3598 &css_param
->yuv2rgb_cc_config
;
3601 if (arg
->rgb2yuv_cc_config
&&
3602 (from_user
|| !cur_config
->rgb2yuv_cc_config
)) {
3603 if (copy_from_compatible(&css_param
->rgb2yuv_cc_config
,
3604 arg
->rgb2yuv_cc_config
,
3605 sizeof(struct atomisp_css_cc_config
),
3608 css_param
->update_flag
.rgb2yuv_cc_config
=
3609 (struct atomisp_cc_config
*)
3610 &css_param
->rgb2yuv_cc_config
;
3613 if (arg
->macc_table
&& (from_user
|| !cur_config
->macc_table
)) {
3614 if (copy_from_compatible(&css_param
->macc_table
,
3616 sizeof(struct atomisp_css_macc_table
),
3619 css_param
->update_flag
.macc_table
=
3620 (struct atomisp_macc_table
*)
3621 &css_param
->macc_table
;
3624 if (arg
->xnr_table
&& (from_user
|| !cur_config
->xnr_table
)) {
3625 if (copy_from_compatible(&css_param
->xnr_table
,
3627 sizeof(struct atomisp_css_xnr_table
),
3630 css_param
->update_flag
.xnr_table
=
3631 (struct atomisp_xnr_table
*) &css_param
->xnr_table
;
3634 if (arg
->r_gamma_table
&& (from_user
|| !cur_config
->r_gamma_table
)) {
3635 if (copy_from_compatible(&css_param
->r_gamma_table
,
3637 sizeof(struct atomisp_css_rgb_gamma_table
),
3640 css_param
->update_flag
.r_gamma_table
=
3641 (struct atomisp_rgb_gamma_table
*)
3642 &css_param
->r_gamma_table
;
3645 if (arg
->g_gamma_table
&& (from_user
|| !cur_config
->g_gamma_table
)) {
3646 if (copy_from_compatible(&css_param
->g_gamma_table
,
3648 sizeof(struct atomisp_css_rgb_gamma_table
),
3651 css_param
->update_flag
.g_gamma_table
=
3652 (struct atomisp_rgb_gamma_table
*)
3653 &css_param
->g_gamma_table
;
3656 if (arg
->b_gamma_table
&& (from_user
|| !cur_config
->b_gamma_table
)) {
3657 if (copy_from_compatible(&css_param
->b_gamma_table
,
3659 sizeof(struct atomisp_css_rgb_gamma_table
),
3662 css_param
->update_flag
.b_gamma_table
=
3663 (struct atomisp_rgb_gamma_table
*)
3664 &css_param
->b_gamma_table
;
3667 if (arg
->anr_thres
&& (from_user
|| !cur_config
->anr_thres
)) {
3668 if (copy_from_compatible(&css_param
->anr_thres
, arg
->anr_thres
,
3669 sizeof(struct atomisp_css_anr_thres
),
3672 css_param
->update_flag
.anr_thres
=
3673 (struct atomisp_anr_thres
*) &css_param
->anr_thres
;
3677 css_param
->isp_config_id
= arg
->isp_config_id
;
3679 * These configurations are on used by ISP1.x, not for ISP2.x,
3680 * so do not handle them. see comments of ia_css_isp_config.
3692 int atomisp_cp_lsc_table(struct atomisp_sub_device
*asd
,
3693 struct atomisp_shading_table
*source_st
,
3694 struct atomisp_css_params
*css_param
,
3698 unsigned int len_table
;
3699 struct atomisp_css_shading_table
*shading_table
;
3700 struct atomisp_css_shading_table
*old_table
;
3702 struct atomisp_shading_table st
;
3711 if (!from_user
&& css_param
->update_flag
.shading_table
)
3715 if (copy_from_compatible(&st
, source_st
,
3716 sizeof(struct atomisp_shading_table
),
3718 dev_err(asd
->isp
->dev
, "copy shading table failed!");
3723 old_table
= css_param
->shading_table
;
3728 /* user config is to disable the shading table. */
3730 if (!source_st
->enable
) {
3734 /* Generate a minimum table with enable = 0. */
3735 shading_table
= atomisp_css_shading_table_alloc(1, 1);
3738 shading_table
->enable
= 0;
3742 /* Setting a new table. Validate first - all tables must be set */
3743 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3745 if (!source_st
->data
[i
])
3748 dev_err(asd
->isp
->dev
, "shading table validate failed");
3756 /* Shading table size per color */
3758 if (source_st
->width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
3759 source_st
->height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
)
3761 if (st
.width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
3762 st
.height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
) {
3763 dev_err(asd
->isp
->dev
, "shading table w/h validate failed!");
3771 shading_table
= atomisp_css_shading_table_alloc(source_st
->width
,
3776 shading_table
= atomisp_css_shading_table_alloc(st
.width
,
3778 if (!shading_table
) {
3779 dev_err(asd
->isp
->dev
, "shading table alloc failed!");
3785 len_table
= source_st
->width
* source_st
->height
* ATOMISP_SC_TYPE_SIZE
;
3787 len_table
= st
.width
* st
.height
* ATOMISP_SC_TYPE_SIZE
;
3789 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3790 if (copy_from_compatible(shading_table
->data
[i
],
3792 source_st
->data
[i
], len_table
, from_user
)) {
3794 st
.data
[i
], len_table
, from_user
)) {
3796 atomisp_css_shading_table_free(shading_table
);
3802 shading_table
->sensor_width
= source_st
->sensor_width
;
3803 shading_table
->sensor_height
= source_st
->sensor_height
;
3804 shading_table
->fraction_bits
= source_st
->fraction_bits
;
3805 shading_table
->enable
= source_st
->enable
;
3807 shading_table
->sensor_width
= st
.sensor_width
;
3808 shading_table
->sensor_height
= st
.sensor_height
;
3809 shading_table
->fraction_bits
= st
.fraction_bits
;
3810 shading_table
->enable
= st
.enable
;
3813 /* No need to update shading table if it is the same */
3814 if (old_table
!= NULL
&&
3815 old_table
->sensor_width
== shading_table
->sensor_width
&&
3816 old_table
->sensor_height
== shading_table
->sensor_height
&&
3817 old_table
->width
== shading_table
->width
&&
3818 old_table
->height
== shading_table
->height
&&
3819 old_table
->fraction_bits
== shading_table
->fraction_bits
&&
3820 old_table
->enable
== shading_table
->enable
) {
3821 bool data_is_same
= true;
3823 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
3824 if (memcmp(shading_table
->data
[i
], old_table
->data
[i
],
3826 data_is_same
= false;
3832 atomisp_css_shading_table_free(shading_table
);
3838 /* set LSC to CSS */
3839 css_param
->shading_table
= shading_table
;
3840 css_param
->update_flag
.shading_table
=
3841 (struct atomisp_shading_table
*) shading_table
;
3842 asd
->params
.sc_en
= shading_table
!= NULL
;
3845 atomisp_css_shading_table_free(old_table
);
3850 int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device
*asd
,
3851 struct ia_css_dvs2_coefficients
*coefs
,
3852 struct atomisp_css_params
*css_param
,
3855 struct atomisp_css_dvs_grid_info
*cur
=
3856 atomisp_css_get_dvs_grid_info(&asd
->params
.curr_grid_info
);
3857 int dvs_hor_coef_bytes
, dvs_ver_coef_bytes
;
3859 struct ia_css_dvs2_coefficients dvs2_coefs
;
3865 if (!from_user
&& css_param
->update_flag
.dvs2_coefs
)
3869 if (sizeof(*cur
) != sizeof(coefs
->grid
) ||
3870 memcmp(&coefs
->grid
, cur
, sizeof(coefs
->grid
))) {
3872 if (copy_from_compatible(&dvs2_coefs
, coefs
,
3873 sizeof(struct ia_css_dvs2_coefficients
),
3875 dev_err(asd
->isp
->dev
, "copy dvs2 coef failed");
3879 if (sizeof(*cur
) != sizeof(dvs2_coefs
.grid
) ||
3880 memcmp(&dvs2_coefs
.grid
, cur
, sizeof(dvs2_coefs
.grid
))) {
3882 dev_err(asd
->isp
->dev
, "dvs grid mis-match!\n");
3883 /* If the grid info in the argument differs from the current
3884 grid info, we tell the caller to reset the grid size and
3890 if (coefs
->hor_coefs
.odd_real
== NULL
||
3891 coefs
->hor_coefs
.odd_imag
== NULL
||
3892 coefs
->hor_coefs
.even_real
== NULL
||
3893 coefs
->hor_coefs
.even_imag
== NULL
||
3894 coefs
->ver_coefs
.odd_real
== NULL
||
3895 coefs
->ver_coefs
.odd_imag
== NULL
||
3896 coefs
->ver_coefs
.even_real
== NULL
||
3897 coefs
->ver_coefs
.even_imag
== NULL
)
3899 if (dvs2_coefs
.hor_coefs
.odd_real
== NULL
||
3900 dvs2_coefs
.hor_coefs
.odd_imag
== NULL
||
3901 dvs2_coefs
.hor_coefs
.even_real
== NULL
||
3902 dvs2_coefs
.hor_coefs
.even_imag
== NULL
||
3903 dvs2_coefs
.ver_coefs
.odd_real
== NULL
||
3904 dvs2_coefs
.ver_coefs
.odd_imag
== NULL
||
3905 dvs2_coefs
.ver_coefs
.even_real
== NULL
||
3906 dvs2_coefs
.ver_coefs
.even_imag
== NULL
)
3910 if (!css_param
->dvs2_coeff
) {
3911 /* DIS coefficients. */
3912 css_param
->dvs2_coeff
= ia_css_dvs2_coefficients_allocate(cur
);
3913 if (!css_param
->dvs2_coeff
)
3917 dvs_hor_coef_bytes
= asd
->params
.dvs_hor_coef_bytes
;
3918 dvs_ver_coef_bytes
= asd
->params
.dvs_ver_coef_bytes
;
3919 if (copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.odd_real
,
3921 coefs
->hor_coefs
.odd_real
, dvs_hor_coef_bytes
, from_user
) ||
3923 dvs2_coefs
.hor_coefs
.odd_real
, dvs_hor_coef_bytes
, from_user
) ||
3925 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.odd_imag
,
3927 coefs
->hor_coefs
.odd_imag
, dvs_hor_coef_bytes
, from_user
) ||
3929 dvs2_coefs
.hor_coefs
.odd_imag
, dvs_hor_coef_bytes
, from_user
) ||
3931 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.even_real
,
3933 coefs
->hor_coefs
.even_real
, dvs_hor_coef_bytes
, from_user
) ||
3935 dvs2_coefs
.hor_coefs
.even_real
, dvs_hor_coef_bytes
, from_user
) ||
3937 copy_from_compatible(css_param
->dvs2_coeff
->hor_coefs
.even_imag
,
3939 coefs
->hor_coefs
.even_imag
, dvs_hor_coef_bytes
, from_user
) ||
3941 dvs2_coefs
.hor_coefs
.even_imag
, dvs_hor_coef_bytes
, from_user
) ||
3943 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.odd_real
,
3945 coefs
->ver_coefs
.odd_real
, dvs_ver_coef_bytes
, from_user
) ||
3947 dvs2_coefs
.ver_coefs
.odd_real
, dvs_ver_coef_bytes
, from_user
) ||
3949 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.odd_imag
,
3951 coefs
->ver_coefs
.odd_imag
, dvs_ver_coef_bytes
, from_user
) ||
3953 dvs2_coefs
.ver_coefs
.odd_imag
, dvs_ver_coef_bytes
, from_user
) ||
3955 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.even_real
,
3957 coefs
->ver_coefs
.even_real
, dvs_ver_coef_bytes
, from_user
) ||
3959 dvs2_coefs
.ver_coefs
.even_real
, dvs_ver_coef_bytes
, from_user
) ||
3961 copy_from_compatible(css_param
->dvs2_coeff
->ver_coefs
.even_imag
,
3963 coefs
->ver_coefs
.even_imag
, dvs_ver_coef_bytes
, from_user
)) {
3965 dvs2_coefs
.ver_coefs
.even_imag
, dvs_ver_coef_bytes
, from_user
)) {
3967 ia_css_dvs2_coefficients_free(css_param
->dvs2_coeff
);
3968 css_param
->dvs2_coeff
= NULL
;
3972 css_param
->update_flag
.dvs2_coefs
=
3973 (struct atomisp_dvs2_coefficients
*)css_param
->dvs2_coeff
;
3977 int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device
*asd
,
3978 struct atomisp_dvs_6axis_config
*source_6axis_config
,
3979 struct atomisp_css_params
*css_param
,
3982 struct atomisp_css_dvs_6axis_config
*dvs_6axis_config
;
3983 struct atomisp_css_dvs_6axis_config
*old_6axis_config
;
3985 struct atomisp_css_dvs_6axis_config t_6axis_config
;
3987 struct ia_css_stream
*stream
=
3988 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
;
3989 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
3990 atomisp_css_get_dvs_grid_info(&asd
->params
.curr_grid_info
);
3993 if (stream
== NULL
) {
3994 dev_err(asd
->isp
->dev
, "%s: internal error!", __func__
);
3998 if (!source_6axis_config
|| !dvs_grid_info
)
4001 if (!dvs_grid_info
->enable
)
4004 if (!from_user
&& css_param
->update_flag
.dvs_6axis_config
)
4007 /* check whether need to reallocate for 6 axis config */
4008 old_6axis_config
= css_param
->dvs_6axis
;
4009 dvs_6axis_config
= old_6axis_config
;
4012 if (copy_from_compatible(&t_6axis_config
, source_6axis_config
,
4013 sizeof(struct atomisp_dvs_6axis_config
),
4015 dev_err(asd
->isp
->dev
, "copy morph table failed!");
4020 if (old_6axis_config
&&
4022 (old_6axis_config
->width_y
!= source_6axis_config
->width_y
||
4023 old_6axis_config
->height_y
!= source_6axis_config
->height_y
||
4024 old_6axis_config
->width_uv
!= source_6axis_config
->width_uv
||
4025 old_6axis_config
->height_uv
!= source_6axis_config
->height_uv
)) {
4027 (old_6axis_config
->width_y
!= t_6axis_config
.width_y
||
4028 old_6axis_config
->height_y
!= t_6axis_config
.height_y
||
4029 old_6axis_config
->width_uv
!= t_6axis_config
.width_uv
||
4030 old_6axis_config
->height_uv
!= t_6axis_config
.height_uv
)) {
4032 ia_css_dvs2_6axis_config_free(css_param
->dvs_6axis
);
4033 css_param
->dvs_6axis
= NULL
;
4035 dvs_6axis_config
= ia_css_dvs2_6axis_config_allocate(stream
);
4036 if (!dvs_6axis_config
)
4038 } else if (!dvs_6axis_config
) {
4039 dvs_6axis_config
= ia_css_dvs2_6axis_config_allocate(stream
);
4040 if (!dvs_6axis_config
)
4045 dvs_6axis_config
->exp_id
= source_6axis_config
->exp_id
;
4047 dvs_6axis_config
->exp_id
= t_6axis_config
.exp_id
;
4050 if (copy_from_compatible(dvs_6axis_config
->xcoords_y
,
4052 source_6axis_config
->xcoords_y
,
4053 source_6axis_config
->width_y
*
4054 source_6axis_config
->height_y
*
4055 sizeof(*source_6axis_config
->xcoords_y
),
4057 t_6axis_config
.xcoords_y
,
4058 t_6axis_config
.width_y
*
4059 t_6axis_config
.height_y
*
4060 sizeof(*dvs_6axis_config
->xcoords_y
),
4064 if (copy_from_compatible(dvs_6axis_config
->ycoords_y
,
4066 source_6axis_config
->ycoords_y
,
4067 source_6axis_config
->width_y
*
4068 source_6axis_config
->height_y
*
4069 sizeof(*source_6axis_config
->ycoords_y
),
4071 t_6axis_config
.ycoords_y
,
4072 t_6axis_config
.width_y
*
4073 t_6axis_config
.height_y
*
4074 sizeof(*dvs_6axis_config
->ycoords_y
),
4078 if (copy_from_compatible(dvs_6axis_config
->xcoords_uv
,
4080 source_6axis_config
->xcoords_uv
,
4081 source_6axis_config
->width_uv
*
4082 source_6axis_config
->height_uv
*
4083 sizeof(*source_6axis_config
->xcoords_uv
),
4085 t_6axis_config
.xcoords_uv
,
4086 t_6axis_config
.width_uv
*
4087 t_6axis_config
.height_uv
*
4088 sizeof(*dvs_6axis_config
->xcoords_uv
),
4092 if (copy_from_compatible(dvs_6axis_config
->ycoords_uv
,
4094 source_6axis_config
->ycoords_uv
,
4095 source_6axis_config
->width_uv
*
4096 source_6axis_config
->height_uv
*
4097 sizeof(*source_6axis_config
->ycoords_uv
),
4099 t_6axis_config
.ycoords_uv
,
4100 t_6axis_config
.width_uv
*
4101 t_6axis_config
.height_uv
*
4102 sizeof(*dvs_6axis_config
->ycoords_uv
),
4107 css_param
->dvs_6axis
= dvs_6axis_config
;
4108 css_param
->update_flag
.dvs_6axis_config
=
4109 (struct atomisp_dvs_6axis_config
*) dvs_6axis_config
;
4113 if (dvs_6axis_config
)
4114 ia_css_dvs2_6axis_config_free(dvs_6axis_config
);
4118 int atomisp_cp_morph_table(struct atomisp_sub_device
*asd
,
4119 struct atomisp_morph_table
*source_morph_table
,
4120 struct atomisp_css_params
*css_param
,
4125 struct atomisp_css_morph_table
*morph_table
;
4127 struct atomisp_css_morph_table mtbl
;
4129 struct atomisp_css_morph_table
*old_morph_table
;
4131 if (!source_morph_table
)
4134 if (!from_user
&& css_param
->update_flag
.morph_table
)
4137 old_morph_table
= css_param
->morph_table
;
4140 if (copy_from_compatible(&mtbl
, source_morph_table
,
4141 sizeof(struct atomisp_morph_table
),
4143 dev_err(asd
->isp
->dev
, "copy morph table failed!");
4148 morph_table
= atomisp_css_morph_table_allocate(
4150 source_morph_table
->width
,
4151 source_morph_table
->height
);
4159 for (i
= 0; i
< CSS_MORPH_TABLE_NUM_PLANES
; i
++) {
4160 if (copy_from_compatible(morph_table
->coordinates_x
[i
],
4161 source_morph_table
->coordinates_x
[i
],
4163 source_morph_table
->height
* source_morph_table
->width
*
4164 sizeof(*source_morph_table
->coordinates_x
[i
]),
4166 mtbl
.height
* mtbl
.width
*
4167 sizeof(*morph_table
->coordinates_x
[i
]),
4172 if (copy_from_compatible(morph_table
->coordinates_y
[i
],
4173 source_morph_table
->coordinates_y
[i
],
4175 source_morph_table
->height
* source_morph_table
->width
*
4176 sizeof(*source_morph_table
->coordinates_y
[i
]),
4178 mtbl
.height
* mtbl
.width
*
4179 sizeof(*morph_table
->coordinates_y
[i
]),
4185 css_param
->morph_table
= morph_table
;
4186 if (old_morph_table
)
4187 atomisp_css_morph_table_free(old_morph_table
);
4188 css_param
->update_flag
.morph_table
=
4189 (struct atomisp_morph_table
*) morph_table
;
4194 atomisp_css_morph_table_free(morph_table
);
4198 int atomisp_makeup_css_parameters(struct atomisp_sub_device
*asd
,
4199 struct atomisp_parameters
*arg
,
4200 struct atomisp_css_params
*css_param
)
4204 ret
= atomisp_cp_general_isp_parameters(asd
, arg
, css_param
, false);
4207 ret
= atomisp_cp_lsc_table(asd
, arg
->shading_table
, css_param
, false);
4210 ret
= atomisp_cp_morph_table(asd
, arg
->morph_table
, css_param
, false);
4213 ret
= atomisp_css_cp_dvs2_coefs(asd
,
4214 (struct ia_css_dvs2_coefficients
*) arg
->dvs2_coefs
,
4218 ret
= atomisp_cp_dvs_6axis_config(asd
, arg
->dvs_6axis_config
,
4223 void atomisp_free_css_parameters(struct atomisp_css_params
*css_param
)
4225 if (css_param
->dvs_6axis
) {
4226 ia_css_dvs2_6axis_config_free(css_param
->dvs_6axis
);
4227 css_param
->dvs_6axis
= NULL
;
4229 if (css_param
->dvs2_coeff
) {
4230 ia_css_dvs2_coefficients_free(css_param
->dvs2_coeff
);
4231 css_param
->dvs2_coeff
= NULL
;
4233 if (css_param
->shading_table
) {
4234 ia_css_shading_table_free(css_param
->shading_table
);
4235 css_param
->shading_table
= NULL
;
4237 if (css_param
->morph_table
) {
4238 ia_css_morph_table_free(css_param
->morph_table
);
4239 css_param
->morph_table
= NULL
;
4244 * Check parameter queue list and buffer queue list to find out if matched items
4245 * and then set parameter to CSS and enqueue buffer to CSS.
4246 * Of course, if the buffer in buffer waiting list is not bound to a per-frame
4247 * parameter, it will be enqueued into CSS as long as the per-frame setting
4248 * buffers before it get enqueued.
4250 void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe
*pipe
)
4252 struct atomisp_sub_device
*asd
= pipe
->asd
;
4253 struct videobuf_buffer
*vb
= NULL
, *vb_tmp
;
4254 struct atomisp_css_params_with_list
*param
= NULL
, *param_tmp
;
4255 struct videobuf_vmalloc_memory
*vm_mem
= NULL
;
4256 unsigned long irqflags
;
4257 bool need_to_enqueue_buffer
= false;
4259 if (atomisp_is_vf_pipe(pipe
))
4263 * CSS/FW requires set parameter and enqueue buffer happen after ISP
4266 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
4269 if (list_empty(&pipe
->per_frame_params
) ||
4270 list_empty(&pipe
->buffers_waiting_for_param
))
4273 list_for_each_entry_safe(vb
, vb_tmp
,
4274 &pipe
->buffers_waiting_for_param
, queue
) {
4275 if (pipe
->frame_request_config_id
[vb
->i
]) {
4276 list_for_each_entry_safe(param
, param_tmp
,
4277 &pipe
->per_frame_params
, list
) {
4278 if (pipe
->frame_request_config_id
[vb
->i
] !=
4279 param
->params
.isp_config_id
)
4282 list_del(¶m
->list
);
4283 list_del(&vb
->queue
);
4285 * clear the request config id as the buffer
4286 * will be handled and enqueued into CSS soon
4288 pipe
->frame_request_config_id
[vb
->i
] = 0;
4289 pipe
->frame_params
[vb
->i
] = param
;
4296 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
4297 list_add_tail(&vb
->queue
, &pipe
->activeq
);
4298 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
4300 need_to_enqueue_buffer
= true;
4302 /* The is the end, stop further loop */
4306 list_del(&vb
->queue
);
4307 pipe
->frame_params
[vb
->i
] = NULL
;
4308 spin_lock_irqsave(&pipe
->irq_lock
, irqflags
);
4309 list_add_tail(&vb
->queue
, &pipe
->activeq
);
4310 spin_unlock_irqrestore(&pipe
->irq_lock
, irqflags
);
4311 need_to_enqueue_buffer
= true;
4315 if (need_to_enqueue_buffer
) {
4316 atomisp_qbuffers_to_css(asd
);
4318 if (!atomisp_is_wdt_running(asd
) && atomisp_buffers_queued(asd
))
4319 atomisp_wdt_start(asd
);
4321 if (atomisp_buffers_queued_pipe(pipe
)) {
4322 if (!atomisp_is_wdt_running(pipe
))
4323 atomisp_wdt_start(pipe
);
4325 atomisp_wdt_refresh_pipe(pipe
,
4326 ATOMISP_WDT_KEEP_CURRENT_DELAY
);
4333 * Function to configure ISP parameters
4335 int atomisp_set_parameters(struct video_device
*vdev
,
4336 struct atomisp_parameters
*arg
)
4338 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
4339 struct atomisp_sub_device
*asd
= pipe
->asd
;
4340 struct atomisp_css_params_with_list
*param
= NULL
;
4341 struct atomisp_css_params
*css_param
= &asd
->params
.css_param
;
4344 if (asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream
== NULL
) {
4345 dev_err(asd
->isp
->dev
, "%s: internal error!\n", __func__
);
4349 dev_dbg(asd
->isp
->dev
, "%s: set parameter(per_frame_setting %d) for asd%d with isp_config_id %d of %s\n",
4350 __func__
, arg
->per_frame_setting
, asd
->index
,
4351 arg
->isp_config_id
, vdev
->name
);
4354 if (atomisp_is_vf_pipe(pipe
) && arg
->per_frame_setting
) {
4355 dev_err(asd
->isp
->dev
, "%s: vf pipe not support per_frame_setting",
4361 if (arg
->per_frame_setting
&& !atomisp_is_vf_pipe(pipe
)) {
4363 * Per-frame setting enabled, we allocate a new paramter
4364 * buffer to cache the parameters and only when frame buffers
4365 * are ready, the parameters will be set to CSS.
4366 * per-frame setting only works for the main output frame.
4368 param
= atomisp_kernel_zalloc(sizeof(*param
), true);
4370 dev_err(asd
->isp
->dev
, "%s: failed to alloc params buffer\n",
4374 css_param
= ¶m
->params
;
4377 ret
= atomisp_cp_general_isp_parameters(asd
, arg
, css_param
, true);
4379 goto apply_parameter_failed
;
4381 ret
= atomisp_cp_lsc_table(asd
, arg
->shading_table
, css_param
, true);
4383 goto apply_parameter_failed
;
4385 ret
= atomisp_cp_morph_table(asd
, arg
->morph_table
, css_param
, true);
4387 goto apply_parameter_failed
;
4389 ret
= atomisp_css_cp_dvs2_coefs(asd
,
4390 (struct ia_css_dvs2_coefficients
*) arg
->dvs2_coefs
,
4393 goto apply_parameter_failed
;
4395 ret
= atomisp_cp_dvs_6axis_config(asd
, arg
->dvs_6axis_config
,
4398 goto apply_parameter_failed
;
4400 if (!(arg
->per_frame_setting
&& !atomisp_is_vf_pipe(pipe
))) {
4401 /* indicate to CSS that we have parameters to be updated */
4402 asd
->params
.css_update_params_needed
= true;
4404 list_add_tail(¶m
->list
, &pipe
->per_frame_params
);
4405 atomisp_handle_parameter_and_buffer(pipe
);
4410 apply_parameter_failed
:
4412 atomisp_free_css_parameters(css_param
);
4414 atomisp_kernel_free(param
);
4420 * Function to set/get isp parameters to isp
4422 int atomisp_param(struct atomisp_sub_device
*asd
, int flag
,
4423 struct atomisp_parm
*config
)
4425 struct atomisp_device
*isp
= asd
->isp
;
4426 struct ia_css_pipe_config
*vp_cfg
=
4427 &asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].
4428 pipe_configs
[IA_CSS_PIPE_ID_VIDEO
];
4430 /* Read parameter for 3A binary info */
4432 struct atomisp_css_dvs_grid_info
*dvs_grid_info
=
4433 atomisp_css_get_dvs_grid_info(
4434 &asd
->params
.curr_grid_info
);
4436 if (&config
->info
== NULL
) {
4437 dev_err(isp
->dev
, "ERROR: NULL pointer in grid_info\n");
4440 atomisp_curr_user_grid_info(asd
, &config
->info
);
4442 /* We always return the resolution and stride even if there is
4443 * no valid metadata. This allows the caller to get the
4444 * information needed to allocate user-space buffers. */
4445 config
->metadata_config
.metadata_height
= asd
->
4446 stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream_info
.
4447 metadata_info
.resolution
.height
;
4448 config
->metadata_config
.metadata_stride
= asd
->
4449 stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].stream_info
.
4450 metadata_info
.stride
;
4452 /* update dvs grid info */
4454 memcpy(&config
->dvs_grid
,
4456 sizeof(struct atomisp_css_dvs_grid_info
));
4458 if (asd
->run_mode
->val
!= ATOMISP_RUN_MODE_VIDEO
) {
4459 config
->dvs_envelop
.width
= 0;
4460 config
->dvs_envelop
.height
= 0;
4464 /* update dvs envelop info */
4465 if (!asd
->continuous_mode
->val
) {
4466 config
->dvs_envelop
.width
= vp_cfg
->dvs_envelope
.width
;
4467 config
->dvs_envelop
.height
=
4468 vp_cfg
->dvs_envelope
.height
;
4470 unsigned int dvs_w
, dvs_h
, dvs_w_max
, dvs_h_max
;
4472 dvs_w
= vp_cfg
->bayer_ds_out_res
.width
-
4473 vp_cfg
->output_info
[0].res
.width
;
4474 dvs_h
= vp_cfg
->bayer_ds_out_res
.height
-
4475 vp_cfg
->output_info
[0].res
.height
;
4476 dvs_w_max
= rounddown(
4477 vp_cfg
->output_info
[0].res
.width
/ 5,
4478 ATOM_ISP_STEP_WIDTH
);
4479 dvs_h_max
= rounddown(
4480 vp_cfg
->output_info
[0].res
.height
/ 5,
4481 ATOM_ISP_STEP_HEIGHT
);
4483 config
->dvs_envelop
.width
= min(dvs_w
, dvs_w_max
);
4484 config
->dvs_envelop
.height
= min(dvs_h
, dvs_h_max
);
4490 memcpy(&asd
->params
.css_param
.wb_config
, &config
->wb_config
,
4491 sizeof(struct atomisp_css_wb_config
));
4492 memcpy(&asd
->params
.css_param
.ob_config
, &config
->ob_config
,
4493 sizeof(struct atomisp_css_ob_config
));
4494 memcpy(&asd
->params
.css_param
.dp_config
, &config
->dp_config
,
4495 sizeof(struct atomisp_css_dp_config
));
4496 memcpy(&asd
->params
.css_param
.de_config
, &config
->de_config
,
4497 sizeof(struct atomisp_css_de_config
));
4498 memcpy(&asd
->params
.css_param
.dz_config
, &config
->dz_config
,
4499 sizeof(struct atomisp_css_dz_config
));
4500 memcpy(&asd
->params
.css_param
.ce_config
, &config
->ce_config
,
4501 sizeof(struct atomisp_css_ce_config
));
4502 memcpy(&asd
->params
.css_param
.nr_config
, &config
->nr_config
,
4503 sizeof(struct atomisp_css_nr_config
));
4504 memcpy(&asd
->params
.css_param
.ee_config
, &config
->ee_config
,
4505 sizeof(struct atomisp_css_ee_config
));
4506 memcpy(&asd
->params
.css_param
.tnr_config
, &config
->tnr_config
,
4507 sizeof(struct atomisp_css_tnr_config
));
4509 if (asd
->params
.color_effect
== V4L2_COLORFX_NEGATIVE
) {
4510 asd
->params
.css_param
.cc_config
.matrix
[3] = -config
->cc_config
.matrix
[3];
4511 asd
->params
.css_param
.cc_config
.matrix
[4] = -config
->cc_config
.matrix
[4];
4512 asd
->params
.css_param
.cc_config
.matrix
[5] = -config
->cc_config
.matrix
[5];
4513 asd
->params
.css_param
.cc_config
.matrix
[6] = -config
->cc_config
.matrix
[6];
4514 asd
->params
.css_param
.cc_config
.matrix
[7] = -config
->cc_config
.matrix
[7];
4515 asd
->params
.css_param
.cc_config
.matrix
[8] = -config
->cc_config
.matrix
[8];
4518 if (asd
->params
.color_effect
!= V4L2_COLORFX_SEPIA
&&
4519 asd
->params
.color_effect
!= V4L2_COLORFX_BW
) {
4520 memcpy(&asd
->params
.css_param
.cc_config
, &config
->cc_config
,
4521 sizeof(struct atomisp_css_cc_config
));
4522 atomisp_css_set_cc_config(asd
, &asd
->params
.css_param
.cc_config
);
4525 atomisp_css_set_wb_config(asd
, &asd
->params
.css_param
.wb_config
);
4526 atomisp_css_set_ob_config(asd
, &asd
->params
.css_param
.ob_config
);
4527 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4528 atomisp_css_set_dz_config(asd
, &asd
->params
.css_param
.dz_config
);
4529 atomisp_css_set_ce_config(asd
, &asd
->params
.css_param
.ce_config
);
4530 atomisp_css_set_dp_config(asd
, &asd
->params
.css_param
.dp_config
);
4531 atomisp_css_set_nr_config(asd
, &asd
->params
.css_param
.nr_config
);
4532 atomisp_css_set_ee_config(asd
, &asd
->params
.css_param
.ee_config
);
4533 atomisp_css_set_tnr_config(asd
, &asd
->params
.css_param
.tnr_config
);
4534 asd
->params
.css_update_params_needed
= true;
4540 * Function to configure color effect of the image
4542 int atomisp_color_effect(struct atomisp_sub_device
*asd
, int flag
,
4545 struct atomisp_css_cc_config
*cc_config
= NULL
;
4546 struct atomisp_css_macc_table
*macc_table
= NULL
;
4547 struct atomisp_css_ctc_table
*ctc_table
= NULL
;
4549 struct v4l2_control control
;
4550 struct atomisp_device
*isp
= asd
->isp
;
4553 *effect
= asd
->params
.color_effect
;
4558 control
.id
= V4L2_CID_COLORFX
;
4559 control
.value
= *effect
;
4561 v4l2_s_ctrl(NULL
, isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
,
4564 * if set color effect to sensor successfully, return
4568 asd
->params
.color_effect
= (u32
)*effect
;
4572 if (*effect
== asd
->params
.color_effect
)
4576 * isp_subdev->params.macc_en should be set to false.
4578 asd
->params
.macc_en
= false;
4581 case V4L2_COLORFX_NONE
:
4582 macc_table
= &asd
->params
.css_param
.macc_table
;
4583 asd
->params
.macc_en
= true;
4585 case V4L2_COLORFX_SEPIA
:
4586 cc_config
= &sepia_cc_config
;
4588 case V4L2_COLORFX_NEGATIVE
:
4589 cc_config
= &nega_cc_config
;
4591 case V4L2_COLORFX_BW
:
4592 cc_config
= &mono_cc_config
;
4594 case V4L2_COLORFX_SKY_BLUE
:
4595 macc_table
= &blue_macc_table
;
4596 asd
->params
.macc_en
= true;
4598 case V4L2_COLORFX_GRASS_GREEN
:
4599 macc_table
= &green_macc_table
;
4600 asd
->params
.macc_en
= true;
4602 case V4L2_COLORFX_SKIN_WHITEN_LOW
:
4603 macc_table
= &skin_low_macc_table
;
4604 asd
->params
.macc_en
= true;
4606 case V4L2_COLORFX_SKIN_WHITEN
:
4607 macc_table
= &skin_medium_macc_table
;
4608 asd
->params
.macc_en
= true;
4610 case V4L2_COLORFX_SKIN_WHITEN_HIGH
:
4611 macc_table
= &skin_high_macc_table
;
4612 asd
->params
.macc_en
= true;
4614 case V4L2_COLORFX_VIVID
:
4615 ctc_table
= &vivid_ctc_table
;
4620 atomisp_update_capture_mode(asd
);
4623 atomisp_css_set_cc_config(asd
, cc_config
);
4625 atomisp_css_set_macc_table(asd
, macc_table
);
4627 atomisp_css_set_ctc_table(asd
, ctc_table
);
4628 asd
->params
.color_effect
= (u32
)*effect
;
4629 asd
->params
.css_update_params_needed
= true;
4634 * Function to configure bad pixel correction
4636 int atomisp_bad_pixel(struct atomisp_sub_device
*asd
, int flag
,
4641 *value
= asd
->params
.bad_pixel_en
;
4644 asd
->params
.bad_pixel_en
= !!*value
;
4650 * Function to configure bad pixel correction params
4652 int atomisp_bad_pixel_param(struct atomisp_sub_device
*asd
, int flag
,
4653 struct atomisp_dp_config
*config
)
4656 /* Get bad pixel from current setup */
4657 if (atomisp_css_get_dp_config(asd
, config
))
4660 /* Set bad pixel to isp parameters */
4661 memcpy(&asd
->params
.css_param
.dp_config
, config
,
4662 sizeof(asd
->params
.css_param
.dp_config
));
4663 atomisp_css_set_dp_config(asd
, &asd
->params
.css_param
.dp_config
);
4664 asd
->params
.css_update_params_needed
= true;
4671 * Function to enable/disable video image stablization
4673 int atomisp_video_stable(struct atomisp_sub_device
*asd
, int flag
,
4677 *value
= asd
->params
.video_dis_en
;
4679 asd
->params
.video_dis_en
= !!*value
;
4685 * Function to configure fixed pattern noise
4687 int atomisp_fixed_pattern(struct atomisp_sub_device
*asd
, int flag
,
4692 *value
= asd
->params
.fpn_en
;
4697 asd
->params
.fpn_en
= 0;
4701 /* Add function to get black from from sensor with shutter off */
4706 atomisp_bytesperline_to_padded_width(unsigned int bytesperline
,
4707 enum atomisp_css_frame_format format
)
4710 case CSS_FRAME_FORMAT_UYVY
:
4711 case CSS_FRAME_FORMAT_YUYV
:
4712 case CSS_FRAME_FORMAT_RAW
:
4713 case CSS_FRAME_FORMAT_RGB565
:
4714 return bytesperline
/2;
4715 case CSS_FRAME_FORMAT_RGBA888
:
4716 return bytesperline
/4;
4717 /* The following cases could be removed, but we leave them
4718 in to document the formats that are included. */
4719 case CSS_FRAME_FORMAT_NV11
:
4720 case CSS_FRAME_FORMAT_NV12
:
4721 case CSS_FRAME_FORMAT_NV16
:
4722 case CSS_FRAME_FORMAT_NV21
:
4723 case CSS_FRAME_FORMAT_NV61
:
4724 case CSS_FRAME_FORMAT_YV12
:
4725 case CSS_FRAME_FORMAT_YV16
:
4726 case CSS_FRAME_FORMAT_YUV420
:
4727 case CSS_FRAME_FORMAT_YUV420_16
:
4728 case CSS_FRAME_FORMAT_YUV422
:
4729 case CSS_FRAME_FORMAT_YUV422_16
:
4730 case CSS_FRAME_FORMAT_YUV444
:
4731 case CSS_FRAME_FORMAT_YUV_LINE
:
4732 case CSS_FRAME_FORMAT_PLANAR_RGB888
:
4733 case CSS_FRAME_FORMAT_QPLANE6
:
4734 case CSS_FRAME_FORMAT_BINARY_8
:
4736 return bytesperline
;
4741 atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer
*arg
,
4742 struct atomisp_css_frame
**result
)
4744 struct atomisp_css_frame
*res
;
4745 unsigned int padded_width
;
4746 enum atomisp_css_frame_format sh_format
;
4747 char *tmp_buf
= NULL
;
4750 sh_format
= v4l2_fmt_to_sh_fmt(arg
->fmt
.pixelformat
);
4751 padded_width
= atomisp_bytesperline_to_padded_width(
4752 arg
->fmt
.bytesperline
, sh_format
);
4754 /* Note: the padded width on an atomisp_css_frame is in elements, not in
4755 bytes. The RAW frame we use here should always be a 16bit RAW
4756 frame. This is why we bytesperline/2 is equal to the padded with */
4757 if (atomisp_css_frame_allocate(&res
, arg
->fmt
.width
, arg
->fmt
.height
,
4758 sh_format
, padded_width
, 0)) {
4763 tmp_buf
= vmalloc(arg
->fmt
.sizeimage
);
4768 if (copy_from_user(tmp_buf
, (void __user __force
*)arg
->base
,
4769 arg
->fmt
.sizeimage
)) {
4774 if (hmm_store(res
->data
, tmp_buf
, arg
->fmt
.sizeimage
)) {
4781 atomisp_css_frame_free(res
);
4790 * Function to configure fixed pattern noise table
4792 int atomisp_fixed_pattern_table(struct atomisp_sub_device
*asd
,
4793 struct v4l2_framebuffer
*arg
)
4795 struct atomisp_css_frame
*raw_black_frame
= NULL
;
4801 ret
= atomisp_v4l2_framebuffer_to_css_frame(arg
, &raw_black_frame
);
4804 if (atomisp_css_set_black_frame(asd
, raw_black_frame
))
4807 atomisp_css_frame_free(raw_black_frame
);
4812 * Function to configure false color correction
4814 int atomisp_false_color(struct atomisp_sub_device
*asd
, int flag
,
4817 /* Get nr config from current setup */
4819 *value
= asd
->params
.false_color
;
4823 /* Set nr config to isp parameters */
4825 atomisp_css_set_default_de_config(asd
);
4827 asd
->params
.css_param
.de_config
.pixelnoise
= 0;
4828 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4830 asd
->params
.css_update_params_needed
= true;
4831 asd
->params
.false_color
= *value
;
4836 * Function to configure bad pixel correction params
4838 int atomisp_false_color_param(struct atomisp_sub_device
*asd
, int flag
,
4839 struct atomisp_de_config
*config
)
4842 /* Get false color from current setup */
4843 if (atomisp_css_get_de_config(asd
, config
))
4846 /* Set false color to isp parameters */
4847 memcpy(&asd
->params
.css_param
.de_config
, config
,
4848 sizeof(asd
->params
.css_param
.de_config
));
4849 atomisp_css_set_de_config(asd
, &asd
->params
.css_param
.de_config
);
4850 asd
->params
.css_update_params_needed
= true;
4857 * Function to configure white balance params
4859 int atomisp_white_balance_param(struct atomisp_sub_device
*asd
, int flag
,
4860 struct atomisp_wb_config
*config
)
4863 /* Get white balance from current setup */
4864 if (atomisp_css_get_wb_config(asd
, config
))
4867 /* Set white balance to isp parameters */
4868 memcpy(&asd
->params
.css_param
.wb_config
, config
,
4869 sizeof(asd
->params
.css_param
.wb_config
));
4870 atomisp_css_set_wb_config(asd
, &asd
->params
.css_param
.wb_config
);
4871 asd
->params
.css_update_params_needed
= true;
4877 int atomisp_3a_config_param(struct atomisp_sub_device
*asd
, int flag
,
4878 struct atomisp_3a_config
*config
)
4880 struct atomisp_device
*isp
= asd
->isp
;
4882 dev_dbg(isp
->dev
, ">%s %d\n", __func__
, flag
);
4885 /* Get white balance from current setup */
4886 if (atomisp_css_get_3a_config(asd
, config
))
4889 /* Set white balance to isp parameters */
4890 memcpy(&asd
->params
.css_param
.s3a_config
, config
,
4891 sizeof(asd
->params
.css_param
.s3a_config
));
4892 atomisp_css_set_3a_config(asd
, &asd
->params
.css_param
.s3a_config
);
4893 asd
->params
.css_update_params_needed
= true;
4896 dev_dbg(isp
->dev
, "<%s %d\n", __func__
, flag
);
4901 * Function to setup digital zoom
4903 int atomisp_digital_zoom(struct atomisp_sub_device
*asd
, int flag
,
4907 struct atomisp_device
*isp
= asd
->isp
;
4909 unsigned int max_zoom
= MRFLD_MAX_ZOOM_FACTOR
;
4912 atomisp_css_get_zoom_factor(asd
, &zoom
);
4913 *value
= max_zoom
- zoom
;
4918 zoom
= max_zoom
- min_t(u32
, max_zoom
- 1, *value
);
4919 atomisp_css_set_zoom_factor(asd
, zoom
);
4921 dev_dbg(isp
->dev
, "%s, zoom: %d\n", __func__
, zoom
);
4922 asd
->params
.css_update_params_needed
= true;
4929 * Function to get sensor specific info for current resolution,
4930 * which will be used for auto exposure conversion.
4932 int atomisp_get_sensor_mode_data(struct atomisp_sub_device
*asd
,
4933 struct atomisp_sensor_mode_data
*config
)
4935 struct camera_mipi_info
*mipi_info
;
4936 struct atomisp_device
*isp
= asd
->isp
;
4938 mipi_info
= atomisp_to_sensor_mipi_info(
4939 isp
->inputs
[asd
->input_curr
].camera
);
4940 if (mipi_info
== NULL
)
4943 memcpy(config
, &mipi_info
->data
, sizeof(*config
));
4947 int atomisp_get_fmt(struct video_device
*vdev
, struct v4l2_format
*f
)
4949 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
4951 f
->fmt
.pix
= pipe
->pix
;
4956 static void __atomisp_update_stream_env(struct atomisp_sub_device
*asd
,
4957 uint16_t stream_index
, struct atomisp_input_stream_info
*stream_info
)
4961 #if defined(ISP2401_NEW_INPUT_SYSTEM)
4962 /* assign virtual channel id return from sensor driver query */
4963 asd
->stream_env
[stream_index
].ch_id
= stream_info
->ch_id
;
4965 asd
->stream_env
[stream_index
].isys_configs
= stream_info
->isys_configs
;
4966 for (i
= 0; i
< stream_info
->isys_configs
; i
++) {
4967 asd
->stream_env
[stream_index
].isys_info
[i
].input_format
=
4968 stream_info
->isys_info
[i
].input_format
;
4969 asd
->stream_env
[stream_index
].isys_info
[i
].width
=
4970 stream_info
->isys_info
[i
].width
;
4971 asd
->stream_env
[stream_index
].isys_info
[i
].height
=
4972 stream_info
->isys_info
[i
].height
;
4976 static void __atomisp_init_stream_info(uint16_t stream_index
,
4977 struct atomisp_input_stream_info
*stream_info
)
4981 stream_info
->enable
= 1;
4982 stream_info
->stream
= stream_index
;
4983 stream_info
->ch_id
= 0;
4984 stream_info
->isys_configs
= 0;
4985 for (i
= 0; i
< MAX_STREAMS_PER_CHANNEL
; i
++) {
4986 stream_info
->isys_info
[i
].input_format
= 0;
4987 stream_info
->isys_info
[i
].width
= 0;
4988 stream_info
->isys_info
[i
].height
= 0;
4992 /* This function looks up the closest available resolution. */
4993 int atomisp_try_fmt(struct video_device
*vdev
, struct v4l2_format
*f
,
4996 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
4997 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
4999 struct v4l2_subdev_pad_config pad_cfg
;
5001 struct v4l2_subdev_pad_config pad_cfg
;
5003 struct v4l2_subdev_format format
= {
5004 .which
= V4L2_SUBDEV_FORMAT_TRY
,
5010 struct v4l2_mbus_framefmt
*snr_mbus_fmt
= &format
.format
;
5011 const struct atomisp_format_bridge
*fmt
;
5012 struct atomisp_input_stream_info
*stream_info
=
5014 (struct atomisp_input_stream_info
*)snr_mbus_fmt
->reserved
;
5016 (struct atomisp_input_stream_info
*)snr_mbus_fmt
->reserved
;
5018 uint16_t stream_index
;
5019 int source_pad
= atomisp_subdev_source_pad(vdev
);
5022 if (isp
->inputs
[asd
->input_curr
].camera
== NULL
)
5025 stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
5026 fmt
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
5028 dev_err(isp
->dev
, "unsupported pixelformat!\n");
5029 fmt
= atomisp_output_fmts
;
5033 if (f
->fmt
.pix
.width
<= 0 || f
->fmt
.pix
.height
<= 0)
5037 snr_mbus_fmt
->code
= fmt
->mbus_code
;
5038 snr_mbus_fmt
->width
= f
->fmt
.pix
.width
;
5039 snr_mbus_fmt
->height
= f
->fmt
.pix
.height
;
5041 __atomisp_init_stream_info(stream_index
, stream_info
);
5043 dev_dbg(isp
->dev
, "try_mbus_fmt: asking for %ux%u\n",
5044 snr_mbus_fmt
->width
, snr_mbus_fmt
->height
);
5046 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
5048 pad
, set_fmt
, &pad_cfg
, &format
);
5050 pad
, set_fmt
, &pad_cfg
, &format
);
5055 dev_dbg(isp
->dev
, "try_mbus_fmt: got %ux%u\n",
5056 snr_mbus_fmt
->width
, snr_mbus_fmt
->height
);
5058 fmt
= atomisp_get_format_bridge_from_mbus(snr_mbus_fmt
->code
);
5060 dev_err(isp
->dev
, "unknown sensor format 0x%8.8x\n",
5061 snr_mbus_fmt
->code
);
5065 f
->fmt
.pix
.pixelformat
= fmt
->pixelformat
;
5068 * If the format is jpeg or custom RAW, then the width and height will
5069 * not satisfy the normal atomisp requirements and no need to check
5070 * the below conditions. So just assign to what is being returned from
5071 * the sensor driver.
5073 if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_JPEG
||
5074 f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_CUSTOM_M10MO_RAW
) {
5075 f
->fmt
.pix
.width
= snr_mbus_fmt
->width
;
5076 f
->fmt
.pix
.height
= snr_mbus_fmt
->height
;
5080 if (snr_mbus_fmt
->width
< f
->fmt
.pix
.width
5081 && snr_mbus_fmt
->height
< f
->fmt
.pix
.height
) {
5082 f
->fmt
.pix
.width
= snr_mbus_fmt
->width
;
5083 f
->fmt
.pix
.height
= snr_mbus_fmt
->height
;
5084 /* Set the flag when resolution requested is
5085 * beyond the max value supported by sensor
5087 if (res_overflow
!= NULL
)
5088 *res_overflow
= true;
5092 f
->fmt
.pix
.width
= rounddown(
5093 clamp_t(u32
, f
->fmt
.pix
.width
, ATOM_ISP_MIN_WIDTH
,
5094 ATOM_ISP_MAX_WIDTH
), ATOM_ISP_STEP_WIDTH
);
5095 f
->fmt
.pix
.height
= rounddown(
5096 clamp_t(u32
, f
->fmt
.pix
.height
, ATOM_ISP_MIN_HEIGHT
,
5097 ATOM_ISP_MAX_HEIGHT
), ATOM_ISP_STEP_HEIGHT
);
5103 atomisp_try_fmt_file(struct atomisp_device
*isp
, struct v4l2_format
*f
)
5105 u32 width
= f
->fmt
.pix
.width
;
5106 u32 height
= f
->fmt
.pix
.height
;
5107 u32 pixelformat
= f
->fmt
.pix
.pixelformat
;
5108 enum v4l2_field field
= f
->fmt
.pix
.field
;
5111 if (!atomisp_get_format_bridge(pixelformat
)) {
5112 dev_err(isp
->dev
, "Wrong output pixelformat\n");
5116 depth
= get_pixel_depth(pixelformat
);
5118 if (!field
|| field
== V4L2_FIELD_ANY
)
5119 field
= V4L2_FIELD_NONE
;
5120 else if (field
!= V4L2_FIELD_NONE
) {
5121 dev_err(isp
->dev
, "Wrong output field\n");
5125 f
->fmt
.pix
.field
= field
;
5126 f
->fmt
.pix
.width
= clamp_t(u32
,
5127 rounddown(width
, (u32
)ATOM_ISP_STEP_WIDTH
),
5128 ATOM_ISP_MIN_WIDTH
, ATOM_ISP_MAX_WIDTH
);
5129 f
->fmt
.pix
.height
= clamp_t(u32
, rounddown(height
,
5130 (u32
)ATOM_ISP_STEP_HEIGHT
),
5131 ATOM_ISP_MIN_HEIGHT
, ATOM_ISP_MAX_HEIGHT
);
5132 f
->fmt
.pix
.bytesperline
= (width
* depth
) >> 3;
5137 mipi_port_ID_t
__get_mipi_port(struct atomisp_device
*isp
,
5138 enum atomisp_camera_port port
)
5141 case ATOMISP_CAMERA_PORT_PRIMARY
:
5142 return MIPI_PORT0_ID
;
5143 case ATOMISP_CAMERA_PORT_SECONDARY
:
5144 return MIPI_PORT1_ID
;
5145 case ATOMISP_CAMERA_PORT_TERTIARY
:
5146 if (MIPI_PORT1_ID
+ 1 != N_MIPI_PORT_ID
)
5147 return MIPI_PORT1_ID
+ 1;
5148 /* go through down for else case */
5150 dev_err(isp
->dev
, "unsupported port: %d\n", port
);
5151 return MIPI_PORT0_ID
;
5155 static inline int atomisp_set_sensor_mipi_to_isp(
5156 struct atomisp_sub_device
*asd
,
5157 enum atomisp_input_stream_id stream_id
,
5158 struct camera_mipi_info
*mipi_info
)
5160 struct v4l2_control ctrl
;
5161 struct atomisp_device
*isp
= asd
->isp
;
5162 const struct atomisp_in_fmt_conv
*fc
;
5164 unsigned int input_format
, bayer_order
;
5166 ctrl
.id
= V4L2_CID_LINK_FREQ
;
5168 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
) == 0)
5169 mipi_freq
= ctrl
.value
;
5171 if (asd
->stream_env
[stream_id
].isys_configs
== 1) {
5173 asd
->stream_env
[stream_id
].isys_info
[0].input_format
;
5174 atomisp_css_isys_set_format(asd
, stream_id
,
5175 input_format
, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX
);
5176 } else if (asd
->stream_env
[stream_id
].isys_configs
== 2) {
5177 atomisp_css_isys_two_stream_cfg_update_stream1(
5179 asd
->stream_env
[stream_id
].isys_info
[0].input_format
,
5180 asd
->stream_env
[stream_id
].isys_info
[0].width
,
5181 asd
->stream_env
[stream_id
].isys_info
[0].height
);
5183 atomisp_css_isys_two_stream_cfg_update_stream2(
5185 asd
->stream_env
[stream_id
].isys_info
[1].input_format
,
5186 asd
->stream_env
[stream_id
].isys_info
[1].width
,
5187 asd
->stream_env
[stream_id
].isys_info
[1].height
);
5190 /* Compatibility for sensors which provide no media bus code
5191 * in s_mbus_framefmt() nor support pad formats. */
5192 if (mipi_info
->input_format
!= -1) {
5193 bayer_order
= mipi_info
->raw_bayer_order
;
5195 /* Input stream config is still needs configured */
5196 /* TODO: Check if this is necessary */
5197 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5198 mipi_info
->input_format
);
5201 input_format
= fc
->css_stream_fmt
;
5203 struct v4l2_mbus_framefmt
*sink
;
5204 sink
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5205 V4L2_SUBDEV_FORMAT_ACTIVE
,
5206 ATOMISP_SUBDEV_PAD_SINK
);
5207 fc
= atomisp_find_in_fmt_conv(sink
->code
);
5210 input_format
= fc
->css_stream_fmt
;
5211 bayer_order
= fc
->bayer_order
;
5214 atomisp_css_input_set_format(asd
, stream_id
, input_format
);
5215 atomisp_css_input_set_bayer_order(asd
, stream_id
, bayer_order
);
5217 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5218 mipi_info
->metadata_format
);
5221 input_format
= fc
->css_stream_fmt
;
5222 atomisp_css_input_configure_port(asd
,
5223 __get_mipi_port(asd
->isp
, mipi_info
->port
),
5224 mipi_info
->num_lanes
,
5227 mipi_info
->metadata_width
,
5228 mipi_info
->metadata_height
);
5232 static int __enable_continuous_mode(struct atomisp_sub_device
*asd
,
5235 struct atomisp_device
*isp
= asd
->isp
;
5238 "continuous mode %d, raw buffers %d, stop preview %d\n",
5239 enable
, asd
->continuous_raw_buffer_size
->val
,
5240 !asd
->continuous_viewfinder
->val
);
5242 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_PRIMARY
);
5244 atomisp_update_capture_mode(asd
);
5246 /* in case of ANR, force capture pipe to offline mode */
5247 atomisp_css_capture_enable_online(asd
, ATOMISP_INPUT_STREAM_GENERAL
,
5248 asd
->params
.low_light
? false : !enable
);
5249 atomisp_css_preview_enable_online(asd
, ATOMISP_INPUT_STREAM_GENERAL
,
5251 atomisp_css_enable_continuous(asd
, enable
);
5252 atomisp_css_enable_cvf(asd
, asd
->continuous_viewfinder
->val
);
5254 if (atomisp_css_continuous_set_num_raw_frames(asd
,
5255 asd
->continuous_raw_buffer_size
->val
)) {
5256 dev_err(isp
->dev
, "css_continuous_set_num_raw_frames failed\n");
5261 atomisp_css_enable_raw_binning(asd
, false);
5262 atomisp_css_input_set_two_pixels_per_clock(asd
, false);
5265 if (isp
->inputs
[asd
->input_curr
].type
!= FILE_INPUT
)
5266 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_SENSOR
);
5268 return atomisp_update_run_mode(asd
);
5271 int configure_pp_input_nop(struct atomisp_sub_device
*asd
,
5272 unsigned int width
, unsigned int height
)
5277 int configure_output_nop(struct atomisp_sub_device
*asd
,
5278 unsigned int width
, unsigned int height
,
5279 unsigned int min_width
,
5280 enum atomisp_css_frame_format sh_fmt
)
5285 int get_frame_info_nop(struct atomisp_sub_device
*asd
,
5286 struct atomisp_css_frame_info
*finfo
)
5292 * Resets CSS parameters that depend on input resolution.
5294 * Update params like CSS RAW binning, 2ppc mode and pp_input
5295 * which depend on input size, but are not automatically
5296 * handled in CSS when the input resolution is changed.
5298 static int css_input_resolution_changed(struct atomisp_sub_device
*asd
,
5299 struct v4l2_mbus_framefmt
*ffmt
)
5301 struct atomisp_metadata_buf
*md_buf
= NULL
, *_md_buf
;
5304 dev_dbg(asd
->isp
->dev
, "css_input_resolution_changed to %ux%u\n",
5305 ffmt
->width
, ffmt
->height
);
5307 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5308 atomisp_css_input_set_two_pixels_per_clock(asd
, false);
5310 atomisp_css_input_set_two_pixels_per_clock(asd
, true);
5312 if (asd
->continuous_mode
->val
) {
5313 /* Note for all checks: ffmt includes pad_w+pad_h */
5314 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
||
5315 (ffmt
->width
>= 2048 || ffmt
->height
>= 1536)) {
5317 * For preview pipe, enable only if resolution
5318 * is >= 3M for ISP2400.
5320 atomisp_css_enable_raw_binning(asd
, true);
5324 * If sensor input changed, which means metadata resolution changed
5325 * together. Release all metadata buffers here to let it re-allocated
5326 * next time in reqbufs.
5328 for (i
= 0; i
< ATOMISP_METADATA_TYPE_NUM
; i
++) {
5329 list_for_each_entry_safe(md_buf
, _md_buf
, &asd
->metadata
[i
],
5331 atomisp_css_free_metadata_buffer(md_buf
);
5332 list_del(&md_buf
->list
);
5339 * TODO: atomisp_css_preview_configure_pp_input() not
5340 * reset due to CSS bug tracked as PSI BZ 115124
5344 static int atomisp_set_fmt_to_isp(struct video_device
*vdev
,
5345 struct atomisp_css_frame_info
*output_info
,
5346 struct atomisp_css_frame_info
*raw_output_info
,
5347 struct v4l2_pix_format
*pix
,
5348 unsigned int source_pad
)
5350 struct camera_mipi_info
*mipi_info
;
5351 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
5352 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
5353 const struct atomisp_format_bridge
*format
;
5354 struct v4l2_rect
*isp_sink_crop
;
5355 enum atomisp_css_pipe_id pipe_id
;
5356 struct v4l2_subdev_fh fh
;
5357 int (*configure_output
)(struct atomisp_sub_device
*asd
,
5358 unsigned int width
, unsigned int height
,
5359 unsigned int min_width
,
5360 enum atomisp_css_frame_format sh_fmt
) =
5361 configure_output_nop
;
5362 int (*get_frame_info
)(struct atomisp_sub_device
*asd
,
5363 struct atomisp_css_frame_info
*finfo
) =
5365 int (*configure_pp_input
)(struct atomisp_sub_device
*asd
,
5366 unsigned int width
, unsigned int height
) =
5367 configure_pp_input_nop
;
5368 uint16_t stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
5369 const struct atomisp_in_fmt_conv
*fc
;
5372 v4l2_fh_init(&fh
.vfh
, vdev
);
5374 isp_sink_crop
= atomisp_subdev_get_rect(
5375 &asd
->subdev
, NULL
, V4L2_SUBDEV_FORMAT_ACTIVE
,
5376 ATOMISP_SUBDEV_PAD_SINK
, V4L2_SEL_TGT_CROP
);
5378 format
= atomisp_get_format_bridge(pix
->pixelformat
);
5382 if (isp
->inputs
[asd
->input_curr
].type
!= TEST_PATTERN
&&
5383 isp
->inputs
[asd
->input_curr
].type
!= FILE_INPUT
) {
5384 mipi_info
= atomisp_to_sensor_mipi_info(
5385 isp
->inputs
[asd
->input_curr
].camera
);
5387 dev_err(isp
->dev
, "mipi_info is NULL\n");
5390 if (atomisp_set_sensor_mipi_to_isp(asd
, stream_index
,
5393 fc
= atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
5394 mipi_info
->input_format
);
5396 fc
= atomisp_find_in_fmt_conv(
5397 atomisp_subdev_get_ffmt(&asd
->subdev
,
5398 NULL
, V4L2_SUBDEV_FORMAT_ACTIVE
,
5399 ATOMISP_SUBDEV_PAD_SINK
)->code
);
5402 if (format
->sh_fmt
== CSS_FRAME_FORMAT_RAW
&&
5403 raw_output_format_match_input(fc
->css_stream_fmt
,
5409 * Configure viewfinder also when vfpp is disabled: the
5410 * CSS still requires viewfinder configuration.
5412 if (asd
->fmt_auto
->val
||
5413 asd
->vfpp
->val
!= ATOMISP_VFPP_ENABLE
) {
5414 struct v4l2_rect vf_size
= {0};
5415 struct v4l2_mbus_framefmt vf_ffmt
= {0};
5417 if (pix
->width
< 640 || pix
->height
< 480) {
5418 vf_size
.width
= pix
->width
;
5419 vf_size
.height
= pix
->height
;
5421 vf_size
.width
= 640;
5422 vf_size
.height
= 480;
5425 /* FIXME: proper format name for this one. See
5426 atomisp_output_fmts[] in atomisp_v4l2.c */
5427 vf_ffmt
.code
= V4L2_MBUS_FMT_CUSTOM_YUV420
;
5429 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
5430 V4L2_SUBDEV_FORMAT_ACTIVE
,
5431 ATOMISP_SUBDEV_PAD_SOURCE_VF
,
5432 V4L2_SEL_TGT_COMPOSE
, 0, &vf_size
);
5433 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5434 V4L2_SUBDEV_FORMAT_ACTIVE
,
5435 ATOMISP_SUBDEV_PAD_SOURCE_VF
, &vf_ffmt
);
5436 asd
->video_out_vf
.sh_fmt
= CSS_FRAME_FORMAT_NV12
;
5438 if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
) {
5439 atomisp_css_video_configure_viewfinder(asd
,
5440 vf_size
.width
, vf_size
.height
, 0,
5441 asd
->video_out_vf
.sh_fmt
);
5442 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5443 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5444 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
)
5445 atomisp_css_video_configure_viewfinder(asd
,
5446 vf_size
.width
, vf_size
.height
, 0,
5447 asd
->video_out_vf
.sh_fmt
);
5449 atomisp_css_capture_configure_viewfinder(asd
,
5450 vf_size
.width
, vf_size
.height
, 0,
5451 asd
->video_out_vf
.sh_fmt
);
5452 } else if (source_pad
!= ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5453 asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_LOWLAT
) {
5454 atomisp_css_capture_configure_viewfinder(asd
,
5455 vf_size
.width
, vf_size
.height
, 0,
5456 asd
->video_out_vf
.sh_fmt
);
5460 if (asd
->continuous_mode
->val
) {
5461 ret
= __enable_continuous_mode(asd
, true);
5466 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_SENSOR
);
5467 atomisp_css_disable_vf_pp(asd
,
5468 asd
->vfpp
->val
!= ATOMISP_VFPP_ENABLE
);
5470 /* ISP2401 new input system need to use copy pipe */
5471 if (asd
->copy_mode
) {
5472 pipe_id
= CSS_PIPE_ID_COPY
;
5473 atomisp_css_capture_enable_online(asd
, stream_index
, false);
5474 } else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
) {
5475 /* video same in continuouscapture and online modes */
5476 configure_output
= atomisp_css_video_configure_output
;
5477 get_frame_info
= atomisp_css_video_get_output_frame_info
;
5478 pipe_id
= CSS_PIPE_ID_VIDEO
;
5479 } else if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5480 if (!asd
->continuous_mode
->val
) {
5481 configure_output
= atomisp_css_video_configure_output
;
5483 atomisp_css_video_get_output_frame_info
;
5484 pipe_id
= CSS_PIPE_ID_VIDEO
;
5486 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
||
5487 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
) {
5489 atomisp_css_video_configure_output
;
5491 atomisp_css_video_get_output_frame_info
;
5492 configure_pp_input
=
5493 atomisp_css_video_configure_pp_input
;
5494 pipe_id
= CSS_PIPE_ID_VIDEO
;
5497 atomisp_css_capture_configure_output
;
5499 atomisp_css_capture_get_output_frame_info
;
5500 configure_pp_input
=
5501 atomisp_css_capture_configure_pp_input
;
5502 pipe_id
= CSS_PIPE_ID_CAPTURE
;
5504 atomisp_update_capture_mode(asd
);
5505 atomisp_css_capture_enable_online(asd
, stream_index
, false);
5508 } else if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
) {
5509 configure_output
= atomisp_css_preview_configure_output
;
5510 get_frame_info
= atomisp_css_preview_get_output_frame_info
;
5511 configure_pp_input
= atomisp_css_preview_configure_pp_input
;
5512 pipe_id
= CSS_PIPE_ID_PREVIEW
;
5514 /* CSS doesn't support low light mode on SOC cameras, so disable
5515 * it. FIXME: if this is done elsewhere, it gives corrupted
5516 * colors into thumbnail image.
5518 if (isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
)
5519 asd
->params
.low_light
= false;
5521 if (format
->sh_fmt
== CSS_FRAME_FORMAT_RAW
) {
5522 atomisp_css_capture_set_mode(asd
, CSS_CAPTURE_MODE_RAW
);
5523 atomisp_css_enable_dz(asd
, false);
5525 atomisp_update_capture_mode(asd
);
5528 if (!asd
->continuous_mode
->val
)
5529 /* in case of ANR, force capture pipe to offline mode */
5530 atomisp_css_capture_enable_online(asd
, stream_index
,
5531 asd
->params
.low_light
?
5532 false : asd
->params
.online_process
);
5534 configure_output
= atomisp_css_capture_configure_output
;
5535 get_frame_info
= atomisp_css_capture_get_output_frame_info
;
5536 configure_pp_input
= atomisp_css_capture_configure_pp_input
;
5537 pipe_id
= CSS_PIPE_ID_CAPTURE
;
5539 if (!asd
->params
.online_process
&&
5540 !asd
->continuous_mode
->val
) {
5541 ret
= atomisp_css_capture_get_output_raw_frame_info(asd
,
5546 if (!asd
->continuous_mode
->val
&& asd
->run_mode
->val
5547 != ATOMISP_RUN_MODE_STILL_CAPTURE
) {
5549 "Need to set the running mode first\n");
5550 asd
->run_mode
->val
= ATOMISP_RUN_MODE_STILL_CAPTURE
;
5555 * to SOC camera, use yuvpp pipe.
5557 if (ATOMISP_USE_YUVPP(asd
))
5558 pipe_id
= CSS_PIPE_ID_YUVPP
;
5561 ret
= atomisp_css_copy_configure_output(asd
, stream_index
,
5562 pix
->width
, pix
->height
,
5563 format
->planar
? pix
->bytesperline
:
5564 pix
->bytesperline
* 8 / format
->depth
,
5567 ret
= configure_output(asd
, pix
->width
, pix
->height
,
5568 format
->planar
? pix
->bytesperline
:
5569 pix
->bytesperline
* 8 / format
->depth
,
5572 dev_err(isp
->dev
, "configure_output %ux%u, format %8.8x\n",
5573 pix
->width
, pix
->height
, format
->sh_fmt
);
5577 if (asd
->continuous_mode
->val
&&
5578 (configure_pp_input
== atomisp_css_preview_configure_pp_input
||
5579 configure_pp_input
== atomisp_css_video_configure_pp_input
)) {
5580 /* for isp 2.2, configure pp input is available for continuous
5582 ret
= configure_pp_input(asd
, isp_sink_crop
->width
,
5583 isp_sink_crop
->height
);
5585 dev_err(isp
->dev
, "configure_pp_input %ux%u\n",
5586 isp_sink_crop
->width
,
5587 isp_sink_crop
->height
);
5591 ret
= configure_pp_input(asd
, isp_sink_crop
->width
,
5592 isp_sink_crop
->height
);
5594 dev_err(isp
->dev
, "configure_pp_input %ux%u\n",
5595 isp_sink_crop
->width
, isp_sink_crop
->height
);
5600 ret
= atomisp_css_copy_get_output_frame_info(asd
, stream_index
,
5603 ret
= get_frame_info(asd
, output_info
);
5605 dev_err(isp
->dev
, "get_frame_info %ux%u (padded to %u)\n",
5606 pix
->width
, pix
->height
, pix
->bytesperline
);
5610 atomisp_update_grid_info(asd
, pipe_id
, source_pad
);
5612 /* Free the raw_dump buffer first */
5613 atomisp_css_frame_free(asd
->raw_output_frame
);
5614 asd
->raw_output_frame
= NULL
;
5616 if (!asd
->continuous_mode
->val
&&
5617 !asd
->params
.online_process
&& !isp
->sw_contex
.file_input
&&
5618 atomisp_css_frame_allocate_from_info(&asd
->raw_output_frame
,
5625 static void atomisp_get_dis_envelop(struct atomisp_sub_device
*asd
,
5626 unsigned int width
, unsigned int height
,
5627 unsigned int *dvs_env_w
, unsigned int *dvs_env_h
)
5629 struct atomisp_device
*isp
= asd
->isp
;
5631 /* if subdev type is SOC camera,we do not need to set DVS */
5632 if (isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
)
5633 asd
->params
.video_dis_en
= 0;
5635 if (asd
->params
.video_dis_en
&&
5636 asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
) {
5637 /* envelope is 20% of the output resolution */
5639 * dvs envelope cannot be round up.
5640 * it would cause ISP timeout and color switch issue
5642 *dvs_env_w
= rounddown(width
/ 5, ATOM_ISP_STEP_WIDTH
);
5643 *dvs_env_h
= rounddown(height
/ 5, ATOM_ISP_STEP_HEIGHT
);
5646 asd
->params
.dis_proj_data_valid
= false;
5647 asd
->params
.css_update_params_needed
= true;
5650 static void atomisp_check_copy_mode(struct atomisp_sub_device
*asd
,
5651 int source_pad
, struct v4l2_format
*f
)
5653 #if defined(ISP2401_NEW_INPUT_SYSTEM)
5654 struct v4l2_mbus_framefmt
*sink
, *src
;
5656 sink
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5657 V4L2_SUBDEV_FORMAT_ACTIVE
, ATOMISP_SUBDEV_PAD_SINK
);
5658 src
= atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5659 V4L2_SUBDEV_FORMAT_ACTIVE
, source_pad
);
5661 if ((sink
->code
== src
->code
&&
5662 sink
->width
== f
->fmt
.pix
.width
&&
5663 sink
->height
== f
->fmt
.pix
.height
) ||
5664 ((asd
->isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
) &&
5665 (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
5666 sensor
[asd
->sensor_curr
].stream_num
> 1)))
5667 asd
->copy_mode
= true;
5670 /* Only used for the new input system */
5671 asd
->copy_mode
= false;
5673 dev_dbg(asd
->isp
->dev
, "copy_mode: %d\n", asd
->copy_mode
);
5677 static int atomisp_set_fmt_to_snr(struct video_device
*vdev
,
5678 struct v4l2_format
*f
, unsigned int pixelformat
,
5679 unsigned int padding_w
, unsigned int padding_h
,
5680 unsigned int dvs_env_w
, unsigned int dvs_env_h
)
5682 struct atomisp_sub_device
*asd
= atomisp_to_video_pipe(vdev
)->asd
;
5683 const struct atomisp_format_bridge
*format
;
5684 struct v4l2_subdev_pad_config pad_cfg
;
5685 struct v4l2_subdev_format vformat
= {
5686 .which
= V4L2_SUBDEV_FORMAT_TRY
,
5688 struct v4l2_mbus_framefmt
*ffmt
= &vformat
.format
;
5689 struct v4l2_mbus_framefmt
*req_ffmt
;
5690 struct atomisp_device
*isp
= asd
->isp
;
5691 struct atomisp_input_stream_info
*stream_info
=
5692 (struct atomisp_input_stream_info
*)ffmt
->reserved
;
5693 uint16_t stream_index
= ATOMISP_INPUT_STREAM_GENERAL
;
5694 int source_pad
= atomisp_subdev_source_pad(vdev
);
5695 struct v4l2_subdev_fh fh
;
5698 v4l2_fh_init(&fh
.vfh
, vdev
);
5700 stream_index
= atomisp_source_pad_to_stream_id(asd
, source_pad
);
5702 format
= atomisp_get_format_bridge(pixelformat
);
5706 v4l2_fill_mbus_format(ffmt
, &f
->fmt
.pix
, format
->mbus_code
);
5707 ffmt
->height
+= padding_h
+ dvs_env_h
;
5708 ffmt
->width
+= padding_w
+ dvs_env_w
;
5710 dev_dbg(isp
->dev
, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n",
5711 ffmt
->width
, ffmt
->height
, padding_w
, padding_h
,
5712 dvs_env_w
, dvs_env_h
);
5714 __atomisp_init_stream_info(stream_index
, stream_info
);
5718 /* Disable dvs if resolution can't be supported by sensor */
5719 if (asd
->params
.video_dis_en
&&
5720 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
) {
5721 vformat
.which
= V4L2_SUBDEV_FORMAT_TRY
;
5722 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
5723 pad
, set_fmt
, &pad_cfg
, &vformat
);
5726 if (ffmt
->width
< req_ffmt
->width
||
5727 ffmt
->height
< req_ffmt
->height
) {
5728 req_ffmt
->height
-= dvs_env_h
;
5729 req_ffmt
->width
-= dvs_env_w
;
5732 "can not enable video dis due to sensor limitation.");
5733 asd
->params
.video_dis_en
= 0;
5736 dev_dbg(isp
->dev
, "sensor width: %d, height: %d\n",
5737 ffmt
->width
, ffmt
->height
);
5738 vformat
.which
= V4L2_SUBDEV_FORMAT_ACTIVE
;
5739 ret
= v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
, pad
,
5740 set_fmt
, NULL
, &vformat
);
5744 __atomisp_update_stream_env(asd
, stream_index
, stream_info
);
5746 dev_dbg(isp
->dev
, "sensor width: %d, height: %d\n",
5747 ffmt
->width
, ffmt
->height
);
5749 if (ffmt
->width
< ATOM_ISP_STEP_WIDTH
||
5750 ffmt
->height
< ATOM_ISP_STEP_HEIGHT
)
5753 if (asd
->params
.video_dis_en
&&
5754 source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
&&
5755 (ffmt
->width
< req_ffmt
->width
|| ffmt
->height
< req_ffmt
->height
)) {
5757 "can not enable video dis due to sensor limitation.");
5758 asd
->params
.video_dis_en
= 0;
5761 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5762 V4L2_SUBDEV_FORMAT_ACTIVE
,
5763 ATOMISP_SUBDEV_PAD_SINK
, ffmt
);
5765 return css_input_resolution_changed(asd
, ffmt
);
5768 int atomisp_set_fmt(struct video_device
*vdev
, struct v4l2_format
*f
)
5770 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
5771 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
5772 struct atomisp_sub_device
*asd
= pipe
->asd
;
5773 const struct atomisp_format_bridge
*format_bridge
;
5774 const struct atomisp_format_bridge
*snr_format_bridge
;
5775 struct atomisp_css_frame_info output_info
, raw_output_info
;
5776 struct v4l2_format snr_fmt
= *f
;
5777 struct v4l2_format backup_fmt
= *f
, s_fmt
= *f
;
5778 unsigned int dvs_env_w
= 0, dvs_env_h
= 0;
5779 unsigned int padding_w
= pad_w
, padding_h
= pad_h
;
5780 bool res_overflow
= false, crop_needs_override
= false;
5781 struct v4l2_mbus_framefmt isp_sink_fmt
;
5782 struct v4l2_mbus_framefmt isp_source_fmt
= {0};
5783 struct v4l2_rect isp_sink_crop
;
5784 uint16_t source_pad
= atomisp_subdev_source_pad(vdev
);
5785 struct v4l2_subdev_fh fh
;
5789 "setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n",
5790 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
, source_pad
,
5791 asd
->index
, f
->fmt
.pix
.bytesperline
);
5793 if (source_pad
>= ATOMISP_SUBDEV_PADS_NUM
)
5796 if (asd
->streaming
== ATOMISP_DEVICE_STREAMING_ENABLED
) {
5797 dev_warn(isp
->dev
, "ISP does not support set format while at streaming!\n");
5801 v4l2_fh_init(&fh
.vfh
, vdev
);
5803 format_bridge
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
5804 if (format_bridge
== NULL
)
5807 pipe
->sh_fmt
= format_bridge
->sh_fmt
;
5808 pipe
->pix
.pixelformat
= f
->fmt
.pix
.pixelformat
;
5810 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_VF
||
5811 (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5812 && asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)) {
5813 if (asd
->fmt_auto
->val
) {
5814 struct v4l2_rect
*capture_comp
;
5815 struct v4l2_rect r
= {0};
5817 r
.width
= f
->fmt
.pix
.width
;
5818 r
.height
= f
->fmt
.pix
.height
;
5820 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
)
5821 capture_comp
= atomisp_subdev_get_rect(
5823 V4L2_SUBDEV_FORMAT_ACTIVE
,
5824 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
,
5825 V4L2_SEL_TGT_COMPOSE
);
5827 capture_comp
= atomisp_subdev_get_rect(
5829 V4L2_SUBDEV_FORMAT_ACTIVE
,
5830 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
,
5831 V4L2_SEL_TGT_COMPOSE
);
5833 if (capture_comp
->width
< r
.width
5834 || capture_comp
->height
< r
.height
) {
5835 r
.width
= capture_comp
->width
;
5836 r
.height
= capture_comp
->height
;
5839 atomisp_subdev_set_selection(
5840 &asd
->subdev
, fh
.pad
,
5841 V4L2_SUBDEV_FORMAT_ACTIVE
, source_pad
,
5842 V4L2_SEL_TGT_COMPOSE
, 0, &r
);
5844 f
->fmt
.pix
.width
= r
.width
;
5845 f
->fmt
.pix
.height
= r
.height
;
5848 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
&&
5849 (asd
->isp
->inputs
[asd
->input_curr
].type
== SOC_CAMERA
) &&
5850 (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
5851 sensor
[asd
->sensor_curr
].stream_num
> 1)) {
5852 /* For M10MO outputing YUV preview images. */
5853 uint16_t video_index
=
5854 atomisp_source_pad_to_stream_id(asd
,
5855 ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
);
5857 ret
= atomisp_css_copy_get_output_frame_info(asd
,
5858 video_index
, &output_info
);
5861 "copy_get_output_frame_info ret %i", ret
);
5864 if (!asd
->yuvpp_mode
) {
5866 * If viewfinder was configured into copy_mode,
5867 * we switch to using yuvpp pipe instead.
5869 asd
->yuvpp_mode
= true;
5870 ret
= atomisp_css_copy_configure_output(
5871 asd
, video_index
, 0, 0, 0, 0);
5874 "failed to disable copy pipe");
5877 ret
= atomisp_css_yuvpp_configure_output(
5879 output_info
.res
.width
,
5880 output_info
.res
.height
,
5881 output_info
.padded_width
,
5882 output_info
.format
);
5885 "failed to set up yuvpp pipe\n");
5888 atomisp_css_video_enable_online(asd
, false);
5889 atomisp_css_preview_enable_online(asd
,
5890 ATOMISP_INPUT_STREAM_GENERAL
, false);
5892 atomisp_css_yuvpp_configure_viewfinder(asd
, video_index
,
5893 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5894 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5895 : f
->fmt
.pix
.bytesperline
* 8
5896 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5897 atomisp_css_yuvpp_get_viewfinder_frame_info(
5898 asd
, video_index
, &output_info
);
5899 } else if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
) {
5900 atomisp_css_video_configure_viewfinder(asd
,
5901 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5902 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5903 : f
->fmt
.pix
.bytesperline
* 8
5904 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5905 atomisp_css_video_get_viewfinder_frame_info(asd
,
5907 asd
->copy_mode
= false;
5909 atomisp_css_capture_configure_viewfinder(asd
,
5910 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5911 format_bridge
->planar
? f
->fmt
.pix
.bytesperline
5912 : f
->fmt
.pix
.bytesperline
* 8
5913 / format_bridge
->depth
, format_bridge
->sh_fmt
);
5914 atomisp_css_capture_get_viewfinder_frame_info(asd
,
5916 asd
->copy_mode
= false;
5922 * Check whether main resolution configured smaller
5923 * than snapshot resolution. If so, force main resolution
5924 * to be the same as snapshot resolution
5926 if (source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
) {
5927 struct v4l2_rect
*r
;
5929 r
= atomisp_subdev_get_rect(
5931 V4L2_SUBDEV_FORMAT_ACTIVE
,
5932 ATOMISP_SUBDEV_PAD_SOURCE_VF
, V4L2_SEL_TGT_COMPOSE
);
5934 if (r
->width
&& r
->height
5935 && (r
->width
> f
->fmt
.pix
.width
5936 || r
->height
> f
->fmt
.pix
.height
))
5938 "Main Resolution config smaller then Vf Resolution. Force to be equal with Vf Resolution.");
5941 /* Pipeline configuration done through subdevs. Bail out now. */
5942 if (!asd
->fmt_auto
->val
)
5943 goto set_fmt_to_isp
;
5945 /* get sensor resolution and format */
5946 ret
= atomisp_try_fmt(vdev
, &snr_fmt
, &res_overflow
);
5949 f
->fmt
.pix
.width
= snr_fmt
.fmt
.pix
.width
;
5950 f
->fmt
.pix
.height
= snr_fmt
.fmt
.pix
.height
;
5953 atomisp_get_format_bridge(snr_fmt
.fmt
.pix
.pixelformat
);
5954 if (!snr_format_bridge
)
5957 atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5958 V4L2_SUBDEV_FORMAT_ACTIVE
,
5959 ATOMISP_SUBDEV_PAD_SINK
)->code
=
5960 snr_format_bridge
->mbus_code
;
5962 isp_sink_fmt
= *atomisp_subdev_get_ffmt(&asd
->subdev
, NULL
,
5963 V4L2_SUBDEV_FORMAT_ACTIVE
,
5964 ATOMISP_SUBDEV_PAD_SINK
);
5966 isp_source_fmt
.code
= format_bridge
->mbus_code
;
5967 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
,
5968 V4L2_SUBDEV_FORMAT_ACTIVE
,
5969 source_pad
, &isp_source_fmt
);
5971 if (!atomisp_subdev_format_conversion(asd
, source_pad
)) {
5974 } else if (IS_BYT
) {
5979 /* construct resolution supported by isp */
5980 if (res_overflow
&& !asd
->continuous_mode
->val
) {
5981 f
->fmt
.pix
.width
= rounddown(
5982 clamp_t(u32
, f
->fmt
.pix
.width
- padding_w
,
5984 ATOM_ISP_MAX_WIDTH
), ATOM_ISP_STEP_WIDTH
);
5985 f
->fmt
.pix
.height
= rounddown(
5986 clamp_t(u32
, f
->fmt
.pix
.height
- padding_h
,
5987 ATOM_ISP_MIN_HEIGHT
,
5988 ATOM_ISP_MAX_HEIGHT
), ATOM_ISP_STEP_HEIGHT
);
5991 atomisp_get_dis_envelop(asd
, f
->fmt
.pix
.width
, f
->fmt
.pix
.height
,
5992 &dvs_env_w
, &dvs_env_h
);
5994 if (asd
->continuous_mode
->val
) {
5995 struct v4l2_rect
*r
;
5997 r
= atomisp_subdev_get_rect(
5999 V4L2_SUBDEV_FORMAT_ACTIVE
,
6000 ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
,
6001 V4L2_SEL_TGT_COMPOSE
);
6003 * The ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE should get resolutions
6004 * properly set otherwise, it should not be the capture_pad.
6006 if (r
->width
&& r
->height
)
6007 asd
->capture_pad
= ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
;
6009 asd
->capture_pad
= source_pad
;
6011 asd
->capture_pad
= source_pad
;
6014 * set format info to sensor
6015 * In continuous mode, resolution is set only if it is higher than
6016 * existing value. This because preview pipe will be configured after
6017 * capture pipe and usually has lower resolution than capture pipe.
6019 if (!asd
->continuous_mode
->val
||
6020 isp_sink_fmt
.width
< (f
->fmt
.pix
.width
+ padding_w
+ dvs_env_w
) ||
6021 isp_sink_fmt
.height
< (f
->fmt
.pix
.height
+ padding_h
+
6024 * For jpeg or custom raw format the sensor will return constant
6025 * width and height. Because we already had quried try_mbus_fmt,
6026 * f->fmt.pix.width and f->fmt.pix.height has been changed to
6027 * this fixed width and height. So we cannot select the correct
6028 * resolution with that information. So use the original width
6029 * and height while set_mbus_fmt() so actual resolutions are
6030 * being used in while set media bus format.
6033 if (f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_JPEG
||
6034 f
->fmt
.pix
.pixelformat
== V4L2_PIX_FMT_CUSTOM_M10MO_RAW
) {
6035 s_fmt
.fmt
.pix
.width
= backup_fmt
.fmt
.pix
.width
;
6036 s_fmt
.fmt
.pix
.height
= backup_fmt
.fmt
.pix
.height
;
6038 ret
= atomisp_set_fmt_to_snr(vdev
, &s_fmt
,
6039 f
->fmt
.pix
.pixelformat
, padding_w
,
6040 padding_h
, dvs_env_w
, dvs_env_h
);
6044 atomisp_csi_lane_config(isp
);
6045 crop_needs_override
= true;
6048 atomisp_check_copy_mode(asd
, source_pad
, &backup_fmt
);
6049 asd
->yuvpp_mode
= false; /* Reset variable */
6051 isp_sink_crop
= *atomisp_subdev_get_rect(&asd
->subdev
, NULL
,
6052 V4L2_SUBDEV_FORMAT_ACTIVE
,
6053 ATOMISP_SUBDEV_PAD_SINK
,
6056 /* Try to enable YUV downscaling if ISP input is 10 % (either
6057 * width or height) bigger than the desired result. */
6058 if (isp_sink_crop
.width
* 9 / 10 < f
->fmt
.pix
.width
||
6059 isp_sink_crop
.height
* 9 / 10 < f
->fmt
.pix
.height
||
6060 (atomisp_subdev_format_conversion(asd
, source_pad
) &&
6061 ((asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
6062 !asd
->continuous_mode
->val
) ||
6063 asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
))) {
6064 /* for continuous mode, preview size might be smaller than
6065 * still capture size. if preview size still needs crop,
6066 * pick the larger one between crop size of preview and
6069 if (asd
->continuous_mode
->val
6070 && source_pad
== ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
6071 && !crop_needs_override
) {
6072 isp_sink_crop
.width
=
6073 max_t(unsigned int, f
->fmt
.pix
.width
,
6074 isp_sink_crop
.width
);
6075 isp_sink_crop
.height
=
6076 max_t(unsigned int, f
->fmt
.pix
.height
,
6077 isp_sink_crop
.height
);
6079 isp_sink_crop
.width
= f
->fmt
.pix
.width
;
6080 isp_sink_crop
.height
= f
->fmt
.pix
.height
;
6083 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6084 V4L2_SUBDEV_FORMAT_ACTIVE
,
6085 ATOMISP_SUBDEV_PAD_SINK
,
6087 V4L2_SEL_FLAG_KEEP_CONFIG
,
6089 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6090 V4L2_SUBDEV_FORMAT_ACTIVE
,
6091 source_pad
, V4L2_SEL_TGT_COMPOSE
,
6093 } else if (IS_MOFD
) {
6094 struct v4l2_rect main_compose
= {0};
6096 main_compose
.width
= isp_sink_crop
.width
;
6097 main_compose
.height
=
6098 DIV_ROUND_UP(main_compose
.width
* f
->fmt
.pix
.height
,
6100 if (main_compose
.height
> isp_sink_crop
.height
) {
6101 main_compose
.height
= isp_sink_crop
.height
;
6102 main_compose
.width
=
6103 DIV_ROUND_UP(main_compose
.height
*
6108 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6109 V4L2_SUBDEV_FORMAT_ACTIVE
,
6111 V4L2_SEL_TGT_COMPOSE
, 0,
6114 struct v4l2_rect sink_crop
= {0};
6115 struct v4l2_rect main_compose
= {0};
6117 main_compose
.width
= f
->fmt
.pix
.width
;
6118 main_compose
.height
= f
->fmt
.pix
.height
;
6121 /* WORKAROUND: this override is universally enabled in
6122 * GMIN to work around a CTS failures (GMINL-539)
6123 * which appears to be related by a hardware
6124 * performance limitation. It's unclear why this
6125 * particular code triggers the issue. */
6127 crop_needs_override
) {
6129 if (crop_needs_override
) {
6131 if (isp_sink_crop
.width
* main_compose
.height
>
6132 isp_sink_crop
.height
* main_compose
.width
) {
6133 sink_crop
.height
= isp_sink_crop
.height
;
6134 sink_crop
.width
= DIV_NEAREST_STEP(
6138 ATOM_ISP_STEP_WIDTH
);
6140 sink_crop
.width
= isp_sink_crop
.width
;
6141 sink_crop
.height
= DIV_NEAREST_STEP(
6145 ATOM_ISP_STEP_HEIGHT
);
6147 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6148 V4L2_SUBDEV_FORMAT_ACTIVE
,
6149 ATOMISP_SUBDEV_PAD_SINK
,
6151 V4L2_SEL_FLAG_KEEP_CONFIG
,
6154 atomisp_subdev_set_selection(&asd
->subdev
, fh
.pad
,
6155 V4L2_SUBDEV_FORMAT_ACTIVE
,
6157 V4L2_SEL_TGT_COMPOSE
, 0,
6162 ret
= atomisp_set_fmt_to_isp(vdev
, &output_info
, &raw_output_info
,
6163 &f
->fmt
.pix
, source_pad
);
6167 pipe
->pix
.width
= f
->fmt
.pix
.width
;
6168 pipe
->pix
.height
= f
->fmt
.pix
.height
;
6169 pipe
->pix
.pixelformat
= f
->fmt
.pix
.pixelformat
;
6170 if (format_bridge
->planar
) {
6171 pipe
->pix
.bytesperline
= output_info
.padded_width
;
6172 pipe
->pix
.sizeimage
= PAGE_ALIGN(f
->fmt
.pix
.height
*
6173 DIV_ROUND_UP(format_bridge
->depth
*
6174 output_info
.padded_width
, 8));
6176 pipe
->pix
.bytesperline
=
6177 DIV_ROUND_UP(format_bridge
->depth
*
6178 output_info
.padded_width
, 8);
6179 pipe
->pix
.sizeimage
=
6180 PAGE_ALIGN(f
->fmt
.pix
.height
* pipe
->pix
.bytesperline
);
6183 if (f
->fmt
.pix
.field
== V4L2_FIELD_ANY
)
6184 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
6185 pipe
->pix
.field
= f
->fmt
.pix
.field
;
6187 f
->fmt
.pix
= pipe
->pix
;
6188 f
->fmt
.pix
.priv
= PAGE_ALIGN(pipe
->pix
.width
*
6189 pipe
->pix
.height
* 2);
6191 pipe
->capq
.field
= f
->fmt
.pix
.field
;
6194 * If in video 480P case, no GFX throttle
6196 if (asd
->run_mode
->val
== ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
&&
6197 f
->fmt
.pix
.width
== 720 && f
->fmt
.pix
.height
== 480)
6198 isp
->need_gfx_throttle
= false;
6200 isp
->need_gfx_throttle
= true;
6205 int atomisp_set_fmt_file(struct video_device
*vdev
, struct v4l2_format
*f
)
6207 struct atomisp_device
*isp
= video_get_drvdata(vdev
);
6208 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
6209 struct atomisp_sub_device
*asd
= pipe
->asd
;
6210 struct v4l2_mbus_framefmt ffmt
= {0};
6211 const struct atomisp_format_bridge
*format_bridge
;
6212 struct v4l2_subdev_fh fh
;
6215 v4l2_fh_init(&fh
.vfh
, vdev
);
6217 dev_dbg(isp
->dev
, "setting fmt %ux%u 0x%x for file inject\n",
6218 f
->fmt
.pix
.width
, f
->fmt
.pix
.height
, f
->fmt
.pix
.pixelformat
);
6219 ret
= atomisp_try_fmt_file(isp
, f
);
6221 dev_err(isp
->dev
, "atomisp_try_fmt_file err: %d\n", ret
);
6225 format_bridge
= atomisp_get_format_bridge(f
->fmt
.pix
.pixelformat
);
6226 if (format_bridge
== NULL
) {
6227 dev_dbg(isp
->dev
, "atomisp_get_format_bridge err! fmt:0x%x\n",
6228 f
->fmt
.pix
.pixelformat
);
6232 pipe
->pix
= f
->fmt
.pix
;
6233 atomisp_css_input_set_mode(asd
, CSS_INPUT_MODE_FIFO
);
6234 atomisp_css_input_configure_port(asd
,
6235 __get_mipi_port(isp
, ATOMISP_CAMERA_PORT_PRIMARY
), 2, 0xffff4,
6237 ffmt
.width
= f
->fmt
.pix
.width
;
6238 ffmt
.height
= f
->fmt
.pix
.height
;
6239 ffmt
.code
= format_bridge
->mbus_code
;
6241 atomisp_subdev_set_ffmt(&asd
->subdev
, fh
.pad
, V4L2_SUBDEV_FORMAT_ACTIVE
,
6242 ATOMISP_SUBDEV_PAD_SINK
, &ffmt
);
6247 int atomisp_set_shading_table(struct atomisp_sub_device
*asd
,
6248 struct atomisp_shading_table
*user_shading_table
)
6250 struct atomisp_css_shading_table
*shading_table
;
6251 struct atomisp_css_shading_table
*free_table
;
6252 unsigned int len_table
;
6256 if (!user_shading_table
)
6259 if (!user_shading_table
->enable
) {
6260 atomisp_css_set_shading_table(asd
, NULL
);
6261 asd
->params
.sc_en
= 0;
6265 /* If enabling, all tables must be set */
6266 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
6267 if (!user_shading_table
->data
[i
])
6271 /* Shading table size per color */
6272 if (user_shading_table
->width
> SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR
||
6273 user_shading_table
->height
> SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR
)
6276 shading_table
= atomisp_css_shading_table_alloc(
6277 user_shading_table
->width
, user_shading_table
->height
);
6281 len_table
= user_shading_table
->width
* user_shading_table
->height
*
6282 ATOMISP_SC_TYPE_SIZE
;
6283 for (i
= 0; i
< ATOMISP_NUM_SC_COLORS
; i
++) {
6284 ret
= copy_from_user(shading_table
->data
[i
],
6285 user_shading_table
->data
[i
], len_table
);
6287 free_table
= shading_table
;
6292 shading_table
->sensor_width
= user_shading_table
->sensor_width
;
6293 shading_table
->sensor_height
= user_shading_table
->sensor_height
;
6294 shading_table
->fraction_bits
= user_shading_table
->fraction_bits
;
6296 free_table
= asd
->params
.css_param
.shading_table
;
6297 asd
->params
.css_param
.shading_table
= shading_table
;
6298 atomisp_css_set_shading_table(asd
, shading_table
);
6299 asd
->params
.sc_en
= 1;
6302 if (free_table
!= NULL
)
6303 atomisp_css_shading_table_free(free_table
);
6308 /*Turn off ISP dphy */
6309 int atomisp_ospm_dphy_down(struct atomisp_device
*isp
)
6311 unsigned long flags
;
6314 dev_dbg(isp
->dev
, "%s\n", __func__
);
6316 /* if ISP timeout, we can force powerdown */
6317 if (isp
->isp_timeout
)
6320 if (!atomisp_dev_users(isp
))
6323 spin_lock_irqsave(&isp
->lock
, flags
);
6324 isp
->sw_contex
.power_state
= ATOM_ISP_POWER_DOWN
;
6325 spin_unlock_irqrestore(&isp
->lock
, flags
);
6328 * MRFLD IUNIT DPHY is located in an always-power-on island
6329 * MRFLD HW design need all CSI ports are disabled before
6330 * powering down the IUNIT.
6332 pci_read_config_dword(isp
->pdev
, MRFLD_PCI_CSI_CONTROL
, ®
);
6333 reg
|= MRFLD_ALL_CSI_PORTS_OFF_MASK
;
6334 pci_write_config_dword(isp
->pdev
, MRFLD_PCI_CSI_CONTROL
, reg
);
6338 /*Turn on ISP dphy */
6339 int atomisp_ospm_dphy_up(struct atomisp_device
*isp
)
6341 unsigned long flags
;
6342 dev_dbg(isp
->dev
, "%s\n", __func__
);
6344 spin_lock_irqsave(&isp
->lock
, flags
);
6345 isp
->sw_contex
.power_state
= ATOM_ISP_POWER_UP
;
6346 spin_unlock_irqrestore(&isp
->lock
, flags
);
6352 int atomisp_exif_makernote(struct atomisp_sub_device
*asd
,
6353 struct atomisp_makernote_info
*config
)
6355 struct v4l2_control ctrl
;
6356 struct atomisp_device
*isp
= asd
->isp
;
6358 ctrl
.id
= V4L2_CID_FOCAL_ABSOLUTE
;
6360 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6361 dev_warn(isp
->dev
, "failed to g_ctrl for focal length\n");
6364 config
->focal_length
= ctrl
.value
;
6367 ctrl
.id
= V4L2_CID_FNUMBER_ABSOLUTE
;
6369 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6370 dev_warn(isp
->dev
, "failed to g_ctrl for f-number\n");
6373 config
->f_number_curr
= ctrl
.value
;
6376 ctrl
.id
= V4L2_CID_FNUMBER_RANGE
;
6378 (isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
, &ctrl
)) {
6379 dev_warn(isp
->dev
, "failed to g_ctrl for f number range\n");
6382 config
->f_number_range
= ctrl
.value
;
6388 int atomisp_offline_capture_configure(struct atomisp_sub_device
*asd
,
6389 struct atomisp_cont_capture_conf
*cvf_config
)
6391 struct v4l2_ctrl
*c
;
6394 * In case of M10MO ZSL capture case, we need to issue a separate
6395 * capture request to M10MO which will output captured jpeg image
6398 asd
->isp
->inputs
[asd
->input_curr
].camera
->ctrl_handler
,
6399 V4L2_CID_START_ZSL_CAPTURE
);
6402 dev_dbg(asd
->isp
->dev
, "%s trigger ZSL capture request\n",
6404 /* TODO: use the cvf_config */
6405 ret
= v4l2_ctrl_s_ctrl(c
, 1);
6409 return v4l2_ctrl_s_ctrl(c
, 0);
6412 asd
->params
.offline_parm
= *cvf_config
;
6414 if (asd
->params
.offline_parm
.num_captures
) {
6415 if (asd
->streaming
== ATOMISP_DEVICE_STREAMING_DISABLED
) {
6416 unsigned int init_raw_num
;
6418 if (asd
->enable_raw_buffer_lock
->val
) {
6420 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN
;
6421 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
6422 asd
->params
.video_dis_en
)
6424 ATOMISP_CSS2_NUM_DVS_FRAME_DELAY
;
6427 ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES
;
6430 /* TODO: this can be removed once user-space
6431 * has been updated to use control API */
6432 asd
->continuous_raw_buffer_size
->val
=
6434 asd
->continuous_raw_buffer_size
->val
,
6435 asd
->params
.offline_parm
.
6436 num_captures
+ init_raw_num
);
6437 asd
->continuous_raw_buffer_size
->val
=
6438 min_t(int, ATOMISP_CONT_RAW_FRAMES
,
6439 asd
->continuous_raw_buffer_size
->val
);
6441 asd
->continuous_mode
->val
= true;
6443 asd
->continuous_mode
->val
= false;
6444 __enable_continuous_mode(asd
, false);
6451 * set auto exposure metering window to camera sensor
6453 int atomisp_s_ae_window(struct atomisp_sub_device
*asd
,
6454 struct atomisp_ae_window
*arg
)
6456 struct atomisp_device
*isp
= asd
->isp
;
6458 /* Coverity CID 298071 - initialzize struct */
6460 struct v4l2_subdev_selection sel
= { 0 };
6462 sel
.r
.left
= arg
->x_left
;
6463 sel
.r
.top
= arg
->y_top
;
6464 sel
.r
.width
= arg
->x_right
- arg
->x_left
+ 1;
6465 sel
.r
.height
= arg
->y_bottom
- arg
->y_top
+ 1;
6467 if (v4l2_subdev_call(isp
->inputs
[asd
->input_curr
].camera
,
6468 pad
, set_selection
, NULL
, &sel
)) {
6469 dev_err(isp
->dev
, "failed to call sensor set_selection.\n");
6476 int atomisp_flash_enable(struct atomisp_sub_device
*asd
, int num_frames
)
6478 struct atomisp_device
*isp
= asd
->isp
;
6480 if (num_frames
< 0) {
6481 dev_dbg(isp
->dev
, "%s ERROR: num_frames: %d\n", __func__
,
6485 /* a requested flash is still in progress. */
6486 if (num_frames
&& asd
->params
.flash_state
!= ATOMISP_FLASH_IDLE
) {
6487 dev_dbg(isp
->dev
, "%s flash busy: %d frames left: %d\n",
6488 __func__
, asd
->params
.flash_state
,
6489 asd
->params
.num_flash_frames
);
6493 asd
->params
.num_flash_frames
= num_frames
;
6494 asd
->params
.flash_state
= ATOMISP_FLASH_REQUESTED
;
6498 int atomisp_source_pad_to_stream_id(struct atomisp_sub_device
*asd
,
6499 uint16_t source_pad
)
6502 struct atomisp_device
*isp
= asd
->isp
;
6504 if (isp
->inputs
[asd
->input_curr
].camera_caps
->
6505 sensor
[asd
->sensor_curr
].stream_num
== 1)
6506 return ATOMISP_INPUT_STREAM_GENERAL
;
6508 switch (source_pad
) {
6509 case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE
:
6510 stream_id
= ATOMISP_INPUT_STREAM_CAPTURE
;
6512 case ATOMISP_SUBDEV_PAD_SOURCE_VF
:
6513 stream_id
= ATOMISP_INPUT_STREAM_POSTVIEW
;
6515 case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
:
6516 stream_id
= ATOMISP_INPUT_STREAM_PREVIEW
;
6518 case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO
:
6519 stream_id
= ATOMISP_INPUT_STREAM_VIDEO
;
6522 stream_id
= ATOMISP_INPUT_STREAM_GENERAL
;
6528 bool atomisp_is_vf_pipe(struct atomisp_video_pipe
*pipe
)
6530 struct atomisp_sub_device
*asd
= pipe
->asd
;
6532 if (pipe
== &asd
->video_out_vf
)
6535 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
&&
6536 pipe
== &asd
->video_out_preview
)
6542 static int __checking_exp_id(struct atomisp_sub_device
*asd
, int exp_id
)
6544 struct atomisp_device
*isp
= asd
->isp
;
6546 if (!asd
->enable_raw_buffer_lock
->val
) {
6547 dev_warn(isp
->dev
, "%s Raw Buffer Lock is disable.\n", __func__
);
6550 if (asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
) {
6551 dev_err(isp
->dev
, "%s streaming %d invalid exp_id %d.\n",
6552 __func__
, exp_id
, asd
->streaming
);
6555 if ((exp_id
> ATOMISP_MAX_EXP_ID
) || (exp_id
<= 0)) {
6556 dev_err(isp
->dev
, "%s exp_id %d invalid.\n", __func__
, exp_id
);
6562 void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device
*asd
)
6564 unsigned long flags
;
6565 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6566 memset(asd
->raw_buffer_bitmap
, 0, sizeof(asd
->raw_buffer_bitmap
));
6567 asd
->raw_buffer_locked_count
= 0;
6568 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6571 int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device
*asd
, int exp_id
)
6574 unsigned long flags
;
6576 if (__checking_exp_id(asd
, exp_id
))
6579 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6581 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6582 (*bitmap
) |= (1 << bit
);
6583 asd
->raw_buffer_locked_count
++;
6584 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6586 dev_dbg(asd
->isp
->dev
, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6587 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6589 /* Check if the raw buffer after next is still locked!!! */
6591 if (exp_id
> ATOMISP_MAX_EXP_ID
)
6592 exp_id
-= ATOMISP_MAX_EXP_ID
;
6593 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6595 if ((*bitmap
) & (1 << bit
)) {
6598 /* WORKAROUND unlock the raw buffer compulsively */
6599 ret
= atomisp_css_exp_id_unlock(asd
, exp_id
);
6601 dev_err(asd
->isp
->dev
, "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n",
6602 __func__
, exp_id
, ret
);
6606 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6607 (*bitmap
) &= ~(1 << bit
);
6608 asd
->raw_buffer_locked_count
--;
6609 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6610 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",
6611 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6616 static int __is_raw_buffer_locked(struct atomisp_sub_device
*asd
, int exp_id
)
6619 unsigned long flags
;
6622 if (__checking_exp_id(asd
, exp_id
))
6625 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6627 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6628 ret
= ((*bitmap
) & (1 << bit
));
6629 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6633 static int __clear_raw_buffer_bitmap(struct atomisp_sub_device
*asd
, int exp_id
)
6636 unsigned long flags
;
6638 if (__is_raw_buffer_locked(asd
, exp_id
))
6641 bitmap
= asd
->raw_buffer_bitmap
+ exp_id
/ 32;
6643 spin_lock_irqsave(&asd
->raw_buffer_bitmap_lock
, flags
);
6644 (*bitmap
) &= ~(1 << bit
);
6645 asd
->raw_buffer_locked_count
--;
6646 spin_unlock_irqrestore(&asd
->raw_buffer_bitmap_lock
, flags
);
6648 dev_dbg(asd
->isp
->dev
, "%s: exp_id %d, raw_buffer_locked_count %d\n",
6649 __func__
, exp_id
, asd
->raw_buffer_locked_count
);
6653 int atomisp_exp_id_capture(struct atomisp_sub_device
*asd
, int *exp_id
)
6655 struct atomisp_device
*isp
= asd
->isp
;
6656 int value
= *exp_id
;
6659 ret
= __is_raw_buffer_locked(asd
, value
);
6661 dev_err(isp
->dev
, "%s exp_id %d invalid %d.\n", __func__
, value
, ret
);
6665 dev_dbg(isp
->dev
, "%s exp_id %d\n", __func__
, value
);
6666 ret
= atomisp_css_exp_id_capture(asd
, value
);
6668 dev_err(isp
->dev
, "%s exp_id %d failed.\n", __func__
, value
);
6674 int atomisp_exp_id_unlock(struct atomisp_sub_device
*asd
, int *exp_id
)
6676 struct atomisp_device
*isp
= asd
->isp
;
6677 int value
= *exp_id
;
6680 ret
= __clear_raw_buffer_bitmap(asd
, value
);
6682 dev_err(isp
->dev
, "%s exp_id %d invalid %d.\n", __func__
, value
, ret
);
6686 dev_dbg(isp
->dev
, "%s exp_id %d\n", __func__
, value
);
6687 ret
= atomisp_css_exp_id_unlock(asd
, value
);
6689 dev_err(isp
->dev
, "%s exp_id %d failed, err %d.\n",
6690 __func__
, value
, ret
);
6695 int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device
*asd
,
6696 unsigned int *enable
)
6703 value
= *enable
> 0 ? true : false;
6705 atomisp_en_dz_capt_pipe(asd
, value
);
6710 int atomisp_inject_a_fake_event(struct atomisp_sub_device
*asd
, int *event
)
6712 if (!event
|| asd
->streaming
!= ATOMISP_DEVICE_STREAMING_ENABLED
)
6715 dev_dbg(asd
->isp
->dev
, "%s: trying to inject a fake event 0x%x\n",
6719 case V4L2_EVENT_FRAME_SYNC
:
6720 atomisp_sof_event(asd
);
6722 case V4L2_EVENT_FRAME_END
:
6723 atomisp_eof_event(asd
, 0);
6725 case V4L2_EVENT_ATOMISP_3A_STATS_READY
:
6726 atomisp_3a_stats_ready_event(asd
, 0);
6728 case V4L2_EVENT_ATOMISP_METADATA_READY
:
6729 atomisp_metadata_ready_event(asd
, 0);
6738 int atomisp_get_pipe_id(struct atomisp_video_pipe
*pipe
)
6740 struct atomisp_sub_device
*asd
= pipe
->asd
;
6742 if (ATOMISP_USE_YUVPP(asd
))
6743 return CSS_PIPE_ID_YUVPP
;
6744 else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_SCALER
)
6745 return CSS_PIPE_ID_VIDEO
;
6746 else if (asd
->vfpp
->val
== ATOMISP_VFPP_DISABLE_LOWLAT
)
6747 return CSS_PIPE_ID_CAPTURE
;
6748 else if (pipe
== &asd
->video_out_video_capture
)
6749 return CSS_PIPE_ID_VIDEO
;
6750 else if (pipe
== &asd
->video_out_vf
)
6751 return CSS_PIPE_ID_CAPTURE
;
6752 else if (pipe
== &asd
->video_out_preview
) {
6753 if (asd
->run_mode
->val
== ATOMISP_RUN_MODE_VIDEO
)
6754 return CSS_PIPE_ID_VIDEO
;
6756 return CSS_PIPE_ID_PREVIEW
;
6757 } else if (pipe
== &asd
->video_out_capture
) {
6759 return IA_CSS_PIPE_ID_COPY
;
6761 return CSS_PIPE_ID_CAPTURE
;
6765 dev_warn(asd
->isp
->dev
, "%s failed to find proper pipe\n",
6767 return CSS_PIPE_ID_CAPTURE
;
6770 int atomisp_get_invalid_frame_num(struct video_device
*vdev
,
6771 int *invalid_frame_num
)
6773 struct atomisp_video_pipe
*pipe
= atomisp_to_video_pipe(vdev
);
6774 struct atomisp_sub_device
*asd
= pipe
->asd
;
6775 enum atomisp_css_pipe_id pipe_id
;
6776 struct ia_css_pipe_info p_info
;
6779 if (asd
->isp
->inputs
[asd
->input_curr
].camera_caps
->
6780 sensor
[asd
->sensor_curr
].stream_num
> 1) {
6782 *invalid_frame_num
= 0;
6786 pipe_id
= atomisp_get_pipe_id(pipe
);
6787 if (!asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
].pipes
[pipe_id
]) {
6788 dev_warn(asd
->isp
->dev
, "%s pipe %d has not been created yet, do SET_FMT first!\n",
6793 ret
= ia_css_pipe_get_info(
6794 asd
->stream_env
[ATOMISP_INPUT_STREAM_GENERAL
]
6795 .pipes
[pipe_id
], &p_info
);
6796 if (ret
== IA_CSS_SUCCESS
) {
6797 *invalid_frame_num
= p_info
.num_invalid_frames
;
6800 dev_warn(asd
->isp
->dev
, "%s get pipe infor failed %d\n",