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

Reply via email to