This series is the Video Input Interface driver
for Toshiba's ARM SoC, Visconti.
This provides DT binding documentation,
device driver, documentation and MAINTAINER files.
A visconti VIIF driver instance exposes
1 media control device file, 3 video device files for capture
and 2 video device files for controlling image signal processor.
Detailed HW/SW are described in documentation directory.
The VIIF hardware has CSI2 receiver,
image signal processor and DMAC inside.
The subdevice for image signal processor provides
vendor specific V4L2 controls.
The device driver depends on two other drivers under development;
clock framework driver and IOMMU driver.
Corresponding features will be added later.
Best regards,
Yuji
Changelog v2:
- Resend v1 because a patch exceeds size limit.
Changelog v3:
- Add documentation to describe SW and HW
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters
Changelog v4:
- Split patches because a patch exceeds size limit
- fix dt-bindings document
- stop specifying ID numbers for driver instance explicitly at device tree
- use pm_runtime to trigger initialization of HW
along with open/close of device files.
- add a entry for a header file at MAINTAINERS file
Changelog v5:
- Fix coding style problem in viif.c (patch 2/6)
Changelog v6:
- add register definition of BUS-IF and MPU in dt-bindings
- add CSI2RX subdevice (separeted from ISP subdevice)
- change directory layout (moved to media/platform/toshiba/visconti)
- change source file layout (removed hwd_xxxx.c)
- pointer to userland memory is removed from uAPI parameters
- change register access (from struct style to macro style)
- remove unused macros
Changelog v7:
- remove redundant "bindings" from header and description text
- fix multiline text of "description"
- change "compatible" to "visconti5-viif"
- explicitly define allowed properties for port::endpoint
- remove unused variables
- update kerneldoc comments
- update references to headers
Changelog v8:
- rename bindings description file
- remove/simplify items in bindings
- update operations around v4l2_async_notifier
- use v4l2_async_connection instead of v4l2_async_subdev
- use dev_err_probe()
- better error handling at probe
- remove redundant mutex
- add V4L2_CTRL_TYPE_VISCONTI_ISP constant
Changelog v9:
- dictionary ordering of dt-bindings properties
- applied sparce checker
- call div64_u64 for 64bit division
- rebase to media_staging tree
- fix warning for cast between ptr and dma_addr_t
Changelog v10:
- add an independent entry in MAINTAINERS
- add paddings to uAPI structs
- use parameter buffer to control ISP (instead of vendor specific controls)
Yuji Ishikawa (6):
dt-bindings: media: platform: visconti: Add Toshiba Visconti Video
Input Interface
media: videodev2.h: add visconti viif meta buffer format
media: platform: visconti: Add Toshiba Visconti Video Input Interface
driver
media: platform: visconti: add streaming interface for ISP parameters
and status
documentation: media: add documentation for Toshiba Visconti Video
Input Interface driver
MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface
.../admin-guide/media/v4l-drivers.rst | 1 +
.../admin-guide/media/visconti-viif.dot | 18 +
.../admin-guide/media/visconti-viif.rst | 252 ++
.../media/toshiba,visconti5-viif.yaml | 105 +
.../userspace-api/media/v4l/meta-formats.rst | 1 +
.../media/v4l/metafmt-visconti-viif.rst | 48 +
MAINTAINERS | 11 +
drivers/media/platform/Kconfig | 1 +
drivers/media/platform/Makefile | 1 +
drivers/media/platform/toshiba/Kconfig | 6 +
drivers/media/platform/toshiba/Makefile | 2 +
.../media/platform/toshiba/visconti/Kconfig | 19 +
.../media/platform/toshiba/visconti/Makefile | 8 +
.../media/platform/toshiba/visconti/viif.c | 664 ++++++
.../media/platform/toshiba/visconti/viif.h | 398 ++++
.../platform/toshiba/visconti/viif_capture.c | 1472 ++++++++++++
.../platform/toshiba/visconti/viif_capture.h | 22 +
.../platform/toshiba/visconti/viif_common.c | 239 ++
.../platform/toshiba/visconti/viif_common.h | 40 +
.../platform/toshiba/visconti/viif_csi2rx.c | 657 ++++++
.../platform/toshiba/visconti/viif_csi2rx.h | 24 +
.../toshiba/visconti/viif_csi2rx_regs.h | 102 +
.../platform/toshiba/visconti/viif_isp.c | 1191 ++++++++++
.../platform/toshiba/visconti/viif_isp.h | 24 +
.../platform/toshiba/visconti/viif_params.c | 2026 +++++++++++++++++
.../platform/toshiba/visconti/viif_params.h | 19 +
.../platform/toshiba/visconti/viif_regs.h | 721 ++++++
.../platform/toshiba/visconti/viif_stats.c | 334 +++
.../platform/toshiba/visconti/viif_stats.h | 14 +
include/uapi/linux/videodev2.h | 4 +
include/uapi/linux/visconti_viif.h | 1921 ++++++++++++++++
31 files changed, 10345 insertions(+)
create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
create mode 100644 Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
create mode 100644 drivers/media/platform/toshiba/Kconfig
create mode 100644 drivers/media/platform/toshiba/Makefile
create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
create mode 100644 drivers/media/platform/toshiba/visconti/viif.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx_regs.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_regs.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h
create mode 100644 include/uapi/linux/visconti_viif.h
--
2.25.1
Add support to Image Signal Processors of Visconti's Video Input Interface.
This patch adds two streaming interfaces;
one for passing parameters to the signal processor,
the other for receiving status.
Signed-off-by: Yuji Ishikawa <[email protected]>
---
Changelog v2:
- Resend v1 because a patch exceeds size limit.
Changelog v3:
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters
Changelog v4:
- Split patches because the v3 patch exceeds size limit
- Stop using ID number to identify driver instance:
- Use dynamically allocated structure to hold HW specific context,
instead of static one.
- Call HW layer functions with the context structure instead of ID number
Changelog v5:
- no change
Changelog v6:
- remove unused macros
- removed hwd_ and HWD_ prefix
- update source code documentation
- Suggestion from Hans Verkuil
- pointer to userland memory is removed from uAPI arguments
- style of structure is now "nested" instead of "chained by pointer";
- use div64_u64 for 64bit division
- vendor specific controls support TRY_EXT_CTRLS
- add READ_ONLY flag to GET_CALIBRATION_STATUS control and similar ones
- human friendry control names for vendor specific controls
- add initial value to each vendor specific control
- GET_LAST_CAPTURE_STATUS control is updated asyncnously from workqueue
- remove EXECUTE_ON_WRITE flag of vendor specific control
- uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
- applied v4l2-compliance
- Suggestion from Sakari Ailus
- use div64_u64 for 64bit division
- update copyright's year
- remove redandunt cast
- use bool instead of HWD_VIIF_ENABLE/DISABLE
- simplify comparison to 0
- simplify statements with trigram operator
- remove redundant local variables
- use general integer types instead of u32/s32
- Suggestion from Laurent Pinchart
- moved VIIF driver to driver/platform/toshiba/visconti
- change register access: struct-style to macro-style
- remove unused type definitions
- define enums instead of successive macro constants
- remove redundant parenthesis of macro constant
- embed struct hwd_res into struct viif_device
- use xxx_dma instead of xxx_paddr for variable names of IOVA
- literal value: just 0 instead of 0x0
- use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register access
- use true or false instead of HWD_VIIF_ENABLE, DISABLE for function calls
- uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
Changelog v7:
- remove unused variables
- split long statements which have multiple logical-OR and trigram operators
Changelog v8:
- define constant V4L2_CTRL_TYPE_VISCONTI_ISP for datatype
of Visconti specific controls
- Suggestion from Hans Verkuil
- remove pr_info()
- use pm_runtime_get_if_in_use() to get power status
Changelog v9:
- fix warning for cast between ptr and dma_addr_t
Changelog v10:
- use parameter buffer instead of vendor specific compound controls
- add viif_params interface for passing ISP parameters
- add viif_stats interface for passing ISP status
- remove parameter validation routine; moved to userland library
.../media/platform/toshiba/visconti/Makefile | 2 +-
.../media/platform/toshiba/visconti/viif.c | 28 +-
.../platform/toshiba/visconti/viif_isp.c | 7 +
.../platform/toshiba/visconti/viif_params.c | 2026 +++++++++++++++++
.../platform/toshiba/visconti/viif_params.h | 19 +
.../platform/toshiba/visconti/viif_stats.c | 334 +++
.../platform/toshiba/visconti/viif_stats.h | 14 +
7 files changed, 2427 insertions(+), 3 deletions(-)
create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h
diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
index 5f2f9199c7..8afe8a3fdd 100644
--- a/drivers/media/platform/toshiba/visconti/Makefile
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -3,6 +3,6 @@
# Makefile for the Visconti video input device driver
#
-visconti-viif-objs = viif.o viif_capture.o viif_isp.o viif_csi2rx.o viif_common.o
+visconti-viif-objs = viif.o viif_capture.o viif_isp.o viif_csi2rx.o viif_common.o viif_params.o viif_stats.o
obj-$(CONFIG_VIDEO_VISCONTI_VIIF) += visconti-viif.o
diff --git a/drivers/media/platform/toshiba/visconti/viif.c b/drivers/media/platform/toshiba/visconti/viif.c
index 10a67730aa..a7e818c929 100644
--- a/drivers/media/platform/toshiba/visconti/viif.c
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -19,6 +19,8 @@
#include "viif.h"
#include "viif_capture.h"
#include "viif_csi2rx.h"
+#include "viif_params.h"
+#include "viif_stats.h"
#include "viif_common.h"
#include "viif_isp.h"
#include "viif_regs.h"
@@ -177,6 +179,8 @@ static void viif_vsync_irq_handler_w_isp(struct viif_device *viif_dev)
/* Delayed Vsync of MAIN unit */
if (event_main & MASK_INT_M_SYNC_LINES_DELAY_INT2) {
+ unsigned int seq0 = viif_dev->cap_dev0.sequence;
+
/* unmask timeout error of gamma table */
viif_main_status_err_set_irq_mask(viif_dev, MASK_INT_M_DELAY_INT_ERROR);
viif_dev->masked_gamma_path = 0;
@@ -195,6 +199,8 @@ static void viif_vsync_irq_handler_w_isp(struct viif_device *viif_dev)
l2_transfer_status, ts);
visconti_viif_capture_switch_buffer(&viif_dev->cap_dev1, status_err,
l2_transfer_status, ts);
+ visconti_viif_stats_isr(viif_dev, seq0, ts);
+ visconti_viif_params_isr(viif_dev);
}
/* Delayed Vsync of SUB unit */
@@ -539,16 +545,32 @@ static int visconti_viif_probe(struct platform_device *pdev)
goto error_isp_unregister;
}
+ ret = visconti_viif_params_register(viif_dev);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register parameter node\n");
+ goto error_capture_unregister;
+ }
+
+ ret = visconti_viif_stats_register(viif_dev);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register stat node\n");
+ goto error_params_unregister;
+ }
+
ret = visconti_viif_create_links(viif_dev);
if (ret)
- goto error_capture_unregister;
+ goto error_stats_unregister;
visconti_viif_subdev_notifier_register(viif_dev);
if (ret)
- goto error_capture_unregister;
+ goto error_stats_unregister;
return 0;
+error_stats_unregister:
+ visconti_viif_stats_unregister(viif_dev);
+error_params_unregister:
+ visconti_viif_params_unregister(viif_dev);
error_capture_unregister:
visconti_viif_capture_unregister(viif_dev);
error_isp_unregister:
@@ -573,6 +595,8 @@ static int visconti_viif_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&viif_dev->notifier);
v4l2_async_nf_cleanup(&viif_dev->notifier);
visconti_viif_capture_unregister(viif_dev);
+ visconti_viif_params_unregister(viif_dev);
+ visconti_viif_stats_unregister(viif_dev);
visconti_viif_isp_unregister(viif_dev);
visconti_viif_csi2rx_unregister(viif_dev);
media_device_unregister(&viif_dev->media_dev);
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
index bc0169af70..e1c54a2e27 100644
--- a/drivers/media/platform/toshiba/visconti/viif_isp.c
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -13,6 +13,7 @@
#include "viif.h"
#include "viif_common.h"
#include "viif_isp.h"
+#include "viif_params.h"
#include "viif_regs.h"
/* disable CSI2 capture at viif_mux_start() */
@@ -744,6 +745,10 @@ int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev)
/* Enable regbuf */
hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);
+ /* L2 UNDIST Enable through mode as default */
+ ret = visconti_viif_l2_undist_through(viif_dev);
+ if (ret)
+ dev_err(viif_dev->dev, "l2_set_undist error. %d\n", ret);
return ret;
}
@@ -797,6 +802,8 @@ static int visconti_viif_isp_s_stream(struct v4l2_subdev *sd, int enable)
}
/* enabling: start ISP, MUX -> start CSI2RX, sensor */
+ // prepare ISP parameters
+ visconti_viif_params_eval_queue(viif_dev);
// start ISP
viif_dev->masked_gamma_path = 0;
viif_mux_start(viif_dev, 0, 0);
diff --git a/drivers/media/platform/toshiba/visconti/viif_params.c b/drivers/media/platform/toshiba/visconti/viif_params.c
new file mode 100644
index 0000000000..5170d371c2
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.c
@@ -0,0 +1,2026 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "viif.h"
+#include "viif_csi2rx.h"
+#include "viif_isp.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+#include "viif_params.h"
+
+/* ISP_L1_SET_HDRC */
+#define VIIF_L1_HDRC_RATIO_OFFSET 10U
+#define VIIF_REGBUF_ACCESS_TIME 15360UL
+#define VIIF_L1_DELAY_W_HDRC 31U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST */
+#define VIIF_L2_UNDIST_POLY_NUM 11U
+
+/*=======================================================================*/
+/* ISP parameter configuration */
+/*=======================================================================*/
+static void viif_l1_set_input_mode(struct viif_device *viif_dev,
+ const struct viif_l1_input_mode_config *arg)
+{
+ unsigned long irqflags;
+
+ /* values are already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_INPUT_MODE, (u32)arg->mode);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_rgb_to_y_coef(struct viif_device *viif_dev,
+ const struct viif_l1_rgb_to_y_coef_config *arg)
+{
+ unsigned long irqflags;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_R, (u32)arg->coef_r);
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_G, (u32)arg->coef_g);
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_B, (u32)arg->coef_b);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_ag_mode(struct viif_device *viif_dev,
+ const struct viif_l1_ag_mode_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* SYSM_AG_PARAM */
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_A,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[0], arg->sysm_ag_ofst[0]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_B,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[1], arg->sysm_ag_ofst[1]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_C,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[2], arg->sysm_ag_ofst[2]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_D,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[3], arg->sysm_ag_ofst[3]));
+
+ /* SYSM_AG_SEL */
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_HOBC,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_hobc_high,
+ arg->sysm_ag_psel_hobc_middle_led,
+ arg->sysm_ag_psel_hobc_low));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_ABPC,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_abpc_high,
+ arg->sysm_ag_psel_abpc_middle_led,
+ arg->sysm_ag_psel_abpc_low));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_RCNR,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_rcnr_high,
+ arg->sysm_ag_psel_rcnr_middle_led,
+ arg->sysm_ag_psel_rcnr_low));
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_LSSC,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_lssc, arg->sysm_ag_psel_lssc));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_MPRO,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_mpro, arg->sysm_ag_psel_mpro));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_VPRO,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_vpro, arg->sysm_ag_psel_vpro));
+
+ /* SYSM_AG_CONT */
+ val = arg->sysm_ag_cont_hobc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_hobc_test_middle_led);
+ val |= arg->sysm_ag_cont_hobc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_hobc_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC01_EN, val);
+
+ val = arg->sysm_ag_cont_hobc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_hobc_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC2_EN, val);
+
+ val = arg->sysm_ag_cont_abpc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_abpc_test_middle_led);
+ val |= arg->sysm_ag_cont_abpc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_abpc_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC01_EN, val);
+
+ val = arg->sysm_ag_cont_abpc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_abpc_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC2_EN, val);
+
+ val = arg->sysm_ag_cont_rcnr_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_rcnr_test_middle_led);
+ val |= arg->sysm_ag_cont_rcnr_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_rcnr_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR01_EN, val);
+
+ val = arg->sysm_ag_cont_rcnr_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_rcnr_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR2_EN, val);
+
+ val = arg->sysm_ag_cont_lssc_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_lssc_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_LSSC_EN, val);
+
+ val = arg->sysm_ag_cont_mpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_mpro_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_MPRO_EN, val);
+
+ val = arg->sysm_ag_cont_vpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_vpro_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_VPRO_EN, val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_ag(struct viif_device *viif_dev, const struct viif_l1_ag_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_H, (u32)arg->gain_h);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_M, (u32)arg->gain_m);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_L, (u32)arg->gain_l);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_hdre(struct viif_device *viif_dev, const struct viif_l1_hdre_config *arg)
+{
+ unsigned long irqflags;
+ int i;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ for (i = 0; i < LEN_L1_HDRE_SRCPOINT; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCPOINT(i), arg->hdre_src_point[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(0), 0);
+ for (i = 1; i < LEN_L1_HDRE_SRCBASE; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(i), arg->hdre_src_point[i - 1]);
+
+ for (i = 0; i < LEN_L1_HDRE_DSTBASE; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_DSTBASE(i), arg->hdre_dst_base[i]);
+
+ for (i = 0; i < LEN_L1_HDRE_RATIO; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_RATIO(i), arg->hdre_ratio[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRE_DSTMAXVAL, arg->hdre_dst_max_val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_img_extraction(struct viif_device *viif_dev,
+ const struct viif_l1_img_extraction_config *arg)
+{
+ unsigned long irqflags;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GR, arg->input_black_gr);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_R, arg->input_black_r);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_B, arg->input_black_b);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GB, arg->input_black_gb);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_config_vdm_tgroup(struct viif_device *viif_dev, int idx)
+{
+ const struct {
+ u32 cfg;
+ u32 sram_base;
+ u32 sram_size;
+ } conf[] = {
+ /* T01: L1_SET_DPC, L1_SET_LSC */
+ { VAL_TGROUP_CFG_64BIT_RD, 0x600, 0x20 },
+ /* T02: L2_UNDIST grid table */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x620, 0x20 },
+ /* T02: L2_GAMMA (path0) */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x640, 0x20 },
+ /* T03: L2 GAMMA (path1) */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x660, 0x20 },
+ };
+
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_CFG(idx), conf[idx].cfg);
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_BASE(idx), conf[idx].sram_base);
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_SIZE(idx), conf[idx].sram_size);
+}
+
+static void dpc_table_transmission(struct viif_device *viif_dev, uintptr_t table_h,
+ uintptr_t table_m, uintptr_t table_l)
+{
+ u32 val = 0x0U;
+
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+ if (table_h) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_H),
+ (u32)table_h);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_H),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_H;
+ }
+
+ if (table_m) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_M),
+ (u32)table_m);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_M),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_M;
+ }
+
+ if (table_l) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_L),
+ (u32)table_l);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_L),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_L;
+ }
+
+ val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_DPC);
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static void viif_l1_set_dpc(struct viif_device *viif_dev, const struct viif_l1_dpc_config *arg)
+{
+ const struct viif_l1_dpc *param_h, *param_m, *param_l;
+ dma_addr_t table_h = 0;
+ dma_addr_t table_m = 0;
+ dma_addr_t table_l = 0;
+ unsigned long irqflags;
+ u32 val;
+
+ if (arg->param_h.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_h, arg->table_h, VIIF_DPC_TABLE_BYTES);
+ table_h = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->dpc_table_h;
+ }
+ if (arg->param_m.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_m, arg->table_m, VIIF_DPC_TABLE_BYTES);
+ table_m = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->dpc_table_m;
+ }
+ if (arg->param_l.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_l, arg->table_l, VIIF_DPC_TABLE_BYTES);
+ table_l = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->dpc_table_l;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ dpc_table_transmission(viif_dev, table_h, table_m, table_l);
+
+ param_h = &arg->param_h;
+ param_m = &arg->param_m;
+ param_l = &arg->param_l;
+
+ val = (param_h->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_H : 0;
+ val |= (param_m->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_M : 0;
+ val |= (param_l->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_L : 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_STA_EN, val);
+
+ val = (param_h->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_H : 0;
+ val |= (param_m->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_M : 0;
+ val |= (param_l->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_L : 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_EN, val);
+
+ val = (param_h->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_H : 0;
+ val |= (param_m->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_M : 0;
+ val |= (param_l->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_L : 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_MODE, val);
+
+ /* setup param_h */
+ viif_capture_write(viif_dev, REG_L1_ABPC0_RATIO_LIMIT, param_h->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_DARK_LIMIT, param_h->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MIN, param_h->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MID, param_h->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MAX, param_h->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MIN, param_h->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MID, param_h->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MAX, param_h->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MIN, param_h->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MAX, param_h->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MIN, param_h->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MAX, param_h->abpc_sn_coef_b_th_max);
+
+ /* setup param_m */
+ viif_capture_write(viif_dev, REG_L1_ABPC1_RATIO_LIMIT, param_m->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_DARK_LIMIT, param_m->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MIN, param_m->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MID, param_m->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MAX, param_m->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MIN, param_m->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MID, param_m->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MAX, param_m->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MIN, param_m->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MAX, param_m->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MIN, param_m->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MAX, param_m->abpc_sn_coef_b_th_max);
+
+ /* setup param_l */
+ viif_capture_write(viif_dev, REG_L1_ABPC2_RATIO_LIMIT, param_l->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_DARK_LIMIT, param_l->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MIN, param_l->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MID, param_l->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MAX, param_l->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MIN, param_l->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MID, param_l->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MAX, param_l->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MIN, param_l->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MAX, param_l->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MIN, param_l->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MAX, param_l->abpc_sn_coef_b_th_max);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_preset_white_balance(struct viif_device *viif_dev,
+ const struct viif_l1_preset_white_balance_config *arg)
+{
+ const struct viif_l1_preset_wb *param_h, *param_m, *param_l;
+ unsigned long irqflags;
+
+ param_h = &arg->param_h;
+ param_m = &arg->param_m;
+ param_l = &arg->param_l;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_DSTMAXVAL, arg->dstmaxval);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_H_GR, param_h->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_HR, param_h->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_HB, param_h->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_H_GB, param_h->gain_gb);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_M_GR, param_m->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_MR, param_m->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_MB, param_m->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_M_GB, param_m->gain_gb);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_L_GR, param_l->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_LR, param_l->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_LB, param_l->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_L_GB, param_l->gain_gb);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void
+viif_l1_set_raw_color_noise_reduction(struct viif_device *viif_dev,
+ const struct viif_l1_raw_color_noise_reduction_config *arg)
+{
+ const struct viif_l1_raw_color_noise_reduction *params[] = {
+ &arg->param_h,
+ &arg->param_m,
+ &arg->param_l,
+ };
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ for (i = 0; i < 3; i++) {
+ const struct viif_l1_raw_color_noise_reduction *param = params[i];
+ /* param_h */
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_SW(i), param->rcnr_sw ? 1 : 0);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG0(i),
+ param->rcnr_cnf_dark_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG1(i),
+ param->rcnr_cnf_dark_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG2(i),
+ param->rcnr_cnf_dark_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG0(i),
+ param->rcnr_cnf_ratio_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG1(i),
+ param->rcnr_cnf_ratio_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG2(i),
+ param->rcnr_cnf_ratio_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_R(i),
+ param->rcnr_cnf_clip_gain_r);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_G(i),
+ param->rcnr_cnf_clip_gain_g);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_B(i),
+ param->rcnr_cnf_clip_gain_b);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG0(i),
+ param->rcnr_a1l_dark_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG1(i),
+ param->rcnr_a1l_dark_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG2(i),
+ param->rcnr_a1l_dark_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG0(i),
+ param->rcnr_a1l_ratio_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG1(i),
+ param->rcnr_a1l_ratio_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG2(i),
+ param->rcnr_a1l_ratio_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_INF_ZERO_CLIP(i),
+ param->rcnr_inf_zero_clip);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG0(i),
+ param->rcnr_merge_d2blend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG1(i),
+ param->rcnr_merge_d2blend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG2(i),
+ param->rcnr_merge_d2blend_ag2);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_BLACK(i), param->rcnr_merge_black);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_MINDIV(i),
+ param->rcnr_merge_mindiv);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_HRY_TYPE(i), param->rcnr_hry_type);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG0(i),
+ param->rcnr_anf_blend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG1(i),
+ param->rcnr_anf_blend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG2(i),
+ param->rcnr_anf_blend_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_LPF_THRESHOLD(i),
+ param->rcnr_lpf_threshold);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG0(i),
+ param->rcnr_merge_hlblend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG1(i),
+ param->rcnr_merge_hlblend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG2(i),
+ param->rcnr_merge_hlblend_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_SW(i), param->rcnr_gnr_sw ? 1 : 0);
+
+ if (param->rcnr_gnr_sw) {
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_RATIO(i),
+ param->rcnr_gnr_ratio);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_WIDE_EN(i),
+ param->rcnr_gnr_wide_en ? 1 : 0);
+ }
+ }
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_hdrs(struct viif_device *viif_dev, const struct viif_l1_hdrs_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRMODE, arg->hdrs_hdr_mode);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_M, arg->hdrs_hdr_ratio_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_L, arg->hdrs_hdr_ratio_l);
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_E, arg->hdrs_hdr_ratio_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_H, arg->hdrs_dg_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_M, arg->hdrs_dg_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_L, arg->hdrs_dg_l);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_E, arg->hdrs_dg_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_H, arg->hdrs_blendend_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_M, arg->hdrs_blendend_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_E, arg->hdrs_blendend_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_H, arg->hdrs_blendbeg_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_M, arg->hdrs_blendbeg_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_E, arg->hdrs_blendbeg_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_LEDMODE_ON, arg->hdrs_led_mode_on ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DSTMAXVAL, arg->hdrs_dst_max_val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void
+viif_l1_set_black_level_correction(struct viif_device *viif_dev,
+ const struct viif_l1_black_level_correction_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_GR, arg->srcblacklevel_gr);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_R, arg->srcblacklevel_r);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_B, arg->srcblacklevel_b);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVELGB, arg->srcblacklevel_gb);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GR, arg->mulval_gr);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_R, arg->mulval_r);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_B, arg->mulval_b);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GB, arg->mulval_gb);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_DSTMAXVAL, arg->dstmaxval);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void lsc_table_transmission(struct viif_device *viif_dev, dma_addr_t table_gr,
+ dma_addr_t table_r, dma_addr_t table_b, dma_addr_t table_gb)
+{
+ u32 val = 0x0U;
+
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+ if (table_gr) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GR),
+ (u32)table_gr);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GR),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_GR;
+ }
+
+ if (table_r) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_R),
+ (u32)table_r);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_R),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_R;
+ }
+
+ if (table_b) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_B),
+ (u32)table_b);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_B),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_B;
+ }
+
+ if (table_gb) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GB),
+ (u32)table_gb);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GB),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_GB;
+ }
+
+ val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_LSSC);
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static inline u32 gen_grid_size(u32 param)
+{
+ switch (param) {
+ case 32U:
+ return 5U;
+ case 64U:
+ return 6U;
+ case 128U:
+ return 7U;
+ case 256U:
+ return 8U;
+ case 512U:
+ return 9U;
+ default:
+ return 0;
+ }
+}
+
+#define PACK_PARA_COEF(max, min) (FIELD_PREP(0x1FFF0000, (max)) | FIELD_PREP(0x1FFF, (min)))
+
+static void viif_l1_set_lsc(struct viif_device *viif_dev, const struct viif_l1_lsc_config *arg)
+{
+ dma_addr_t table_gr = 0;
+ dma_addr_t table_gb = 0;
+ dma_addr_t table_r = 0;
+ dma_addr_t table_b = 0;
+ unsigned long irqflags;
+ u32 val;
+
+ if (!arg->enable) {
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_EN, 0);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+ return;
+ }
+
+ if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+ memcpy(viif_dev->tables->lsc_table_gr, arg->table_gr, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_r, arg->table_r, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_b, arg->table_b, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_gb, arg->table_gb, VIIF_LSC_TABLE_BYTES);
+ table_gr = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->lsc_table_gr;
+ table_r = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->lsc_table_r;
+ table_b = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->lsc_table_b;
+ table_gb = (dma_addr_t)(uintptr_t)viif_dev->tables_dma->lsc_table_gb;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+ lsc_table_transmission(viif_dev, table_gr, table_r, table_b, table_gb);
+
+ /* parabola shading */
+ if (arg->enable & VIIF_L1_LSC_PARABOLA_EN_MASK) {
+ const struct viif_l1_lsc_parabola_param *parabola_param =
+ &arg->param.lssc_parabola_param;
+ const struct viif_l1_lsc_parabola_ag_param *params[] = {
+ ¶bola_param->r_2d, ¶bola_param->r_4d, ¶bola_param->gr_2d,
+ ¶bola_param->gr_4d, ¶bola_param->gb_2d, ¶bola_param->gb_4d,
+ ¶bola_param->b_2d, ¶bola_param->b_4d,
+ };
+ int i;
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 1);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_CENTER,
+ parabola_param->lssc_para_h_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_CENTER,
+ parabola_param->lssc_para_v_center);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_GAIN,
+ parabola_param->lssc_para_h_gain);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_GAIN,
+ parabola_param->lssc_para_v_gain);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL2,
+ parabola_param->lssc_para_mgsel2);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL4,
+ parabola_param->lssc_para_mgsel4);
+
+ for (i = 0; i < 8; i++) {
+ const struct viif_l1_lsc_parabola_ag_param *p = params[i];
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_L(i),
+ PACK_PARA_COEF(p->lssc_paracoef_h_l_max,
+ p->lssc_paracoef_h_l_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_R(i),
+ PACK_PARA_COEF(p->lssc_paracoef_h_r_max,
+ p->lssc_paracoef_h_r_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_U(i),
+ PACK_PARA_COEF(p->lssc_paracoef_v_u_max,
+ p->lssc_paracoef_v_u_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_D(i),
+ PACK_PARA_COEF(p->lssc_paracoef_v_d_max,
+ p->lssc_paracoef_v_d_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LU(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_lu_max,
+ p->lssc_paracoef_hv_lu_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RU(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_ru_max,
+ p->lssc_paracoef_hv_ru_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LD(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_ld_max,
+ p->lssc_paracoef_hv_ld_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RD(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_rd_max,
+ p->lssc_paracoef_hv_rd_min));
+ }
+ } else {
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 0);
+ }
+
+ /* grid shading */
+ if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+ const struct viif_l1_lsc_grid_param *grid_param = &arg->param.lssc_grid_param;
+ u32 grid_h_size = gen_grid_size(grid_param->lssc_grid_h_size);
+ u32 grid_v_size = gen_grid_size(grid_param->lssc_grid_v_size);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 1);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_SIZE, grid_h_size);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_SIZE, grid_v_size);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_CENTER,
+ grid_param->lssc_grid_h_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_CENTER,
+ grid_param->lssc_grid_v_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_MGSEL, grid_param->lssc_grid_mgsel);
+
+ } else {
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 0);
+ }
+
+ /* preset white balance */
+ val = (arg->param.lssc_pwhb_r_gain_max << 16U) | (arg->param.lssc_pwhb_r_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_R_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_gr_gain_max << 16U) | (arg->param.lssc_pwhb_gr_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GR_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_gb_gain_max << 16U) | (arg->param.lssc_pwhb_gb_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GB_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_b_gain_max << 16U) | (arg->param.lssc_pwhb_b_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_B_GAIN, val);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_EN, 1);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_main_process(struct viif_device *viif_dev,
+ const struct viif_l1_main_process_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_CONF, arg->damp_lsbsel << 4);
+ viif_capture_write(viif_dev, REG_L1_MPRO_LCS_MODE, arg->demosaic_mode);
+
+ if (arg->colormat_enable) {
+ const struct viif_l1_color_matrix_correction *color_matrix = &arg->colormat_param;
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_SW, 1);
+
+ val = (u32)color_matrix->coef_rmg_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MIN, val);
+
+ val = (u32)color_matrix->coef_rmg_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MAX, val);
+
+ val = (u32)color_matrix->coef_rmb_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MIN, val);
+
+ val = (u32)color_matrix->coef_rmb_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MAX, val);
+
+ val = (u32)color_matrix->coef_gmr_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MIN, val);
+
+ val = (u32)color_matrix->coef_gmr_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MAX, val);
+
+ val = (u32)color_matrix->coef_gmb_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MIN, val);
+
+ val = (u32)color_matrix->coef_gmb_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MAX, val);
+
+ val = (u32)color_matrix->coef_bmr_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MIN, val);
+
+ val = (u32)color_matrix->coef_bmr_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MAX, val);
+
+ val = (u32)color_matrix->coef_bmg_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MIN, val);
+
+ val = (u32)color_matrix->coef_bmg_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MAX, val);
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_DST_MINVAL, (u32)color_matrix->dst_minval);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_MPRO_SW, 0);
+ }
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_DST_MAXVAL, arg->dst_maxval);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_awb(struct viif_device *viif_dev, const struct viif_l1_awb_config *arg)
+{
+ const struct viif_l1_awb *param = &arg->param;
+ unsigned long irqflags;
+ u32 val, ygate_data;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMRG, arg->awhb_wbmrg);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMGG, arg->awhb_wbmgg);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMBG, arg->awhb_wbmbg);
+
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_EN;
+
+ /* disabling AWB */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+ goto op_done;
+ }
+
+ /* enabling AWB */
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val | MASK_L1_AWHB_SW_EN);
+
+ if (param->awhb_ygate_data == 64U)
+ ygate_data = 0U;
+ else if (param->awhb_ygate_data == 128U)
+ ygate_data = 1U;
+ else if (param->awhb_ygate_data == 256U)
+ ygate_data = 2U;
+ else
+ ygate_data = 3U;
+
+ val = param->awhb_ygate_sel ? MASK_L1_AWHB_GATE_YGATE_SEL : 0;
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_YGATE_DATA, ygate_data);
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_CGRANGE, param->awhb_cgrange);
+ viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF0, val);
+
+ val = param->awhb_ygatesw ? MASK_L1_AWHB_GATE_YGATESW : 0;
+ val |= param->awhb_hexsw ? MASK_L1_AWHB_GATE_HEXSW : 0;
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_AREAMODE, param->awhb_areamode);
+ viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF1, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HSIZE, param->awhb_area_hsize);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VSIZE, param->awhb_area_vsize);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HOFS, param->awhb_area_hofs);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VOFS, param->awhb_area_vofs);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKH, param->awhb_area_maskh);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKL, param->awhb_area_maskl);
+
+ val = param->awhb_sq_sw[0] ? MASK_L1_AWHB_SQ_CONF_SQ1SW : 0;
+ val |= param->awhb_sq_pol[0] ? MASK_L1_AWHB_SQ_CONF_SQ1POL : 0;
+ val |= param->awhb_sq_sw[1] ? MASK_L1_AWHB_SQ_CONF_SQ2SW : 0;
+ val |= param->awhb_sq_pol[1] ? MASK_L1_AWHB_SQ_CONF_SQ2POL : 0;
+ val |= param->awhb_sq_sw[2] ? MASK_L1_AWHB_SQ_CONF_SQ3SW : 0;
+ val |= param->awhb_sq_pol[2] ? MASK_L1_AWHB_SQ_CONF_SQ3POL : 0;
+ viif_capture_write(viif_dev, REG_L1_AWHB_SQ_CONF, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_YGATEH, (u32)param->awhb_ygateh);
+ viif_capture_write(viif_dev, REG_L1_AWHB_YGATEL, (u32)param->awhb_ygatel);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0P, param->awhb_bycut0p);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0N, param->awhb_bycut0n);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0P, param->awhb_rycut0p);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0N, param->awhb_rycut0n);
+
+ val = (u32)param->awhb_rbcut0h & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0H, val);
+ val = (u32)param->awhb_rbcut0l & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0L, val);
+
+ val = (u32)param->awhb_bycut_h[0] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1L, param->awhb_bycut_l[0]);
+ val = (u32)param->awhb_bycut_h[1] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2L, param->awhb_bycut_l[1]);
+ val = (u32)param->awhb_bycut_h[2] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3L, param->awhb_bycut_l[2]);
+
+ val = (u32)param->awhb_rycut_h[0] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1L, param->awhb_rycut_l[0]);
+ val = (u32)param->awhb_rycut_h[1] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2L, param->awhb_rycut_l[1]);
+ val = (u32)param->awhb_rycut_h[2] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3L, param->awhb_rycut_l[2]);
+
+ val = (u32)param->awhb_awbsftu & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTU, val);
+ val = (u32)param->awhb_awbsftv & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTV, val);
+
+ val = (param->awhb_awbhuecor ? MASK_L1_AWHB_AWBSPD_HUECOR : 0);
+ val |= FIELD_PREP(MASK_L1_AWHB_AWBSPD_SPD, param->awhb_awbspd);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSPD, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBULV, param->awhb_awbulv);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBVLV, param->awhb_awbvlv);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBWAIT, (u32)param->awhb_awbwait);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBONDOT, param->awhb_awbondot);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBFZTIM, param->awhb_awbfztim);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMAX, (u32)param->awhb_wbgrmax);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMAX, (u32)param->awhb_wbgbmax);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMIN, (u32)param->awhb_wbgrmin);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMIN, (u32)param->awhb_wbgbmin);
+
+op_done:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_lock_awb_gain(struct viif_device *viif_dev, const u32 *enable)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_LOCK;
+ val |= (*enable ? MASK_L1_AWHB_SW_LOCK : 0);
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+/* Convert the unit of time-period (from sysclk, to num lines in the image) */
+static u32 sysclk_to_numlines(u32 time_in_sysclk, const struct viif_img_clk *img_clk)
+{
+ u64 v1 = (u64)time_in_sysclk * img_clk->pixel_clock;
+ u64 v2 = (u64)img_clk->htotal_size * VIIF_SYS_CLK;
+
+ return (u32)div64_u64(v1, v2);
+}
+
+static void viif_l1_set_hdrc(struct viif_device *viif_dev, const struct viif_l1_hdrc_config *arg)
+{
+ const struct viif_l1_hdrc *param = &arg->param;
+ unsigned long irqflags;
+ u32 val, sw_delay1;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling HDRC */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_HDRC_THR_SFT_AMT, arg->hdrc_thr_sft_amt);
+ viif_capture_write(viif_dev, REG_L1_HDRC_EN, 0);
+
+ goto done_op;
+ }
+
+ /* enabling HDRC */
+ viif_capture_write(viif_dev, REG_L1_HDRC_RATIO,
+ (param->hdrc_ratio - VIIF_L1_HDRC_RATIO_OFFSET));
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_RATIO, param->hdrc_pt_ratio);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND, param->hdrc_pt_blend);
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND2, param->hdrc_pt_blend2);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_SAT, param->hdrc_pt_sat);
+ viif_capture_write(viif_dev, REG_L1_HDRC_TN_TYPE, param->hdrc_tn_type);
+
+ for (i = 0; i < LEN_L1_HDRC_UTN_TBL; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRC_UTN_TBL(i), param->hdrc_utn_tbl[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_FLR_VAL, param->hdrc_flr_val);
+ viif_capture_write(viif_dev, REG_L1_HDRC_FLR_ADP, param->hdrc_flr_adp ? 1 : 0);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_YBR_OFF, param->hdrc_ybr_off ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L1_HDRC_ORGY_BLEND, param->hdrc_orgy_blend);
+
+ val = ((viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT)) % 64U) / 2U;
+ viif_capture_write(viif_dev, REG_L1_HDRC_MAR_TOP, val);
+ val = ((viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH)) % 64U) / 2U;
+ viif_capture_write(viif_dev, REG_L1_HDRC_MAR_LEFT, val);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_EN, 1);
+
+ /* update of sw_delay1 must be done when MAIN unit is NOT running. */
+ if (!viif_dev->run_flag_main) {
+ sw_delay1 = sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, &viif_dev->img_clk) +
+ VIIF_L1_DELAY_W_HDRC + 1U;
+ val = viif_capture_read(viif_dev, REG_INT_M1_LINE) & 0xffffU;
+ val |= (sw_delay1 << 16U);
+ viif_capture_write(viif_dev, REG_INT_M1_LINE, val);
+ /* M2_LINE is the same condition as M1_LINE */
+ viif_capture_write(viif_dev, REG_INT_M2_LINE, val);
+ }
+
+done_op:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_hdrc_ltm(struct viif_device *viif_dev,
+ const struct viif_l1_hdrc_ltm_config *arg)
+{
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAX, arg->tnp_max);
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAG, arg->tnp_mag);
+
+ for (i = 0; i < LEN_L1_HDRC_TNP_FIL; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_FIL(i), (u32)arg->tnp_fil[i]);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void viif_l1_set_gamma(struct viif_device *viif_dev, const struct viif_l1_gamma_config *arg)
+{
+ const struct viif_l1_gamma *param = &arg->param;
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling L1 gamma */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 0);
+ goto done_op;
+ }
+
+ /* enabling L1 gamma */
+ for (i = 0; i < 44; i++)
+ viif_capture_write(viif_dev, REG_L1_VPRO_GAMxP(i), param->gam_p[i]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLKADJ, param->blkadj);
+ viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 1);
+
+done_op:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void
+viif_l1_set_img_quality_adjustment(struct viif_device *viif_dev,
+ const struct viif_l1_img_quality_adjustment_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* RGB to YUV (enabled by default, should be enabled) */
+ viif_capture_write(viif_dev, REG_L1_VPRO_YUVC_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_MAT, (u32)arg->coef_cb);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_MAT, (u32)arg->coef_cr);
+
+ /* brightness */
+ val = (u32)arg->brightness & 0xffffU;
+ if (val) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT, val);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 0);
+ }
+
+ /* linear contrast */
+ if ((u32)arg->linear_contrast != 128U) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCONT_LEV, arg->linear_contrast);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 0);
+ }
+
+ /* nonlinear contrast */
+ if (arg->enable & VIIF_L1_IQA_NONLINEAR_CONTRAST_EN_MASK) {
+ const struct viif_l1_nonlinear_contrast *nonlinear_contrast =
+ &arg->nonlinear_contrast;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_KNEE, nonlinear_contrast->blk_knee);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_KNEE, nonlinear_contrast->wht_knee);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT0,
+ nonlinear_contrast->blk_cont[0]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT1,
+ nonlinear_contrast->blk_cont[1]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT2,
+ nonlinear_contrast->blk_cont[2]);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT0,
+ nonlinear_contrast->wht_cont[0]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT1,
+ nonlinear_contrast->wht_cont[1]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT2,
+ nonlinear_contrast->wht_cont[2]);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 0);
+ }
+
+ /* luminance noise reduction */
+ if (arg->enable & VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK) {
+ const struct viif_l1_lum_noise_reduction *lum_noise_reduction =
+ &arg->lum_noise_reduction;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MIN,
+ lum_noise_reduction->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MAX,
+ lum_noise_reduction->gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MIN, lum_noise_reduction->lim_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MAX, lum_noise_reduction->lim_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 0);
+ }
+
+ /* edge enhancement */
+ if (arg->enable & VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK) {
+ const struct viif_l1_edge_enhancement *edge_enhancement = &arg->edge_enhancement;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MIN, edge_enhancement->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MAX, edge_enhancement->gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MIN, edge_enhancement->lim_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MAX, edge_enhancement->lim_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MIN,
+ edge_enhancement->coring_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MAX,
+ edge_enhancement->coring_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 0);
+ }
+
+ /* UV suppression */
+ if (arg->enable & VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK) {
+ const struct viif_l1_uv_suppression *uv_suppression = &arg->uv_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_SLV, uv_suppression->bk_slv);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_MP, uv_suppression->bk_mp);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BLACK, uv_suppression->black);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_SLV, uv_suppression->wh_slv);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_MP, uv_suppression->wh_mp);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WHITE, uv_suppression->white);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 0);
+ }
+
+ /* coring suppression */
+ if (arg->enable & VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK) {
+ const struct viif_l1_coring_suppression *coring_suppression =
+ &arg->coring_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MIN,
+ coring_suppression->lv_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MAX,
+ coring_suppression->lv_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MIN,
+ coring_suppression->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MAX,
+ coring_suppression->gain_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 0);
+ }
+
+ /* edge suppression */
+ if (arg->enable & VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK) {
+ const struct viif_l1_edge_suppression *edge_suppression = &arg->edge_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_GAIN, edge_suppression->gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_LIM, edge_suppression->lim);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 0);
+ }
+
+ /* color level */
+ if (arg->enable & VIIF_L1_IQA_COLOR_LEVEL_EN_MASK) {
+ const struct viif_l1_color_level *color_level = &arg->color_level;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, color_level->cb_gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, color_level->cr_gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, color_level->cbr_mgain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, color_level->cbp_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, color_level->cbm_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, color_level->crp_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, color_level->crm_gain_max);
+ } else {
+ /* disable */
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, 0U);
+ }
+
+ /* color noise reduction */
+ viif_capture_write(viif_dev, REG_L1_VPRO_CNR_SW,
+ arg->enable & VIIF_L1_IQA_COLOR_NOISE_REDUCTION_EN_MASK ? 1 : 0);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static inline u32 pack_weight(const u32 *vec)
+{
+ return (vec[0] << 14) | (vec[1] << 12) | (vec[2] << 10) | (vec[3] << 8) | (vec[4] << 6) |
+ (vec[5] << 4) | (vec[6] << 2U) | (vec[7]);
+}
+
+static void viif_l1_set_avg_lum_generation(struct viif_device *viif_dev,
+ const struct viif_l1_avg_lum_generation_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling aggregation */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_AEXP_ON, 0);
+ goto op_done;
+ }
+
+ /* enabling aggregation */
+ viif_capture_write(viif_dev, REG_L1_AEXP_ON, 1);
+ viif_capture_write(viif_dev, REG_L1_AEXP_START_X, arg->aexp_start_x);
+ viif_capture_write(viif_dev, REG_L1_AEXP_START_Y, arg->aexp_start_y);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_WIDTH, arg->aexp_block_width);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_HEIGHT, arg->aexp_block_height);
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_0, pack_weight(arg->aexp_weight[0]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_1, pack_weight(arg->aexp_weight[1]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_2, pack_weight(arg->aexp_weight[2]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[3]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[4]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_4, pack_weight(arg->aexp_weight[5]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_5, pack_weight(arg->aexp_weight[6]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_7, pack_weight(arg->aexp_weight[7]));
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_RATIO, arg->aexp_satur_ratio);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLACK_RATIO, arg->aexp_black_ratio);
+ viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_LEVEL, arg->aexp_satur_level);
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY0, arg->aexp_ave4linesy[0]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY1, arg->aexp_ave4linesy[1]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY2, arg->aexp_ave4linesy[2]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY3, arg->aexp_ave4linesy[3]);
+
+op_done:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static void undist_table_transmission(struct viif_device *viif_dev, dma_addr_t write_g,
+ dma_addr_t read_b, dma_addr_t read_g, dma_addr_t read_r,
+ u32 size)
+{
+ u32 val = 0U;
+
+ if (read_b) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_B),
+ (u32)read_b);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_B), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_B;
+ }
+ if (read_g) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_G),
+ (u32)read_g);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_G), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_G;
+ }
+ if (read_r) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_R),
+ (u32)read_r);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_R), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_R;
+ }
+ if (write_g) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_WR_G),
+ (u32)write_g);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_WR_G), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_WR_G;
+ }
+
+ if (val)
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_UNDIST);
+
+ val |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L2_UNDIST;
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static void undist_setup(struct viif_device *viif_dev, const struct viif_l2_undist *param)
+{
+ u32 val;
+ unsigned int i;
+
+ /* Undist through mode */
+ if (param->through_mode) {
+ /* Enable through mode */
+ viif_capture_write(viif_dev, REG_L2_MODE, 1);
+ return;
+ }
+
+ /* Undist operation */
+ val = (param->roi_mode[0] << 1U) | (param->roi_mode[1] << 3U);
+ viif_capture_write(viif_dev, REG_L2_MODE, val);
+ val = (u32)param->sensor_crop_ofs_h & GENMASK(13, 0);
+ viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_H, val);
+ val = (u32)param->sensor_crop_ofs_v & GENMASK(12, 0);
+ viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_V, val);
+ viif_capture_write(viif_dev, REG_L2_NORM_SCALE, param->norm_scale);
+ viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_POLY, param->valid_r_norm2_poly);
+ viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_GRID, param->valid_r_norm2_grid);
+ viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(0),
+ param->roi_write_area_delta[0]);
+ viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(1),
+ param->roi_write_area_delta[1]);
+
+ for (i = 0; i < VIIF_L2_UNDIST_POLY_NUM; i++) {
+ val = (u32)param->poly_write_g_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_WRITE_G_COEF(i), val);
+ val = (u32)param->poly_read_b_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_B_COEF(i), val);
+ val = (u32)param->poly_read_g_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_G_COEF(i), val);
+ val = (u32)param->poly_read_r_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_R_COEF(i), val);
+ }
+ viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_H, param->grid_node_num_h);
+ viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_V, param->grid_node_num_v);
+ viif_capture_write(viif_dev, REG_L2_GRID_PATCH_HSIZE_INV, param->grid_patch_hsize_inv);
+ viif_capture_write(viif_dev, REG_L2_GRID_PATCH_VSIZE_INV, param->grid_patch_vsize_inv);
+}
+
+static void viif_l2_set_undist(struct viif_device *viif_dev,
+ const struct viif_l2_undist_config *arg)
+{
+ dma_addr_t table_write_g = 0;
+ dma_addr_t table_read_b = 0;
+ dma_addr_t table_read_g = 0;
+ dma_addr_t table_read_r = 0;
+ unsigned long irqflags;
+
+ if (arg->param.roi_mode[0] != VIIF_L2_UNDIST_POLY ||
+ arg->param.roi_mode[1] != VIIF_L2_UNDIST_POLY) {
+ memcpy(viif_dev->tables->undist_write_g, arg->write_g, arg->size);
+ memcpy(viif_dev->tables->undist_read_b, arg->read_b, arg->size);
+ memcpy(viif_dev->tables->undist_read_g, arg->read_g, arg->size);
+ memcpy(viif_dev->tables->undist_read_r, arg->read_r, arg->size);
+
+ table_write_g = (uintptr_t)viif_dev->tables_dma->undist_write_g;
+ table_read_b = (uintptr_t)viif_dev->tables_dma->undist_read_b;
+ table_read_g = (uintptr_t)viif_dev->tables_dma->undist_read_g;
+ table_read_r = (uintptr_t)viif_dev->tables_dma->undist_read_r;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ undist_table_transmission(viif_dev, table_write_g, table_read_b, table_read_g, table_read_r,
+ arg->size);
+
+ undist_setup(viif_dev, &arg->param);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+int visconti_viif_l2_undist_through(struct viif_device *viif_dev)
+{
+ struct viif_l2_undist undist = { 0 };
+
+ undist.through_mode = VIIF_ENABLE;
+ undist.sensor_crop_ofs_h =
+ 1 - FIELD_GET(0x1FFF, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE));
+ undist.sensor_crop_ofs_v =
+ 1 - FIELD_GET(0x0FFF, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE));
+ undist.grid_node_num_h = 16;
+ undist.grid_node_num_v = 16;
+
+ undist_setup(viif_dev, &undist);
+
+ return 0;
+}
+
+static void viif_l2_set_roi_wrap(struct viif_device *viif_dev, const struct viif_l2_roi_config *roi)
+{
+ unsigned long irqflags;
+
+ /* update ROI parameter */
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+ visconti_viif_l2_set_roi(viif_dev, roi);
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ /* reflect change to pad::compose_rect */
+ visconti_viif_isp_set_compose_rect(viif_dev, roi);
+}
+
+struct viif_l2_gamma_table {
+ dma_addr_t table[VIIF_L2_GAMMA_TABLE_CH_NUM];
+};
+
+static void l2_gamma_table_transmission(struct viif_device *viif_dev, u32 post_id,
+ const struct viif_l2_gamma_table *gamma_table)
+{
+ u32 vdm_enable = 0U;
+ u32 i;
+
+ /* 0: LUT0-G/Y, 1: LUT1-G/Y, 2: LUT0-B/U, 3: LUT1-B/U, 4: LUT0-R/V, 5: LUT1-R/V */
+ for (i = 0; i < VIIF_L2_GAMMA_TABLE_CH_NUM; i++) {
+ if (gamma_table->table[i]) {
+ int idx = IDX_TPORT_L2_GAMMA_LUT(post_id, i);
+
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(idx),
+ (u32)gamma_table->table[i]);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(idx),
+ VIIF_L2_GAMMA_TABLE_BYTES);
+ vdm_enable |= MASK_VDM_T_ENABLE_L2_GAMMA(post_id, i);
+ }
+ }
+ if (vdm_enable)
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_GAMMA_LUT(post_id));
+
+ vdm_enable |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) &
+ ~MASK_VDM_T_ENABLE_L2_GAMMA_ALL(post_id);
+
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, vdm_enable);
+}
+
+static void viif_l2_set_gamma(struct viif_device *viif_dev, int pathid,
+ const struct viif_l2_gamma_config *l2_gamma)
+{
+ struct viif_l2_gamma_table dma_table = { 0 };
+ int postid = (pathid == CAPTURE_PATH_MAIN_POST0) ? VIIF_L2ISP_POST_0 : VIIF_L2ISP_POST_1;
+ unsigned long irqflags;
+ int table_en;
+ u32 val;
+ int i;
+
+ table_en = l2_gamma->table_en;
+ for (i = 0; i < 6; i++) {
+ if (table_en & BIT(i)) {
+ memcpy(viif_dev->tables->l2_gamma_table[pathid][i], l2_gamma->table[i],
+ VIIF_L2_GAMMA_TABLE_BYTES);
+ dma_table.table[i] =
+ (dma_addr_t)(uintptr_t)
+ viif_dev->tables_dma->l2_gamma_table[pathid][i];
+ }
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ l2_gamma_table_transmission(viif_dev, postid, &dma_table);
+
+ val = (l2_gamma->vsplit << 16U) | (l2_gamma->mode << 4U) | (table_en != 0 ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L2_POST_X_GAMMA_M(postid), val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static const struct viif_l1_input_mode_config defval_l1_set_input_mode = {
+ .mode = VIIF_L1_INPUT_HDR,
+};
+
+static const struct viif_l1_rgb_to_y_coef_config defval_l1_set_rgb_to_y_coef = {
+ /* ITU-R BT.601 */
+ .coef_r = 0x4C8C,
+ .coef_g = 0x9644,
+ .coef_b = 0x1D30,
+};
+
+static const struct viif_l1_ag_mode_config defval_l1_set_ag_mode = { 0 };
+
+static const struct viif_l1_ag_config defval_l1_set_ag = { 0 };
+
+static const struct viif_l1_hdre_config defval_l1_set_hdre = {
+ .hdre_src_point[0] = 0x3FFF,
+ .hdre_dst_max_val = 0xFFFFFF,
+};
+
+static const struct viif_l1_img_extraction_config defval_l1_set_img_extraction = {
+ .input_black_gr = 256,
+ .input_black_r = 256,
+ .input_black_b = 256,
+ .input_black_gb = 256,
+};
+
+static const struct viif_l1_dpc_config defval_l1_set_dpc = { 0 };
+
+static const struct viif_l1_preset_white_balance_config defval_l1_set_preset_white_balance = {
+ .dstmaxval = 0x0FFF,
+ .param_h = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+ .param_m = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+ .param_l = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+};
+
+static const
+struct viif_l1_raw_color_noise_reduction_config defval_l1_set_raw_color_noise_reduction = {
+ .param_h = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+ .param_m = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+ .param_l = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+};
+
+static const struct viif_l1_hdrs_config defval_l1_set_hdrs = {
+ .hdrs_hdr_mode = 1,
+ .hdrs_hdr_ratio_m = 0x10000,
+ .hdrs_hdr_ratio_l = 0x400000,
+ .hdrs_hdr_ratio_e = 0x400,
+ .hdrs_dg_h = 0x400,
+ .hdrs_dg_m = 0x400,
+ .hdrs_dg_l = 0x400,
+ .hdrs_dg_e = 0x400,
+ .hdrs_blendend_h = 0xFA0,
+ .hdrs_blendend_m = 0xFA0,
+ .hdrs_blendend_e = 0xFA0,
+ .hdrs_blendbeg_h = 0x12C,
+ .hdrs_blendbeg_m = 0x12C,
+ .hdrs_blendbeg_e = 0x12C,
+ .hdrs_dst_max_val = 0xFFFFFF,
+};
+
+static const struct viif_l1_black_level_correction_config defval_l1_set_black_level_correction = {
+ .srcblacklevel_gr = 0x40,
+ .srcblacklevel_r = 0x40,
+ .srcblacklevel_b = 0x40,
+ .srcblacklevel_gb = 0x40,
+ .mulval_gr = 0x40000,
+ .mulval_r = 0x40000,
+ .mulval_b = 0x40000,
+ .mulval_gb = 0x40000,
+ .dstmaxval = 0xFFFFFF,
+};
+
+static const struct viif_l1_lsc_config defval_l1_set_lsc = { 0 };
+
+static const struct viif_l1_main_process_config defval_l1_set_main_process = {
+ .damp_lsbsel = 0x8,
+ .demosaic_mode = 1,
+ .colormat_enable = 0,
+ .dst_maxval = 0xFFFFFF,
+};
+
+static const struct viif_l1_awb_config defval_l1_set_awb = {
+ .enable = 0,
+ .awhb_wbmrg = 256,
+ .awhb_wbmgg = 256,
+ .awhb_wbmbg = 256,
+};
+
+static const u32 defval_l1_lock_awb_gain;
+
+static const struct viif_l1_hdrc_config
+ defval_l1_set_hdrc = { .enable = 1,
+ .param = {
+ .hdrc_ratio = 0x0E + VIIF_L1_HDRC_RATIO_OFFSET,
+ .hdrc_pt_ratio = 7,
+ .hdrc_pt_sat = 0xFFC0,
+ .hdrc_tn_type = 1,
+ } };
+
+static const struct viif_l1_hdrc_ltm_config defval_l1_set_hdrc_ltm = {
+ .tnp_max = 0x3FFFFF,
+ .tnp_mag = 0x40,
+ .tnp_fil = { 0x88, 0x84, 0x7A, 0x6A, 0x54 },
+};
+
+static const struct viif_l1_gamma_config defval_l1_set_gamma = {
+ .enable = 1,
+ .param = {
+ .gam_p = {
+ 0x02F, 0x01B, 0x02A, 0x023, 0x020, 0x037, 0x031, 0x057, 0x04D, 0x088,
+ 0x078, 0x0D6, 0x0BD, 0x14F, 0x12A, 0x20D, 0x1D3, 0x1AB, 0x18D, 0x2DC,
+ 0x29E, 0x271, 0x47C, 0x41B, 0x3D4, 0x70A, 0x672, 0x601, 0xB0C, 0xA1D,
+ 0x96C, 0x8E2, 0x874, 0xFDD, 0xEC9, 0xDF2, 0xD42, 0xCB1, 0xC35, 0xBC9,
+ 0xB6A, 0xB16, 0xACB, 0xA86},
+ .blkadj = 0x1000,
+ },
+};
+
+static const struct viif_l1_img_quality_adjustment_config defval_l1_set_img_quality_adjustment = {
+ .enable = 0,
+ .coef_cb = 0x9078,
+ .coef_cr = 0xB699,
+ .brightness = 0,
+ .linear_contrast = 128,
+};
+
+static const struct viif_l1_avg_lum_generation_config defval_l1_set_avg_lum_generation = {
+ .enable = 0
+};
+
+static const struct viif_l2_undist_config defval_l2_set_undist = { .param = {
+ .through_mode = 1,
+ .roi_mode = { 0, 0 },
+ .grid_node_num_h = 0x10,
+ .grid_node_num_v = 0x10,
+ } };
+
+static const struct viif_l2_roi_config defval_l2_set_roi = {
+ .roi_num = 1,
+ .roi_scale = { 65536, 65536 },
+ .roi_scale_inv = { 65536, 65536 },
+ .corrected_wo_scale_hsize = { 0x80, 0x80 },
+ .corrected_hsize = { 0x80, 0x80 },
+ .corrected_wo_scale_vsize = { 0x80, 0x80 },
+ .corrected_vsize = { 0x80, 0x80 },
+};
+
+static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
+
+static void viif_apply_default_parameter(struct viif_device *viif_dev)
+{
+ viif_l1_set_input_mode(viif_dev, &defval_l1_set_input_mode);
+ viif_l1_set_rgb_to_y_coef(viif_dev, &defval_l1_set_rgb_to_y_coef);
+ viif_l1_set_ag_mode(viif_dev, &defval_l1_set_ag_mode);
+ viif_l1_set_ag(viif_dev, &defval_l1_set_ag);
+ viif_l1_set_hdre(viif_dev, &defval_l1_set_hdre);
+ viif_l1_set_img_extraction(viif_dev, &defval_l1_set_img_extraction);
+ viif_l1_set_dpc(viif_dev, &defval_l1_set_dpc);
+ viif_l1_set_preset_white_balance(viif_dev, &defval_l1_set_preset_white_balance);
+ viif_l1_set_raw_color_noise_reduction(viif_dev, &defval_l1_set_raw_color_noise_reduction);
+ viif_l1_set_hdrs(viif_dev, &defval_l1_set_hdrs);
+ viif_l1_set_black_level_correction(viif_dev, &defval_l1_set_black_level_correction);
+ viif_l1_set_lsc(viif_dev, &defval_l1_set_lsc);
+ viif_l1_set_main_process(viif_dev, &defval_l1_set_main_process);
+ viif_l1_set_awb(viif_dev, &defval_l1_set_awb);
+ viif_l1_lock_awb_gain(viif_dev, &defval_l1_lock_awb_gain);
+ viif_l1_set_hdrc(viif_dev, &defval_l1_set_hdrc);
+ viif_l1_set_hdrc_ltm(viif_dev, &defval_l1_set_hdrc_ltm);
+ viif_l1_set_gamma(viif_dev, &defval_l1_set_gamma);
+ viif_l1_set_img_quality_adjustment(viif_dev, &defval_l1_set_img_quality_adjustment);
+ viif_l1_set_avg_lum_generation(viif_dev, &defval_l1_set_avg_lum_generation);
+ viif_l2_set_undist(viif_dev, &defval_l2_set_undist);
+ viif_l2_set_roi_wrap(viif_dev, &defval_l2_set_roi);
+ viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &defval_l2_set_gamma);
+ viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &defval_l2_set_gamma);
+}
+
+/*=======================================================================*/
+/* parameter buffer streaming interface */
+/*=======================================================================*/
+struct viif_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head queue;
+};
+
+static bool viif_params_get_buffer(struct params_dev *params_dev, struct viif_buffer **buf,
+ struct visconti_viif_isp_config **cfg)
+{
+ if (list_empty(¶ms_dev->params_queue))
+ return false;
+
+ *buf = list_first_entry(¶ms_dev->params_queue, struct viif_buffer, queue);
+ *cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
+
+ return true;
+}
+
+static int viif_apply_queued_parameter(struct viif_device *viif_dev, bool initial_cfg)
+{
+ struct params_dev *params_dev = &viif_dev->params_dev;
+ struct visconti_viif_isp_config *new_params;
+ struct viif_buffer *cur_buf;
+ int ret = 0;
+
+ spin_lock(¶ms_dev->params_lock);
+
+ if (!viif_params_get_buffer(params_dev, &cur_buf, &new_params)) {
+ ret = 1;
+ goto unlock;
+ }
+
+ /* evaluate new_params */
+ if (initial_cfg) {
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_INPUT_MODE)
+ viif_l1_set_input_mode(viif_dev, &new_params->l1_input_mode);
+ }
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RGB_TO_Y_COEF)
+ viif_l1_set_rgb_to_y_coef(viif_dev, &new_params->l1_rgb_to_y_coef);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG_MODE)
+ viif_l1_set_ag_mode(viif_dev, &new_params->l1_ag_mode);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG)
+ viif_l1_set_ag(viif_dev, &new_params->l1_ag);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRE)
+ viif_l1_set_hdre(viif_dev, &new_params->l1_hdre);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_EXTRACTION)
+ viif_l1_set_img_extraction(viif_dev, &new_params->l1_img_extraction);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_DPC)
+ viif_l1_set_dpc(viif_dev, &new_params->l1_dpc);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_PRESET_WHITE_BALANCE)
+ viif_l1_set_preset_white_balance(viif_dev, &new_params->l1_preset_white_balance);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RAW_COLOR_NOISE_REDUCTION)
+ viif_l1_set_raw_color_noise_reduction(viif_dev,
+ &new_params->l1_raw_color_noise_reduction);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRS)
+ viif_l1_set_hdrs(viif_dev, &new_params->l1_hdrs);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_BLACK_LEVEL_CORRECTION)
+ viif_l1_set_black_level_correction(viif_dev,
+ &new_params->l1_black_level_correction);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LSC)
+ viif_l1_set_lsc(viif_dev, &new_params->l1_lsc);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_MAIN_PROCESS)
+ viif_l1_set_main_process(viif_dev, &new_params->l1_main_process);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AWB)
+ viif_l1_set_awb(viif_dev, &new_params->l1_awb);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LOCK_AWB_GAIN)
+ viif_l1_lock_awb_gain(viif_dev, &new_params->lock_awb_gain);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC)
+ viif_l1_set_hdrc(viif_dev, &new_params->l1_hdrc);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC_LTM)
+ viif_l1_set_hdrc_ltm(viif_dev, &new_params->l1_hdrc_ltm);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_GAMMA)
+ viif_l1_set_gamma(viif_dev, &new_params->l1_gamma);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_QUALITY_ADJUSTMENT)
+ viif_l1_set_img_quality_adjustment(viif_dev,
+ &new_params->l1_img_quality_adjustment);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AVG_LUM_GENERATION)
+ viif_l1_set_avg_lum_generation(viif_dev, &new_params->l1_avg_lum_generation);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_UNDIST)
+ viif_l2_set_undist(viif_dev, &new_params->l2_undist);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_ROI)
+ viif_l2_set_roi_wrap(viif_dev, &new_params->l2_roi);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST0)
+ viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &new_params->l2_gamma_post0);
+ if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST1)
+ viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &new_params->l2_gamma_post1);
+
+ /* release buffer */
+ list_del(&cur_buf->queue);
+ cur_buf->vb.sequence = 0;
+ vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+unlock:
+ spin_unlock(¶ms_dev->params_lock);
+ return ret;
+}
+
+void visconti_viif_params_isr(struct viif_device *viif_dev)
+{
+ viif_apply_queued_parameter(viif_dev, false);
+}
+
+void visconti_viif_params_eval_queue(struct viif_device *viif_dev)
+{
+ if (viif_apply_queued_parameter(viif_dev, true))
+ viif_apply_default_parameter(viif_dev);
+}
+
+static int viif_params_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (f->index > 0 || f->type != vdev->queue->type)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
+
+ return 0;
+}
+
+static int viif_params_g_fmt_meta_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_meta_format *meta = &f->fmt.meta;
+
+ if (f->type != vdev->queue->type)
+ return -EINVAL;
+
+ memset(meta, 0, sizeof(*meta));
+ meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
+ meta->buffersize = sizeof(struct visconti_viif_isp_config);
+
+ return 0;
+}
+
+static int viif_params_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
+ strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0", sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_params_ioctl = {
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_enum_fmt_meta_out = viif_params_enum_fmt_meta_out,
+ .vidioc_g_fmt_meta_out = viif_params_g_fmt_meta_out,
+ .vidioc_s_fmt_meta_out = viif_params_g_fmt_meta_out,
+ .vidioc_try_fmt_meta_out = viif_params_g_fmt_meta_out,
+ .vidioc_querycap = viif_params_querycap,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations viif_params_fops = { .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = vb2_fop_poll,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release };
+
+static int viif_params_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
+ *num_planes = 1;
+ sizes[0] = sizeof(struct visconti_viif_isp_config);
+ return 0;
+}
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct params_dev *vb2queue_to_paramsdev(struct vb2_queue *vq)
+{
+ return (struct params_dev *)vb2_get_drv_priv(vq);
+}
+
+static void viif_params_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct params_dev *params_dev = vb2queue_to_paramsdev(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct viif_buffer *buf = vb2_to_viif(vbuf);
+
+ spin_lock_irq(¶ms_dev->params_lock);
+ list_add_tail(&buf->queue, ¶ms_dev->params_queue);
+ spin_unlock_irq(¶ms_dev->params_lock);
+}
+
+static int viif_params_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_config))
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_config));
+ return 0;
+}
+
+static int viif_params_vb2_start_streaming(struct vb2_queue *q, unsigned int arg)
+{
+ return 0;
+}
+
+static void viif_params_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct params_dev *params_dev = vb2queue_to_paramsdev(q);
+ struct viif_buffer *buf;
+ LIST_HEAD(tmp_list);
+
+ spin_lock_irq(¶ms_dev->params_lock);
+ list_splice_init(¶ms_dev->params_queue, &tmp_list);
+ spin_unlock_irq(¶ms_dev->params_lock);
+
+ list_for_each_entry(buf, &tmp_list, queue)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops viif_params_vb2_ops = {
+ .queue_setup = viif_params_vb2_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = viif_params_vb2_buf_queue,
+ .buf_prepare = viif_params_vb2_buf_prepare,
+ .start_streaming = viif_params_vb2_start_streaming,
+ .stop_streaming = viif_params_vb2_stop_streaming,
+};
+
+int visconti_viif_params_register(struct viif_device *viif_dev)
+{
+ struct params_dev *params_dev = &viif_dev->params_dev;
+ struct video_device *vdev = ¶ms_dev->vdev;
+ struct vb2_queue *q = ¶ms_dev->vb2_vq;
+ int ret;
+
+ mutex_init(¶ms_dev->vlock);
+ INIT_LIST_HEAD(¶ms_dev->params_queue);
+ spin_lock_init(¶ms_dev->params_lock);
+
+ strscpy(vdev->name, "viif_params", sizeof(vdev->name));
+
+ /* Register the video device */
+ video_set_drvdata(vdev, params_dev);
+ vdev->ioctl_ops = &viif_params_ioctl;
+ vdev->fops = &viif_params_fops;
+ vdev->release = video_device_release_empty;
+ vdev->lock = ¶ms_dev->vlock;
+ vdev->v4l2_dev = &viif_dev->v4l2_dev;
+ vdev->queue = ¶ms_dev->vb2_vq;
+ vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT;
+ vdev->vfl_dir = VFL_DIR_TX;
+
+ /* Initialize vb2 queue */
+ q->type = V4L2_BUF_TYPE_META_OUTPUT;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = params_dev;
+ q->ops = &viif_params_vb2_ops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->buf_struct_size = sizeof(struct viif_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = ¶ms_dev->vlock;
+ q->dev = viif_dev->v4l2_dev.dev;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+
+ params_dev->params_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&vdev->entity, VIIF_PARAMS_PAD_NUM, ¶ms_dev->params_pad);
+ if (ret)
+ goto error;
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(¶ms_dev->vlock);
+
+ return ret;
+}
+
+void visconti_viif_params_unregister(struct viif_device *viif_dev)
+{
+ struct params_dev *params = &viif_dev->params_dev;
+ struct video_device *vdev = ¶ms->vdev;
+
+ if (!video_is_registered(vdev))
+ return;
+
+ vb2_video_unregister_device(vdev);
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(¶ms->vlock);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_params.h b/drivers/media/platform/toshiba/visconti/viif_params.h
new file mode 100644
index 0000000000..609c651c33
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_params.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_PARAMS_H
+#define VIIF_PARAMS_H
+
+struct viif_device;
+
+void visconti_viif_params_eval_queue(struct viif_device *viif_dev);
+void visconti_viif_params_isr(struct viif_device *viif_dev);
+int visconti_viif_params_register(struct viif_device *viif_dev);
+void visconti_viif_params_unregister(struct viif_device *viif_dev);
+
+int visconti_viif_l2_undist_through(struct viif_device *viif_dev);
+#endif /* VIIF_PARAMS_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.c b/drivers/media/platform/toshiba/visconti/viif_stats.c
new file mode 100644
index 0000000000..28cd879b5f
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "viif.h"
+#include "viif_csi2rx.h"
+#include "viif_isp.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+#include "viif_stats.h"
+
+struct viif_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head queue;
+};
+
+static void read_isp_capture_regs(struct viif_l1_info *l1_info, struct viif_device *viif_dev)
+{
+ unsigned long irqflags;
+ int i, j;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* change register buffer to regbuf0 where driver gets information */
+ viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0);
+
+ /* get AWB info */
+ l1_info->awb_ave_u = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_USIG);
+ l1_info->awb_ave_v = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_VSIG);
+ l1_info->awb_accumulated_pixel = viif_capture_read(viif_dev, REG_L1_AWHB_NUM_UVON);
+ l1_info->awb_gain_r = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINR);
+ l1_info->awb_gain_g = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAING);
+ l1_info->awb_gain_b = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINB);
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_R_CTR_STOP);
+ l1_info->awb_status_u = (FIELD_GET(BIT(1), val) != 0);
+ l1_info->awb_status_v = (FIELD_GET(BIT(0), val) != 0);
+
+ /* get average luminance info */
+ l1_info->avg_lum_weight = viif_capture_read(viif_dev, REG_L1_AEXP_RESULT_AVE);
+ val = viif_capture_read(viif_dev, REG_L1_AEXP_SATUR_BLACK_PIXNUM);
+ l1_info->avg_satur_pixnum = FIELD_GET(GENMASK(31, 16), val);
+ l1_info->avg_black_pixnum = FIELD_GET(GENMASK(15, 0), val);
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ l1_info->avg_lum_block[i][j] =
+ viif_capture_read(viif_dev, REG_L1_AEXP_AVE(i, j));
+ }
+ }
+ l1_info->avg_lum_four_line_lum[0] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES0);
+ l1_info->avg_lum_four_line_lum[1] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES1);
+ l1_info->avg_lum_four_line_lum[2] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES2);
+ l1_info->avg_lum_four_line_lum[3] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES3);
+
+ /* revert to register access from register buffer access */
+ viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+}
+
+static const struct viif_csi2rx_dphy_calibration_status calib_status_not_streaming = {
+ .term_cal_with_rext = -EAGAIN,
+ .clock_lane_offset_cal = -EAGAIN,
+ .data_lane0_offset_cal = -EAGAIN,
+ .data_lane1_offset_cal = -EAGAIN,
+ .data_lane2_offset_cal = -EAGAIN,
+ .data_lane3_offset_cal = -EAGAIN,
+ .data_lane0_ddl_tuning_cal = -EAGAIN,
+ .data_lane1_ddl_tuning_cal = -EAGAIN,
+ .data_lane2_ddl_tuning_cal = -EAGAIN,
+ .data_lane3_ddl_tuning_cal = -EAGAIN,
+};
+
+static const struct viif_csi2rx_err_status csi_err_not_streaming;
+
+void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp)
+{
+ struct visconti_viif_isp_stat *cur_stat_buf;
+ struct stats_dev *stats_dev = &viif_dev->stats_dev;
+ struct viif_buffer *cur_buf;
+
+ spin_lock(&stats_dev->stats_lock);
+
+ if (list_empty(&stats_dev->stats_queue))
+ goto done;
+
+ cur_buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
+ list_del(&cur_buf->queue);
+ cur_stat_buf = (struct visconti_viif_isp_stat *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
+
+ if (!vb2_start_streaming_called(&viif_dev->cap_dev0.vb2_vq)) {
+ cur_stat_buf->csi2rx_dphy_calibration = calib_status_not_streaming;
+ } else {
+ visconti_viif_csi2rx_get_calibration_status(viif_dev,
+ &cur_stat_buf->csi2rx_dphy_calibration);
+ }
+
+ if (!vb2_is_streaming(&viif_dev->cap_dev0.vb2_vq))
+ cur_stat_buf->csi2rx_err = csi_err_not_streaming;
+ else
+ visconti_viif_csi2rx_get_err_status(viif_dev, &cur_stat_buf->csi2rx_err);
+
+ read_isp_capture_regs(&cur_stat_buf->isp_capture.l1_info, viif_dev);
+
+ cur_stat_buf->errors.main = viif_dev->reported_err_main;
+ cur_stat_buf->errors.sub = viif_dev->reported_err_sub;
+ cur_stat_buf->errors.csi2rx = viif_dev->reported_err_csi2rx;
+ viif_dev->reported_err_main = 0;
+ viif_dev->reported_err_sub = 0;
+ viif_dev->reported_err_csi2rx = 0;
+
+ vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, sizeof(struct visconti_viif_isp_stat));
+
+ cur_buf->vb.sequence = sequence;
+ cur_buf->vb.vb2_buf.timestamp = timestamp;
+ vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+done:
+ spin_unlock(&stats_dev->stats_lock);
+}
+
+static int viif_stats_enum_fmt_meta_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (f->index > 0 || f->type != vdev->queue->type)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
+
+ return 0;
+}
+
+static int viif_stats_g_fmt_meta_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_meta_format *meta = &f->fmt.meta;
+
+ if (f->type != vdev->queue->type)
+ return -EINVAL;
+
+ memset(meta, 0, sizeof(*meta));
+ meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
+ meta->buffersize = sizeof(struct visconti_viif_isp_stat);
+
+ return 0;
+}
+
+static int viif_stats_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, vdev->name, sizeof(cap->card));
+ strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0", sizeof(cap->bus_info));
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops viif_stats_ioctl = {
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_enum_fmt_meta_cap = viif_stats_enum_fmt_meta_cap,
+ .vidioc_g_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+ .vidioc_s_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+ .vidioc_try_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
+ .vidioc_querycap = viif_stats_querycap,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations viif_stats_fops = { .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = vb2_fop_poll,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release };
+
+static int viif_stats_vb2_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ *num_planes = 1;
+ *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
+ sizes[0] = sizeof(struct visconti_viif_isp_stat);
+
+ return 0;
+}
+
+static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct viif_buffer, vb);
+}
+
+static inline struct stats_dev *vb2queue_to_statsdev(struct vb2_queue *q)
+{
+ return (struct stats_dev *)vb2_get_drv_priv(q);
+}
+
+static void viif_stats_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct stats_dev *stats_dev = vb2queue_to_statsdev(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct viif_buffer *buf = vb2_to_viif(vbuf);
+
+ spin_lock_irq(&stats_dev->stats_lock);
+ list_add_tail(&buf->queue, &stats_dev->stats_queue);
+ spin_unlock_irq(&stats_dev->stats_lock);
+}
+
+static int viif_stats_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_stat))
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_stat));
+
+ return 0;
+}
+
+static void viif_stats_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct stats_dev *stats_dev = vb2queue_to_statsdev(q);
+ struct viif_buffer *buf;
+ unsigned int i;
+
+ spin_lock_irq(&stats_dev->stats_lock);
+ for (i = 0; i < 8; i++) {
+ if (list_empty(&stats_dev->stats_queue))
+ break;
+ buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irq(&stats_dev->stats_lock);
+}
+
+static const struct vb2_ops viif_stats_vb2_ops = {
+ .queue_setup = viif_stats_vb2_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = viif_stats_vb2_buf_queue,
+ .buf_prepare = viif_stats_vb2_buf_prepare,
+ .stop_streaming = viif_stats_vb2_stop_streaming,
+};
+
+int visconti_viif_stats_register(struct viif_device *viif_dev)
+{
+ struct stats_dev *stats_dev = &viif_dev->stats_dev;
+ struct video_device *vdev = &stats_dev->vdev;
+ struct vb2_queue *q = &stats_dev->vb2_vq;
+ int ret;
+
+ mutex_init(&stats_dev->vlock);
+ INIT_LIST_HEAD(&stats_dev->stats_queue);
+ spin_lock_init(&stats_dev->stats_lock);
+
+ strscpy(vdev->name, "viif_stats", sizeof(vdev->name));
+
+ /* Register the video device */
+ video_set_drvdata(vdev, stats_dev);
+ vdev->ioctl_ops = &viif_stats_ioctl;
+ vdev->fops = &viif_stats_fops;
+ vdev->release = video_device_release_empty;
+ vdev->lock = &stats_dev->vlock;
+ vdev->v4l2_dev = &viif_dev->v4l2_dev;
+ vdev->queue = &stats_dev->vb2_vq;
+ vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
+ vdev->vfl_dir = VFL_DIR_RX;
+
+ /* Initialize vb2 queue */
+ q->type = V4L2_BUF_TYPE_META_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = stats_dev;
+ q->ops = &viif_stats_vb2_ops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->buf_struct_size = sizeof(struct viif_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &stats_dev->vlock;
+ q->dev = viif_dev->v4l2_dev.dev;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+
+ stats_dev->stats_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vdev->entity, VIIF_STATS_PAD_NUM, &stats_dev->stats_pad);
+ if (ret)
+ goto error;
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&stats_dev->vlock);
+
+ return ret;
+}
+
+void visconti_viif_stats_unregister(struct viif_device *viif_dev)
+{
+ struct stats_dev *stats_dev = &viif_dev->stats_dev;
+ struct video_device *vdev = &stats_dev->vdev;
+
+ if (!video_is_registered(vdev))
+ return;
+
+ vb2_video_unregister_device(vdev);
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&stats_dev->vlock);
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.h b/drivers/media/platform/toshiba/visconti/viif_stats.h
new file mode 100644
index 0000000000..3f778c58ef
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_stats.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_STATS_H
+#define VIIF_STATS_H
+
+void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp);
+int visconti_viif_stats_register(struct viif_device *viif_dev);
+void visconti_viif_stats_unregister(struct viif_device *viif_dev);
+#endif /* VIIF_STATS_H */
--
2.25.1
Added entries for visconti Video Input Interface driver, including;
* device tree bindings
* source files
* documentation files
Signed-off-by: Yuji Ishikawa <[email protected]>
Reviewed-by: Nobuhiro Iwamatsu <[email protected]>
---
Changelog v2:
- no change
Changelog v3:
- added entry for driver API documentation
Changelog v4:
- added entry for header file
Changelog v5:
- no change
Changelog v6:
- update path to VIIF driver source files
Changelog v7:
- no change
Changelog v8:
- rename bindings description file
Changelog v9:
- no change
Changelog v10:
- add a separate entry of VIIF driver
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index c23fda1aa1..411e708d06 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22408,6 +22408,17 @@ F: Documentation/devicetree/bindings/media/i2c/tc358743.txt
F: drivers/media/i2c/tc358743*
F: include/media/i2c/tc358743.h
+TOSHIBA VISCONTI VIIF DRIVER
+M: Nobuhiro Iwamatsu <[email protected]>
+M: Yuji Ishikawa <[email protected]>
+L: [email protected]
+S: Maintained
+F: Documentation/admin-guide/media/visconti-viif.*
+F: Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
+F: Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
+F: drivers/media/platform/toshiba/visconti/
+F: include/uapi/linux/visconti_viif.h
+
TOSHIBA WMI HOTKEYS DRIVER
M: Azael Avalos <[email protected]>
L: [email protected]
--
2.25.1
Adds the Toshiba Visconti VIIF specific metadata format
- V4L2_META_FMT_VISCONTI_VIIF_PARAMS for ISP parameters
- V4L2_META_FMT_VISCONTI_VIIF_STATS for ISP statistics
Signed-off-by: Yuji Ishikawa <[email protected]>
---
Changelog v10:
- add entry for V4L2_META_FMT_VISCONTI_VIIF_PARAMS
- add entry for V4L2_META_FMT_VISCONTI_VIIF_STATS
include/uapi/linux/videodev2.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index a8015e5e7f..686657e022 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -839,6 +839,10 @@ struct v4l2_pix_format {
#define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */
#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
+/* Vendor specific - used for Visconti VIIF sub-system */
+#define V4L2_META_FMT_VISCONTI_VIIF_PARAMS v4l2_fourcc('V', 'I', 'F', 'P') /* ISP Params */
+#define V4L2_META_FMT_VISCONTI_VIIF_STATS v4l2_fourcc('V', 'I', 'F', 'S') /* ISP Stats */
+
/* priv field value to indicates that subsequent fields are valid. */
#define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe
--
2.25.1
Hi Yuji,
Some small comments:
On 24/04/2024 04:42, Yuji Ishikawa wrote:
> Add support to Image Signal Processors of Visconti's Video Input Interface.
> This patch adds two streaming interfaces;
> one for passing parameters to the signal processor,
> the other for receiving status.
>
> Signed-off-by: Yuji Ishikawa <[email protected]>
> ---
> Changelog v2:
> - Resend v1 because a patch exceeds size limit.
>
> Changelog v3:
> - Adapted to media control framework
> - Introduced ISP subdevice, capture device
> - Remove private IOCTLs and add vendor specific V4L2 controls
> - Change function name avoiding camelcase and uppercase letters
>
> Changelog v4:
> - Split patches because the v3 patch exceeds size limit
> - Stop using ID number to identify driver instance:
> - Use dynamically allocated structure to hold HW specific context,
> instead of static one.
> - Call HW layer functions with the context structure instead of ID number
>
> Changelog v5:
> - no change
>
> Changelog v6:
> - remove unused macros
> - removed hwd_ and HWD_ prefix
> - update source code documentation
> - Suggestion from Hans Verkuil
> - pointer to userland memory is removed from uAPI arguments
> - style of structure is now "nested" instead of "chained by pointer";
> - use div64_u64 for 64bit division
> - vendor specific controls support TRY_EXT_CTRLS
> - add READ_ONLY flag to GET_CALIBRATION_STATUS control and similar ones
> - human friendry control names for vendor specific controls
> - add initial value to each vendor specific control
> - GET_LAST_CAPTURE_STATUS control is updated asyncnously from workqueue
> - remove EXECUTE_ON_WRITE flag of vendor specific control
> - uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
> - applied v4l2-compliance
> - Suggestion from Sakari Ailus
> - use div64_u64 for 64bit division
> - update copyright's year
> - remove redandunt cast
> - use bool instead of HWD_VIIF_ENABLE/DISABLE
> - simplify comparison to 0
> - simplify statements with trigram operator
> - remove redundant local variables
> - use general integer types instead of u32/s32
> - Suggestion from Laurent Pinchart
> - moved VIIF driver to driver/platform/toshiba/visconti
> - change register access: struct-style to macro-style
> - remove unused type definitions
> - define enums instead of successive macro constants
> - remove redundant parenthesis of macro constant
> - embed struct hwd_res into struct viif_device
> - use xxx_dma instead of xxx_paddr for variable names of IOVA
> - literal value: just 0 instead of 0x0
> - use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register access
> - use true or false instead of HWD_VIIF_ENABLE, DISABLE for function calls
> - uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
>
> Changelog v7:
> - remove unused variables
> - split long statements which have multiple logical-OR and trigram operators
>
> Changelog v8:
> - define constant V4L2_CTRL_TYPE_VISCONTI_ISP for datatype
> of Visconti specific controls
> - Suggestion from Hans Verkuil
> - remove pr_info()
> - use pm_runtime_get_if_in_use() to get power status
>
> Changelog v9:
> - fix warning for cast between ptr and dma_addr_t
>
> Changelog v10:
> - use parameter buffer instead of vendor specific compound controls
> - add viif_params interface for passing ISP parameters
> - add viif_stats interface for passing ISP status
> - remove parameter validation routine; moved to userland library
>
> .../media/platform/toshiba/visconti/Makefile | 2 +-
> .../media/platform/toshiba/visconti/viif.c | 28 +-
> .../platform/toshiba/visconti/viif_isp.c | 7 +
> .../platform/toshiba/visconti/viif_params.c | 2026 +++++++++++++++++
> .../platform/toshiba/visconti/viif_params.h | 19 +
> .../platform/toshiba/visconti/viif_stats.c | 334 +++
> .../platform/toshiba/visconti/viif_stats.h | 14 +
> 7 files changed, 2427 insertions(+), 3 deletions(-)
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h
>
<snip>
> diff --git a/drivers/media/platform/toshiba/visconti/viif_params.c b/drivers/media/platform/toshiba/visconti/viif_params.c
> new file mode 100644
> index 0000000000..5170d371c2
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/viif_params.c
> @@ -0,0 +1,2026 @@
<snip>
> +static const struct viif_l1_hdrc_config
> + defval_l1_set_hdrc = { .enable = 1,
> + .param = {
> + .hdrc_ratio = 0x0E + VIIF_L1_HDRC_RATIO_OFFSET,
> + .hdrc_pt_ratio = 7,
> + .hdrc_pt_sat = 0xFFC0,
> + .hdrc_tn_type = 1,
> + } };
Strange layout, can you write this like almost all other structs?
static const struct viif_l1_hdrc_config defval_l1_set_hdrc = {
.enable = 1,
.param = {
.hdrc_ratio = 0x0E + VIIF_L1_HDRC_RATIO_OFFSET,
.hdrc_pt_ratio = 7,
.hdrc_pt_sat = 0xFFC0,
.hdrc_tn_type = 1,
}
};
> +
> +static const struct viif_l1_hdrc_ltm_config defval_l1_set_hdrc_ltm = {
> + .tnp_max = 0x3FFFFF,
> + .tnp_mag = 0x40,
> + .tnp_fil = { 0x88, 0x84, 0x7A, 0x6A, 0x54 },
> +};
> +
> +static const struct viif_l1_gamma_config defval_l1_set_gamma = {
> + .enable = 1,
> + .param = {
> + .gam_p = {
> + 0x02F, 0x01B, 0x02A, 0x023, 0x020, 0x037, 0x031, 0x057, 0x04D, 0x088,
> + 0x078, 0x0D6, 0x0BD, 0x14F, 0x12A, 0x20D, 0x1D3, 0x1AB, 0x18D, 0x2DC,
> + 0x29E, 0x271, 0x47C, 0x41B, 0x3D4, 0x70A, 0x672, 0x601, 0xB0C, 0xA1D,
> + 0x96C, 0x8E2, 0x874, 0xFDD, 0xEC9, 0xDF2, 0xD42, 0xCB1, 0xC35, 0xBC9,
> + 0xB6A, 0xB16, 0xACB, 0xA86},
> + .blkadj = 0x1000,
> + },
> +};
> +
> +static const struct viif_l1_img_quality_adjustment_config defval_l1_set_img_quality_adjustment = {
> + .enable = 0,
> + .coef_cb = 0x9078,
> + .coef_cr = 0xB699,
> + .brightness = 0,
> + .linear_contrast = 128,
> +};
> +
> +static const struct viif_l1_avg_lum_generation_config defval_l1_set_avg_lum_generation = {
> + .enable = 0
> +};
> +
> +static const struct viif_l2_undist_config defval_l2_set_undist = { .param = {
> + .through_mode = 1,
> + .roi_mode = { 0, 0 },
> + .grid_node_num_h = 0x10,
> + .grid_node_num_v = 0x10,
> + } };
Another weird layout.
> +
> +static const struct viif_l2_roi_config defval_l2_set_roi = {
> + .roi_num = 1,
> + .roi_scale = { 65536, 65536 },
> + .roi_scale_inv = { 65536, 65536 },
> + .corrected_wo_scale_hsize = { 0x80, 0x80 },
> + .corrected_hsize = { 0x80, 0x80 },
> + .corrected_wo_scale_vsize = { 0x80, 0x80 },
> + .corrected_vsize = { 0x80, 0x80 },
> +};
> +
> +static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
> +
> +static void viif_apply_default_parameter(struct viif_device *viif_dev)
> +{
> + viif_l1_set_input_mode(viif_dev, &defval_l1_set_input_mode);
> + viif_l1_set_rgb_to_y_coef(viif_dev, &defval_l1_set_rgb_to_y_coef);
> + viif_l1_set_ag_mode(viif_dev, &defval_l1_set_ag_mode);
> + viif_l1_set_ag(viif_dev, &defval_l1_set_ag);
> + viif_l1_set_hdre(viif_dev, &defval_l1_set_hdre);
> + viif_l1_set_img_extraction(viif_dev, &defval_l1_set_img_extraction);
> + viif_l1_set_dpc(viif_dev, &defval_l1_set_dpc);
> + viif_l1_set_preset_white_balance(viif_dev, &defval_l1_set_preset_white_balance);
> + viif_l1_set_raw_color_noise_reduction(viif_dev, &defval_l1_set_raw_color_noise_reduction);
> + viif_l1_set_hdrs(viif_dev, &defval_l1_set_hdrs);
> + viif_l1_set_black_level_correction(viif_dev, &defval_l1_set_black_level_correction);
> + viif_l1_set_lsc(viif_dev, &defval_l1_set_lsc);
> + viif_l1_set_main_process(viif_dev, &defval_l1_set_main_process);
> + viif_l1_set_awb(viif_dev, &defval_l1_set_awb);
> + viif_l1_lock_awb_gain(viif_dev, &defval_l1_lock_awb_gain);
> + viif_l1_set_hdrc(viif_dev, &defval_l1_set_hdrc);
> + viif_l1_set_hdrc_ltm(viif_dev, &defval_l1_set_hdrc_ltm);
> + viif_l1_set_gamma(viif_dev, &defval_l1_set_gamma);
> + viif_l1_set_img_quality_adjustment(viif_dev, &defval_l1_set_img_quality_adjustment);
> + viif_l1_set_avg_lum_generation(viif_dev, &defval_l1_set_avg_lum_generation);
> + viif_l2_set_undist(viif_dev, &defval_l2_set_undist);
> + viif_l2_set_roi_wrap(viif_dev, &defval_l2_set_roi);
> + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &defval_l2_set_gamma);
> + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &defval_l2_set_gamma);
> +}
> +
> +/*=======================================================================*/
> +/* parameter buffer streaming interface */
> +/*=======================================================================*/
> +struct viif_buffer {
> + struct vb2_v4l2_buffer vb;
> + struct list_head queue;
> +};
> +
> +static bool viif_params_get_buffer(struct params_dev *params_dev, struct viif_buffer **buf,
> + struct visconti_viif_isp_config **cfg)
> +{
> + if (list_empty(¶ms_dev->params_queue))
> + return false;
> +
> + *buf = list_first_entry(¶ms_dev->params_queue, struct viif_buffer, queue);
> + *cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
> +
> + return true;
> +}
> +
> +static int viif_apply_queued_parameter(struct viif_device *viif_dev, bool initial_cfg)
> +{
> + struct params_dev *params_dev = &viif_dev->params_dev;
> + struct visconti_viif_isp_config *new_params;
> + struct viif_buffer *cur_buf;
> + int ret = 0;
> +
> + spin_lock(¶ms_dev->params_lock);
> +
> + if (!viif_params_get_buffer(params_dev, &cur_buf, &new_params)) {
> + ret = 1;
> + goto unlock;
> + }
> +
> + /* evaluate new_params */
> + if (initial_cfg) {
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_INPUT_MODE)
> + viif_l1_set_input_mode(viif_dev, &new_params->l1_input_mode);
> + }
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RGB_TO_Y_COEF)
> + viif_l1_set_rgb_to_y_coef(viif_dev, &new_params->l1_rgb_to_y_coef);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG_MODE)
> + viif_l1_set_ag_mode(viif_dev, &new_params->l1_ag_mode);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG)
> + viif_l1_set_ag(viif_dev, &new_params->l1_ag);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRE)
> + viif_l1_set_hdre(viif_dev, &new_params->l1_hdre);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_EXTRACTION)
> + viif_l1_set_img_extraction(viif_dev, &new_params->l1_img_extraction);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_DPC)
> + viif_l1_set_dpc(viif_dev, &new_params->l1_dpc);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_PRESET_WHITE_BALANCE)
> + viif_l1_set_preset_white_balance(viif_dev, &new_params->l1_preset_white_balance);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_RAW_COLOR_NOISE_REDUCTION)
> + viif_l1_set_raw_color_noise_reduction(viif_dev,
> + &new_params->l1_raw_color_noise_reduction);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRS)
> + viif_l1_set_hdrs(viif_dev, &new_params->l1_hdrs);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_BLACK_LEVEL_CORRECTION)
> + viif_l1_set_black_level_correction(viif_dev,
> + &new_params->l1_black_level_correction);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LSC)
> + viif_l1_set_lsc(viif_dev, &new_params->l1_lsc);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_MAIN_PROCESS)
> + viif_l1_set_main_process(viif_dev, &new_params->l1_main_process);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AWB)
> + viif_l1_set_awb(viif_dev, &new_params->l1_awb);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LOCK_AWB_GAIN)
> + viif_l1_lock_awb_gain(viif_dev, &new_params->lock_awb_gain);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC)
> + viif_l1_set_hdrc(viif_dev, &new_params->l1_hdrc);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC_LTM)
> + viif_l1_set_hdrc_ltm(viif_dev, &new_params->l1_hdrc_ltm);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_GAMMA)
> + viif_l1_set_gamma(viif_dev, &new_params->l1_gamma);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_IMG_QUALITY_ADJUSTMENT)
> + viif_l1_set_img_quality_adjustment(viif_dev,
> + &new_params->l1_img_quality_adjustment);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AVG_LUM_GENERATION)
> + viif_l1_set_avg_lum_generation(viif_dev, &new_params->l1_avg_lum_generation);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_UNDIST)
> + viif_l2_set_undist(viif_dev, &new_params->l2_undist);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_ROI)
> + viif_l2_set_roi_wrap(viif_dev, &new_params->l2_roi);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST0)
> + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0, &new_params->l2_gamma_post0);
> + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST1)
> + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1, &new_params->l2_gamma_post1);
> +
> + /* release buffer */
> + list_del(&cur_buf->queue);
> + cur_buf->vb.sequence = 0;
> + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +unlock:
> + spin_unlock(¶ms_dev->params_lock);
> + return ret;
> +}
> +
> +void visconti_viif_params_isr(struct viif_device *viif_dev)
> +{
> + viif_apply_queued_parameter(viif_dev, false);
> +}
> +
> +void visconti_viif_params_eval_queue(struct viif_device *viif_dev)
> +{
> + if (viif_apply_queued_parameter(viif_dev, true))
> + viif_apply_default_parameter(viif_dev);
> +}
> +
> +static int viif_params_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (f->index > 0 || f->type != vdev->queue->type)
> + return -EINVAL;
> +
> + f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
> +
> + return 0;
> +}
> +
> +static int viif_params_g_fmt_meta_out(struct file *file, void *fh, struct v4l2_format *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> + struct v4l2_meta_format *meta = &f->fmt.meta;
> +
> + if (f->type != vdev->queue->type)
> + return -EINVAL;
> +
> + memset(meta, 0, sizeof(*meta));
> + meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
> + meta->buffersize = sizeof(struct visconti_viif_isp_config);
> +
> + return 0;
> +}
> +
> +static int viif_params_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
> + strscpy(cap->card, vdev->name, sizeof(cap->card));
> + strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0", sizeof(cap->bus_info));
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops viif_params_ioctl = {
> + .vidioc_reqbufs = vb2_ioctl_reqbufs,
> + .vidioc_querybuf = vb2_ioctl_querybuf,
> + .vidioc_create_bufs = vb2_ioctl_create_bufs,
> + .vidioc_qbuf = vb2_ioctl_qbuf,
> + .vidioc_dqbuf = vb2_ioctl_dqbuf,
> + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> + .vidioc_expbuf = vb2_ioctl_expbuf,
> + .vidioc_streamon = vb2_ioctl_streamon,
> + .vidioc_streamoff = vb2_ioctl_streamoff,
> + .vidioc_enum_fmt_meta_out = viif_params_enum_fmt_meta_out,
> + .vidioc_g_fmt_meta_out = viif_params_g_fmt_meta_out,
> + .vidioc_s_fmt_meta_out = viif_params_g_fmt_meta_out,
> + .vidioc_try_fmt_meta_out = viif_params_g_fmt_meta_out,
> + .vidioc_querycap = viif_params_querycap,
> + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +};
> +
> +static const struct v4l2_file_operations viif_params_fops = { .mmap = vb2_fop_mmap,
> + .unlocked_ioctl = video_ioctl2,
> + .poll = vb2_fop_poll,
> + .open = v4l2_fh_open,
> + .release = vb2_fop_release };
Weird layout.
> +
> +static int viif_params_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
> + unsigned int *num_planes, unsigned int sizes[],
> + struct device *alloc_devs[])
> +{
> + *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
> + *num_planes = 1;
> + sizes[0] = sizeof(struct visconti_viif_isp_config);
> + return 0;
> +}
> +
> +static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
> +{
> + return container_of(vbuf, struct viif_buffer, vb);
> +}
> +
> +static inline struct params_dev *vb2queue_to_paramsdev(struct vb2_queue *vq)
> +{
> + return (struct params_dev *)vb2_get_drv_priv(vq);
> +}
> +
> +static void viif_params_vb2_buf_queue(struct vb2_buffer *vb)
> +{
> + struct params_dev *params_dev = vb2queue_to_paramsdev(vb->vb2_queue);
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct viif_buffer *buf = vb2_to_viif(vbuf);
> +
> + spin_lock_irq(¶ms_dev->params_lock);
> + list_add_tail(&buf->queue, ¶ms_dev->params_queue);
> + spin_unlock_irq(¶ms_dev->params_lock);
> +}
> +
> +static int viif_params_vb2_buf_prepare(struct vb2_buffer *vb)
> +{
> + if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_config))
> + return -EINVAL;
> +
> + vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_config));
> + return 0;
> +}
> +
> +static int viif_params_vb2_start_streaming(struct vb2_queue *q, unsigned int arg)
> +{
> + return 0;
> +}
> +
> +static void viif_params_vb2_stop_streaming(struct vb2_queue *q)
> +{
> + struct params_dev *params_dev = vb2queue_to_paramsdev(q);
> + struct viif_buffer *buf;
> + LIST_HEAD(tmp_list);
> +
> + spin_lock_irq(¶ms_dev->params_lock);
> + list_splice_init(¶ms_dev->params_queue, &tmp_list);
> + spin_unlock_irq(¶ms_dev->params_lock);
> +
> + list_for_each_entry(buf, &tmp_list, queue)
> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
> +}
> +
> +static const struct vb2_ops viif_params_vb2_ops = {
> + .queue_setup = viif_params_vb2_queue_setup,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
> + .buf_queue = viif_params_vb2_buf_queue,
> + .buf_prepare = viif_params_vb2_buf_prepare,
> + .start_streaming = viif_params_vb2_start_streaming,
> + .stop_streaming = viif_params_vb2_stop_streaming,
> +};
> +
> +int visconti_viif_params_register(struct viif_device *viif_dev)
> +{
> + struct params_dev *params_dev = &viif_dev->params_dev;
> + struct video_device *vdev = ¶ms_dev->vdev;
> + struct vb2_queue *q = ¶ms_dev->vb2_vq;
> + int ret;
> +
> + mutex_init(¶ms_dev->vlock);
> + INIT_LIST_HEAD(¶ms_dev->params_queue);
> + spin_lock_init(¶ms_dev->params_lock);
> +
> + strscpy(vdev->name, "viif_params", sizeof(vdev->name));
> +
> + /* Register the video device */
> + video_set_drvdata(vdev, params_dev);
> + vdev->ioctl_ops = &viif_params_ioctl;
> + vdev->fops = &viif_params_fops;
> + vdev->release = video_device_release_empty;
> + vdev->lock = ¶ms_dev->vlock;
> + vdev->v4l2_dev = &viif_dev->v4l2_dev;
> + vdev->queue = ¶ms_dev->vb2_vq;
> + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT;
> + vdev->vfl_dir = VFL_DIR_TX;
> +
> + /* Initialize vb2 queue */
> + q->type = V4L2_BUF_TYPE_META_OUTPUT;
> + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
Why do you want to support VB2_USERPTR? While not officially deprecated,
we do discourage it for new drivers.
> + q->drv_priv = params_dev;
> + q->ops = &viif_params_vb2_ops;
> + q->mem_ops = &vb2_vmalloc_memops;
> + q->buf_struct_size = sizeof(struct viif_buffer);
> + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> + q->lock = ¶ms_dev->vlock;
> + q->dev = viif_dev->v4l2_dev.dev;
> +
> + ret = vb2_queue_init(q);
> + if (ret)
> + return ret;
> +
> + params_dev->params_pad.flags = MEDIA_PAD_FL_SOURCE;
> + ret = media_entity_pads_init(&vdev->entity, VIIF_PARAMS_PAD_NUM, ¶ms_dev->params_pad);
> + if (ret)
> + goto error;
> +
> + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> + if (ret) {
> + dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
> + goto error;
> + }
> +
> + return 0;
> +
> +error:
> + media_entity_cleanup(&vdev->entity);
> + mutex_destroy(¶ms_dev->vlock);
> +
> + return ret;
> +}
> +
> +void visconti_viif_params_unregister(struct viif_device *viif_dev)
> +{
> + struct params_dev *params = &viif_dev->params_dev;
> + struct video_device *vdev = ¶ms->vdev;
> +
> + if (!video_is_registered(vdev))
> + return;
> +
> + vb2_video_unregister_device(vdev);
> + media_entity_cleanup(&vdev->entity);
> + mutex_destroy(¶ms->vlock);
> +}
<snip>
> diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.c b/drivers/media/platform/toshiba/visconti/viif_stats.c
> new file mode 100644
> index 0000000000..28cd879b5f
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/viif_stats.c
> @@ -0,0 +1,334 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> +/* Toshiba Visconti Video Capture Support
> + *
> + * (C) Copyright 2023 TOSHIBA CORPORATION
> + * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/pm_runtime.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/videobuf2-vmalloc.h>
> +
> +#include "viif.h"
> +#include "viif_csi2rx.h"
> +#include "viif_isp.h"
> +#include "viif_common.h"
> +#include "viif_regs.h"
> +#include "viif_stats.h"
> +
> +struct viif_buffer {
> + struct vb2_v4l2_buffer vb;
> + struct list_head queue;
> +};
> +
> +static void read_isp_capture_regs(struct viif_l1_info *l1_info, struct viif_device *viif_dev)
> +{
> + unsigned long irqflags;
> + int i, j;
> + u32 val;
> +
> + spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
> + hwd_viif_isp_guard_start(viif_dev);
> +
> + /* change register buffer to regbuf0 where driver gets information */
> + viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0);
> +
> + /* get AWB info */
> + l1_info->awb_ave_u = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_USIG);
> + l1_info->awb_ave_v = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_VSIG);
> + l1_info->awb_accumulated_pixel = viif_capture_read(viif_dev, REG_L1_AWHB_NUM_UVON);
> + l1_info->awb_gain_r = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINR);
> + l1_info->awb_gain_g = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAING);
> + l1_info->awb_gain_b = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINB);
> + val = viif_capture_read(viif_dev, REG_L1_AWHB_R_CTR_STOP);
> + l1_info->awb_status_u = (FIELD_GET(BIT(1), val) != 0);
> + l1_info->awb_status_v = (FIELD_GET(BIT(0), val) != 0);
> +
> + /* get average luminance info */
> + l1_info->avg_lum_weight = viif_capture_read(viif_dev, REG_L1_AEXP_RESULT_AVE);
> + val = viif_capture_read(viif_dev, REG_L1_AEXP_SATUR_BLACK_PIXNUM);
> + l1_info->avg_satur_pixnum = FIELD_GET(GENMASK(31, 16), val);
> + l1_info->avg_black_pixnum = FIELD_GET(GENMASK(15, 0), val);
> + for (i = 0; i < 8; i++) {
> + for (j = 0; j < 8; j++) {
> + l1_info->avg_lum_block[i][j] =
> + viif_capture_read(viif_dev, REG_L1_AEXP_AVE(i, j));
> + }
> + }
> + l1_info->avg_lum_four_line_lum[0] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES0);
> + l1_info->avg_lum_four_line_lum[1] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES1);
> + l1_info->avg_lum_four_line_lum[2] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES2);
> + l1_info->avg_lum_four_line_lum[3] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES3);
> +
> + /* revert to register access from register buffer access */
> + viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS);
> +
> + hwd_viif_isp_guard_end(viif_dev);
> + spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
> +}
> +
> +static const struct viif_csi2rx_dphy_calibration_status calib_status_not_streaming = {
> + .term_cal_with_rext = -EAGAIN,
> + .clock_lane_offset_cal = -EAGAIN,
> + .data_lane0_offset_cal = -EAGAIN,
> + .data_lane1_offset_cal = -EAGAIN,
> + .data_lane2_offset_cal = -EAGAIN,
> + .data_lane3_offset_cal = -EAGAIN,
> + .data_lane0_ddl_tuning_cal = -EAGAIN,
> + .data_lane1_ddl_tuning_cal = -EAGAIN,
> + .data_lane2_ddl_tuning_cal = -EAGAIN,
> + .data_lane3_ddl_tuning_cal = -EAGAIN,
> +};
> +
> +static const struct viif_csi2rx_err_status csi_err_not_streaming;
> +
> +void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp)
> +{
> + struct visconti_viif_isp_stat *cur_stat_buf;
> + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> + struct viif_buffer *cur_buf;
> +
> + spin_lock(&stats_dev->stats_lock);
> +
> + if (list_empty(&stats_dev->stats_queue))
> + goto done;
> +
> + cur_buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
> + list_del(&cur_buf->queue);
> + cur_stat_buf = (struct visconti_viif_isp_stat *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
> +
> + if (!vb2_start_streaming_called(&viif_dev->cap_dev0.vb2_vq)) {
> + cur_stat_buf->csi2rx_dphy_calibration = calib_status_not_streaming;
> + } else {
> + visconti_viif_csi2rx_get_calibration_status(viif_dev,
> + &cur_stat_buf->csi2rx_dphy_calibration);
> + }
> +
> + if (!vb2_is_streaming(&viif_dev->cap_dev0.vb2_vq))
> + cur_stat_buf->csi2rx_err = csi_err_not_streaming;
> + else
> + visconti_viif_csi2rx_get_err_status(viif_dev, &cur_stat_buf->csi2rx_err);
> +
> + read_isp_capture_regs(&cur_stat_buf->isp_capture.l1_info, viif_dev);
> +
> + cur_stat_buf->errors.main = viif_dev->reported_err_main;
> + cur_stat_buf->errors.sub = viif_dev->reported_err_sub;
> + cur_stat_buf->errors.csi2rx = viif_dev->reported_err_csi2rx;
> + viif_dev->reported_err_main = 0;
> + viif_dev->reported_err_sub = 0;
> + viif_dev->reported_err_csi2rx = 0;
> +
> + vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, sizeof(struct visconti_viif_isp_stat));
> +
> + cur_buf->vb.sequence = sequence;
> + cur_buf->vb.vb2_buf.timestamp = timestamp;
> + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +done:
> + spin_unlock(&stats_dev->stats_lock);
> +}
> +
> +static int viif_stats_enum_fmt_meta_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (f->index > 0 || f->type != vdev->queue->type)
> + return -EINVAL;
> +
> + f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
> +
> + return 0;
> +}
> +
> +static int viif_stats_g_fmt_meta_cap(struct file *file, void *priv, struct v4l2_format *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> + struct v4l2_meta_format *meta = &f->fmt.meta;
> +
> + if (f->type != vdev->queue->type)
> + return -EINVAL;
> +
> + memset(meta, 0, sizeof(*meta));
> + meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
> + meta->buffersize = sizeof(struct visconti_viif_isp_stat);
> +
> + return 0;
> +}
> +
> +static int viif_stats_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
> + strscpy(cap->card, vdev->name, sizeof(cap->card));
> + strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0", sizeof(cap->bus_info));
> +
> + return 0;
> +}
> +
> +static const struct v4l2_ioctl_ops viif_stats_ioctl = {
> + .vidioc_reqbufs = vb2_ioctl_reqbufs,
> + .vidioc_querybuf = vb2_ioctl_querybuf,
> + .vidioc_create_bufs = vb2_ioctl_create_bufs,
> + .vidioc_qbuf = vb2_ioctl_qbuf,
> + .vidioc_dqbuf = vb2_ioctl_dqbuf,
> + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> + .vidioc_expbuf = vb2_ioctl_expbuf,
> + .vidioc_streamon = vb2_ioctl_streamon,
> + .vidioc_streamoff = vb2_ioctl_streamoff,
> + .vidioc_enum_fmt_meta_cap = viif_stats_enum_fmt_meta_cap,
> + .vidioc_g_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> + .vidioc_s_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> + .vidioc_try_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> + .vidioc_querycap = viif_stats_querycap,
> + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> + .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
> +};
> +
> +static const struct v4l2_file_operations viif_stats_fops = { .mmap = vb2_fop_mmap,
> + .unlocked_ioctl = video_ioctl2,
> + .poll = vb2_fop_poll,
> + .open = v4l2_fh_open,
> + .release = vb2_fop_release };
Weird layout.
> +
> +static int viif_stats_vb2_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
> + unsigned int *num_planes, unsigned int sizes[],
> + struct device *alloc_devs[])
> +{
> + *num_planes = 1;
> + *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
> + sizes[0] = sizeof(struct visconti_viif_isp_stat);
> +
> + return 0;
> +}
> +
> +static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer *vbuf)
> +{
> + return container_of(vbuf, struct viif_buffer, vb);
> +}
> +
> +static inline struct stats_dev *vb2queue_to_statsdev(struct vb2_queue *q)
> +{
> + return (struct stats_dev *)vb2_get_drv_priv(q);
> +}
> +
> +static void viif_stats_vb2_buf_queue(struct vb2_buffer *vb)
> +{
> + struct stats_dev *stats_dev = vb2queue_to_statsdev(vb->vb2_queue);
> + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> + struct viif_buffer *buf = vb2_to_viif(vbuf);
> +
> + spin_lock_irq(&stats_dev->stats_lock);
> + list_add_tail(&buf->queue, &stats_dev->stats_queue);
> + spin_unlock_irq(&stats_dev->stats_lock);
> +}
> +
> +static int viif_stats_vb2_buf_prepare(struct vb2_buffer *vb)
> +{
> + if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_stat))
> + return -EINVAL;
> +
> + vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_stat));
> +
> + return 0;
> +}
> +
> +static void viif_stats_vb2_stop_streaming(struct vb2_queue *q)
> +{
> + struct stats_dev *stats_dev = vb2queue_to_statsdev(q);
> + struct viif_buffer *buf;
> + unsigned int i;
> +
> + spin_lock_irq(&stats_dev->stats_lock);
> + for (i = 0; i < 8; i++) {
> + if (list_empty(&stats_dev->stats_queue))
> + break;
> + buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer, queue);
> + list_del(&buf->queue);
> + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
> + }
> + spin_unlock_irq(&stats_dev->stats_lock);
> +}
> +
> +static const struct vb2_ops viif_stats_vb2_ops = {
> + .queue_setup = viif_stats_vb2_queue_setup,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
> + .buf_queue = viif_stats_vb2_buf_queue,
> + .buf_prepare = viif_stats_vb2_buf_prepare,
> + .stop_streaming = viif_stats_vb2_stop_streaming,
> +};
> +
> +int visconti_viif_stats_register(struct viif_device *viif_dev)
> +{
> + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> + struct video_device *vdev = &stats_dev->vdev;
> + struct vb2_queue *q = &stats_dev->vb2_vq;
> + int ret;
> +
> + mutex_init(&stats_dev->vlock);
> + INIT_LIST_HEAD(&stats_dev->stats_queue);
> + spin_lock_init(&stats_dev->stats_lock);
> +
> + strscpy(vdev->name, "viif_stats", sizeof(vdev->name));
> +
> + /* Register the video device */
> + video_set_drvdata(vdev, stats_dev);
> + vdev->ioctl_ops = &viif_stats_ioctl;
> + vdev->fops = &viif_stats_fops;
> + vdev->release = video_device_release_empty;
> + vdev->lock = &stats_dev->vlock;
> + vdev->v4l2_dev = &viif_dev->v4l2_dev;
> + vdev->queue = &stats_dev->vb2_vq;
> + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
> + vdev->vfl_dir = VFL_DIR_RX;
> +
> + /* Initialize vb2 queue */
> + q->type = V4L2_BUF_TYPE_META_CAPTURE;
> + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
Same question regarding VB2_USERPTR: do you really need this?
> + q->drv_priv = stats_dev;
> + q->ops = &viif_stats_vb2_ops;
> + q->mem_ops = &vb2_vmalloc_memops;
> + q->buf_struct_size = sizeof(struct viif_buffer);
> + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> + q->lock = &stats_dev->vlock;
> + q->dev = viif_dev->v4l2_dev.dev;
> +
> + ret = vb2_queue_init(q);
> + if (ret)
> + return ret;
> +
> + stats_dev->stats_pad.flags = MEDIA_PAD_FL_SINK;
> + ret = media_entity_pads_init(&vdev->entity, VIIF_STATS_PAD_NUM, &stats_dev->stats_pad);
> + if (ret)
> + goto error;
> +
> + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> + if (ret) {
> + dev_err(viif_dev->v4l2_dev.dev, "video_register_device failed: %d\n", ret);
> + goto error;
> + }
> +
> + return 0;
> +
> +error:
> + media_entity_cleanup(&vdev->entity);
> + mutex_destroy(&stats_dev->vlock);
> +
> + return ret;
> +}
> +
> +void visconti_viif_stats_unregister(struct viif_device *viif_dev)
> +{
> + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> + struct video_device *vdev = &stats_dev->vdev;
> +
> + if (!video_is_registered(vdev))
> + return;
> +
> + vb2_video_unregister_device(vdev);
> + media_entity_cleanup(&vdev->entity);
> + mutex_destroy(&stats_dev->vlock);
> +}
> diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.h b/drivers/media/platform/toshiba/visconti/viif_stats.h
> new file mode 100644
> index 0000000000..3f778c58ef
> --- /dev/null
> +++ b/drivers/media/platform/toshiba/visconti/viif_stats.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
> +/* Toshiba Visconti Video Capture Support
> + *
> + * (C) Copyright 2023 TOSHIBA CORPORATION
> + * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#ifndef VIIF_STATS_H
> +#define VIIF_STATS_H
> +
> +void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned int sequence, u64 timestamp);
> +int visconti_viif_stats_register(struct viif_device *viif_dev);
> +void visconti_viif_stats_unregister(struct viif_device *viif_dev);
> +#endif /* VIIF_STATS_H */
Regards,
Hans
Hi Yuji,
On 24/04/2024 04:42, Yuji Ishikawa wrote:
> This series is the Video Input Interface driver
> for Toshiba's ARM SoC, Visconti.
> This provides DT binding documentation,
> device driver, documentation and MAINTAINER files.
>
> A visconti VIIF driver instance exposes
> 1 media control device file, 3 video device files for capture
> and 2 video device files for controlling image signal processor.
> Detailed HW/SW are described in documentation directory.
> The VIIF hardware has CSI2 receiver,
> image signal processor and DMAC inside.
> The subdevice for image signal processor provides
> vendor specific V4L2 controls.
>
> The device driver depends on two other drivers under development;
> clock framework driver and IOMMU driver.
> Corresponding features will be added later.
>
> Best regards,
> Yuji
I commented on patches 3 and 4.
I also ran this series through my build scripts, and it did found a few small
warnings:
kerneldoc: WARNINGS:
drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct member 'subdevs' description in 'viif_device'
drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct member 'asds' description in 'viif_device'
drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct member 'sd' description in 'viif_device'
drivers/media/platform/toshiba/visconti/viif_common.h:30: warning: Function parameter or struct member 'bayer_pattern' not described in 'viif_mbus_format'
drivers/media/platform/toshiba/visconti/viif_common.h:30: warning: Function parameter or struct member 'is_bayer' not described in 'viif_mbus_format'
Should be trivial to fix.
Regards,
Hans
>
> Changelog v2:
> - Resend v1 because a patch exceeds size limit.
>
> Changelog v3:
> - Add documentation to describe SW and HW
> - Adapted to media control framework
> - Introduced ISP subdevice, capture device
> - Remove private IOCTLs and add vendor specific V4L2 controls
> - Change function name avoiding camelcase and uppercase letters
>
> Changelog v4:
> - Split patches because a patch exceeds size limit
> - fix dt-bindings document
> - stop specifying ID numbers for driver instance explicitly at device tree
> - use pm_runtime to trigger initialization of HW
> along with open/close of device files.
> - add a entry for a header file at MAINTAINERS file
>
> Changelog v5:
> - Fix coding style problem in viif.c (patch 2/6)
>
> Changelog v6:
> - add register definition of BUS-IF and MPU in dt-bindings
> - add CSI2RX subdevice (separeted from ISP subdevice)
> - change directory layout (moved to media/platform/toshiba/visconti)
> - change source file layout (removed hwd_xxxx.c)
> - pointer to userland memory is removed from uAPI parameters
> - change register access (from struct style to macro style)
> - remove unused macros
>
> Changelog v7:
> - remove redundant "bindings" from header and description text
> - fix multiline text of "description"
> - change "compatible" to "visconti5-viif"
> - explicitly define allowed properties for port::endpoint
> - remove unused variables
> - update kerneldoc comments
> - update references to headers
>
> Changelog v8:
> - rename bindings description file
> - remove/simplify items in bindings
> - update operations around v4l2_async_notifier
> - use v4l2_async_connection instead of v4l2_async_subdev
> - use dev_err_probe()
> - better error handling at probe
> - remove redundant mutex
> - add V4L2_CTRL_TYPE_VISCONTI_ISP constant
>
> Changelog v9:
> - dictionary ordering of dt-bindings properties
> - applied sparce checker
> - call div64_u64 for 64bit division
> - rebase to media_staging tree
> - fix warning for cast between ptr and dma_addr_t
>
> Changelog v10:
> - add an independent entry in MAINTAINERS
> - add paddings to uAPI structs
> - use parameter buffer to control ISP (instead of vendor specific controls)
>
> Yuji Ishikawa (6):
> dt-bindings: media: platform: visconti: Add Toshiba Visconti Video
> Input Interface
> media: videodev2.h: add visconti viif meta buffer format
> media: platform: visconti: Add Toshiba Visconti Video Input Interface
> driver
> media: platform: visconti: add streaming interface for ISP parameters
> and status
> documentation: media: add documentation for Toshiba Visconti Video
> Input Interface driver
> MAINTAINERS: Add entries for Toshiba Visconti Video Input Interface
>
> .../admin-guide/media/v4l-drivers.rst | 1 +
> .../admin-guide/media/visconti-viif.dot | 18 +
> .../admin-guide/media/visconti-viif.rst | 252 ++
> .../media/toshiba,visconti5-viif.yaml | 105 +
> .../userspace-api/media/v4l/meta-formats.rst | 1 +
> .../media/v4l/metafmt-visconti-viif.rst | 48 +
> MAINTAINERS | 11 +
> drivers/media/platform/Kconfig | 1 +
> drivers/media/platform/Makefile | 1 +
> drivers/media/platform/toshiba/Kconfig | 6 +
> drivers/media/platform/toshiba/Makefile | 2 +
> .../media/platform/toshiba/visconti/Kconfig | 19 +
> .../media/platform/toshiba/visconti/Makefile | 8 +
> .../media/platform/toshiba/visconti/viif.c | 664 ++++++
> .../media/platform/toshiba/visconti/viif.h | 398 ++++
> .../platform/toshiba/visconti/viif_capture.c | 1472 ++++++++++++
> .../platform/toshiba/visconti/viif_capture.h | 22 +
> .../platform/toshiba/visconti/viif_common.c | 239 ++
> .../platform/toshiba/visconti/viif_common.h | 40 +
> .../platform/toshiba/visconti/viif_csi2rx.c | 657 ++++++
> .../platform/toshiba/visconti/viif_csi2rx.h | 24 +
> .../toshiba/visconti/viif_csi2rx_regs.h | 102 +
> .../platform/toshiba/visconti/viif_isp.c | 1191 ++++++++++
> .../platform/toshiba/visconti/viif_isp.h | 24 +
> .../platform/toshiba/visconti/viif_params.c | 2026 +++++++++++++++++
> .../platform/toshiba/visconti/viif_params.h | 19 +
> .../platform/toshiba/visconti/viif_regs.h | 721 ++++++
> .../platform/toshiba/visconti/viif_stats.c | 334 +++
> .../platform/toshiba/visconti/viif_stats.h | 14 +
> include/uapi/linux/videodev2.h | 4 +
> include/uapi/linux/visconti_viif.h | 1921 ++++++++++++++++
> 31 files changed, 10345 insertions(+)
> create mode 100644 Documentation/admin-guide/media/visconti-viif.dot
> create mode 100644 Documentation/admin-guide/media/visconti-viif.rst
> create mode 100644 Documentation/devicetree/bindings/media/toshiba,visconti5-viif.yaml
> create mode 100644 Documentation/userspace-api/media/v4l/metafmt-visconti-viif.rst
> create mode 100644 drivers/media/platform/toshiba/Kconfig
> create mode 100644 drivers/media/platform/toshiba/Makefile
> create mode 100644 drivers/media/platform/toshiba/visconti/Kconfig
> create mode 100644 drivers/media/platform/toshiba/visconti/Makefile
> create mode 100644 drivers/media/platform/toshiba/visconti/viif.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_capture.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_common.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_csi2rx_regs.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_isp.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_params.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_regs.h
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.c
> create mode 100644 drivers/media/platform/toshiba/visconti/viif_stats.h
> create mode 100644 include/uapi/linux/visconti_viif.h
>
Hello Hans,
Thank you for your review.
> -----Original Message-----
> From: Hans Verkuil <[email protected]>
> Sent: Friday, May 31, 2024 8:02 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <[email protected]>; Laurent Pinchart
> <[email protected]>; Mauro Carvalho Chehab
> <[email protected]>; Rob Herring <[email protected]>; Krzysztof Kozlowski
> <[email protected]>; Conor Dooley <[email protected]>; Rafael J .
> Wysocki <[email protected]>; iwamatsu nobuhiro(岩松 信洋 ○DI
> TC□DIT○OST) <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]
> Subject: Re: [PATCH v10 0/6] Add Toshiba Visconti Video Input Interface driver
>
> Hi Yuji,
>
> On 24/04/2024 04:42, Yuji Ishikawa wrote:
> > This series is the Video Input Interface driver for Toshiba's ARM SoC,
> > Visconti.
> > This provides DT binding documentation, device driver, documentation
> > and MAINTAINER files.
> >
> > A visconti VIIF driver instance exposes
> > 1 media control device file, 3 video device files for capture and 2
> > video device files for controlling image signal processor.
> > Detailed HW/SW are described in documentation directory.
> > The VIIF hardware has CSI2 receiver,
> > image signal processor and DMAC inside.
> > The subdevice for image signal processor provides vendor specific V4L2
> > controls.
> >
> > The device driver depends on two other drivers under development;
> > clock framework driver and IOMMU driver.
> > Corresponding features will be added later.
> >
> > Best regards,
> > Yuji
>
> I commented on patches 3 and 4.
>
> I also ran this series through my build scripts, and it did found a few small
> warnings:
>
> kerneldoc: WARNINGS:
>
> drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct
> member 'subdevs' description in 'viif_device'
> drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct
> member 'asds' description in 'viif_device'
> drivers/media/platform/toshiba/visconti/viif.h:386: warning: Excess struct
> member 'sd' description in 'viif_device'
> drivers/media/platform/toshiba/visconti/viif_common.h:30: warning: Function
> parameter or struct member 'bayer_pattern' not described in 'viif_mbus_format'
> drivers/media/platform/toshiba/visconti/viif_common.h:30: warning: Function
> parameter or struct member 'is_bayer' not described in 'viif_mbus_format'
>
> Should be trivial to fix.
>
I'll fix kerneldoc comments.
> Regards,
>
> Hans
>
Best regards,
Yuji
Hello Hans,
Thank you for your review.
> -----Original Message-----
> From: Hans Verkuil <[email protected]>
> Sent: Friday, May 31, 2024 8:00 PM
> To: ishikawa yuji(石川 悠司 ○RDC□AITC○EA開)
> <[email protected]>; Laurent Pinchart
> <[email protected]>; Mauro Carvalho Chehab
> <[email protected]>; Rob Herring <[email protected]>; Krzysztof Kozlowski
> <[email protected]>; Conor Dooley <[email protected]>; Rafael J .
> Wysocki <[email protected]>; iwamatsu nobuhiro(岩松 信洋 ○DI
> TC□DIT○OST) <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]
> Subject: Re: [PATCH v10 4/6] media: platform: visconti: add streaming
> interface for ISP parameters and status
>
> Hi Yuji,
>
> Some small comments:
>
> On 24/04/2024 04:42, Yuji Ishikawa wrote:
> > Add support to Image Signal Processors of Visconti's Video Input Interface.
> > This patch adds two streaming interfaces; one for passing parameters
> > to the signal processor, the other for receiving status.
> >
> > Signed-off-by: Yuji Ishikawa <[email protected]>
> > ---
> > Changelog v2:
> > - Resend v1 because a patch exceeds size limit.
> >
> > Changelog v3:
> > - Adapted to media control framework
> > - Introduced ISP subdevice, capture device
> > - Remove private IOCTLs and add vendor specific V4L2 controls
> > - Change function name avoiding camelcase and uppercase letters
> >
> > Changelog v4:
> > - Split patches because the v3 patch exceeds size limit
> > - Stop using ID number to identify driver instance:
> > - Use dynamically allocated structure to hold HW specific context,
> > instead of static one.
> > - Call HW layer functions with the context structure instead of ID
> > number
> >
> > Changelog v5:
> > - no change
> >
> > Changelog v6:
> > - remove unused macros
> > - removed hwd_ and HWD_ prefix
> > - update source code documentation
> > - Suggestion from Hans Verkuil
> > - pointer to userland memory is removed from uAPI arguments
> > - style of structure is now "nested" instead of "chained by pointer";
> > - use div64_u64 for 64bit division
> > - vendor specific controls support TRY_EXT_CTRLS
> > - add READ_ONLY flag to GET_CALIBRATION_STATUS control and similar
> ones
> > - human friendry control names for vendor specific controls
> > - add initial value to each vendor specific control
> > - GET_LAST_CAPTURE_STATUS control is updated asyncnously from
> workqueue
> > - remove EXECUTE_ON_WRITE flag of vendor specific control
> > - uAPI: return value of GET_CALIBRATION_STATUS follows common rules
> of error codes
> > - applied v4l2-compliance
> > - Suggestion from Sakari Ailus
> > - use div64_u64 for 64bit division
> > - update copyright's year
> > - remove redandunt cast
> > - use bool instead of HWD_VIIF_ENABLE/DISABLE
> > - simplify comparison to 0
> > - simplify statements with trigram operator
> > - remove redundant local variables
> > - use general integer types instead of u32/s32
> > - Suggestion from Laurent Pinchart
> > - moved VIIF driver to driver/platform/toshiba/visconti
> > - change register access: struct-style to macro-style
> > - remove unused type definitions
> > - define enums instead of successive macro constants
> > - remove redundant parenthesis of macro constant
> > - embed struct hwd_res into struct viif_device
> > - use xxx_dma instead of xxx_paddr for variable names of IOVA
> > - literal value: just 0 instead of 0x0
> > - use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register
> access
> > - use true or false instead of HWD_VIIF_ENABLE, DISABLE for function
> calls
> > - uAPI: return value of GET_CALIBRATION_STATUS follows common rules
> > of error codes
> >
> > Changelog v7:
> > - remove unused variables
> > - split long statements which have multiple logical-OR and trigram
> > operators
> >
> > Changelog v8:
> > - define constant V4L2_CTRL_TYPE_VISCONTI_ISP for datatype
> > of Visconti specific controls
> > - Suggestion from Hans Verkuil
> > - remove pr_info()
> > - use pm_runtime_get_if_in_use() to get power status
> >
> > Changelog v9:
> > - fix warning for cast between ptr and dma_addr_t
> >
> > Changelog v10:
> > - use parameter buffer instead of vendor specific compound controls
> > - add viif_params interface for passing ISP parameters
> > - add viif_stats interface for passing ISP status
> > - remove parameter validation routine; moved to userland library
> >
> > .../media/platform/toshiba/visconti/Makefile | 2 +-
> > .../media/platform/toshiba/visconti/viif.c | 28 +-
> > .../platform/toshiba/visconti/viif_isp.c | 7 +
> > .../platform/toshiba/visconti/viif_params.c | 2026
> +++++++++++++++++
> > .../platform/toshiba/visconti/viif_params.h | 19 +
> > .../platform/toshiba/visconti/viif_stats.c | 334 +++
> > .../platform/toshiba/visconti/viif_stats.h | 14 +
> > 7 files changed, 2427 insertions(+), 3 deletions(-) create mode
> > 100644 drivers/media/platform/toshiba/visconti/viif_params.c
> > create mode 100644
> > drivers/media/platform/toshiba/visconti/viif_params.h
> > create mode 100644
> > drivers/media/platform/toshiba/visconti/viif_stats.c
> > create mode 100644
> > drivers/media/platform/toshiba/visconti/viif_stats.h
> >
>
> <snip>
>
> > diff --git a/drivers/media/platform/toshiba/visconti/viif_params.c
> > b/drivers/media/platform/toshiba/visconti/viif_params.c
> > new file mode 100644
> > index 0000000000..5170d371c2
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/viif_params.c
> > @@ -0,0 +1,2026 @@
>
> <snip>
>
> > +static const struct viif_l1_hdrc_config
> > + defval_l1_set_hdrc = { .enable = 1,
> > + .param = {
> > + .hdrc_ratio = 0x0E +
> VIIF_L1_HDRC_RATIO_OFFSET,
> > + .hdrc_pt_ratio = 7,
> > + .hdrc_pt_sat = 0xFFC0,
> > + .hdrc_tn_type = 1,
> > + } };
>
> Strange layout, can you write this like almost all other structs?
>
> static const struct viif_l1_hdrc_config defval_l1_set_hdrc = {
> .enable = 1,
> .param = {
> .hdrc_ratio = 0x0E + VIIF_L1_HDRC_RATIO_OFFSET,
> .hdrc_pt_ratio = 7,
> .hdrc_pt_sat = 0xFFC0,
> .hdrc_tn_type = 1,
> }
> };
>
I'll fix this strange layout as well as others.
Also I'll check settings of clang-format.
> > +
> > +static const struct viif_l1_hdrc_ltm_config defval_l1_set_hdrc_ltm = {
> > + .tnp_max = 0x3FFFFF,
> > + .tnp_mag = 0x40,
> > + .tnp_fil = { 0x88, 0x84, 0x7A, 0x6A, 0x54 }, };
> > +
> > +static const struct viif_l1_gamma_config defval_l1_set_gamma = {
> > + .enable = 1,
> > + .param = {
> > + .gam_p = {
> > + 0x02F, 0x01B, 0x02A, 0x023, 0x020, 0x037, 0x031,
> 0x057, 0x04D, 0x088,
> > + 0x078, 0x0D6, 0x0BD, 0x14F, 0x12A, 0x20D, 0x1D3,
> 0x1AB, 0x18D, 0x2DC,
> > + 0x29E, 0x271, 0x47C, 0x41B, 0x3D4, 0x70A, 0x672,
> 0x601, 0xB0C, 0xA1D,
> > + 0x96C, 0x8E2, 0x874, 0xFDD, 0xEC9, 0xDF2, 0xD42,
> 0xCB1, 0xC35, 0xBC9,
> > + 0xB6A, 0xB16, 0xACB, 0xA86},
> > + .blkadj = 0x1000,
> > + },
> > +};
> > +
> > +static const struct viif_l1_img_quality_adjustment_config
> defval_l1_set_img_quality_adjustment = {
> > + .enable = 0,
> > + .coef_cb = 0x9078,
> > + .coef_cr = 0xB699,
> > + .brightness = 0,
> > + .linear_contrast = 128,
> > +};
> > +
> > +static const struct viif_l1_avg_lum_generation_config
> defval_l1_set_avg_lum_generation = {
> > + .enable = 0
> > +};
> > +
> > +static const struct viif_l2_undist_config defval_l2_set_undist = { .param = {
> > +
> .through_mode = 1,
> > +
> .roi_mode = { 0, 0 },
> > +
> .grid_node_num_h = 0x10,
> > +
> .grid_node_num_v = 0x10,
> > + } };
>
> Another weird layout.
>
I'll fix the layout.
> > +
> > +static const struct viif_l2_roi_config defval_l2_set_roi = {
> > + .roi_num = 1,
> > + .roi_scale = { 65536, 65536 },
> > + .roi_scale_inv = { 65536, 65536 },
> > + .corrected_wo_scale_hsize = { 0x80, 0x80 },
> > + .corrected_hsize = { 0x80, 0x80 },
> > + .corrected_wo_scale_vsize = { 0x80, 0x80 },
> > + .corrected_vsize = { 0x80, 0x80 },
> > +};
> > +
> > +static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
> > +
> > +static void viif_apply_default_parameter(struct viif_device
> > +*viif_dev) {
> > + viif_l1_set_input_mode(viif_dev, &defval_l1_set_input_mode);
> > + viif_l1_set_rgb_to_y_coef(viif_dev, &defval_l1_set_rgb_to_y_coef);
> > + viif_l1_set_ag_mode(viif_dev, &defval_l1_set_ag_mode);
> > + viif_l1_set_ag(viif_dev, &defval_l1_set_ag);
> > + viif_l1_set_hdre(viif_dev, &defval_l1_set_hdre);
> > + viif_l1_set_img_extraction(viif_dev, &defval_l1_set_img_extraction);
> > + viif_l1_set_dpc(viif_dev, &defval_l1_set_dpc);
> > + viif_l1_set_preset_white_balance(viif_dev,
> &defval_l1_set_preset_white_balance);
> > + viif_l1_set_raw_color_noise_reduction(viif_dev,
> &defval_l1_set_raw_color_noise_reduction);
> > + viif_l1_set_hdrs(viif_dev, &defval_l1_set_hdrs);
> > + viif_l1_set_black_level_correction(viif_dev,
> &defval_l1_set_black_level_correction);
> > + viif_l1_set_lsc(viif_dev, &defval_l1_set_lsc);
> > + viif_l1_set_main_process(viif_dev, &defval_l1_set_main_process);
> > + viif_l1_set_awb(viif_dev, &defval_l1_set_awb);
> > + viif_l1_lock_awb_gain(viif_dev, &defval_l1_lock_awb_gain);
> > + viif_l1_set_hdrc(viif_dev, &defval_l1_set_hdrc);
> > + viif_l1_set_hdrc_ltm(viif_dev, &defval_l1_set_hdrc_ltm);
> > + viif_l1_set_gamma(viif_dev, &defval_l1_set_gamma);
> > + viif_l1_set_img_quality_adjustment(viif_dev,
> &defval_l1_set_img_quality_adjustment);
> > + viif_l1_set_avg_lum_generation(viif_dev,
> &defval_l1_set_avg_lum_generation);
> > + viif_l2_set_undist(viif_dev, &defval_l2_set_undist);
> > + viif_l2_set_roi_wrap(viif_dev, &defval_l2_set_roi);
> > + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0,
> &defval_l2_set_gamma);
> > + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1,
> > +&defval_l2_set_gamma); }
> > +
> >
> +/*===============================================
> ====================
> > +====*/
> > +/* parameter buffer streaming interface */
> >
> +/*===============================================
> ====================
> > +====*/
> > +struct viif_buffer {
> > + struct vb2_v4l2_buffer vb;
> > + struct list_head queue;
> > +};
> > +
> > +static bool viif_params_get_buffer(struct params_dev *params_dev, struct
> viif_buffer **buf,
> > + struct visconti_viif_isp_config **cfg) {
> > + if (list_empty(¶ms_dev->params_queue))
> > + return false;
> > +
> > + *buf = list_first_entry(¶ms_dev->params_queue, struct
> viif_buffer, queue);
> > + *cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0);
> > +
> > + return true;
> > +}
> > +
> > +static int viif_apply_queued_parameter(struct viif_device *viif_dev,
> > +bool initial_cfg) {
> > + struct params_dev *params_dev = &viif_dev->params_dev;
> > + struct visconti_viif_isp_config *new_params;
> > + struct viif_buffer *cur_buf;
> > + int ret = 0;
> > +
> > + spin_lock(¶ms_dev->params_lock);
> > +
> > + if (!viif_params_get_buffer(params_dev, &cur_buf, &new_params)) {
> > + ret = 1;
> > + goto unlock;
> > + }
> > +
> > + /* evaluate new_params */
> > + if (initial_cfg) {
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_INPUT_MODE)
> > + viif_l1_set_input_mode(viif_dev,
> &new_params->l1_input_mode);
> > + }
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_RGB_TO_Y_COEF)
> > + viif_l1_set_rgb_to_y_coef(viif_dev,
> &new_params->l1_rgb_to_y_coef);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_AG_MODE)
> > + viif_l1_set_ag_mode(viif_dev, &new_params->l1_ag_mode);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AG)
> > + viif_l1_set_ag(viif_dev, &new_params->l1_ag);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRE)
> > + viif_l1_set_hdre(viif_dev, &new_params->l1_hdre);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_IMG_EXTRACTION)
> > + viif_l1_set_img_extraction(viif_dev,
> &new_params->l1_img_extraction);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_DPC)
> > + viif_l1_set_dpc(viif_dev, &new_params->l1_dpc);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_PRESET_WHITE_BALANCE)
> > + viif_l1_set_preset_white_balance(viif_dev,
> &new_params->l1_preset_white_balance);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_RAW_COLOR_NOISE_REDUCTION)
> > + viif_l1_set_raw_color_noise_reduction(viif_dev,
> > +
> &new_params->l1_raw_color_noise_reduction);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRS)
> > + viif_l1_set_hdrs(viif_dev, &new_params->l1_hdrs);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_BLACK_LEVEL_CORRECTION)
> > + viif_l1_set_black_level_correction(viif_dev,
> > +
> &new_params->l1_black_level_correction);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_LSC)
> > + viif_l1_set_lsc(viif_dev, &new_params->l1_lsc);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_MAIN_PROCESS)
> > + viif_l1_set_main_process(viif_dev,
> &new_params->l1_main_process);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_AWB)
> > + viif_l1_set_awb(viif_dev, &new_params->l1_awb);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_LOCK_AWB_GAIN)
> > + viif_l1_lock_awb_gain(viif_dev,
> &new_params->lock_awb_gain);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_HDRC)
> > + viif_l1_set_hdrc(viif_dev, &new_params->l1_hdrc);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_HDRC_LTM)
> > + viif_l1_set_hdrc_ltm(viif_dev, &new_params->l1_hdrc_ltm);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L1_GAMMA)
> > + viif_l1_set_gamma(viif_dev, &new_params->l1_gamma);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_IMG_QUALITY_ADJUSTMENT)
> > + viif_l1_set_img_quality_adjustment(viif_dev,
> > +
> &new_params->l1_img_quality_adjustment);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L1_AVG_LUM_GENERATION)
> > + viif_l1_set_avg_lum_generation(viif_dev,
> &new_params->l1_avg_lum_generation);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_UNDIST)
> > + viif_l2_set_undist(viif_dev, &new_params->l2_undist);
> > + if (new_params->update_cfg & VISCONTI_VIIF_CFG_ISP_L2_ROI)
> > + viif_l2_set_roi_wrap(viif_dev, &new_params->l2_roi);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST0)
> > + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST0,
> &new_params->l2_gamma_post0);
> > + if (new_params->update_cfg &
> VISCONTI_VIIF_CFG_ISP_L2_GAMMA_POST1)
> > + viif_l2_set_gamma(viif_dev, CAPTURE_PATH_MAIN_POST1,
> > +&new_params->l2_gamma_post1);
> > +
> > + /* release buffer */
> > + list_del(&cur_buf->queue);
> > + cur_buf->vb.sequence = 0;
> > + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +
> > +unlock:
> > + spin_unlock(¶ms_dev->params_lock);
> > + return ret;
> > +}
> > +
> > +void visconti_viif_params_isr(struct viif_device *viif_dev) {
> > + viif_apply_queued_parameter(viif_dev, false); }
> > +
> > +void visconti_viif_params_eval_queue(struct viif_device *viif_dev) {
> > + if (viif_apply_queued_parameter(viif_dev, true))
> > + viif_apply_default_parameter(viif_dev);
> > +}
> > +
> > +static int viif_params_enum_fmt_meta_out(struct file *file, void
> > +*priv, struct v4l2_fmtdesc *f) {
> > + struct video_device *vdev = video_devdata(file);
> > +
> > + if (f->index > 0 || f->type != vdev->queue->type)
> > + return -EINVAL;
> > +
> > + f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
> > +
> > + return 0;
> > +}
> > +
> > +static int viif_params_g_fmt_meta_out(struct file *file, void *fh,
> > +struct v4l2_format *f) {
> > + struct video_device *vdev = video_devdata(file);
> > + struct v4l2_meta_format *meta = &f->fmt.meta;
> > +
> > + if (f->type != vdev->queue->type)
> > + return -EINVAL;
> > +
> > + memset(meta, 0, sizeof(*meta));
> > + meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_PARAMS;
> > + meta->buffersize = sizeof(struct visconti_viif_isp_config);
> > +
> > + return 0;
> > +}
> > +
> > +static int viif_params_querycap(struct file *file, void *priv, struct
> > +v4l2_capability *cap) {
> > + struct video_device *vdev = video_devdata(file);
> > +
> > + strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
> > + strscpy(cap->card, vdev->name, sizeof(cap->card));
> > + strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0",
> > +sizeof(cap->bus_info));
> > +
> > + return 0;
> > +}
> > +
> > +static const struct v4l2_ioctl_ops viif_params_ioctl = {
> > + .vidioc_reqbufs = vb2_ioctl_reqbufs,
> > + .vidioc_querybuf = vb2_ioctl_querybuf,
> > + .vidioc_create_bufs = vb2_ioctl_create_bufs,
> > + .vidioc_qbuf = vb2_ioctl_qbuf,
> > + .vidioc_dqbuf = vb2_ioctl_dqbuf,
> > + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> > + .vidioc_expbuf = vb2_ioctl_expbuf,
> > + .vidioc_streamon = vb2_ioctl_streamon,
> > + .vidioc_streamoff = vb2_ioctl_streamoff,
> > + .vidioc_enum_fmt_meta_out = viif_params_enum_fmt_meta_out,
> > + .vidioc_g_fmt_meta_out = viif_params_g_fmt_meta_out,
> > + .vidioc_s_fmt_meta_out = viif_params_g_fmt_meta_out,
> > + .vidioc_try_fmt_meta_out = viif_params_g_fmt_meta_out,
> > + .vidioc_querycap = viif_params_querycap,
> > + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> > + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, };
> > +
> > +static const struct v4l2_file_operations viif_params_fops = { .mmap =
> vb2_fop_mmap,
> > +
> .unlocked_ioctl = video_ioctl2,
> > + .poll =
> vb2_fop_poll,
> > + .open =
> v4l2_fh_open,
> > + .release =
> vb2_fop_release };
>
> Weird layout.
>
I'll fix the layout.
> > +
> > +static int viif_params_vb2_queue_setup(struct vb2_queue *q, unsigned int
> *num_buffers,
> > + unsigned int *num_planes, unsigned
> int sizes[],
> > + struct device *alloc_devs[]) {
> > + *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
> > + *num_planes = 1;
> > + sizes[0] = sizeof(struct visconti_viif_isp_config);
> > + return 0;
> > +}
> > +
> > +static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer
> > +*vbuf) {
> > + return container_of(vbuf, struct viif_buffer, vb); }
> > +
> > +static inline struct params_dev *vb2queue_to_paramsdev(struct
> > +vb2_queue *vq) {
> > + return (struct params_dev *)vb2_get_drv_priv(vq); }
> > +
> > +static void viif_params_vb2_buf_queue(struct vb2_buffer *vb) {
> > + struct params_dev *params_dev =
> vb2queue_to_paramsdev(vb->vb2_queue);
> > + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> > + struct viif_buffer *buf = vb2_to_viif(vbuf);
> > +
> > + spin_lock_irq(¶ms_dev->params_lock);
> > + list_add_tail(&buf->queue, ¶ms_dev->params_queue);
> > + spin_unlock_irq(¶ms_dev->params_lock);
> > +}
> > +
> > +static int viif_params_vb2_buf_prepare(struct vb2_buffer *vb) {
> > + if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_config))
> > + return -EINVAL;
> > +
> > + vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_config));
> > + return 0;
> > +}
> > +
> > +static int viif_params_vb2_start_streaming(struct vb2_queue *q,
> > +unsigned int arg) {
> > + return 0;
> > +}
> > +
> > +static void viif_params_vb2_stop_streaming(struct vb2_queue *q) {
> > + struct params_dev *params_dev = vb2queue_to_paramsdev(q);
> > + struct viif_buffer *buf;
> > + LIST_HEAD(tmp_list);
> > +
> > + spin_lock_irq(¶ms_dev->params_lock);
> > + list_splice_init(¶ms_dev->params_queue, &tmp_list);
> > + spin_unlock_irq(¶ms_dev->params_lock);
> > +
> > + list_for_each_entry(buf, &tmp_list, queue)
> > + vb2_buffer_done(&buf->vb.vb2_buf,
> VB2_BUF_STATE_ERROR); }
> > +
> > +static const struct vb2_ops viif_params_vb2_ops = {
> > + .queue_setup = viif_params_vb2_queue_setup,
> > + .wait_prepare = vb2_ops_wait_prepare,
> > + .wait_finish = vb2_ops_wait_finish,
> > + .buf_queue = viif_params_vb2_buf_queue,
> > + .buf_prepare = viif_params_vb2_buf_prepare,
> > + .start_streaming = viif_params_vb2_start_streaming,
> > + .stop_streaming = viif_params_vb2_stop_streaming, };
> > +
> > +int visconti_viif_params_register(struct viif_device *viif_dev) {
> > + struct params_dev *params_dev = &viif_dev->params_dev;
> > + struct video_device *vdev = ¶ms_dev->vdev;
> > + struct vb2_queue *q = ¶ms_dev->vb2_vq;
> > + int ret;
> > +
> > + mutex_init(¶ms_dev->vlock);
> > + INIT_LIST_HEAD(¶ms_dev->params_queue);
> > + spin_lock_init(¶ms_dev->params_lock);
> > +
> > + strscpy(vdev->name, "viif_params", sizeof(vdev->name));
> > +
> > + /* Register the video device */
> > + video_set_drvdata(vdev, params_dev);
> > + vdev->ioctl_ops = &viif_params_ioctl;
> > + vdev->fops = &viif_params_fops;
> > + vdev->release = video_device_release_empty;
> > + vdev->lock = ¶ms_dev->vlock;
> > + vdev->v4l2_dev = &viif_dev->v4l2_dev;
> > + vdev->queue = ¶ms_dev->vb2_vq;
> > + vdev->device_caps = V4L2_CAP_STREAMING |
> V4L2_CAP_META_OUTPUT;
> > + vdev->vfl_dir = VFL_DIR_TX;
> > +
> > + /* Initialize vb2 queue */
> > + q->type = V4L2_BUF_TYPE_META_OUTPUT;
> > + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
>
> Why do you want to support VB2_USERPTR? While not officially deprecated,
> we do discourage it for new drivers.
>
I'll remove VB2_USERPTR.
We do not have specific usecase of this flag for our driver.
> > + q->drv_priv = params_dev;
> > + q->ops = &viif_params_vb2_ops;
> > + q->mem_ops = &vb2_vmalloc_memops;
> > + q->buf_struct_size = sizeof(struct viif_buffer);
> > + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> > + q->lock = ¶ms_dev->vlock;
> > + q->dev = viif_dev->v4l2_dev.dev;
> > +
> > + ret = vb2_queue_init(q);
> > + if (ret)
> > + return ret;
> > +
> > + params_dev->params_pad.flags = MEDIA_PAD_FL_SOURCE;
> > + ret = media_entity_pads_init(&vdev->entity, VIIF_PARAMS_PAD_NUM,
> ¶ms_dev->params_pad);
> > + if (ret)
> > + goto error;
> > +
> > + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> > + if (ret) {
> > + dev_err(viif_dev->v4l2_dev.dev, "video_register_device
> failed: %d\n", ret);
> > + goto error;
> > + }
> > +
> > + return 0;
> > +
> > +error:
> > + media_entity_cleanup(&vdev->entity);
> > + mutex_destroy(¶ms_dev->vlock);
> > +
> > + return ret;
> > +}
> > +
> > +void visconti_viif_params_unregister(struct viif_device *viif_dev) {
> > + struct params_dev *params = &viif_dev->params_dev;
> > + struct video_device *vdev = ¶ms->vdev;
> > +
> > + if (!video_is_registered(vdev))
> > + return;
> > +
> > + vb2_video_unregister_device(vdev);
> > + media_entity_cleanup(&vdev->entity);
> > + mutex_destroy(¶ms->vlock);
> > +}
>
> <snip>
>
> > diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.c
> > b/drivers/media/platform/toshiba/visconti/viif_stats.c
> > new file mode 100644
> > index 0000000000..28cd879b5f
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/viif_stats.c
> > @@ -0,0 +1,334 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
> > +/* Toshiba Visconti Video Capture Support
> > + *
> > + * (C) Copyright 2023 TOSHIBA CORPORATION
> > + * (C) Copyright 2023 Toshiba Electronic Devices & Storage
> > +Corporation */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/pm_runtime.h>
> > +#include <media/v4l2-common.h>
> > +#include <media/v4l2-subdev.h>
> > +#include <media/videobuf2-vmalloc.h>
> > +
> > +#include "viif.h"
> > +#include "viif_csi2rx.h"
> > +#include "viif_isp.h"
> > +#include "viif_common.h"
> > +#include "viif_regs.h"
> > +#include "viif_stats.h"
> > +
> > +struct viif_buffer {
> > + struct vb2_v4l2_buffer vb;
> > + struct list_head queue;
> > +};
> > +
> > +static void read_isp_capture_regs(struct viif_l1_info *l1_info,
> > +struct viif_device *viif_dev) {
> > + unsigned long irqflags;
> > + int i, j;
> > + u32 val;
> > +
> > + spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
> > + hwd_viif_isp_guard_start(viif_dev);
> > +
> > + /* change register buffer to regbuf0 where driver gets information */
> > + viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF,
> > +VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0);
> > +
> > + /* get AWB info */
> > + l1_info->awb_ave_u = viif_capture_read(viif_dev,
> REG_L1_AWHB_AVE_USIG);
> > + l1_info->awb_ave_v = viif_capture_read(viif_dev,
> REG_L1_AWHB_AVE_VSIG);
> > + l1_info->awb_accumulated_pixel = viif_capture_read(viif_dev,
> REG_L1_AWHB_NUM_UVON);
> > + l1_info->awb_gain_r = viif_capture_read(viif_dev,
> REG_L1_AWHB_AWBGAINR);
> > + l1_info->awb_gain_g = viif_capture_read(viif_dev,
> REG_L1_AWHB_AWBGAING);
> > + l1_info->awb_gain_b = viif_capture_read(viif_dev,
> REG_L1_AWHB_AWBGAINB);
> > + val = viif_capture_read(viif_dev, REG_L1_AWHB_R_CTR_STOP);
> > + l1_info->awb_status_u = (FIELD_GET(BIT(1), val) != 0);
> > + l1_info->awb_status_v = (FIELD_GET(BIT(0), val) != 0);
> > +
> > + /* get average luminance info */
> > + l1_info->avg_lum_weight = viif_capture_read(viif_dev,
> REG_L1_AEXP_RESULT_AVE);
> > + val = viif_capture_read(viif_dev,
> REG_L1_AEXP_SATUR_BLACK_PIXNUM);
> > + l1_info->avg_satur_pixnum = FIELD_GET(GENMASK(31, 16), val);
> > + l1_info->avg_black_pixnum = FIELD_GET(GENMASK(15, 0), val);
> > + for (i = 0; i < 8; i++) {
> > + for (j = 0; j < 8; j++) {
> > + l1_info->avg_lum_block[i][j] =
> > + viif_capture_read(viif_dev,
> REG_L1_AEXP_AVE(i, j));
> > + }
> > + }
> > + l1_info->avg_lum_four_line_lum[0] = viif_capture_read(viif_dev,
> REG_L1_AEXP_AVE4LINES0);
> > + l1_info->avg_lum_four_line_lum[1] = viif_capture_read(viif_dev,
> REG_L1_AEXP_AVE4LINES1);
> > + l1_info->avg_lum_four_line_lum[2] = viif_capture_read(viif_dev,
> REG_L1_AEXP_AVE4LINES2);
> > + l1_info->avg_lum_four_line_lum[3] = viif_capture_read(viif_dev,
> > +REG_L1_AEXP_AVE4LINES3);
> > +
> > + /* revert to register access from register buffer access */
> > + viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF,
> > +VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS);
> > +
> > + hwd_viif_isp_guard_end(viif_dev);
> > + spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags); }
> > +
> > +static const struct viif_csi2rx_dphy_calibration_status
> calib_status_not_streaming = {
> > + .term_cal_with_rext = -EAGAIN,
> > + .clock_lane_offset_cal = -EAGAIN,
> > + .data_lane0_offset_cal = -EAGAIN,
> > + .data_lane1_offset_cal = -EAGAIN,
> > + .data_lane2_offset_cal = -EAGAIN,
> > + .data_lane3_offset_cal = -EAGAIN,
> > + .data_lane0_ddl_tuning_cal = -EAGAIN,
> > + .data_lane1_ddl_tuning_cal = -EAGAIN,
> > + .data_lane2_ddl_tuning_cal = -EAGAIN,
> > + .data_lane3_ddl_tuning_cal = -EAGAIN, };
> > +
> > +static const struct viif_csi2rx_err_status csi_err_not_streaming;
> > +
> > +void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned
> > +int sequence, u64 timestamp) {
> > + struct visconti_viif_isp_stat *cur_stat_buf;
> > + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> > + struct viif_buffer *cur_buf;
> > +
> > + spin_lock(&stats_dev->stats_lock);
> > +
> > + if (list_empty(&stats_dev->stats_queue))
> > + goto done;
> > +
> > + cur_buf = list_first_entry(&stats_dev->stats_queue, struct viif_buffer,
> queue);
> > + list_del(&cur_buf->queue);
> > + cur_stat_buf = (struct visconti_viif_isp_stat
> > +*)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0);
> > +
> > + if (!vb2_start_streaming_called(&viif_dev->cap_dev0.vb2_vq)) {
> > + cur_stat_buf->csi2rx_dphy_calibration =
> calib_status_not_streaming;
> > + } else {
> > + visconti_viif_csi2rx_get_calibration_status(viif_dev,
> > +
> &cur_stat_buf->csi2rx_dphy_calibration);
> > + }
> > +
> > + if (!vb2_is_streaming(&viif_dev->cap_dev0.vb2_vq))
> > + cur_stat_buf->csi2rx_err = csi_err_not_streaming;
> > + else
> > + visconti_viif_csi2rx_get_err_status(viif_dev,
> > +&cur_stat_buf->csi2rx_err);
> > +
> > + read_isp_capture_regs(&cur_stat_buf->isp_capture.l1_info, viif_dev);
> > +
> > + cur_stat_buf->errors.main = viif_dev->reported_err_main;
> > + cur_stat_buf->errors.sub = viif_dev->reported_err_sub;
> > + cur_stat_buf->errors.csi2rx = viif_dev->reported_err_csi2rx;
> > + viif_dev->reported_err_main = 0;
> > + viif_dev->reported_err_sub = 0;
> > + viif_dev->reported_err_csi2rx = 0;
> > +
> > + vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, sizeof(struct
> > +visconti_viif_isp_stat));
> > +
> > + cur_buf->vb.sequence = sequence;
> > + cur_buf->vb.vb2_buf.timestamp = timestamp;
> > + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +
> > +done:
> > + spin_unlock(&stats_dev->stats_lock);
> > +}
> > +
> > +static int viif_stats_enum_fmt_meta_cap(struct file *file, void
> > +*priv, struct v4l2_fmtdesc *f) {
> > + struct video_device *vdev = video_devdata(file);
> > +
> > + if (f->index > 0 || f->type != vdev->queue->type)
> > + return -EINVAL;
> > +
> > + f->pixelformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
> > +
> > + return 0;
> > +}
> > +
> > +static int viif_stats_g_fmt_meta_cap(struct file *file, void *priv,
> > +struct v4l2_format *f) {
> > + struct video_device *vdev = video_devdata(file);
> > + struct v4l2_meta_format *meta = &f->fmt.meta;
> > +
> > + if (f->type != vdev->queue->type)
> > + return -EINVAL;
> > +
> > + memset(meta, 0, sizeof(*meta));
> > + meta->dataformat = V4L2_META_FMT_VISCONTI_VIIF_STATS;
> > + meta->buffersize = sizeof(struct visconti_viif_isp_stat);
> > +
> > + return 0;
> > +}
> > +
> > +static int viif_stats_querycap(struct file *file, void *priv, struct
> > +v4l2_capability *cap) {
> > + struct video_device *vdev = video_devdata(file);
> > +
> > + strscpy(cap->driver, VIIF_DRIVER_NAME, sizeof(cap->driver));
> > + strscpy(cap->card, vdev->name, sizeof(cap->card));
> > + strscpy(cap->bus_info, VIIF_BUS_INFO_BASE "-0",
> > +sizeof(cap->bus_info));
> > +
> > + return 0;
> > +}
> > +
> > +static const struct v4l2_ioctl_ops viif_stats_ioctl = {
> > + .vidioc_reqbufs = vb2_ioctl_reqbufs,
> > + .vidioc_querybuf = vb2_ioctl_querybuf,
> > + .vidioc_create_bufs = vb2_ioctl_create_bufs,
> > + .vidioc_qbuf = vb2_ioctl_qbuf,
> > + .vidioc_dqbuf = vb2_ioctl_dqbuf,
> > + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> > + .vidioc_expbuf = vb2_ioctl_expbuf,
> > + .vidioc_streamon = vb2_ioctl_streamon,
> > + .vidioc_streamoff = vb2_ioctl_streamoff,
> > + .vidioc_enum_fmt_meta_cap = viif_stats_enum_fmt_meta_cap,
> > + .vidioc_g_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> > + .vidioc_s_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> > + .vidioc_try_fmt_meta_cap = viif_stats_g_fmt_meta_cap,
> > + .vidioc_querycap = viif_stats_querycap,
> > + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> > + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, };
> > +
> > +static const struct v4l2_file_operations viif_stats_fops = { .mmap =
> vb2_fop_mmap,
> > + .unlocked_ioctl
> = video_ioctl2,
> > + .poll =
> vb2_fop_poll,
> > + .open =
> v4l2_fh_open,
> > + .release =
> vb2_fop_release };
>
> Weird layout.
>
I'll fix the layout.
> > +
> > +static int viif_stats_vb2_queue_setup(struct vb2_queue *vq, unsigned int
> *num_buffers,
> > + unsigned int *num_planes, unsigned
> int sizes[],
> > + struct device *alloc_devs[]) {
> > + *num_planes = 1;
> > + *num_buffers = clamp_t(u32, *num_buffers, 2, 8);
> > + sizes[0] = sizeof(struct visconti_viif_isp_stat);
> > +
> > + return 0;
> > +}
> > +
> > +static inline struct viif_buffer *vb2_to_viif(struct vb2_v4l2_buffer
> > +*vbuf) {
> > + return container_of(vbuf, struct viif_buffer, vb); }
> > +
> > +static inline struct stats_dev *vb2queue_to_statsdev(struct vb2_queue
> > +*q) {
> > + return (struct stats_dev *)vb2_get_drv_priv(q); }
> > +
> > +static void viif_stats_vb2_buf_queue(struct vb2_buffer *vb) {
> > + struct stats_dev *stats_dev = vb2queue_to_statsdev(vb->vb2_queue);
> > + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> > + struct viif_buffer *buf = vb2_to_viif(vbuf);
> > +
> > + spin_lock_irq(&stats_dev->stats_lock);
> > + list_add_tail(&buf->queue, &stats_dev->stats_queue);
> > + spin_unlock_irq(&stats_dev->stats_lock);
> > +}
> > +
> > +static int viif_stats_vb2_buf_prepare(struct vb2_buffer *vb) {
> > + if (vb2_plane_size(vb, 0) < sizeof(struct visconti_viif_isp_stat))
> > + return -EINVAL;
> > +
> > + vb2_set_plane_payload(vb, 0, sizeof(struct visconti_viif_isp_stat));
> > +
> > + return 0;
> > +}
> > +
> > +static void viif_stats_vb2_stop_streaming(struct vb2_queue *q) {
> > + struct stats_dev *stats_dev = vb2queue_to_statsdev(q);
> > + struct viif_buffer *buf;
> > + unsigned int i;
> > +
> > + spin_lock_irq(&stats_dev->stats_lock);
> > + for (i = 0; i < 8; i++) {
> > + if (list_empty(&stats_dev->stats_queue))
> > + break;
> > + buf = list_first_entry(&stats_dev->stats_queue, struct
> viif_buffer, queue);
> > + list_del(&buf->queue);
> > + vb2_buffer_done(&buf->vb.vb2_buf,
> VB2_BUF_STATE_ERROR);
> > + }
> > + spin_unlock_irq(&stats_dev->stats_lock);
> > +}
> > +
> > +static const struct vb2_ops viif_stats_vb2_ops = {
> > + .queue_setup = viif_stats_vb2_queue_setup,
> > + .wait_prepare = vb2_ops_wait_prepare,
> > + .wait_finish = vb2_ops_wait_finish,
> > + .buf_queue = viif_stats_vb2_buf_queue,
> > + .buf_prepare = viif_stats_vb2_buf_prepare,
> > + .stop_streaming = viif_stats_vb2_stop_streaming, };
> > +
> > +int visconti_viif_stats_register(struct viif_device *viif_dev) {
> > + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> > + struct video_device *vdev = &stats_dev->vdev;
> > + struct vb2_queue *q = &stats_dev->vb2_vq;
> > + int ret;
> > +
> > + mutex_init(&stats_dev->vlock);
> > + INIT_LIST_HEAD(&stats_dev->stats_queue);
> > + spin_lock_init(&stats_dev->stats_lock);
> > +
> > + strscpy(vdev->name, "viif_stats", sizeof(vdev->name));
> > +
> > + /* Register the video device */
> > + video_set_drvdata(vdev, stats_dev);
> > + vdev->ioctl_ops = &viif_stats_ioctl;
> > + vdev->fops = &viif_stats_fops;
> > + vdev->release = video_device_release_empty;
> > + vdev->lock = &stats_dev->vlock;
> > + vdev->v4l2_dev = &viif_dev->v4l2_dev;
> > + vdev->queue = &stats_dev->vb2_vq;
> > + vdev->device_caps = V4L2_CAP_META_CAPTURE |
> V4L2_CAP_STREAMING;
> > + vdev->vfl_dir = VFL_DIR_RX;
> > +
> > + /* Initialize vb2 queue */
> > + q->type = V4L2_BUF_TYPE_META_CAPTURE;
> > + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
>
> Same question regarding VB2_USERPTR: do you really need this?
>
I'll remove VB2_USERPTR.
> > + q->drv_priv = stats_dev;
> > + q->ops = &viif_stats_vb2_ops;
> > + q->mem_ops = &vb2_vmalloc_memops;
> > + q->buf_struct_size = sizeof(struct viif_buffer);
> > + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> > + q->lock = &stats_dev->vlock;
> > + q->dev = viif_dev->v4l2_dev.dev;
> > +
> > + ret = vb2_queue_init(q);
> > + if (ret)
> > + return ret;
> > +
> > + stats_dev->stats_pad.flags = MEDIA_PAD_FL_SINK;
> > + ret = media_entity_pads_init(&vdev->entity, VIIF_STATS_PAD_NUM,
> &stats_dev->stats_pad);
> > + if (ret)
> > + goto error;
> > +
> > + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> > + if (ret) {
> > + dev_err(viif_dev->v4l2_dev.dev, "video_register_device
> failed: %d\n", ret);
> > + goto error;
> > + }
> > +
> > + return 0;
> > +
> > +error:
> > + media_entity_cleanup(&vdev->entity);
> > + mutex_destroy(&stats_dev->vlock);
> > +
> > + return ret;
> > +}
> > +
> > +void visconti_viif_stats_unregister(struct viif_device *viif_dev) {
> > + struct stats_dev *stats_dev = &viif_dev->stats_dev;
> > + struct video_device *vdev = &stats_dev->vdev;
> > +
> > + if (!video_is_registered(vdev))
> > + return;
> > +
> > + vb2_video_unregister_device(vdev);
> > + media_entity_cleanup(&vdev->entity);
> > + mutex_destroy(&stats_dev->vlock);
> > +}
> > diff --git a/drivers/media/platform/toshiba/visconti/viif_stats.h
> > b/drivers/media/platform/toshiba/visconti/viif_stats.h
> > new file mode 100644
> > index 0000000000..3f778c58ef
> > --- /dev/null
> > +++ b/drivers/media/platform/toshiba/visconti/viif_stats.h
> > @@ -0,0 +1,14 @@
> > +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
> > +/* Toshiba Visconti Video Capture Support
> > + *
> > + * (C) Copyright 2023 TOSHIBA CORPORATION
> > + * (C) Copyright 2023 Toshiba Electronic Devices & Storage
> > +Corporation */
> > +
> > +#ifndef VIIF_STATS_H
> > +#define VIIF_STATS_H
> > +
> > +void visconti_viif_stats_isr(struct viif_device *viif_dev, unsigned
> > +int sequence, u64 timestamp); int visconti_viif_stats_register(struct
> > +viif_device *viif_dev); void visconti_viif_stats_unregister(struct
> > +viif_device *viif_dev); #endif /* VIIF_STATS_H */
>
> Regards,
>
> Hans
Best Regards,
Yuji