[PATCH 54/74] media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock

From: Bryan O'Donoghue

Date: Mon Oct 05 2026 - 13:35:26 EST


vfe_wm_start() runs from vfe_enable_output_v2() with output_lock held
and interrupts disabled. Calling vfe_880_setup_pixel_pipe() from there
put about 3.3k register writes in that window on every STREAMON, most
of them gamma, BHIST and downscaler table uploads.

Add an optional vfe_line_prepare() hw op. vfe_enable_v2() calls it once
vfe_get_output_v2() has reserved the line's outputs and before
vfe_enable_output_v2() takes the lock. vfe-880 uses it to program the
NV12 pixel pipe.

The ordering is unchanged: the pipe is still written before the write
masters and before the IPP reg update that latches both, and the CSID
still resumes the IPP afterwards. Doing it after the reservation means
a line whose outputs are busy fails without touching a pipe that might
be in use.

Signed-off-by: Bryan O'Donoghue <bod@xxxxxxxxxx>
---
drivers/media/platform/qcom/camss/camss-vfe-880-pp.c | 2 +-
drivers/media/platform/qcom/camss/camss-vfe.c | 3 +++
drivers/media/platform/qcom/camss/camss-vfe.h | 7 +++++++
3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
index 8f56e584b180b..a4bccedb4a2f1 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
@@ -593,7 +593,7 @@ static void vfe_setup_ds16(struct vfe_device *vfe, u32 w, u32 h)
writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH2_CLAMP_MAX);
}

-/* Called from vfe_wm_start() for NV12, ahead of the write masters and the IPP reg update */
+/* Called from vfe_line_prepare() for NV12, ahead of the write masters and the IPP reg update */
void vfe_880_setup_pixel_pipe(struct vfe_device *vfe, u32 w, u32 h)
{
vfe_setup_core_config(vfe);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index fbc2068b301bc..82a23be7cae9c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -821,6 +821,9 @@ int vfe_enable_v2(struct vfe_line *line)
if (ret < 0)
goto error_get_output;

+ if (ops->vfe_line_prepare)
+ ops->vfe_line_prepare(line);
+
ret = vfe_enable_output_v2(line);
if (ret < 0)
goto error_enable_output;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0b632479cefc6..318b025702007 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -188,6 +188,13 @@ struct vfe_hw_ops {
void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
struct vfe_line *line);

+ /*
+ * Optional: program line-level hardware once the line's outputs are
+ * reserved, outside output_lock. Runs before vfe_wm_start() and the
+ * reg update that latches it.
+ */
+ void (*vfe_line_prepare)(struct vfe_line *line);
+
/* Output based API - new and shiny */
void (*vfe_output_start)(struct vfe_device *vfe, struct vfe_output *output);
void (*vfe_output_stop)(struct vfe_device *vfe, struct vfe_output *output);

--
2.55.0