[PATCH v2 8/8] media: qcom: camss: vfe: Add support for VFE 1190
Nihal Kumar Gupta
nihal.gupta at oss.qualcomm.com
Tue Oct 13 04:02:50 PDT 2026
From: Hangxiang Ma <hangxiang.ma at oss.qualcomm.com>
Add support for the Video Front End (VFE) 1190 found on Hawi SoC.
In the Hawi camera subsystem, the front-end blocks are referred to as
TFEs (Thin Front Ends). This driver continues to use the VFE naming in
some places to preserve consistency with the existing code and avoid
unnecessary renaming. Support is currently limited to three output
lines, matching the constraints of the CAMSS framework.
Signed-off-by: Hangxiang Ma <hangxiang.ma at oss.qualcomm.com>
Signed-off-by: Nihal Kumar Gupta <nihal.gupta at oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/Makefile | 1 +
drivers/media/platform/qcom/camss/camss-vfe-1190.c | 200 +++++++++++++++++++++
drivers/media/platform/qcom/camss/camss-vfe.c | 2 +
drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
drivers/media/platform/qcom/camss/camss.c | 151 ++++++++++++++++
5 files changed, 355 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index d62f978991aab5f5339207b709a2ab018f3759aa..e48df14933fa0e2b1910de5e68bec0b5c57dd1b2 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -28,6 +28,7 @@ qcom-camss-objs += \
camss-vfe-480.o \
camss-vfe-680.o \
camss-vfe-1080.o \
+ camss-vfe-1190.o \
camss-vfe-gen1.o \
camss-vfe-gen3.o \
camss-vfe-vbif.o \
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-1190.c b/drivers/media/platform/qcom/camss/camss-vfe-1190.c
new file mode 100644
index 0000000000000000000000000000000000000000..f331c6f2e7a5da7dfb1a6acf86f2e19f4c352513
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-1190.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-1190.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module 1190
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+
+/* VFE-1190 Bus Register Base Addresses */
+#define BUS_REG_BASE (0x800)
+#define BUS_REG_OFFSET(n) (0x1000 + (n) * 0x200)
+
+#define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x4)
+#define WM_CGC_OVERRIDE_ALL (0x7FFFFFF)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0x144)
+
+#define VFE_BUS_WM_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n))
+#define WM_CFG_EN BIT(0)
+#define WM_VIR_FRM_EN BIT(1)
+#define WM_CFG_MODE BIT(16)
+#define VFE_BUS_WM_IMAGE_ADDR(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x4)
+#define VFE_BUS_WM_FRAME_INCR(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x8)
+#define VFE_BUS_WM_IMAGE_CFG_0(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0xC)
+#define WM_IMAGE_CFG_0_DEFAULT_WIDTH (0xFFFF)
+#define VFE_BUS_WM_IMAGE_CFG_2(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x14)
+#define WM_IMAGE_CFG_2_DEFAULT_STRIDE (0xFFFF)
+#define VFE_BUS_WM_PACKER_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x18)
+
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x30)
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x34)
+
+/* VFE lite has no such registers */
+#define VFE_BUS_WM_FRAMEDROP_PERIOD(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x38)
+#define VFE_BUS_WM_FRAMEDROP_PATTERN(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x3C)
+
+#define VFE_BUS_WM_MMU_PREFETCH_CFG(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x64)
+#define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n) (BUS_REG_BASE + BUS_REG_OFFSET(n) + 0x68)
+
+/*
+ * VFE 1190 write master client IDs
+ *
+ * VIDEO_FULL_Y 0
+ * VIDEO_FULL_UV 1
+ * VIDEO_DC4_Y 2
+ * VIDEO_DC4_C 3
+ * VIDEO_DC16_Y 4
+ * VIDEO_DC16_C 5
+ * FD_Y 6
+ * FD_C 7
+ * RAW_OUT 8
+ * STATS_AEC_BG 9
+ * STATS_AEC_BHIST 10
+ * STATS_TINTLESS_BG 11
+ * STATS_AWB_BG 12
+ * STATS_AWB_BFW 13
+ * STATS_AF_BHIST 14
+ * STATS_ALSC_BG 15
+ * STATS_FLICKER_BAYERRS 16
+ * STATS_TMC_BHIST 17
+ * PDAF_0 18
+ * PDAF_1 19
+ * PDAF_2 20
+ * PDAF_3 21
+ * PDAF_4 22
+ * RDI0 23
+ * RDI1 24
+ * RDI2 25
+ * RDI3 26
+ * RDI4 27
+ * C2PA Y 28
+ * C2PA C 29
+ *
+ * VFE Lite 1190 write master client IDs
+ *
+ * RDI0 0
+ * RDI1 1
+ * RDI2 2
+ * RDI3 3
+ * GAMMA 4
+ * STATES_BG 5
+ */
+#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))
+
+static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+{
+ struct v4l2_pix_format_mplane *pix =
+ &line->video_out.active_fmt.fmt.pix_mp;
+
+ wm = RDI_WM(wm);
+
+ /* no clock gating at bus input */
+ writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
+
+ writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+ writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
+ vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
+ writel((WM_IMAGE_CFG_0_DEFAULT_WIDTH & 0xFFFF),
+ vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
+ writel(WM_IMAGE_CFG_2_DEFAULT_STRIDE,
+ vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
+ writel(0, vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
+
+ /* no dropped frames, one irq per frame */
+ if (!vfe_is_lite(vfe)) {
+ writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
+ writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
+ }
+
+ writel(0, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(wm));
+ writel(1, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(wm));
+
+ writel(1, vfe->base + VFE_BUS_WM_MMU_PREFETCH_CFG(wm));
+ writel(0xFFFFFFFF, vfe->base + VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(wm));
+
+ writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+{
+ wm = RDI_WM(wm);
+ writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+ struct vfe_line *line)
+{
+ wm = RDI_WM(wm);
+ writel(addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+
+ dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n", wm, addr);
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_reg_update(vfe->camss, vfe->id, port_id, false);
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+ enum vfe_line_id line_id)
+{
+ int port_id = line_id;
+
+ camss_reg_update(vfe->camss, vfe->id, port_id, true);
+}
+
+static const struct camss_video_ops vfe_video_ops_1190 = {
+ .queue_buffer = vfe_queue_buffer_v2,
+ .flush_buffers = vfe_flush_buffers,
+};
+
+static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
+{
+ vfe->video_ops = vfe_video_ops_1190;
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+ vfe_isr_reset_ack(vfe);
+}
+
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+ /* nop */
+ return IRQ_HANDLED;
+}
+
+static int vfe_halt(struct vfe_device *vfe)
+{
+ /* rely on vfe_disable_output() to stop the VFE */
+ return 0;
+}
+
+const struct vfe_hw_ops vfe_ops_1190 = {
+ .global_reset = vfe_global_reset,
+ .hw_version = vfe_hw_version,
+ .isr = vfe_isr,
+ .pm_domain_off = vfe_pm_domain_off,
+ .pm_domain_on = vfe_pm_domain_on,
+ .reg_update = vfe_reg_update,
+ .reg_update_clear = vfe_reg_update_clear,
+ .subdev_init = vfe_subdev_init,
+ .vfe_disable = vfe_disable,
+ .vfe_enable = vfe_enable_v2,
+ .vfe_halt = vfe_halt,
+ .vfe_wm_start = vfe_wm_start,
+ .vfe_wm_stop = vfe_wm_stop,
+ .vfe_buf_done = vfe_buf_done,
+ .vfe_wm_update = vfe_wm_update,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 58f62a2437a1663a71d34af56178af52d5d10f95..afb5d3458334b0a8ebdaaa8a69e0449e8349cf35 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -353,6 +353,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
case CAMSS_8550:
case CAMSS_8650:
case CAMSS_8775P:
+ case CAMSS_HAWI:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
switch (sink_code) {
@@ -2049,6 +2050,7 @@ static int vfe_bpl_align_rdi(struct vfe_device *vfe)
case CAMSS_8550:
case CAMSS_8650:
case CAMSS_8775P:
+ case CAMSS_HAWI:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
ret = 16;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index f0abc10f0e703aad0be03e0218f1996ecaa99ff8..eec15bb8201079b203d29ac6460adb128aeded57 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -249,6 +249,7 @@ extern const struct vfe_hw_ops vfe_ops_340;
extern const struct vfe_hw_ops vfe_ops_480;
extern const struct vfe_hw_ops vfe_ops_680;
extern const struct vfe_hw_ops vfe_ops_1080;
+extern const struct vfe_hw_ops vfe_ops_1190;
extern const struct vfe_hw_ops vfe_ops_gen3;
int vfe_get(struct vfe_device *vfe);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 16047c19b0942bc38da8aa2974e814c3d6a13f69..60322ce7e14af224d3014a3a052f5054a50d92c0 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4381,6 +4381,155 @@ static const struct resources_icc icc_res_sa8775p[] = {
},
};
+static const struct camss_subdev_resources vfe_res_hawi[] = {
+ /* VFE0 - TFE Full */
+ {
+ .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb",
+ "vfe0_fast_ahb", "vfe0", "cpas_vfe0",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe0" },
+ .interrupt = { "vfe0" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife0",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE1 - TFE Full */
+ {
+ .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb",
+ "vfe1_fast_ahb", "vfe1", "cpas_vfe1",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe1" },
+ .interrupt = { "vfe1" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife1",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE2 - TFE Full */
+ {
+ .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb",
+ "vfe2_fast_ahb", "vfe2", "cpas_vfe2",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 238200000, 397000000, 440000000, 480000000,
+ 630000000, 750000000, 833000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe2" },
+ .interrupt = { "vfe2" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife2",
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE3 - IFE Lite */
+ {
+ .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb",
+ "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 200000000, 400000000, 480000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite0" },
+ .interrupt = { "vfe_lite0" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = true,
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE4 - IFE Lite */
+ {
+ .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb",
+ "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo",
+ "cpas_mnoc_hf", "cpas_mnoc_sf" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 200000000, 400000000, 480000000 },
+ { 0 },
+ { 171428571, 240000000, 300000000, 400000000,
+ 480000000, 600000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite1" },
+ .interrupt = { "vfe_lite1" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = true,
+ .hw_ops = &vfe_ops_1190,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+};
+
static const struct camss_subdev_resources csid_res_hawi[] = {
/* CSID0 */
{
@@ -6175,11 +6324,13 @@ static const struct camss_resources hawi_resources = {
.csiphy_res = csiphy_res_kaanapali,
.tpg_res = tpg_res_x1e80100,
.csid_res = csid_res_hawi,
+ .vfe_res = vfe_res_hawi,
.icc_res = icc_res_hawi,
.icc_path_num = ARRAY_SIZE(icc_res_hawi),
.csiphy_num = ARRAY_SIZE(csiphy_res_kaanapali),
.tpg_num = ARRAY_SIZE(tpg_res_x1e80100),
.csid_num = ARRAY_SIZE(csid_res_hawi),
+ .vfe_num = ARRAY_SIZE(vfe_res_hawi),
};
static const struct camss_resources x1e80100_resources = {
--
2.34.1
More information about the linux-phy
mailing list