Re: [PATCH v4 6/7] media: qcom: camss: Add CAMSS Offline Processing Engine driver
Bryan O'Donoghue <[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 | <[email protected]> |
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. > 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. > +#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 ? I think you should check again. Same comment for each of these blocks HW_VERSION should be the first register. --- bod