[PATCH RESEND 09/45] media: qcom: camss: sm8250: add IFE top v20x

From: Gjorgji . Rosikopulos . gjorgji . rosikopulos

Date: Wed Oct 07 2026 - 05:06:26 EST


From: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>

Add the IFE top controller used by the SM8250 full pixel path.

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

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 92f1938a693d..f26806c69e14 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -18,6 +18,7 @@ qcom-camss-objs += \
camss-ife-camif-v10x.o \
camss-ife-mod-v10x.o \
camss-ife-scale-v10x.o \
+ camss-ife-top-v20x.o \
camss-ispif.o \
camss-tpg.o \
camss-tpg-gen1.o \
diff --git a/drivers/media/platform/qcom/camss/camss-ife-top-v20x.c b/drivers/media/platform/qcom/camss/camss-ife-top-v20x.c
new file mode 100644
index 000000000000..bd1ce71c2dd4
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-ife-top-v20x.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Technologies, Inc.
+ */
+
+#include "camss-ife-camif-v10x.h"
+#include "camss-ife-scale-v10x.h"
+#include "camss-ife.h"
+#include "camss.h"
+
+/* Block base offsets */
+#define IFE_V20X_TOP_OFFS 0x0000
+#define IFE_V20X_CAMIF_PP_OFFSET (IFE_V20X_TOP_OFFS + 0x2600)
+#define IFE_V20X_CAMIF_RDI_OFFSET (IFE_V20X_TOP_OFFS + 0x9a00)
+
+/* Per-output DS M/N scaler base offsets */
+#define IFE_V20X_VID_DS_MN_Y_OFFSET 0x6400
+#define IFE_V20X_DISP_DS_MN_Y_OFFSET 0x4c00
+#define IFE_V20X_FD_DS_MN_Y_OFFSET 0x4400
+#define IFE_V20X_DS_MN_C_OFFSET(addr) ((addr) + 0x200)
+
+/* HW version fields */
+#define IFE_V20X_TOP_VER_MAJOR GENMASK(31, 28)
+#define IFE_V20X_TOP_VER_MINOR GENMASK(27, 16)
+#define IFE_V20X_TOP_VER_STEPS GENMASK(15, 0)
+#define IFE_V20X_TOP_MAJOR_VERSION(val) FIELD_GET(IFE_V20X_TOP_VER_MAJOR, val)
+#define IFE_V20X_TOP_MINOR_VERSION(val) FIELD_GET(IFE_V20X_TOP_VER_MINOR, val)
+#define IFE_V20X_TOP_STEPS_VERSION(val) FIELD_GET(IFE_V20X_TOP_VER_STEPS, val)
+
+/* CSID-level reset and register-update */
+#define IFE_V20X_TOP_RST_CMD_CORE_SW_RST BIT(0)
+#define IFE_V20X_TOP_IRQ_CMD_CLEAR BIT(0)
+
+/* IRQ_STATUS_0 bits - overflow, frame drop, reset */
+#define IFE_V20X_TOP_IRQ_S0_PP_OVERFLOW BIT(31)
+#define IFE_V20X_TOP_IRQ_S0_DUAL_PD_OVERFLOW BIT(30)
+#define IFE_V20X_TOP_IRQ_S0_RDI0_OVERFLOW BIT(29)
+#define IFE_V20X_TOP_IRQ_S0_RDI1_OVERFLOW BIT(28)
+#define IFE_V20X_TOP_IRQ_S0_RDI2_OVERFLOW BIT(27)
+#define IFE_V20X_TOP_IRQ_S0_PP_FRAME_DROP BIT(25)
+#define IFE_V20X_TOP_IRQ_S0_DUAL_PD_FRAME_DROP BIT(24)
+#define IFE_V20X_TOP_IRQ_S0_RDI0_FRAME_DROP BIT(23)
+#define IFE_V20X_TOP_IRQ_S0_RDI1_FRAME_DROP BIT(22)
+#define IFE_V20X_TOP_IRQ_S0_RDI2_FRAME_DROP BIT(21)
+#define IFE_V20X_TOP_IRQ_S0_DSP_OVERFLOW BIT(9)
+#define IFE_V20X_TOP_IRQ_S0_BUSWR BIT(7)
+#define IFE_V20X_TOP_IRQ_S0_RST_DONE BIT(0)
+
+#define IFE_V20X_TOP_IRQ_S0_ERRORS_MASK \
+ (IFE_V20X_TOP_IRQ_S0_PP_OVERFLOW | \
+ IFE_V20X_TOP_IRQ_S0_DUAL_PD_OVERFLOW | \
+ IFE_V20X_TOP_IRQ_S0_RDI0_OVERFLOW | \
+ IFE_V20X_TOP_IRQ_S0_RDI1_OVERFLOW | \
+ IFE_V20X_TOP_IRQ_S0_RDI2_OVERFLOW | \
+ IFE_V20X_TOP_IRQ_S0_PP_FRAME_DROP | \
+ IFE_V20X_TOP_IRQ_S0_DUAL_PD_FRAME_DROP | \
+ IFE_V20X_TOP_IRQ_S0_RDI0_FRAME_DROP | \
+ IFE_V20X_TOP_IRQ_S0_RDI1_FRAME_DROP | \
+ IFE_V20X_TOP_IRQ_S0_RDI2_FRAME_DROP | \
+ IFE_V20X_TOP_IRQ_S0_DSP_OVERFLOW)
+
+/* IRQ_STATUS_1 bits - per-pipe SOF/EOF/EPOCH */
+#define IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH1 BIT(15)
+#define IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH0 BIT(14)
+#define IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EOF BIT(13)
+#define IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_SOF BIT(12)
+#define IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH1 BIT(11)
+#define IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH0 BIT(10)
+#define IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EOF BIT(9)
+#define IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_SOF BIT(8)
+#define IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH1 BIT(7)
+#define IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH0 BIT(6)
+#define IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EOF BIT(5)
+#define IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_SOF BIT(4)
+#define IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH1 BIT(3)
+#define IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH0 BIT(2)
+#define IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EOF BIT(1)
+#define IFE_V20X_TOP_IRQ_S1_PP_CAMIF_SOF BIT(0)
+
+#define IFE_V20X_TOP_IRQ_S1_RDI0 \
+ (IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH1 | \
+ IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH0 | \
+ IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EOF | \
+ IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_SOF)
+
+#define IFE_V20X_TOP_IRQ_S1_RDI1 \
+ (IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH1 | \
+ IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH0 | \
+ IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EOF | \
+ IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_SOF)
+
+#define IFE_V20X_TOP_IRQ_S1_RDI2 \
+ (IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH1 | \
+ IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH0 | \
+ IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EOF | \
+ IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_SOF)
+
+#define IFE_V20X_TOP_IRQ_S1_PP \
+ (IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH1 | \
+ IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH0 | \
+ IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EOF | \
+ IFE_V20X_TOP_IRQ_S1_PP_CAMIF_SOF)
+
+/* IRQ_STATUS_2 bits - violations */
+#define IFE_V20X_TOP_IRQ_S2_RDI2_CAMIF_VIOLATION BIT(19)
+#define IFE_V20X_TOP_IRQ_S2_RDI1_CAMIF_VIOLATION BIT(18)
+#define IFE_V20X_TOP_IRQ_S2_RDI0_CAMIF_VIOLATION BIT(17)
+#define IFE_V20X_TOP_IRQ_S2_PP_VIOLATION BIT(12)
+#define IFE_V20X_TOP_IRQ_S2_PP_CAMIF_VIOLATION BIT(11)
+#define IFE_V20X_TOP_IRQ_S2_PP_PREPROCESS_VIOLATION BIT(10)
+
+#define IFE_V20X_TOP_IRQ_S2_ERRORS_MASK \
+ (IFE_V20X_TOP_IRQ_S2_RDI2_CAMIF_VIOLATION | \
+ IFE_V20X_TOP_IRQ_S2_RDI1_CAMIF_VIOLATION | \
+ IFE_V20X_TOP_IRQ_S2_RDI0_CAMIF_VIOLATION | \
+ IFE_V20X_TOP_IRQ_S2_PP_VIOLATION | \
+ IFE_V20X_TOP_IRQ_S2_PP_CAMIF_VIOLATION | \
+ IFE_V20X_TOP_IRQ_S2_PP_PREPROCESS_VIOLATION)
+
+/* Pixel-path write-master IDs */
+#define IFE_V20X_CFG0_PP_FULL_Y_WM 0
+#define IFE_V20X_CFG0_PP_FULL_C_WM 1
+#define IFE_V20X_CFG0_PP_DISP_Y_WM 4
+#define IFE_V20X_CFG0_PP_DISP_C_WM 5
+#define IFE_V20X_CFG0_PP_FD_Y_WM 8
+#define IFE_V20X_CFG0_PP_FD_C_WM 9
+
+/* CORE_CFG_0 fields */
+#define IFE_V20X_CFG0_VID_DS16_R2PD_DISABLE BIT(30)
+#define IFE_V20X_CFG0_VID_DS4_R2PD_DISABLE BIT(29)
+#define IFE_V20X_CFG0_DISP_DS16_R2PD_DISABLE BIT(28)
+#define IFE_V20X_CFG0_DISP_DS4_R2PD_DISABLE BIT(27)
+#define IFE_V20X_CFG0_DUAL_PD_OPERATING_MODE BIT(13)
+#define IFE_V20X_CFG0_PP_OPERATING_MODE_OFFLINE 1
+#define IFE_V20X_CFG0_PP_OPERATING_MODE GENMASK(12, 11)
+
+/* CORE_CFG_1 fields */
+#define IFE_V20X_CFG1_BAYER_PLAIN16 1
+#define IFE_V20X_CFG1_PIXEL_RAW_FMT GENMASK(7, 4)
+
+/* Register-update command bits */
+#define IFE_V20X_TOP_RUP_CMD_RDI2_UPDATE BIT(3)
+#define IFE_V20X_TOP_RUP_CMD_RDI1_UPDATE BIT(2)
+#define IFE_V20X_TOP_RUP_CMD_RDI0_UPDATE BIT(1)
+#define IFE_V20X_TOP_RUP_CMD_PP_UPDATE BIT(0)
+
+/* Top register offsets */
+#define IFE_V20X_HW_VERSION 0x00000000
+#define IFE_V20X_RST_CMD 0x0000001c
+#define IFE_V20X_CGC_OVERRIDE_0 0x00000020
+#define IFE_V20X_CGC_OVERRIDE_1 0x00000024
+#define IFE_V20X_CGC_OVERRIDE_2 0x00000028
+#define IFE_V20X_CGC_OVERRIDE_3 0x00000094
+#define IFE_V20X_CORE_CFG_0 0x0000002c
+#define IFE_V20X_CORE_CFG_1 0x00000030
+#define IFE_V20X_REG_UPDATE_CMD 0x00000034
+#define IFE_V20X_IRQ_CMD 0x00000038
+#define IFE_V20X_IRQ_MASK_S0 0x0000003c
+#define IFE_V20X_IRQ_MASK_S1 0x00000040
+#define IFE_V20X_IRQ_MASK_S2 0x00000044
+#define IFE_V20X_IRQ_CLEAR_S0 0x00000048
+#define IFE_V20X_IRQ_CLEAR_S1 0x0000004c
+#define IFE_V20X_IRQ_CLEAR_S2 0x00000050
+#define IFE_V20X_IRQ_STATUS_S0 0x00000054
+#define IFE_V20X_IRQ_STATUS_S1 0x00000058
+#define IFE_V20X_IRQ_STATUS_S2 0x0000005c
+
+static inline void __iomem *ife_v20x_get_vid_base(void __iomem *base)
+{
+ return base + IFE_V20X_VID_DS_MN_Y_OFFSET;
+}
+
+static inline void __iomem *ife_v20x_get_disp_base(void __iomem *base)
+{
+ return base + IFE_V20X_DISP_DS_MN_Y_OFFSET;
+}
+
+static inline void __iomem *ife_v20x_get_fd_base(void __iomem *base)
+{
+ return base + IFE_V20X_FD_DS_MN_Y_OFFSET;
+}
+
+static int ife_top_v20x_acquire(struct ife_device *ife, void __iomem *base,
+ void __iomem *csid_base)
+{
+ struct ife_top_ctx *ctx = &ife->top_ctx;
+
+ ctx->base = base + IFE_V20X_TOP_OFFS;
+ ctx->rdi_base = base + IFE_V20X_CAMIF_RDI_OFFSET;
+ ctx->pp_base = base + IFE_V20X_CAMIF_PP_OFFSET;
+ ctx->camif_ops = ife->res->camif_ops;
+ ctx->dev = ife->camss->dev;
+
+ return 0;
+}
+
+static void ife_top_v20x_release(struct ife_top_ctx *ctx)
+{
+ ctx->base = NULL;
+ ctx->camif_ops = NULL;
+}
+
+static int ife_top_v20x_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)
+{
+ const struct ife_hw_camif_ops *camif_ops = ctx->camif_ops;
+ enum camss_ife_hw_pipe hw_pipe = desc->hw_pipe;
+ void __iomem *base = ctx->base;
+ void __iomem *scale_base;
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ camif_ops->config(ctx->rdi_base + IFE_CAMIF_V10X_RDIX_OFFS(hw_pipe),
+ hw_pipe, pipeline_cfg);
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ /* Config CAMIF hardware pipeline */
+ camif_ops->config(ctx->pp_base, hw_pipe, pipeline_cfg);
+
+ /* Config FULL M/N DS scalers */
+ if (wm_cfg[Y_PLANE].wm_id == IFE_V20X_CFG0_PP_FULL_Y_WM &&
+ wm_cfg[C_PLANE].wm_id == IFE_V20X_CFG0_PP_FULL_C_WM) {
+ scale_base = ife_v20x_get_vid_base(base);
+ camif_v10x_scale_config(scale_base, pipeline_cfg, &wm_cfg[Y_PLANE]);
+ camif_v10x_scale_config(IFE_V20X_DS_MN_C_OFFSET(scale_base), pipeline_cfg,
+ &wm_cfg[C_PLANE]);
+ }
+
+ /* Config DISP M/N DS scalers */
+ if (wm_cfg[Y_PLANE].wm_id == IFE_V20X_CFG0_PP_DISP_Y_WM &&
+ wm_cfg[C_PLANE].wm_id == IFE_V20X_CFG0_PP_DISP_C_WM) {
+ scale_base = ife_v20x_get_disp_base(base);
+ camif_v10x_scale_config(scale_base, pipeline_cfg, &wm_cfg[Y_PLANE]);
+ camif_v10x_scale_config(IFE_V20X_DS_MN_C_OFFSET(scale_base), pipeline_cfg,
+ &wm_cfg[C_PLANE]);
+ }
+
+ /* Config FD M/N DS scalers */
+ if (wm_cfg[Y_PLANE].wm_id == IFE_V20X_CFG0_PP_FD_Y_WM &&
+ wm_cfg[C_PLANE].wm_id == IFE_V20X_CFG0_PP_FD_C_WM) {
+ scale_base = ife_v20x_get_fd_base(base);
+ camif_v10x_scale_config(scale_base, pipeline_cfg, &wm_cfg[Y_PLANE]);
+ camif_v10x_scale_config(IFE_V20X_DS_MN_C_OFFSET(scale_base), pipeline_cfg,
+ &wm_cfg[C_PLANE]);
+ }
+
+ break;
+ default:
+ dev_err(ctx->dev, "Invalid HW pipeline identifier: 0x%x\n", hw_pipe);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ife_top_v20x_pipe_enable(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *desc)
+{
+ const struct ife_hw_camif_ops *camif_ops = ctx->camif_ops;
+ enum camss_ife_hw_pipe hw_pipe = desc->hw_pipe;
+ void __iomem *base = ctx->base;
+ void __iomem *scale_base;
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ camif_ops->enable(ctx->rdi_base + IFE_CAMIF_V10X_RDIX_OFFS(hw_pipe),
+ hw_pipe);
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ /* Enable FULL M/N DS scalers */
+ scale_base = ife_v20x_get_vid_base(base);
+ camif_v10x_scale_enable(scale_base);
+ camif_v10x_scale_enable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Enable DISP M/N DS scalers */
+ scale_base = ife_v20x_get_disp_base(base);
+ camif_v10x_scale_enable(scale_base);
+ camif_v10x_scale_enable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Enable FD M/N DS scalers */
+ scale_base = ife_v20x_get_fd_base(base);
+ camif_v10x_scale_enable(scale_base);
+ camif_v10x_scale_enable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Enable CAMIF hardware pipeline */
+ camif_ops->enable(ctx->pp_base, hw_pipe);
+ break;
+ default:
+ dev_err(ctx->dev, "Invalid HW pipeline identifier: 0x%x\n", hw_pipe);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ife_top_v20x_pipe_disable(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *desc)
+{
+ const struct ife_hw_camif_ops *camif_ops = ctx->camif_ops;
+ enum camss_ife_hw_pipe hw_pipe = desc->hw_pipe;
+ void __iomem *base = ctx->base;
+ void __iomem *scale_base;
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ camif_ops->disable(ctx->rdi_base + IFE_CAMIF_V10X_RDIX_OFFS(hw_pipe),
+ hw_pipe);
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ /* Disable FULL M/N DS scalers */
+ scale_base = ife_v20x_get_vid_base(base);
+ camif_v10x_scale_disable(scale_base);
+ camif_v10x_scale_disable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Disable DISP M/N DS scalers */
+ scale_base = ife_v20x_get_disp_base(base);
+ camif_v10x_scale_disable(scale_base);
+ camif_v10x_scale_disable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Disable FD M/N DS scalers */
+ scale_base = ife_v20x_get_fd_base(base);
+ camif_v10x_scale_disable(scale_base);
+ camif_v10x_scale_disable(IFE_V20X_DS_MN_C_OFFSET(scale_base));
+
+ /* Disable CAMIF hardware pipeline */
+ camif_ops->disable(ctx->pp_base, hw_pipe);
+
+ break;
+ default:
+ dev_err(ctx->dev, "Invalid HW pipeline identifier: 0x%x\n", hw_pipe);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u32 ife_top_20x_version(struct ife_top_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+ u32 reg = readl_relaxed(base + IFE_V20X_HW_VERSION);
+ struct camss_hw_version hw_ver;
+
+ hw_ver.ids.major = IFE_V20X_TOP_MAJOR_VERSION(reg);
+ hw_ver.ids.minor = IFE_V20X_TOP_MINOR_VERSION(reg);
+ hw_ver.ids.steps = IFE_V20X_TOP_STEPS_VERSION(reg);
+
+ return hw_ver.hw_version;
+}
+
+static void ife_top_20x_reset(struct ife_top_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S0);
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S1);
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S2);
+ writel_relaxed(IFE_V20X_TOP_IRQ_S0_RST_DONE,
+ base + IFE_V20X_IRQ_MASK_S0);
+ writel_relaxed(IFE_V20X_TOP_RST_CMD_CORE_SW_RST, base + IFE_V20X_RST_CMD);
+}
+
+static void ife_top_20x_reg_update(struct ife_top_ctx *ctx,
+ const struct ife_pad_desc *dsc)
+{
+ void __iomem *base = ctx->base;
+
+ switch (dsc->hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ writel_relaxed(IFE_V20X_TOP_RUP_CMD_RDI0_UPDATE, base + IFE_V20X_REG_UPDATE_CMD);
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ writel_relaxed(IFE_V20X_TOP_RUP_CMD_RDI1_UPDATE, base + IFE_V20X_REG_UPDATE_CMD);
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ writel_relaxed(IFE_V20X_TOP_RUP_CMD_RDI2_UPDATE, base + IFE_V20X_REG_UPDATE_CMD);
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ writel_relaxed(IFE_V20X_TOP_RUP_CMD_PP_UPDATE, base + IFE_V20X_REG_UPDATE_CMD);
+ break;
+ default:
+ dev_warn(ctx->dev, "The requested RUP is invalid: 0x%x\n", dsc->hw_pipe);
+ }
+}
+
+static void ife_top_20x_prepare(struct ife_top_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+ u32 rval;
+
+ writel_relaxed(~0, base + IFE_V20X_CGC_OVERRIDE_0);
+ writel_relaxed(~0, base + IFE_V20X_CGC_OVERRIDE_1);
+ writel_relaxed(~0, base + IFE_V20X_CGC_OVERRIDE_2);
+ writel_relaxed(~0, base + IFE_V20X_CGC_OVERRIDE_3);
+
+ rval = IFE_V20X_CFG0_VID_DS16_R2PD_DISABLE;
+ rval |= IFE_V20X_CFG0_VID_DS4_R2PD_DISABLE;
+ rval |= IFE_V20X_CFG0_DUAL_PD_OPERATING_MODE;
+ rval |= IFE_V20X_CFG0_DISP_DS16_R2PD_DISABLE;
+ rval |= IFE_V20X_CFG0_DISP_DS4_R2PD_DISABLE;
+ rval |= FIELD_PREP(IFE_V20X_CFG0_PP_OPERATING_MODE,
+ IFE_V20X_CFG0_PP_OPERATING_MODE_OFFLINE);
+ writel_relaxed(rval, base + IFE_V20X_CORE_CFG_0);
+
+ rval = FIELD_PREP(IFE_V20X_CFG1_PIXEL_RAW_FMT, IFE_V20X_CFG1_BAYER_PLAIN16);
+ writel_relaxed(rval, base + IFE_V20X_CORE_CFG_1);
+
+ /* Clear pending interrupts */
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S0);
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S1);
+ writel_relaxed(~0, base + IFE_V20X_IRQ_CLEAR_S2);
+ writel_relaxed(IFE_V20X_TOP_IRQ_CMD_CLEAR, base + IFE_V20X_IRQ_CMD);
+
+ /* Enable common, frame drops and overflow interrupts */
+ rval = IFE_V20X_TOP_IRQ_S0_BUSWR | IFE_V20X_TOP_IRQ_S0_ERRORS_MASK;
+ writel_relaxed(rval, base + IFE_V20X_IRQ_MASK_S0);
+
+ /* Enable violation error interrupts */
+ rval = IFE_V20X_TOP_IRQ_S2_ERRORS_MASK;
+ writel_relaxed(rval, base + IFE_V20X_IRQ_MASK_S2);
+}
+
+static void ife_top_20x_enable(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe)
+{
+ void __iomem *base = ctx->base;
+ u32 mask;
+ u32 rval;
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI0;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI1;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI2;
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ mask = IFE_V20X_TOP_IRQ_S1_PP;
+ break;
+ default:
+ WARN_ONCE(true, "The hw_pipe is invalid: 0x%x\n", hw_pipe);
+ return;
+ }
+
+ rval = readl_relaxed(base + IFE_V20X_IRQ_MASK_S1);
+ writel_relaxed(rval | mask, base + IFE_V20X_IRQ_MASK_S1);
+}
+
+static void ife_top_20x_disable(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe)
+{
+ void __iomem *base = ctx->base;
+ u32 mask;
+ u32 rval;
+
+ switch (hw_pipe) {
+ case CAMSS_IFE_HW_PIPE_RDI0:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI0;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI1:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI1;
+ break;
+ case CAMSS_IFE_HW_PIPE_RDI2:
+ mask = IFE_V20X_TOP_IRQ_S1_RDI2;
+ break;
+ case CAMSS_IFE_HW_PIPE_PP:
+ mask = IFE_V20X_TOP_IRQ_S1_PP;
+ break;
+ default:
+ WARN_ONCE(true, "The hw_pipe is invalid: 0x%x\n", hw_pipe);
+ return;
+ }
+
+ rval = readl_relaxed(base + IFE_V20X_IRQ_MASK_S1);
+ writel_relaxed(rval & ~mask, base + IFE_V20X_IRQ_MASK_S1);
+}
+
+static void ife_top_20x_irq_status(struct ife_top_ctx *ctx, u32 isr_stat[IFE_TOP_STATUS_MAX])
+{
+ void __iomem *base = ctx->base;
+ u32 top_stat;
+
+ isr_stat[IFE_TOP_STATUS_ID0] = 0;
+
+ top_stat = readl_relaxed(base + IFE_V20X_IRQ_STATUS_S0);
+ writel_relaxed(top_stat, base + IFE_V20X_IRQ_CLEAR_S0);
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S0_RST_DONE)
+ isr_stat[IFE_TOP_STATUS_ID0] = IFE_HW_TOP_IRQ0_RST_DONE;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S0_BUSWR)
+ isr_stat[IFE_TOP_STATUS_ID0] |= IFE_HW_TOP_IRQ0_BUSWR;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S0_ERRORS_MASK)
+ isr_stat[IFE_TOP_STATUS_ID0] |= top_stat & IFE_V20X_TOP_IRQ_S0_ERRORS_MASK;
+
+ isr_stat[IFE_TOP_STATUS_ID1] = 0;
+
+ top_stat = readl_relaxed(base + IFE_V20X_IRQ_STATUS_S1);
+ writel_relaxed(top_stat, base + IFE_V20X_IRQ_CLEAR_S1);
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI0_SOF;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI1_SOF;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI2_SOF;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_PP_CAMIF_SOF)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_PP_SOF;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH0)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI0_EPOCH0;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI0_CAMIF_EPOCH1)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI0_EPOCH1;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH0)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI1_EPOCH0;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI1_CAMIF_EPOCH1)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI1_EPOCH1;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH0)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI2_EPOCH0;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_RDI2_CAMIF_EPOCH1)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_RDI2_EPOCH1;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH0)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_PP_EPOCH0;
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S1_PP_CAMIF_EPOCH1)
+ isr_stat[IFE_TOP_STATUS_ID1] |= IFE_HW_TOP_IRQ1_PP_EPOCH1;
+
+ isr_stat[IFE_TOP_STATUS_ID2] = 0;
+
+ top_stat = readl_relaxed(base + IFE_V20X_IRQ_STATUS_S2);
+ writel_relaxed(top_stat, base + IFE_V20X_IRQ_CLEAR_S2);
+
+ if (top_stat & IFE_V20X_TOP_IRQ_S2_ERRORS_MASK)
+ isr_stat[IFE_TOP_STATUS_ID2] |= top_stat & IFE_V20X_TOP_IRQ_S2_ERRORS_MASK;
+
+ writel_relaxed(IFE_V20X_TOP_IRQ_CMD_CLEAR, base + IFE_V20X_IRQ_CMD);
+}
+
+const struct ife_hw_top_ops ife_top_20x_ops = {
+ .acquire = ife_top_v20x_acquire,
+ .release = ife_top_v20x_release,
+ .version = ife_top_20x_version,
+ .prepare = ife_top_20x_prepare,
+ .enable = ife_top_20x_enable,
+ .disable = ife_top_20x_disable,
+ .pipe_config = ife_top_v20x_pipe_config,
+ .pipe_enable = ife_top_v20x_pipe_enable,
+ .pipe_disable = ife_top_v20x_pipe_disable,
+ .reg_update = ife_top_20x_reg_update,
+ .reset = ife_top_20x_reset,
+ .irq_status = ife_top_20x_irq_status,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-ife.h b/drivers/media/platform/qcom/camss/camss-ife.h
index 233b0292c107..258af76c94ea 100644
--- a/drivers/media/platform/qcom/camss/camss-ife.h
+++ b/drivers/media/platform/qcom/camss/camss-ife.h
@@ -389,6 +389,7 @@ camss_ife_pipe_for_stream_id(int nstreams,
const struct camss_ife_stream *streams,
u32 id);

+extern const struct ife_hw_top_ops ife_top_20x_ops;
extern const struct ife_hw_buswr_ops ife_buswr_20x_ops;
extern const struct camss_mod_ops ife_mod_v10x_ops;

--
2.34.1