[PATCH 6/7] media: qcom: camss: vfe: Add support for VFE gen4

Hangxiang Ma
2025-11-26T09:40:13Z

Add support for Video Front End (VFE) that is on the SM8750 SoCs. The
bus_wr configuration and the registers offsets closely match with the
driver that had been added for Kaanapali. Hence, rename the previously
added driver as 'gen4' and use that for both to avoid redundancy. Handle
the minor differences in the driver using the chipset version.

This change limits SM8750 VFE output lines to 3 for now as constrained
by the CAMSS driver framework.

Co-developed-by: Atiya Kailany <atiya.kailany@oss.qualcomm.com>
Signed-off-by: Atiya Kailany <atiya.kailany@oss.qualcomm.com>
Signed-off-by: Hangxiang Ma <hangxiang.ma@oss.qualcomm.com>
---
drivers/media/platform/qcom/camss/Makefile | 4 +-
.../camss/{camss-vfe-1080.c => camss-vfe-gen4.c} | 60 +++++----
drivers/media/platform/qcom/camss/camss-vfe.c | 2 +
drivers/media/platform/qcom/camss/camss-vfe.h | 2 +-
drivers/media/platform/qcom/camss/camss.c | 150 ++++++++++++++++++++-
5 files changed, 182 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 74e12ec65427..6e54d2d11ed3 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -23,9 +23,9 @@ qcom-camss-objs += \
camss-vfe-340.o \
camss-vfe-480.o \
camss-vfe-680.o \
- camss-vfe-1080.o \
- camss-vfe-gen3.o \
camss-vfe-gen1.o \
+ camss-vfe-gen3.o \
+ camss-vfe-gen4.o \
camss-vfe-vbif.o \
camss-vfe.o \
camss-video.o \
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-1080.c b/drivers/media/platform/qcom/camss/camss-vfe-gen4.c
similarity index 75%
rename from drivers/media/platform/qcom/camss/camss-vfe-1080.c
rename to drivers/media/platform/qcom/camss/camss-vfe-gen4.c
index 9ad3dee2e80b..d0218950c05c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-1080.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen4.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * camss-vfe-1080.c
+ * camss-vfe-gen4.c
*
- * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v1080
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module gen4
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
@@ -13,8 +13,12 @@
#include "camss.h"
#include "camss-vfe.h"

-/* VFE-1080 Bus Register Base Addresses */
-#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x800 : 0x1000)
+#define IS_VFE_980(vfe) ((vfe)->camss->res->version == CAMSS_8750)
+
+#define BUS_REG_BASE_980 (vfe_is_lite(vfe) ? 0x200 : 0x800)
+#define BUS_REG_BASE_1080 (vfe_is_lite(vfe) ? 0x800 : 0x1000)
+#define BUS_REG_BASE \
+ (IS_VFE_980(vfe) ? BUS_REG_BASE_980 : BUS_REG_BASE_1080)

#define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x08)
#define WM_CGC_OVERRIDE_ALL (0x7FFFFFF)
@@ -55,7 +59,7 @@
* DISPLAY_DS2_C 6
* FD_Y 7
* FD_C 8
- * PIXEL_RAW 9
+ * RAW_OUT(1080)/IR_OUT(980) 9
* STATS_AEC_BG 10
* STATS_AEC_BHIST 11
* STATS_TINTLESS_BG 12
@@ -86,7 +90,7 @@
*/
#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))

-static void vfe_wm_start_1080(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+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;
@@ -121,14 +125,14 @@ static void vfe_wm_start_1080(struct vfe_device *vfe, u8 wm, struct vfe_line *li
writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
}

-static void vfe_wm_stop_1080(struct vfe_device *vfe, u8 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_1080(struct vfe_device *vfe, u8 wm, u32 addr,
- struct vfe_line *line)
+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));
@@ -136,62 +140,62 @@ static void vfe_wm_update_1080(struct vfe_device *vfe, u8 wm, u32 addr,
dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n", wm, addr);
}

-static void vfe_reg_update_1080(struct vfe_device *vfe, enum vfe_line_id line_id)
+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_1080(struct vfe_device *vfe,
- enum vfe_line_id line_id)
+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_1080 = {
+static const struct camss_video_ops vfe_video_ops = {
.queue_buffer = vfe_queue_buffer_v2,
.flush_buffers = vfe_flush_buffers,
};

-static void vfe_subdev_init_1080(struct device *dev, struct vfe_device *vfe)
+static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
{
- vfe->video_ops = vfe_video_ops_1080;
+ vfe->video_ops = vfe_video_ops;
}

-static void vfe_global_reset_1080(struct vfe_device *vfe)
+static void vfe_global_reset(struct vfe_device *vfe)
{
vfe_isr_reset_ack(vfe);
}

-static irqreturn_t vfe_isr_1080(int irq, void *dev)
+static irqreturn_t vfe_isr(int irq, void *dev)
{
/* nop */
return IRQ_HANDLED;
}

-static int vfe_halt_1080(struct vfe_device *vfe)
+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_1080 = {
- .global_reset = vfe_global_reset_1080,
+const struct vfe_hw_ops vfe_ops_gen4 = {
+ .global_reset = vfe_global_reset,
.hw_version = vfe_hw_version,
- .isr = vfe_isr_1080,
+ .isr = vfe_isr,
.pm_domain_off = vfe_pm_domain_off,
.pm_domain_on = vfe_pm_domain_on,
- .reg_update = vfe_reg_update_1080,
- .reg_update_clear = vfe_reg_update_clear_1080,
- .subdev_init = vfe_subdev_init_1080,
+ .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_1080,
- .vfe_wm_start = vfe_wm_start_1080,
- .vfe_wm_stop = vfe_wm_stop_1080,
+ .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_1080,
+ .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 399be8b70fed..b8aa4b7d1a8d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -350,6 +350,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
case CAMSS_845:
case CAMSS_8550:
case CAMSS_8650:
+ case CAMSS_8750:
case CAMSS_8775P:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
@@ -2012,6 +2013,7 @@ static int vfe_bpl_align(struct vfe_device *vfe)
case CAMSS_845:
case CAMSS_8550:
case CAMSS_8650:
+ case CAMSS_8750:
case CAMSS_8775P:
case CAMSS_KAANAPALI:
case CAMSS_X1E80100:
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 118cac5daf37..c402ef170c81 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -249,8 +249,8 @@ extern const struct vfe_hw_ops vfe_ops_170;
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_gen3;
+extern const struct vfe_hw_ops vfe_ops_gen4;

int vfe_get(struct vfe_device *vfe);
void vfe_put(struct vfe_device *vfe);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 9dea343c1ac5..48d8f282d780 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -245,7 +245,7 @@ static const struct camss_subdev_resources vfe_res_kaanapali[] = {
.reg_update_after_csid_config = true,
.has_pd = true,
.pd_name = "vfe0",
- .hw_ops = &vfe_ops_1080,
+ .hw_ops = &vfe_ops_gen4,
.formats_rdi = &vfe_formats_rdi_845,
.formats_pix = &vfe_formats_pix_845
}
@@ -274,7 +274,7 @@ static const struct camss_subdev_resources vfe_res_kaanapali[] = {
.reg_update_after_csid_config = true,
.has_pd = true,
.pd_name = "vfe1",
- .hw_ops = &vfe_ops_1080,
+ .hw_ops = &vfe_ops_gen4,
.formats_rdi = &vfe_formats_rdi_845,
.formats_pix = &vfe_formats_pix_845
}
@@ -303,7 +303,7 @@ static const struct camss_subdev_resources vfe_res_kaanapali[] = {
.reg_update_after_csid_config = true,
.has_pd = true,
.pd_name = "vfe2",
- .hw_ops = &vfe_ops_1080,
+ .hw_ops = &vfe_ops_gen4,
.formats_rdi = &vfe_formats_rdi_845,
.formats_pix = &vfe_formats_pix_845
}
@@ -327,7 +327,7 @@ static const struct camss_subdev_resources vfe_res_kaanapali[] = {
.line_num = 4,
.is_lite = true,
.reg_update_after_csid_config = true,
- .hw_ops = &vfe_ops_1080,
+ .hw_ops = &vfe_ops_gen4,
.formats_rdi = &vfe_formats_rdi_845,
.formats_pix = &vfe_formats_pix_845
}
@@ -351,7 +351,7 @@ static const struct camss_subdev_resources vfe_res_kaanapali[] = {
.line_num = 4,
.is_lite = true,
.reg_update_after_csid_config = true,
- .hw_ops = &vfe_ops_1080,
+ .hw_ops = &vfe_ops_gen4,
.formats_rdi = &vfe_formats_rdi_845,
.formats_pix = &vfe_formats_pix_845
}
@@ -4053,6 +4053,144 @@ static const struct camss_subdev_resources csid_res_8750[] = {
}
};

+static const struct camss_subdev_resources vfe_res_8750[] = {
+ /* VFE0 - TFE Full */
+ {
+ .regulators = {},
+ .clock = { "gcc_hf_axi", "vfe0_fast_ahb", "vfe0",
+ "camnoc_rt_vfe0", "camnoc_rt_vfe1", "camnoc_rt_vfe2",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 360280000, 480000000, 630000000, 716000000,
+ 833000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 200000000, 300000000, 400000000, 480000000 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe0" },
+ .interrupt = { "vfe0" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = false,
+ .reg_update_after_csid_config = true,
+ .has_pd = true,
+ .pd_name = "vfe0",
+ .hw_ops = &vfe_ops_gen4,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE1 - TFE Full */
+ {
+ .regulators = {},
+ .clock = { "gcc_hf_axi", "vfe1_fast_ahb", "vfe1",
+ "camnoc_rt_vfe0", "camnoc_rt_vfe1", "camnoc_rt_vfe2",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 360280000, 480000000, 630000000, 716000000,
+ 833000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 200000000, 300000000, 400000000, 480000000 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe1" },
+ .interrupt = { "vfe1" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = false,
+ .reg_update_after_csid_config = true,
+ .has_pd = true,
+ .pd_name = "vfe1",
+ .hw_ops = &vfe_ops_gen4,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE2 - TFE Full */
+ {
+ .regulators = {},
+ .clock = { "gcc_hf_axi", "vfe2_fast_ahb", "vfe2",
+ "camnoc_rt_vfe0", "camnoc_rt_vfe1", "camnoc_rt_vfe2",
+ "camnoc_rt_axi", "camnoc_nrt_axi", "qdss_debug_xo" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 360280000, 480000000, 630000000, 716000000,
+ 833000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 200000000, 300000000, 400000000, 480000000 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe2" },
+ .interrupt = { "vfe2" },
+ .vfe = {
+ .line_num = 3,
+ .is_lite = false,
+ .reg_update_after_csid_config = true,
+ .has_pd = true,
+ .pd_name = "vfe2",
+ .hw_ops = &vfe_ops_gen4,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE_LITE0 */
+ {
+ .regulators = {},
+ .clock = { "gcc_hf_axi", "vfe_lite_ahb", "vfe_lite",
+ "camnoc_rt_vfe_lite", "camnoc_rt_axi",
+ "camnoc_nrt_axi", "qdss_debug_xo" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 266666667, 400000000, 480000000 },
+ { 0 },
+ { 200000000, 300000000, 400000000, 480000000 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite0" },
+ .interrupt = { "vfe_lite0" },
+ .vfe = {
+ .line_num = 4,
+ .is_lite = true,
+ .reg_update_after_csid_config = true,
+ .hw_ops = &vfe_ops_gen4,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ },
+ /* VFE_LITE1 */
+ {
+ .regulators = {},
+ .clock = { "gcc_hf_axi", "vfe_lite_ahb", "vfe_lite",
+ "camnoc_rt_vfe_lite", "camnoc_rt_axi",
+ "camnoc_nrt_axi", "qdss_debug_xo" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 266666667, 400000000, 480000000 },
+ { 0 },
+ { 200000000, 300000000, 400000000, 480000000 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe_lite1" },
+ .interrupt = { "vfe_lite1" },
+ .vfe = {
+ .line_num = 4,
+ .is_lite = true,
+ .reg_update_after_csid_config = true,
+ .hw_ops = &vfe_ops_gen4,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
+ }
+};
+
static const struct resources_icc icc_res_sm8750[] = {
{
.name = "ahb",
@@ -5485,9 +5623,11 @@ static const struct camss_resources sm8750_resources = {
.pd_name = "top",
.csiphy_res = csiphy_res_8750,
.csid_res = csid_res_8750,
+ .vfe_res = vfe_res_8750,
.icc_res = icc_res_sm8750,
.csiphy_num = ARRAY_SIZE(csiphy_res_8750),
.csid_num = ARRAY_SIZE(csid_res_8750),
+ .vfe_num = ARRAY_SIZE(vfe_res_8750),
.icc_path_num = ARRAY_SIZE(icc_res_sm8750),
};

--
2.34.1