Re: [PATCH v4 6/7] media: qcom: camss: Add CAMSS Offline Processing Engine driver

Loic Poulain <[email protected]>
Newsgroups org.kernel.vger.linux-hardening,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-media
Message-ID <CAFEp6-2nTWjU0VrMQ8D8nDzH9P-vbA1gFPimv8aX+qREWHPNow@mail.gmail.com>
On Mon, Jul 13, 2026 at 3:05 PM Bryan O'Donoghue
<[email protected]> wrote:
>
> On 10/07/2026 10:04, Loic Poulain wrote:
> > Add an image processing driver for the Qualcomm Offline Processing Engine
> > (OPE). OPE is a memory-to-memory ISP block that converts raw Bayer
> > frames to YUV, performing white balance, demosaic, chroma enhancement,
> > color correction and downscaling.
> >
> > The hardware architecture consists of Fetch Engines and Write Engines,
> > connected through intermediate pipeline modules for pix processing.
> >
> > The driver exposes three video nodes per pipeline instance:
> >    - ope_input: Bayer RAW input (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> >    - ope_disp_output: YUV output     (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> >    - ope_params: ISP parameters (V4L2_BUF_TYPE_META_OUTPUT)
> >
> > Hardware features:
> >    - Stripe-based processing (up to 336 pixels wide per stripe)
> >    - White balance (CLC_WB)
> >    - Demosaic / Bayer-to-RGB (CLC_DEMO)
> >    - RGB-to-YUV conversion (CLC_CHROMA_ENHAN)
> >    - Color correction matrix (CLC_CC)
> >    - MN downscaler for chroma and luma planes
> >
> > Default configuration values are based on public standards such as BT.601.
> >
> > Processing Model:
> > OPE processes frames in stripes of up to 336 pixels. Therefore, frames must
> > be split into stripes for processing. Each stripe is configured after the
> > previous one has been acquired (double buffered registers). To minimize
> > inter-stripe latency, stripe configurations are generated ahead of time.
> >
> > Signed-off-by: Loic Poulain <[email protected]>
> > Co-developed-by: Hans de Goede <[email protected]>
> > Signed-off-by: Hans de Goede <[email protected]>
> > ---
> >   drivers/media/platform/qcom/camss/Kconfig     |   18 +
> >   drivers/media/platform/qcom/camss/Makefile    |    4 +
> >   drivers/media/platform/qcom/camss/camss-ope.c | 3245 +++++++++++++++++++++++++
>
> I think this should be in a sub-directory.

You mean a OPE specific directory or a kind of offline engine generic one like:
drivers/media/platform/qcom/camss/offline/ope.c ?

>
> >   3 files changed, 3267 insertions(+)
> >
> > diff --git a/drivers/media/platform/qcom/camss/Kconfig b/drivers/media/platform/qcom/camss/Kconfig
> > index 4eda48cb1adf049a7fb6cb59b9da3c0870fe57f4..895fc57a679655fcb6f308be1565dc6b77bbbd67 100644
> > --- a/drivers/media/platform/qcom/camss/Kconfig
> > +++ b/drivers/media/platform/qcom/camss/Kconfig
> > @@ -7,3 +7,21 @@ config VIDEO_QCOM_CAMSS
> >       select VIDEO_V4L2_SUBDEV_API
> >       select VIDEOBUF2_DMA_SG
> >       select V4L2_FWNODE
> > +
> > +config VIDEO_QCOM_CAMSS_OPE
> > +     tristate "Qualcomm Offline Processing Engine (OPE) driver"
> > +     depends on VIDEO_QCOM_CAMSS
> > +     depends on V4L_PLATFORM_DRIVERS
> > +     depends on VIDEO_DEV
> > +     depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
> > +     select V4L2_ISP
> > +     select VIDEOBUF2_DMA_CONTIG
> > +     select VIDEOBUF2_VMALLOC
> > +     help
> > +       Enable support for the Qualcomm Offline Processing Engine (OPE).
> > +       OPE is a memory-to-memory ISP block that converts raw Bayer frames
> > +       to YUV, performing white balance, demosaic, chroma enhancement and
> > +       downscaling. Found on QCM2290 and related SoCs.
> > +
> > +       To compile this driver as a module, choose M here: the module
> > +       will be called qcom-camss-ope.
> > diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> > index 5678621efb6780b67a043ec8a2e914cce02d9b98..422eebc0a86301de3f39c743fbc06c437b17ac9a 100644
> > --- a/drivers/media/platform/qcom/camss/Makefile
> > +++ b/drivers/media/platform/qcom/camss/Makefile
> > @@ -31,3 +31,7 @@ qcom-camss-objs += \
> >               camss-params.o \
> >
> >   obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o
> > +
> > +qcom-camss-ope-objs := camss-ope.o
> > +
> > +obj-$(CONFIG_VIDEO_QCOM_CAMSS_OPE) += qcom-camss-ope.o
> > diff --git a/drivers/media/platform/qcom/camss/camss-ope.c b/drivers/media/platform/qcom/camss/camss-ope.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..2c0d68cf1a637c998ebe4d3afb1fa6dbdb68f029
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-ope.c
> > @@ -0,0 +1,3245 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * camss-ope.c
> > + *
> > + * Qualcomm MSM Camera Subsystem - Offline Processing Engine
> > + *
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +/*
> > + * This driver provides driver implementation for the Qualcomm Offline
> > + * Processing Engine (OPE). OPE is a memory-to-memory hardware block
> > + * designed for image processing on a source frame. Typically, the input
> > + * frame originates from the SoC CSI capture path, though not limited to.
> > + *
> > + * The hardware architecture consists of Fetch Engines and Write Engines,
> > + * connected through intermediate pipeline modules:
> > + *   [FETCH ENGINES] => [Pipeline Modules] => [WRITE ENGINES]
> > + *
> > + * Current Configuration:
> > + *     Fetch Engine: One fetch engine is used for Bayer frame input.
> > + *     Write Engines: Two display write engines for Y and UV planes output.
> > + *
> > + * Only a subset of the pipeline modules are enabled:
> > + *   CLC_WB: White balance for channel gain configuration
> > + *   CLC_DEMO: Demosaic for Bayer to RGB conversion
> > + *   CLC_CC: Color Correct, coefficient based RGB correction
> > + *   CLC_CHROMA_ENHAN: for RGB to YUV conversion
> > + *   CLC_DOWNSCALE*: Downscaling for UV (YUV444 -> YUV422/YUV420) and YUV planes
> > + *
> > + * Default configuration values are based on public standards such as BT.601.
> > + *
> > + * Processing Model:
> > + * OPE processes frames in stripes of up to 336 pixels. Therefore, frames must
> > + * be split into stripes for processing. Each stripe is configured after the
> > + * previous one has been acquired (double buffered registers). To minimize
> > + * inter-stripe latency, the stripe configurations are generated ahead of time.
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/cleanup.h>
> > +#include <linux/clk.h>
> > +#include <linux/completion.h>
> > +#include <linux/delay.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/interconnect.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_clock.h>
> > +#include <linux/pm_domain.h>
> > +#include <linux/pm_opp.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/slab.h>
> > +#include <linux/units.h>
> > +
> > +#include <media/v4l2-device.h>
> > +#include <media/media-device.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-fh.h>
> > +#include <media/v4l2-ioctl.h>
> > +#include <media/v4l2-rect.h>
> > +
> > +#include "camss-pipeline.h"
> > +
> > +#include <media/videobuf2-dma-contig.h>
> > +#include <media/videobuf2-vmalloc.h>
> > +
> > +#include <uapi/linux/camss-config.h>
> > +
> > +#include "camss-params.h"
> > +
> > +#define OPE_NAME     "qcom-camss-ope"
> > +
> > +/* Format descriptor */
> > +struct ope_fmt {
> > +     u32             fourcc;
> > +     unsigned int    depth;
> > +     unsigned int    align;
> > +     unsigned int    num_planes;
> > +     u32             mbus_code;
> > +     unsigned int    c_hsub;
> > +     unsigned int    c_vsub;
> > +};
> > +
> > +/* Per-queue format state */
> > +struct ope_fmt_state {
> > +     const struct ope_fmt    *fmt;
> > +     unsigned int            width;
> > +     unsigned int            height;
> > +     struct v4l2_rect        crop;
> > +     unsigned int            bytesperline;
> > +     unsigned int            sizeimage;
> > +     enum v4l2_colorspace    colorspace;
> > +     enum v4l2_xfer_func     xfer_func;
> > +     enum v4l2_ycbcr_encoding        ycbcr_enc;
> > +     enum v4l2_quantization  quantization;
> > +     unsigned int            sequence;
> > +     struct v4l2_fract       timeperframe;
> > +};
> > +
> > +/* -------- Register layout -------- */
> > +
> > +#define OPE_TOP_HW_VERSION                                   0x000
> > +#define              OPE_TOP_HW_VERSION_STEP         GENMASK(15, 0)
> > +#define              OPE_TOP_HW_VERSION_REV          GENMASK(27, 16)
> > +#define              OPE_TOP_HW_VERSION_GEN          GENMASK(31, 28)
> > +#define OPE_TOP_RESET_CMD                                    0x004
> > +#define              OPE_TOP_RESET_CMD_HW            BIT(0)
> > +#define              OPE_TOP_RESET_CMD_SW            BIT(1)
> > +#define OPE_TOP_IRQ_STATUS                                   0x014
> > +#define OPE_TOP_IRQ_MASK                                     0x018
> > +#define              OPE_TOP_IRQ_STATUS_RST_DONE     BIT(0)
> > +#define              OPE_TOP_IRQ_STATUS_WE           BIT(1)
> > +#define              OPE_TOP_IRQ_STATUS_FE           BIT(2)
> > +#define              OPE_TOP_IRQ_STATUS_VIOL         BIT(3)
> > +#define              OPE_TOP_IRQ_STATUS_IDLE         BIT(4)
> > +#define OPE_TOP_IRQ_CLEAR                                    0x01c
> > +#define OPE_TOP_IRQ_CMD                                              0x024
> > +#define              OPE_TOP_IRQ_CMD_CLEAR           BIT(0)
> > +#define OPE_TOP_VIOLATION_STATUS                             0x028
> > +
> > +/* Fetch engine */
> > +#define OPE_BUS_RD_INPUT_IF_IRQ_MASK                         0x00c
> > +#define OPE_BUS_RD_INPUT_IF_IRQ_CLEAR                                0x010
> > +#define OPE_BUS_RD_INPUT_IF_IRQ_CMD                          0x014
> > +#define              OPE_BUS_RD_INPUT_IF_IRQ_CMD_CLEAR       BIT(0)
> > +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS                               0x018
> > +#define OPE_BUS_RD_INPUT_IF_CMD                                      0x01c
> > +#define              OPE_BUS_RD_INPUT_IF_CMD_GO_CMD          BIT(0)
> > +#define OPE_BUS_RD_CLIENT_0_CORE_CFG                         0x050
> > +#define              OPE_BUS_RD_CLIENT_0_CORE_CFG_EN BIT(0)
> > +#define OPE_BUS_RD_CLIENT_0_CCIF_META_DATA                   0x054
> > +#define              OPE_BUS_RD_CLIENT_0_CCIF_MD_PIX_PATTERN GENMASK(7, 2)
> > +#define OPE_BUS_RD_CLIENT_0_ADDR_IMAGE                               0x058
> > +#define OPE_BUS_RD_CLIENT_0_RD_BUFFER_SIZE                   0x05c
> > +#define OPE_BUS_RD_CLIENT_0_RD_STRIDE                                0x060
> > +#define OPE_BUS_RD_CLIENT_0_UNPACK_CFG_0                     0x064
> > +
> > +/* Write engines */
> > +#define OPE_BUS_WR_INPUT_IF_IRQ_MASK_0                               0x018
> > +#define OPE_BUS_WR_INPUT_IF_IRQ_MASK_1                               0x01c
> > +#define OPE_BUS_WR_INPUT_IF_IRQ_CLEAR_0                              0x020
> > +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0                     0x028
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_RUP_DONE       BIT(0)
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_BUF_DONE       BIT(8)
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_CONS_VIOL      BIT(28)
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_VIOL           BIT(30)
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_IMG_SZ_VIOL    BIT(31)
> > +#define OPE_BUS_WR_INPUT_IF_IRQ_CMD                          0x030
> > +#define              OPE_BUS_WR_INPUT_IF_IRQ_CMD_CLEAR       BIT(0)
> > +#define OPE_BUS_WR_VIOLATION_STATUS                          0x064
> > +#define OPE_BUS_WR_IMAGE_SIZE_VIOLATION_STATUS                       0x070
> > +#define OPE_BUS_WR_CLIENT_CFG(c)                             (0x200 + (c) * 0x100)
> > +#define              OPE_BUS_WR_CLIENT_CFG_EN                BIT(0)
> > +#define              OPE_BUS_WR_CLIENT_CFG_AUTORECOVER       BIT(4)
> > +#define OPE_BUS_WR_CLIENT_ADDR_IMAGE(c)                              (0x204 + (c) * 0x100)
> > +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_0(c)                     (0x20c + (c) * 0x100)
> > +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_1(c)                     (0x210 + (c) * 0x100)
> > +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_2(c)                     (0x214 + (c) * 0x100)
> > +#define OPE_BUS_WR_CLIENT_PACKER_CFG(c)                              (0x218 + (c) * 0x100)
> > +#define OPE_BUS_WR_CLIENT_MAX        4
> > +
> > +/* Pipeline modules */
> > +#define OPE_PP_CLC_WB_GAIN_MODULE_CFG                                (0x200 + 0x60)
>
> Can you just map the individual blocks so that we can interrogate
> HW_VERSION HW_STATUS and friends ? Those regs usually come first. I can
> see useful debugfs and/or dev_dbg() usages of those data.

Sure, will do.

> > +#define              OPE_PP_CLC_WB_GAIN_MODULE_CFG_EN        BIT(0)
> > +#define OPE_PP_CLC_WB_GAIN_WB_CFG(ch)                                (0x200 + 0x68 + 4 * (ch))
> > +#define              OPE_PP_CLC_WB_GAIN_WB_CFG_GAIN          GENMASK(14, 0)
> > +#define OPE_PP_CLC_WB_GAIN_WB_SUB_CFG(ch)                    (0x200 + 0x74 + 4 * (ch))
> > +#define              OPE_PP_CLC_WB_GAIN_WB_SUB_CFG_VAL       GENMASK(31, 20)
> > +#define OPE_PP_CLC_WB_GAIN_WB_ADD_CFG(ch)                    (0x200 + 0x80 + 4 * (ch))
> > +#define              OPE_PP_CLC_WB_GAIN_WB_ADD_CFG_VAL       GENMASK(31, 20)
> > +
> > +#define OPE_PP_CLC_CC_BASE                                   0x400
>
> Is this actually the correct register base for CCM ?

Nope, you're right.

>
> I think you should check again.
>
> Same comment for each of these blocks HW_VERSION should be the first
> register.

Ack I will define generic macro for them.

Regards,
Loic
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.