[PATCH 06/45] media: qcom: camss: add IFE subdevice interface
From: Gjorgji . Rosikopulos . gjorgji . rosikopulos
Date: Tue Oct 06 2026 - 18:44:14 EST
From: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>
Add the common IFE types and hardware operation interfaces. Later
patches use them to add the IFE engines and subdevice.
Signed-off-by: Atanas Filipov <atanas.filipov@xxxxxxxxxxxxxxxx>
---
drivers/media/platform/qcom/camss/camss-ife.h | 392 ++++++++++++++++++
1 file changed, 392 insertions(+)
create mode 100644 drivers/media/platform/qcom/camss/camss-ife.h
diff --git a/drivers/media/platform/qcom/camss/camss-ife.h b/drivers/media/platform/qcom/camss/camss-ife.h
new file mode 100644
index 000000000000..39e8cfa74909
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-ife.h
@@ -0,0 +1,392 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Technologies, Inc.
+ */
+
+#ifndef CAMSS_IFE_SUB_DEV_H
+#define CAMSS_IFE_SUB_DEV_H
+
+#include <media/v4l2-isp.h>
+#include <media/v4l2-subdev.h>
+
+#include "camss-format.h"
+#include "camss-video.h"
+
+#define IFE_CAMIF_HW_PIPES_MAX 6
+
+/* IFE irq 0 status flags */
+#define IFE_HW_TOP_IRQ0_RST_DONE BIT(0)
+#define IFE_HW_TOP_IRQ0_BUSWR BIT(1)
+
+/* IFE top */
+#define IFE_HW_TOP_IRQ1_RDI0_SOF BIT(0)
+#define IFE_HW_TOP_IRQ1_RDI0_EPOCH0 BIT(1)
+#define IFE_HW_TOP_IRQ1_RDI0_EPOCH1 BIT(2)
+#define IFE_HW_TOP_IRQ1_RDI1_SOF BIT(3)
+#define IFE_HW_TOP_IRQ1_RDI1_EPOCH0 BIT(4)
+#define IFE_HW_TOP_IRQ1_RDI1_EPOCH1 BIT(5)
+#define IFE_HW_TOP_IRQ1_RDI2_SOF BIT(6)
+#define IFE_HW_TOP_IRQ1_RDI2_EPOCH0 BIT(7)
+#define IFE_HW_TOP_IRQ1_RDI2_EPOCH1 BIT(8)
+#define IFE_HW_TOP_IRQ1_RDI3_SOF BIT(9)
+#define IFE_HW_TOP_IRQ1_PP_SOF BIT(12)
+#define IFE_HW_TOP_IRQ1_PP_EPOCH0 BIT(13)
+#define IFE_HW_TOP_IRQ1_PP_EPOCH1 BIT(14)
+
+#define BUSWR_CLIENT_CFG_MODE_LINE_BASED 0
+#define BUSWR_CLIENT_CFG_MODE_FRAME_BASED 1
+
+enum camss_ife_output {
+ CAMSS_IFE_OUTPUT_INVALID,
+ CAMSS_IFE_OUTPUT_RDI0,
+ CAMSS_IFE_OUTPUT_RDI1,
+ CAMSS_IFE_OUTPUT_RDI2,
+ CAMSS_IFE_OUTPUT_RDI3,
+ CAMSS_IFE_OUTPUT_VID_FULL,
+ CAMSS_IFE_OUTPUT_DISP_FULL,
+ CAMSS_IFE_OUTPUT_FD,
+};
+
+enum camss_ife_hw_pipe {
+ CAMSS_IFE_HW_PIPE_RDI0,
+ CAMSS_IFE_HW_PIPE_RDI1,
+ CAMSS_IFE_HW_PIPE_RDI2,
+ CAMSS_IFE_HW_PIPE_RDI3,
+ CAMSS_IFE_HW_PIPE_PP,
+ CAMSS_IFE_HW_PIPE_INVALID,
+};
+
+enum ife_hw_planes {
+ Y_PLANE = 0,
+ C_PLANE,
+ IFE_HW_PLANES
+};
+
+enum ife_top_status {
+ IFE_TOP_STATUS_ID0,
+ IFE_TOP_STATUS_ID1,
+ IFE_TOP_STATUS_ID2,
+ IFE_TOP_STATUS_MAX,
+};
+
+struct camss_hw_version {
+ union {
+ u32 hw_version;
+ struct {
+ u32 major: 4;
+ u32 minor: 12;
+ u32 steps: 16;
+ } ids;
+ };
+};
+
+struct camss_ife_wm_config {
+ u32 wm_id;
+ u32 width;
+ u32 height;
+ u32 bytes;
+ u32 stride;
+ u32 lines;
+ u32 mode_config;
+ u32 packing_fmt;
+};
+
+struct camss_ife_pipeline_cfg {
+ u32 in_code;
+ u32 in_width;
+ u32 in_height;
+ struct v4l2_rect *ds_mn_crop;
+};
+
+struct camss;
+struct camss_subdev_resources;
+struct ife_device;
+struct ife_pad_desc;
+struct ife_top_ctx;
+struct ife_pp_ctx;
+struct vb2_buffer;
+struct ife_buswr_ctx;
+
+/**
+ * struct ife_hw_camif_ops - CAMIF hardware ops interface.
+ *
+ * Abstracts the CAMIF config/enable/disable operations so that
+ * top-level controllers are not coupled to a specific CAMIF IP version.
+ *
+ * @config: Program CAMIF registers for the given pipe and pipeline config.
+ * @enable: Enable the CAMIF output for the given pipe.
+ * @disable: Disable the CAMIF output for the given pipe.
+ */
+struct ife_hw_camif_ops {
+ int (*config)(void __iomem *base, enum camss_ife_hw_pipe hw_pipe,
+ const struct camss_ife_pipeline_cfg *cfg);
+ void (*enable)(void __iomem *base, enum camss_ife_hw_pipe hw_pipe);
+ void (*disable)(void __iomem *base, enum camss_ife_hw_pipe hw_pipe);
+};
+
+struct ife_hw_top_ops {
+ int (*acquire)(struct ife_device *ife, void __iomem *base,
+ void __iomem *csid_base);
+ void (*release)(struct ife_top_ctx *ctx);
+
+ u32 (*version)(struct ife_top_ctx *ctx);
+ void (*prepare)(struct ife_top_ctx *ctx);
+ void (*enable)(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe);
+ void (*disable)(struct ife_top_ctx *ctx, enum camss_ife_hw_pipe hw_pipe);
+
+ int (*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);
+ int (*pipe_enable)(struct ife_top_ctx *ctx, const struct ife_pad_desc *desc);
+ int (*pipe_disable)(struct ife_top_ctx *ctx, const struct ife_pad_desc *desc);
+
+ void (*reg_update)(struct ife_top_ctx *ctx, const struct ife_pad_desc *dsc);
+ void (*reset)(struct ife_top_ctx *ctx);
+ void (*irq_status)(struct ife_top_ctx *ctx, u32 isr_stat[IFE_TOP_STATUS_MAX]);
+};
+
+struct ife_hw_buswr_ops {
+ void (*acquire)(struct ife_device *ife, void __iomem *base);
+ void (*release)(struct ife_buswr_ctx *ctx);
+ void (*irq_enable)(struct ife_buswr_ctx *ctx);
+ void (*irq_disable)(struct ife_buswr_ctx *ctx);
+ void (*wm_config)(struct ife_buswr_ctx *ctx, const u8 wm,
+ const struct camss_ife_wm_config *cfg);
+ void (*wm_enable)(struct ife_buswr_ctx *ctx, u8 wm);
+ void (*wm_disable)(struct ife_buswr_ctx *ctx, u8 wm);
+ void (*queue_buf)(struct ife_buswr_ctx *ctx, const u8 num_wms,
+ const u8 *wm, dma_addr_t *addr);
+ u32 (*consumed_addr)(struct ife_buswr_ctx *ctx, u8 wm);
+ u32 (*irq_status)(struct ife_buswr_ctx *ctx);
+ bool (*is_fifo_full)(struct ife_buswr_ctx *ctx, u8 wm);
+};
+
+/**
+ * struct camss_pp_cfg - PP module pipeline configuration.
+ *
+ * @width: Input frame width in pixels.
+ * @height: Input frame height in pixels.
+ * @in_code: Input media bus format code (MEDIA_BUS_FMT_*).
+ */
+struct camss_pp_cfg {
+ u32 width;
+ u32 height;
+ u32 in_code;
+};
+
+/**
+ * struct camss_mod_ops - PP module ops interface.
+ *
+ * Engine-agnostic ops for configuring, enabling and disabling a set of
+ * post-processing hardware modules. The concrete implementation is
+ * provided by the IP-specific backend (e.g. pp_v10x_modules_ops).
+ *
+ * @acquire: Initialise the context; store @base in @ctx.
+ * @release: Release the context.
+ * @config: Program module registers with default values derived from @cfg.
+ * Called once per stream start before @enable.
+ * @enable: Enable all modules managed by this backend.
+ * @disable: Disable all modules managed by this backend.
+ * @apply_params: Apply per-frame IFE module parameters (optional).
+ */
+struct camss_mod_ops {
+ void (*acquire)(struct ife_device *ife, struct ife_pp_ctx *ctx, void __iomem *base);
+ void (*release)(struct ife_pp_ctx *ctx);
+ void (*config)(struct ife_pp_ctx *ctx, const struct camss_pp_cfg *cfg);
+ void (*enable)(struct ife_pp_ctx *ctx);
+ void (*disable)(struct ife_pp_ctx *ctx);
+ int (*apply_params)(struct ife_pp_ctx *ctx, struct vb2_buffer *vb);
+};
+
+/**
+ * struct ife_top_ctx - runtime context for the IFE top controller.
+ *
+ * Holds the hardware base address and the CAMIF ops pointer so that
+ * top-level pipe functions do not need to receive them as arguments.
+ * Initialised once at device probe via ife_hw_top_ops::acquire().
+ *
+ * @base: MMIO base of the IFE top register block.
+ * @camif_ops: CAMIF hardware ops bound to this IFE hardware block.
+ * @dev: Device used for diagnostic messages.
+ */
+struct ife_top_ctx {
+ void __iomem *base;
+ void __iomem *csid_base;
+ void __iomem *rdi_base;
+ void __iomem *pp_base;
+ const struct ife_hw_camif_ops *camif_ops;
+ struct device *dev;
+};
+
+/**
+ * struct ife_buswr_ctx - runtime context for the IFE BUS write engine.
+ *
+ * Holds the hardware base address so that BUS write ops do not need to
+ * receive it as an argument on every call.
+ * Initialised once at device probe via ife_hw_buswr_ops::acquire().
+ *
+ * @base: MMIO base of the IFE BUS write register block.
+ * @dev: Device used for diagnostics.
+ */
+struct ife_buswr_ctx {
+ void __iomem *base;
+ struct device *dev;
+};
+
+/**
+ * struct ife_pp_ctx - runtime context for the IFE post-processing engine.
+ *
+ * Holds the hardware base address so that PP ops do not need to receive
+ * it as an argument on every call.
+ * Initialised once at device probe via camss_mod_ops::acquire().
+ * @in_width/@in_height are latched from struct camss_pp_cfg on
+ * camss_mod_ops::config() and reused by apply_params() for modules (e.g.
+ * LSC) whose per-frame register values depend on the input frame size.
+ *
+ * @base: MMIO base of the IFE PP register block.
+ * @in_width: Input frame width in pixels, latched from the last @config call.
+ * @in_height: Input frame height in pixels, latched from the last @config call.
+ * @dev: Device used for allocating @params_scratch and diagnostics.
+ * @params_scratch: Scratch buffer used to validate/stage an apply_params() buffer.
+ */
+struct ife_pp_ctx {
+ void __iomem *base;
+ u32 in_width;
+ u32 in_height;
+ struct device *dev;
+ struct v4l2_isp_params_buffer *params_scratch;
+};
+
+struct ife_pad_limits {
+ u32 min_width;
+ u32 min_height;
+ u32 max_width;
+ u32 max_height;
+ u32 max_h_ratio;
+ u32 max_v_ratio;
+};
+
+struct ife_pad_desc {
+ u16 pad_flags;
+ struct camss_formats sup_fmts;
+ const struct ife_pad_limits *limits;
+
+ const char *video_name;
+ u32 link_flags;
+
+ enum v4l2_buf_type buf_type;
+ enum camss_ife_output output;
+ u32 hw_pipe;
+
+ u8 packing_fmt;
+ u8 mode_config;
+
+ u32 rup_group_mask;
+ u32 comp_group_mask;
+
+ u8 num_wms;
+ u8 wm[IFE_HW_PLANES];
+};
+
+struct ife_pads_descriptors {
+ unsigned int num_desc;
+ const struct ife_pad_desc *desc;
+};
+
+enum ife_subdev_type {
+ CAMSS_IFE_SUBDEV_TYPE_IFE = 0,
+ CAMSS_IFE_SUBDEV_TYPE_IFE_LITE,
+};
+
+struct camss_ife_stream {
+ u32 id;
+ enum camss_ife_hw_pipe pipe;
+};
+
+struct ife_subdev_resources {
+ enum ife_subdev_type type;
+ const struct ife_hw_top_ops *top_ops;
+ const struct ife_hw_camif_ops *camif_ops;
+ const struct camss_mod_ops *mod_ops;
+ const struct ife_hw_buswr_ops *buswr_ops;
+ const struct ife_pads_descriptors *pads;
+
+ unsigned int num_sink_streams;
+ const struct camss_ife_stream *sink_streams;
+};
+
+struct ife_video_pad {
+ struct ife_device *ife;
+ u32 pad_index;
+
+ struct camss_video video;
+ bool streaming;
+
+ struct list_head pending_bufs;
+ struct list_head processing_bufs;
+};
+
+struct ife_subdev_pads {
+ const struct ife_pad_desc *desc;
+ struct v4l2_mbus_framefmt fmt;
+ struct ife_video_pad *vid_pad;
+};
+
+struct ife_device {
+ u8 id;
+ struct camss *camss;
+ struct ife_top_ctx top_ctx;
+ struct ife_buswr_ctx buswr_ctx;
+ struct ife_pp_ctx pp_ctx;
+
+ const struct ife_subdev_resources *res;
+ u32 irq;
+ char irq_name[sizeof(((struct v4l2_subdev *)0)->name)];
+
+ int nclocks;
+ struct camss_clock *clock;
+
+ struct completion reset_complete;
+
+ struct mutex state_mutex; /* Protects all pad states */
+ spinlock_t bufs_lock; /* Protects buffer lists */
+ unsigned int stream_count;
+
+ struct ife_subdev_pads *pads;
+ struct media_pad *mpads;
+ int npads;
+ u32 sink_pad;
+
+ struct {
+ unsigned int stream_count;
+ u32 next_seq;
+ } camif_data[IFE_CAMIF_HW_PIPES_MAX];
+
+ struct camss_ife_pipeline_cfg pipeline_cfg[IFE_CAMIF_HW_PIPES_MAX];
+
+ struct v4l2_subdev sd;
+ struct device *genpd;
+ struct device_link *genpd_link;
+};
+
+int camss_ife_subdev_init(struct camss *camss, struct ife_device *ife,
+ const struct camss_subdev_resources *res, u8 id,
+ void __iomem *csid_base);
+
+int ife_register_entities(struct ife_device *ife, struct v4l2_device *v4l2_dev);
+void ife_unregister_entities(struct ife_device *ife);
+
+int ife_get(struct ife_device *ife);
+void ife_put(struct ife_device *ife);
+
+int camss_ife_link_entities(struct camss *camss);
+
+u32 camss_ife_stream_id_for_pipe(int nstreams,
+ const struct camss_ife_stream *streams,
+ enum camss_ife_hw_pipe pipe);
+enum camss_ife_hw_pipe
+camss_ife_pipe_for_stream_id(int nstreams,
+ const struct camss_ife_stream *streams,
+ u32 id);
+
+#endif /* CAMSS_IFE_SUB_DEV_H */
--
2.34.1