[PATCH 30/45] media: qcom: camss: sa8775p: add IFE lite top v3.0x

From: Gjorgji . Rosikopulos . gjorgji . rosikopulos

Date: Tue Oct 06 2026 - 18:52:16 EST


From: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>

Add the IFE lite top v3.0x engine used by the SA8775P RDI paths.

Signed-off-by: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>
---
drivers/media/platform/qcom/camss/Makefile | 1 +
.../qcom/camss/camss-ife-lite-top-v30x.c | 265 ++++++++++++++++++
drivers/media/platform/qcom/camss/camss-ife.h | 1 +
3 files changed, 267 insertions(+)
create mode 100644 drivers/media/platform/qcom/camss/camss-ife-lite-top-v30x.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 479ab17f3bdb..695924e0c03b 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -17,6 +17,7 @@ qcom-camss-objs += \
camss-ife.o \
camss-ife-bus-v20x.o \
camss-ife-bus-v31x.o \
+ camss-ife-lite-top-v30x.o \
camss-ife-camif-v10x.o \
camss-ife-lite-top-v10x.o \
camss-ife-mod-v10x.o \
diff --git a/drivers/media/platform/qcom/camss/camss-ife-lite-top-v30x.c b/drivers/media/platform/qcom/camss/camss-ife-lite-top-v30x.c
new file mode 100644
index 000000000000..c3c182e4c895
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-ife-lite-top-v30x.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Technologies, Inc.
+ */
+
+#include "camss-ife.h"
+#include "camss.h"
+
+#define IFE_LT_V30X_TOP_OFFS 0x0000
+
+/* CSID register update command */
+#define IFE_LT_V30X_CSID_RUP_AUP_CMD 0x00000018
+#define IFE_LT_V30X_CSID_RUP_RDI0 BIT(4)
+#define IFE_LT_V30X_CSID_RUP_RDI1 BIT(5)
+#define IFE_LT_V30X_CSID_RUP_RDI2 BIT(6)
+#define IFE_LT_V30X_CSID_RUP_RDI3 BIT(7)
+#define IFE_LT_V30X_CSID_AUP_RDI0 BIT(20)
+#define IFE_LT_V30X_CSID_AUP_RDI1 BIT(21)
+#define IFE_LT_V30X_CSID_AUP_RDI2 BIT(22)
+#define IFE_LT_V30X_CSID_AUP_RDI3 BIT(23)
+
+#define IFE_LT_V30X_MOD_VER_GEN GENMASK(31, 28)
+#define IFE_LT_V30X_MOD_VER_REV GENMASK(27, 16)
+#define IFE_LT_V30X_MOD_VER_STEP GENMASK(15, 0)
+#define IFE_LT_V30X_MOD_GEN(val) FIELD_GET(IFE_LT_V30X_MOD_VER_GEN, val)
+#define IFE_LT_V30X_MOD_REV(val) FIELD_GET(IFE_LT_V30X_MOD_VER_REV, val)
+#define IFE_LT_V30X_MOD_STEP(val) FIELD_GET(IFE_LT_V30X_MOD_VER_STEP, val)
+
+/* TOP functional IRQ registers */
+#define IFE_LT_V30X_FUNC_IRQ_CMD 0x00000064
+#define IFE_LT_V30X_FUNC_IRQ_CMD_CLEAR BIT(0)
+#define IFE_LT_V30X_FUNC_IRQ_MASK_0 0x00000068
+#define IFE_LT_V30X_FUNC_IRQ_MASK_1 0x0000006c
+#define IFE_LT_V30X_FUNC_IRQ_CLEAR_0 0x00000070
+#define IFE_LT_V30X_FUNC_IRQ_CLEAR_1 0x00000074
+#define IFE_LT_V30X_FUNC_IRQ_STATUS_0 0x00000078
+#define IFE_LT_V30X_FUNC_IRQ_STATUS_1 0x0000007c
+
+/* IRQ_STATUS_0 bits */
+#define IFE_LT_V30X_IRQ0_DIAG_VIOLATION BIT(1)
+#define IFE_LT_V30X_IRQ0_BUSWR BIT(0)
+#define IFE_LT_V30X_IRQ0_ERRORS_MASK \
+ (IFE_LT_V30X_IRQ0_DIAG_VIOLATION)
+
+/* IRQ_STATUS_1 bits - per-RDI SOF/EOF */
+#define IFE_LT_V30X_IRQ1_RDI3_EOF BIT(7)
+#define IFE_LT_V30X_IRQ1_RDI3_SOF BIT(6)
+#define IFE_LT_V30X_IRQ1_RDI2_EOF BIT(5)
+#define IFE_LT_V30X_IRQ1_RDI2_SOF BIT(4)
+#define IFE_LT_V30X_IRQ1_RDI1_EOF BIT(3)
+#define IFE_LT_V30X_IRQ1_RDI1_SOF BIT(2)
+#define IFE_LT_V30X_IRQ1_RDI0_EOF BIT(1)
+#define IFE_LT_V30X_IRQ1_RDI0_SOF BIT(0)
+
+#define IFE_LT_V30X_IRQ1_RDI0 \
+ (IFE_LT_V30X_IRQ1_RDI0_SOF | IFE_LT_V30X_IRQ1_RDI0_EOF)
+#define IFE_LT_V30X_IRQ1_RDI1 \
+ (IFE_LT_V30X_IRQ1_RDI1_SOF | IFE_LT_V30X_IRQ1_RDI1_EOF)
+#define IFE_LT_V30X_IRQ1_RDI2 \
+ (IFE_LT_V30X_IRQ1_RDI2_SOF | IFE_LT_V30X_IRQ1_RDI2_EOF)
+#define IFE_LT_V30X_IRQ1_RDI3 \
+ (IFE_LT_V30X_IRQ1_RDI3_SOF | IFE_LT_V30X_IRQ1_RDI3_EOF)
+
+#define IFE_LT_V30X_HW_VERSION 0x00000000
+
+static int ife_lite_top_30x_acquire(struct ife_device *ife, void __iomem *base,
+ void __iomem *csid_base)
+{
+ struct ife_top_ctx *ctx = &ife->top_ctx;
+
+ if (!csid_base)
+ return -EINVAL;
+
+ ctx->base = base + IFE_LT_V30X_TOP_OFFS;
+ ctx->dev = ife->camss->dev;
+ ctx->csid_base = csid_base;
+
+ return 0;
+}
+
+static void ife_lite_top_30x_release(struct ife_top_ctx *ctx)
+{
+ ctx->base = NULL;
+ ctx->csid_base = NULL;
+}
+
+static u32 ife_lite_top_30x_version(struct ife_top_ctx *ctx)
+{
+ struct camss_hw_version hw_ver;
+ u32 reg = readl_relaxed(ctx->base + IFE_LT_V30X_HW_VERSION);
+
+ hw_ver.ids.major = IFE_LT_V30X_MOD_GEN(reg);
+ hw_ver.ids.minor = IFE_LT_V30X_MOD_REV(reg);
+ hw_ver.ids.steps = IFE_LT_V30X_MOD_STEP(reg);
+
+ return hw_ver.hw_version;
+}
+
+static void ife_lite_top_30x_reset(struct ife_top_ctx *ctx)
+{
+ void __iomem *top = ctx->base;
+
+ writel_relaxed(~0, top + IFE_LT_V30X_FUNC_IRQ_CLEAR_0);
+ writel_relaxed(~0, top + IFE_LT_V30X_FUNC_IRQ_CLEAR_1);
+ writel_relaxed(IFE_LT_V30X_FUNC_IRQ_CMD_CLEAR, top + IFE_LT_V30X_FUNC_IRQ_CMD);
+}
+
+static void ife_lite_top_30x_reg_update(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *dsc)
+{
+ void __iomem *csid = ctx->csid_base;
+ u32 rval;
+
+ switch (dsc->hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ rval = IFE_LT_V30X_CSID_RUP_RDI0 | IFE_LT_V30X_CSID_AUP_RDI0;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ rval = IFE_LT_V30X_CSID_RUP_RDI1 | IFE_LT_V30X_CSID_AUP_RDI1;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ rval = IFE_LT_V30X_CSID_RUP_RDI2 | IFE_LT_V30X_CSID_AUP_RDI2;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI3:
+ rval = IFE_LT_V30X_CSID_RUP_RDI3 | IFE_LT_V30X_CSID_AUP_RDI3;
+ break;
+ default:
+ dev_warn(ctx->dev, "Invalid RUP pipe: 0x%x\n", dsc->hw_pipe);
+ return;
+ }
+
+ writel_relaxed(rval, csid + IFE_LT_V30X_CSID_RUP_AUP_CMD);
+}
+
+static int ife_lite_top_30x_pipe_config(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *desc,
+ const struct camss_ife_pipeline_cfg *pipeline_cfg,
+ const struct camss_ife_wm_config *wm_cfg)
+{
+ return 0;
+}
+
+static int ife_lite_top_30x_pipe_enable(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *desc)
+{
+ return 0;
+}
+
+static int ife_lite_top_30x_pipe_disable(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *desc)
+{
+ return 0;
+}
+
+static void ife_lite_top_30x_prepare(struct ife_top_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+ u32 rval;
+
+ writel_relaxed(~0, base + IFE_LT_V30X_FUNC_IRQ_CLEAR_0);
+ writel_relaxed(~0, base + IFE_LT_V30X_FUNC_IRQ_CLEAR_1);
+ writel_relaxed(IFE_LT_V30X_FUNC_IRQ_CMD_CLEAR, base + IFE_LT_V30X_FUNC_IRQ_CMD);
+
+ rval = IFE_LT_V30X_IRQ0_BUSWR | IFE_LT_V30X_IRQ0_ERRORS_MASK;
+ writel_relaxed(rval, base + IFE_LT_V30X_FUNC_IRQ_MASK_0);
+}
+
+static void ife_lite_top_30x_enable(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe)
+{
+ void __iomem *base = ctx->base;
+ u32 rval = readl_relaxed(base + IFE_LT_V30X_FUNC_IRQ_MASK_1);
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ rval |= IFE_LT_V30X_IRQ1_RDI0;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ rval |= IFE_LT_V30X_IRQ1_RDI1;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ rval |= IFE_LT_V30X_IRQ1_RDI2;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI3:
+ rval |= IFE_LT_V30X_IRQ1_RDI3;
+ break;
+ default:
+ return;
+ }
+
+ writel_relaxed(rval, base + IFE_LT_V30X_FUNC_IRQ_MASK_1);
+}
+
+static void ife_lite_top_30x_disable(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe)
+{
+ void __iomem *base = ctx->base;
+ u32 rval = readl_relaxed(base + IFE_LT_V30X_FUNC_IRQ_MASK_1);
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ rval &= ~IFE_LT_V30X_IRQ1_RDI0;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ rval &= ~IFE_LT_V30X_IRQ1_RDI1;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ rval &= ~IFE_LT_V30X_IRQ1_RDI2;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI3:
+ rval &= ~IFE_LT_V30X_IRQ1_RDI3;
+ break;
+ default:
+ dev_warn(ctx->dev, "Invalid HW pipeline identifier: 0x%x\n", hw_pipe);
+ return;
+ }
+
+ writel_relaxed(rval, base + IFE_LT_V30X_FUNC_IRQ_MASK_1);
+}
+
+static void ife_lite_top_30x_irq_status(struct ife_top_ctx *ctx, u32 isr_stat[IFE_TOP_STATUS_MAX])
+{
+ void __iomem *base = ctx->base;
+ u32 stat0;
+ u32 stat1;
+
+ stat0 = readl_relaxed(base + IFE_LT_V30X_FUNC_IRQ_STATUS_0);
+ stat1 = readl_relaxed(base + IFE_LT_V30X_FUNC_IRQ_STATUS_1);
+
+ writel_relaxed(stat0, base + IFE_LT_V30X_FUNC_IRQ_CLEAR_0);
+ writel_relaxed(stat1, base + IFE_LT_V30X_FUNC_IRQ_CLEAR_1);
+ writel_relaxed(IFE_LT_V30X_FUNC_IRQ_CMD_CLEAR, base + IFE_LT_V30X_FUNC_IRQ_CMD);
+
+ isr_stat[IFE_TOP_STATUS_ID0] = 0;
+ isr_stat[IFE_TOP_STATUS_ID1] = 0;
+ isr_stat[IFE_TOP_STATUS_ID2] = stat0 & IFE_LT_V30X_IRQ0_ERRORS_MASK;
+
+ if (stat0 & IFE_LT_V30X_IRQ0_BUSWR)
+ isr_stat[IFE_TOP_STATUS_ID0] |= IFE_HW_TOP_IRQ0_BUSWR;
+
+ if (stat1 & IFE_LT_V30X_IRQ1_RDI0_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI0_SOF;
+
+ if (stat1 & IFE_LT_V30X_IRQ1_RDI1_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI1_SOF;
+
+ if (stat1 & IFE_LT_V30X_IRQ1_RDI2_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI2_SOF;
+
+ if (stat1 & IFE_LT_V30X_IRQ1_RDI3_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI3_SOF;
+}
+
+const struct ife_hw_top_ops ife_lite_top_30x_ops = {
+ .acquire = ife_lite_top_30x_acquire,
+ .release = ife_lite_top_30x_release,
+ .version = ife_lite_top_30x_version,
+ .prepare = ife_lite_top_30x_prepare,
+ .enable = ife_lite_top_30x_enable,
+ .disable = ife_lite_top_30x_disable,
+ .pipe_config = ife_lite_top_30x_pipe_config,
+ .pipe_enable = ife_lite_top_30x_pipe_enable,
+ .pipe_disable = ife_lite_top_30x_pipe_disable,
+ .reg_update = ife_lite_top_30x_reg_update,
+ .reset = ife_lite_top_30x_reset,
+ .irq_status = ife_lite_top_30x_irq_status,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-ife.h b/drivers/media/platform/qcom/camss/camss-ife.h
index 31d9c83767a5..eff4ab4bd1c9 100644
--- a/drivers/media/platform/qcom/camss/camss-ife.h
+++ b/drivers/media/platform/qcom/camss/camss-ife.h
@@ -403,5 +403,6 @@ extern const struct camss_mod_ops ife_mod_v10x_ops;

extern const struct ife_pads_descriptors ife_lite_pads_v20x;
extern const struct ife_hw_top_ops ife_lite_top_10x_ops;
+extern const struct ife_hw_top_ops ife_lite_top_30x_ops;

#endif /* CAMSS_IFE_SUB_DEV_H */
--
2.34.1