* [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340
@ 2026-03-13 13:17 Loic Poulain
2026-03-13 13:17 ` [PATCH v4 1/5] media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL registers Loic Poulain
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
Add PIX-path support to the CAMSS pipeline on CSID-340 and VFE-340,
allowing frames to be routed to the VFE PIX interface and exposed
through PIX output devices such as msm_vfe0_pix.
On CM2290/TFE, the PIX interface includes a minimal inline processing
engine, which we will be able to leverage later to export statistics
needed for proper 3A frame processing. This also fixes the PIX path
not being usable on this platform, as PIX routing was previously
unsupported, causing frame capture hangs.
Changes in V4:
- Remove unnecessary boundary check for wm-to-client
- Remove stray \n and fix commit subject for 2/5
- Add proper define for PIX pad index in csid-340
Changes in V3:
- Introduce what PIX is/means in 2/5 as discussed with Dmitry.
- Fix patches format/encoding (proper ASCII)
Changes in V2:
- Fix various typos, extra spaces, and reword commit messages.
- Split the CSID-340 patch into three independent changes.
- Make VC/DT-ID configuration explicit in the CSID/PIX setup.
- Add the csid_vc_iface_map helper to retrieve the interface offset
from a Virtual Channel (VC).
- Add cropping configuration in the VFE/PIX path so that it
respects the crop parameters defined in camss-vfe.
Loic Poulain (5):
media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL
registers
media: qcom: camss: csid-340: Add VC-to-interface mapping
media: qcom: camss: csid-340: Enable PIX interface routing
media: qcom: camss: vfe-340: Proper client handling
media: qcom: camss: vfe-340: Support for PIX client
.../platform/qcom/camss/camss-csid-340.c | 109 ++++++++----
.../media/platform/qcom/camss/camss-vfe-340.c | 155 +++++++++++++-----
2 files changed, 187 insertions(+), 77 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/5] media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL registers
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
@ 2026-03-13 13:17 ` Loic Poulain
2026-03-13 13:17 ` [PATCH v4 2/5] media: qcom: camss: csid-340: Add VC-to-interface mapping Loic Poulain
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
The former RDI-specific register definitions (CSID_RDI_CFG0/CTRL) are
renamed to unified CSID_CFG0/CSID_CTRL variants, as their layout is
interface agnostic. This refactoring provides the foundation for
extending csid-340 with missing PIX interface/path support.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
.../platform/qcom/camss/camss-csid-340.c | 43 ++++++++++---------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-csid-340.c b/drivers/media/platform/qcom/camss/camss-csid-340.c
index 2b50f9b96a34..adcbe3e01d62 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-340.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-340.c
@@ -41,19 +41,20 @@
#define CSI2_RX_CFG1_MISR_EN BIT(6)
#define CSI2_RX_CFG1_CGC_MODE BIT(7)
-#define CSID_RDI_CFG0(rdi) (0x300 + 0x100 * (rdi))
-#define CSID_RDI_CFG0_BYTE_CNTR_EN BIT(0)
-#define CSID_RDI_CFG0_TIMESTAMP_EN BIT(1)
-#define CSID_RDI_CFG0_DECODE_FORMAT_MASK GENMASK(15, 12)
-#define CSID_RDI_CFG0_DECODE_FORMAT_NOP CSID_RDI_CFG0_DECODE_FORMAT_MASK
-#define CSID_RDI_CFG0_DT_MASK GENMASK(21, 16)
-#define CSID_RDI_CFG0_VC_MASK GENMASK(23, 22)
-#define CSID_RDI_CFG0_DTID_MASK GENMASK(28, 27)
-#define CSID_RDI_CFG0_ENABLE BIT(31)
-
-#define CSID_RDI_CTRL(rdi) (0x308 + 0x100 * (rdi))
-#define CSID_RDI_CTRL_HALT_AT_FRAME_BOUNDARY 0
-#define CSID_RDI_CTRL_RESUME_AT_FRAME_BOUNDARY 1
+#define CSID_CFG0(iface) (0x300 + 0x100 * (iface))
+#define CSID_CFG0_BYTE_CNTR_EN BIT(0)
+#define CSID_CFG0_TIMESTAMP_EN BIT(1)
+#define CSID_CFG0_DECODE_FORMAT_MASK GENMASK(15, 12)
+#define CSID_CFG0_DECODE_FORMAT_NOP CSID_CFG0_DECODE_FORMAT_MASK
+#define CSID_CFG0_DT_MASK GENMASK(21, 16)
+#define CSID_CFG0_VC_MASK GENMASK(23, 22)
+#define CSID_CFG0_DTID_MASK GENMASK(28, 27)
+#define CSID_CFG0_ENABLE BIT(31)
+
+#define CSID_CTRL(iface) (0x308 + 0x100 * (iface))
+#define CSID_CTRL_HALT_AT_FRAME_BOUNDARY 0
+#define CSID_CTRL_RESUME_AT_FRAME_BOUNDARY 1
+
static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config *phy)
{
@@ -71,7 +72,7 @@ static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config
static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi)
{
- writel_relaxed(!!enable, csid->base + CSID_RDI_CTRL(rdi));
+ writel_relaxed(!!enable, csid->base + CSID_CTRL(rdi));
}
static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)
@@ -88,7 +89,7 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8
* the four least significant bits of the five bit VC
* bitfield to generate an internal CID value.
*
- * CSID_RDI_CFG0(vc)
+ * CSID_CFG0(vc)
* DT_ID : 28:27
* VC : 26:22
* DT : 21:16
@@ -97,18 +98,18 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8
*/
dt_id = vc & 0x03;
- val = CSID_RDI_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */
- val |= FIELD_PREP(CSID_RDI_CFG0_DT_MASK, format->data_type);
- val |= FIELD_PREP(CSID_RDI_CFG0_VC_MASK, vc);
- val |= FIELD_PREP(CSID_RDI_CFG0_DTID_MASK, dt_id);
+ val = CSID_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */
+ val |= FIELD_PREP(CSID_CFG0_DT_MASK, format->data_type);
+ val |= FIELD_PREP(CSID_CFG0_VC_MASK, vc);
+ val |= FIELD_PREP(CSID_CFG0_DTID_MASK, dt_id);
if (enable)
- val |= CSID_RDI_CFG0_ENABLE;
+ val |= CSID_CFG0_ENABLE;
dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n",
csid->id, enable ? "enable" : "disable", format->data_type, vc);
- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
+ writel_relaxed(val, csid->base + CSID_CFG0(vc));
}
static void csid_configure_stream(struct csid_device *csid, u8 enable)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/5] media: qcom: camss: csid-340: Add VC-to-interface mapping
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
2026-03-13 13:17 ` [PATCH v4 1/5] media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL registers Loic Poulain
@ 2026-03-13 13:17 ` Loic Poulain
2026-03-13 13:17 ` [PATCH v4 3/5] media: qcom: camss: csid-340: Enable PIX interface routing Loic Poulain
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
The CSID-340 block uses different register offsets for the PIX and RDI
interfaces, but the driver previously indexed these registers directly
with the VC number. This happened to work for RDI because the VC index
matches the RDI register layout, but this assumption breaks with upcoming
PIX interface support
Introduce an explicit VC-to-interface mapping and use the mapped iface
index when programming CSID_CFG0 and CSID_CTRL. This replaces the
standalone __csid_ctrl_rdi() helper and simplifies the RDI stream setup
path.
Also correct the CSID_CFG0/CTRL base offsets and clean up the code in
preparation for full PIX path support.
Like RDI, PIX outputs Bayer frames but can also achieve some image
processing such as scaling, cropping and generating statitics (e.g.
histogram), it also offer more flexebility in term of image alignment
and stride. All of that can then later be leveraged to improve
software or hardware frames post-processing.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
.../platform/qcom/camss/camss-csid-340.c | 42 ++++++++++++-------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-csid-340.c b/drivers/media/platform/qcom/camss/camss-csid-340.c
index adcbe3e01d62..ef13c4c50ab2 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-340.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-340.c
@@ -41,7 +41,7 @@
#define CSI2_RX_CFG1_MISR_EN BIT(6)
#define CSI2_RX_CFG1_CGC_MODE BIT(7)
-#define CSID_CFG0(iface) (0x300 + 0x100 * (iface))
+#define CSID_CFG0(iface) (0x200 + 0x100 * (iface))
#define CSID_CFG0_BYTE_CNTR_EN BIT(0)
#define CSID_CFG0_TIMESTAMP_EN BIT(1)
#define CSID_CFG0_DECODE_FORMAT_MASK GENMASK(15, 12)
@@ -51,10 +51,24 @@
#define CSID_CFG0_DTID_MASK GENMASK(28, 27)
#define CSID_CFG0_ENABLE BIT(31)
-#define CSID_CTRL(iface) (0x308 + 0x100 * (iface))
+#define CSID_CTRL(iface) (0x208 + 0x100 * (iface))
#define CSID_CTRL_HALT_AT_FRAME_BOUNDARY 0
#define CSID_CTRL_RESUME_AT_FRAME_BOUNDARY 1
+#define CSID_MAX_RDI_SRC_STREAMS (MSM_CSID_MAX_SRC_STREAMS - 1)
+
+enum csid_iface {
+ CSID_IFACE_PIX,
+ CSID_IFACE_RDI0,
+ CSID_IFACE_RDI1,
+ CSID_IFACE_RDI2,
+};
+
+static enum csid_iface csid_vc_iface_map[CSID_MAX_RDI_SRC_STREAMS] = {
+ [0] = CSID_IFACE_RDI0,
+ [1] = CSID_IFACE_RDI1,
+ [2] = CSID_IFACE_RDI2,
+};
static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config *phy)
{
@@ -70,17 +84,13 @@ static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config
writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1);
}
-static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi)
-{
- writel_relaxed(!!enable, csid->base + CSID_CTRL(rdi));
-}
-
-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)
+static void __csid_configure_rdi_stream(struct csid_device *csid, bool enable, u8 vc)
{
struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
csid->res->formats->nformats,
input_format->code);
+ enum csid_iface iface = csid_vc_iface_map[vc];
u8 dt_id;
u32 val;
@@ -106,10 +116,11 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8
if (enable)
val |= CSID_CFG0_ENABLE;
- dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n",
- csid->id, enable ? "enable" : "disable", format->data_type, vc);
+ dev_dbg(csid->camss->dev, "CSID%u: Stream %sable RDI (dt:0x%x vc:%u)\n",
+ csid->id, enable ? "en" : "dis", format->data_type, vc);
- writel_relaxed(val, csid->base + CSID_CFG0(vc));
+ writel_relaxed(val, csid->base + CSID_CFG0(iface));
+ writel_relaxed(enable, csid->base + CSID_CTRL(iface));
}
static void csid_configure_stream(struct csid_device *csid, u8 enable)
@@ -118,11 +129,10 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
__csid_configure_rx(csid, &csid->phy);
- for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) {
- if (csid->phy.en_vc & BIT(i)) {
- __csid_configure_rdi_stream(csid, enable, i);
- __csid_ctrl_rdi(csid, enable, i);
- }
+ /* RDIs */
+ for (i = 0; i < CSID_MAX_RDI_SRC_STREAMS; i++) {
+ if (csid->phy.en_vc & BIT(i))
+ __csid_configure_rdi_stream(csid, !!enable, i);
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/5] media: qcom: camss: csid-340: Enable PIX interface routing
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
2026-03-13 13:17 ` [PATCH v4 1/5] media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL registers Loic Poulain
2026-03-13 13:17 ` [PATCH v4 2/5] media: qcom: camss: csid-340: Add VC-to-interface mapping Loic Poulain
@ 2026-03-13 13:17 ` Loic Poulain
2026-03-13 13:17 ` [PATCH v4 4/5] media: qcom: camss: vfe-340: Proper client handling Loic Poulain
2026-03-13 13:17 ` [PATCH v4 5/5] media: qcom: camss: vfe-340: Support for PIX client Loic Poulain
4 siblings, 0 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
Add PIX path support to the CSID-340 driver. The hardware exposes a
dedicated PIX interface in addition to the existing RDI paths, but
the driver only supported RDI stream configuration so far.
Implements a dedicated __csid_configure_pix_stream() helper. The
PIX path is configured similarly to RDI but uses the primary stream
(VC0/DT0) and the appropriate CSID_CFG0/CSID_CTRL registers. Stream
selection logic is also updated so RDI and PIX paths are configured
independently.
The PIX pipeline can subsequently perform further processing,
including scaling, cropping, and statistics.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../platform/qcom/camss/camss-csid-340.c | 34 ++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/camss/camss-csid-340.c b/drivers/media/platform/qcom/camss/camss-csid-340.c
index ef13c4c50ab2..094fdd3697ad 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-340.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-340.c
@@ -56,6 +56,8 @@
#define CSID_CTRL_RESUME_AT_FRAME_BOUNDARY 1
#define CSID_MAX_RDI_SRC_STREAMS (MSM_CSID_MAX_SRC_STREAMS - 1)
+#define CSID_PIX_SRC_STREAM CSID_MAX_RDI_SRC_STREAMS
+#define CSID_PIX_SRC_PAD (MSM_CSID_PAD_FIRST_SRC + CSID_PIX_SRC_STREAM)
enum csid_iface {
CSID_IFACE_PIX,
@@ -64,10 +66,11 @@ enum csid_iface {
CSID_IFACE_RDI2,
};
-static enum csid_iface csid_vc_iface_map[CSID_MAX_RDI_SRC_STREAMS] = {
+static enum csid_iface csid_vc_iface_map[MSM_CSID_MAX_SRC_STREAMS] = {
[0] = CSID_IFACE_RDI0,
[1] = CSID_IFACE_RDI1,
[2] = CSID_IFACE_RDI2,
+ [3] = CSID_IFACE_PIX,
};
static void __csid_configure_rx(struct csid_device *csid, struct csid_phy_config *phy)
@@ -123,6 +126,31 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, bool enable, u
writel_relaxed(enable, csid->base + CSID_CTRL(iface));
}
+static void __csid_configure_pix_stream(struct csid_device *csid, bool enable)
+{
+ struct v4l2_mbus_framefmt *input_format = &csid->fmt[CSID_PIX_SRC_PAD];
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+ u32 val;
+
+ val = FIELD_PREP(CSID_CFG0_DECODE_FORMAT_MASK, format->decode_format);
+ val |= FIELD_PREP(CSID_CFG0_DT_MASK, format->data_type);
+
+ /* For PIX we use the same VC/DTID as RDI0 (0) to capture the main stream */
+ val |= FIELD_PREP(CSID_CFG0_VC_MASK, 0);
+ val |= FIELD_PREP(CSID_CFG0_DTID_MASK, 0);
+
+ if (enable)
+ val |= CSID_CFG0_ENABLE;
+
+ dev_dbg(csid->camss->dev, "CSID%u: Stream %sable PIX (dt:0x%x df:0x%x)\n",
+ csid->id, enable ? "en" : "dis", format->data_type, format->decode_format);
+
+ writel_relaxed(val, csid->base + CSID_CFG0(CSID_IFACE_PIX));
+ writel_relaxed(enable, csid->base + CSID_CTRL(CSID_IFACE_PIX));
+}
+
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
int i;
@@ -134,6 +162,10 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
if (csid->phy.en_vc & BIT(i))
__csid_configure_rdi_stream(csid, !!enable, i);
}
+
+ /* PIX */
+ if (csid->phy.en_vc & BIT(CSID_PIX_SRC_STREAM))
+ __csid_configure_pix_stream(csid, !!enable);
}
static int csid_reset(struct csid_device *csid)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 4/5] media: qcom: camss: vfe-340: Proper client handling
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
` (2 preceding siblings ...)
2026-03-13 13:17 ` [PATCH v4 3/5] media: qcom: camss: csid-340: Enable PIX interface routing Loic Poulain
@ 2026-03-13 13:17 ` Loic Poulain
2026-03-13 13:17 ` [PATCH v4 5/5] media: qcom: camss: vfe-340: Support for PIX client Loic Poulain
4 siblings, 0 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
We need to properly map camss WM index to our internal WM client
instance. Today we only support RDI interfaces with the RDI_WM
macro, introduce a __wm_to_client helper to support any interface.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../media/platform/qcom/camss/camss-vfe-340.c | 84 ++++++++++---------
1 file changed, 43 insertions(+), 41 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 30d7630b3e8b..d129b0d3a6ed 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -69,24 +69,19 @@
#define TFE_BUS_FRAMEDROP_CFG_0(c) BUS_REG(0x238 + (c) * 0x100)
#define TFE_BUS_FRAMEDROP_CFG_1(c) BUS_REG(0x23c + (c) * 0x100)
-/*
- * TODO: differentiate the port id based on requested type of RDI, BHIST etc
- *
- * TFE write master IDs (clients)
- *
- * BAYER 0
- * IDEAL_RAW 1
- * STATS_TINTLESS_BG 2
- * STATS_BHIST 3
- * STATS_AWB_BG 4
- * STATS_AEC_BG 5
- * STATS_BAF 6
- * RDI0 7
- * RDI1 8
- * RDI2 9
- */
-#define RDI_WM(n) (7 + (n))
-#define TFE_WM_NUM 10
+enum tfe_client {
+ TFE_CLI_BAYER,
+ TFE_CLI_IDEAL_RAW,
+ TFE_CLI_STATS_TINTLESS_BG,
+ TFE_CLI_STATS_BHIST,
+ TFE_CLI_STATS_AWB_BG,
+ TFE_CLI_STATS_AEC_BG,
+ TFE_CLI_STATS_BAF,
+ TFE_CLI_RDI0,
+ TFE_CLI_RDI1,
+ TFE_CLI_RDI2,
+ TFE_CLI_NUM
+};
enum tfe_iface {
TFE_IFACE_PIX,
@@ -108,6 +103,13 @@ enum tfe_subgroups {
TFE_SUBGROUP_NUM
};
+static enum tfe_client tfe_wm_client_map[VFE_LINE_NUM_MAX] = {
+ [VFE_LINE_RDI0] = TFE_CLI_RDI0,
+ [VFE_LINE_RDI1] = TFE_CLI_RDI1,
+ [VFE_LINE_RDI2] = TFE_CLI_RDI2,
+ [VFE_LINE_PIX] = TFE_CLI_BAYER,
+};
+
static enum tfe_iface tfe_line_iface_map[VFE_LINE_NUM_MAX] = {
[VFE_LINE_RDI0] = TFE_IFACE_RDI0,
[VFE_LINE_RDI1] = TFE_IFACE_RDI1,
@@ -209,10 +211,10 @@ static irqreturn_t vfe_isr(int irq, void *dev)
status = readl_relaxed(vfe->base + TFE_BUS_OVERFLOW_STATUS);
if (status) {
writel_relaxed(status, vfe->base + TFE_BUS_STATUS_CLEAR);
- for (i = 0; i < TFE_WM_NUM; i++) {
+ for (i = 0; i < TFE_CLI_NUM; i++) {
if (status & BIT(i))
dev_err_ratelimited(vfe->camss->dev,
- "VFE%u: bus overflow for wm %u\n",
+ "VFE%u: bus overflow for client %u\n",
vfe->id, i);
}
}
@@ -235,49 +237,49 @@ static void vfe_enable_irq(struct vfe_device *vfe)
TFE_BUS_IRQ_MASK_0_IMG_VIOL, vfe->base + TFE_BUS_IRQ_MASK_0);
}
-static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
struct vfe_line *line)
{
- u8 wm = RDI_WM(rdi);
+ u8 client = tfe_wm_client_map[wm];
- writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(wm));
+ writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(client));
}
-static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line)
+static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
{
struct v4l2_pix_format_mplane *pix = &line->video_out.active_fmt.fmt.pix_mp;
u32 stride = pix->plane_fmt[0].bytesperline;
- u8 wm = RDI_WM(rdi);
+ u8 client = tfe_wm_client_map[wm];
/* Configuration for plain RDI frames */
- writel_relaxed(TFE_BUS_IMAGE_CFG_0_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_0(wm));
- writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(wm));
- writel_relaxed(TFE_BUS_IMAGE_CFG_2_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_2(wm));
- writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(wm));
- writel_relaxed(TFE_BUS_PACKER_CFG_FMT_PLAIN64, vfe->base + TFE_BUS_PACKER_CFG(wm));
+ writel_relaxed(TFE_BUS_IMAGE_CFG_0_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_0(client));
+ writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(client));
+ writel_relaxed(TFE_BUS_IMAGE_CFG_2_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_2(client));
+ writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(client));
+ writel_relaxed(TFE_BUS_PACKER_CFG_FMT_PLAIN64, vfe->base + TFE_BUS_PACKER_CFG(client));
/* No dropped frames, one irq per frame */
- writel_relaxed(0, vfe->base + TFE_BUS_FRAMEDROP_CFG_0(wm));
- writel_relaxed(1, vfe->base + TFE_BUS_FRAMEDROP_CFG_1(wm));
- writel_relaxed(0, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_0(wm));
- writel_relaxed(1, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_1(wm));
+ writel_relaxed(0, vfe->base + TFE_BUS_FRAMEDROP_CFG_0(client));
+ writel_relaxed(1, vfe->base + TFE_BUS_FRAMEDROP_CFG_1(client));
+ writel_relaxed(0, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_0(client));
+ writel_relaxed(1, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_1(client));
vfe_enable_irq(vfe);
writel(TFE_BUS_CLIENT_CFG_EN | TFE_BUS_CLIENT_CFG_MODE_FRAME,
- vfe->base + TFE_BUS_CLIENT_CFG(wm));
+ vfe->base + TFE_BUS_CLIENT_CFG(client));
- dev_dbg(vfe->camss->dev, "VFE%u: Started RDI%u width %u height %u stride %u\n",
- vfe->id, rdi, pix->width, pix->height, stride);
+ dev_dbg(vfe->camss->dev, "VFE%u: Started client %u width %u height %u stride %u\n",
+ vfe->id, client, pix->width, pix->height, client);
}
-static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
{
- u8 wm = RDI_WM(rdi);
+ u8 client = tfe_wm_client_map[wm];
- writel(0, vfe->base + TFE_BUS_CLIENT_CFG(wm));
+ writel(0, vfe->base + TFE_BUS_CLIENT_CFG(client));
- dev_dbg(vfe->camss->dev, "VFE%u: Stopped RDI%u\n", vfe->id, rdi);
+ dev_dbg(vfe->camss->dev, "VFE%u: Stopped client %u\n", vfe->id, client);
}
static const struct camss_video_ops vfe_video_ops_520 = {
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 5/5] media: qcom: camss: vfe-340: Support for PIX client
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
` (3 preceding siblings ...)
2026-03-13 13:17 ` [PATCH v4 4/5] media: qcom: camss: vfe-340: Proper client handling Loic Poulain
@ 2026-03-13 13:17 ` Loic Poulain
4 siblings, 0 replies; 6+ messages in thread
From: Loic Poulain @ 2026-03-13 13:17 UTC (permalink / raw)
To: bryan.odonoghue, vladimir.zapolskiy
Cc: linux-media, linux-arm-msm, mchehab, konrad.dybcio,
dmitry.baryshkov, Loic Poulain
Add support for the vfe-340 PIX write engine, enabling frame capture
through the PIX video device (e.g. msm_vfe0_pix). The PIX path requires
a separate configuration flow from RDI, including cropping setup, line-
based write engine configuration, and the correct packer format based
on the input pixel format.
In contrast to RDI, the PIX interface embeds a lightweight processing
engine we can use for cropping, configuring custom stride/alignment,
and, in the future, extracting frame statistics.
The functionality has been validated on Arduino-Uno-Q with:
media-ctl -d /dev/media0 --reset
media-ctl -d /dev/media0 -l '"msm_csiphy0":1->"msm_csid0":0[1],"msm_csid0":4->"msm_vfe0_pix":0[1]'
media-ctl -d /dev/media0 -V '"imx219 1-0010":0[fmt:SRGGB8_1X8/640x480 field:none]'
media-ctl -d /dev/media0 -V '"msm_csiphy0":0[fmt:SRGGB8_1X8/640x480 field:none]'
media-ctl -d /dev/media0 -V '"msm_csid0":0[fmt:SRGGB8_1X8/640x480 field:none]'
media-ctl -d /dev/media0 -V '"msm_vfe0_pix":0[fmt:SRGGB8_1X8/640x480 field:none]'
yavta -B capture-mplane --capture=3 -n 3 -f SRGGB8 -s 640x480 /dev/video3
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
.../media/platform/qcom/camss/camss-vfe-340.c | 85 ++++++++++++++++---
1 file changed, 75 insertions(+), 10 deletions(-)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index d129b0d3a6ed..600c472534fb 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -54,6 +54,7 @@
#define TFE_BUS_CLIENT_CFG(c) BUS_REG(0x200 + (c) * 0x100)
#define TFE_BUS_CLIENT_CFG_EN BIT(0)
+#define TFE_BUS_CLIENT_CFG_AUTORECOVER BIT(4)
#define TFE_BUS_CLIENT_CFG_MODE_FRAME BIT(16)
#define TFE_BUS_IMAGE_ADDR(c) BUS_REG(0x204 + (c) * 0x100)
#define TFE_BUS_FRAME_INCR(c) BUS_REG(0x208 + (c) * 0x100)
@@ -63,12 +64,23 @@
#define TFE_BUS_IMAGE_CFG_2(c) BUS_REG(0x214 + (c) * 0x100)
#define TFE_BUS_IMAGE_CFG_2_DEFAULT 0xffff
#define TFE_BUS_PACKER_CFG(c) BUS_REG(0x218 + (c) * 0x100)
+#define TFE_BUS_PACKER_CFG_FMT_PLAIN8 0x1
#define TFE_BUS_PACKER_CFG_FMT_PLAIN64 0xa
+#define TFE_BUS_PACKER_CFG_FMT_MIPI10 0xc
+#define TFE_BUS_PACKER_CFG_FMT_MIPI12 0xd
#define TFE_BUS_IRQ_SUBSAMPLE_CFG_0(c) BUS_REG(0x230 + (c) * 0x100)
#define TFE_BUS_IRQ_SUBSAMPLE_CFG_1(c) BUS_REG(0x234 + (c) * 0x100)
#define TFE_BUS_FRAMEDROP_CFG_0(c) BUS_REG(0x238 + (c) * 0x100)
#define TFE_BUS_FRAMEDROP_CFG_1(c) BUS_REG(0x23c + (c) * 0x100)
+#define PP_CROP_REG(a) (0x2800 + (a))
+#define TFE_PP_CROP_CFG PP_CROP_REG(0x60)
+#define TFE_PP_CROP_CFG_EN (BIT(0) | BIT(9))
+#define TFE_PP_CROP_LINE_CFG PP_CROP_REG(0x68)
+#define TFE_PP_CROP_FIRST GENMASK(29, 16)
+#define TFE_PP_CROP_LAST GENMASK(13, 0)
+#define TFE_PP_CROP_PIX_CFG PP_CROP_REG(0x6C)
+
enum tfe_client {
TFE_CLI_BAYER,
TFE_CLI_IDEAL_RAW,
@@ -245,18 +257,72 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(client));
}
+static u32 vfe_packer_format(struct vfe_device *vfe, u32 pixelformat)
+{
+ const struct camss_formats *fmt = vfe->res->formats_rdi;
+ int i;
+
+ for (i = 0; i < fmt->nformats; i++)
+ if (fmt->formats[i].pixelformat == pixelformat)
+ break;
+
+ if (i >= fmt->nformats)
+ return TFE_BUS_PACKER_CFG_FMT_PLAIN64;
+
+ switch (fmt->formats[i].mbus_bpp) {
+ case 8:
+ return TFE_BUS_PACKER_CFG_FMT_PLAIN8;
+ case 10:
+ return TFE_BUS_PACKER_CFG_FMT_MIPI10;
+ case 12:
+ return TFE_BUS_PACKER_CFG_FMT_MIPI12;
+ default:
+ dev_err(vfe->camss->dev, "VFE%u: Unsupported pixelformat", vfe->id);
+ }
+
+ return TFE_BUS_PACKER_CFG_FMT_PLAIN64;
+}
+
static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
{
struct v4l2_pix_format_mplane *pix = &line->video_out.active_fmt.fmt.pix_mp;
u32 stride = pix->plane_fmt[0].bytesperline;
u8 client = tfe_wm_client_map[wm];
-
- /* Configuration for plain RDI frames */
- writel_relaxed(TFE_BUS_IMAGE_CFG_0_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_0(client));
- writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(client));
- writel_relaxed(TFE_BUS_IMAGE_CFG_2_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_2(client));
- writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(client));
- writel_relaxed(TFE_BUS_PACKER_CFG_FMT_PLAIN64, vfe->base + TFE_BUS_PACKER_CFG(client));
+ u32 cfg = TFE_BUS_CLIENT_CFG_EN;
+
+ if (client == TFE_CLI_BAYER) { /* PIX - Line based */
+ struct v4l2_rect *crop = &line->crop;
+
+ /* Cropping */
+ writel_relaxed(TFE_PP_CROP_CFG_EN, vfe->base + TFE_PP_CROP_CFG);
+ writel_relaxed(FIELD_PREP(TFE_PP_CROP_FIRST, crop->top) |
+ FIELD_PREP(TFE_PP_CROP_LAST, crop->top + crop->height - 1),
+ vfe->base + TFE_PP_CROP_LINE_CFG);
+ writel_relaxed(FIELD_PREP(TFE_PP_CROP_FIRST, crop->left) |
+ FIELD_PREP(TFE_PP_CROP_LAST, crop->left + crop->width - 1),
+ vfe->base + TFE_PP_CROP_PIX_CFG);
+
+ /* Write Engine */
+ writel_relaxed(pix->width + (pix->height << 16),
+ vfe->base + TFE_BUS_IMAGE_CFG_0(client));
+ writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(client));
+ writel_relaxed(stride, vfe->base + TFE_BUS_IMAGE_CFG_2(client));
+ writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(client));
+ writel_relaxed(vfe_packer_format(vfe, pix->pixelformat),
+ vfe->base + TFE_BUS_PACKER_CFG(client));
+
+ cfg |= TFE_BUS_CLIENT_CFG_AUTORECOVER;
+ } else { /* RDI - Frame based */
+ writel_relaxed(TFE_BUS_IMAGE_CFG_0_DEFAULT,
+ vfe->base + TFE_BUS_IMAGE_CFG_0(client));
+ writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(client));
+ writel_relaxed(TFE_BUS_IMAGE_CFG_2_DEFAULT,
+ vfe->base + TFE_BUS_IMAGE_CFG_2(client));
+ writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(client));
+ writel_relaxed(TFE_BUS_PACKER_CFG_FMT_PLAIN64,
+ vfe->base + TFE_BUS_PACKER_CFG(client));
+ cfg |= TFE_BUS_CLIENT_CFG_MODE_FRAME;
+ }
/* No dropped frames, one irq per frame */
writel_relaxed(0, vfe->base + TFE_BUS_FRAMEDROP_CFG_0(client));
@@ -266,11 +332,10 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
vfe_enable_irq(vfe);
- writel(TFE_BUS_CLIENT_CFG_EN | TFE_BUS_CLIENT_CFG_MODE_FRAME,
- vfe->base + TFE_BUS_CLIENT_CFG(client));
+ writel(cfg, vfe->base + TFE_BUS_CLIENT_CFG(client));
dev_dbg(vfe->camss->dev, "VFE%u: Started client %u width %u height %u stride %u\n",
- vfe->id, client, pix->width, pix->height, client);
+ vfe->id, client, pix->width, pix->height, stride);
}
static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-03-13 13:18 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-13 13:17 [PATCH v4 0/5] media: qcom: camss: Add PIX support for CSID/VFE-340 Loic Poulain
2026-03-13 13:17 ` [PATCH v4 1/5] media: qcom: camss: csid-340: Switch to generic CSID_CFG/CTRL registers Loic Poulain
2026-03-13 13:17 ` [PATCH v4 2/5] media: qcom: camss: csid-340: Add VC-to-interface mapping Loic Poulain
2026-03-13 13:17 ` [PATCH v4 3/5] media: qcom: camss: csid-340: Enable PIX interface routing Loic Poulain
2026-03-13 13:17 ` [PATCH v4 4/5] media: qcom: camss: vfe-340: Proper client handling Loic Poulain
2026-03-13 13:17 ` [PATCH v4 5/5] media: qcom: camss: vfe-340: Support for PIX client Loic Poulain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox