mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650
@ 2026-10-05 17:13 Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 01/74] media: qcom: camss: vfe: Rename gen3 back to vfe780 Bryan O'Donoghue
                   ` (74 more replies)
  0 siblings, 75 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Antoine Bouyer, Niklas Söderlund, Sakari Ailus, stable

This extensive series restructures CAMSS around the idea of lines and
outputs more closely matching the concepts in the camera hardware.

To begin with some bug fixing and some dependencies on the OPE series are
pulled in.

Following that a series of changes to enable the IFE hardware is introduced
for VFE780.

Supported in this drop:

- YUV output on the pix path
  YUV downscale 16 and downscale 4 work on a staging branch
  but with this series at 60 patches I've not included that.

- Stats output
  Bayer histogram only

  How many stats are intended to be brought out this way ?
  Consider that scene in The Terminator when the guy in the gun
  store.

  Gun store owner: "So which will it be"
  The Terminator: "All"

  More seriously once this series lands then it will be possible to bring
  out stats for Agatti mitigating the need for calculating stats in
  software.

- Params application
  AEC Bayer hist params

  Again there are no limits envisaged on which params are to be enabled.

  "All"

- Testing on HDK sm8650

  There is a repo to test this stuff out:

  https://github.com/0xB0D/ife-tests

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
Antoine Bouyer (2):
      media: uapi: v4l2-isp: Add extensible statistics
      media: Documentation: uapi: Update V4L2 ISP for extensible stats

Bryan O'Donoghue (66):
      media: qcom: camss: vfe: Rename gen3 back to vfe780
      media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880
      media: qcom: camss: Fix invalid declaration of PIX for SDM670
      media: qcom: camss: Fix invalid declaration of PIX for SDM845
      media: qcom: camss: Fix invalid declaration of PIX for sc8280xp
      media: qcom: camss: Fix invalid declaration of PIX for x1e80100
      media: qcom: camss: csid: Configure the stream on every s_stream
      media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845
      media: qcom: camss: Define PIX formats for x1e PIX interface
      media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt()
      media: qcom: camss: vfe: Represent output as an array instead of a singleton
      media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output
      media: qcom: camss: vfe: Represent vfe wm inside of a struct
      media: qcom: camss: vfe: Add is_pix to struct line
      media: qcom: camss: vfe: Add comp_group to struct vfe_wm
      media: qcom: camss: vfe: Define vfe v3 completion group enum
      media: qcom: camss: vfe: Define output based VFE controls
      media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration
      media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init
      media: qcom: camss: vfe: Add planes identifier to struct wm
      media: qcom: camss: vfe: Specify number of pads via line->num_pads
      media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group
      media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group
      media: qcom: camss: vfe: Update an output group's write masters on buffer done
      media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters
      media: qcom: camss: vfe: Stop an output group once
      media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw
      media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern
      media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default()
      media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic
      media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX
      media: qcom: camss: vfe-gen3: Define full array of write-masters
      media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces
      media: qcom: camss: vfe: Pass struct line to wm_stop
      media: qcom: camss: vfe-780: Use bus-client to derive write master index
      media: qcom: camss: vfe-780: Switch on YUV pix path
      media: qcom: camss: vfe: Add support for pix pad data-types
      media: qcom: camss: vfe: Add helper methods to enumerate output descriptors
      media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done
      media: qcom: camss: Add a status field to camss_buf_done_info
      media: qcom: camss: csid-gen3: Enable the IPP path
      media: qcom: camss: vfe: Pass the completion info to vfe_buf_done()
      media: qcom: camss: vfe: Pass the buffer to vfe_wm_update()
      media: qcom: camss: Add the SM8650 IFE pixel pipe configuration
      media: qcom: camss: csid-gen3: Define the IPP reg update port in the header
      media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock
      media: qcom: camss: vfe: Make is_pix the only test for the pixel path
      media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds
      media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line
      media: uapi: Add CAMSS ISP statistics definition
      media: Documentation: uapi: Add qcom-camss ISP statistics
      media: qcom: camss: vfe: Select line-based mode for the pixel path's video node
      media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock
      media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one
      media: qcom: camss: video: Support metadata capture nodes
      media: qcom: camss: vfe: Register a statistics node for the pixel line
      media: qcom: camss: vfe: Complete pixel line outputs on their own completion group
      media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics
      media: uapi: Add the CAMSS AEC Bayer histogram configuration
      media: v4l2: Add the Qualcomm CAMSS ISP parameters format
      media: Documentation: uapi: Add the CAMSS IFE parameters
      media: qcom: camss: video: Support metadata output nodes
      media: qcom: camss: vfe: Register and apply a parameters node for the pixel line
      media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters
      media: qcom: camss: vfe-780: Drive the write masters through the output ops
      media: qcom: camss: vfe: Pass the write master its address again

Jacopo Mondi (4):
      media: v4l2-isp: Rename v4l2_isp_params_buffer_size
      media: v4l2-isp: Add per-block validation callback
      media: amlogic-c3: Implement per-block validation
      media: v4l2-isp: Add helpers for stats buffer

Loic Poulain (2):
      media: uapi: Add CAMSS ISP configuration definition
      media: Documentation: uapi: Add qcom-camss ISP params documentation

 .../userspace-api/media/v4l/meta-formats.rst       |   1 +
 .../userspace-api/media/v4l/metafmt-qcom-isp.rst   | 219 +++++
 Documentation/userspace-api/media/v4l/v4l2-isp.rst |  45 +-
 MAINTAINERS                                        |   1 +
 .../media/platform/amlogic/c3/isp/c3-isp-params.c  |  42 +-
 .../media/platform/arm/mali-c55/mali-c55-params.c  |  12 +-
 drivers/media/platform/qcom/camss/Kconfig          |   2 +
 drivers/media/platform/qcom/camss/Makefile         |   4 +-
 drivers/media/platform/qcom/camss/camss-csid-680.c |   8 +-
 .../media/platform/qcom/camss/camss-csid-gen3.c    | 131 ++-
 .../media/platform/qcom/camss/camss-csid-gen3.h    |   3 +
 drivers/media/platform/qcom/camss/camss-csid.c     |  37 +-
 drivers/media/platform/qcom/camss/camss-csid.h     |  18 +-
 drivers/media/platform/qcom/camss/camss-vfe-17x.c  |  10 +-
 drivers/media/platform/qcom/camss/camss-vfe-340.c  |  12 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c  |  20 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c  |  34 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-8.c  |  34 +-
 drivers/media/platform/qcom/camss/camss-vfe-480.c  |  19 +-
 drivers/media/platform/qcom/camss/camss-vfe-680.c  |   4 +-
 .../camss/{camss-vfe-gen3.c => camss-vfe-690.c}    |  53 +-
 drivers/media/platform/qcom/camss/camss-vfe-780.c  | 419 +++++++++
 .../media/platform/qcom/camss/camss-vfe-880-pp.c   | 629 +++++++++++++
 .../media/platform/qcom/camss/camss-vfe-880-pp.h   |  13 +
 drivers/media/platform/qcom/camss/camss-vfe-gen1.c |  96 +-
 drivers/media/platform/qcom/camss/camss-vfe.c      | 985 ++++++++++++++++++---
 drivers/media/platform/qcom/camss/camss-vfe.h      | 156 +++-
 drivers/media/platform/qcom/camss/camss-video.c    | 235 ++++-
 drivers/media/platform/qcom/camss/camss-video.h    |   8 +
 drivers/media/platform/qcom/camss/camss.c          | 156 ++--
 drivers/media/platform/qcom/camss/camss.h          |   8 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |   2 +
 drivers/media/v4l2-core/v4l2-isp.c                 |  55 ++
 include/media/v4l2-isp.h                           |  94 +-
 include/uapi/linux/media/v4l2-isp.h                | 125 ++-
 include/uapi/linux/qcom-camss-config.h             | 273 ++++++
 include/uapi/linux/videodev2.h                     |   4 +
 37 files changed, 3464 insertions(+), 503 deletions(-)
---
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
change-id: 20261005-linux-mainline-7-2-sm8650-hdk-rfc-0-aa75cdf2c39b

Best regards,
--  
Bryan O'Donoghue <bod@kernel.org>


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 01/74] media: qcom: camss: vfe: Rename gen3 back to vfe780
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 02/74] media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880 Bryan O'Donoghue
                   ` (73 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Conjoining 690 and 780/880 class VFEs doesn't make sense when you consider
he write-master indexes are different. Clearly these are not the same
generation of silicon and the code to support them that way is cumbersome.

As a first step to fixing that, rename vfe gen3 back to 780.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/Makefile         |  2 +-
 .../camss/{camss-vfe-gen3.c => camss-vfe-780.c}    |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe.h      |  2 +-
 drivers/media/platform/qcom/camss/camss.c          | 34 +++++++++++-----------
 4 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 27898b3cc7d3c..e82bc8141c241 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -25,8 +25,8 @@ qcom-camss-objs += \
 		camss-vfe-340.o \
 		camss-vfe-480.o \
 		camss-vfe-680.o \
+		camss-vfe-780.o \
 		camss-vfe-gen1.o \
-		camss-vfe-gen3.o \
 		camss-vfe-vbif.o \
 		camss-video.o
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen3.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
similarity index 99%
rename from drivers/media/platform/qcom/camss/camss-vfe-gen3.c
rename to drivers/media/platform/qcom/camss/camss-vfe-780.c
index 22579617def78..6c04e3c64b841 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen3.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -174,7 +174,7 @@ static int vfe_halt(struct vfe_device *vfe)
 	return 0;
 }
 
-const struct vfe_hw_ops vfe_ops_gen3 = {
+const struct vfe_hw_ops vfe_ops_780 = {
 	.global_reset = vfe_global_reset,
 	.hw_version = vfe_hw_version,
 	.isr = vfe_isr,
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index ae9dad353a378..68cd05331ffe7 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -248,7 +248,7 @@ extern const struct vfe_hw_ops vfe_ops_170;
 extern const struct vfe_hw_ops vfe_ops_340;
 extern const struct vfe_hw_ops vfe_ops_480;
 extern const struct vfe_hw_ops vfe_ops_680;
-extern const struct vfe_hw_ops vfe_ops_gen3;
+extern const struct vfe_hw_ops vfe_ops_780;
 
 int vfe_get(struct vfe_device *vfe);
 void vfe_put(struct vfe_device *vfe);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 2123f6388e3d7..80697d0ab701b 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -3218,7 +3218,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.is_lite = false,
 			.has_pd = true,
 			.pd_name = "ife0",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -3242,7 +3242,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.is_lite = false,
 			.has_pd = true,
 			.pd_name = "ife1",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -3266,7 +3266,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.is_lite = false,
 			.has_pd = true,
 			.pd_name = "ife2",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -3287,7 +3287,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -3308,7 +3308,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -3533,7 +3533,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.line_num = 3,
 			.has_pd = true,
 			.pd_name = "ife0",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		},
@@ -3560,7 +3560,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.line_num = 3,
 			.has_pd = true,
 			.pd_name = "ife1",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		},
@@ -3587,7 +3587,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.line_num = 3,
 			.has_pd = true,
 			.pd_name = "ife2",
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		},
@@ -3612,7 +3612,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		},
@@ -3637,7 +3637,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		},
@@ -4001,7 +4001,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = false,
 			.has_pd = false,
 			.pd_name = NULL,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4029,7 +4029,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = false,
 			.has_pd = false,
 			.pd_name = NULL,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4054,7 +4054,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4079,7 +4079,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4104,7 +4104,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4129,7 +4129,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4154,7 +4154,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_gen3,
+			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 02/74] media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 01/74] media: qcom: camss: vfe: Rename gen3 back to vfe780 Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 03/74] media: uapi: v4l2-isp: Add extensible statistics bod
                   ` (72 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Looking at the write-master index for VFE 690 and VFE 780/880 we can see a
discontinuity between 690 and 780/880. Extending out the functionality in
these files will result in spaghettification of the code for no good
purpose.

The WM index difference is indication enough that the silicon should live
in separate files.

Disjoin now.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/Makefile        |   1 +
 drivers/media/platform/qcom/camss/camss-vfe-690.c | 168 ++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe-780.c |  53 ++-----
 drivers/media/platform/qcom/camss/camss-vfe.h     |   1 +
 drivers/media/platform/qcom/camss/camss.c         |  14 +-
 5 files changed, 187 insertions(+), 50 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index e82bc8141c241..4dcb08a0e25aa 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -25,6 +25,7 @@ qcom-camss-objs += \
 		camss-vfe-340.o \
 		camss-vfe-480.o \
 		camss-vfe-680.o \
+		camss-vfe-690.o \
 		camss-vfe-780.o \
 		camss-vfe-gen1.o \
 		camss-vfe-vbif.o \
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-690.c b/drivers/media/platform/qcom/camss/camss-vfe-690.c
new file mode 100644
index 0000000000000..6f90134d5ed64
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-690.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module 690
+ *
+ * Copyright (c) 2024 Qualcomm Technologies, Inc.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+
+#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x480 : 0x400)
+
+#define VFE_TOP_CORE_CFG (0x24)
+#define VFE_DISABLE_DSCALING_DS4  BIT(21)
+#define VFE_DISABLE_DSCALING_DS16 BIT(22)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0xFC)
+/*
+ * Bus client mapping:
+ *
+ * Full VFE:
+ * VFE_690: 16 = RDI0, 17 = RDI1, 18 = RDI2
+ *
+ * VFE LITE:
+ * VFE_690 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4, 5 = RDI5
+ */
+#define RDI_WM(n)	((vfe_is_lite(vfe) ? 0x0 : 0x10) + (n))
+
+#define VFE_BUS_WM_CGC_OVERRIDE		(BUS_REG_BASE + 0x08)
+#define		WM_CGC_OVERRIDE_ALL		(0x7FFFFFF)
+
+#define VFE_BUS_WM_CFG(n)		(BUS_REG_BASE + 0x200 + (n) * 0x100)
+#define		WM_CFG_EN			BIT(0)
+#define		WM_VIR_FRM_EN			BIT(1)
+#define		WM_CFG_MODE			BIT(16)
+#define VFE_BUS_WM_IMAGE_ADDR(n)	(BUS_REG_BASE + 0x204 + (n) * 0x100)
+#define VFE_BUS_WM_FRAME_INCR(n)	(BUS_REG_BASE + 0x208 + (n) * 0x100)
+#define VFE_BUS_WM_IMAGE_CFG_0(n)	(BUS_REG_BASE + 0x20c + (n) * 0x100)
+#define		WM_IMAGE_CFG_0_DEFAULT_WIDTH	(0xFFFF)
+#define VFE_BUS_WM_IMAGE_CFG_2(n)	(BUS_REG_BASE + 0x214 + (n) * 0x100)
+#define		WM_IMAGE_CFG_2_DEFAULT_STRIDE	(0xFFFF)
+#define VFE_BUS_WM_PACKER_CFG(n)	(BUS_REG_BASE + 0x218 + (n) * 0x100)
+
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(BUS_REG_BASE + 0x230 + (n) * 0x100)
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(BUS_REG_BASE + 0x234 + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(BUS_REG_BASE + 0x238 + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(BUS_REG_BASE + 0x23c + (n) * 0x100)
+
+#define VFE_BUS_WM_MMU_PREFETCH_CFG(n)		(BUS_REG_BASE + 0x260 + (n) * 0x100)
+#define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n)	(BUS_REG_BASE + 0x264 + (n) * 0x100)
+
+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;
+
+	wm = RDI_WM(wm);
+
+	/* no clock gating at bus input */
+	writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
+
+	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+	writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height,
+	       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
+
+	writel((WM_IMAGE_CFG_0_DEFAULT_WIDTH & 0xFFFF),
+	       vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
+	writel(WM_IMAGE_CFG_2_DEFAULT_STRIDE,
+	       vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
+	writel(0, vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
+
+	/* TOP CORE CFG */
+	writel(VFE_DISABLE_DSCALING_DS4 | VFE_DISABLE_DSCALING_DS16,
+		vfe->base + VFE_TOP_CORE_CFG);
+
+	/* no dropped frames, one irq per frame */
+	writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
+	writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
+	writel(0, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(wm));
+	writel(1, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(wm));
+
+	writel(1, vfe->base + VFE_BUS_WM_MMU_PREFETCH_CFG(wm));
+	writel(0xFFFFFFFF, vfe->base + VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(wm));
+
+	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+{
+	wm = RDI_WM(wm);
+	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+			  struct vfe_line *line)
+{
+	wm = RDI_WM(wm);
+
+	writel(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+
+	dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n",
+		wm, addr);
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	int port_id = line_id;
+
+	camss_reg_update(vfe->camss, vfe->id, port_id, false);
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+					enum vfe_line_id line_id)
+{
+	int port_id = line_id;
+
+	camss_reg_update(vfe->camss, vfe->id, port_id, true);
+}
+
+static const struct camss_video_ops vfe_video_ops_690 = {
+	.queue_buffer = vfe_queue_buffer_v2,
+	.flush_buffers = vfe_flush_buffers,
+};
+
+static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
+{
+	vfe->video_ops = vfe_video_ops_690;
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+	vfe_isr_reset_ack(vfe);
+}
+
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+	/* nop */
+	return IRQ_HANDLED;
+}
+
+static int vfe_halt(struct vfe_device *vfe)
+{
+	/* rely on vfe_disable_output() to stop the VFE */
+	return 0;
+}
+
+const struct vfe_hw_ops vfe_ops_690 = {
+	.global_reset = vfe_global_reset,
+	.hw_version = vfe_hw_version,
+	.isr = vfe_isr,
+	.pm_domain_off = vfe_pm_domain_off,
+	.pm_domain_on = vfe_pm_domain_on,
+	.reg_update = vfe_reg_update,
+	.reg_update_clear = vfe_reg_update_clear,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_disable,
+	.vfe_enable = vfe_enable_v2,
+	.vfe_halt = vfe_halt,
+	.vfe_wm_start = vfe_wm_start,
+	.vfe_wm_stop = vfe_wm_stop,
+	.vfe_buf_done = vfe_buf_done,
+	.vfe_wm_update = vfe_wm_update,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 6c04e3c64b841..4adbd0680898f 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module gen3
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module 780
  *
  * Copyright (c) 2024 Qualcomm Technologies, Inc.
  */
@@ -12,40 +12,19 @@
 #include "camss.h"
 #include "camss-vfe.h"
 
-#define IS_VFE_690(vfe) \
-	    ((vfe->camss->res->version == CAMSS_8775P) \
-	    || (vfe->camss->res->version == CAMSS_8300))
-
-#define BUS_REG_BASE_690 \
-	    (vfe_is_lite(vfe) ? 0x480 : 0x400)
-#define BUS_REG_BASE_780 \
-	    (vfe_is_lite(vfe) ? 0x200 : 0xC00)
-#define BUS_REG_BASE \
-	    (IS_VFE_690(vfe) ? BUS_REG_BASE_690 : BUS_REG_BASE_780)
-
-#define VFE_TOP_CORE_CFG (0x24)
-#define VFE_DISABLE_DSCALING_DS4  BIT(21)
-#define VFE_DISABLE_DSCALING_DS16 BIT(22)
-
-#define VFE_BUS_WM_TEST_BUS_CTRL_690 (BUS_REG_BASE + 0xFC)
-#define VFE_BUS_WM_TEST_BUS_CTRL_780 (BUS_REG_BASE + 0xDC)
-#define VFE_BUS_WM_TEST_BUS_CTRL \
-	    (IS_VFE_690(vfe) ? VFE_BUS_WM_TEST_BUS_CTRL_690 \
-	     : VFE_BUS_WM_TEST_BUS_CTRL_780)
+#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x200 : 0xC00)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0xDC)
 /*
  * Bus client mapping:
  *
  * Full VFE:
- * VFE_690: 16 = RDI0, 17 = RDI1, 18 = RDI2
  * VFE_780: 23 = RDI0, 24 = RDI1, 25 = RDI2
  *
  * VFE LITE:
- * VFE_690 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4, 5 = RDI5
  * VFE_780 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4
  */
-#define RDI_WM_690(n)	((vfe_is_lite(vfe) ? 0x0 : 0x10) + (n))
-#define RDI_WM_780(n)	((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))
-#define RDI_WM(n)	(IS_VFE_690(vfe) ? RDI_WM_690(n) : RDI_WM_780(n))
+#define RDI_WM(n)	((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))
 
 #define VFE_BUS_WM_CGC_OVERRIDE		(BUS_REG_BASE + 0x08)
 #define		WM_CGC_OVERRIDE_ALL		(0x7FFFFFF)
@@ -82,12 +61,8 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 
 	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
 
-	if (IS_VFE_690(vfe))
-		writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height,
-		       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
-	else
-		writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
-		       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
+	writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
+	       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
 
 	writel((WM_IMAGE_CFG_0_DEFAULT_WIDTH & 0xFFFF),
 	       vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
@@ -95,11 +70,6 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	       vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
 	writel(0, vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
 
-	/* TOP CORE CFG */
-	if (IS_VFE_690(vfe))
-		writel(VFE_DISABLE_DSCALING_DS4 | VFE_DISABLE_DSCALING_DS16,
-			vfe->base + VFE_TOP_CORE_CFG);
-
 	/* no dropped frames, one irq per frame */
 	writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
 	writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
@@ -123,10 +93,7 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 {
 	wm = RDI_WM(wm);
 
-	if (IS_VFE_690(vfe))
-		writel(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
-	else
-		writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+	writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 
 	dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n",
 		wm, addr);
@@ -147,14 +114,14 @@ static inline void vfe_reg_update_clear(struct vfe_device *vfe,
 	camss_reg_update(vfe->camss, vfe->id, port_id, true);
 }
 
-static const struct camss_video_ops vfe_video_ops_gen3 = {
+static const struct camss_video_ops vfe_video_ops_780 = {
 	.queue_buffer = vfe_queue_buffer_v2,
 	.flush_buffers = vfe_flush_buffers,
 };
 
 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 {
-	vfe->video_ops = vfe_video_ops_gen3;
+	vfe->video_ops = vfe_video_ops_780;
 }
 
 static void vfe_global_reset(struct vfe_device *vfe)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 68cd05331ffe7..089f525b98cf5 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -248,6 +248,7 @@ extern const struct vfe_hw_ops vfe_ops_170;
 extern const struct vfe_hw_ops vfe_ops_340;
 extern const struct vfe_hw_ops vfe_ops_480;
 extern const struct vfe_hw_ops vfe_ops_680;
+extern const struct vfe_hw_ops vfe_ops_690;
 extern const struct vfe_hw_ops vfe_ops_780;
 
 int vfe_get(struct vfe_device *vfe);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 80697d0ab701b..40a993ade5f6d 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4001,7 +4001,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = false,
 			.has_pd = false,
 			.pd_name = NULL,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4029,7 +4029,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = false,
 			.has_pd = false,
 			.pd_name = NULL,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4054,7 +4054,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4079,7 +4079,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4104,7 +4104,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4129,7 +4129,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}
@@ -4154,7 +4154,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 		.vfe = {
 			.line_num = 4,
 			.is_lite = true,
-			.hw_ops = &vfe_ops_780,
+			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
 			.formats_pix = &vfe_formats_pix_845
 		}

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 03/74] media: uapi: v4l2-isp: Add extensible statistics
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 01/74] media: qcom: camss: vfe: Rename gen3 back to vfe780 Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 02/74] media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880 Bryan O'Donoghue
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 04/74] media: Documentation: uapi: Update V4L2 ISP for extensible stats bod
                   ` (71 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Antoine Bouyer, Niklas Söderlund, Sakari Ailus

From: Antoine Bouyer <antoine.bouyer@nxp.com>

Extend the v4l2-isp extensible format introduced for isp parameters buffers
to the support buffers of ISP statistic.

Like for ISP configuration purpose, that will help supporting various ISP
hardware versions reporting different statistics data with less impact on
userspace.

Rename all 'v4l2_isp_params' types to generic 'v4l2_isp' types to
prepare to use them for statistics as well and maintain the existing
types for compatibility with existing userspace only.

Signed-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
[Rework to remove 'v4l2_isp_stats' and unify types]
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 include/uapi/linux/media/v4l2-isp.h | 125 +++++++++++++++++++++++-------------
 1 file changed, 79 insertions(+), 46 deletions(-)

diff --git a/include/uapi/linux/media/v4l2-isp.h b/include/uapi/linux/media/v4l2-isp.h
index 779168f9058e3..e4607e1217e1a 100644
--- a/include/uapi/linux/media/v4l2-isp.h
+++ b/include/uapi/linux/media/v4l2-isp.h
@@ -13,25 +13,33 @@
 #include <linux/types.h>
 
 /**
- * enum v4l2_isp_params_version - V4L2 ISP parameters versioning
+ * enum v4l2_isp_version - V4L2 ISP serialization format versioning
  *
- * @V4L2_ISP_PARAMS_VERSION_V0: First version of the V4L2 ISP parameters format
- *				(for compatibility)
- * @V4L2_ISP_PARAMS_VERSION_V1: First version of the V4L2 ISP parameters format
+ * @V4L2_ISP_VERSION_V0: First version of the V4L2 ISP serialization format
+ *                       (for compatibility)
+ * @V4L2_ISP_VERSION_V1: First version of the V4L2 ISP serialization format
  *
  * V0 and V1 are identical in order to support drivers compatible with the V4L2
- * ISP parameters format already upstreamed which use either 0 or 1 as their
- * versioning identifier. Both V0 and V1 refers to the first version of the
- * V4L2 ISP parameters format.
+ * ISP format already upstreamed which use either 0 or 1 as their versioning
+ * identifier. Both V0 and V1 refers to the first version of the V4L2 ISP
+ * serialization format.
  *
- * Future revisions of the V4L2 ISP parameters format should start from the
+ * Future revisions of the V4L2 ISP serialization format should start from the
  * value of 2.
  */
-enum v4l2_isp_params_version {
-	V4L2_ISP_PARAMS_VERSION_V0 = 0,
-	V4L2_ISP_PARAMS_VERSION_V1
+enum v4l2_isp_version {
+	V4L2_ISP_VERSION_V0 = 0,
+	V4L2_ISP_VERSION_V1
 };
 
+/*
+ * Compatibility with existing users of v4l2_isp_params which pre-date the
+ * introduction of v4l2_isp_stats.
+ */
+#define v4l2_isp_params_version			v4l2_isp_version
+#define V4L2_ISP_PARAMS_VERSION_V0		V4L2_ISP_VERSION_V0
+#define V4L2_ISP_PARAMS_VERSION_V1		V4L2_ISP_VERSION_V1
+
 #define V4L2_ISP_PARAMS_FL_BLOCK_DISABLE	(1U << 0)
 #define V4L2_ISP_PARAMS_FL_BLOCK_ENABLE		(1U << 1)
 
@@ -39,64 +47,89 @@ enum v4l2_isp_params_version {
  * Reserve the first 8 bits for V4L2_ISP_PARAMS_FL_* flag.
  *
  * Driver-specific flags should be defined as:
- * #define DRIVER_SPECIFIC_FLAG0     ((1U << V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(0))
- * #define DRIVER_SPECIFIC_FLAG1     ((1U << V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(1))
+ * #define DRIVER_SPECIFIC_FLAG0     ((1U << V4L2_ISP_FL_DRIVER_FLAGS(0))
+ * #define DRIVER_SPECIFIC_FLAG1     ((1U << V4L2_ISP_FL_DRIVER_FLAGS(1))
  */
-#define V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(n)       ((n) + 8)
+#define V4L2_ISP_FL_DRIVER_FLAGS(n)		((n) + 8)
 
 /**
- * struct v4l2_isp_params_block_header - V4L2 extensible parameters block header
- * @type: The parameters block type (driver-specific)
+ * struct v4l2_isp_block_header - V4L2 extensible block header
+ * @type: The parameters or statistics block type (driver-specific)
  * @flags: A bitmask of block flags (driver-specific)
- * @size: Size (in bytes) of the parameters block, including this header
+ * @size: Size (in bytes) of the block, including this header
  *
- * This structure represents the common part of all the ISP configuration
- * blocks. Each parameters block shall embed an instance of this structure type
- * as its first member, followed by the block-specific configuration data.
+ * This structure represents the common part of all the ISP configuration or
+ * statistic blocks. Each block shall embed an instance of this structure type
+ * as its first member, followed by the block-specific configuration or
+ * statistic data.
  *
  * The @type field is an ISP driver-specific value that identifies the block
- * type. The @size field specifies the size of the parameters block.
+ * type. The @size field specifies the size of the block, including this
+ * header.
  *
- * The @flags field is a bitmask of per-block flags V4L2_PARAMS_ISP_FL_* and
- * driver-specific flags specified by the driver header.
+ * The @flags field is a bitmask of per-block flags. If a block is used for
+ * configuration parameters this field can be a combination of
+ * V4L2_ISP_PARAMS_FL_* and driver-specific flags. If a block is used
+ * for statistics this fields is used to report optional
+ * driver-specific flags, if any.
  */
-struct v4l2_isp_params_block_header {
+struct v4l2_isp_block_header {
 	__u16 type;
 	__u16 flags;
 	__u32 size;
 } __attribute__((aligned(8)));
 
 /**
- * struct v4l2_isp_params_buffer - V4L2 extensible parameters configuration
- * @version: The parameters buffer version (driver-specific)
- * @data_size: The configuration data effective size, excluding this header
- * @data: The configuration data
+ * v4l2_isp_params_block_header - V4L2 extensible parameters block header
+ *
+ * Compatibility with existing users of v4l2_isp_params_block_header
+ * which pre-date the introduction of v4l2_isp_block_header.
+ */
+#define v4l2_isp_params_block_header v4l2_isp_block_header
+
+/**
+ * struct v4l2_isp_buffer - V4L2 extensible buffer
+ * @version: The extensible buffer version (driver-specific)
+ * @data_size: The data effective size, excluding this header
+ * @data: The configuration or statistics data
  *
- * This structure contains the configuration parameters of the ISP algorithms,
- * serialized by userspace into a data buffer. Each configuration parameter
- * block is represented by a block-specific structure which contains a
- * :c:type:`v4l2_isp_params_block_header` entry as first member. Userspace
- * populates the @data buffer with configuration parameters for the blocks that
- * it intends to configure. As a consequence, the data buffer effective size
- * changes according to the number of ISP blocks that userspace intends to
- * configure and is set by userspace in the @data_size field.
+ * This structure contains ISP configuration parameters or ISP hardware
+ * statistics serialized into a data buffer. Each block is represented by a
+ * block-specific structure which contains a :c:type:`v4l2_isp_block_header`
+ * entry as first member.
  *
- * The parameters buffer is versioned by the @version field to allow modifying
- * and extending its definition. Userspace shall populate the @version field to
- * inform the driver about the version it intends to use. The driver will parse
- * and handle the @data buffer according to the data layout specific to the
- * indicated version and return an error if the desired version is not
+ * When used for ISP parameters, userspace populates the @data buffer with
+ * configuration parameters for the blocks that it intends to configure. As a
+ * consequence, the data buffer effective size changes according to the number
+ * of ISP blocks that userspace intends to configure.
+ *
+ * When used to report ISP statistics, the driver populates the @data buffer
+ * with statistics for each supported measurement block.
+ *
+ * The buffer is versioned by the @version field to allow modifying
+ * and extending its definition. The writer shall populate the @version field
+ * to inform the reader about the version it intends to use. The reader will
+ * parse and handle the @data buffer according to the data layout specific to
+ * the indicated version and return an error if the desired version is not
  * supported.
  *
- * For each ISP block that userspace wants to configure, a block-specific
- * structure is appended to the @data buffer, one after the other without gaps
- * in between. Userspace shall populate the @data_size field with the effective
- * size, in bytes, of the @data buffer.
+ * For each ISP block, a block-specific structure is appended to the @data
+ * buffer, one after the other without gaps in between. The writer shall
+ * populate the @data_size field with the effective size, in bytes, of the
+ * @data buffer.
  */
-struct v4l2_isp_params_buffer {
+struct v4l2_isp_buffer {
 	__u32 version;
 	__u32 data_size;
 	__u8 data[] __counted_by(data_size);
 };
 
+/**
+ * v4l2_isp_params_buffer - V4L2 extensible parameters compatibility
+ *
+ * Compatibility with existing users of v4l2_isp_params_buffer which
+ * pre-date the introduction of v4l2_isp_buffer.
+ */
+#define v4l2_isp_params_buffer v4l2_isp_buffer
+
 #endif /* _UAPI_V4L2_ISP_H_ */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 04/74] media: Documentation: uapi: Update V4L2 ISP for extensible stats
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (2 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 03/74] media: uapi: v4l2-isp: Add extensible statistics bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 05/74] media: v4l2-isp: Rename v4l2_isp_params_buffer_size bod
                   ` (70 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Antoine Bouyer, Niklas Söderlund, Sakari Ailus

From: Antoine Bouyer <antoine.bouyer@nxp.com>

Rework the userspace-api documentation of V4L2 ISP to support
statistics.

Update all occurences of 'v4l2_isp_param' types to match the uAPI
changes and add a section to document the statistics serialization
format.

Signed-off-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
[Update on uAPI changes]
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 Documentation/userspace-api/media/v4l/v4l2-isp.rst | 45 ++++++++++++++++------
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/Documentation/userspace-api/media/v4l/v4l2-isp.rst b/Documentation/userspace-api/media/v4l/v4l2-isp.rst
index facf6dba1ca7f..8a3f05b5e85fd 100644
--- a/Documentation/userspace-api/media/v4l/v4l2-isp.rst
+++ b/Documentation/userspace-api/media/v4l/v4l2-isp.rst
@@ -18,22 +18,22 @@ single C structure that contains a header, followed by a binary buffer where
 userspace programs a variable number of ISP configuration data block, one for
 each supported ISP feature.
 
-The :c:type:`v4l2_isp_params_buffer` structure defines the buffer header which
-is followed by a binary buffer of ISP configuration data. Userspace shall
-correctly populate the buffer header with the generic parameters format version
-and with the size (in bytes) of the binary data buffer where it will store the
-ISP blocks configuration.
-
-Each *ISP configuration block* is preceded by an header implemented by the
-:c:type:`v4l2_isp_params_block_header` structure, followed by the configuration
+The :c:type:`v4l2_isp_buffer` structure defines the buffer header which is
+followed by a binary buffer of ISP configuration data. Userspace shall correctly
+populate the buffer header with the serialization format version and with the
+size (in bytes) of the binary data buffer where it will store the ISP blocks
+configuration.
+
+Each *ISP configuration block* is preceded by a header implemented by the
+:c:type:`v4l2_isp_block_header` structure, followed by the configuration
 parameters for that specific block, defined by the ISP driver specific data
 types.
 
 Userspace applications are responsible for correctly populating each block's
 header fields (type, flags and size) and the block-specific parameters.
 
-ISP block enabling, disabling and configuration
------------------------------------------------
+ISP parameters block enabling, disabling and configuration
+----------------------------------------------------------
 
 When userspace wants to configure and enable an ISP block it shall fully
 populate the block configuration and set the V4L2_ISP_PARAMS_FL_BLOCK_ENABLE
@@ -59,7 +59,30 @@ definition without invalidating the existing ones.
 ISP statistics
 ==============
 
-Support for generic statistics format is not yet implemented in Video4Linux2.
+The generic ISP statistics format is identical to the generic ISP configuration
+parameters format. It is realized by defining a C structure that contains a
+header, followed by binary buffer where the ISP driver copies a variable number
+of ISP statistics blocks.
+
+Extensible statistics buffers have :c:type:`v4l2_isp_buffer` header followed by
+a binary buffer of ISP statistics data. ISP drivers populate the buffer header
+with the serialization format version and with the size (in bytes) of the binary
+data buffer where ISP statistics data are serialized. Applications shall
+validate that the serialization format version matches the expected one and that
+the buffer size doesn't exceed the maximum size for a statistics buffer as
+declared by the driver's uAPI header.
+
+Each *ISP statistics block* is preceded by a header implemented by the
+:c:type:`v4l2_isp_block_header` structure, followed by the statistics data for
+that specific block. The driver might optionally report platform-specific flags
+associated with each statistics block.
+
+Applications inspect the statistics block type as reported in the header and
+validates the reported size matches the block's expected size before accessing
+the ISP statistics data.
+
+Extension to the statistics format can be implemented by adding new blocks
+definition without invalidating the existing ones.
 
 V4L2 ISP uAPI data types
 ========================

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 05/74] media: v4l2-isp: Rename v4l2_isp_params_buffer_size
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (3 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 04/74] media: Documentation: uapi: Update V4L2 ISP for extensible stats bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 06/74] media: v4l2-isp: Add per-block validation callback bod
                   ` (69 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Niklas Söderlund, Sakari Ailus

From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Rename v4l2_isp_params_buffer_size() to v4l2_isp_buffer_size() to
support statistics.

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../media/platform/arm/mali-c55/mali-c55-params.c  | 12 ++++++------
 include/media/v4l2-isp.h                           | 22 +++++++++++++---------
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-params.c b/drivers/media/platform/arm/mali-c55/mali-c55-params.c
index de0e9d898db7b..dc483f0322d6e 100644
--- a/drivers/media/platform/arm/mali-c55/mali-c55-params.c
+++ b/drivers/media/platform/arm/mali-c55/mali-c55-params.c
@@ -487,7 +487,7 @@ static int mali_c55_params_g_fmt_meta_out(struct file *file, void *fh,
 {
 	static const struct v4l2_meta_format mfmt = {
 		.dataformat = V4L2_META_FMT_MALI_C55_PARAMS,
-		.buffersize = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE),
+		.buffersize = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE),
 	};
 
 	f->fmt.meta = mfmt;
@@ -540,13 +540,13 @@ mali_c55_params_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
 	if (*num_planes && *num_planes > 1)
 		return -EINVAL;
 
-	if (sizes[0] && sizes[0] < v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE))
+	if (sizes[0] && sizes[0] < v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE))
 		return -EINVAL;
 
 	*num_planes = 1;
 
 	if (!sizes[0])
-		sizes[0] = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE);
+		sizes[0] = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE);
 
 	return 0;
 }
@@ -556,7 +556,7 @@ static int mali_c55_params_buf_init(struct vb2_buffer *vb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf);
 
-	buf->config = kvmalloc(v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE),
+	buf->config = kvmalloc(v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE),
 			       GFP_KERNEL);
 	if (!buf->config)
 		return -ENOMEM;
@@ -583,7 +583,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb)
 	int ret;
 
 	ret = v4l2_isp_params_validate_buffer_size(mali_c55->dev, vb,
-			v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE));
+			v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE));
 	if (ret)
 		return ret;
 
@@ -593,7 +593,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb)
 	 * changed to the buffer content whilst the driver processes it.
 	 */
 
-	memcpy(buf->config, config, v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE));
+	memcpy(buf->config, config, v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE));
 
 	return v4l2_isp_params_validate_buffer(mali_c55->dev, vb, buf->config,
 					       mali_c55_params_block_types_info,
diff --git a/include/media/v4l2-isp.h b/include/media/v4l2-isp.h
index f3a6d0edcb24c..d70ed6b431e7b 100644
--- a/include/media/v4l2-isp.h
+++ b/include/media/v4l2-isp.h
@@ -15,17 +15,21 @@ struct device;
 struct vb2_buffer;
 
 /**
- * v4l2_isp_params_buffer_size - Calculate size of v4l2_isp_params_buffer
- * @max_params_size: The total size of the ISP configuration blocks
+ * v4l2_isp_buffer_size - Calculate size of v4l2_isp_buffer
+ * @max_size: The total size of the ISP configuration or statistics blocks
+ *
+ * Users of v4l2-isp will have differing sized data arrays for parameters and
+ * statistics, depending on their specific blocks. Drivers need to be able to
+ * calculate the appropriate size of the buffer to accommodate all ISP blocks
+ * supported by the platform. This macro provides a convenient tool for the
+ * calculation.
+ *
+ * The intended users of this function are drivers initializing the size
+ * of their metadata (parameters and statistics) buffers.
  *
- * Users of the v4l2 extensible parameters will have differing sized data arrays
- * depending on their specific parameter buffers. Drivers and userspace will
- * need to be able to calculate the appropriate size of the struct to
- * accommodate all ISP configuration blocks provided by the platform.
- * This macro provides a convenient tool for the calculation.
  */
-#define v4l2_isp_params_buffer_size(max_params_size) \
-	(offsetof(struct v4l2_isp_params_buffer, data) + (max_params_size))
+#define v4l2_isp_buffer_size(max_size)			\
+	(offsetof(struct v4l2_isp_buffer, data) + (max_size))
 
 /**
  * v4l2_isp_params_validate_buffer_size - Validate a V4L2 ISP buffer sizes

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 06/74] media: v4l2-isp: Add per-block validation callback
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (4 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 05/74] media: v4l2-isp: Rename v4l2_isp_params_buffer_size bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 07/74] media: amlogic-c3: Implement per-block validation bod
                   ` (68 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Niklas Söderlund, Sakari Ailus

From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Drivers are expected to provide to the helper function
v4l2_isp_params_validate_buffer() a list of 'struct
v4l2_isp_params_block_type_info' entries, one for each supported ISP block.

The type 'struct v4l2_isp_params_block_type_info' so far only contained the
expected block size for the core framework to validate the declared block
size against the expected one.

For some blocks, drivers might want to implement more precise per-block
validations. Add a function pointer member to 'struct
v4l2_isp_params_block_type_info' to allow drivers to register a callback
and call it from the core framework during validation.

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-isp.c |  3 +++
 include/media/v4l2-isp.h           | 11 ++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-isp.c b/drivers/media/v4l2-core/v4l2-isp.c
index 29831f7032e94..f497471e9f18f 100644
--- a/drivers/media/v4l2-core/v4l2-isp.c
+++ b/drivers/media/v4l2-core/v4l2-isp.c
@@ -114,6 +114,9 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb,
 			return -EINVAL;
 		}
 
+		if (info->block_validate && info->block_validate(dev, block))
+			return -EINVAL;
+
 		block_offset += block->size;
 		buffer_size -= block->size;
 	}
diff --git a/include/media/v4l2-isp.h b/include/media/v4l2-isp.h
index d70ed6b431e7b..1f35a52f978a1 100644
--- a/include/media/v4l2-isp.h
+++ b/include/media/v4l2-isp.h
@@ -55,17 +55,22 @@ int v4l2_isp_params_validate_buffer_size(struct device *dev,
 /**
  * struct v4l2_isp_params_block_type_info - V4L2 ISP per-block-type info
  * @size: the block type expected size
+ * @block_validate: driver's callback to implement per-block validation
  *
  * The v4l2_isp_params_block_type_info collects information of the ISP
- * configuration block types for validation purposes. It currently only contains
- * the expected block type size.
+ * configuration block types for validation purposes. It contains the expected
+ * block type size and a function pointer where drivers can register a callback
+ * for additional per-block validation purposes. The validation function is
+ * expected to return 0 on success or a negative error number for errors.
  *
  * Drivers shall prepare a list of block type info, indexed by block type, one
  * for each supported ISP block type and correctly populate them with the
- * expected block type size.
+ * expected block type size and the optional callback.
  */
 struct v4l2_isp_params_block_type_info {
 	size_t size;
+	int (*block_validate)(struct device *dev,
+			      const struct v4l2_isp_block_header *block);
 };
 
 /**

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 07/74] media: amlogic-c3: Implement per-block validation
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (5 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 06/74] media: v4l2-isp: Add per-block validation callback bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 08/74] media: v4l2-isp: Add helpers for stats buffer bod
                   ` (67 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Sakari Ailus

From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Use the newly introduced per-block validation in v4l2-isp framework to
implement a validation callback for the AWB and AE configuration blocks
to make sure the configured metering zones do not exceed the hardware
capabilities.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 .../media/platform/amlogic/c3/isp/c3-isp-params.c  | 42 ++++++++++++++++++++--
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c
index aec3eed0e443e..ae0777a20bdaf 100644
--- a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c
+++ b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c
@@ -535,16 +535,52 @@ static const c3_isp_block_handler c3_isp_params_handlers[] = {
 	[C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc,
 };
 
-#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \
+static int
+c3_isp_params_awb_config_validate(struct device *dev,
+				  const struct v4l2_isp_block_header *block)
+{
+	const struct c3_isp_params_awb_config *cfg =
+			(const struct c3_isp_params_awb_config *)block;
+
+	if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AWB_MAX_ZONES) {
+		dev_dbg(dev, "Invalid number of AWB measurement zones\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+c3_isp_params_ae_config_validate(struct device *dev,
+				 const struct v4l2_isp_block_header *block)
+{
+	const struct c3_isp_params_ae_config *cfg =
+			(const struct c3_isp_params_ae_config *)block;
+
+	if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AE_MAX_ZONES) {
+		dev_dbg(dev, "Invalid number of AE measurement zones\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, cbk) \
 	[C3_ISP_PARAMS_BLOCK_ ## block] = { \
 		.size = sizeof(struct c3_isp_params_ ## data), \
+		.block_validate = (cbk)\
 	}
 
+#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \
+	C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, NULL)
+
 static const struct v4l2_isp_params_block_type_info
 c3_isp_params_block_types_info[] = {
 	C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains),
-	C3_ISP_PARAMS_BLOCK_INFO(AWB_CONFIG, awb_config),
-	C3_ISP_PARAMS_BLOCK_INFO(AE_CONFIG, ae_config),
+	C3_ISP_PARAMS_BLOCK_INFO_CBK(AWB_CONFIG, awb_config,
+				     &c3_isp_params_awb_config_validate),
+	C3_ISP_PARAMS_BLOCK_INFO_CBK(AE_CONFIG, ae_config,
+				     &c3_isp_params_ae_config_validate),
 	C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config),
 	C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma),
 	C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm),

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 08/74] media: v4l2-isp: Add helpers for stats buffer
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (6 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 07/74] media: amlogic-c3: Implement per-block validation bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 09/74] media: uapi: Add CAMSS ISP configuration definition bod
                   ` (66 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue,
	Niklas Söderlund, Sakari Ailus

From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Add two helper functions to v4l2-isp to handle statistics:

- v4l2_isp_stats_init_buffer() to initialize a statistics buffer
- v4l2_isp_stats_init_block() to initialize a statistics block in the
  next available memory location of a buffer

The v4l2_isp_stats_init_buffer() resets the data size counter of the
buffer and initializes its 'version' field.

The v4l2_isp_stats_init_block() helper accepts the type of the stats
block about to be populated, an array of per-block-type information and
the maximum size of the v4l2-isp buffer. If enough space for the new
block is available, the function increments the
v4l2_isp_buffer.data_size counter, initializes the new stats block
header and returns a pointer to the block for the driver to populate it.

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-isp.c | 52 +++++++++++++++++++++++++++++++++
 include/media/v4l2-isp.h           | 59 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-isp.c b/drivers/media/v4l2-core/v4l2-isp.c
index f497471e9f18f..1eb46e080afa1 100644
--- a/drivers/media/v4l2-core/v4l2-isp.c
+++ b/drivers/media/v4l2-core/v4l2-isp.c
@@ -130,6 +130,58 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb,
 }
 EXPORT_SYMBOL_GPL(v4l2_isp_params_validate_buffer);
 
+void v4l2_isp_stats_init_buffer(struct v4l2_isp_buffer *buf,
+				enum v4l2_isp_version version)
+{
+	if (WARN_ON(!buf))
+		return;
+
+	if (WARN_ON(version > V4L2_ISP_VERSION_V1))
+		return;
+
+	buf->version = version;
+	buf->data_size = 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_buffer);
+
+struct v4l2_isp_block_header *
+v4l2_isp_stats_init_block(struct device *dev, struct v4l2_isp_buffer *buf,
+			  const struct v4l2_isp_stats_block_type_info *type_info,
+			  size_t num_block_types, unsigned int block_type,
+			  size_t max_size)
+{
+	const struct v4l2_isp_stats_block_type_info *block_info;
+	struct v4l2_isp_block_header *header;
+	size_t used;
+
+	if (WARN_ON(!dev || !buf || !type_info))
+		return ERR_PTR(-EINVAL);
+
+	if (block_type >= num_block_types) {
+		dev_err(dev, "Invalid block type %u\n", block_type);
+		return ERR_PTR(-EINVAL);
+	}
+
+	block_info = &type_info[block_type];
+	used = buf->data_size;
+
+	if (used + block_info->size > max_size) {
+		dev_err(dev, "No space for stats block type %u of size %zu\n",
+			block_type, block_info->size);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	buf->data_size += block_info->size;
+
+	header = (struct v4l2_isp_block_header *)&buf->data[used];
+	header->type = block_type;
+	header->size = block_info->size;
+	header->flags = 0;
+
+	return header;
+}
+EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_block);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com");
 MODULE_DESCRIPTION("V4L2 generic ISP parameters and statistics helpers");
diff --git a/include/media/v4l2-isp.h b/include/media/v4l2-isp.h
index 1f35a52f978a1..7a54cf98c79af 100644
--- a/include/media/v4l2-isp.h
+++ b/include/media/v4l2-isp.h
@@ -53,7 +53,7 @@ int v4l2_isp_params_validate_buffer_size(struct device *dev,
 					 size_t max_size);
 
 /**
- * struct v4l2_isp_params_block_type_info - V4L2 ISP per-block-type info
+ * struct v4l2_isp_params_block_type_info - V4L2 ISP params per-block-type info
  * @size: the block type expected size
  * @block_validate: driver's callback to implement per-block validation
  *
@@ -97,4 +97,61 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb,
 				    const struct v4l2_isp_params_block_type_info *type_info,
 				    size_t num_block_types);
 
+/**
+ * struct v4l2_isp_stats_block_type_info - V4L2 ISP stats per-block-type info
+ * @size: the block type expected size
+ *
+ * The v4l2_isp_stats_block_type_info collects information of the ISP
+ * statistics block types for validation purposes. It currently only contains
+ * the expected block size.
+ *
+ * Drivers shall prepare a list of statistics block type info, indexed by block
+ * type, one for each supported ISP statistics block type and correctly populate
+ * them with the expected block size.
+ */
+struct v4l2_isp_stats_block_type_info {
+	size_t size;
+};
+
+/**
+ * v4l2_isp_stats_init_buffer - Initialize a statistics buffer
+ *
+ * Initialize a buffer of statistics. Only set the 'version' field and reset
+ * 'data_size' to 0.
+ *
+ * @buf: the v4l2_isp_buffer to initialize
+ * @version: the v4l2-isp serialization format version used by the driver
+ */
+void v4l2_isp_stats_init_buffer(struct v4l2_isp_buffer *buf,
+				enum v4l2_isp_version version);
+
+/**
+ * v4l2_isp_stats_init_block - Create and initialize a new block in a statistics
+ *			       buffer
+ * @dev: the driver's device pointer
+ * @buf: the v4l2_isp_buffer where statistics are serialized
+ * @type_info: the array of per-block-type validation info
+ * @num_block_types: the number of block types in the type_info array
+ * @block_type: the type of the statistics block to initialize
+ * @max_size: the maximum size of the data[] member of @buf
+ *
+ * This function locates and initialize a new statistics block in @buf for the
+ * driver to populate its content. The function checks that enough space for the
+ * requested @block_type is available in @buf and increments the 'data_size'
+ * member of @buf. The newly created statistics block's header is initialized
+ * with the size and type information provided by the caller in @type_info.
+ *
+ * Drivers should call this function before populating a new statistics block
+ * content.
+ *
+ * Returns a pointer to the next available location in @buf, or an error pointer
+ * if the requested @block_size is not available in @buf or @block_type is not
+ * valid.
+ */
+struct v4l2_isp_block_header *
+v4l2_isp_stats_init_block(struct device *dev, struct v4l2_isp_buffer *buf,
+			  const struct v4l2_isp_stats_block_type_info *type_info,
+			  size_t num_block_types, unsigned int block_type,
+			  size_t max_size);
+
 #endif /* _V4L2_ISP_H_ */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 09/74] media: uapi: Add CAMSS ISP configuration definition
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (7 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 08/74] media: v4l2-isp: Add helpers for stats buffer bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 10/74] media: Documentation: uapi: Add qcom-camss ISP params documentation bod
                   ` (65 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Loic Poulain <loic.poulain@oss.qualcomm.com>

Add the uapi header qcom-camss-config.h defining the ISP parameter
structures used by the CAMSS Offline Processing Engine (OPE) driver.
This includes structures for white balance, chroma enhancement and
color correction configuration.

The block type enum is shared across CAMSS ISPs so that userspace only
has to deal with a single set of block identifiers.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 include/uapi/linux/qcom-camss-config.h | 212 +++++++++++++++++++++++++++++++++
 1 file changed, 212 insertions(+)

diff --git a/include/uapi/linux/qcom-camss-config.h b/include/uapi/linux/qcom-camss-config.h
new file mode 100644
index 0000000000000..aa3d97cfcc78e
--- /dev/null
+++ b/include/uapi/linux/qcom-camss-config.h
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * Qualcomm CAMSS ISP Driver - Userspace API
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _UAPI_LINUX_QCOM_CAMSS_CONFIG_H
+#define _UAPI_LINUX_QCOM_CAMSS_CONFIG_H
+
+#include <linux/types.h>
+#include <linux/media/v4l2-isp.h>
+
+/**
+ * enum camss_params_block_type - CAMSS ISP parameter block identifiers
+ *
+ * Each value identifies one ISP processing block.  The value is placed in
+ * the @type field of &struct v4l2_isp_params_block_header.
+ *
+ * @CAMSS_PARAMS_WB_GAIN: white balance gains and offsets (CLC_WB),
+ *	&struct camss_params_wb_gain
+ * @CAMSS_PARAMS_CHROMA_ENHAN: RGB to YUV colour transfer matrix
+ *	(CLC_CHROMA_ENHAN), &struct camss_params_chroma_enhan
+ * @CAMSS_PARAMS_COLOR_CORRECT: colour correction matrix (CLC_CC),
+ *	&struct camss_params_color_correct
+ * @CAMSS_PARAMS_GAMMA: per-channel gamma correction curves (CLC_GLUT),
+ *	&struct camss_params_gamma
+ */
+enum camss_params_block_type {
+	CAMSS_PARAMS_WB_GAIN = 1,
+	CAMSS_PARAMS_CHROMA_ENHAN = 2,
+	CAMSS_PARAMS_COLOR_CORRECT = 3,
+	CAMSS_PARAMS_GAMMA = 4,
+};
+
+/* Number of entries in each gamma channel LUT. */
+#define CAMSS_GAMMA_LUT_SIZE	256
+
+/**
+ * struct camss_params_wb_gain - White Balance gains
+ *
+ * Implements the CLC_WB pipeline module.  The pipeline applies three
+ * sequential operations per channel:
+ *   1. Subtract sub-offset (black-level subtraction)
+ *   2. Multiply by gain    (colour balance)
+ *   3. Add add-offset      (output pedestal)
+ *
+ * Gains are 15uQ10 (15-bit unsigned, 10 fractional bits). Offsets
+ * are 16-bit unsigned, normalised to full input scale (65535 = 1.0)
+ *
+ * @header:   block header; @header.type = CAMSS_PARAMS_WB_GAIN
+ * @g_gain:   green channel gain (15uQ10, 1024 = 1.0)
+ * @b_gain:   blue  channel gain (15uQ10, 1024 = 1.0)
+ * @r_gain:   red   channel gain (15uQ10, 1024 = 1.0)
+ * @g_sub:    green sub-offset, subtracted before gain (16u)
+ * @b_sub:    blue  sub-offset, subtracted before gain (16u)
+ * @r_sub:    red   sub-offset, subtracted before gain (16u)
+ * @g_add:    green add-offset, added after gain (16u)
+ * @b_add:    blue  add-offset, added after gain (16u)
+ * @r_add:    red   add-offset, added after gain (16u)
+ * @_pad:     padding for 64-bit alignment, must be zero
+ */
+struct camss_params_wb_gain {
+	struct v4l2_isp_params_block_header header;
+	__u16 g_gain;
+	__u16 b_gain;
+	__u16 r_gain;
+	__u16 g_sub;
+	__u16 b_sub;
+	__u16 r_sub;
+	__u16 g_add;
+	__u16 b_add;
+	__u16 r_add;
+	__u16 _pad[3];
+} __attribute__((aligned(8)));
+
+/**
+ * struct camss_params_chroma_enhan - RGB to YUV colour transfer matrix
+ *
+ * Implements the CLC_CHROMA_ENHAN pipeline module. All coefficients are
+ * signed 12-bit fixed-point Q3.8 (range roughly -8.0 to +7.996).
+ *
+ * RGB2Y - Luma (Y) coefficients
+ * Y = v0 * R + v1 * G + v2 * B
+ *
+ * @luma_v0:  R-to-Y coefficient (12sQ8)
+ * @luma_v1:  G-to-Y coefficient (12sQ8)
+ * @luma_v2:  B-to-Y coefficient (12sQ8)
+ * @luma_k:   Y output offset    (9s,  0 = no offset)
+ *
+ * RGB2Cb - Chroma (Cb) coefficients
+ * Cb = a x ((B - G) + b(R - G)) + KCb
+ * with:
+ *   a = ap, when (B-G) + b(R-G) > 0; a = am, when (B-G) + b(R-G) ≤ 0;
+ *   b = bp when (R-G) > 0; b = bm when (R-G) ≤ 0
+ *
+ * @coeff_ap: Cb positive coefficient (12sQ8)
+ * @coeff_am: Cb negative coefficient (12sQ8)
+ * @coeff_bp: Cb positive coefficient (12sQ8)
+ * @coeff_bm: Cb negative coefficient (12sQ8)
+ * @kcb:      Cb output offset        (11s)
+ *
+ * RGB2Cr - Chroma (Cr) coefficients:
+ * Cr = c x ((R - G) + d(B - G)) + KCr
+ * with:
+ *   c = cp, when (R-G) + d(B-G) > 0; c = cm, when (R-G) + d(B-G) ≤ 0
+ *   d = dp when (B-G) > 0; d = dm when (B-G) ≤ 0
+ *
+ * @coeff_cp: Cr positive coefficient (12sQ8)
+ * @coeff_cm: Cr negative coefficient (12sQ8)
+ * @coeff_dp: Cr positive coefficient (12sQ8)
+ * @coeff_dm: Cr negative coefficient (12sQ8)
+ * @kcr:      Cr output offset        (11s)
+ *
+ * @header: generic block header; @header.type = CAMSS_PARAMS_CHROMA_ENHAN
+ * @_pad:   padding for 64-bit alignment, must be zero
+ */
+struct camss_params_chroma_enhan {
+	struct v4l2_isp_params_block_header header;
+	__u16 luma_v0;
+	__u16 luma_v1;
+	__u16 luma_v2;
+	__u16 luma_k;
+	__u16 coeff_ap;
+	__u16 coeff_am;
+	__u16 coeff_bp;
+	__u16 coeff_bm;
+	__u16 coeff_cp;
+	__u16 coeff_cm;
+	__u16 coeff_dp;
+	__u16 coeff_dm;
+	__u16 kcb;
+	__u16 kcr;
+	__u16 _pad[2];
+} __attribute__((aligned(8)));
+
+/**
+ * struct camss_params_color_correct - colour correction matrix
+ *
+ * Implements the CLC_CC pipeline module.  The matrix computes:
+ *   Out_ch0 (G) = a0*G + b0*B + c0*R + k0
+ *   Out_ch1 (B) = a1*G + b1*B + c1*R + k1
+ *   Out_ch2 (R) = a2*G + b2*B + c2*R + k2
+ *
+ * @header:  block header; @header.type = CAMSS_PARAMS_COLOR_CORRECT
+ * @a:       G-input coefficients per output channel (12s;
+ *           a[0]=Out_G, a[1]=Out_B, a[2]=Out_R)
+ * @b:       B-input coefficients (12s)
+ * @c:       R-input coefficients (12s)
+ * @k:       per-output-channel offsets (typically 9s effective)
+ * @qfactor: Q-format selector (2u):
+ *           0 = 12sQ7  (range ~-16.0 .. +15.992)
+ *           1 = 12sQ8  (range  ~-8.0 ..  +7.996)
+ *           2 = 12sQ9  (range  ~-4.0 ..  +3.998)
+ *           3 = 12sQ10 (range  ~-2.0 ..  +1.999)
+ * @_pad:    padding for 64-bit alignment, must be zero
+ */
+struct camss_params_color_correct {
+	struct v4l2_isp_params_block_header header;
+	__u16 a[3];
+	__u16 b[3];
+	__u16 c[3];
+	__u16 k[3];
+	__u16 qfactor;
+	__u16 _pad[3];
+} __attribute__((aligned(8)));
+
+/**
+ * struct camss_params_gamma - per-channel gamma correction curves
+ *
+ * Implements the CLC_GLUT pipeline module, applied in the RGB domain.  It
+ * holds one independent lookup table per colour channel. Each table is a
+ * direct (not segmented) map of input level to output level.
+ *
+ * Each table has @CAMSS_GAMMA_LUT_SIZE (256) entries of 16-bit unsigned
+ * output. The number of significant output bits follows the width of the
+ * engine's internal bus; the upper bits are ignored by the hardware.
+ *
+ * The module maps a 12-bit input to an 8-bit output: the top 8 input bits
+ * index the table and the low 4 bits are used to linearly interpolate
+ * between adjacent entries. Entry i therefore represents the output for
+ * input level i/255 of full scale.
+ * Output range: 0x00 = black, 0xFF = white.
+ *
+ * How to fill a curve (same on all three channels for pure luminance
+ * gamma; different curves per channel additionally shift colour balance):
+ *
+ *   Identity (pass-through, gamma 1.0):
+ *     lut[i] = i;                                // i = 0..255
+ *
+ *   Encode with gamma g (e.g. sRGB-like, g = 2.2):
+ *     lut[i] = round(pow(i / 255.0, 1.0 / g) * 255.0);
+ *
+ * @header:  block header; @header.type = CAMSS_PARAMS_GAMMA
+ * @glut:    green channel gamma curve
+ * @blut:    blue  channel gamma curve
+ * @rlut:    red   channel gamma curve
+ */
+struct camss_params_gamma {
+	struct v4l2_isp_params_block_header header;
+	__u16 glut[CAMSS_GAMMA_LUT_SIZE];
+	__u16 blut[CAMSS_GAMMA_LUT_SIZE];
+	__u16 rlut[CAMSS_GAMMA_LUT_SIZE];
+} __attribute__((aligned(8)));
+
+#define CAMSS_PARAMS_OPE_MAX_PAYLOAD		\
+	(sizeof(struct camss_params_wb_gain)	+\
+	 sizeof(struct camss_params_chroma_enhan)	+\
+	 sizeof(struct camss_params_color_correct)	+\
+	 sizeof(struct camss_params_gamma))
+
+#endif /* _UAPI_LINUX_QCOM_CAMSS_CONFIG_H */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 10/74] media: Documentation: uapi: Add qcom-camss ISP params documentation
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (8 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 09/74] media: uapi: Add CAMSS ISP configuration definition bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 11/74] media: qcom: camss: Fix invalid declaration of PIX for SDM670 bod
                   ` (64 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Loic Poulain <loic.poulain@oss.qualcomm.com>

Add documentation for the Qualcomm CAMSS ISP parameters metadata format
(V4L2_META_FMT_QCOM_ISP_PARAMS). The format is built on the V4L2
extensible ISP parameters system, with per-block structs defined in the
qcom-camss-config.h uAPI header, and is designed to be shared by any
CAMSS ISP engine exposing a parameters metadata output video node. The
Offline Processing Engine (OPE) ope_params node is the first consumer,
with additional engines expected to add their own parameter blocks in
the future.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
 .../userspace-api/media/v4l/meta-formats.rst       |   1 +
 .../userspace-api/media/v4l/metafmt-qcom-isp.rst   | 147 +++++++++++++++++++++
 MAINTAINERS                                        |   1 +
 3 files changed, 149 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst
index 3e0cab153f0ac..1b39bb844cbba 100644
--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
+++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
@@ -20,6 +20,7 @@ These formats are used for the :ref:`metadata` interface only.
     metafmt-intel-ipu3
     metafmt-pisp-be
     metafmt-pisp-fe
+    metafmt-qcom-isp
     metafmt-rkisp1
     metafmt-uvc
     metafmt-uvc-msxu-1-5
diff --git a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
new file mode 100644
index 0000000000000..2f3654a9ba897
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
@@ -0,0 +1,147 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. c:namespace:: V4L
+
+.. _v4l2-meta-fmt-qcom-isp-params:
+
+**************************************
+V4L2_META_FMT_QCOM_ISP_PARAMS ('QCIP')
+**************************************
+
+Configuration Parameters
+========================
+
+The ``V4L2_META_FMT_QCOM_ISP_PARAMS`` format carries image processing
+configuration for the ISP engines found in the Qualcomm Camera Subsystem
+(CAMSS). It is passed to a metadata output video node using the
+:c:type:`v4l2_meta_format` interface.
+
+Rather than a single struct containing sub-structs for each configurable area
+of the ISP, parameters use the :ref:`v4l2-isp` parameters system, through which
+groups of parameters are defined as distinct structs or "blocks" which may be
+added to the data member of :c:type:`v4l2_isp_params_buffer`. Userspace is
+responsible for populating the data member with the blocks that need to be
+configured by the driver. Each block-specific struct embeds
+:c:type:`v4l2_isp_params_block_header` as its first member and userspace must
+populate the type member with a value from :c:type:`camss_params_block_type`.
+Populated blocks must be placed consecutively in the data member, and the
+combined size of all populated blocks must be set in the data_size member of
+:c:type:`v4l2_isp_params_buffer`.
+
+The set of supported blocks depends on the CAMSS engine consuming the buffer.
+The block definitions themselves are shared across CAMSS ISPs; currently the
+Offline Processing Engine (OPE) is the only engine consuming them, through its
+``ope_params`` metadata output video node. Additional engines and blocks may be
+added to this format in the future.
+
+A block carrying ``V4L2_ISP_PARAMS_FL_BLOCK_DISABLE`` bypasses the
+corresponding hardware module. Any other block updates the module's
+configuration and leaves it enabled. Blocks omitted from a buffer keep their
+previously programmed configuration and enable state; until userspace submits
+a block for a given module, the driver's default configuration applies.
+
+OPE processing pipeline
+=======================
+
+The OPE is a memory-to-memory engine that reads a Bayer RAW frame from its
+``ope_input`` node and writes a YUV frame to its ``ope_disp_output`` node. The
+parameter blocks configure fixed-function hardware modules that the frame data
+passes through, in the following order:
+
+.. code-block:: none
+
+	 Bayer RAW in            RGB domain                      YUV domain      YUV out
+	 (8/10-bit)   +------+   +------+   +------+   +------+   +------+   +------+   (NV12/NV16/
+	  ----------> |  WB  |-->| DEMO |-->|  CC  |-->| GLUT |-->|CHROMA|-->| DSC  |----------->
+	              +------+   +------+   +------+   +------+   |ENHAN |   +------+    NV24/GREY)
+	                                                         +------+
+
+The stages, and the parameter block that configures each one, are:
+
+.. flat-table:: OPE pipeline stages
+    :header-rows: 1
+    :stub-columns: 0
+
+    * - Stage
+      - Module
+      - Parameter block
+      - Function
+    * - WB
+      - CLC_WB
+      - :c:type:`camss_params_wb_gain`
+      - Per-channel white balance gains and black-level / pedestal offsets,
+        applied to the raw Bayer data.
+    * - DEMO
+      - CLC_DEMO
+      - *(none)*
+      - Demosaic: reconstructs a full-resolution RGB image from the Bayer
+        mosaic. Always enabled; not configurable through this format.
+    * - CC
+      - CLC_CC
+      - :c:type:`camss_params_color_correct`
+      - Color correction matrix applied in the RGB domain.
+    * - GLUT
+      - CLC_GLUT
+      - :c:type:`camss_params_gamma`
+      - Per-channel gamma correction curves (256-entry LUTs).
+    * - CHROMA_ENHAN
+      - CLC_CHROMA_ENHAN
+      - :c:type:`camss_params_chroma_enhan`
+      - RGB to YUV color transfer matrix.
+    * - DSC
+      - Downscaler
+      - *(none)*
+      - Chroma (and, when required, luma) downscaling to produce the requested
+        YUV subsampling, e.g. YUV 4:4:4 to 4:2:2 (NV16) or 4:2:0 (NV12).
+
+The input node accepts 8-bit and 10-bit packed Bayer RAW formats (for example
+``V4L2_PIX_FMT_SRGGB8`` and ``V4L2_PIX_FMT_SRGGB10P``). The output node
+produces semi-planar YUV (``V4L2_PIX_FMT_NV12`` / ``NV21`` / ``NV16`` /
+``NV61`` / ``NV24`` / ``NV42``) or luma-only ``V4L2_PIX_FMT_GREY``. A
+configurable stage is bypassed while its block carries
+``V4L2_ISP_PARAMS_FL_BLOCK_DISABLE``.
+
+The following example populates an OPE parameters buffer with a white balance
+and a gamma correction block:
+
+.. code-block:: c
+
+	struct v4l2_isp_params_buffer *params =
+		(struct v4l2_isp_params_buffer *)buffer;
+
+	params->version = V4L2_ISP_PARAMS_VERSION_V1;
+	params->data_size = sizeof(struct camss_params_wb_gain) +
+			    sizeof(struct camss_params_gamma);
+
+	__u8 *data = params->data;
+
+	struct camss_params_wb_gain *wb =
+		(struct camss_params_wb_gain *)data;
+
+	memset(wb, 0, sizeof(*wb));
+	wb->header.type = CAMSS_PARAMS_WB_GAIN;
+	wb->header.flags = V4L2_ISP_PARAMS_FL_BLOCK_ENABLE;
+	wb->header.size = sizeof(struct camss_params_wb_gain);
+
+	/* Unity gain on all three channels (15uQ10, 1024 = 1.0) */
+	wb->g_gain = 1024;
+	wb->b_gain = 1024;
+	wb->r_gain = 1024;
+
+	data += sizeof(struct camss_params_wb_gain);
+
+	struct camss_params_gamma *gamma =
+		(struct camss_params_gamma *)data;
+
+	memset(gamma, 0, sizeof(*gamma));
+	gamma->header.type = CAMSS_PARAMS_GAMMA;
+	gamma->header.flags = V4L2_ISP_PARAMS_FL_BLOCK_ENABLE;
+	gamma->header.size = sizeof(struct camss_params_gamma);
+
+	/* Identity curve (pass-through, gamma 1.0) */
+	for (unsigned int i = 0; i < CAMSS_GAMMA_LUT_SIZE; i++)
+		gamma->glut[i] = gamma->blut[i] = gamma->rlut[i] = i;
+
+Qualcomm CAMSS ISP uAPI data types
+==================================
+
+.. kernel-doc:: include/uapi/linux/qcom-camss-config.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 8014b9f8253ed..ebb857e2168cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22119,6 +22119,7 @@ L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	Documentation/admin-guide/media/qcom_camss.rst
 F:	Documentation/devicetree/bindings/media/qcom,*camss*
+F:	Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
 F:	drivers/media/platform/qcom/camss/
 
 QUALCOMM CLOCK DRIVERS

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 11/74] media: qcom: camss: Fix invalid declaration of PIX for SDM670
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (9 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 10/74] media: Documentation: uapi: Add qcom-camss ISP params documentation bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 12/74] media: qcom: camss: Fix invalid declaration of PIX for SDM845 bod
                   ` (63 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

line_num is declarative of the number and type of data-interfaces a VFE
has in CAMSS. The fourth line on full VFEs is reserved to the "PIX" path -
meaning the path that can do YUV, downscaling, stats, params or some
version of that.

In contrast the raw dump interfaces (RDI) 0, 1, 2 can only write
unformatted pixel-data and cannot generate stats.

The PIX path lives at a different register offset and has significantly
different setup to RDI.

VFE Lite has four RDI interfaces where VFE (full) has three RDI and one PIX
interface.

Unless/until PIX is actually implemented for SDM670 reduce line_num to
three to stop populating a pix path which simply isn't implemented.

Fixes: c52643b24152 ("media: qcom: camss: add support for SDM670 camss")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 40a993ade5f6d..f46ad1db6dbbe 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1202,7 +1202,7 @@ static const struct camss_subdev_resources vfe_res_670[] = {
 		.reg = { "vfe0" },
 		.interrupt = { "vfe0" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.has_pd = true,
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
@@ -1224,7 +1224,7 @@ static const struct camss_subdev_resources vfe_res_670[] = {
 		.reg = { "vfe1" },
 		.interrupt = { "vfe1" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.has_pd = true,
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 12/74] media: qcom: camss: Fix invalid declaration of PIX for SDM845
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (10 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 11/74] media: qcom: camss: Fix invalid declaration of PIX for SDM670 bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 13/74] media: qcom: camss: Fix invalid declaration of PIX for sc8280xp bod
                   ` (62 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

sdm845 similarly to sdm670 has declared an additional line_num on the full
VFE path, which implies support for PIX which does not exist.

Implement the same fix for sdm845 as was done for sdm670.

Fixes: ae44829a4a97a3 ("media: qcom: camss: Add per sub-device type resources")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index f46ad1db6dbbe..69b976bac60aa 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1455,7 +1455,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
 		.reg = { "vfe0" },
 		.interrupt = { "vfe0" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife0",
 			.has_pd = true,
 			.hw_ops = &vfe_ops_170,
@@ -1483,7 +1483,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
 		.reg = { "vfe1" },
 		.interrupt = { "vfe1" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife1",
 			.has_pd = true,
 			.hw_ops = &vfe_ops_170,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 13/74] media: qcom: camss: Fix invalid declaration of PIX for sc8280xp
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (11 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 12/74] media: qcom: camss: Fix invalid declaration of PIX for SDM845 bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 14/74] media: qcom: camss: Fix invalid declaration of PIX for x1e80100 bod
                   ` (61 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

sc8280xp similarly to sdm670 has declared an additional line_num on the full
VFE path, which implies support for PIX which does not exist.

Implement the same fix for sc8280xp as was done for sdm670.

Fixes: ae44829a4a97a3 ("media: qcom: camss: Add per sub-device type resources")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 69b976bac60aa..0960e7c1ce46a 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -2809,7 +2809,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 		.reg = { "vfe0" },
 		.interrupt = { "vfe0" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
@@ -2829,7 +2829,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 		.reg = { "vfe1" },
 		.interrupt = { "vfe1" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
@@ -2849,7 +2849,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 		.reg = { "vfe2" },
 		.interrupt = { "vfe2" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
@@ -2869,7 +2869,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 		.reg = { "vfe3" },
 		.interrupt = { "vfe3" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife3",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 14/74] media: qcom: camss: Fix invalid declaration of PIX for x1e80100
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (12 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 13/74] media: qcom: camss: Fix invalid declaration of PIX for sc8280xp bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 15/74] media: qcom: camss: csid: Configure the stream on every s_stream bod
                   ` (60 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue, stable

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

x1e80100 similarly to sdm670 has declared an additional line_num on the full
VFE path, which implies support for PIX which does not exist.

Implement the same fix for x1e80100 as was done for sdm670.

Fixes: 1830cf0f56c3 ("media: qcom: camss: Add x1e80100 specific support")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 0960e7c1ce46a..e7a1a25d7c9a3 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4430,7 +4430,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 		.reg = { "vfe0" },
 		.interrupt = { "vfe0" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
@@ -4454,7 +4454,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 		.reg = { "vfe1" },
 		.interrupt = { "vfe1" },
 		.vfe = {
-			.line_num = 4,
+			.line_num = 3,
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 15/74] media: qcom: camss: csid: Configure the stream on every s_stream
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (13 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 14/74] media: qcom: camss: Fix invalid declaration of PIX for x1e80100 bod
@ 2026-10-05 17:13 ` bod
  2026-10-05 17:13 ` [PATCH 16/74] media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845 Bryan O'Donoghue
                   ` (59 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

csid_set_stream() only calls configure_stream() when need_vc_update is
set, and need_vc_update is only set at power on and on a CSID link
change. Stopping and restarting a stream while the pipeline stays
powered, as userspace does when it keeps the video node open across
STREAMOFF and STREAMON, therefore breaks the CSID in two ways:

- STREAMOFF does not stop the CSID: the paths it enabled keep running
  after the VFE has stopped.
- The following STREAMON does not configure the CSID: a format set
  between the two streams is never programmed, and the CSID runs with
  the previous stream's configuration.

need_vc_update was added so that several video nodes streaming through
one CSID would configure it only once. Its counterpart in
video_stop_streaming() was removed by commit 25f18cb1b673 ("media: qcom:
camss: Remove use_count guard in stop_streaming"). Drop the rest of it and
configure the stream on every s_stream.

Fixes: 3c4ed72a16bc ("media: camss: sm8250: Virtual channels for CSID")
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid.c | 9 +--------
 drivers/media/platform/qcom/camss/camss-csid.h | 1 -
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 48459b46a981b..645e02ad6b9b1 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -721,8 +721,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 			return ret;
 		}
 
-		csid->phy.need_vc_update = true;
-
 		enable_irq(csid->irq);
 
 		ret = csid->res->hw_ops->reset(csid);
@@ -777,10 +775,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 			return -ENOLINK;
 	}
 
-	if (csid->phy.need_vc_update) {
-		csid->res->hw_ops->configure_stream(csid, enable);
-		csid->phy.need_vc_update = false;
-	}
+	csid->res->hw_ops->configure_stream(csid, enable);
 
 	return 0;
 }
@@ -1306,8 +1301,6 @@ static int csid_link_setup(struct media_entity *entity,
 		else
 			csid->phy.en_vc &= ~BIT(local->index - 1);
 
-		csid->phy.need_vc_update = true;
-
 		dev_dbg(dev, "%s: Enabled CSID virtual channels mask 0x%x\n",
 			__func__, csid->phy.en_vc);
 	}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 5296b10f6bac8..53f43ae7b9327 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -69,7 +69,6 @@ struct csid_phy_config {
 	u8 lane_cnt;
 	u32 lane_assign;
 	u32 en_vc;
-	u8 need_vc_update;
 };
 
 struct csid_device;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 16/74] media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (14 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 15/74] media: qcom: camss: csid: Configure the stream on every s_stream bod
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 17/74] media: qcom: camss: Define PIX formats for x1e PIX interface Bryan O'Donoghue
                   ` (58 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Right now the vfe_formats_pix_845 points to the same data as
vfe_formats_rdi_845. When we actually switch on the PIX formats though only
some of the PIX interfaces will support the format conversions. Repoint
existing PIX interfaces to the RDI formats they actually support. As YUV
formats are enabled on a per SoC basis the enabled SoC's can be pointed at
the expanded list.

Repoint existing stuff to the right location as a precursor.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss.c | 98 +++++++++++++++----------------
 1 file changed, 49 insertions(+), 49 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index e7a1a25d7c9a3..ff09873706c0d 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -777,7 +777,7 @@ static const struct camss_subdev_resources vfe_res_2290[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_340,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 
@@ -797,7 +797,7 @@ static const struct camss_subdev_resources vfe_res_2290[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_340,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -1207,7 +1207,7 @@ static const struct camss_subdev_resources vfe_res_670[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 
@@ -1229,7 +1229,7 @@ static const struct camss_subdev_resources vfe_res_670[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 
@@ -1249,7 +1249,7 @@ static const struct camss_subdev_resources vfe_res_670[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	}
 };
@@ -1460,7 +1460,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
 			.has_pd = true,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 
@@ -1488,7 +1488,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
 			.has_pd = true,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 
@@ -1514,7 +1514,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	}
 };
@@ -1642,7 +1642,7 @@ static const struct camss_subdev_resources vfe_res_sm6150[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -1665,7 +1665,7 @@ static const struct camss_subdev_resources vfe_res_sm6150[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 */
@@ -1685,7 +1685,7 @@ static const struct camss_subdev_resources vfe_res_sm6150[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -2150,7 +2150,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_480,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -2176,7 +2176,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_480,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 (lite) */
@@ -2200,7 +2200,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_480,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE3 (lite) */
@@ -2224,7 +2224,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_480,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -2467,7 +2467,7 @@ static const struct camss_subdev_resources vfe_res_7280[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -2493,7 +2493,7 @@ static const struct camss_subdev_resources vfe_res_7280[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 */
@@ -2519,7 +2519,7 @@ static const struct camss_subdev_resources vfe_res_7280[] = {
 			.has_pd = true,
 			.pd_name = "ife2",
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE3 (lite) */
@@ -2541,7 +2541,7 @@ static const struct camss_subdev_resources vfe_res_7280[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE4 (lite) */
@@ -2563,7 +2563,7 @@ static const struct camss_subdev_resources vfe_res_7280[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -2813,7 +2813,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -2833,7 +2833,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 */
@@ -2853,7 +2853,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE3 */
@@ -2873,7 +2873,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.pd_name = "ife3",
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE_LITE_0 */
@@ -2892,7 +2892,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE_LITE_1 */
@@ -2911,7 +2911,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE_LITE_2 */
@@ -2930,7 +2930,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE_LITE_3 */
@@ -2949,7 +2949,7 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_170,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -3220,7 +3220,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -3244,7 +3244,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 */
@@ -3268,7 +3268,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE3 lite */
@@ -3289,7 +3289,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE4 lite */
@@ -3310,7 +3310,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -3535,7 +3535,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* VFE1 */
@@ -3562,7 +3562,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* VFE2 */
@@ -3589,7 +3589,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* VFE3 lite */
@@ -3614,7 +3614,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* VFE4 lite */
@@ -3639,7 +3639,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 };
@@ -4003,7 +4003,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.pd_name = NULL,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE1 */
@@ -4031,7 +4031,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.pd_name = NULL,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE2 (lite) */
@@ -4056,7 +4056,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE3 (lite) */
@@ -4081,7 +4081,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE4 (lite) */
@@ -4106,7 +4106,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE5 (lite) */
@@ -4131,7 +4131,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 	/* VFE6 (lite) */
@@ -4156,7 +4156,7 @@ static const struct camss_subdev_resources vfe_res_8775p[] = {
 			.is_lite = true,
 			.hw_ops = &vfe_ops_690,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		}
 	},
 };
@@ -4434,7 +4434,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* IFE1 */
@@ -4458,7 +4458,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* IFE_LITE_0 */
@@ -4481,7 +4481,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 	/* IFE_LITE_1 */
@@ -4504,7 +4504,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.line_num = 4,
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_pix_845
+			.formats_pix = &vfe_formats_rdi_845
 		},
 	},
 };

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 17/74] media: qcom: camss: Define PIX formats for x1e PIX interface
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (15 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 16/74] media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845 Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 18/74] media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt() Bryan O'Donoghue
                   ` (57 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 93 ++++++++++++++++++++++++++-
 drivers/media/platform/qcom/camss/camss.c     |  4 +-
 2 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 319d191589884..5b5201b55a485 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -174,6 +174,94 @@ static const struct camss_format_info formats_rdi_845[] = {
 	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
 };
 
+static const struct camss_format_info formats_pix_845[] = {
+	/* Passthrought formats */
+	{ MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+	{ MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+	{ MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+	{ MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_SBGGR10, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14, V4L2_PIX_FMT_SBGGR14P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14, V4L2_PIX_FMT_SGBRG14P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14, V4L2_PIX_FMT_SGRBG14P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14, V4L2_PIX_FMT_SRGGB14P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+	{ MEDIA_BUS_FMT_Y8_1X8, 8, V4L2_PIX_FMT_GREY, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+	{ MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_Y10, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+
+	/* 4:2:0 Bayer to YUV */
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+
+	/* 4:2:2 Bayer to YUV */
+	{ MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+	{ MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+	  PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+};
+
 static const struct camss_format_info formats_pix_8x16[] = {
 	{ MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
 	  PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
@@ -277,10 +365,9 @@ const struct camss_formats vfe_formats_rdi_845 = {
 	.formats = formats_rdi_845
 };
 
-/* TODO: Replace with pix formats */
 const struct camss_formats vfe_formats_pix_845 = {
-	.nformats = ARRAY_SIZE(formats_rdi_845),
-	.formats = formats_rdi_845
+	.nformats = ARRAY_SIZE(formats_pix_845),
+	.formats = formats_pix_845
 };
 
 static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index ff09873706c0d..6f3de2c185bc9 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -4434,7 +4434,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_rdi_845
+			.formats_pix = &vfe_formats_pix_845
 		},
 	},
 	/* IFE1 */
@@ -4458,7 +4458,7 @@ static const struct camss_subdev_resources vfe_res_x1e80100[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_680,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_rdi_845
+			.formats_pix = &vfe_formats_pix_845
 		},
 	},
 	/* IFE_LITE_0 */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 18/74] media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt()
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (16 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 17/74] media: qcom: camss: Define PIX formats for x1e PIX interface Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 19/74] media: qcom: camss: vfe: Represent output as an array instead of a singleton Bryan O'Donoghue
                   ` (56 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

vfe_bus_v3_packer_fmt()'s job in life is to translate a given v4l2 pixel
format and plane into the appropriate bus packing format for v3 class
hardware.

Other versions are currently not covered.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 53 +++++++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.h | 32 ++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 5b5201b55a485..c95fe5b0b05fc 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -370,6 +370,59 @@ const struct camss_formats vfe_formats_pix_845 = {
 	.formats = formats_pix_845
 };
 
+u32 vfe_bus_v3_packer_fmt(u32 v4l2_fmt, u8 plane, u8 align_shift)
+{
+	switch (v4l2_fmt) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV12M:
+	case V4L2_PIX_FMT_NV16:
+		return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_LSB_MSB_10;
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV21M:
+	case V4L2_PIX_FMT_NV61:
+		return plane ? VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_LSB_MSB_10_ODD_EVEN
+			     : VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_LSB_MSB_10;
+
+	case V4L2_PIX_FMT_SRGGB10P:
+	case V4L2_PIX_FMT_SGRBG10P:
+	case V4L2_PIX_FMT_SGBRG10P:
+	case V4L2_PIX_FMT_SBGGR10P:
+		return VFE_BUS_WM_PACKER_FMT_V3_MIPI10;
+	case V4L2_PIX_FMT_SRGGB12P:
+	case V4L2_PIX_FMT_SGRBG12P:
+	case V4L2_PIX_FMT_SGBRG12P:
+	case V4L2_PIX_FMT_SBGGR12P:
+		return VFE_BUS_WM_PACKER_FMT_V3_MIPI12;
+	case V4L2_PIX_FMT_SRGGB14P:
+	case V4L2_PIX_FMT_SGRBG14P:
+	case V4L2_PIX_FMT_SGBRG14P:
+	case V4L2_PIX_FMT_SBGGR14P:
+		return VFE_BUS_WM_PACKER_FMT_V3_MIPI14;
+
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
+		return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_10BPP |
+		       BIT(align_shift);
+	case V4L2_PIX_FMT_SRGGB12:
+	case V4L2_PIX_FMT_SGRBG12:
+	case V4L2_PIX_FMT_SGBRG12:
+	case V4L2_PIX_FMT_SBGGR12:
+		return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_12BPP |
+		       BIT(align_shift);
+
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+		return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8;
+	}
+
+	WARN_ONCE(1, "no packer format for 0x%08x\n", v4l2_fmt);
+	return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_128;
+}
+
 static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			    unsigned int index, u32 src_req_code)
 {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 089f525b98cf5..98d403a71cf95 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -56,6 +56,27 @@ enum vfe_line_id {
 	VFE_LINE_NUM_MAX = 4
 };
 
+enum vfe_packer_format_v3 {
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_128 = 0,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_ODD_EVEN,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_LSB_MSB_10,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_8_LSB_MSB_10_ODD_EVEN,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_10BPP,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_12BPP,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_14BPP,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_16_16BPP,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_32,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN_64,
+	VFE_BUS_WM_PACKER_FMT_V3_TP_10,
+	VFE_BUS_WM_PACKER_FMT_V3_MIPI10,
+	VFE_BUS_WM_PACKER_FMT_V3_MIPI12,
+	VFE_BUS_WM_PACKER_FMT_V3_MIPI14,
+	VFE_BUS_WM_PACKER_FMT_V3_MIPI20,
+	VFE_BUS_WM_PACKER_FMT_V3_PLAIN32_20BPP,
+	VFE_BUS_WM_PACKER_FMT_V3_MAX,
+};
+
 struct vfe_output {
 	u8 wm_num;
 	u8 wm_idx[3];
@@ -315,4 +336,15 @@ int vfe_enable_output_v2(struct vfe_line *line);
 int vfe_queue_buffer_v2(struct camss_video *vid,
 			struct camss_buffer *buf);
 
+/*
+ * vfe_bus_v3_packer_fmt
+ *
+ * @v4l2_fmt: v4l2 format
+ * @plane: plane for the given format
+ * @align_shift: bit position of the PLAIN16 LSB alignment flag
+ *
+ * Return: the bus packer format for the register
+ */
+u32 vfe_bus_v3_packer_fmt(u32 v4l2_fmt, u8 plane, u8 align_shift);
+
 #endif /* QC_MSM_CAMSS_VFE_H */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 19/74] media: qcom: camss: vfe: Represent output as an array instead of a singleton
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (17 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 18/74] media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt() Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 20/74] media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output Bryan O'Donoghue
                   ` (55 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

In order to instantiate multiple v4l2 sub-devices off of one "PIX" device
we need to represent more than one output per IFE. Right now the
representation between an IFE line and an output is 1:1. That simple link
works fine for the case of a raw data dump however, for multiple SOURCE and
SINK pads connected to a PIX device, we will require more outputs.

The first low-intervention step is to represent the existing singleton
output as one instance of an array of outputs. Since container_of() won't
work on an array element as input, introduce a line pointer to the output
structure to make that linkage back between output and line.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c  |  4 ++--
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c  |  4 ++--
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c  |  4 ++--
 drivers/media/platform/qcom/camss/camss-vfe-4-8.c  |  4 ++--
 drivers/media/platform/qcom/camss/camss-vfe-480.c  |  6 ++---
 drivers/media/platform/qcom/camss/camss-vfe-gen1.c | 16 ++++++-------
 drivers/media/platform/qcom/camss/camss-vfe.c      | 26 +++++++++++++---------
 drivers/media/platform/qcom/camss/camss-vfe.h      |  6 ++++-
 8 files changed, 39 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index e5ee7e717b3bc..d2dc2acc9d234 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -490,7 +490,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	vfe->res->hw_ops->reg_update_clear(vfe, line_id);
 
-	output = &vfe->line[line_id].output;
+	output = &vfe->line[line_id].output[0];
 
 	if (output->wait_reg_update) {
 		output->wait_reg_update = 0;
@@ -521,7 +521,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 				    "Received wm done for unmapped index\n");
 		goto out_unlock;
 	}
-	output = &vfe->line[vfe->wm_output_map[wm]].output;
+	output = &vfe->line[vfe->wm_output_map[wm]].output[0];
 
 	ready_buf = output->buf[0];
 	if (!ready_buf) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
index 9cf1ccdb2fe7c..a2a91217a3cf8 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -475,7 +475,7 @@ static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
 static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
-	struct vfe_line *line = container_of(output, struct vfe_line, output);
+	struct vfe_line *line = output->line;
 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	unsigned int i;
@@ -555,7 +555,7 @@ static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
 static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 				    enum vfe_line_id line_id, u8 enable)
 {
-	struct vfe_output *output = &vfe->line[line_id].output;
+	struct vfe_output *output = &vfe->line[line_id].output[0];
 	unsigned int i;
 	u32 irq_en0;
 	u32 irq_en1;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index 76729607db02d..2eb4c3d505ebf 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -565,7 +565,7 @@ static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
 static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
-	struct vfe_line *line = container_of(output, struct vfe_line, output);
+	struct vfe_line *line = output->line;
 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 
@@ -706,7 +706,7 @@ static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
 static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 				    enum vfe_line_id line_id, u8 enable)
 {
-	struct vfe_output *output = &vfe->line[line_id].output;
+	struct vfe_output *output = &vfe->line[line_id].output[0];
 	unsigned int i;
 	u32 irq_en0;
 	u32 irq_en1;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
index b2f7d855d8dd0..3166660d864ec 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -536,7 +536,7 @@ static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
 static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
-	struct vfe_line *line = container_of(output, struct vfe_line, output);
+	struct vfe_line *line = output->line;
 	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 
@@ -678,7 +678,7 @@ static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
 static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 				    enum vfe_line_id line_id, u8 enable)
 {
-	struct vfe_output *output = &vfe->line[line_id].output;
+	struct vfe_output *output = &vfe->line[line_id].output[0];
 	unsigned int i;
 	u32 irq_en0;
 	u32 irq_en1;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index d73f733fde045..616d80ae1da74 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -164,8 +164,8 @@ static void vfe_enable_irq(struct vfe_device *vfe)
 
 	for (i = 0; i < MAX_VFE_OUTPUT_LINES; i++) {
 		/* Enable IRQ for newly added lines, but also keep already running lines's IRQ */
-		if (vfe->line[i].output.state == VFE_OUTPUT_RESERVED ||
-		    vfe->line[i].output.state == VFE_OUTPUT_ON) {
+		if (vfe->line[i].output[0].state == VFE_OUTPUT_RESERVED ||
+		    vfe->line[i].output[0].state == VFE_OUTPUT_ON) {
 			bus_irq_mask |= BUS_IRQ_MASK_0_RDI_RUP(vfe, i)
 					| BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i));
 			}
@@ -242,7 +242,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	vfe_reg_update_clear(vfe, line_id);
 
-	output = &vfe->line[line_id].output;
+	output = &vfe->line[line_id].output[0];
 
 	if (output->wait_reg_update) {
 		output->wait_reg_update = 0;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
index d84a375e33187..3e3d103e0d09d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -36,7 +36,7 @@ int vfe_gen1_halt(struct vfe_device *vfe)
 static int vfe_disable_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
+	struct vfe_output *output = &line->output[0];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
 	unsigned long flags;
 	unsigned long time;
@@ -162,13 +162,13 @@ static void vfe_output_frame_drop(struct vfe_device *vfe,
 		vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm_idx[i], drop_pattern);
 	}
 
-	vfe->res->hw_ops->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
+	vfe->res->hw_ops->reg_update(vfe, output->line->id);
 }
 
 static int vfe_enable_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
+	struct vfe_output *output = &line->output[0];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
 	struct media_pad *sensor_pad;
 	unsigned long flags;
@@ -289,7 +289,7 @@ static int vfe_get_output(struct vfe_line *line)
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
-	output = &line->output;
+	output = &line->output[0];
 	if (output->state > VFE_OUTPUT_RESERVED) {
 		dev_err(vfe->camss->dev, "Output is running\n");
 		goto error;
@@ -526,7 +526,7 @@ static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
 	unsigned long flags;
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
-	output = &vfe->line[line_id].output;
+	output = &vfe->line[line_id].output[0];
 	if (output->gen1.wait_sof) {
 		output->gen1.wait_sof = 0;
 		complete(&output->sof);
@@ -548,7 +548,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	vfe->res->hw_ops->reg_update_clear(vfe, line_id);
 
-	output = &line->output;
+	output = &line->output[0];
 
 	if (output->wait_reg_update) {
 		output->wait_reg_update = 0;
@@ -625,7 +625,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 				    "Received wm done for unmapped index\n");
 		goto out_unlock;
 	}
-	output = &vfe->line[vfe->wm_output_map[wm]].output;
+	output = &vfe->line[vfe->wm_output_map[wm]].output[0];
 
 	if (output->gen1.active_buf == active_index && 0) {
 		dev_err_ratelimited(vfe->camss->dev,
@@ -693,7 +693,7 @@ static int vfe_queue_buffer(struct camss_video *vid, struct camss_buffer *buf)
 	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output;
+	output = &line->output[0];
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index c95fe5b0b05fc..54ab906b01a82 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -604,7 +604,7 @@ void vfe_buf_done(struct vfe_device *vfe, int wm)
 				    "Received wm done for unmapped index\n");
 		goto out_unlock;
 	}
-	output = &vfe->line[vfe->wm_output_map[wm]].output;
+	output = &vfe->line[vfe->wm_output_map[wm]].output[0];
 
 	ready_buf = output->buf[0];
 	if (!ready_buf) {
@@ -645,7 +645,7 @@ void vfe_buf_done(struct vfe_device *vfe, int wm)
 int vfe_enable_output_v2(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
+	struct vfe_output *output = &line->output[0];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
 	struct media_pad *sensor_pad;
 	unsigned long flags;
@@ -719,7 +719,7 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
 	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output;
+	output = &line->output[0];
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
@@ -798,7 +798,7 @@ int vfe_get_output_v2(struct vfe_line *line)
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
-	output = &line->output;
+	output = &line->output[0];
 	if (output->state > VFE_OUTPUT_RESERVED) {
 		dev_err(vfe->camss->dev, "Output is running\n");
 		goto error;
@@ -849,7 +849,7 @@ static void vfe_init_outputs(struct vfe_device *vfe)
 	int i;
 
 	for (i = 0; i < vfe->res->line_num; i++) {
-		struct vfe_output *output = &vfe->line[i].output;
+		struct vfe_output *output = &vfe->line[i].output[0];
 
 		output->state = VFE_OUTPUT_OFF;
 		output->buf[0] = NULL;
@@ -933,7 +933,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output,
 int vfe_put_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
+	struct vfe_output *output = &line->output[0];
 	unsigned long flags;
 	unsigned int i;
 
@@ -951,7 +951,7 @@ int vfe_put_output(struct vfe_line *line)
 static int vfe_disable_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
+	struct vfe_output *output = &line->output[0];
 	unsigned long flags;
 	unsigned int i;
 
@@ -1325,7 +1325,7 @@ int vfe_flush_buffers(struct camss_video *vid,
 	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output;
+	output = &line->output[0];
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
@@ -1387,7 +1387,7 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
 	int ret;
 
 	if (enable) {
-		line->output.state = VFE_OUTPUT_RESERVED;
+		line->output[0].state = VFE_OUTPUT_RESERVED;
 		ret = vfe->res->hw_ops->vfe_enable(line);
 		if (ret < 0)
 			dev_err(vfe->camss->dev,
@@ -2055,8 +2055,12 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 		l->video_out.camss = camss;
 		l->id = i;
-		init_completion(&l->output.sof);
-		init_completion(&l->output.reg_update);
+
+		l->num_outputs = 1;
+		l->output[0].line = l;
+
+		init_completion(&l->output[0].sof);
+		init_completion(&l->output[0].reg_update);
 
 		if (i == VFE_LINE_PIX) {
 			l->nformats = res->vfe.formats_pix->nformats;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 98d403a71cf95..e043ef4468626 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -22,6 +22,7 @@
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
 #define MSM_VFE_PADS_NUM 2
+#define MSM_VFE_NUM_OUTPUTS 1
 
 #define MSM_VFE_IMAGE_MASTERS_NUM 7
 #define MSM_VFE_COMPOSITE_IRQ_NUM 4
@@ -102,6 +103,8 @@ struct vfe_output {
 	int wait_reg_update;
 	struct completion sof;
 	struct completion reg_update;
+
+	struct vfe_line *line;
 };
 
 struct vfe_line {
@@ -112,7 +115,8 @@ struct vfe_line {
 	struct v4l2_rect compose;
 	struct v4l2_rect crop;
 	struct camss_video video_out;
-	struct vfe_output output;
+	struct vfe_output output[MSM_VFE_NUM_OUTPUTS];
+	u32 num_outputs;
 	const struct camss_format_info *formats;
 	unsigned int nformats;
 };

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 20/74] media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (18 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 19/74] media: qcom: camss: vfe: Represent output as an array instead of a singleton Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 21/74] media: qcom: camss: vfe: Represent vfe wm inside of a struct Bryan O'Donoghue
                   ` (54 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

In preparation for having multiple source/sink pads on VFE PIX nodes, move
the video_out structure to vfe_output.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-340.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c  |  6 +++---
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c  |  8 ++++----
 drivers/media/platform/qcom/camss/camss-vfe-4-8.c  |  8 ++++----
 drivers/media/platform/qcom/camss/camss-vfe-480.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-680.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-690.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-780.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-gen1.c | 10 ++++------
 drivers/media/platform/qcom/camss/camss-vfe.c      | 22 +++++++++-------------
 drivers/media/platform/qcom/camss/camss-vfe.h      |  2 +-
 12 files changed, 31 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index d2dc2acc9d234..d9e37cf609823 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -257,7 +257,7 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
 	struct v4l2_pix_format_mplane *pix =
-		&line->video_out.active_fmt.fmt.pix_mp;
+		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 	u32 stride = pix->plane_fmt[0].bytesperline;
 
 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 2526d568686db..6edbfcf766dad 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -282,7 +282,7 @@ static u32 vfe_packer_format(struct vfe_device *vfe, u32 pixelformat)
 
 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;
+	struct v4l2_pix_format_mplane *pix = &line->output[0].video_out.active_fmt.fmt.pix_mp;
 	u32 stride = pix->plane_fmt[0].bytesperline;
 	u8 client = tfe_wm_client_map[wm];
 	u32 cfg = TFE_BUS_CLIENT_CFG_EN;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
index a2a91217a3cf8..ccc065924b6b6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -476,7 +476,7 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
 	struct vfe_line *line = output->line;
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	unsigned int i;
 
@@ -631,7 +631,7 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 input, output;
 	u8 interp_reso;
@@ -686,7 +686,7 @@ static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 first, last;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index 2eb4c3d505ebf..1f02adb79f921 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -566,7 +566,7 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
 	struct vfe_line *line = output->line;
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 
 	switch (p) {
@@ -635,7 +635,7 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line,
 				u8 enable)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
 
 	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
@@ -782,7 +782,7 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 input, output;
 	u8 interp_reso;
@@ -837,7 +837,7 @@ static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 first, last;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
index 3166660d864ec..577d1ddfe84b4 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -537,7 +537,7 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			     u8 enable)
 {
 	struct vfe_line *line = output->line;
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 
 	switch (p) {
@@ -606,7 +606,7 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line,
 				u8 enable)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
 
 	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
@@ -753,7 +753,7 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 input, output;
 	u8 interp_reso;
@@ -808,7 +808,7 @@ static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
 
 static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line)
 {
-	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 p = line->output[0].video_out.active_fmt.fmt.pix_mp.pixelformat;
 	u32 reg;
 	u16 first, last;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 616d80ae1da74..73bfb53266c3e 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -99,7 +99,7 @@ static void vfe_global_reset(struct vfe_device *vfe)
 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;
+		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 
 	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-680.c b/drivers/media/platform/qcom/camss/camss-vfe-680.c
index 99036e7c1e763..c002ff126135a 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-680.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-680.c
@@ -155,7 +155,7 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr,
 static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line)
 {
 	struct v4l2_pix_format_mplane *pix =
-		&line->video_out.active_fmt.fmt.pix_mp;
+		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 	u32 stride = pix->plane_fmt[0].bytesperline;
 	u32 cfg;
 	u8 wm;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-690.c b/drivers/media/platform/qcom/camss/camss-vfe-690.c
index 6f90134d5ed64..88dc902dd30dd 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-690.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-690.c
@@ -56,7 +56,7 @@
 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;
+		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 
 	wm = RDI_WM(wm);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 4adbd0680898f..a4a2beb0c38b7 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -52,7 +52,7 @@
 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;
+		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 
 	wm = RDI_WM(wm);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
index 3e3d103e0d09d..ac4c4fd261b33 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -255,7 +255,7 @@ static int vfe_enable_output(struct vfe_line *line)
 			vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[i],
 						     (ub_size + 1) * output->wm_idx[i], ub_size);
 			vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i],
-						     &line->video_out.active_fmt.fmt.pix_mp, i, 1);
+						     &line->output[0].video_out.active_fmt.fmt.pix_mp, i, 1);
 			vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 1);
 			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
 		}
@@ -282,7 +282,7 @@ static int vfe_get_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
 	struct vfe_output *output;
-	struct v4l2_format *f = &line->video_out.active_fmt;
+	struct v4l2_format *f = &line->output[0].video_out.active_fmt;
 	unsigned long flags;
 	int i;
 	int wm_idx;
@@ -688,13 +688,11 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
  */
 static int vfe_queue_buffer(struct camss_video *vid, struct camss_buffer *buf)
 {
-	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
+	struct vfe_output *output = container_of(vid, struct vfe_output, video_out);
+	struct vfe_line *line = output->line;
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output[0];
-
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
 	vfe_buf_update_wm_on_new(vfe, output, buf, line);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 54ab906b01a82..18f66bea5e3b1 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -713,14 +713,12 @@ int vfe_enable_output_v2(struct vfe_line *line)
 int vfe_queue_buffer_v2(struct camss_video *vid,
 			struct camss_buffer *buf)
 {
-	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
+	struct vfe_output *output = container_of(vid, struct vfe_output, video_out);
+	struct vfe_line *line = output->line;
 	struct vfe_device *vfe = to_vfe(line);
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
-	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output[0];
-
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
 	if (output->state == VFE_OUTPUT_ON &&
@@ -1320,13 +1318,11 @@ void vfe_put(struct vfe_device *vfe)
 int vfe_flush_buffers(struct camss_video *vid,
 		      enum vb2_buffer_state state)
 {
-	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
+	struct vfe_output *output = container_of(vid, struct vfe_output, video_out);
+	struct vfe_line *line = output->line;
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output;
 	unsigned long flags;
 
-	output = &line->output[0];
-
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
 	vfe_buf_flush_pending(output, state);
@@ -2052,8 +2048,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 	for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
 		struct vfe_line *l = &vfe->line[i];
 
-		l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-		l->video_out.camss = camss;
+		l->output[0].video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+		l->output[0].video_out.camss = camss;
 		l->id = i;
 
 		l->num_outputs = 1;
@@ -2212,7 +2208,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 
 		sd = &vfe->line[i].subdev;
 		pads = vfe->line[i].pads;
-		video_out = &vfe->line[i].video_out;
+		video_out = &vfe->line[i].output[0].video_out;
 
 		v4l2_subdev_init(sd, &vfe_v4l2_ops);
 		sd->internal_ops = &vfe_v4l2_internal_ops;
@@ -2297,7 +2293,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 error_init:
 	for (i--; i >= 0; i--) {
 		sd = &vfe->line[i].subdev;
-		video_out = &vfe->line[i].video_out;
+		video_out = &vfe->line[i].output[0].video_out;
 
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
@@ -2320,7 +2316,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
 
 	for (i = 0; i < vfe->res->line_num; i++) {
 		struct v4l2_subdev *sd = &vfe->line[i].subdev;
-		struct camss_video *video_out = &vfe->line[i].video_out;
+		struct camss_video *video_out = &vfe->line[i].output[0].video_out;
 
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index e043ef4468626..42ac030d339b0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -105,6 +105,7 @@ struct vfe_output {
 	struct completion reg_update;
 
 	struct vfe_line *line;
+	struct camss_video video_out;
 };
 
 struct vfe_line {
@@ -114,7 +115,6 @@ struct vfe_line {
 	struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM];
 	struct v4l2_rect compose;
 	struct v4l2_rect crop;
-	struct camss_video video_out;
 	struct vfe_output output[MSM_VFE_NUM_OUTPUTS];
 	u32 num_outputs;
 	const struct camss_format_info *formats;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 21/74] media: qcom: camss: vfe: Represent vfe wm inside of a struct
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (19 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 20/74] media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 22/74] media: qcom: camss: vfe: Add is_pix to struct line Bryan O'Donoghue
                   ` (53 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Right now we have a major source of concept confusion where write-master is
used in-lieu of of completion group. In the code when we say "wm" we
actually mean "completion group".

To extend this driver out to support completion groups where multiple
write-masters within one completion group signal readiness via their group
completion status, we need to associate write masters with their completion
groups.

Firs step is to stop indexing wm's as sacrosanct indexes and instead hide
their fake sacral nature in a struct.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c  |  2 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c  | 10 +--
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c  | 22 +++----
 drivers/media/platform/qcom/camss/camss-vfe-4-8.c  | 22 +++----
 drivers/media/platform/qcom/camss/camss-vfe-gen1.c | 72 +++++++++++-----------
 drivers/media/platform/qcom/camss/camss-vfe.c      | 14 ++---
 drivers/media/platform/qcom/camss/camss-vfe.h      |  8 ++-
 7 files changed, 78 insertions(+), 72 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index d9e37cf609823..8cb0c028a3bce 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -541,7 +541,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 	output->buf[index] = vfe_buf_get_pending(output);
 
 	if (output->buf[index])
-		vfe_wm_update(vfe, output->wm_idx[0], output->buf[index]->addr[0], line);
+		vfe_wm_update(vfe, output->wm[0].bus_client, output->buf[index]->addr[0], line);
 	else
 		output->gen2.active_num--;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
index ccc065924b6b6..40fa7cecd0f71 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -493,16 +493,16 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 			break;
 		}
 
-		if (output->wm_idx[i] % 2 == 1)
+		if (output->wm[i].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[i].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[i].bus_client),
 				    reg);
 	}
 }
@@ -568,8 +568,8 @@ static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 	irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR;
 	for (i = 0; i < output->wm_num; i++) {
 		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(
-							output->wm_idx[i]);
-		comp_mask |= (1 << output->wm_idx[i]) << comp * 8;
+							output->wm[i].bus_client);
+		comp_mask |= (1 << output->wm[i].bus_client) << comp * 8;
 	}
 
 	if (enable) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index 1f02adb79f921..f98986641ae1a 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -577,32 +577,32 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA <<
 			VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
 
-		if (output->wm_idx[0] % 2 == 1)
+		if (output->wm[0].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 
 		reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
 		if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16)
 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
 
-		if (output->wm_idx[1] % 2 == 1)
+		if (output->wm[1].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[1].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[1].bus_client),
 				    reg);
 		break;
 	case V4L2_PIX_FMT_YUYV:
@@ -615,16 +615,16 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 		if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU)
 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
 
-		if (output->wm_idx[0] % 2 == 1)
+		if (output->wm[0].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		break;
 	default:
@@ -719,8 +719,8 @@ static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 	irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR;
 	for (i = 0; i < output->wm_num; i++) {
 		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(
-							output->wm_idx[i]);
-		comp_mask |= (1 << output->wm_idx[i]) << comp * 8;
+							output->wm[i].bus_client);
+		comp_mask |= (1 << output->wm[i].bus_client) << comp * 8;
 	}
 
 	if (enable) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
index 577d1ddfe84b4..06bcdf72132b2 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -548,32 +548,32 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA <<
 			VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
 
-		if (output->wm_idx[0] % 2 == 1)
+		if (output->wm[0].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 
 		reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
 		if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16)
 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
 
-		if (output->wm_idx[1] % 2 == 1)
+		if (output->wm[1].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[1].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[1].bus_client),
 				    reg);
 		break;
 	case V4L2_PIX_FMT_YUYV:
@@ -586,16 +586,16 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
 		if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU)
 			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
 
-		if (output->wm_idx[0] % 2 == 1)
+		if (output->wm[0].bus_client % 2 == 1)
 			reg <<= 16;
 
 		if (enable)
 			vfe_reg_set(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		else
 			vfe_reg_clr(vfe,
-				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    VFE_0_BUS_XBAR_CFG_x(output->wm[0].bus_client),
 				    reg);
 		break;
 	default:
@@ -690,8 +690,8 @@ static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
 	irq_en0 |= VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
 	irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR;
 	for (i = 0; i < output->wm_num; i++) {
-		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(output->wm_idx[i]);
-		comp_mask |= (1 << output->wm_idx[i]) << comp * 8;
+		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(output->wm[i].bus_client);
+		comp_mask |= (1 << output->wm[i].bus_client) << comp * 8;
 	}
 
 	if (enable) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
index ac4c4fd261b33..4b0fe2db7fcf5 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -53,7 +53,7 @@ static int vfe_disable_output(struct vfe_line *line)
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	for (i = 0; i < output->wm_num; i++)
-		vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 0);
+		vfe->ops_gen1->wm_enable(vfe, output->wm[i].bus_client, 0);
 
 	ops->reg_update(vfe, line->id);
 	output->wait_reg_update = 1;
@@ -66,15 +66,15 @@ static int vfe_disable_output(struct vfe_line *line)
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
 	if (line->id != VFE_LINE_PIX) {
-		vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 0);
-		vfe->ops_gen1->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0], line->id);
-		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
-		vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 0);
+		vfe->ops_gen1->wm_frame_based(vfe, output->wm[0].bus_client, 0);
+		vfe->ops_gen1->bus_disconnect_wm_from_rdi(vfe, output->wm[0].bus_client, line->id);
+		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm[0].bus_client, line->id, 0);
+		vfe->ops_gen1->set_cgc_override(vfe, output->wm[0].bus_client, 0);
 		spin_unlock_irqrestore(&vfe->output_lock, flags);
 	} else {
 		for (i = 0; i < output->wm_num; i++) {
-			vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
-			vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 0);
+			vfe->ops_gen1->wm_line_based(vfe, output->wm[i].bus_client, NULL, i, 0);
+			vfe->ops_gen1->set_cgc_override(vfe, output->wm[i].bus_client, 0);
 		}
 
 		vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 0);
@@ -138,10 +138,10 @@ static void vfe_output_init_addrs(struct vfe_device *vfe,
 		else
 			pong_addr = ping_addr;
 
-		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
-		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
+		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm[i].bus_client, ping_addr);
+		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm[i].bus_client, pong_addr);
 		if (sync)
-			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm[i].bus_client);
 	}
 }
 
@@ -158,8 +158,8 @@ static void vfe_output_frame_drop(struct vfe_device *vfe,
 	drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
 
 	for (i = 0; i < output->wm_num; i++) {
-		vfe->ops_gen1->wm_set_framedrop_period(vfe, output->wm_idx[i], drop_period);
-		vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm_idx[i], drop_pattern);
+		vfe->ops_gen1->wm_set_framedrop_period(vfe, output->wm[i].bus_client, drop_period);
+		vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm[i].bus_client, drop_pattern);
 	}
 
 	vfe->res->hw_ops->reg_update(vfe, output->line->id);
@@ -237,27 +237,27 @@ static int vfe_enable_output(struct vfe_line *line)
 	vfe_output_init_addrs(vfe, output, 0, line);
 
 	if (line->id != VFE_LINE_PIX) {
-		vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 1);
-		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
-		vfe->ops_gen1->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
-		vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[0]);
+		vfe->ops_gen1->set_cgc_override(vfe, output->wm[0].bus_client, 1);
+		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm[0].bus_client, line->id, 1);
+		vfe->ops_gen1->bus_connect_wm_to_rdi(vfe, output->wm[0].bus_client, line->id);
+		vfe->ops_gen1->wm_set_subsample(vfe, output->wm[0].bus_client);
 		vfe->ops_gen1->set_rdi_cid(vfe, line->id, 0);
-		vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[0],
-					    (ub_size + 1) * output->wm_idx[0], ub_size);
-		vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 1);
-		vfe->ops_gen1->wm_enable(vfe, output->wm_idx[0], 1);
-		vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[0]);
+		vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm[0].bus_client,
+					    (ub_size + 1) * output->wm[0].bus_client, ub_size);
+		vfe->ops_gen1->wm_frame_based(vfe, output->wm[0].bus_client, 1);
+		vfe->ops_gen1->wm_enable(vfe, output->wm[0].bus_client, 1);
+		vfe->ops_gen1->bus_reload_wm(vfe, output->wm[0].bus_client);
 	} else {
 		ub_size /= output->wm_num;
 		for (i = 0; i < output->wm_num; i++) {
-			vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 1);
-			vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[i]);
-			vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[i],
-						     (ub_size + 1) * output->wm_idx[i], ub_size);
-			vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i],
+			vfe->ops_gen1->set_cgc_override(vfe, output->wm[i].bus_client, 1);
+			vfe->ops_gen1->wm_set_subsample(vfe, output->wm[i].bus_client);
+			vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm[i].bus_client,
+						     (ub_size + 1) * output->wm[i].bus_client, ub_size);
+			vfe->ops_gen1->wm_line_based(vfe, output->wm[i].bus_client,
 						     &line->output[0].video_out.active_fmt.fmt.pix_mp, i, 1);
-			vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 1);
-			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+			vfe->ops_gen1->wm_enable(vfe, output->wm[i].bus_client, 1);
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm[i].bus_client);
 		}
 		vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 1);
 		vfe->ops_gen1->set_module_cfg(vfe, 1);
@@ -316,7 +316,7 @@ static int vfe_get_output(struct vfe_line *line)
 			dev_err(vfe->camss->dev, "Can not reserve wm\n");
 			goto error_get_wm;
 		}
-		output->wm_idx[i] = wm_idx;
+		output->wm[i].bus_client = wm_idx;
 	}
 
 	output->drop_update_idx = 0;
@@ -327,7 +327,7 @@ static int vfe_get_output(struct vfe_line *line)
 
 error_get_wm:
 	for (i--; i >= 0; i--)
-		vfe_release_wm(vfe, output->wm_idx[i]);
+		vfe_release_wm(vfe, output->wm[i].bus_client);
 	output->state = VFE_OUTPUT_OFF;
 error:
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
@@ -394,9 +394,9 @@ static void vfe_output_update_ping_addr(struct vfe_device *vfe,
 		else
 			addr = 0;
 
-		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
+		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm[i].bus_client, addr);
 		if (sync)
-			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm[i].bus_client);
 	}
 }
 
@@ -413,9 +413,9 @@ static void vfe_output_update_pong_addr(struct vfe_device *vfe,
 		else
 			addr = 0;
 
-		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
+		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm[i].bus_client, addr);
 		if (sync)
-			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm[i].bus_client);
 	}
 }
 
@@ -658,10 +658,10 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 
 	if (active_index)
 		for (i = 0; i < output->wm_num; i++)
-			vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], new_addr[i]);
+			vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm[i].bus_client, new_addr[i]);
 	else
 		for (i = 0; i < output->wm_num; i++)
-			vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]);
+			vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm[i].bus_client, new_addr[i]);
 
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 18f66bea5e3b1..8899f02ceba02 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -624,7 +624,7 @@ void vfe_buf_done(struct vfe_device *vfe, int wm)
 	output->buf[index] = vfe_buf_get_pending(output);
 
 	if (output->buf[index]) {
-		ops->vfe_wm_update(vfe, output->wm_idx[0],
+		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
 				   output->buf[index]->addr[0],
 				   line);
 		ops->reg_update(vfe, line->id);
@@ -683,14 +683,14 @@ int vfe_enable_output_v2(struct vfe_line *line)
 	output->wait_reg_update = 0;
 	reinit_completion(&output->reg_update);
 
-	ops->vfe_wm_start(vfe, output->wm_idx[0], line);
+	ops->vfe_wm_start(vfe, output->wm[0].bus_client, line);
 
 	for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) {
 		output->buf[i] = vfe_buf_get_pending(output);
 		if (!output->buf[i])
 			break;
 		output->gen2.active_num++;
-		ops->vfe_wm_update(vfe, output->wm_idx[0],
+		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
 				   output->buf[i]->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	}
@@ -724,7 +724,7 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
 	if (output->state == VFE_OUTPUT_ON &&
 	    output->gen2.active_num < 2) {
 		output->buf[output->gen2.active_num++] = buf;
-		ops->vfe_wm_update(vfe, output->wm_idx[0],
+		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
 				   buf->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	} else {
@@ -808,7 +808,7 @@ int vfe_get_output_v2(struct vfe_line *line)
 	 * line 0 -> RDI 0, line 1 -> RDI1, line 2 -> RDI2, line 3 -> PIX/RDI3
 	 * Note this 1:1 mapping will not work for PIX streams.
 	 */
-	output->wm_idx[0] = line->id;
+	output->wm[0].bus_client = line->id;
 	vfe->wm_output_map[line->id] = line->id;
 
 	output->drop_update_idx = 0;
@@ -938,7 +938,7 @@ int vfe_put_output(struct vfe_line *line)
 	spin_lock_irqsave(&vfe->output_lock, flags);
 
 	for (i = 0; i < output->wm_num; i++)
-		vfe_release_wm(vfe, output->wm_idx[i]);
+		vfe_release_wm(vfe, output->wm[i].bus_client);
 
 	output->state = VFE_OUTPUT_OFF;
 
@@ -955,7 +955,7 @@ static int vfe_disable_output(struct vfe_line *line)
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	for (i = 0; i < output->wm_num; i++)
-		vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm_idx[i]);
+		vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm[i].bus_client);
 	output->gen2.active_num = 0;
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 42ac030d339b0..29682e8e9f401 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -78,9 +78,15 @@ enum vfe_packer_format_v3 {
 	VFE_BUS_WM_PACKER_FMT_V3_MAX,
 };
 
+struct vfe_wm {
+	u8 bus_client;
+};
+
+#define VFE_MAX_WM_PER_OUTPUT 3
+
 struct vfe_output {
 	u8 wm_num;
-	u8 wm_idx[3];
+	struct vfe_wm wm[VFE_MAX_WM_PER_OUTPUT];
 
 	struct camss_buffer *buf[2];
 	struct camss_buffer *last_buffer;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 22/74] media: qcom: camss: vfe: Add is_pix to struct line
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (20 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 21/74] media: qcom: camss: vfe: Represent vfe wm inside of a struct Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 23/74] media: qcom: camss: vfe: Add comp_group to struct vfe_wm Bryan O'Donoghue
                   ` (52 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Differentiating the "line" the input line to the VFE as pix or non-pix will
allow us to properly differentiate PIX from RDI without any magic indexing.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 29682e8e9f401..79786c34e48a9 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -116,6 +116,7 @@ struct vfe_output {
 
 struct vfe_line {
 	enum vfe_line_id id;
+	bool is_pix;
 	struct v4l2_subdev subdev;
 	struct media_pad pads[MSM_VFE_PADS_NUM];
 	struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM];

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 23/74] media: qcom: camss: vfe: Add comp_group to struct vfe_wm
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (21 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 22/74] media: qcom: camss: vfe: Add is_pix to struct line Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 24/74] media: qcom: camss: vfe: Define vfe v3 completion group enum Bryan O'Donoghue
                   ` (51 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 79786c34e48a9..925b0e59f9605 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -85,6 +85,7 @@ struct vfe_wm {
 #define VFE_MAX_WM_PER_OUTPUT 3
 
 struct vfe_output {
+	u8 comp_group;
 	u8 wm_num;
 	struct vfe_wm wm[VFE_MAX_WM_PER_OUTPUT];
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 24/74] media: qcom: camss: vfe: Define vfe v3 completion group enum
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (22 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 23/74] media: qcom: camss: vfe: Add comp_group to struct vfe_wm Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 25/74] media: qcom: camss: vfe: Define output based VFE controls Bryan O'Donoghue
                   ` (50 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 925b0e59f9605..6ba0d0c7d6be2 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -78,6 +78,27 @@ enum vfe_packer_format_v3 {
 	VFE_BUS_WM_PACKER_FMT_V3_MAX,
 };
 
+enum vfe_v3_comp_group {
+	VFE_V3_COMP_GRP_0,
+	VFE_V3_COMP_GRP_1,
+	VFE_V3_COMP_GRP_2,
+	VFE_V3_COMP_GRP_3,
+	VFE_V3_COMP_GRP_4,
+	VFE_V3_COMP_GRP_5,
+	VFE_V3_COMP_GRP_6,
+	VFE_V3_COMP_GRP_7,
+	VFE_V3_COMP_GRP_8,
+	VFE_V3_COMP_GRP_9,
+	VFE_V3_COMP_GRP_10,
+	VFE_V3_COMP_GRP_11,
+	VFE_V3_COMP_GRP_12,
+	VFE_V3_COMP_GRP_13,
+	VFE_V3_COMP_GRP_14,
+	VFE_V3_COMP_GRP_15,
+	VFE_V3_COMP_GRP_16,
+	VFE_V3_COMP_GRP_MAX,
+};
+
 struct vfe_wm {
 	u8 bus_client;
 };

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 25/74] media: qcom: camss: vfe: Define output based VFE controls
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (23 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 24/74] media: qcom: camss: vfe: Define vfe v3 completion group enum Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 26/74] media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration Bryan O'Donoghue
                   ` (49 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 6ba0d0c7d6be2..bf8dccf4c901e 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -168,12 +168,22 @@ struct vfe_hw_ops {
 	int (*vfe_enable)(struct vfe_line *line);
 	int (*vfe_halt)(struct vfe_device *vfe);
 	void (*violation_read)(struct vfe_device *vfe);
+
+	/* RDI based API - deprecated */
 	void (*vfe_wm_start)(struct vfe_device *vfe, u8 wm,
 			     struct vfe_line *line);
 	void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm);
 	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id);
 	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, u32 addr,
 			      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);
+	void (*vfe_output_buf_done)(struct vfe_device *vfe, struct vfe_output *output);
+	void (*vfe_output_update)(struct vfe_device *vfe, struct vfe_output *output,
+				  struct camss_buffer *buf);
+
 };
 
 struct vfe_isr_ops {

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 26/74] media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (24 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 25/74] media: qcom: camss: vfe: Define output based VFE controls Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 27/74] media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init Bryan O'Donoghue
                   ` (48 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 8899f02ceba02..667cda379be44 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1930,7 +1930,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		return -EINVAL;
 
 	vfe->res = &res->vfe;
-	vfe->res->hw_ops->subdev_init(dev, vfe);
 
 	/* Power domain */
 
@@ -2067,6 +2066,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		}
 	}
 
+	vfe->res->hw_ops->subdev_init(dev, vfe);
+
 	init_completion(&vfe->reset_complete);
 	init_completion(&vfe->halt_complete);
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 27/74] media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (25 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 26/74] media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 28/74] media: qcom: camss: vfe: Add planes identifier to struct wm Bryan O'Donoghue
                   ` (47 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Initialising core elements of a logical structure shouldn't be done in
get(). For the fixed RDI logic assigning the write-index in get() is 100%
redundant. For the expanded PIX path the assignment itself will be wrong.

Move the legacy assignment out of get() and into subdev_init().

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 667cda379be44..35ab3203d75af 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -802,13 +802,6 @@ int vfe_get_output_v2(struct vfe_line *line)
 		goto error;
 	}
 
-	output->wm_num = 1;
-
-	/* Correspondence between VFE line number and WM number.
-	 * line 0 -> RDI 0, line 1 -> RDI1, line 2 -> RDI2, line 3 -> PIX/RDI3
-	 * Note this 1:1 mapping will not work for PIX streams.
-	 */
-	output->wm[0].bus_client = line->id;
 	vfe->wm_output_map[line->id] = line->id;
 
 	output->drop_update_idx = 0;
@@ -2054,6 +2047,9 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		l->num_outputs = 1;
 		l->output[0].line = l;
 
+		l->output[0].wm_num = 1;
+		l->output[0].wm[0].bus_client = l->id;
+
 		init_completion(&l->output[0].sof);
 		init_completion(&l->output[0].reg_update);
 
@@ -2064,6 +2060,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 			l->nformats = res->vfe.formats_rdi->nformats;
 			l->formats = res->vfe.formats_rdi->formats;
 		}
+
 	}
 
 	vfe->res->hw_ops->subdev_init(dev, vfe);

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 28/74] media: qcom: camss: vfe: Add planes identifier to struct wm
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (26 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 27/74] media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:13 ` [PATCH 29/74] media: qcom: camss: vfe: Specify number of pads via line->num_pads Bryan O'Donoghue
                   ` (46 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Define the number of planes a given IFE write master will write as a
data-field in the WM structure.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index bf8dccf4c901e..8bc07fe7798e1 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -101,6 +101,7 @@ enum vfe_v3_comp_group {
 
 struct vfe_wm {
 	u8 bus_client;
+	u8 plane;
 };
 
 #define VFE_MAX_WM_PER_OUTPUT 3

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 29/74] media: qcom: camss: vfe: Specify number of pads via line->num_pads
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (27 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 28/74] media: qcom: camss: vfe: Add planes identifier to struct wm Bryan O'Donoghue
@ 2026-10-05 17:13 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 30/74] media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group Bryan O'Donoghue
                   ` (45 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:13 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

We will need more pads to support the pix path - allow the code to specify
the number of pads via variable instead of via fixed define.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 4 +++-
 drivers/media/platform/qcom/camss/camss-vfe.h | 8 +++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 35ab3203d75af..3fe0139f82d16 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -2050,6 +2050,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		l->output[0].wm_num = 1;
 		l->output[0].wm[0].bus_client = l->id;
 
+		l->num_pads = MSM_VFE_PAD_NUM_RDI;
+
 		init_completion(&l->output[0].sof);
 		init_completion(&l->output[0].reg_update);
 
@@ -2231,7 +2233,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 
 		sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
 		sd->entity.ops = &vfe_media_ops;
-		ret = media_entity_pads_init(&sd->entity, MSM_VFE_PADS_NUM,
+		ret = media_entity_pads_init(&sd->entity, vfe->line[i].num_pads,
 					     pads);
 		if (ret < 0) {
 			dev_err(dev, "Failed to init media entity: %d\n", ret);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 8bc07fe7798e1..8fee26a0dc2e6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -21,7 +21,8 @@
 
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
-#define MSM_VFE_PADS_NUM 2
+#define MSM_VFE_PAD_NUM_RDI 2
+#define MSM_VFE_MAX_PADS MSM_VFE_PAD_NUM_RDI
 #define MSM_VFE_NUM_OUTPUTS 1
 
 #define MSM_VFE_IMAGE_MASTERS_NUM 7
@@ -141,8 +142,9 @@ struct vfe_line {
 	enum vfe_line_id id;
 	bool is_pix;
 	struct v4l2_subdev subdev;
-	struct media_pad pads[MSM_VFE_PADS_NUM];
-	struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM];
+	struct media_pad pads[MSM_VFE_MAX_PADS];
+	struct v4l2_mbus_framefmt fmt[MSM_VFE_MAX_PADS];
+	u32 num_pads;
 	struct v4l2_rect compose;
 	struct v4l2_rect crop;
 	struct vfe_output output[MSM_VFE_NUM_OUTPUTS];

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 30/74] media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (28 preceding siblings ...)
  2026-10-05 17:13 ` [PATCH 29/74] media: qcom: camss: vfe: Specify number of pads via line->num_pads Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 31/74] media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group Bryan O'Donoghue
                   ` (44 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 63 +++++++++++++++++----------
 1 file changed, 40 insertions(+), 23 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 3fe0139f82d16..c078af53b0758 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -642,36 +642,16 @@ void vfe_buf_done(struct vfe_device *vfe, int wm)
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 }
 
-int vfe_enable_output_v2(struct vfe_line *line)
+static int vfe_enable_one_output(struct vfe_line *line, struct vfe_output *output)
 {
 	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output[0];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
-	struct media_pad *sensor_pad;
-	unsigned long flags;
-	unsigned int frame_skip = 0;
 	unsigned int i;
 
-	sensor_pad = camss_find_sensor_pad(&line->subdev.entity);
-	if (sensor_pad) {
-		struct v4l2_subdev *subdev =
-			media_entity_to_v4l2_subdev(sensor_pad->entity);
-
-		v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
-		/* Max frame skip is 29 frames */
-		if (frame_skip > VFE_FRAME_DROP_VAL - 1)
-			frame_skip = VFE_FRAME_DROP_VAL - 1;
-	}
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	ops->reg_update_clear(vfe, line->id);
-
 	if (output->state > VFE_OUTPUT_RESERVED) {
 		dev_err(vfe->camss->dev,
 			"Output is not in reserved state %d\n",
 			output->state);
-		spin_unlock_irqrestore(&vfe->output_lock, flags);
 		return -EINVAL;
 	}
 
@@ -683,7 +663,10 @@ int vfe_enable_output_v2(struct vfe_line *line)
 	output->wait_reg_update = 0;
 	reinit_completion(&output->reg_update);
 
-	ops->vfe_wm_start(vfe, output->wm[0].bus_client, line);
+	if (ops->vfe_output_start)
+		ops->vfe_output_start(vfe, output);
+	else
+		ops->vfe_wm_start(vfe, output->wm[0].bus_client, line);
 
 	for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) {
 		output->buf[i] = vfe_buf_get_pending(output);
@@ -695,9 +678,43 @@ int vfe_enable_output_v2(struct vfe_line *line)
 		ops->reg_update(vfe, line->id);
 	}
 
+	return 0;
+}
+
+int vfe_enable_output_v2(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
+	struct media_pad *sensor_pad;
+	unsigned long flags;
+	unsigned int frame_skip = 0;
+	unsigned int i;
+	int ret;
+
+	sensor_pad = camss_find_sensor_pad(&line->subdev.entity);
+	if (sensor_pad) {
+		struct v4l2_subdev *subdev =
+			media_entity_to_v4l2_subdev(sensor_pad->entity);
+
+		v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
+		/* Max frame skip is 29 frames */
+		if (frame_skip > VFE_FRAME_DROP_VAL - 1)
+			frame_skip = VFE_FRAME_DROP_VAL - 1;
+	}
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	ops->reg_update_clear(vfe, line->id);
+
+	for (i = 0; i < line->num_outputs; i++) {
+		ret = vfe_enable_one_output(line, &line->output[i]);
+		if (ret)
+			break;
+	}
+
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 
-	return 0;
+	return ret;
 }
 
 /*

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 31/74] media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (29 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 30/74] media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 32/74] media: qcom: camss: vfe: Update an output group's write masters on buffer done bod
                   ` (43 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index c078af53b0758..20d8b3e1e4459 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -673,8 +673,11 @@ static int vfe_enable_one_output(struct vfe_line *line, struct vfe_output *outpu
 		if (!output->buf[i])
 			break;
 		output->gen2.active_num++;
-		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-				   output->buf[i]->addr[0], line);
+		if (ops->vfe_output_update)
+			ops->vfe_output_update(vfe, output, output->buf[i]);
+		else
+			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
+					   output->buf[i]->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	}
 
@@ -741,8 +744,11 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
 	if (output->state == VFE_OUTPUT_ON &&
 	    output->gen2.active_num < 2) {
 		output->buf[output->gen2.active_num++] = buf;
-		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-				   buf->addr[0], line);
+		if (ops->vfe_output_update)
+			ops->vfe_output_update(vfe, output, buf);
+		else
+			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
+					   buf->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	} else {
 		vfe_buf_add_pending(output, buf);

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 32/74] media: qcom: camss: vfe: Update an output group's write masters on buffer done
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (30 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 31/74] media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group Bryan O'Donoghue
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 33/74] media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters Bryan O'Donoghue
                   ` (42 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

vfe_buf_done() hands the next buffer to the write master directly with
vfe_wm_update(), so an output group never sees it. Hand it to
vfe_output_update() when the backend provides one, as starting the
output and queuing a buffer already do.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 20d8b3e1e4459..23c86e08776ea 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -624,9 +624,12 @@ void vfe_buf_done(struct vfe_device *vfe, int wm)
 	output->buf[index] = vfe_buf_get_pending(output);
 
 	if (output->buf[index]) {
-		ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-				   output->buf[index]->addr[0],
-				   line);
+		if (ops->vfe_output_update)
+			ops->vfe_output_update(vfe, output, output->buf[index]);
+		else
+			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
+					   output->buf[index]->addr[0],
+					   line);
 		ops->reg_update(vfe, line->id);
 	} else {
 		output->gen2.active_num--;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 33/74] media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (31 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 32/74] media: qcom: camss: vfe: Update an output group's write masters on buffer done bod
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 34/74] media: qcom: camss: vfe: Stop an output group once bod
                   ` (41 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 23c86e08776ea..f7907287c8ed4 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -968,13 +968,17 @@ int vfe_put_output(struct vfe_line *line)
 static int vfe_disable_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
+	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
 	struct vfe_output *output = &line->output[0];
 	unsigned long flags;
 	unsigned int i;
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
 	for (i = 0; i < output->wm_num; i++)
-		vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm[i].bus_client);
+		if (ops->vfe_output_stop)
+			ops->vfe_output_stop(vfe, output);
+		else
+			ops->vfe_wm_stop(vfe, output->wm[i].bus_client);
 	output->gen2.active_num = 0;
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 34/74] media: qcom: camss: vfe: Stop an output group once
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (32 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 33/74] media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters Bryan O'Donoghue
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 35/74] media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw Bryan O'Donoghue
                   ` (40 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

vfe_disable_output() calls vfe_output_stop() once per write master of
the output, but the output op stops all of the group's write masters
itself. Call it once, and loop over the write masters only for backends
without one.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index f7907287c8ed4..9793df66b4149 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -974,10 +974,10 @@ static int vfe_disable_output(struct vfe_line *line)
 	unsigned int i;
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
-	for (i = 0; i < output->wm_num; i++)
-		if (ops->vfe_output_stop)
-			ops->vfe_output_stop(vfe, output);
-		else
+	if (ops->vfe_output_stop)
+		ops->vfe_output_stop(vfe, output);
+	else
+		for (i = 0; i < output->wm_num; i++)
 			ops->vfe_wm_stop(vfe, output->wm[i].bus_client);
 	output->gen2.active_num = 0;
 	spin_unlock_irqrestore(&vfe->output_lock, flags);

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 35/74] media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (33 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 34/74] media: qcom: camss: vfe: Stop an output group once bod
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 36/74] media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern bod
                   ` (39 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

It does exactly what it says on the tin.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 9793df66b4149..43c91ec8db494 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -340,6 +340,18 @@ static const struct camss_format_info formats_pix_8x96[] = {
 	  PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
 };
 
+static bool __vfe_pix_fmt_is_raw(const struct camss_formats *fmts, u32 code)
+{
+	unsigned int i;
+
+	for (i = 0; i < fmts->nformats; i++) {
+		if (fmts->formats[i].code == code)
+			return true;
+	}
+
+	return false;
+}
+
 const struct camss_formats vfe_formats_rdi_8x16 = {
 	.nformats = ARRAY_SIZE(formats_rdi_8x16),
 	.formats = formats_rdi_8x16

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 36/74] media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (34 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 35/74] media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw Bryan O'Donoghue
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 37/74] media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default() Bryan O'Donoghue
                   ` (38 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Simple helper function which translates a media bus format into the
appropriate CSID IPP pixel format.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid.c | 28 ++++++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-csid.h | 16 +++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 645e02ad6b9b1..abdd7195fa6c5 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -1437,3 +1437,31 @@ inline bool csid_is_lite(struct csid_device *csid)
 {
 	return csid->camss->res->csid_res[csid->id].csid.is_lite;
 }
+
+int csid_ipp_bayer_pattern(u32 code)
+{
+	switch (code) {
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SRGGB12_1X12:
+	case MEDIA_BUS_FMT_SRGGB14_1X14:
+		return CSID_IPP_BAYER_RGGB;
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG12_1X12:
+	case MEDIA_BUS_FMT_SGRBG14_1X14:
+		return CSID_IPP_BAYER_GRBG;
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SBGGR12_1X12:
+	case MEDIA_BUS_FMT_SBGGR14_1X14:
+		return CSID_IPP_BAYER_BGGR;
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG12_1X12:
+	case MEDIA_BUS_FMT_SGBRG14_1X14:
+		return CSID_IPP_BAYER_GBRG;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 53f43ae7b9327..400995f35f0ef 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -44,6 +44,13 @@ enum csid_testgen_mode {
 	CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */
 };
 
+enum csid_ipp_bayer_pattern {
+	CSID_IPP_BAYER_RGGB = 0,
+	CSID_IPP_BAYER_GRBG,
+	CSID_IPP_BAYER_BGGR,
+	CSID_IPP_BAYER_GBRG,
+};
+
 struct csid_format_info {
 	u32 code;
 	u8 data_type;
@@ -247,4 +254,13 @@ u32 csid_hw_version(struct csid_device *csid);
 u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
 		      unsigned int match_format_idx, u32 match_code);
 
+/*
+ * csid_ipp_bayer_pattern - IPP Bayer pattern for media bus code
+ *
+ * code: the media_bus code
+ *
+ * Return: IPP bayer pattern constant for reg programming or -EINVAL
+ */
+int csid_ipp_bayer_pattern(u32 code);
+
 #endif /* QC_MSM_CAMSS_CSID_H */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 37/74] media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default()
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (35 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 36/74] media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern bod
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 38/74] media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic Bryan O'Donoghue
                   ` (37 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 43c91ec8db494..c8ab5e124ad4b 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -435,6 +435,14 @@ u32 vfe_bus_v3_packer_fmt(u32 v4l2_fmt, u8 plane, u8 align_shift)
 	return VFE_BUS_WM_PACKER_FMT_V3_PLAIN_128;
 }
 
+static u32 __vfe_src_pad_default(unsigned int index, u32 sink_code)
+{
+	if (index > 0)
+		return 0;
+
+	return sink_code;
+}
+
 static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			    unsigned int index, u32 src_req_code)
 {
@@ -486,10 +494,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 						      index, src_req_code);
 		}
 		default:
-			if (index > 0)
-				return 0;
-
-			return sink_code;
+			return __vfe_src_pad_default(index, sink_code);
 		}
 		break;
 	case CAMSS_660:
@@ -560,10 +565,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 						      index, src_req_code);
 		}
 		default:
-			if (index > 0)
-				return 0;
-
-			return sink_code;
+			return __vfe_src_pad_default(index, sink_code);
 		}
 		break;
 	default:

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 38/74] media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (36 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 37/74] media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default() Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 39/74] media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX Bryan O'Donoghue
                   ` (36 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index c8ab5e124ad4b..900f8ec79c8dc 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -497,20 +497,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			return __vfe_src_pad_default(index, sink_code);
 		}
 		break;
-	case CAMSS_660:
-	case CAMSS_2290:
-	case CAMSS_6150:
-	case CAMSS_6350:
-	case CAMSS_7280:
-	case CAMSS_8x96:
-	case CAMSS_8250:
-	case CAMSS_8280XP:
-	case CAMSS_8300:
-	case CAMSS_845:
-	case CAMSS_8550:
-	case CAMSS_8650:
-	case CAMSS_8775P:
-	case CAMSS_X1E80100:
+	default:
 		switch (sink_code) {
 		case MEDIA_BUS_FMT_YUYV8_1X16:
 		{
@@ -568,10 +555,6 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			return __vfe_src_pad_default(index, sink_code);
 		}
 		break;
-	default:
-		WARN(1, "Unsupported HW version: %x\n",
-		     vfe->camss->res->version);
-		break;
 	}
 	return 0;
 }

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 39/74] media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (37 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 38/74] media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 40/74] media: qcom: camss: vfe-gen3: Define full array of write-masters Bryan O'Donoghue
                   ` (35 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 37 +++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 900f8ec79c8dc..926cb7559f78e 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -551,6 +551,43 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
 						      index, src_req_code);
 		}
+		case MEDIA_BUS_FMT_SBGGR8_1X8:
+		case MEDIA_BUS_FMT_SGBRG8_1X8:
+		case MEDIA_BUS_FMT_SGRBG8_1X8:
+		case MEDIA_BUS_FMT_SRGGB8_1X8:
+		case MEDIA_BUS_FMT_SBGGR10_1X10:
+		case MEDIA_BUS_FMT_SGBRG10_1X10:
+		case MEDIA_BUS_FMT_SGRBG10_1X10:
+		case MEDIA_BUS_FMT_SRGGB10_1X10:
+		case MEDIA_BUS_FMT_SBGGR12_1X12:
+		case MEDIA_BUS_FMT_SGBRG12_1X12:
+		case MEDIA_BUS_FMT_SGRBG12_1X12:
+		case MEDIA_BUS_FMT_SRGGB12_1X12:
+		case MEDIA_BUS_FMT_SBGGR14_1X14:
+		case MEDIA_BUS_FMT_SGBRG14_1X14:
+		case MEDIA_BUS_FMT_SGRBG14_1X14:
+		case MEDIA_BUS_FMT_SRGGB14_1X14:
+		case MEDIA_BUS_FMT_Y8_1X8:
+		case MEDIA_BUS_FMT_Y10_1X10:
+		{
+			if (!line->is_pix)
+				return __vfe_src_pad_default(index, sink_code);
+
+			u32 src_code[] = {
+				sink_code,
+				MEDIA_BUS_FMT_UYVY8_1X16,
+				MEDIA_BUS_FMT_VYUY8_1X16,
+				MEDIA_BUS_FMT_YUYV8_1X16,
+				MEDIA_BUS_FMT_YVYU8_1X16,
+				MEDIA_BUS_FMT_UYVY8_1_5X8,
+				MEDIA_BUS_FMT_VYUY8_1_5X8,
+				MEDIA_BUS_FMT_YUYV8_1_5X8,
+				MEDIA_BUS_FMT_YVYU8_1_5X8,
+			};
+
+			return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+						      index, src_req_code);
+		}
 		default:
 			return __vfe_src_pad_default(index, sink_code);
 		}

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 40/74] media: qcom: camss: vfe-gen3: Define full array of write-masters
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (38 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 39/74] media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 41/74] media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces Bryan O'Donoghue
                   ` (34 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 40 +++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index a4a2beb0c38b7..32b6565aa91df 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -12,6 +12,46 @@
 #include "camss.h"
 #include "camss-vfe.h"
 
+typedef enum {
+	VFE_WM_VIDEO_FULL_Y = 0,
+	VFE_WM_VIDEO_FULL_C,
+	VFE_WM_VIDEO_DS_4,
+	VFE_WM_VIDEO_DS_16,
+	VFE_WM_DISPLAY_FULL_Y,
+	VFE_WM_DISPLAY_FULL_C,
+	VFE_WM_DISPLAY_DS_4,
+	VFE_WM_DISPLAY_DS_16,
+	VFE_WM_FD_Y,
+	VFE_WM_FD_C,
+	VFE_WM_PIXEL_RAW,
+	VFE_WM_STATS_AEC_BE,
+	VFE_WM_STATS_AEC_BHIST,
+	VFE_WM_STATS_TINTLESS_BG,
+	VFE_WM_STATS_AWB_BG,
+	VFE_WM_STATS_AWB_BFW,
+	VFE_WM_STATS_BF,
+	VFE_WM_STATS_GTM_BHIST,
+	VFE_WM_STATS_RS,
+	VFE_WM_STATS_IHIST,
+	VFE_WM_PDAF_2PD,
+	VFE_WM_PDAF_PREPROCESS_2PD,
+	VFE_WM_PDAF_PARSED,
+	VFE_WM_RDI0,
+	VFE_WM_RDI1,
+	VFE_WM_RDI2,
+	VFE_WM_LTM,
+	VFE_WM_STATS_ALSC,
+}vfe_wm_t;
+
+typedef enum {
+	VFE_LITE_WM_RDI0 = 0,
+	VFE_LITE_WM_RDI1,
+	VFE_LITE_WM_RDI2,
+	VFE_LITE_WM_RDI3,
+	VFE_LITE_WM_PREPROCESS_RAW,
+	VFE_LITE_WM_STATS_BG,
+} vfe_lite_wm_t;
+
 #define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x200 : 0xC00)
 
 #define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0xDC)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 41/74] media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (39 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 40/74] media: qcom: camss: vfe-gen3: Define full array of write-masters Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 42/74] media: qcom: camss: vfe: Pass struct line to wm_stop Bryan O'Donoghue
                   ` (33 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 6f3de2c185bc9..66aa665848fe8 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -3535,7 +3535,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_rdi_845
+			.formats_pix = &vfe_formats_pix_845
 		},
 	},
 	/* VFE1 */
@@ -3562,7 +3562,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_rdi_845
+			.formats_pix = &vfe_formats_pix_845
 		},
 	},
 	/* VFE2 */
@@ -3589,7 +3589,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_780,
 			.formats_rdi = &vfe_formats_rdi_845,
-			.formats_pix = &vfe_formats_rdi_845
+			.formats_pix = &vfe_formats_pix_845
 		},
 	},
 	/* VFE3 lite */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 42/74] media: qcom: camss: vfe: Pass struct line to wm_stop
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (40 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 41/74] media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 43/74] media: qcom: camss: vfe-780: Use bus-client to derive write master index Bryan O'Donoghue
                   ` (32 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Passing the write-master is a function of being tied to RDI ports - almost
everywhere we pass wm we mean to pass line. Amend wm_stop to take the
struct line it needs to take. Once we get done converting all of the VFEs
to the new interface we can dispense with passing WM.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-340.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-480.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-680.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-690.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe.c     | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe.h     | 3 ++-
 8 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index 8cb0c028a3bce..52812d34530d6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -247,7 +247,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	/* Disable WM */
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 6edbfcf766dad..87f3e8f2ff539 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -335,7 +335,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 		vfe->id, client, pix->width, pix->height, stride);
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	u8 client = tfe_wm_client_map[wm];
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 73bfb53266c3e..6edbd8119aa7d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -127,7 +127,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 		       vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-680.c b/drivers/media/platform/qcom/camss/camss-vfe-680.c
index c002ff126135a..d9a6402e8d928 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-680.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-680.c
@@ -193,7 +193,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line)
 		rdi, wm, pix->width, pix->height, stride);
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi, struct vfe_line *line)
 {
 	u8 wm = RDI_WM(rdi);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-690.c b/drivers/media/platform/qcom/camss/camss-vfe-690.c
index 88dc902dd30dd..fb40560d4ab41 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-690.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-690.c
@@ -90,7 +90,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	wm = RDI_WM(wm);
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 32b6565aa91df..93f7c7a8e33f7 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -122,7 +122,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	wm = RDI_WM(wm);
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 926cb7559f78e..e57590b417f3d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1012,7 +1012,7 @@ static int vfe_disable_output(struct vfe_line *line)
 		ops->vfe_output_stop(vfe, output);
 	else
 		for (i = 0; i < output->wm_num; i++)
-			ops->vfe_wm_stop(vfe, output->wm[i].bus_client);
+			ops->vfe_wm_stop(vfe, output->wm[i].bus_client, line);
 	output->gen2.active_num = 0;
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 8fee26a0dc2e6..b84b324940b64 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -175,7 +175,8 @@ struct vfe_hw_ops {
 	/* RDI based API - deprecated */
 	void (*vfe_wm_start)(struct vfe_device *vfe, u8 wm,
 			     struct vfe_line *line);
-	void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm);
+	void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm,
+			    struct vfe_line *line);
 	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id);
 	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, u32 addr,
 			      struct vfe_line *line);

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 43/74] media: qcom: camss: vfe-780: Use bus-client to derive write master index
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (41 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 42/74] media: qcom: camss: vfe: Pass struct line to wm_stop Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 44/74] media: qcom: camss: vfe-780: Switch on YUV pix path Bryan O'Donoghue
                   ` (31 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Use line->output->bus_client defined in subdev_init instead of fixed macro
offsets to derive write-master indexes.

Aside from extensibility and grouping of code together this allows us to
very obviously see by just looking at plain and simple code what a
write-master identifier ought to be, what its completion group is, what its
pixel format is etc.

The macros need to be deprecated globally, starting here.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 43 ++++++++++++++++-------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 93f7c7a8e33f7..381d053dd9c15 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -55,16 +55,6 @@ typedef enum {
 #define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x200 : 0xC00)
 
 #define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0xDC)
-/*
- * Bus client mapping:
- *
- * Full VFE:
- * VFE_780: 23 = RDI0, 24 = RDI1, 25 = RDI2
- *
- * VFE LITE:
- * VFE_780 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4
- */
-#define RDI_WM(n)	((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n))
 
 #define VFE_BUS_WM_CGC_OVERRIDE		(BUS_REG_BASE + 0x08)
 #define		WM_CGC_OVERRIDE_ALL		(0x7FFFFFF)
@@ -94,7 +84,7 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	struct v4l2_pix_format_mplane *pix =
 		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 
-	wm = RDI_WM(wm);
+	wm = line->output[0].wm[0].bus_client;
 
 	/* no clock gating at bus input */
 	writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
@@ -124,14 +114,14 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 
 static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
-	wm = RDI_WM(wm);
+	wm = line->output[0].wm[0].bus_client;
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
 static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
-	wm = RDI_WM(wm);
+	wm = line->output[0].wm[0].bus_client;
 
 	writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 
@@ -159,9 +149,36 @@ static const struct camss_video_ops vfe_video_ops_780 = {
 	.flush_buffers = vfe_flush_buffers,
 };
 
+static void vfe_add_rdi(struct vfe_line *line, int bus_client, int comp_group)
+{
+	line->output[0].wm_num = 1;
+	line->output[0].wm[0].bus_client = bus_client;
+	line->output[0].wm[0].plane = 0;
+	line->output[0].comp_group = comp_group;
+}
+
 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 {
 	vfe->video_ops = vfe_video_ops_780;
+
+	if (vfe_is_lite(vfe)) {
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI0], VFE_LITE_WM_RDI0, VFE_V3_COMP_GRP_1);
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI1], VFE_LITE_WM_RDI1, VFE_V3_COMP_GRP_2);
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI2], VFE_LITE_WM_RDI2, VFE_V3_COMP_GRP_3);
+		vfe_add_rdi(&vfe->line[VFE_LINE_PIX], VFE_LITE_WM_RDI3, VFE_V3_COMP_GRP_4);
+		return;
+	}
+
+	/* RDI0 */
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI0], VFE_WM_RDI0, VFE_V3_COMP_GRP_14);
+
+	/* RDI1 */
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI1], VFE_WM_RDI1, VFE_V3_COMP_GRP_15);
+
+	/* RDI2 */
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI2], VFE_WM_RDI2, VFE_V3_COMP_GRP_16);
+
+	return;
 }
 
 static void vfe_global_reset(struct vfe_device *vfe)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 44/74] media: qcom: camss: vfe-780: Switch on YUV pix path
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (42 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 43/74] media: qcom: camss: vfe-780: Use bus-client to derive write master index Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 45/74] media: qcom: camss: vfe: Add support for pix pad data-types Bryan O'Donoghue
                   ` (30 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 10 ++++++++++
 drivers/media/platform/qcom/camss/camss.c         |  6 +++---
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 381d053dd9c15..9c20bb8d2e45f 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -178,6 +178,16 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 	/* RDI2 */
 	vfe_add_rdi(&vfe->line[VFE_LINE_RDI2], VFE_WM_RDI2, VFE_V3_COMP_GRP_16);
 
+	/* PIX YUV: FULL Y + C, one plane each, group 0 */
+	vfe->line[VFE_LINE_PIX].is_pix = true;
+	vfe->line[VFE_LINE_PIX].output[0].wm_num = 2;
+	vfe->line[VFE_LINE_PIX].output[0].wm[0].bus_client = VFE_WM_VIDEO_FULL_Y;
+	vfe->line[VFE_LINE_PIX].output[0].wm[0].plane = 0;
+	vfe->line[VFE_LINE_PIX].output[0].wm[1].bus_client = VFE_WM_VIDEO_FULL_C;
+	vfe->line[VFE_LINE_PIX].output[0].wm[1].plane = 1;
+	vfe->line[VFE_LINE_PIX].output[0].comp_group = VFE_V3_COMP_GRP_0;
+	vfe->line[VFE_LINE_PIX].output[0].type = VFE_OUTPUT_TYPE_PIXEL_YUV;
+
 	return;
 }
 
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 66aa665848fe8..2551f0dfa37bb 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -3530,7 +3530,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 		.reg = { "vfe0" },
 		.interrupt = { "vfe0" },
 		.vfe = {
-			.line_num = 3,
+			.line_num = 4,
 			.has_pd = true,
 			.pd_name = "ife0",
 			.hw_ops = &vfe_ops_780,
@@ -3557,7 +3557,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 		.reg = { "vfe1" },
 		.interrupt = { "vfe1" },
 		.vfe = {
-			.line_num = 3,
+			.line_num = 4,
 			.has_pd = true,
 			.pd_name = "ife1",
 			.hw_ops = &vfe_ops_780,
@@ -3584,7 +3584,7 @@ static const struct camss_subdev_resources vfe_res_sm8650[] = {
 		.reg = { "vfe2" },
 		.interrupt = { "vfe2" },
 		.vfe = {
-			.line_num = 3,
+			.line_num = 4,
 			.has_pd = true,
 			.pd_name = "ife2",
 			.hw_ops = &vfe_ops_780,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 45/74] media: qcom: camss: vfe: Add support for pix pad data-types
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (43 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 44/74] media: qcom: camss: vfe-780: Switch on YUV pix path Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 46/74] media: qcom: camss: vfe: Add helper methods to enumerate output descriptors Bryan O'Donoghue
                   ` (29 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

We already export src and sink for the simple RDI pads.
The pix sub-device will need to export

- Downscalers
- Statistics
- Parameters

Put code in place to describe these pads when a given VFE declares
support for them:

- DS4 and DS16 report a format derived from the source pad on every
  read, and enumerate only that code
- Statistics and parameters report MEDIA_BUS_FMT_METADATA_FIXED and
  have no frame size
- Selection is rejected on every pad other than the sink (compose) and
  the source (crop)

No VFE declares these pads yet, so there is no functional change.

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 59 ++++++++++++++++++++++++++-
 drivers/media/platform/qcom/camss/camss-vfe.h |  7 +++-
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index e57590b417f3d..8726353b52d3d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1529,8 +1529,10 @@ static void vfe_try_format(struct vfe_line *line,
 			   struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
+	struct v4l2_mbus_framefmt *src;
 	unsigned int i;
 	u32 code;
+	u32 w, h;
 
 	switch (pad) {
 	case MSM_VFE_PAD_SINK:
@@ -1571,6 +1573,28 @@ static void vfe_try_format(struct vfe_line *line,
 		}
 
 		break;
+
+	case MSM_VFE_PAD_SRC_DS4:
+	case MSM_VFE_PAD_SRC_DS16:
+		src = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SRC, which);
+		w = ALIGN(src->width, 8) / 4;
+		h = ALIGN(src->height, 8) / 4;
+
+		if (pad == MSM_VFE_PAD_SRC_DS16) {
+			w = (w / 4) & ~1u;
+			h = (h / 4) & ~1u;
+		}
+		*fmt = *src;
+		fmt->width = w;
+		fmt->height = h;
+
+		break;
+	case MSM_VFE_PAD_SRC_STATS:
+	case MSM_VFE_PAD_SINK_PARAMS:
+		memset(fmt, 0, sizeof(*fmt));
+		fmt->code = MEDIA_BUS_FMT_METADATA_FIXED;
+		fmt->field = V4L2_FIELD_NONE;
+		return;
 	}
 
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
@@ -1672,6 +1696,22 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
 {
 	struct vfe_line *line = v4l2_get_subdevdata(sd);
 
+	switch (code->pad) {
+	case MSM_VFE_PAD_SRC_DS4:
+	case MSM_VFE_PAD_SRC_DS16:
+		if (code->index)
+			return -EINVAL;
+		code->code = __vfe_get_format(line, sd_state, MSM_VFE_PAD_SRC,
+					      code->which)->code;
+		return 0;
+	case MSM_VFE_PAD_SRC_STATS:
+	case MSM_VFE_PAD_SINK_PARAMS:
+		if (code->index)
+			return -EINVAL;
+		code->code = MEDIA_BUS_FMT_METADATA_FIXED;
+		return 0;
+	}
+
 	if (code->pad == MSM_VFE_PAD_SINK) {
 		if (code->index >= line->nformats)
 			return -EINVAL;
@@ -1707,6 +1747,11 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
 	struct vfe_line *line = v4l2_get_subdevdata(sd);
 	struct v4l2_mbus_framefmt format;
 
+	/* Metadata has no frame size */
+	if (fse->pad == MSM_VFE_PAD_SRC_STATS ||
+	    fse->pad == MSM_VFE_PAD_SINK_PARAMS)
+		return -ENOTTY;
+
 	if (fse->index != 0)
 		return -EINVAL;
 
@@ -1749,7 +1794,11 @@ static int vfe_get_format(struct v4l2_subdev *sd,
 	if (format == NULL)
 		return -EINVAL;
 
-	fmt->format = *format;
+	/* Every pad past the src - downscalers, stats, params don't get assigned */
+	if (fmt->pad > MSM_VFE_PAD_SRC)
+		vfe_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which);
+	else
+		fmt->format = *format;
 
 	return 0;
 }
@@ -1875,6 +1924,8 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
 		default:
 			return -EINVAL;
 		}
+	else
+		return -EINVAL;
 
 	return 0;
 }
@@ -2294,6 +2345,12 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 
 		pads[MSM_VFE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
 		pads[MSM_VFE_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+		if (vfe->line[i].num_pads == MSM_VFE_PAD_NUM_PIX) {
+			pads[MSM_VFE_PAD_SRC_DS4].flags = MEDIA_PAD_FL_SOURCE;
+			pads[MSM_VFE_PAD_SRC_DS16].flags = MEDIA_PAD_FL_SOURCE;
+			pads[MSM_VFE_PAD_SRC_STATS].flags = MEDIA_PAD_FL_SOURCE;
+			pads[MSM_VFE_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
+		}
 
 		sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
 		sd->entity.ops = &vfe_media_ops;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index b84b324940b64..18403bf46178c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -21,8 +21,13 @@
 
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
+#define MSM_VFE_PAD_SRC_DS4 2
+#define MSM_VFE_PAD_SRC_DS16 3
+#define MSM_VFE_PAD_SRC_STATS 4
+#define MSM_VFE_PAD_SINK_PARAMS 5
 #define MSM_VFE_PAD_NUM_RDI 2
-#define MSM_VFE_MAX_PADS MSM_VFE_PAD_NUM_RDI
+#define MSM_VFE_PAD_NUM_PIX 6
+#define MSM_VFE_MAX_PADS MSM_VFE_PAD_NUM_PIX
 #define MSM_VFE_NUM_OUTPUTS 1
 
 #define MSM_VFE_IMAGE_MASTERS_NUM 7

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 46/74] media: qcom: camss: vfe: Add helper methods to enumerate output descriptors
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (44 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 45/74] media: qcom: camss: vfe: Add support for pix pad data-types Bryan O'Donoghue
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 47/74] media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done bod
                   ` (28 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 50 +++++++++--------------
 drivers/media/platform/qcom/camss/camss-vfe.c     | 49 ++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.h     | 17 ++++++++
 3 files changed, 85 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 9c20bb8d2e45f..88d74323fe276 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -148,47 +148,35 @@ static const struct camss_video_ops vfe_video_ops_780 = {
 	.queue_buffer = vfe_queue_buffer_v2,
 	.flush_buffers = vfe_flush_buffers,
 };
-
-static void vfe_add_rdi(struct vfe_line *line, int bus_client, int comp_group)
-{
-	line->output[0].wm_num = 1;
-	line->output[0].wm[0].bus_client = bus_client;
-	line->output[0].wm[0].plane = 0;
-	line->output[0].comp_group = comp_group;
-}
-
 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 {
+	struct vfe_line *pix = &vfe->line[VFE_LINE_PIX];
+
 	vfe->video_ops = vfe_video_ops_780;
 
+	/* RDI lite */
 	if (vfe_is_lite(vfe)) {
-		vfe_add_rdi(&vfe->line[VFE_LINE_RDI0], VFE_LITE_WM_RDI0, VFE_V3_COMP_GRP_1);
-		vfe_add_rdi(&vfe->line[VFE_LINE_RDI1], VFE_LITE_WM_RDI1, VFE_V3_COMP_GRP_2);
-		vfe_add_rdi(&vfe->line[VFE_LINE_RDI2], VFE_LITE_WM_RDI2, VFE_V3_COMP_GRP_3);
-		vfe_add_rdi(&vfe->line[VFE_LINE_PIX], VFE_LITE_WM_RDI3, VFE_V3_COMP_GRP_4);
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI0].output[0], VFE_LITE_WM_RDI0, VFE_V3_COMP_GRP_1);
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI1].output[0], VFE_LITE_WM_RDI1, VFE_V3_COMP_GRP_2);
+		vfe_add_rdi(&vfe->line[VFE_LINE_RDI2].output[0], VFE_LITE_WM_RDI2, VFE_V3_COMP_GRP_3);
+		vfe_add_rdi(&pix->output[0], VFE_LITE_WM_RDI3, VFE_V3_COMP_GRP_4);
 		return;
 	}
 
-	/* RDI0 */
-	vfe_add_rdi(&vfe->line[VFE_LINE_RDI0], VFE_WM_RDI0, VFE_V3_COMP_GRP_14);
-
-	/* RDI1 */
-	vfe_add_rdi(&vfe->line[VFE_LINE_RDI1], VFE_WM_RDI1, VFE_V3_COMP_GRP_15);
-
-	/* RDI2 */
-	vfe_add_rdi(&vfe->line[VFE_LINE_RDI2], VFE_WM_RDI2, VFE_V3_COMP_GRP_16);
+	/* RDI */
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI0].output[0], VFE_WM_RDI0, VFE_V3_COMP_GRP_14);
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI1].output[0], VFE_WM_RDI1, VFE_V3_COMP_GRP_15);
+	vfe_add_rdi(&vfe->line[VFE_LINE_RDI2].output[0], VFE_WM_RDI2, VFE_V3_COMP_GRP_16);
 
-	/* PIX YUV: FULL Y + C, one plane each, group 0 */
-	vfe->line[VFE_LINE_PIX].is_pix = true;
-	vfe->line[VFE_LINE_PIX].output[0].wm_num = 2;
-	vfe->line[VFE_LINE_PIX].output[0].wm[0].bus_client = VFE_WM_VIDEO_FULL_Y;
-	vfe->line[VFE_LINE_PIX].output[0].wm[0].plane = 0;
-	vfe->line[VFE_LINE_PIX].output[0].wm[1].bus_client = VFE_WM_VIDEO_FULL_C;
-	vfe->line[VFE_LINE_PIX].output[0].wm[1].plane = 1;
-	vfe->line[VFE_LINE_PIX].output[0].comp_group = VFE_V3_COMP_GRP_0;
-	vfe->line[VFE_LINE_PIX].output[0].type = VFE_OUTPUT_TYPE_PIXEL_YUV;
+	/* Add YUV, DS4, DS16, stats and params descriptors */
+	vfe_add_yuv(&pix->output[0], VFE_WM_VIDEO_FULL_Y, VFE_WM_VIDEO_FULL_C, VFE_V3_COMP_GRP_0);
+	vfe_add_ds(&pix->output[1], MSM_VFE_PAD_SRC_DS4, VFE_WM_VIDEO_DS_4, VFE_V3_COMP_GRP_0);
+	vfe_add_ds(&pix->output[2], MSM_VFE_PAD_SRC_DS16, VFE_WM_VIDEO_DS_16, VFE_V3_COMP_GRP_0);
+	vfe_add_stats(&pix->output[3], VFE_WM_STATS_AEC_BHIST, VFE_V3_COMP_GRP_4);
+	vfe_add_params(&pix->output[4], VFE_V3_COMP_GRP_0);
 
-	return;
+	/* PIX mode */
+	vfe_set_pix(pix, 5);
 }
 
 static void vfe_global_reset(struct vfe_device *vfe)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 8726353b52d3d..6ee9b5024447d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -2449,3 +2449,52 @@ bool vfe_is_lite(struct vfe_device *vfe)
 {
 	return vfe->camss->res->vfe_res[vfe->id].vfe.is_lite;
 }
+
+void vfe_add_output(struct vfe_output *output, u8 pad, u8 comp_group,
+		    unsigned int wm_num, const u8 *bus_client)
+{
+	unsigned int i;
+
+	output->comp_group = comp_group;
+	output->wm_num = wm_num;
+	for (i = 0; i < wm_num; i++) {
+		output->wm[i].bus_client = bus_client[i];
+		output->wm[i].plane = i;
+	}
+}
+
+void vfe_add_rdi(struct vfe_output *output, u8 bus_client, u8 comp_group)
+{
+	vfe_add_output(output, MSM_VFE_PAD_SRC, comp_group, 1, &bus_client);
+}
+
+void vfe_add_yuv(struct vfe_output *output, u8 bus_client_y,
+		 u8 bus_client_c, u8 comp_group)
+{
+	const u8 wm[] = { bus_client_y, bus_client_c };
+
+	vfe_add_output(output, MSM_VFE_PAD_SRC, comp_group, ARRAY_SIZE(wm), wm);
+}
+
+void vfe_add_ds(struct vfe_output *output, u8 pad, u8 bus_client,
+	       u8 comp_group)
+{
+	vfe_add_output(output, pad, comp_group, 1, &bus_client);
+}
+
+void vfe_add_stats(struct vfe_output *output, u8 bus_client, u8 comp_group)
+{
+	vfe_add_output(output, MSM_VFE_PAD_SRC_STATS, comp_group, 1, &bus_client);
+}
+
+void vfe_add_params(struct vfe_output *output, u8 comp_group)
+{
+	vfe_add_output(output, MSM_VFE_PAD_SINK_PARAMS, comp_group, 0, NULL);
+}
+
+void vfe_set_pix(struct vfe_line *line, int num_outputs)
+{
+	line->num_pads = MSM_VFE_PAD_NUM_PIX;
+	line->num_outputs = num_outputs;
+	line->is_pix = true;
+}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 18403bf46178c..06bdc337f4d83 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -399,4 +399,21 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
  */
 u32 vfe_bus_v3_packer_fmt(u32 v4l2_fmt, u8 plane, u8 align_shift);
 
+void vfe_add_output(struct vfe_output *output, u8 pad, u8 comp_group,
+		    unsigned int wm_num, const u8 *bus_client);
+
+void vfe_add_rdi(struct vfe_output *output, u8 bus_client, u8 comp_group);
+
+void vfe_add_yuv(struct vfe_output *output, u8 bus_client_y,
+		 u8 bus_client_c, u8 comp_group);
+
+void vfe_add_ds(struct vfe_output *output, u8 pad, u8 bus_client,
+		u8 comp_group);
+
+void vfe_add_stats(struct vfe_output *output, u8 bus_client, u8 comp_group);
+
+void vfe_add_params(struct vfe_output *output, u8 comp_group);
+
+void vfe_set_pix(struct vfe_line *line, int num_outputs);
+
 #endif /* QC_MSM_CAMSS_VFE_H */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 47/74] media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (45 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 46/74] media: qcom: camss: vfe: Add helper methods to enumerate output descriptors Bryan O'Donoghue
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 48/74] media: qcom: camss: Add a status field to camss_buf_done_info bod
                   ` (27 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Right now we pass hw_id and port_id to camss_buf_done. That data will be
useful outside of this method so in preparation for better passing of
data-around define camss_buf_done_info including the two data fields.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid-680.c  | 8 ++++++--
 drivers/media/platform/qcom/camss/camss-csid-gen3.c | 5 ++++-
 drivers/media/platform/qcom/camss/camss.c           | 8 ++++----
 drivers/media/platform/qcom/camss/camss.h           | 7 ++++++-
 4 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csid-680.c b/drivers/media/platform/qcom/camss/camss-csid-680.c
index 345a67c8fb947..8ed190db5b528 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-680.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-680.c
@@ -373,6 +373,7 @@ static void csid_rup_complete(struct csid_device *csid, int rdi)
  */
 static irqreturn_t csid_isr(int irq, void *dev)
 {
+	struct camss_buf_done_info info;
 	struct csid_device *csid = dev;
 	u32 buf_done_val, val, val_top;
 	int i;
@@ -398,8 +399,11 @@ static irqreturn_t csid_isr(int irq, void *dev)
 		if (val & CSID_CSI2_RDIN_RUP_DONE)
 			csid_rup_complete(csid, i);
 
-		if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i))
-			camss_buf_done(csid->camss, csid->id, i);
+		if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i)) {
+			info.hw_id = csid->id;
+			info.port_id = i;
+			camss_buf_done(csid->camss, &info);
+		}
 	}
 
 	/* Issue clear command */
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
index 0fdbf75fb27db..3a48bd072e0df 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
@@ -258,6 +258,7 @@ static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool c
  */
 static irqreturn_t csid_isr(int irq, void *dev)
 {
+	struct camss_buf_done_info info;
 	struct csid_device *csid = dev;
 	u32 val, buf_done_val;
 	u8 reset_done;
@@ -289,7 +290,9 @@ static irqreturn_t csid_isr(int irq, void *dev)
 				 * CSID from VFE. Once CSID received bus done, need notify
 				 * VFE of this event. Trigger VFE to handle bus done process.
 				 */
-				camss_buf_done(csid->camss, csid->id, i);
+				info.hw_id = csid->id;
+				info.port_id = i;
+				camss_buf_done(csid->camss, &info);
 			}
 		}
 
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 2551f0dfa37bb..065d14a872526 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -5033,14 +5033,14 @@ void camss_reg_update(struct camss *camss, int hw_id, int port_id, bool is_clear
 	}
 }
 
-void camss_buf_done(struct camss *camss, int hw_id, int port_id)
+void camss_buf_done(struct camss *camss, struct camss_buf_done_info *info)
 {
 	struct vfe_device *vfe;
 
-	if (hw_id < camss->res->vfe_num) {
-		vfe = &camss->vfe[hw_id];
+	if (info->hw_id < camss->res->vfe_num) {
+		vfe = &camss->vfe[info->hw_id];
 
-		vfe->res->hw_ops->vfe_buf_done(vfe, port_id);
+		vfe->res->hw_ops->vfe_buf_done(vfe, info->port_id);
 	}
 }
 
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 93d691c8ac63b..6a0d781ae7951 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -140,6 +140,11 @@ struct camss {
 	const struct camss_resources *res;
 };
 
+struct camss_buf_done_info {
+	int hw_id;
+	int port_id;
+};
+
 struct camss_camera_interface {
 	u8 csiphy_id;
 	struct csiphy_csi2_cfg csi2;
@@ -176,7 +181,7 @@ void camss_pm_domain_off(struct camss *camss, int id);
 int camss_vfe_get(struct camss *camss, int id);
 void camss_vfe_put(struct camss *camss, int id);
 void camss_delete(struct camss *camss);
-void camss_buf_done(struct camss *camss, int hw_id, int port_id);
+void camss_buf_done(struct camss *camss, struct camss_buf_done_info *info);
 void camss_reg_update(struct camss *camss, int hw_id,
 		      int port_id, bool is_clear);
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 48/74] media: qcom: camss: Add a status field to camss_buf_done_info
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (46 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 47/74] media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 49/74] media: qcom: camss: csid-gen3: Enable the IPP path bod
                   ` (26 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The pixel path completes several outputs, each on its own completion group.
Add a field to the camss_buf_done_info descriptor so that VFE can
understand which output finished.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 6a0d781ae7951..2974532401c81 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -143,6 +143,7 @@ struct camss {
 struct camss_buf_done_info {
 	int hw_id;
 	int port_id;
+	u32 status;
 };
 
 struct camss_camera_interface {

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 49/74] media: qcom: camss: csid-gen3: Enable the IPP path
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (47 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 48/74] media: qcom: camss: Add a status field to camss_buf_done_info bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 50/74] media: qcom: camss: vfe: Pass the completion info to vfe_buf_done() bod
                   ` (25 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 .../media/platform/qcom/camss/camss-csid-gen3.c    | 135 +++++++++++++++++----
 1 file changed, 112 insertions(+), 23 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
index 3a48bd072e0df..f8406c1fa45a5 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
@@ -44,6 +44,10 @@
 #define CSID_CSI2_RX_IRQ_MASK		0xA0
 #define CSID_CSI2_RX_IRQ_CLEAR		0xA4
 #define CSID_CSI2_RX_IRQ_SET		0xA8
+#define CSID_CSI2_IPP_IRQ_STATUS	0xAC
+#define CSID_CSI2_IPP_IRQ_CLEAR		0xB4
+#define		CSID_RUP_AUP_IPP	(BIT(0) | BIT(16))
+#define		CSID_RUP_AUP_MUP	BIT(28)
 
 #define IS_CSID_690(csid)	((csid->camss->res->version == CAMSS_8775P) \
 				 || (csid->camss->res->version == CAMSS_8300))
@@ -73,6 +77,18 @@
 #define		CSI2_RX_CFG1_ECC_CORRECTION_EN	BIT(0)
 #define		CSI2_RX_CFG1_VC_MODE		BIT(2)
 
+#define CSID_IPP_CFG0			0x300
+#define		IPP_CFG0_TIMESTAMP_EN		BIT(6)
+#define		IPP_CFG0_DECODE_FORMAT		12
+#define		IPP_CFG0_DT			16
+#define		IPP_CFG0_VC			22
+#define		IPP_CFG0_DT_ID			27
+#define		IPP_CFG0_EN			BIT(31)
+#define CSID_IPP_CTRL			0x304
+#define		IPP_CTRL_START_CMD		BIT(0)
+#define CSID_IPP_CAMIF_FRAME_CFG	0x330
+#define		IPP_CAMIF_PIXEL_PATTERN		24
+
 #define CSID_RDI_CFG0(rdi)	(csid_is_lite(csid) && IS_CSID_690(csid) ?\
 					(0x300 + 0x100 * (rdi)) :\
 					(0x500 + 0x100 * (rdi)))
@@ -157,6 +173,43 @@ static void __csid_configure_wrapper(struct csid_device *csid)
 	writel(val, csid->camss->csid_wrapper_base + CSID_IO_PATH_CFG0(csid->id));
 }
 
+static bool csid_port_is_ipp(struct csid_device *csid, u8 port)
+{
+	if (csid_is_lite(csid))
+		return false;
+
+	return port == VFE_LINE_PIX;
+}
+
+static void __csid_configure_ipp_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc)
+{
+	struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port];
+	const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+								   csid->res->formats->nformats,
+								   input_format->code);
+	u32 val;
+
+	writel(0, csid->base + CSID_IPP_CTRL);
+
+	/* The IPP decodes pixels for the pixel pipe: real decode format */
+	val = IPP_CFG0_TIMESTAMP_EN;
+	val |= format->decode_format << IPP_CFG0_DECODE_FORMAT;
+	val |= format->data_type << IPP_CFG0_DT;
+	val |= vc << IPP_CFG0_VC;
+	val |= 0 << IPP_CFG0_DT_ID;
+	if (enable)
+		val |= IPP_CFG0_EN;
+	writel(val, csid->base + CSID_IPP_CFG0);
+
+	writel(csid_ipp_bayer_pattern(input_format->code) << IPP_CAMIF_PIXEL_PATTERN,
+	       csid->base + CSID_IPP_CAMIF_FRAME_CFG);
+}
+
+static void __csid_ctrl_ipp(struct csid_device *csid, int resume)
+{
+	writel(resume ? IPP_CTRL_START_CMD : 0, csid->base + CSID_IPP_CTRL);
+}
+
 static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc)
 {
 	u32 val;
@@ -219,6 +272,8 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8
 	writel(val, csid->base + CSID_RDI_CFG0(port));
 }
 
+static int csid_reset(struct csid_device *csid);
+
 static void csid_configure_stream(struct csid_device *csid, u8 enable)
 {
 	u8 i;
@@ -228,9 +283,16 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
 	/* Loop through all enabled ports and configure a stream for each */
 	for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
 		if (csid->phy.en_vc & BIT(i)) {
-			__csid_configure_rdi_stream(csid, enable, i, 0);
-			__csid_configure_rx(csid, &csid->phy, 0);
-			__csid_ctrl_rdi(csid, enable, i);
+			if (csid_port_is_ipp(csid, i)) {
+				/* the VFE has programmed the pixel pipe in its s_stream */
+				__csid_configure_ipp_stream(csid, enable, i, 0);
+				__csid_configure_rx(csid, &csid->phy, 0);
+				__csid_ctrl_ipp(csid, enable);
+			} else {
+				__csid_configure_rdi_stream(csid, enable, i, 0);
+				__csid_configure_rx(csid, &csid->phy, 0);
+				__csid_ctrl_rdi(csid, enable, i);
+			}
 		}
 }
 
@@ -239,12 +301,21 @@ static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
 	return 0;
 }
 
+#define CSID_780_CUSTOM_PORT_ID_IPP0	0x100 /* TODO: bod don't like this too much */
+
 static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool clear)
 {
+	u32 val;
+
+	if (port_id == CSID_780_CUSTOM_PORT_ID_IPP0)
+		val = BIT(0) | BIT(16) | BIT(28);	/* RUP_IPP0 | AUP_IPP0 | MUP */
+	else
+		val = CSID_RUP_AUP_RDI(port_id);
+
 	if (clear) {
-		csid->reg_update &= ~CSID_RUP_AUP_RDI(port_id);
+		csid->reg_update &= ~val;
 	} else {
-		csid->reg_update |= CSID_RUP_AUP_RDI(port_id);
+		csid->reg_update |= val;
 		writel(csid->reg_update, csid->base + CSID_RUP_AUP_CMD);
 	}
 }
@@ -258,7 +329,6 @@ static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool c
  */
 static irqreturn_t csid_isr(int irq, void *dev)
 {
-	struct camss_buf_done_info info;
 	struct csid_device *csid = dev;
 	u32 val, buf_done_val;
 	u8 reset_done;
@@ -274,27 +344,43 @@ static irqreturn_t csid_isr(int irq, void *dev)
 	buf_done_val = readl(csid->base + CSID_BUF_DONE_IRQ_STATUS);
 	writel(buf_done_val, csid->base + CSID_BUF_DONE_IRQ_CLEAR);
 
-	/* Read and clear IRQ status for each enabled RDI channel */
-	for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
-		if (csid->phy.en_vc & BIT(i)) {
+	/* Read and clear IRQ status for each enabled port */
+	for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) {
+		u32 done;
+
+		if (!(csid->phy.en_vc & BIT(i)))
+			continue;
+
+		if (csid_port_is_ipp(csid, i)) {
+			val = readl(csid->base + CSID_CSI2_IPP_IRQ_STATUS);
+			writel(val, csid->base + CSID_CSI2_IPP_IRQ_CLEAR);
+			/* the pixel and statistics completion groups sit below the first RDI bit */
+			done = buf_done_val & (BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET) - 1);
+		} else {
 			val = readl(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i));
 			writel(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i));
+			done = buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i);
+		}
 
-			if (val & RUP_DONE_IRQ_STATUS)
-				/* clear the reg update bit */
-				csid_subdev_reg_update(csid, i, true);
-
-			if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i)) {
-				/*
-				 * For Titan Gen3, bus done and RUP IRQ have been moved to
-				 * CSID from VFE. Once CSID received bus done, need notify
-				 * VFE of this event. Trigger VFE to handle bus done process.
-				 */
-				info.hw_id = csid->id;
-				info.port_id = i;
-				camss_buf_done(csid->camss, &info);
-			}
+		if (val & RUP_DONE_IRQ_STATUS)
+			/* clear the reg update bit */
+			csid_subdev_reg_update(csid, i, true);
+
+		if (done) {
+			struct camss_buf_done_info info = {
+				.hw_id = csid->id,
+				.port_id = i,
+				.status = done,
+			};
+
+			/*
+			 * For Titan Gen3, bus done and RUP IRQ have been moved to
+			 * CSID from VFE. Once CSID received bus done, need notify
+			 * VFE of this event. Trigger VFE to handle bus done process.
+			 */
+			camss_buf_done(csid->camss, &info);
 		}
+	}
 
 	val = IRQ_CMD_CLEAR;
 	writel(val, csid->base + CSID_IRQ_CMD);
@@ -346,6 +432,9 @@ static int csid_reset(struct csid_device *csid)
 		return -EIO;
 	}
 
+	writel_relaxed(~0u, csid->base + CSID_TOP_IRQ_MASK);
+	writel_relaxed(~0u, csid->base + CSID_BUF_DONE_IRQ_MASK);
+
 	return 0;
 }
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 50/74] media: qcom: camss: vfe: Pass the completion info to vfe_buf_done()
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (48 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 49/74] media: qcom: camss: csid-gen3: Enable the IPP path bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 51/74] media: qcom: camss: vfe: Pass the buffer to vfe_wm_update() bod
                   ` (24 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The CSID reports which completion groups finished in the info it passes
to camss_buf_done(). Hand it on to the VFE: the vfe_buf_done() hw op and
the generic vfe_buf_done() take the struct camss_buf_done_info, and the
VFEs that see their own completions, vfe-340 and vfe-480, pass an empty
one.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-340.c | 7 +++++--
 drivers/media/platform/qcom/camss/camss-vfe-480.c | 9 ++++++---
 drivers/media/platform/qcom/camss/camss-vfe.c     | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe.h     | 6 ++++--
 drivers/media/platform/qcom/camss/camss.c         | 2 +-
 5 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 87f3e8f2ff539..493c4b2e64162 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -203,8 +203,11 @@ static irqreturn_t vfe_isr(int irq, void *dev)
 		}
 
 		for (i = 0; i < TFE_SUBGROUP_NUM; i++) {
-			if (bus_status & TFE_BUS_IRQ_MASK_BUF_DONE(i))
-				vfe_buf_done(vfe, __subgroup_to_line(i));
+			if (bus_status & TFE_BUS_IRQ_MASK_BUF_DONE(i)) {
+				struct camss_buf_done_info info = {};
+
+				vfe_buf_done(vfe, __subgroup_to_line(i), &info);
+			}
 		}
 
 		if (bus_status & TFE_BUS_IRQ_MASK_0_CONS_VIOL)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 6edbd8119aa7d..75dc73eadd6d0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -209,8 +209,11 @@ static irqreturn_t vfe_isr(int irq, void *dev)
 
 		/* Loop through all WMs IRQs */
 		for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) {
-			if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i)))
-				vfe_buf_done(vfe, i);
+			if (status & BUS_IRQ_MASK_0_COMP_DONE(vfe, RDI_COMP_GROUP(i))) {
+				struct camss_buf_done_info buf_done_info = {};
+
+				vfe_buf_done(vfe, i, &buf_done_info);
+			}
 		}
 	}
 
@@ -272,7 +275,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
 	/* nop */
 }
 
-static void vfe_buf_done_480(struct vfe_device *vfe, int port_id)
+static void vfe_buf_done_480(struct vfe_device *vfe, int port_id, struct camss_buf_done_info *info)
 {
 	/* nop */
 }
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 6ee9b5024447d..896e8d8e8d8a0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -621,7 +621,7 @@ u32 vfe_hw_version(struct vfe_device *vfe)
  * @vfe: VFE Device
  * @wm: Write master id
  */
-void vfe_buf_done(struct vfe_device *vfe, int wm)
+void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *buf_done_info)
 {
 	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 06bdc337f4d83..4e99a2c5b33af 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -159,6 +159,7 @@ struct vfe_line {
 };
 
 struct vfe_device;
+struct camss_buf_done_info;
 
 struct vfe_hw_ops {
 	void (*enable_irq)(struct vfe_device *vfe);
@@ -182,7 +183,8 @@ struct vfe_hw_ops {
 			     struct vfe_line *line);
 	void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm,
 			    struct vfe_line *line);
-	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id);
+	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id,
+			     struct camss_buf_done_info *buf_done_info);
 	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, u32 addr,
 			      struct vfe_line *line);
 
@@ -357,7 +359,7 @@ int vfe_enable_v2(struct vfe_line *line);
  * @vfe: VFE Device
  * @wm: Write master id
  */
-void vfe_buf_done(struct vfe_device *vfe, int wm);
+void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *buf_done_info);
 
 /*
  * vfe_get_output_v2 - Get vfe output line
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 065d14a872526..123df1d2591e9 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -5040,7 +5040,7 @@ void camss_buf_done(struct camss *camss, struct camss_buf_done_info *info)
 	if (info->hw_id < camss->res->vfe_num) {
 		vfe = &camss->vfe[info->hw_id];
 
-		vfe->res->hw_ops->vfe_buf_done(vfe, info->port_id);
+		vfe->res->hw_ops->vfe_buf_done(vfe, info->port_id, info);
 	}
 }
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 51/74] media: qcom: camss: vfe: Pass the buffer to vfe_wm_update()
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (49 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 50/74] media: qcom: camss: vfe: Pass the completion info to vfe_buf_done() bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 52/74] media: qcom: camss: Add the SM8650 IFE pixel pipe configuration bod
                   ` (23 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

A write master of a multi-planar output needs the address of its own
plane. Pass the struct camss_buffer to the vfe_wm_update() hw op instead
of its first address; every existing backend still programs addr[0].

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c | 5 +++--
 drivers/media/platform/qcom/camss/camss-vfe-340.c | 3 ++-
 drivers/media/platform/qcom/camss/camss-vfe-480.c | 3 ++-
 drivers/media/platform/qcom/camss/camss-vfe-680.c | 5 +++--
 drivers/media/platform/qcom/camss/camss-vfe-690.c | 4 +++-
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 4 +++-
 drivers/media/platform/qcom/camss/camss-vfe.c     | 6 +++---
 drivers/media/platform/qcom/camss/camss-vfe.h     | 2 +-
 8 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index 52812d34530d6..a2d336e7f7aa9 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -253,12 +253,13 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
 	struct v4l2_pix_format_mplane *pix =
 		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 	u32 stride = pix->plane_fmt[0].bytesperline;
+	u32 addr = buffer->addr[0];
 
 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
@@ -541,7 +542,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 	output->buf[index] = vfe_buf_get_pending(output);
 
 	if (output->buf[index])
-		vfe_wm_update(vfe, output->wm[0].bus_client, output->buf[index]->addr[0], line);
+		vfe_wm_update(vfe, output->wm[0].bus_client, output->buf[index], line);
 	else
 		output->gen2.active_num--;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 493c4b2e64162..e5a0a70eed1e6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -252,9 +252,10 @@ 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 wm, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
+	u32 addr = buffer->addr[0];
 	u8 client = tfe_wm_client_map[wm];
 
 	writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(client));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index 75dc73eadd6d0..bb065e47fe91e 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -133,9 +133,10 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
+	u32 addr = buffer->addr[0];
 	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 }
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-680.c b/drivers/media/platform/qcom/camss/camss-vfe-680.c
index d9a6402e8d928..242bacb051cc0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-680.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-680.c
@@ -144,10 +144,11 @@ static void vfe_disable_irq(struct vfe_device *vfe)
 	writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 1));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
-	u8 wm = RDI_WM(rdi);
+	u32 addr = buffer->addr[0];
+	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
 
 	writel(addr, vfe->base + VFE_BUS_IMAGE_ADDR(vfe, wm));
 }
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-690.c b/drivers/media/platform/qcom/camss/camss-vfe-690.c
index fb40560d4ab41..efe8d963b4703 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-690.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-690.c
@@ -96,9 +96,11 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
+	u32 addr = buffer->addr[0];
+
 	wm = RDI_WM(wm);
 
 	writel(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 88d74323fe276..d70e829524fdf 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -118,9 +118,11 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
+	u32 addr = buffer->addr[0];
+
 	wm = line->output[0].wm[0].bus_client;
 
 	writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 896e8d8e8d8a0..fbc2068b301bc 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -662,7 +662,7 @@ void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *bu
 			ops->vfe_output_update(vfe, output, output->buf[index]);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   output->buf[index]->addr[0],
+					   output->buf[index],
 					   line);
 		ops->reg_update(vfe, line->id);
 	} else {
@@ -714,7 +714,7 @@ static int vfe_enable_one_output(struct vfe_line *line, struct vfe_output *outpu
 			ops->vfe_output_update(vfe, output, output->buf[i]);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   output->buf[i]->addr[0], line);
+					   output->buf[i], line);
 		ops->reg_update(vfe, line->id);
 	}
 
@@ -785,7 +785,7 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
 			ops->vfe_output_update(vfe, output, buf);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   buf->addr[0], line);
+					   buf, line);
 		ops->reg_update(vfe, line->id);
 	} else {
 		vfe_buf_add_pending(output, buf);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 4e99a2c5b33af..0b632479cefc6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -185,7 +185,7 @@ struct vfe_hw_ops {
 			    struct vfe_line *line);
 	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id,
 			     struct camss_buf_done_info *buf_done_info);
-	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, u32 addr,
+	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			      struct vfe_line *line);
 
 	/* Output based API - new and shiny */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 52/74] media: qcom: camss: Add the SM8650 IFE pixel pipe configuration
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (50 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 51/74] media: qcom: camss: vfe: Pass the buffer to vfe_wm_update() bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 53/74] media: qcom: camss: csid-gen3: Define the IPP reg update port in the header bod
                   ` (22 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Program the IFE pixel pipe for NV12 output, one function per block:

  vfe_setup_core_config()                TOP CORE_CFG
  vfe_setup_chroma_downscale_nv12()      chroma 2:1          (geometry)
  vfe_setup_demosaic()                   demosaic + WB gains 4.0
  vfe_setup_color_correction()           CC channel permutation
  vfe_setup_gamma_luts()                 per-channel gamma 1/2.2
  vfe_setup_color_transform()            RGB->YUV BT.601
  vfe_setup_aec_bhist()                  AEC BHIST, DMI clear (geometry)
  vfe_setup_main_output_round_clamp()    round mode 2, clamp 0..255
  vfe_setup_ds4()                        DS4 + filter tables (geometry)
  vfe_setup_ds16()                       DS16 + crops        (geometry)

Register values derived from floating-point parameters are kept as
their fixed-point forms; the geometry is computed from the active
format. Tuning stays static until a parameters buffer takes it over.

Nothing calls it yet; the vfe-780 pixel path will.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile         |   1 +
 .../media/platform/qcom/camss/camss-vfe-880-pp.c   | 612 +++++++++++++++++++++
 .../media/platform/qcom/camss/camss-vfe-880-pp.h   |  11 +
 3 files changed, 624 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 4dcb08a0e25aa..b700e6fd594ca 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -27,6 +27,7 @@ qcom-camss-objs += \
 		camss-vfe-680.o \
 		camss-vfe-690.o \
 		camss-vfe-780.o \
+		camss-vfe-880-pp.o \
 		camss-vfe-gen1.o \
 		camss-vfe-vbif.o \
 		camss-video.o
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
new file mode 100644
index 0000000000000..8f56e584b180b
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
@@ -0,0 +1,612 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm MSM Camera Subsystem - VFE 880 (SM8650) pixel pipe setup
+ *
+ * Static pixel pipe configuration for NV12 output, one function per
+ * block. Values derived from floating-point parameters are kept as their
+ * fixed-point register values; geometry comes from the active format.
+ * Tuning (WB, CC, gamma, CST) is static until the params buffer takes it
+ * over.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+#include "camss-vfe-880-pp.h"
+
+/* Register offsets, named as in the IFE register map */
+#define IFE_TOP_CORE_CFG_0                                       0x00024
+#define IFE_WB_GAIN_MODULE_CFG                                   0x04560
+#define IFE_WB_GAIN_WB_CFG_0                                     0x04568
+#define IFE_WB_GAIN_WB_CFG_1                                     0x0456c
+#define IFE_WB_GAIN_WB_CFG_2                                     0x04570
+#define IFE_WB_GAIN_WB_OFFSET_CFG_0                              0x04574
+#define IFE_WB_GAIN_WB_OFFSET_CFG_1                              0x04578
+#define IFE_WB_GAIN_WB_OFFSET_CFG_2                              0x0457c
+#define IFE_WB_GAIN_WB_OFFSET_CFG_3                              0x04580
+#define IFE_WB_GAIN_WB_OFFSET_CFG_4                              0x04584
+#define IFE_WB_GAIN_WB_OFFSET_CFG_5                              0x04588
+#define IFE_DEMOSAIC_MODULE_CFG                                  0x05660
+#define IFE_DEMOSAIC_INTERP_COEFF_CFG_0                          0x05668
+#define IFE_DEMOSAIC_INTERP_COEFF_CFG_1                          0x0566c
+#define IFE_DEMOSAIC_INTERP_CLASSIFIER_CFG_0                     0x05670
+#define IFE_DEMOSAIC_INTERP_CLASSIFIER_CFG_1                     0x05674
+#define IFE_COLOR_CORRECT_MODULE_CFG                             0x05860
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_A_CFG_0            0x05868
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_A_CFG_1            0x0586c
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_B_CFG_0            0x05870
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_B_CFG_1            0x05874
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_C_CFG_0            0x05878
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_C_CFG_1            0x0587c
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_SHIFT_M_CFG              0x0588c
+#define IFE_GLUT_DMI_CFG                                         0x05f08
+#define IFE_GLUT_DMI_LUT_CFG                                     0x05f0c
+#define IFE_GLUT_DMI_DATA                                        0x05f10
+#define IFE_GLUT_DMI_LUT_BANK_CFG                                0x05f58
+#define IFE_GLUT_MODULE_LUT_BANK_CFG                             0x05f5c
+#define IFE_GLUT_MODULE_CFG                                      0x05f60
+#define IFE_COLOR_XFORM_MODULE_CFG                               0x06160
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_COEFF_CFG_0              0x06168
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_COEFF_CFG_1              0x0616c
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_ADDOFFSET_CFG            0x06170
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_SUBOFFSET_CFG            0x06174
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_CLAMP0_CFG               0x06178
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH0_CLAMP1_CFG               0x0617c
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_COEFF_CFG_0              0x06180
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_COEFF_CFG_1              0x06184
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_ADDOFFSET_CFG            0x06188
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_SUBOFFSET_CFG            0x0618c
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_CLAMP0_CFG               0x06190
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH1_CLAMP1_CFG               0x06194
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_COEFF_CFG_0              0x06198
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_COEFF_CFG_1              0x0619c
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_ADDOFFSET_CFG            0x061a0
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_SUBOFFSET_CFG            0x061a4
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_CLAMP0_CFG               0x061a8
+#define IFE_COLOR_XFORM_COLOR_XFORM_CH2_CLAMP1_CFG               0x061ac
+#define IFE_DOWNSCALE_MN_C_VID_OUT_MODULE_CFG                    0x09a60
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_CFG            0x09a64
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_IMAGE_SIZE_CFG 0x09a68
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_H_CFG          0x09a6c
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_H_PHASE_CFG    0x09a70
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_V_CFG          0x09a74
+#define IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_V_PHASE_CFG    0x09a78
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_MODULE_CFG 0x09c60
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_CLAMP_MIN 0x09c70
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_ROUNDING_CFG 0x09c74
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_CLAMP_MIN 0x09c78
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_ROUNDING_CFG 0x09c7c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_CLAMP_MIN 0x09c80
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_ROUNDING_CFG 0x09c84
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_CLAMP_MAX 0x09c88
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_CLAMP_MAX 0x09c8c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_CLAMP_MAX 0x09c90
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_MODULE_CFG 0x09e60
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_CLAMP_MIN 0x09e70
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_ROUNDING_CFG 0x09e74
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_CLAMP_MIN 0x09e78
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_ROUNDING_CFG 0x09e7c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_CLAMP_MIN 0x09e80
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_ROUNDING_CFG 0x09e84
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_CLAMP_MAX 0x09e88
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_CLAMP_MAX 0x09e8c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_CLAMP_MAX 0x09e90
+#define IFE_DSX_Y_VID_OUT_DMI_CFG                                0x0a008
+#define IFE_DSX_Y_VID_OUT_DMI_LUT_CFG                            0x0a00c
+#define IFE_DSX_Y_VID_OUT_DMI_DATA                               0x0a010
+#define IFE_DSX_Y_VID_OUT_DMI_DATA_1                             0x0a014
+#define IFE_DSX_Y_VID_OUT_DMI_LUT_BANK_CFG                       0x0a058
+#define IFE_DSX_Y_VID_OUT_MODULE_LUT_BANK_CFG                    0x0a05c
+#define IFE_DSX_Y_VID_OUT_MODULE_CFG                             0x0a060
+#define IFE_DSX_Y_VID_OUT_MODE                                   0x0a064
+#define IFE_DSX_Y_VID_OUT_START_LOCATION_X                       0x0a068
+#define IFE_DSX_Y_VID_OUT_START_LOCATION_Y                       0x0a06c
+#define IFE_DSX_Y_VID_OUT_SCALE_RATIO_X                          0x0a070
+#define IFE_DSX_Y_VID_OUT_SCALE_RATIO_Y                          0x0a074
+#define IFE_DSX_Y_VID_OUT_OUT_SIZE                               0x0a078
+#define IFE_DSX_Y_VID_OUT_IN_SIZE                                0x0a07c
+#define IFE_DSX_C_VID_OUT_DMI_CFG                                0x0a208
+#define IFE_DSX_C_VID_OUT_DMI_LUT_CFG                            0x0a20c
+#define IFE_DSX_C_VID_OUT_DMI_DATA                               0x0a210
+#define IFE_DSX_C_VID_OUT_DMI_DATA_1                             0x0a214
+#define IFE_DSX_C_VID_OUT_DMI_LUT_BANK_CFG                       0x0a258
+#define IFE_DSX_C_VID_OUT_MODULE_LUT_BANK_CFG                    0x0a25c
+#define IFE_DSX_C_VID_OUT_MODULE_CFG                             0x0a260
+#define IFE_DSX_C_VID_OUT_MODE                                   0x0a264
+#define IFE_DSX_C_VID_OUT_START_LOCATION_X                       0x0a268
+#define IFE_DSX_C_VID_OUT_START_LOCATION_Y                       0x0a26c
+#define IFE_DSX_C_VID_OUT_SCALE_RATIO_X                          0x0a270
+#define IFE_DSX_C_VID_OUT_SCALE_RATIO_Y                          0x0a274
+#define IFE_DSX_C_VID_OUT_OUT_SIZE                               0x0a278
+#define IFE_DSX_C_VID_OUT_IN_SIZE                                0x0a27c
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_MODULE_CFG         0x0a460
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CROP_LINE_CFG      0x0a468
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CROP_PIXEL_CFG     0x0a46c
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH0_CLAMP_MIN      0x0a470
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH1_CLAMP_MIN      0x0a478
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH2_CLAMP_MIN      0x0a480
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH0_CLAMP_MAX      0x0a488
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH1_CLAMP_MAX      0x0a48c
+#define IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH2_CLAMP_MAX      0x0a490
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_MODULE_CFG         0x0a660
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CROP_LINE_CFG      0x0a668
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CROP_PIXEL_CFG     0x0a66c
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH0_CLAMP_MIN      0x0a670
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH1_CLAMP_MIN      0x0a678
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH2_CLAMP_MIN      0x0a680
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH0_CLAMP_MAX      0x0a688
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH1_CLAMP_MAX      0x0a68c
+#define IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH2_CLAMP_MAX      0x0a690
+#define IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_MODULE_CFG             0x0a860
+#define IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_DS_COEFF               0x0a868
+#define IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_LINE_CFG          0x0a904
+#define IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_PIXEL_CFG         0x0a908
+#define IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_MODULE_CFG             0x0aa60
+#define IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_LINE_CFG          0x0ab04
+#define IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_PIXEL_CFG         0x0ab08
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_MODULE_CFG 0x0ac60
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_LINE_CFG 0x0ac68
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_PIXEL_CFG 0x0ac6c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH0_CLAMP_MIN 0x0ac70
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH1_CLAMP_MIN 0x0ac78
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH2_CLAMP_MIN 0x0ac80
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH0_CLAMP_MAX 0x0ac88
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH1_CLAMP_MAX 0x0ac8c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH2_CLAMP_MAX 0x0ac90
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_MODULE_CFG 0x0ae60
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_LINE_CFG 0x0ae68
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_PIXEL_CFG 0x0ae6c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH0_CLAMP_MIN 0x0ae70
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH1_CLAMP_MIN 0x0ae78
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH2_CLAMP_MIN 0x0ae80
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH0_CLAMP_MAX 0x0ae88
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH1_CLAMP_MAX 0x0ae8c
+#define IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH2_CLAMP_MAX 0x0ae90
+#define IFE_STATS_AEC_BHIST_DMI_CFG                              0x0b208
+#define IFE_STATS_AEC_BHIST_DMI_LUT_CFG                          0x0b20c
+#define IFE_STATS_AEC_BHIST_DMI_DATA                             0x0b210
+#define IFE_STATS_AEC_BHIST_DMI_LUT_BANK_CFG                     0x0b258
+#define IFE_STATS_AEC_BHIST_MODULE_LUT_BANK_CFG                  0x0b25c
+#define IFE_STATS_AEC_BHIST_MODULE_CFG                           0x0b260
+#define IFE_STATS_AEC_BHIST_BLACK_LEVEL_SUB_CFG_0                0x0b264
+#define IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG                       0x0b268
+#define IFE_STATS_AEC_BHIST_RGN_NUM_CFG                          0x0b26c
+#define IFE_STATS_AEC_BHIST_SEGMENT_SLOPE_CFG_0                  0x0b290
+#define IFE_STATS_AEC_BHIST_SEGMENT_SLOPE_CFG_1                  0x0b294
+#define IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_0              0x0b298
+#define IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_1              0x0b29c
+#define IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_2              0x0b2a0
+#define IFE_STATS_AEC_BHIST_Y_CONV_COEFF_CFG                     0x0b2a4
+#define IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_1                     0x0b2a8
+#define IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_2                     0x0b2ac
+#define IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_3                     0x0b2b0
+#define IFE_STATS_AEC_BHIST_RGN_NUM_CFG_1                        0x0b2b4
+#define IFE_STATS_AEC_BHIST_RGN_NUM_CFG_2                        0x0b2b8
+#define IFE_STATS_AEC_BHIST_RGN_NUM_CFG_3                        0x0b2bc
+#define IFE_STATS_AEC_BHIST_RGN_WEIGHT_CFG                       0x0b2c0
+#define IFE_COLOR_CORRECT_COLOR_CORRECT_OFFSET_K_CFG(x)          (0x05880 + 4 * (x))
+#define IFE_STATS_AEC_BHIST_RGN_0_SLOPE_CFG(x)                   (0x0b2c4 + 4 * (x))
+#define IFE_STATS_AEC_BHIST_RGN_1_SLOPE_CFG(x)                   (0x0b2d4 + 4 * (x))
+#define IFE_STATS_AEC_BHIST_RGN_2_SLOPE_CFG(x)                   (0x0b2e4 + 4 * (x))
+#define IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(x)                  (0x0b270 + 4 * (x))
+
+/* gamma 1/2.2: value and slope packed per entry */
+static const u32 vfe_pp_gamma_lut[256] = {
+	0x52000, 0x1e148, 0x161c0, 0x1221c, 0x10268, 0x0e2ac,
+	0x0d2e4, 0x0c31c, 0x0b34c, 0x0a37c, 0x0a3a8, 0x093d0,
+	0x093f8, 0x09420, 0x08444, 0x08464, 0x08488, 0x074a8,
+	0x074c8, 0x074e4, 0x07504, 0x07520, 0x0653c, 0x06558,
+	0x06574, 0x0658c, 0x065a8, 0x065c0, 0x065d8, 0x055f0,
+	0x05608, 0x05620, 0x05634, 0x0564c, 0x05664, 0x05678,
+	0x0568c, 0x056a4, 0x056b8, 0x056cc, 0x046e0, 0x046f4,
+	0x04708, 0x0471c, 0x0472c, 0x04740, 0x04754, 0x04764,
+	0x04778, 0x04788, 0x0479c, 0x047ac, 0x047c0, 0x047d0,
+	0x047e0, 0x047f4, 0x04804, 0x04814, 0x04824, 0x04834,
+	0x03844, 0x03854, 0x03864, 0x03874, 0x03884, 0x03894,
+	0x038a0, 0x038b0, 0x038c0, 0x038d0, 0x038dc, 0x038ec,
+	0x038fc, 0x03908, 0x03918, 0x03928, 0x03934, 0x03944,
+	0x03950, 0x03960, 0x0396c, 0x03978, 0x03988, 0x03994,
+	0x039a4, 0x039b0, 0x039bc, 0x039c8, 0x039d8, 0x039e4,
+	0x039f0, 0x039fc, 0x03a0c, 0x03a18, 0x03a24, 0x03a30,
+	0x03a3c, 0x03a48, 0x03a54, 0x03a60, 0x03a6c, 0x03a78,
+	0x02a84, 0x02a90, 0x02a9c, 0x02aa8, 0x02ab4, 0x02ac0,
+	0x02acc, 0x02ad8, 0x02ae4, 0x02af0, 0x02afc, 0x02b08,
+	0x02b10, 0x02b1c, 0x02b28, 0x02b34, 0x02b40, 0x02b48,
+	0x02b54, 0x02b60, 0x02b6c, 0x02b74, 0x02b80, 0x02b8c,
+	0x02b94, 0x02ba0, 0x02bac, 0x02bb4, 0x02bc0, 0x02bcc,
+	0x02bd4, 0x02be0, 0x02be8, 0x02bf4, 0x02c00, 0x02c08,
+	0x02c14, 0x02c1c, 0x02c28, 0x02c30, 0x02c3c, 0x02c44,
+	0x02c50, 0x02c58, 0x02c64, 0x02c6c, 0x02c78, 0x02c80,
+	0x02c8c, 0x02c94, 0x02c9c, 0x02ca8, 0x02cb0, 0x02cbc,
+	0x02cc4, 0x02ccc, 0x02cd8, 0x02ce0, 0x02cec, 0x02cf4,
+	0x02cfc, 0x02d08, 0x02d10, 0x02d18, 0x02d20, 0x02d2c,
+	0x02d34, 0x02d3c, 0x02d48, 0x02d50, 0x02d58, 0x02d60,
+	0x02d6c, 0x02d74, 0x02d7c, 0x02d84, 0x02d90, 0x02d98,
+	0x02da0, 0x02da8, 0x02db0, 0x02dbc, 0x02dc4, 0x02dcc,
+	0x02dd4, 0x02ddc, 0x02de4, 0x02df0, 0x02df8, 0x02e00,
+	0x02e08, 0x02e10, 0x02e18, 0x02e20, 0x02e28, 0x02e34,
+	0x02e3c, 0x02e44, 0x02e4c, 0x02e54, 0x02e5c, 0x02e64,
+	0x02e6c, 0x02e74, 0x02e7c, 0x02e84, 0x02e8c, 0x02e94,
+	0x02e9c, 0x02ea4, 0x02eac, 0x02eb4, 0x02ebc, 0x01ec4,
+	0x01ecc, 0x01ed4, 0x01edc, 0x01ee4, 0x01eec, 0x01ef4,
+	0x01efc, 0x01f04, 0x01f0c, 0x01f14, 0x01f1c, 0x01f24,
+	0x01f2c, 0x01f34, 0x01f3c, 0x01f44, 0x01f4c, 0x01f54,
+	0x01f5c, 0x01f60, 0x01f68, 0x01f70, 0x01f78, 0x01f80,
+	0x01f88, 0x01f90, 0x01f98, 0x01fa0, 0x01fa4, 0x01fac,
+	0x01fb4, 0x01fbc, 0x01fc4, 0x01fcc, 0x01fd4, 0x01fd8,
+	0x01fe0, 0x01fe8, 0x01ff0, 0x01ff8,
+};
+
+/* downscaler filter coefficients: { hi, lo } */
+static const u32 vfe_pp_ds4_y_coeff[96][2] = {
+	{ 0x99099098, 0x00000000 }, { 0x99099099, 0x00000000 }, { 0x99099099, 0x00000000 },
+	{ 0x99098099, 0x00000000 }, { 0x99098099, 0x00000000 }, { 0x98099099, 0x00000000 },
+	{ 0x98098098, 0x00000000 }, { 0x98098098, 0x00000000 }, { 0x98098098, 0x00000000 },
+	{ 0x98098098, 0x00000000 }, { 0x98098098, 0x00000000 }, { 0x98097098, 0x00000000 },
+	{ 0x98097098, 0x00000000 }, { 0x98098098, 0x00000000 }, { 0x97098098, 0x00000000 },
+	{ 0x97097097, 0x00000000 }, { 0x97097097, 0x00000000 }, { 0x97097097, 0x00000000 },
+	{ 0x96096097, 0x00000000 }, { 0x95096096, 0x00000000 }, { 0x94095095, 0x00000000 },
+	{ 0x93094094, 0x00000000 }, { 0x92093093, 0x00000000 }, { 0x90091092, 0x00000000 },
+	{ 0x8e08f090, 0x00000000 }, { 0x8b08c08e, 0x00000000 }, { 0x8808908b, 0x00000000 },
+	{ 0x84086088, 0x00000000 }, { 0x80082084, 0x00000000 }, { 0x7c07e080, 0x00000000 },
+	{ 0x7707907c, 0x00000000 }, { 0x73075077, 0x00000000 }, { 0x6f071073, 0x00000000 },
+	{ 0x6a06d06f, 0x00000000 }, { 0x6706906a, 0x00000000 }, { 0x63065067, 0x00000000 },
+	{ 0x60062063, 0x00000000 }, { 0x5e05f060, 0x00000000 }, { 0x5c05d05e, 0x00000000 },
+	{ 0x5b05b05c, 0x00000000 }, { 0x5b05b05b, 0x00000000 }, { 0x5c05b05b, 0x00000000 },
+	{ 0x5e05d05c, 0x00000000 }, { 0x6106005e, 0x00000000 }, { 0x65063061, 0x00000000 },
+	{ 0x68066065, 0x00000000 }, { 0x6c06a068, 0x00000000 }, { 0x7106e06c, 0x00000000 },
+	{ 0x74073071, 0x00000000 }, { 0x78076074, 0x00000000 }, { 0x7b07a078, 0x00000000 },
+	{ 0x7e07d07b, 0x00000000 }, { 0x7f07f07e, 0x00000000 }, { 0x8008007f, 0x00000000 },
+	{ 0x7f080080, 0x00000000 }, { 0x7d07e07f, 0x00000000 }, { 0x7907b07d, 0x00000000 },
+	{ 0x74077079, 0x00000000 }, { 0x6e071074, 0x00000000 }, { 0x6606a06e, 0x00000000 },
+	{ 0x5d062066, 0x00000000 }, { 0x5405905d, 0x00000000 }, { 0x4b04f054, 0x00000000 },
+	{ 0x4104604b, 0x00000000 }, { 0x3703c041, 0x00000000 }, { 0x2d032037, 0x00000000 },
+	{ 0x2302802d, 0x00000000 }, { 0x1a01f023, 0x00000000 }, { 0x1201601a, 0x00000000 },
+	{ 0x0b00e012, 0x00000000 }, { 0x0500800b, 0x00000000 }, { 0x00002005, 0x00000000 },
+	{ 0xfdffe000, 0x0000000f }, { 0xfaffbffd, 0x0000000f }, { 0xf8ff9ffa, 0x0000000f },
+	{ 0xf7ff8ff8, 0x0000000f }, { 0xf7ff7ff7, 0x0000000f }, { 0xf7ff7ff7, 0x0000000f },
+	{ 0xf7ff7ff7, 0x0000000f }, { 0xf8ff8ff7, 0x0000000f }, { 0xf9ff9ff8, 0x0000000f },
+	{ 0xfbffaff9, 0x0000000f }, { 0xfcffbffb, 0x0000000f }, { 0xfdffcffc, 0x0000000f },
+	{ 0xfeffeffd, 0x0000000f }, { 0xfffffffe, 0x0000000f }, { 0x00000fff, 0x00000000 },
+	{ 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+	{ 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+	{ 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+};
+
+/* downscaler filter coefficients: { hi, lo } */
+static const u32 vfe_pp_ds4_c_coeff[48][2] = {
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 }, { 0x00100100, 0x00000001 },
+	{ 0xf00f8100, 0x00000000 }, { 0xe00e80f0, 0x00000000 }, { 0xd00d80e0, 0x00000000 },
+	{ 0xc00c80d0, 0x00000000 }, { 0xb00b80c0, 0x00000000 }, { 0xa00a80b0, 0x00000000 },
+	{ 0x900980a0, 0x00000000 }, { 0x80088090, 0x00000000 }, { 0x70078080, 0x00000000 },
+	{ 0x60068070, 0x00000000 }, { 0x50058060, 0x00000000 }, { 0x40048050, 0x00000000 },
+	{ 0x30038040, 0x00000000 }, { 0x20028030, 0x00000000 }, { 0x10018020, 0x00000000 },
+	{ 0x00008010, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+	{ 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+	{ 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000 },
+};
+
+/* TOP CORE_CFG: pixel pipe input format and enables */
+static void vfe_setup_core_config(struct vfe_device *vfe)
+{
+	writel_relaxed(0x00006000, vfe->base + IFE_TOP_CORE_CFG_0);
+}
+
+/* Chroma 2:1 for NV12 */
+static void vfe_setup_chroma_downscale_nv12(struct vfe_device *vfe, u32 w, u32 h)
+{
+	writel_relaxed(0x00000001, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_MODULE_CFG);
+	writel_relaxed(0x00000600, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_CFG);
+	writel_relaxed(((w - 1) << 16) | (h - 1), vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_IMAGE_SIZE_CFG);
+	writel_relaxed(0xc0400000, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_H_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_H_PHASE_CFG);
+	writel_relaxed(0xc0400000, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_V_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DOWNSCALE_MN_C_VID_OUT_DOWNSCALE_MN_C_V_PHASE_CFG);
+}
+
+/* Demosaic + WB: sub offsets 0, gains 4.0, add offsets 0 */
+static void vfe_setup_demosaic(struct vfe_device *vfe)
+{
+	writel_relaxed(0x00000001, vfe->base + IFE_DEMOSAIC_MODULE_CFG);
+	writel_relaxed(0x00000080, vfe->base + IFE_DEMOSAIC_INTERP_COEFF_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_DEMOSAIC_INTERP_COEFF_CFG_1);
+	writel_relaxed(0x00000040, vfe->base + IFE_DEMOSAIC_INTERP_CLASSIFIER_CFG_0);
+	writel_relaxed(0x00000066, vfe->base + IFE_DEMOSAIC_INTERP_CLASSIFIER_CFG_1);
+	writel_relaxed(0x00000001, vfe->base + IFE_WB_GAIN_MODULE_CFG);
+	writel_relaxed(0x00001000, vfe->base + IFE_WB_GAIN_WB_CFG_0);
+	writel_relaxed(0x00001000, vfe->base + IFE_WB_GAIN_WB_CFG_1);
+	writel_relaxed(0x00001000, vfe->base + IFE_WB_GAIN_WB_CFG_2);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_2);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_3);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_4);
+	writel_relaxed(0x00000000, vfe->base + IFE_WB_GAIN_WB_OFFSET_CFG_5);
+}
+
+/* Colour correction: channel permutation, no offsets */
+static void vfe_setup_color_correction(struct vfe_device *vfe)
+{
+	writel_relaxed(0x00000001, vfe->base + IFE_COLOR_CORRECT_MODULE_CFG);
+	writel_relaxed(0x00800000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_A_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_A_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_B_CFG_0);
+	writel_relaxed(0x00000080, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_B_CFG_1);
+	writel_relaxed(0x00000080, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_C_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_COEFF_C_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_OFFSET_K_CFG(0));
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_OFFSET_K_CFG(1));
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_OFFSET_K_CFG(2));
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_CORRECT_COLOR_CORRECT_SHIFT_M_CFG);
+}
+
+/* Per-channel gamma LUTs: 1/2.2, 256 entries, same table for R, G and B */
+static void vfe_setup_gamma_luts(struct vfe_device *vfe)
+{
+	int i;
+
+	writel_relaxed(0x00000001, vfe->base + IFE_GLUT_MODULE_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_MODULE_LUT_BANK_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_LUT_BANK_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < 256; i++)
+		writel_relaxed(0, vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000002, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < 256; i++)
+		writel_relaxed(0, vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000003, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < 256; i++)
+		writel_relaxed(0, vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_gamma_lut); i++)
+		writel_relaxed(vfe_pp_gamma_lut[i], vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000002, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_gamma_lut); i++)
+		writel_relaxed(vfe_pp_gamma_lut[i], vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000003, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_gamma_lut); i++)
+		writel_relaxed(vfe_pp_gamma_lut[i], vfe->base + IFE_GLUT_DMI_DATA);
+	writel_relaxed(0x00000000, vfe->base + IFE_GLUT_DMI_LUT_CFG);
+}
+
+/* RGB->YUV: BT.601, Cb/Cr offset 512, clamp 0..1023 */
+static void vfe_setup_color_transform(struct vfe_device *vfe)
+{
+	writel_relaxed(0x00000001, vfe->base + IFE_COLOR_XFORM_MODULE_CFG);
+	writel_relaxed(0x02590132, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_COEFF_CFG_0);
+	writel_relaxed(0x00000074, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_COEFF_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_ADDOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_SUBOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_CLAMP0_CFG);
+	writel_relaxed(0xffc00000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH0_CLAMP1_CFG);
+	writel_relaxed(0x1ead1f54, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_COEFF_CFG_0);
+	writel_relaxed(0x00000200, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_COEFF_CFG_1);
+	writel_relaxed(0x40000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_ADDOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_SUBOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_CLAMP0_CFG);
+	writel_relaxed(0xffc00000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH1_CLAMP1_CFG);
+	writel_relaxed(0x1e540200, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_COEFF_CFG_0);
+	writel_relaxed(0x00001fad, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_COEFF_CFG_1);
+	writel_relaxed(0x40000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_ADDOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_SUBOFFSET_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_CLAMP0_CFG);
+	writel_relaxed(0xffc00000, vfe->base + IFE_COLOR_XFORM_COLOR_XFORM_CH2_CLAMP1_CFG);
+}
+
+/* AEC BHIST: Y histogram over the full frame, DMI cleared */
+static void vfe_setup_aec_bhist(struct vfe_device *vfe, u32 w, u32 h)
+{
+	int i;
+
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_DMI_LUT_BANK_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_STATS_AEC_BHIST_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_DMI_CFG);
+	for (i = 0; i < 1024; i++)
+		writel_relaxed(0, vfe->base + IFE_STATS_AEC_BHIST_DMI_DATA);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_DMI_LUT_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_STATS_AEC_BHIST_MODULE_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_BLACK_LEVEL_SUB_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG);
+	writel_relaxed(((h / 2 - 1) << 16) | (w / 2 - 1), vfe->base + IFE_STATS_AEC_BHIST_RGN_NUM_CFG);
+	writel_relaxed(0xffc00000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(0));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(1));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(2));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(3));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(4));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(5));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(6));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_BASE_CFG(7));
+	writel_relaxed(0x00000008, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_SLOPE_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_SLOPE_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_0);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_SEGMENT_START_BIN_CFG_2);
+	writel_relaxed(0x00081205, vfe->base + IFE_STATS_AEC_BHIST_Y_CONV_COEFF_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_2);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG_3);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_NUM_CFG_1);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_NUM_CFG_2);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_NUM_CFG_3);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_WEIGHT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_0_SLOPE_CFG(0));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_1_SLOPE_CFG(0));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_2_SLOPE_CFG(0));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_0_SLOPE_CFG(1));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_1_SLOPE_CFG(1));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_2_SLOPE_CFG(1));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_0_SLOPE_CFG(2));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_1_SLOPE_CFG(2));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_2_SLOPE_CFG(2));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_0_SLOPE_CFG(3));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_1_SLOPE_CFG(3));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_RGN_2_SLOPE_CFG(3));
+	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_MODULE_LUT_BANK_CFG);
+}
+
+/* Main output round/clamp: round mode 2, clamp 0..255 */
+static void vfe_setup_main_output_round_clamp(struct vfe_device *vfe)
+{
+	writel_relaxed(0x0000fc01, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_MODULE_CFG);
+	writel_relaxed(0x0000fc01, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_MODULE_CFG);
+	writel_relaxed(0x00000010, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_ROUNDING_CFG);
+	writel_relaxed(0x00000010, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_ROUNDING_CFG);
+	writel_relaxed(0x00000010, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_ROUNDING_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH1_CLAMP_MAX);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT_CH2_CLAMP_MAX);
+	writel_relaxed(0x00000011, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_ROUNDING_CFG);
+	writel_relaxed(0x00000011, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_ROUNDING_CFG);
+	writel_relaxed(0x00000011, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_ROUNDING_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH1_CLAMP_MAX);
+	writel_relaxed(0x000000ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT_CH2_CLAMP_MAX);
+}
+
+/* DS4: 4:1 downscale of Y and C, with crops */
+static void vfe_setup_ds4(struct vfe_device *vfe, u32 w, u32 h)
+{
+	const u32 ds4_w = ALIGN(w, 8) / 4;
+	const u32 ds4_h = ALIGN(h, 8) / 4;
+	int i;
+
+	writel_relaxed(0x00000001, vfe->base + IFE_DSX_Y_VID_OUT_MODULE_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_MODULE_LUT_BANK_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_MODE);
+	writel_relaxed(0x00030000, vfe->base + IFE_DSX_Y_VID_OUT_START_LOCATION_X);
+	writel_relaxed(0x00030000, vfe->base + IFE_DSX_Y_VID_OUT_START_LOCATION_Y);
+	writel_relaxed(0x00080000, vfe->base + IFE_DSX_Y_VID_OUT_SCALE_RATIO_X);
+	writel_relaxed(0x00080000, vfe->base + IFE_DSX_Y_VID_OUT_SCALE_RATIO_Y);
+	writel_relaxed((h << 16) | w, vfe->base + IFE_DSX_Y_VID_OUT_IN_SIZE);
+	writel_relaxed((ds4_h << 16) | ds4_w, vfe->base + IFE_DSX_Y_VID_OUT_OUT_SIZE);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_DMI_LUT_BANK_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_DSX_Y_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_ds4_y_coeff); i++) {
+		writel_relaxed(vfe_pp_ds4_y_coeff[i][0], vfe->base + IFE_DSX_Y_VID_OUT_DMI_DATA_1);
+		writel_relaxed(vfe_pp_ds4_y_coeff[i][1], vfe->base + IFE_DSX_Y_VID_OUT_DMI_DATA);
+	}
+	writel_relaxed(0x00000002, vfe->base + IFE_DSX_Y_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_ds4_y_coeff); i++) {
+		writel_relaxed(vfe_pp_ds4_y_coeff[i][0], vfe->base + IFE_DSX_Y_VID_OUT_DMI_DATA_1);
+		writel_relaxed(vfe_pp_ds4_y_coeff[i][1], vfe->base + IFE_DSX_Y_VID_OUT_DMI_DATA);
+	}
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_Y_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_DSX_C_VID_OUT_MODULE_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_MODULE_LUT_BANK_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_MODE);
+	writel_relaxed(0x00030000, vfe->base + IFE_DSX_C_VID_OUT_START_LOCATION_X);
+	writel_relaxed(0x00030000, vfe->base + IFE_DSX_C_VID_OUT_START_LOCATION_Y);
+	writel_relaxed(0x00080000, vfe->base + IFE_DSX_C_VID_OUT_SCALE_RATIO_X);
+	writel_relaxed(0x00080000, vfe->base + IFE_DSX_C_VID_OUT_SCALE_RATIO_Y);
+	writel_relaxed(((h / 2) << 16) | (w / 2), vfe->base + IFE_DSX_C_VID_OUT_IN_SIZE);
+	writel_relaxed(((ds4_h / 2) << 16) | (ds4_w / 2), vfe->base + IFE_DSX_C_VID_OUT_OUT_SIZE);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_DMI_LUT_BANK_CFG);
+	writel_relaxed(0x00000001, vfe->base + IFE_DSX_C_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_ds4_c_coeff); i++) {
+		writel_relaxed(vfe_pp_ds4_c_coeff[i][0], vfe->base + IFE_DSX_C_VID_OUT_DMI_DATA_1);
+		writel_relaxed(vfe_pp_ds4_c_coeff[i][1], vfe->base + IFE_DSX_C_VID_OUT_DMI_DATA);
+	}
+	writel_relaxed(0x00000002, vfe->base + IFE_DSX_C_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_DMI_CFG);
+	for (i = 0; i < ARRAY_SIZE(vfe_pp_ds4_c_coeff); i++) {
+		writel_relaxed(vfe_pp_ds4_c_coeff[i][0], vfe->base + IFE_DSX_C_VID_OUT_DMI_DATA_1);
+		writel_relaxed(vfe_pp_ds4_c_coeff[i][1], vfe->base + IFE_DSX_C_VID_OUT_DMI_DATA);
+	}
+	writel_relaxed(0x00000000, vfe->base + IFE_DSX_C_VID_OUT_DMI_LUT_CFG);
+	writel_relaxed(0x0000fe01, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_MODULE_CFG);
+	writel_relaxed(ds4_h - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds4_w - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH1_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_Y_VID_OUT_CH2_CLAMP_MAX);
+	writel_relaxed(0x0000fe01, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_MODULE_CFG);
+	writel_relaxed(ds4_h / 2 - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds4_w / 2 - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH1_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DSX_C_VID_OUT_CH2_CLAMP_MAX);
+}
+
+/* DS16: 4:1 downscale of DS4 output, with crops */
+static void vfe_setup_ds16(struct vfe_device *vfe, u32 w, u32 h)
+{
+	const u32 ds4_w = ALIGN(w, 8) / 4;
+	const u32 ds4_h = ALIGN(h, 8) / 4;
+	const u32 ds16_w = (ds4_w / 4) & ~1u;
+	const u32 ds16_h = (ds4_h / 4) & ~1u;
+
+	writel_relaxed(0x00000f05, vfe->base + IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_MODULE_CFG);
+	writel_relaxed(0x09016c7d, vfe->base + IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_DS_COEFF);
+	writel_relaxed(ds4_h - 1, vfe->base + IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds4_w - 1, vfe->base + IFE_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x00000f05, vfe->base + IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_MODULE_CFG);
+	writel_relaxed(ds4_h / 2 - 1, vfe->base + IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds4_w / 2 - 1, vfe->base + IFE_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x0000fe01, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_MODULE_CFG);
+	writel_relaxed(ds16_h - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds16_w - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH1_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT_CH2_CLAMP_MAX);
+	writel_relaxed(0x0000fe01, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_MODULE_CFG);
+	writel_relaxed(ds16_h / 2 - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_LINE_CFG);
+	writel_relaxed(ds16_w / 2 - 1, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CROP_PIXEL_CFG);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH0_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH1_CLAMP_MIN);
+	writel_relaxed(0x00000000, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH2_CLAMP_MIN);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH0_CLAMP_MAX);
+	writel_relaxed(0x000003ff, vfe->base + IFE_CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT_CH1_CLAMP_MAX);
+	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 */
+void vfe_880_setup_pixel_pipe(struct vfe_device *vfe, u32 w, u32 h)
+{
+	vfe_setup_core_config(vfe);
+	vfe_setup_chroma_downscale_nv12(vfe, w, h);
+	vfe_setup_demosaic(vfe);
+	vfe_setup_color_correction(vfe);
+	vfe_setup_gamma_luts(vfe);
+	vfe_setup_color_transform(vfe);
+	vfe_setup_aec_bhist(vfe, w, h);
+	vfe_setup_main_output_round_clamp(vfe);
+	vfe_setup_ds4(vfe, w, h);
+	vfe_setup_ds16(vfe, w, h);
+
+	/* make the whole configuration visible before the IPP is resumed */
+	wmb();
+}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h
new file mode 100644
index 0000000000000..32f0a14e5b95a
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef QC_MSM_CAMSS_VFE_880_PP_H
+#define QC_MSM_CAMSS_VFE_880_PP_H
+
+#include <linux/types.h>
+
+struct vfe_device;
+
+void vfe_880_setup_pixel_pipe(struct vfe_device *vfe, u32 width, u32 height);
+
+#endif

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 53/74] media: qcom: camss: csid-gen3: Define the IPP reg update port in the header
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (51 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 52/74] media: qcom: camss: Add the SM8650 IFE pixel pipe configuration bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 54/74] media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock Bryan O'Donoghue
                   ` (21 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The VFE names the port it reg-updates through camss_reg_update(). Move
CSID_780_CUSTOM_PORT_ID_IPP0 from csid-gen3.c to camss-csid-gen3.h so the
pixel path can name the IPP.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid-gen3.c | 1 -
 drivers/media/platform/qcom/camss/camss-csid-gen3.h | 3 +++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
index f8406c1fa45a5..83f19ed0b31aa 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c
@@ -301,7 +301,6 @@ static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
 	return 0;
 }
 
-#define CSID_780_CUSTOM_PORT_ID_IPP0	0x100 /* TODO: bod don't like this too much */
 
 static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool clear)
 {
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.h b/drivers/media/platform/qcom/camss/camss-csid-gen3.h
index 6ee62da770c17..a82dfb16df5dd 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.h
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.h
@@ -22,4 +22,7 @@
 #define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
 #define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
 
+/* port_id passed to camss_reg_update() for the IPP, outside the RDI range */
+#define CSID_780_CUSTOM_PORT_ID_IPP0	0x100
+
 #endif /* __QC_MSM_CAMSS_CSID_GEN3_H__ */

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 54/74] media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (52 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 53/74] media: qcom: camss: csid-gen3: Define the IPP reg update port in the header bod
@ 2026-10-05 17:14 ` Bryan O'Donoghue
  2026-10-05 17:14 ` [PATCH 55/74] media: qcom: camss: vfe: Make is_pix the only test for the pixel path bod
                   ` (20 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: Bryan O'Donoghue @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

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@kernel.org>
---
 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


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 55/74] media: qcom: camss: vfe: Make is_pix the only test for the pixel path
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (53 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 54/74] media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock Bryan O'Donoghue
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 56/74] media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds bod
                   ` (19 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

camss-vfe.c decides whether a line is the pixel path by its index in
most places, comparing against VFE_LINE_PIX. On a VFE lite index 3 is
RDI3, so the lite's fourth RDI picks up the pixel path's selection API,
crop clamp, PIX formats, PIX bytes-per-line alignment, line-based mode
and clock computation.

Make line->is_pix the single test:

- a backend declares its pixel line by setting is_pix; a lite never does
- formats are chosen after the backend's subdev_init(), once is_pix is
  known
- every VFE_LINE_PIX comparison in camss-vfe.c becomes an is_pix test
- add VFE_LINE_RDI3 as the name of index 3 on a lite

vfe-780 already declares its pixel line. vfe-340 declares it here; it is
the only other backend whose tables still give a full VFE four lines.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-340.c |  1 +
 drivers/media/platform/qcom/camss/camss-vfe.c     | 36 +++++++++++++----------
 drivers/media/platform/qcom/camss/camss-vfe.h     |  3 +-
 3 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index e5a0a70eed1e6..708dad42186f9 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -356,6 +356,7 @@ static const struct camss_video_ops vfe_video_ops_520 = {
 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 {
 	vfe->video_ops = vfe_video_ops_520;
+	vfe->line[VFE_LINE_PIX].is_pix = true;
 }
 
 static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 82a23be7cae9c..0c7be87d7bd57 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1059,7 +1059,8 @@ void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
 	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)
-		if (vfe->wm_output_map[i] == VFE_LINE_PIX) {
+		if (vfe->wm_output_map[i] != VFE_LINE_NONE &&
+		    vfe->line[vfe->wm_output_map[i]].is_pix) {
 			vfe->isr_ops.wm_done(vfe, i);
 			break;
 		}
@@ -1167,7 +1168,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
 				u32 tmp;
 				u8 bpp;
 
-				if (j == VFE_LINE_PIX) {
+				if (vfe->line[j].is_pix) {
 					tmp = pixel_clock[j];
 				} else {
 					struct vfe_line *l = &vfe->line[j];
@@ -1248,7 +1249,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
 				u32 tmp;
 				u8 bpp;
 
-				if (j == VFE_LINE_PIX) {
+				if (vfe->line[j].is_pix) {
 					tmp = pixel_clock[j];
 				} else {
 					struct vfe_line *l = &vfe->line[j];
@@ -1566,7 +1567,7 @@ static void vfe_try_format(struct vfe_line *line,
 
 		fmt->code = vfe_src_pad_code(line, fmt->code, 0, code);
 
-		if (line->id == VFE_LINE_PIX) {
+		if (line->is_pix) {
 			struct v4l2_rect *rect;
 
 			rect = __vfe_get_crop(line, sd_state, which);
@@ -1844,7 +1845,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
 		vfe_try_format(line, sd_state, MSM_VFE_PAD_SRC, format,
 			       fmt->which);
 
-		if (line->id != VFE_LINE_PIX)
+		if (!line->is_pix)
 			return 0;
 
 		/* Reset sink pad compose selection */
@@ -1878,7 +1879,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
 	struct v4l2_rect *rect;
 	int ret;
 
-	if (line->id != VFE_LINE_PIX)
+	if (!line->is_pix)
 		return -EINVAL;
 
 	if (sel->pad == MSM_VFE_PAD_SINK)
@@ -1949,7 +1950,7 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
 	struct v4l2_rect *rect;
 	int ret;
 
-	if (line->id != VFE_LINE_PIX)
+	if (!line->is_pix)
 		return -EINVAL;
 
 	if (sel->target == V4L2_SEL_TGT_COMPOSE &&
@@ -2173,18 +2174,21 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 		init_completion(&l->output[0].sof);
 		init_completion(&l->output[0].reg_update);
 
-		if (i == VFE_LINE_PIX) {
-			l->nformats = res->vfe.formats_pix->nformats;
-			l->formats = res->vfe.formats_pix->formats;
-		} else {
-			l->nformats = res->vfe.formats_rdi->nformats;
-			l->formats = res->vfe.formats_rdi->formats;
-		}
 
 	}
 
 	vfe->res->hw_ops->subdev_init(dev, vfe);
 
+	/* Only now does a line know whether it is the pixel path */
+	for (i = 0; i < vfe->res->line_num; i++) {
+		struct vfe_line *l = &vfe->line[i];
+		const struct camss_formats *f = l->is_pix ? res->vfe.formats_pix :
+							    res->vfe.formats_rdi;
+
+		l->nformats = f->nformats;
+		l->formats = f->formats;
+	}
+
 	init_completion(&vfe->reset_complete);
 	init_completion(&vfe->halt_complete);
 
@@ -2331,7 +2335,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 		v4l2_subdev_init(sd, &vfe_v4l2_ops);
 		sd->internal_ops = &vfe_v4l2_internal_ops;
 		sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-		if (i == VFE_LINE_PIX && vfe->res->is_lite == false)
+		if (vfe->line[i].is_pix)
 			snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s",
 				 MSM_VFE_NAME, vfe->id, "pix");
 		else
@@ -2371,7 +2375,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 		}
 
 		video_out->ops = &vfe->video_ops;
-		if (i == VFE_LINE_PIX) {
+		if (vfe->line[i].is_pix) {
 			video_out->bpl_alignment = vfe_bpl_align_pix(vfe);
 			video_out->line_based = 1;
 		} else {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 318b025702007..2b354d6bcc1f5 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -59,7 +59,8 @@ enum vfe_line_id {
 	VFE_LINE_RDI0 = 0,
 	VFE_LINE_RDI1 = 1,
 	VFE_LINE_RDI2 = 2,
-	VFE_LINE_PIX = 3,
+	VFE_LINE_RDI3 = 3,	/* IFE lite */
+	VFE_LINE_PIX = 3,	/* full IFE, when line->is_pix */
 	VFE_LINE_NUM_MAX = 4
 };
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 56/74] media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (54 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 55/74] media: qcom: camss: vfe: Make is_pix the only test for the pixel path bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 57/74] media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line bod
                   ` (18 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The pixel and stats completion groups sit below the first RDI bit in
CSID_BUF_DONE_IRQ_STATUS. csid_isr() hands them to port 0, which only
holds for Valve's NV12-on-RDI, where the IPP output is written through
RDI0's line.

Record the source port csid_configure_stream() routed through the IPP
and complete the groups there. That is the PIX line when it is
streaming, and RDI0 on the NV12-on-RDI path as before.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 400995f35f0ef..b67cb1306acf2 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -161,6 +161,7 @@ struct csid_device {
 	u32 irq;
 	char irq_name[30];
 	u32 reg_update;
+	u8 ipp_port;	/* source port the IPP feeds: PIX, or RDI0 for NV12 compat */
 	struct camss_clock *clock;
 	int nclocks;
 	struct regulator_bulk_data *supplies;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 57/74] media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (55 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 56/74] media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 58/74] media: uapi: Add CAMSS ISP statistics definition bod
                   ` (17 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Stream NV12 from the PIX line, with the pixel pipe at its static
defaults:

- vfe_line_prepare() programs the pixel pipe for NV12 through
  vfe_880_setup_pixel_pipe(), outside output_lock and ahead of the write
  masters
- the PIX output's write masters, FULL Y and FULL C, are programmed per
  plane from the output descriptor: CbCr at half height and the same
  stride, frame based, no frame drop
- buffer addresses are written per plane, addr[1] being the CbCr plane
  camss-video derives for NV12
- the PIX line's reg update goes through the CSID IPP port
  (CSID_780_CUSTOM_PORT_ID_IPP0), and the RDIs through their own ports
  as before

RDI outputs take the one-write-master, plane-0 case of the same stop and
update loops.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 87 +++++++++++++++++++----
 1 file changed, 75 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index d70e829524fdf..1d00a3656d7c3 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -10,7 +10,9 @@
 #include <linux/iopoll.h>
 
 #include "camss.h"
+#include "camss-csid-gen3.h"
 #include "camss-vfe.h"
+#include "camss-vfe-880-pp.h"
 
 typedef enum {
 	VFE_WM_VIDEO_FULL_Y = 0,
@@ -67,6 +69,7 @@ typedef enum {
 #define VFE_BUS_WM_FRAME_INCR(n)	(BUS_REG_BASE + 0x208 + (n) * 0x100)
 #define VFE_BUS_WM_IMAGE_CFG_0(n)	(BUS_REG_BASE + 0x20c + (n) * 0x100)
 #define		WM_IMAGE_CFG_0_DEFAULT_WIDTH	(0xFFFF)
+#define VFE_BUS_WM_IMAGE_CFG_1(n)	(BUS_REG_BASE + 0x210 + (n) * 0x100)
 #define VFE_BUS_WM_IMAGE_CFG_2(n)	(BUS_REG_BASE + 0x214 + (n) * 0x100)
 #define		WM_IMAGE_CFG_2_DEFAULT_STRIDE	(0xFFFF)
 #define VFE_BUS_WM_PACKER_CFG(n)	(BUS_REG_BASE + 0x218 + (n) * 0x100)
@@ -79,6 +82,38 @@ typedef enum {
 #define VFE_BUS_WM_MMU_PREFETCH_CFG(n)		(BUS_REG_BASE + 0x260 + (n) * 0x100)
 #define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n)	(BUS_REG_BASE + 0x264 + (n) * 0x100)
 
+/* One write master per plane of the PIX output: Y, then CbCr at half height */
+static void vfe_wm_start_pix(struct vfe_device *vfe, struct vfe_line *line)
+{
+	struct vfe_output *output = &line->output[0];
+	struct v4l2_pix_format_mplane *pix = &output->video_out.active_fmt.fmt.pix_mp;
+	unsigned int i;
+
+	for (i = 0; i < output->wm_num; i++) {
+		u8 wm = output->wm[i].bus_client;
+		u8 plane = output->wm[i].plane;
+
+		writel((pix->height >> plane) << 16 | pix->width,
+		       vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
+		writel(0, vfe->base + VFE_BUS_WM_IMAGE_CFG_1(wm));
+		writel(pix->plane_fmt[0].bytesperline,
+		       vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
+		writel(0x3, vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
+
+		/* no dropped frames, one irq per frame */
+		writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
+		writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
+		writel(0, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(wm));
+		writel(1, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(wm));
+
+		writel(1, vfe->base + VFE_BUS_WM_MMU_PREFETCH_CFG(wm));
+		writel(0xFFFFFFFF, vfe->base + VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(wm));
+
+		/* frame based */
+		writel(WM_CFG_EN, vfe->base + VFE_BUS_WM_CFG(wm));
+	}
+}
+
 static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
 	struct v4l2_pix_format_mplane *pix =
@@ -91,6 +126,11 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 
 	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
 
+	if (line->is_pix) {
+		vfe_wm_start_pix(vfe, line);
+		return;
+	}
+
 	writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
 	       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
 
@@ -114,36 +154,58 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 
 static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
-	wm = line->output[0].wm[0].bus_client;
-	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
+	struct vfe_output *output = &line->output[0];
+	unsigned int i;
+
+	for (i = 0; i < output->wm_num; i++)
+		writel(0, vfe->base + VFE_BUS_WM_CFG(output->wm[i].bus_client));
 }
 
 static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
 			  struct vfe_line *line)
 {
-	u32 addr = buffer->addr[0];
+	struct vfe_output *output = &line->output[0];
+	unsigned int i;
 
-	wm = line->output[0].wm[0].bus_client;
+	/* camss-video sets addr[1] = addr[0] + bytesperline * height for NV12 */
+	for (i = 0; i < output->wm_num; i++) {
+		u32 addr = buffer->addr[output->wm[i].plane];
 
-	writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+		wm = output->wm[i].bus_client;
+		writel(addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 
-	dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n",
-		wm, addr);
+		dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n",
+			wm, addr);
+	}
 }
 
-static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+/* The PIX line is latched through the CSID's IPP path, RDIs through their own */
+static int vfe_reg_update_port(struct vfe_device *vfe, enum vfe_line_id line_id)
 {
-	int port_id = line_id;
+	return vfe->line[line_id].is_pix ? CSID_780_CUSTOM_PORT_ID_IPP0 : line_id;
+}
 
-	camss_reg_update(vfe->camss, vfe->id, port_id, false);
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	camss_reg_update(vfe->camss, vfe->id, vfe_reg_update_port(vfe, line_id), false);
 }
 
 static inline void vfe_reg_update_clear(struct vfe_device *vfe,
 					enum vfe_line_id line_id)
 {
-	int port_id = line_id;
+	camss_reg_update(vfe->camss, vfe->id, vfe_reg_update_port(vfe, line_id), true);
+}
+
+/*
+ * Program the pixel pipe outside output_lock, before the write masters and
+ * the IPP reg update that latches both.
+ */
+static void vfe_line_prepare(struct vfe_line *line)
+{
+	struct v4l2_pix_format_mplane *pix = &line->output[0].video_out.active_fmt.fmt.pix_mp;
 
-	camss_reg_update(vfe->camss, vfe->id, port_id, true);
+	if (line->is_pix && pix->pixelformat == V4L2_PIX_FMT_NV12)
+		vfe_880_setup_pixel_pipe(to_vfe(line), pix->width, pix->height);
 }
 
 static const struct camss_video_ops vfe_video_ops_780 = {
@@ -209,6 +271,7 @@ const struct vfe_hw_ops vfe_ops_780 = {
 	.subdev_init = vfe_subdev_init,
 	.vfe_disable = vfe_disable,
 	.vfe_enable = vfe_enable_v2,
+	.vfe_line_prepare = vfe_line_prepare,
 	.vfe_halt = vfe_halt,
 	.vfe_wm_start = vfe_wm_start,
 	.vfe_wm_stop = vfe_wm_stop,

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 58/74] media: uapi: Add CAMSS ISP statistics definition
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (56 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 57/74] media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 59/74] media: Documentation: uapi: Add qcom-camss ISP statistics bod
                   ` (16 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Add V4L2_META_FMT_QCOM_ISP_STATS, the statistics counterpart of the CAMSS
ISP parameters. Statistics use the v4l2-isp extensible format: the driver
serialises one block per statistics engine into a struct v4l2_isp_buffer,
each block embedding a struct v4l2_isp_block_header with a type from
enum camss_stats_block_type.

The first block is the AEC Bayer histogram, CAMSS_STATS_AEC_BHIST:
1024 bins counting the luma of each 2x2 Bayer quad in the histogram's
region.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/v4l2-core/v4l2-ioctl.c   |  1 +
 include/uapi/linux/qcom-camss-config.h | 33 +++++++++++++++++++++++++++++++++
 include/uapi/linux/videodev2.h         |  3 +++
 3 files changed, 37 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index a2b650f4ec3c3..e5eccb62e76b2 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1471,6 +1471,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 	case V4L2_META_FMT_C3ISP_STATS:		descr = "Amlogic C3 ISP Statistics"; break;
 	case V4L2_META_FMT_MALI_C55_PARAMS:	descr = "ARM Mali-C55 ISP Parameters"; break;
 	case V4L2_META_FMT_MALI_C55_STATS:	descr = "ARM Mali-C55 ISP 3A Statistics"; break;
+	case V4L2_META_FMT_QCOM_ISP_STATS:	descr = "Qualcomm CAMSS ISP Statistics"; break;
 	case V4L2_PIX_FMT_NV12_8L128:	descr = "NV12 (8x128 Linear)"; break;
 	case V4L2_PIX_FMT_NV12M_8L128:	descr = "NV12M (8x128 Linear)"; break;
 	case V4L2_PIX_FMT_NV12_10BE_8L128:	descr = "10-bit NV12 (8x128 Linear, BE)"; break;
diff --git a/include/uapi/linux/qcom-camss-config.h b/include/uapi/linux/qcom-camss-config.h
index aa3d97cfcc78e..23c12b8955ef6 100644
--- a/include/uapi/linux/qcom-camss-config.h
+++ b/include/uapi/linux/qcom-camss-config.h
@@ -209,4 +209,37 @@ struct camss_params_gamma {
 	 sizeof(struct camss_params_color_correct)	+\
 	 sizeof(struct camss_params_gamma))
 
+/**
+ * enum camss_stats_block_type - CAMSS ISP statistics block identifiers
+ *
+ * Each value identifies one statistics block in a
+ * V4L2_META_FMT_QCOM_ISP_STATS buffer. The value is placed in the @type field
+ * of &struct v4l2_isp_block_header.
+ *
+ * @CAMSS_STATS_AEC_BHIST: AEC Bayer histogram, &struct camss_stats_bhist
+ */
+enum camss_stats_block_type {
+	CAMSS_STATS_AEC_BHIST = 1,
+};
+
+/* Number of bins in a Bayer histogram. */
+#define CAMSS_STATS_BHIST_BINS	1024
+
+/**
+ * struct camss_stats_bhist - Bayer histogram
+ *
+ * Histogram of the luma of each 2x2 Bayer quad inside the histogram's region,
+ * over CAMSS_STATS_BHIST_BINS equal bins spanning its input range. Quads
+ * whose luma falls outside the input range are not counted.
+ *
+ * @header: block header; @header.type = CAMSS_STATS_AEC_BHIST
+ * @bins:   number of quads per bin
+ */
+struct camss_stats_bhist {
+	struct v4l2_isp_block_header header;
+	__u32 bins[CAMSS_STATS_BHIST_BINS];
+} __attribute__((aligned(8)));
+
+#define CAMSS_STATS_MAX_PAYLOAD		sizeof(struct camss_stats_bhist)
+
 #endif /* _UAPI_LINUX_QCOM_CAMSS_CONFIG_H */
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index eda4492e40dc1..700ea9b646979 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -889,6 +889,9 @@ struct v4l2_pix_format {
 #define V4L2_META_FMT_MALI_C55_PARAMS	v4l2_fourcc('C', '5', '5', 'P') /* ARM Mali-C55 Parameters */
 #define V4L2_META_FMT_MALI_C55_STATS	v4l2_fourcc('C', '5', '5', 'S') /* ARM Mali-C55 3A Statistics */
 
+/* Vendor specific - used for Qualcomm CAMSS ISP */
+#define V4L2_META_FMT_QCOM_ISP_STATS	v4l2_fourcc('Q', 'C', 'I', 'S') /* Qualcomm CAMSS ISP Statistics */
+
 #ifdef __KERNEL__
 /*
  * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 59/74] media: Documentation: uapi: Add qcom-camss ISP statistics
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (57 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 58/74] media: uapi: Add CAMSS ISP statistics definition bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 60/74] media: qcom: camss: vfe: Select line-based mode for the pixel path's video node bod
                   ` (15 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Document V4L2_META_FMT_QCOM_ISP_STATS: the v4l2-isp extensible statistics
container, the block types, and the AEC Bayer histogram produced by the
SM8650 IFE pixel path, with an example of walking the blocks.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 .../userspace-api/media/v4l/metafmt-qcom-isp.rst   | 50 ++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
index 2f3654a9ba897..77372b3a32d7d 100644
--- a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
+++ b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
@@ -141,6 +141,56 @@ and a gamma correction block:
 	for (unsigned int i = 0; i < CAMSS_GAMMA_LUT_SIZE; i++)
 		gamma->glut[i] = gamma->blut[i] = gamma->rlut[i] = i;
 
+.. _v4l2-meta-fmt-qcom-isp-stats:
+
+*************************************
+V4L2_META_FMT_QCOM_ISP_STATS ('QCIS')
+*************************************
+
+Statistics
+==========
+
+The ``V4L2_META_FMT_QCOM_ISP_STATS`` format carries the statistics an ISP
+engine of the Qualcomm Camera Subsystem (CAMSS) gathers from a frame. It is
+captured from a metadata capture video node using the
+:c:type:`v4l2_meta_format` interface.
+
+Statistics use the :ref:`v4l2-isp` extensible format. The driver serialises one
+block per statistics engine into the data member of :c:type:`v4l2_isp_buffer`.
+Each block embeds :c:type:`v4l2_isp_block_header` as its first member, with the
+type member set to a value from :c:type:`camss_stats_block_type`. Blocks are
+placed consecutively, and their combined size is reported in the data_size
+member of :c:type:`v4l2_isp_buffer`.
+
+Which blocks a buffer holds depends on the engine producing it and on the
+statistics enabled for the stream. Their order is not defined: userspace walks
+the blocks by the size member of each header and skips types it does not know.
+
+The SM8650 IFE pixel path produces the AEC Bayer histogram,
+:c:type:`camss_stats_bhist`, on its ``msm_vfeN_stats`` metadata capture node.
+
+The following example reads the AEC Bayer histogram from a statistics buffer:
+
+.. code-block:: c
+
+	const struct v4l2_isp_buffer *stats =
+		(const struct v4l2_isp_buffer *)buffer;
+	size_t offset = 0;
+
+	while (offset < stats->data_size) {
+		const struct v4l2_isp_block_header *header =
+			(const struct v4l2_isp_block_header *)&stats->data[offset];
+
+		if (header->type == CAMSS_STATS_AEC_BHIST) {
+			const struct camss_stats_bhist *bhist =
+				(const struct camss_stats_bhist *)header;
+
+			use_histogram(bhist->bins, CAMSS_STATS_BHIST_BINS);
+		}
+
+		offset += header->size;
+	}
+
 Qualcomm CAMSS ISP uAPI data types
 ==================================
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 60/74] media: qcom: camss: vfe: Select line-based mode for the pixel path's video node
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (58 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 59/74] media: Documentation: uapi: Add qcom-camss ISP statistics bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 61/74] media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock bod
                   ` (14 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The pixel path's video node is always marked line based. A line-based
node caps its buffer at CAMSS_FRAME_MAX_HEIGHT_PIX lines of bytesperline,
counting every plane's lines together. That fits the VFE 4.x and TFE
pixel outputs, but not the SM8650 IFE, which writes luma and chroma
through separate write masters, each programmed with its own height.
There, single-buffer NV12 at 4080x3072 needs 4608 lines: the buffer is
cut to 4096 lines and the CbCr write runs off its end.

Add vfe_pix_line_based(), alongside vfe_bpl_align_pix(). Every existing
pixel path stays line based. SM8650 is not.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 0c7be87d7bd57..bf8ae6a6bfae0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -2285,6 +2285,27 @@ static int vfe_bpl_align_rdi(struct vfe_device *vfe)
 	return ret;
 }
 
+/*
+ * vfe_pix_line_based - Select line-based mode for the pixel path's video node
+ * @vfe: VFE device
+ *
+ * A line-based video node caps its buffer at CAMSS_FRAME_MAX_HEIGHT_PIX lines,
+ * counting every plane's lines together. That fits the VFE 4.x and TFE pixel
+ * outputs. The SM8650 IFE writes luma and chroma through separate write
+ * masters, each programmed with its own height, so the cap does not apply.
+ *
+ * Return true if the pixel path's video node is line based
+ */
+static bool vfe_pix_line_based(struct vfe_device *vfe)
+{
+	switch (vfe->camss->res->version) {
+	case CAMSS_8650:
+		return false;
+	default:
+		return true;
+	}
+}
+
 static int vfe_bpl_align_pix(struct vfe_device *vfe)
 {
 	int ret = 16;
@@ -2377,7 +2398,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 		video_out->ops = &vfe->video_ops;
 		if (vfe->line[i].is_pix) {
 			video_out->bpl_alignment = vfe_bpl_align_pix(vfe);
-			video_out->line_based = 1;
+			video_out->line_based = vfe_pix_line_based(vfe);
 		} else {
 			video_out->bpl_alignment = vfe_bpl_align_rdi(vfe);
 			video_out->line_based = 0;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 61/74] media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (59 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 60/74] media: qcom: camss: vfe: Select line-based mode for the pixel path's video node bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 62/74] media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one bod
                   ` (13 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

vfe_check_clock_rates() and vfe_set_clock_rates() size the VFE clock for
a pixel line at one pixel per clock. That holds for the VFE 4.x and TFE
pixel paths, but the SM8650 IFE pixel path takes two pixels per clock.
There the PIX line asks for more than the highest VFE clock level and
fails to power up with "Pixel clock is too high for VFE".

Add vfe_pix_ppc(), alongside vfe_bpl_align_pix(), and divide the pixel
rate by it. Every existing pixel path stays at one pixel per clock.
SM8650 takes two.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index bf8ae6a6bfae0..588a355b67ff0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1137,6 +1137,23 @@ static bool vfe_check_clock_levels(struct camss_clock *clock)
 	return false;
 }
 
+/*
+ * vfe_pix_ppc - Pixels the pixel path consumes per VFE clock
+ * @vfe: VFE device
+ *
+ * The VFE 4.x and TFE pixel paths take one pixel per clock, the SM8650 IFE
+ * pixel path two.
+ */
+static u32 vfe_pix_ppc(struct vfe_device *vfe)
+{
+	switch (vfe->camss->res->version) {
+	case CAMSS_8650:
+		return 2;
+	default:
+		return 1;
+	}
+}
+
 /*
  * vfe_set_clock_rates - Calculate and set clock rates on VFE module
  * @vfe: VFE device
@@ -1169,7 +1186,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
 				u8 bpp;
 
 				if (vfe->line[j].is_pix) {
-					tmp = pixel_clock[j];
+					tmp = div_u64(pixel_clock[j], vfe_pix_ppc(vfe));
 				} else {
 					struct vfe_line *l = &vfe->line[j];
 
@@ -1250,7 +1267,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
 				u8 bpp;
 
 				if (vfe->line[j].is_pix) {
-					tmp = pixel_clock[j];
+					tmp = div_u64(pixel_clock[j], vfe_pix_ppc(vfe));
 				} else {
 					struct vfe_line *l = &vfe->line[j];
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 62/74] media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (60 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 61/74] media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 63/74] media: qcom: camss: video: Support metadata capture nodes bod
                   ` (12 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

The PIX line is described with five outputs, one per source or sink pad
beyond the sink, but struct vfe_line holds MSM_VFE_NUM_OUTPUTS = 1. The
descriptor writes and the enable loop for outputs 1-4 land past the end
of the line.

- size output[] for every pad but the sink
- record the pad each output serves, as vfe_add_output() was passed it
- initialise every output: back pointer, completions, pending list
- start secondary outputs only while their video node streams and they
  have write masters; the first output still starts the line
- stop and release every output that ran

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 70 +++++++++++++++++++--------
 drivers/media/platform/qcom/camss/camss-vfe.h |  3 +-
 2 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 588a355b67ff0..8bcacede0f969 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -679,6 +679,18 @@ void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *bu
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 }
 
+/*
+ * The first output starts the line. The others run only while their video
+ * node is streaming, and only if they write to memory.
+ */
+static bool vfe_output_wanted(struct vfe_line *line, struct vfe_output *output)
+{
+	if (output == &line->output[0])
+		return true;
+
+	return output->wm_num && vb2_is_streaming(&output->video_out.vb2_q);
+}
+
 static int vfe_enable_one_output(struct vfe_line *line, struct vfe_output *output)
 {
 	struct vfe_device *vfe = to_vfe(line);
@@ -747,6 +759,9 @@ int vfe_enable_output_v2(struct vfe_line *line)
 	ops->reg_update_clear(vfe, line->id);
 
 	for (i = 0; i < line->num_outputs; i++) {
+		if (!vfe_output_wanted(line, &line->output[i]))
+			continue;
+
 		ret = vfe_enable_one_output(line, &line->output[i]);
 		if (ret)
 			break;
@@ -900,15 +915,17 @@ int vfe_reset(struct vfe_device *vfe)
 
 static void vfe_init_outputs(struct vfe_device *vfe)
 {
-	int i;
+	int i, o;
 
 	for (i = 0; i < vfe->res->line_num; i++) {
-		struct vfe_output *output = &vfe->line[i].output[0];
+		for (o = 0; o < MSM_VFE_NUM_OUTPUTS; o++) {
+			struct vfe_output *output = &vfe->line[i].output[o];
 
-		output->state = VFE_OUTPUT_OFF;
-		output->buf[0] = NULL;
-		output->buf[1] = NULL;
-		INIT_LIST_HEAD(&output->pending_bufs);
+			output->state = VFE_OUTPUT_OFF;
+			output->buf[0] = NULL;
+			output->buf[1] = NULL;
+			INIT_LIST_HEAD(&output->pending_bufs);
+		}
 	}
 }
 
@@ -996,7 +1013,8 @@ int vfe_put_output(struct vfe_line *line)
 	for (i = 0; i < output->wm_num; i++)
 		vfe_release_wm(vfe, output->wm[i].bus_client);
 
-	output->state = VFE_OUTPUT_OFF;
+	for (i = 0; i < line->num_outputs; i++)
+		line->output[i].state = VFE_OUTPUT_OFF;
 
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 	return 0;
@@ -1006,17 +1024,24 @@ static int vfe_disable_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
-	struct vfe_output *output = &line->output[0];
 	unsigned long flags;
-	unsigned int i;
+	unsigned int i, o;
 
 	spin_lock_irqsave(&vfe->output_lock, flags);
-	if (ops->vfe_output_stop)
-		ops->vfe_output_stop(vfe, output);
-	else
-		for (i = 0; i < output->wm_num; i++)
-			ops->vfe_wm_stop(vfe, output->wm[i].bus_client, line);
-	output->gen2.active_num = 0;
+	for (o = 0; o < line->num_outputs; o++) {
+		struct vfe_output *output = &line->output[o];
+
+		/* the first output is always on; the others only if they streamed */
+		if (o && output->state != VFE_OUTPUT_ON)
+			continue;
+
+		if (ops->vfe_output_stop)
+			ops->vfe_output_stop(vfe, output);
+		else
+			for (i = 0; i < output->wm_num; i++)
+				ops->vfe_wm_stop(vfe, output->wm[i].bus_client, line);
+		output->gen2.active_num = 0;
+	}
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
 
 	return vfe_reset(vfe);
@@ -2175,22 +2200,26 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 
 	for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
 		struct vfe_line *l = &vfe->line[i];
+		unsigned int o;
+
+		for (o = 0; o < MSM_VFE_NUM_OUTPUTS; o++) {
+			l->output[o].line = l;
+			l->output[o].video_out.camss = camss;
+			init_completion(&l->output[o].sof);
+			init_completion(&l->output[o].reg_update);
+		}
 
 		l->output[0].video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-		l->output[0].video_out.camss = camss;
 		l->id = i;
 
 		l->num_outputs = 1;
-		l->output[0].line = l;
+		l->output[0].pad = MSM_VFE_PAD_SRC;
 
 		l->output[0].wm_num = 1;
 		l->output[0].wm[0].bus_client = l->id;
 
 		l->num_pads = MSM_VFE_PAD_NUM_RDI;
 
-		init_completion(&l->output[0].sof);
-		init_completion(&l->output[0].reg_update);
-
 
 	}
 
@@ -2500,6 +2529,7 @@ void vfe_add_output(struct vfe_output *output, u8 pad, u8 comp_group,
 {
 	unsigned int i;
 
+	output->pad = pad;
 	output->comp_group = comp_group;
 	output->wm_num = wm_num;
 	for (i = 0; i < wm_num; i++) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 2b354d6bcc1f5..11cded2b345eb 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -28,7 +28,7 @@
 #define MSM_VFE_PAD_NUM_RDI 2
 #define MSM_VFE_PAD_NUM_PIX 6
 #define MSM_VFE_MAX_PADS MSM_VFE_PAD_NUM_PIX
-#define MSM_VFE_NUM_OUTPUTS 1
+#define MSM_VFE_NUM_OUTPUTS (MSM_VFE_MAX_PADS - 1)	/* every pad but the sink */
 
 #define MSM_VFE_IMAGE_MASTERS_NUM 7
 #define MSM_VFE_COMPOSITE_IRQ_NUM 4
@@ -114,6 +114,7 @@ struct vfe_wm {
 #define VFE_MAX_WM_PER_OUTPUT 3
 
 struct vfe_output {
+	u8 pad;			/* index into line->pads[] this output serves */
 	u8 comp_group;
 	u8 wm_num;
 	struct vfe_wm wm[VFE_MAX_WM_PER_OUTPUT];

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 63/74] media: qcom: camss: video: Support metadata capture nodes
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (61 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 62/74] media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 64/74] media: qcom: camss: vfe: Register a statistics node for the pixel line bod
                   ` (11 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

A video node is always a VIDEO_CAPTURE_MPLANE node. Statistics need
metadata capture nodes.

Register a node of video->type V4L2_BUF_TYPE_META_CAPTURE with its own
queue and ioctl operations:

- one plane of the fixed buffersize the producer sets with dataformat
  before registration; G, S and TRY_FMT all return that format
- buffers are vmalloc backed: the kernel fills them by CPU
- the node follows the image node of its line: starting it provides
  buffers and stopping it returns them, but neither starts nor stops the
  line

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/Kconfig       |   1 +
 drivers/media/platform/qcom/camss/camss-video.c | 146 ++++++++++++++++++++++--
 2 files changed, 136 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/Kconfig b/drivers/media/platform/qcom/camss/Kconfig
index 4eda48cb1adf0..42c3ee13e548b 100644
--- a/drivers/media/platform/qcom/camss/Kconfig
+++ b/drivers/media/platform/qcom/camss/Kconfig
@@ -6,4 +6,5 @@ config VIDEO_QCOM_CAMSS
 	select MEDIA_CONTROLLER
 	select VIDEO_V4L2_SUBDEV_API
 	select VIDEOBUF2_DMA_SG
+	select VIDEOBUF2_VMALLOC
 	select V4L2_FWNODE
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 0852eb6f13154..b8501c895d393 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -14,6 +14,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mc.h>
 #include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-vmalloc.h>
 
 #include "camss-video.h"
 #include "camss.h"
@@ -351,6 +352,68 @@ static const struct vb2_ops msm_video_vb2_q_ops = {
 	.unprepare_streaming = video_unprepare_streaming,
 };
 
+/* -----------------------------------------------------------------------------
+ * Metadata capture queue operations
+ *
+ * A metadata capture node follows the image node of its line: the line starts
+ * and stops with the image node, and the node only provides buffers. The
+ * kernel fills them by CPU, so they are vmalloc backed.
+ */
+
+static int video_meta_queue_setup(struct vb2_queue *q,
+				  unsigned int *num_buffers,
+				  unsigned int *num_planes, unsigned int sizes[],
+				  struct device *alloc_devs[])
+{
+	struct camss_video *video = vb2_get_drv_priv(q);
+	unsigned int size = video->active_fmt.fmt.meta.buffersize;
+
+	if (*num_planes)
+		return (*num_planes != 1 || sizes[0] < size) ? -EINVAL : 0;
+
+	*num_planes = 1;
+	sizes[0] = size;
+
+	return 0;
+}
+
+static int video_meta_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned int size = video->active_fmt.fmt.meta.buffersize;
+
+	if (vb2_plane_size(vb, 0) < size)
+		return -EINVAL;
+
+	vb2_set_plane_payload(vb, 0, size);
+	vbuf->field = V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+static int video_meta_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	return 0;
+}
+
+static void video_meta_stop_streaming(struct vb2_queue *q)
+{
+	struct camss_video *video = vb2_get_drv_priv(q);
+
+	video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops msm_video_meta_vb2_q_ops = {
+	.queue_setup     = video_meta_queue_setup,
+	.buf_prepare     = video_meta_buf_prepare,
+	.buf_queue       = video_buf_queue,
+	.prepare_streaming = video_prepare_streaming,
+	.start_streaming = video_meta_start_streaming,
+	.stop_streaming  = video_meta_stop_streaming,
+	.unprepare_streaming = video_unprepare_streaming,
+};
+
 /* -----------------------------------------------------------------------------
  * V4L2 ioctls
  */
@@ -613,6 +676,51 @@ static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
 	.vidioc_s_input			= video_s_input,
 };
 
+static int video_meta_enum_fmt(struct file *file, void *fh,
+			       struct v4l2_fmtdesc *f)
+{
+	struct camss_video *video = video_drvdata(file);
+
+	if (f->index || f->type != video->type)
+		return -EINVAL;
+
+	f->pixelformat = video->active_fmt.fmt.meta.dataformat;
+
+	return 0;
+}
+
+/* The metadata format is fixed: G, S and TRY all return it */
+static int video_meta_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct camss_video *video = video_drvdata(file);
+
+	if (f->type != video->type)
+		return -EINVAL;
+
+	memset(&f->fmt.meta, 0, sizeof(f->fmt.meta));
+	f->fmt.meta.dataformat = video->active_fmt.fmt.meta.dataformat;
+	f->fmt.meta.buffersize = video->active_fmt.fmt.meta.buffersize;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops msm_vid_meta_ioctl_ops = {
+	.vidioc_querycap		= video_querycap,
+	.vidioc_enum_fmt_meta_cap	= video_meta_enum_fmt,
+	.vidioc_g_fmt_meta_cap		= video_meta_g_fmt,
+	.vidioc_s_fmt_meta_cap		= video_meta_g_fmt,
+	.vidioc_try_fmt_meta_cap	= video_meta_g_fmt,
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_expbuf			= vb2_ioctl_expbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+};
+
 /* -----------------------------------------------------------------------------
  * V4L2 file operations
  */
@@ -688,6 +796,7 @@ static int msm_video_init_format(struct camss_video *video)
 int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 		       const char *name)
 {
+	bool meta = video->type == V4L2_BUF_TYPE_META_CAPTURE;
 	struct media_pad *pad = &video->pad;
 	struct video_device *vdev;
 	struct vb2_queue *q;
@@ -699,10 +808,12 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 
 	q = &video->vb2_q;
 	q->drv_priv = video;
-	q->mem_ops = &vb2_dma_sg_memops;
-	q->ops = &msm_video_vb2_q_ops;
-	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
+	q->mem_ops = meta ? &vb2_vmalloc_memops : &vb2_dma_sg_memops;
+	q->ops = meta ? &msm_video_meta_vb2_q_ops : &msm_video_vb2_q_ops;
+	q->type = meta ? V4L2_BUF_TYPE_META_CAPTURE :
+			 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = meta ? VB2_DMABUF | VB2_MMAP :
+			     VB2_DMABUF | VB2_MMAP | VB2_READ;
 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 	q->buf_struct_size = sizeof(struct camss_buffer);
 	q->dev = video->camss->dev;
@@ -723,16 +834,29 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 
 	mutex_init(&video->lock);
 
-	ret = msm_video_init_format(video);
-	if (ret < 0) {
-		dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret);
-		goto error_video_register;
+	if (meta) {
+		/* dataformat and buffersize are set by the producer */
+		video->active_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
+	} else {
+		ret = msm_video_init_format(video);
+		if (ret < 0) {
+			dev_err(v4l2_dev->dev, "Failed to init format: %d\n",
+				ret);
+			goto error_video_register;
+		}
 	}
 
 	vdev->fops = &msm_vid_fops;
-	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING
-			  | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC;
-	vdev->ioctl_ops = &msm_vid_ioctl_ops;
+	if (meta) {
+		vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING |
+				    V4L2_CAP_IO_MC;
+		vdev->ioctl_ops = &msm_vid_meta_ioctl_ops;
+	} else {
+		vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+				    V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+				    V4L2_CAP_IO_MC;
+		vdev->ioctl_ops = &msm_vid_ioctl_ops;
+	}
 	vdev->release = msm_video_release;
 	vdev->v4l2_dev = v4l2_dev;
 	vdev->vfl_dir = VFL_DIR_RX;

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 64/74] media: qcom: camss: vfe: Register a statistics node for the pixel line
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (62 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 63/74] media: qcom: camss: video: Support metadata capture nodes bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 65/74] media: qcom: camss: vfe: Complete pixel line outputs on their own completion group bod
                   ` (10 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

A line whose descriptor declares a statistics output gets a metadata
capture node, msm_vfeN_stats, linked immutably from its statistics pad.
The node carries V4L2_META_FMT_QCOM_ISP_STATS, sized for every
statistics block the format defines.

Select V4L2_ISP for the statistics buffer helpers.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/Kconfig     |  1 +
 drivers/media/platform/qcom/camss/camss-vfe.c | 76 +++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/Kconfig b/drivers/media/platform/qcom/camss/Kconfig
index 42c3ee13e548b..4f1c1000a501e 100644
--- a/drivers/media/platform/qcom/camss/Kconfig
+++ b/drivers/media/platform/qcom/camss/Kconfig
@@ -8,3 +8,4 @@ config VIDEO_QCOM_CAMSS
 	select VIDEOBUF2_DMA_SG
 	select VIDEOBUF2_VMALLOC
 	select V4L2_FWNODE
+	select V4L2_ISP
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 8bcacede0f969..12d94bdf13bc8 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -20,7 +20,9 @@
 #include <linux/spinlock.h>
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-isp.h>
 #include <media/v4l2-subdev.h>
+#include <linux/qcom-camss-config.h>
 
 #include "camss-vfe.h"
 #include "camss.h"
@@ -2370,6 +2372,74 @@ static int vfe_bpl_align_pix(struct vfe_device *vfe)
 	return ret;
 }
 
+/*
+ * vfe_register_stats_node - Register the statistics node of a pixel line
+ * @vfe: VFE device
+ * @line: VFE line
+ * @v4l2_dev: V4L2 device
+ *
+ * A line whose descriptor declares a statistics output gets a metadata
+ * capture node, msm_vfeN_stats, linked from its statistics pad.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_register_stats_node(struct vfe_device *vfe,
+				   struct vfe_line *line,
+				   struct v4l2_device *v4l2_dev)
+{
+	struct device *dev = vfe->camss->dev;
+	unsigned int o;
+	int ret;
+
+	for (o = 1; o < line->num_outputs; o++) {
+		struct vfe_output *output = &line->output[o];
+		struct camss_video *video = &output->video_out;
+		char name[32];
+
+		if (output->pad != MSM_VFE_PAD_SRC_STATS || !output->wm_num)
+			continue;
+
+		video->type = V4L2_BUF_TYPE_META_CAPTURE;
+		video->active_fmt.fmt.meta.dataformat =
+			V4L2_META_FMT_QCOM_ISP_STATS;
+		video->active_fmt.fmt.meta.buffersize =
+			v4l2_isp_buffer_size(CAMSS_STATS_MAX_PAYLOAD);
+		video->ops = &vfe->video_ops;
+
+		snprintf(name, ARRAY_SIZE(name), "%s%d_%s",
+			 MSM_VFE_NAME, vfe->id, "stats");
+		ret = msm_video_register(video, v4l2_dev, name);
+		if (ret < 0) {
+			dev_err(dev, "Failed to register stats node: %d\n", ret);
+			return ret;
+		}
+
+		ret = media_create_pad_link(&line->subdev.entity, output->pad,
+					    &video->vdev.entity, 0,
+					    MEDIA_LNK_FL_IMMUTABLE |
+					    MEDIA_LNK_FL_ENABLED);
+		if (ret < 0) {
+			dev_err(dev, "Failed to link stats node: %d\n", ret);
+			msm_video_unregister(video);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void vfe_unregister_stats_node(struct vfe_line *line)
+{
+	unsigned int o;
+
+	for (o = 1; o < line->num_outputs; o++) {
+		struct camss_video *video = &line->output[o].video_out;
+
+		if (video_is_registered(&video->vdev))
+			msm_video_unregister(video);
+	}
+}
+
 /*
  * msm_vfe_register_entities - Register subdev node for VFE module
  * @vfe: VFE device
@@ -2472,6 +2542,10 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 				ret);
 			goto error_link;
 		}
+
+		ret = vfe_register_stats_node(vfe, &vfe->line[i], v4l2_dev);
+		if (ret < 0)
+			goto error_link;
 	}
 
 	return 0;
@@ -2490,6 +2564,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 		sd = &vfe->line[i].subdev;
 		video_out = &vfe->line[i].output[0].video_out;
 
+		vfe_unregister_stats_node(&vfe->line[i]);
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
 		media_entity_cleanup(&sd->entity);
@@ -2513,6 +2588,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
 		struct v4l2_subdev *sd = &vfe->line[i].subdev;
 		struct camss_video *video_out = &vfe->line[i].output[0].video_out;
 
+		vfe_unregister_stats_node(&vfe->line[i]);
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
 		media_entity_cleanup(&sd->entity);

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 65/74] media: qcom: camss: vfe: Complete pixel line outputs on their own completion group
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (63 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 64/74] media: qcom: camss: vfe: Register a statistics node for the pixel line bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 66/74] media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics bod
                   ` (9 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

vfe_buf_done() always completes the first output of the line. The
outputs of a pixel line complete on their own completion groups: the
image on one, statistics on another. Completing the image on any group
retires it early once a second output runs.

Split the per-output retirement into vfe_output_done() and, when the
completion carries per-group status, retire each running output whose
group fired. RDI lines, and completions without per-group status such as
the TFE's, keep completing the first output.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 89 +++++++++++++++++++++------
 1 file changed, 69 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 12d94bdf13bc8..b90b538c1aaaf 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -623,30 +623,35 @@ u32 vfe_hw_version(struct vfe_device *vfe)
  * @vfe: VFE Device
  * @wm: Write master id
  */
-void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *buf_done_info)
+/*
+ * vfe_output_done - Retire the filled buffer of one output
+ * @vfe: VFE device
+ * @line: VFE line
+ * @output: VFE output whose write masters completed a frame
+ * @ts: completion timestamp
+ *
+ * Called with output_lock held. Hands the next pending buffer to the write
+ * masters.
+ *
+ * Return the filled buffer for the caller to complete once the lock is
+ * dropped, or NULL if none was queued
+ */
+static struct camss_buffer *vfe_output_done(struct vfe_device *vfe,
+					    struct vfe_line *line,
+					    struct vfe_output *output, u64 ts)
 {
-	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
 	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
 	struct camss_buffer *ready_buf;
-	struct vfe_output *output;
-	unsigned long flags;
 	u32 index;
-	u64 ts = ktime_get_ns();
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Received wm done for unmapped index\n");
-		goto out_unlock;
-	}
-	output = &vfe->line[vfe->wm_output_map[wm]].output[0];
 
 	ready_buf = output->buf[0];
 	if (!ready_buf) {
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Missing ready buf %d!\n", output->state);
-		goto out_unlock;
+		/* only the first output must keep up; the others may starve */
+		if (output == &line->output[0])
+			dev_err_ratelimited(vfe->camss->dev,
+					    "Missing ready buf %d!\n",
+					    output->state);
+		return NULL;
 	}
 
 	ready_buf->vb.vb2_buf.timestamp = ts;
@@ -671,14 +676,58 @@ void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *bu
 		output->gen2.active_num--;
 	}
 
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
+	return ready_buf;
+}
 
-	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+/*
+ * vfe_buf_done - Complete the outputs whose completion groups fired
+ * @vfe: VFE device
+ * @wm: port the completion arrived on
+ * @buf_done_info: completion status, one bit per completion group
+ *
+ * An RDI line has one output. The outputs of a pixel line each complete on
+ * their own group, the image on one and statistics on another, when the
+ * completion carries per-group status.
+ */
+void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *buf_done_info)
+{
+	struct camss_buffer *ready[MSM_VFE_NUM_OUTPUTS] = { };
+	struct vfe_line *line;
+	unsigned long flags;
+	unsigned int o;
+	u64 ts = ktime_get_ns();
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Received wm done for unmapped index\n");
+		goto out_unlock;
+	}
+	line = &vfe->line[vfe->wm_output_map[wm]];
 
-	return;
+	/* Without per-group status (RDI lines, TFE) there is a single output */
+	if (!line->is_pix || !buf_done_info || !buf_done_info->status) {
+		ready[0] = vfe_output_done(vfe, line, &line->output[0], ts);
+	} else {
+		for (o = 0; o < line->num_outputs; o++) {
+			struct vfe_output *output = &line->output[o];
+
+			if (output->state != VFE_OUTPUT_ON || !output->wm_num ||
+			    !(buf_done_info->status & BIT(output->comp_group)))
+				continue;
+
+			ready[o] = vfe_output_done(vfe, line, output, ts);
+		}
+	}
 
 out_unlock:
 	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	for (o = 0; o < MSM_VFE_NUM_OUTPUTS; o++)
+		if (ready[o])
+			vb2_buffer_done(&ready[o]->vb.vb2_buf,
+					VB2_BUF_STATE_DONE);
 }
 
 /*

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 66/74] media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (64 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 65/74] media: qcom: camss: vfe: Complete pixel line outputs on their own completion group bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 67/74] media: uapi: Add the CAMSS AEC Bayer histogram configuration bod
                   ` (8 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Stream the AEC Bayer histogram on the pixel line's statistics node, as
the V4L2_META_FMT_QCOM_ISP_STATS block CAMSS_STATS_AEC_BHIST.

The AEC BHIST write master is frame based, PLAIN64, in completion group
4. Write master addresses are 256 byte aligned and the v4l2-isp block
payloads are not, so the write master fills a kernel buffer and the
completion of group 4 serialises it into the next queued statistics
buffer with v4l2_isp_stats_init_buffer() and
v4l2_isp_stats_init_block(). The copy runs a frame before the write
master writes the kernel buffer again.

As with image buffers, each frame consumes one programmed write master
address, so the write master is handed the kernel buffer once per queued
statistics buffer. Without a queued buffer it has no address and the
frame's statistics are dropped; the sequence numbers show the gap.

The statistics output runs when msm_vfeN_stats is streaming as the
image node starts. The node may stop and start again while the line
runs: vfe_flush_buffers() now forgets the buffers it returns.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 64 +++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.c     | 68 +++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.h     |  9 +++
 3 files changed, 141 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 1d00a3656d7c3..7642d9d4500de 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -114,8 +114,49 @@ static void vfe_wm_start_pix(struct vfe_device *vfe, struct vfe_line *line)
 	}
 }
 
+static struct vfe_output *vfe_stats_output(struct vfe_line *line, u8 wm)
+{
+	unsigned int o;
+
+	if (!line->is_pix)
+		return NULL;
+
+	for (o = 1; o < line->num_outputs; o++)
+		if (line->output[o].pad == MSM_VFE_PAD_SRC_STATS &&
+		    line->output[o].wm_num &&
+		    line->output[o].wm[0].bus_client == wm)
+			return &line->output[o];
+
+	return NULL;
+}
+
+/* Statistics write masters are frame based and fill the output's kernel buffer */
+static void vfe_wm_start_stats(struct vfe_device *vfe, struct vfe_output *output)
+{
+	u8 wm = output->wm[0].bus_client;
+
+	writel(0, vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm));
+	writel(0, vfe->base + VFE_BUS_WM_IMAGE_CFG_1(wm));
+	writel(1, vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm));
+	writel(VFE_BUS_WM_PACKER_FMT_V3_PLAIN_64,
+	       vfe->base + VFE_BUS_WM_PACKER_CFG(wm));
+
+	/* no dropped frames, one irq per frame */
+	writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm));
+	writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm));
+	writel(0, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(wm));
+	writel(1, vfe->base + VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(wm));
+
+	writel(1, vfe->base + VFE_BUS_WM_MMU_PREFETCH_CFG(wm));
+	writel(0xFFFFFFFF, vfe->base + VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(wm));
+
+	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
 static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 {
+	struct vfe_output *stats = vfe_stats_output(line, wm);
+
 	struct v4l2_pix_format_mplane *pix =
 		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 
@@ -126,6 +167,11 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 
 	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
 
+	if (stats) {
+		vfe_wm_start_stats(vfe, stats);
+		return;
+	}
+
 	if (line->is_pix) {
 		vfe_wm_start_pix(vfe, line);
 		return;
@@ -157,6 +203,11 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	struct vfe_output *output = &line->output[0];
 	unsigned int i;
 
+	if (vfe_stats_output(line, wm)) {
+		writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
+		return;
+	}
+
 	for (i = 0; i < output->wm_num; i++)
 		writel(0, vfe->base + VFE_BUS_WM_CFG(output->wm[i].bus_client));
 }
@@ -165,8 +216,19 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *bu
 			  struct vfe_line *line)
 {
 	struct vfe_output *output = &line->output[0];
+	struct vfe_output *stats;
 	unsigned int i;
 
+	/*
+	 * Each frame consumes one programmed address, as for images: hand the
+	 * write master the output's kernel buffer once per queued buffer.
+	 */
+	stats = vfe_stats_output(line, wm);
+	if (stats) {
+		writel(stats->dma_addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
+		return;
+	}
+
 	/* camss-video sets addr[1] = addr[0] + bytesperline * height for NV12 */
 	for (i = 0; i < output->wm_num; i++) {
 		u32 addr = buffer->addr[output->wm[i].plane];
@@ -237,6 +299,8 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 	vfe_add_ds(&pix->output[1], MSM_VFE_PAD_SRC_DS4, VFE_WM_VIDEO_DS_4, VFE_V3_COMP_GRP_0);
 	vfe_add_ds(&pix->output[2], MSM_VFE_PAD_SRC_DS16, VFE_WM_VIDEO_DS_16, VFE_V3_COMP_GRP_0);
 	vfe_add_stats(&pix->output[3], VFE_WM_STATS_AEC_BHIST, VFE_V3_COMP_GRP_4);
+	if (vfe_alloc_stats(vfe, &pix->output[3]))
+		pix->output[3].wm_num = 0;	/* no statistics without their buffer */
 	vfe_add_params(&pix->output[4], VFE_V3_COMP_GRP_0);
 
 	/* PIX mode */
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index b90b538c1aaaf..1522f1046d8dd 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -623,6 +623,63 @@ u32 vfe_hw_version(struct vfe_device *vfe)
  * @vfe: VFE Device
  * @wm: Write master id
  */
+static const struct v4l2_isp_stats_block_type_info vfe_stats_block_info[] = {
+	[CAMSS_STATS_AEC_BHIST] = { .size = sizeof(struct camss_stats_bhist) },
+};
+
+/*
+ * vfe_alloc_stats - Allocate the write master target of a statistics output
+ * @vfe: VFE device
+ * @output: statistics output
+ *
+ * Write master addresses are 256 byte aligned and the v4l2-isp block payloads
+ * are not, so statistics are written to a kernel buffer and copied into the
+ * userspace buffer when their completion group fires.
+ *
+ * Return 0 on success or -ENOMEM
+ */
+int vfe_alloc_stats(struct vfe_device *vfe, struct vfe_output *output)
+{
+	output->dma_size = sizeof_field(struct camss_stats_bhist, bins);
+	output->dma_vaddr = dmam_alloc_coherent(vfe->camss->dev,
+						output->dma_size,
+						&output->dma_addr, GFP_KERNEL);
+
+	return output->dma_vaddr ? 0 : -ENOMEM;
+}
+
+/*
+ * vfe_stats_fill - Serialise a frame's statistics into a userspace buffer
+ * @vfe: VFE device
+ * @output: statistics output
+ * @buf: buffer to fill
+ *
+ * Runs from the completion of the statistics group, a frame before the write
+ * master writes the kernel buffer again.
+ */
+static void vfe_stats_fill(struct vfe_device *vfe, struct vfe_output *output,
+			   struct camss_buffer *buf)
+{
+	struct v4l2_isp_buffer *stats = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+	struct v4l2_isp_block_header *block;
+	struct camss_stats_bhist *bhist;
+
+	v4l2_isp_stats_init_buffer(stats, V4L2_ISP_VERSION_V1);
+
+	block = v4l2_isp_stats_init_block(vfe->camss->dev, stats,
+					  vfe_stats_block_info,
+					  ARRAY_SIZE(vfe_stats_block_info),
+					  CAMSS_STATS_AEC_BHIST,
+					  CAMSS_STATS_MAX_PAYLOAD);
+	if (!IS_ERR(block)) {
+		bhist = container_of(block, struct camss_stats_bhist, header);
+		memcpy(bhist->bins, output->dma_vaddr, sizeof(bhist->bins));
+	}
+
+	vb2_set_plane_payload(&buf->vb.vb2_buf, 0,
+			      v4l2_isp_buffer_size(stats->data_size));
+}
+
 /*
  * vfe_output_done - Retire the filled buffer of one output
  * @vfe: VFE device
@@ -657,6 +714,9 @@ static struct camss_buffer *vfe_output_done(struct vfe_device *vfe,
 	ready_buf->vb.vb2_buf.timestamp = ts;
 	ready_buf->vb.sequence = output->sequence++;
 
+	if (output->pad == MSM_VFE_PAD_SRC_STATS)
+		vfe_stats_fill(vfe, output, ready_buf);
+
 	index = 0;
 	output->buf[0] = output->buf[1];
 	if (output->buf[0])
@@ -1487,6 +1547,14 @@ int vfe_flush_buffers(struct camss_video *vid,
 	if (output->buf[1])
 		vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state);
 
+	/*
+	 * A metadata node stops while its line runs: forget the returned
+	 * buffers so a later completion does not return them again.
+	 */
+	output->buf[0] = NULL;
+	output->buf[1] = NULL;
+	output->gen2.active_num = 0;
+
 	if (output->last_buffer) {
 		vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state);
 		output->last_buffer = NULL;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 11cded2b345eb..0b2634f1e4d6a 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -143,6 +143,14 @@ struct vfe_output {
 
 	struct vfe_line *line;
 	struct camss_video video_out;
+
+	/*
+	 * Kernel buffer the write masters fill, for outputs the CPU copies
+	 * to userspace at completion (statistics)
+	 */
+	void *dma_vaddr;
+	dma_addr_t dma_addr;
+	size_t dma_size;
 };
 
 struct vfe_line {
@@ -422,6 +430,7 @@ void vfe_add_ds(struct vfe_output *output, u8 pad, u8 bus_client,
 		u8 comp_group);
 
 void vfe_add_stats(struct vfe_output *output, u8 bus_client, u8 comp_group);
+int vfe_alloc_stats(struct vfe_device *vfe, struct vfe_output *output);
 
 void vfe_add_params(struct vfe_output *output, u8 comp_group);
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 67/74] media: uapi: Add the CAMSS AEC Bayer histogram configuration
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (65 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 66/74] media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 68/74] media: v4l2: Add the Qualcomm CAMSS ISP parameters format bod
                   ` (7 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Add CAMSS_PARAMS_AEC_BHIST, a V4L2_META_FMT_QCOM_ISP_PARAMS block which
selects the region of the frame the AEC Bayer histogram statistics,
CAMSS_STATS_AEC_BHIST, count. The region is given in pixels of the Bayer
frame entering the ISP, in even values, and is clipped to the frame.

CAMSS_PARAMS_IFE_MAX_PAYLOAD sizes the parameters buffer of the IFE
pixel path.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 include/uapi/linux/qcom-camss-config.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/include/uapi/linux/qcom-camss-config.h b/include/uapi/linux/qcom-camss-config.h
index 23c12b8955ef6..8abd7d262b73c 100644
--- a/include/uapi/linux/qcom-camss-config.h
+++ b/include/uapi/linux/qcom-camss-config.h
@@ -25,12 +25,15 @@
  *	&struct camss_params_color_correct
  * @CAMSS_PARAMS_GAMMA: per-channel gamma correction curves (CLC_GLUT),
  *	&struct camss_params_gamma
+ * @CAMSS_PARAMS_AEC_BHIST: region of the AEC Bayer histogram statistics,
+ *	&struct camss_params_aec_bhist
  */
 enum camss_params_block_type {
 	CAMSS_PARAMS_WB_GAIN = 1,
 	CAMSS_PARAMS_CHROMA_ENHAN = 2,
 	CAMSS_PARAMS_COLOR_CORRECT = 3,
 	CAMSS_PARAMS_GAMMA = 4,
+	CAMSS_PARAMS_AEC_BHIST = 5,
 };
 
 /* Number of entries in each gamma channel LUT. */
@@ -209,6 +212,31 @@ struct camss_params_gamma {
 	 sizeof(struct camss_params_color_correct)	+\
 	 sizeof(struct camss_params_gamma))
 
+/**
+ * struct camss_params_aec_bhist - AEC Bayer histogram configuration
+ *
+ * Selects the region of the frame the AEC Bayer histogram,
+ * &struct camss_stats_bhist, counts. The region is given in pixels of the
+ * Bayer frame entering the ISP; every value must be even, as the histogram
+ * counts 2x2 Bayer quads. A region reaching past the frame is clipped to it.
+ *
+ * @header: block header; @header.type = CAMSS_PARAMS_AEC_BHIST
+ * @left:   horizontal offset of the region
+ * @top:    vertical offset of the region
+ * @width:  width of the region, at least 2
+ * @height: height of the region, at least 2
+ */
+struct camss_params_aec_bhist {
+	struct v4l2_isp_params_block_header header;
+	__u16 left;
+	__u16 top;
+	__u16 width;
+	__u16 height;
+} __attribute__((aligned(8)));
+
+#define CAMSS_PARAMS_IFE_MAX_PAYLOAD		\
+	sizeof(struct camss_params_aec_bhist)
+
 /**
  * enum camss_stats_block_type - CAMSS ISP statistics block identifiers
  *

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 68/74] media: v4l2: Add the Qualcomm CAMSS ISP parameters format
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (66 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 67/74] media: uapi: Add the CAMSS AEC Bayer histogram configuration bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 69/74] media: Documentation: uapi: Add the CAMSS IFE parameters bod
                   ` (6 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Define V4L2_META_FMT_QCOM_ISP_PARAMS ('QCIP'), documented with the CAMSS
ISP parameters blocks, and its description.

Drop this patch if the OPE series providing the same definition is
already applied.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
 include/uapi/linux/videodev2.h       | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index e5eccb62e76b2..f30eb50e4b309 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1471,6 +1471,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 	case V4L2_META_FMT_C3ISP_STATS:		descr = "Amlogic C3 ISP Statistics"; break;
 	case V4L2_META_FMT_MALI_C55_PARAMS:	descr = "ARM Mali-C55 ISP Parameters"; break;
 	case V4L2_META_FMT_MALI_C55_STATS:	descr = "ARM Mali-C55 ISP 3A Statistics"; break;
+	case V4L2_META_FMT_QCOM_ISP_PARAMS:	descr = "Qualcomm CAMSS ISP Parameters"; break;
 	case V4L2_META_FMT_QCOM_ISP_STATS:	descr = "Qualcomm CAMSS ISP Statistics"; break;
 	case V4L2_PIX_FMT_NV12_8L128:	descr = "NV12 (8x128 Linear)"; break;
 	case V4L2_PIX_FMT_NV12M_8L128:	descr = "NV12M (8x128 Linear)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 700ea9b646979..21515f99e3d7c 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -890,6 +890,7 @@ struct v4l2_pix_format {
 #define V4L2_META_FMT_MALI_C55_STATS	v4l2_fourcc('C', '5', '5', 'S') /* ARM Mali-C55 3A Statistics */
 
 /* Vendor specific - used for Qualcomm CAMSS ISP */
+#define V4L2_META_FMT_QCOM_ISP_PARAMS	v4l2_fourcc('Q', 'C', 'I', 'P') /* Qualcomm CAMSS ISP Parameters */
 #define V4L2_META_FMT_QCOM_ISP_STATS	v4l2_fourcc('Q', 'C', 'I', 'S') /* Qualcomm CAMSS ISP Statistics */
 
 #ifdef __KERNEL__

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 69/74] media: Documentation: uapi: Add the CAMSS IFE parameters
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (67 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 68/74] media: v4l2: Add the Qualcomm CAMSS ISP parameters format bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 70/74] media: qcom: camss: video: Support metadata output nodes bod
                   ` (5 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Document the parameters block the SM8650 IFE pixel path accepts on its
msm_vfeN_params node, and when queued parameters apply.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 .../userspace-api/media/v4l/metafmt-qcom-isp.rst   | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
index 77372b3a32d7d..0a7ef8b314423 100644
--- a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
+++ b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst
@@ -141,6 +141,28 @@ and a gamma correction block:
 	for (unsigned int i = 0; i < CAMSS_GAMMA_LUT_SIZE; i++)
 		gamma->glut[i] = gamma->blut[i] = gamma->rlut[i] = i;
 
+IFE pixel path
+==============
+
+The pixel path of the SM8650 IFE consumes the format on its
+``msm_vfeN_params`` metadata output node. It accepts the following block, and
+rejects blocks of other types:
+
+.. flat-table:: IFE parameter blocks
+    :header-rows: 1
+    :stub-columns: 0
+
+    * - Parameter block
+      - Function
+    * - :c:type:`camss_params_aec_bhist`
+      - Region of the frame counted by the AEC Bayer histogram statistics,
+        :c:type:`camss_stats_bhist`.
+
+Parameters queued before the image node starts streaming apply from the first
+frame. Parameters queued while streaming apply from a following frame; the
+buffer is returned with the sequence number of the first frame they can
+affect.
+
 .. _v4l2-meta-fmt-qcom-isp-stats:
 
 *************************************

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 70/74] media: qcom: camss: video: Support metadata output nodes
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (68 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 69/74] media: Documentation: uapi: Add the CAMSS IFE parameters bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 71/74] media: qcom: camss: vfe: Register and apply a parameters node for the pixel line bod
                   ` (4 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Parameters need metadata output nodes. Register a node of video->type
V4L2_BUF_TYPE_META_OUTPUT alongside the metadata capture node:

- a source pad, VFL_DIR_TX and the META_OUTPUT format ioctls, returning
  the fixed format the producer sets before registration
- each buffer has a kernel copy, buf->meta: the payload is copied into
  it when the buffer is prepared, and the optional prepare_buffer()
  video op validates the copy, so what is validated is what the
  producer consumes
- like the capture node, it neither starts nor stops the line, and
  stopping it returns its buffers

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-video.c | 101 ++++++++++++++++++++++--
 drivers/media/platform/qcom/camss/camss-video.h |   8 ++
 2 files changed, 101 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index b8501c895d393..69cbe78b80622 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -414,6 +414,65 @@ static const struct vb2_ops msm_video_meta_vb2_q_ops = {
 	.unprepare_streaming = video_unprepare_streaming,
 };
 
+/*
+ * A metadata output buffer is copied to the kernel when it is prepared, so
+ * what is validated is what the producer later consumes.
+ */
+static int video_meta_out_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+	struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
+						   vb);
+
+	buffer->meta = kvmalloc(video->active_fmt.fmt.meta.buffersize,
+				GFP_KERNEL);
+
+	return buffer->meta ? 0 : -ENOMEM;
+}
+
+static void video_meta_out_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
+						   vb);
+
+	kvfree(buffer->meta);
+	buffer->meta = NULL;
+}
+
+static int video_meta_out_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+	struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer,
+						   vb);
+	size_t payload = vb2_get_plane_payload(vb, 0);
+
+	if (payload > video->active_fmt.fmt.meta.buffersize)
+		return -EINVAL;
+
+	memcpy(buffer->meta, vb2_plane_vaddr(vb, 0), payload);
+	vbuf->field = V4L2_FIELD_NONE;
+
+	if (video->ops->prepare_buffer)
+		return video->ops->prepare_buffer(video, buffer);
+
+	return 0;
+}
+
+static const struct vb2_ops msm_video_meta_out_vb2_q_ops = {
+	.queue_setup     = video_meta_queue_setup,
+	.buf_init        = video_meta_out_buf_init,
+	.buf_cleanup     = video_meta_out_buf_cleanup,
+	.buf_prepare     = video_meta_out_buf_prepare,
+	.buf_queue       = video_buf_queue,
+	.prepare_streaming = video_prepare_streaming,
+	.start_streaming = video_meta_start_streaming,
+	.stop_streaming  = video_meta_stop_streaming,
+	.unprepare_streaming = video_unprepare_streaming,
+};
+
 /* -----------------------------------------------------------------------------
  * V4L2 ioctls
  */
@@ -721,6 +780,23 @@ static const struct v4l2_ioctl_ops msm_vid_meta_ioctl_ops = {
 	.vidioc_streamoff		= vb2_ioctl_streamoff,
 };
 
+static const struct v4l2_ioctl_ops msm_vid_meta_out_ioctl_ops = {
+	.vidioc_querycap		= video_querycap,
+	.vidioc_enum_fmt_meta_out	= video_meta_enum_fmt,
+	.vidioc_g_fmt_meta_out		= video_meta_g_fmt,
+	.vidioc_s_fmt_meta_out		= video_meta_g_fmt,
+	.vidioc_try_fmt_meta_out	= video_meta_g_fmt,
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_expbuf			= vb2_ioctl_expbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+};
+
 /* -----------------------------------------------------------------------------
  * V4L2 file operations
  */
@@ -796,7 +872,8 @@ static int msm_video_init_format(struct camss_video *video)
 int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 		       const char *name)
 {
-	bool meta = video->type == V4L2_BUF_TYPE_META_CAPTURE;
+	bool meta_out = video->type == V4L2_BUF_TYPE_META_OUTPUT;
+	bool meta = meta_out || video->type == V4L2_BUF_TYPE_META_CAPTURE;
 	struct media_pad *pad = &video->pad;
 	struct video_device *vdev;
 	struct vb2_queue *q;
@@ -809,9 +886,13 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 	q = &video->vb2_q;
 	q->drv_priv = video;
 	q->mem_ops = meta ? &vb2_vmalloc_memops : &vb2_dma_sg_memops;
-	q->ops = meta ? &msm_video_meta_vb2_q_ops : &msm_video_vb2_q_ops;
-	q->type = meta ? V4L2_BUF_TYPE_META_CAPTURE :
-			 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	if (meta_out)
+		q->ops = &msm_video_meta_out_vb2_q_ops;
+	else if (meta)
+		q->ops = &msm_video_meta_vb2_q_ops;
+	else
+		q->ops = &msm_video_vb2_q_ops;
+	q->type = meta ? video->type : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	q->io_modes = meta ? VB2_DMABUF | VB2_MMAP :
 			     VB2_DMABUF | VB2_MMAP | VB2_READ;
 	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -824,7 +905,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 		goto error_vb2_init;
 	}
 
-	pad->flags = MEDIA_PAD_FL_SINK;
+	pad->flags = meta_out ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
 	ret = media_entity_pads_init(&vdev->entity, 1, pad);
 	if (ret < 0) {
 		dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n",
@@ -836,7 +917,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 
 	if (meta) {
 		/* dataformat and buffersize are set by the producer */
-		video->active_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
+		video->active_fmt.type = video->type;
 	} else {
 		ret = msm_video_init_format(video);
 		if (ret < 0) {
@@ -847,7 +928,11 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 	}
 
 	vdev->fops = &msm_vid_fops;
-	if (meta) {
+	if (meta_out) {
+		vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING |
+				    V4L2_CAP_IO_MC;
+		vdev->ioctl_ops = &msm_vid_meta_out_ioctl_ops;
+	} else if (meta) {
 		vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING |
 				    V4L2_CAP_IO_MC;
 		vdev->ioctl_ops = &msm_vid_meta_ioctl_ops;
@@ -859,7 +944,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 	}
 	vdev->release = msm_video_release;
 	vdev->v4l2_dev = v4l2_dev;
-	vdev->vfl_dir = VFL_DIR_RX;
+	vdev->vfl_dir = meta_out ? VFL_DIR_TX : VFL_DIR_RX;
 	vdev->queue = &video->vb2_q;
 	vdev->lock = &video->lock;
 	strscpy(vdev->name, name, sizeof(vdev->name));
diff --git a/drivers/media/platform/qcom/camss/camss-video.h b/drivers/media/platform/qcom/camss/camss-video.h
index d3e56e240a888..21a951b7fe9bc 100644
--- a/drivers/media/platform/qcom/camss/camss-video.h
+++ b/drivers/media/platform/qcom/camss/camss-video.h
@@ -23,6 +23,9 @@ struct camss_buffer {
 	struct vb2_v4l2_buffer vb;
 	dma_addr_t addr[3];
 	struct list_head queue;
+
+	/* Metadata output nodes: kernel copy of the buffer, validated at prepare */
+	void *meta;
 };
 
 struct camss_video;
@@ -31,6 +34,11 @@ struct camss_video_ops {
 	int (*queue_buffer)(struct camss_video *vid, struct camss_buffer *buf);
 	int (*flush_buffers)(struct camss_video *vid,
 			     enum vb2_buffer_state state);
+	/*
+	 * Optional, metadata output nodes: validate the kernel copy of a
+	 * buffer, buf->meta, when it is prepared
+	 */
+	int (*prepare_buffer)(struct camss_video *vid, struct camss_buffer *buf);
 };
 
 struct camss_video {

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 71/74] media: qcom: camss: vfe: Register and apply a parameters node for the pixel line
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (69 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 70/74] media: qcom: camss: video: Support metadata output nodes bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 72/74] media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters bod
                   ` (3 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

A pixel line whose descriptor declares a parameters output, on a VFE
whose backend can apply parameters, gets a metadata output node,
msm_vfeN_params, linked immutably to its parameters pad. The node takes
V4L2_META_FMT_QCOM_ISP_PARAMS, in the v4l2-isp extensible format.

The backend provides the blocks the line accepts, indexed by type, and
how to apply a buffer. vfe_params_prepare() validates the kernel copy of
each buffer against them when it is prepared.

Parameters queued before the line starts are applied, oldest first,
after the pixel pipe takes its defaults. While streaming, one queued
buffer is applied per completed image frame, followed by a reg update.
Each buffer is returned with the sequence number of the first frame it
can affect.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 173 +++++++++++++++++++++++---
 drivers/media/platform/qcom/camss/camss-vfe.h |  12 ++
 2 files changed, 165 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 1522f1046d8dd..5c72357bb8f02 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -680,6 +680,99 @@ static void vfe_stats_fill(struct vfe_device *vfe, struct vfe_output *output,
 			      v4l2_isp_buffer_size(stats->data_size));
 }
 
+/*
+ * vfe_params_prepare - Validate a parameters buffer when it is prepared
+ * @vid: video node
+ * @buf: buffer, whose kernel copy buf->meta is validated
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_params_prepare(struct camss_video *vid, struct camss_buffer *buf)
+{
+	struct vfe_output *output = container_of(vid, struct vfe_output,
+						 video_out);
+	struct vfe_device *vfe = to_vfe(output->line);
+	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
+	struct vb2_buffer *vb = &buf->vb.vb2_buf;
+	int ret;
+
+	if (vid->type != V4L2_BUF_TYPE_META_OUTPUT)
+		return 0;
+
+	ret = v4l2_isp_params_validate_buffer_size(vfe->camss->dev, vb,
+						   vid->active_fmt.fmt.meta.buffersize);
+	if (ret)
+		return ret;
+
+	return v4l2_isp_params_validate_buffer(vfe->camss->dev, vb, buf->meta,
+					       ops->params_info,
+					       ops->params_num_types);
+}
+
+static struct vfe_output *vfe_params_output(struct vfe_line *line)
+{
+	unsigned int o;
+
+	for (o = 1; o < line->num_outputs; o++)
+		if (line->output[o].pad == MSM_VFE_PAD_SINK_PARAMS)
+			return &line->output[o];
+
+	return NULL;
+}
+
+/*
+ * vfe_params_apply_next - Apply the oldest queued parameters buffer
+ * @vfe: VFE device
+ * @line: VFE line
+ * @sequence: sequence number of the first frame the parameters can affect
+ *
+ * Called with output_lock held.
+ *
+ * Return the applied buffer for the caller to complete once the lock is
+ * dropped, or NULL if none was queued
+ */
+static struct camss_buffer *vfe_params_apply_next(struct vfe_device *vfe,
+						  struct vfe_line *line,
+						  u32 sequence)
+{
+	const struct vfe_hw_ops *ops = vfe->res->hw_ops;
+	struct vfe_output *params = vfe_params_output(line);
+	struct camss_buffer *buf;
+
+	if (!params || !ops->vfe_params_apply)
+		return NULL;
+
+	buf = vfe_buf_get_pending(params);
+	if (!buf)
+		return NULL;
+
+	ops->vfe_params_apply(vfe, line, buf->meta);
+
+	buf->vb.vb2_buf.timestamp = ktime_get_ns();
+	buf->vb.sequence = sequence;
+
+	return buf;
+}
+
+/* Line start: apply every queued parameters buffer, oldest first */
+static void vfe_params_apply_queued(struct vfe_device *vfe,
+				    struct vfe_line *line)
+{
+	struct camss_buffer *buf;
+	unsigned long flags;
+
+	for (;;) {
+		spin_lock_irqsave(&vfe->output_lock, flags);
+		buf = vfe_params_apply_next(vfe, line, 0);
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+		if (!buf)
+			break;
+
+		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+	}
+}
+
 /*
  * vfe_output_done - Retire the filled buffer of one output
  * @vfe: VFE device
@@ -752,6 +845,7 @@ static struct camss_buffer *vfe_output_done(struct vfe_device *vfe,
 void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *buf_done_info)
 {
 	struct camss_buffer *ready[MSM_VFE_NUM_OUTPUTS] = { };
+	struct camss_buffer *params = NULL;
 	struct vfe_line *line;
 	unsigned long flags;
 	unsigned int o;
@@ -779,6 +873,14 @@ void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *bu
 
 			ready[o] = vfe_output_done(vfe, line, output, ts);
 		}
+
+		/* one parameters buffer per completed image frame */
+		if (ready[0]) {
+			params = vfe_params_apply_next(vfe, line,
+						       line->output[0].sequence);
+			if (params)
+				vfe->res->hw_ops->reg_update(vfe, line->id);
+		}
 	}
 
 out_unlock:
@@ -788,6 +890,9 @@ void vfe_buf_done(struct vfe_device *vfe, int wm, struct camss_buf_done_info *bu
 		if (ready[o])
 			vb2_buffer_done(&ready[o]->vb.vb2_buf,
 					VB2_BUF_STATE_DONE);
+
+	if (params)
+		vb2_buffer_done(&params->vb.vb2_buf, VB2_BUF_STATE_DONE);
 }
 
 /*
@@ -950,6 +1055,10 @@ int vfe_enable_v2(struct vfe_line *line)
 	if (ops->vfe_line_prepare)
 		ops->vfe_line_prepare(line);
 
+	/* queued parameters override the defaults the line starts with */
+	if (line->is_pix)
+		vfe_params_apply_queued(vfe, line);
+
 	ret = vfe_enable_output_v2(line);
 	if (ret < 0)
 		goto error_enable_output;
@@ -2490,17 +2599,19 @@ static int vfe_bpl_align_pix(struct vfe_device *vfe)
 }
 
 /*
- * vfe_register_stats_node - Register the statistics node of a pixel line
+ * vfe_register_meta_nodes - Register the metadata nodes of a pixel line
  * @vfe: VFE device
  * @line: VFE line
  * @v4l2_dev: V4L2 device
  *
  * A line whose descriptor declares a statistics output gets a metadata
- * capture node, msm_vfeN_stats, linked from its statistics pad.
+ * capture node, msm_vfeN_stats, linked from its statistics pad. One that
+ * declares a parameters output, on a VFE able to apply parameters, gets a
+ * metadata output node, msm_vfeN_params, linked to its parameters pad.
  *
  * Return 0 on success or a negative error code otherwise
  */
-static int vfe_register_stats_node(struct vfe_device *vfe,
+static int vfe_register_meta_nodes(struct vfe_device *vfe,
 				   struct vfe_line *line,
 				   struct v4l2_device *v4l2_dev)
 {
@@ -2511,32 +2622,54 @@ static int vfe_register_stats_node(struct vfe_device *vfe,
 	for (o = 1; o < line->num_outputs; o++) {
 		struct vfe_output *output = &line->output[o];
 		struct camss_video *video = &output->video_out;
+		const char *suffix;
 		char name[32];
 
-		if (output->pad != MSM_VFE_PAD_SRC_STATS || !output->wm_num)
+		if (output->pad == MSM_VFE_PAD_SRC_STATS && output->wm_num) {
+			video->type = V4L2_BUF_TYPE_META_CAPTURE;
+			video->active_fmt.fmt.meta.dataformat =
+				V4L2_META_FMT_QCOM_ISP_STATS;
+			video->active_fmt.fmt.meta.buffersize =
+				v4l2_isp_buffer_size(CAMSS_STATS_MAX_PAYLOAD);
+			suffix = "stats";
+		} else if (output->pad == MSM_VFE_PAD_SINK_PARAMS &&
+			   vfe->res->hw_ops->vfe_params_apply) {
+			video->type = V4L2_BUF_TYPE_META_OUTPUT;
+			video->active_fmt.fmt.meta.dataformat =
+				V4L2_META_FMT_QCOM_ISP_PARAMS;
+			video->active_fmt.fmt.meta.buffersize =
+				v4l2_isp_buffer_size(CAMSS_PARAMS_IFE_MAX_PAYLOAD);
+			suffix = "params";
+		} else {
 			continue;
+		}
 
-		video->type = V4L2_BUF_TYPE_META_CAPTURE;
-		video->active_fmt.fmt.meta.dataformat =
-			V4L2_META_FMT_QCOM_ISP_STATS;
-		video->active_fmt.fmt.meta.buffersize =
-			v4l2_isp_buffer_size(CAMSS_STATS_MAX_PAYLOAD);
 		video->ops = &vfe->video_ops;
 
 		snprintf(name, ARRAY_SIZE(name), "%s%d_%s",
-			 MSM_VFE_NAME, vfe->id, "stats");
+			 MSM_VFE_NAME, vfe->id, suffix);
 		ret = msm_video_register(video, v4l2_dev, name);
 		if (ret < 0) {
-			dev_err(dev, "Failed to register stats node: %d\n", ret);
+			dev_err(dev, "Failed to register %s node: %d\n",
+				suffix, ret);
 			return ret;
 		}
 
-		ret = media_create_pad_link(&line->subdev.entity, output->pad,
-					    &video->vdev.entity, 0,
-					    MEDIA_LNK_FL_IMMUTABLE |
-					    MEDIA_LNK_FL_ENABLED);
+		if (video->type == V4L2_BUF_TYPE_META_OUTPUT)
+			ret = media_create_pad_link(&video->vdev.entity, 0,
+						    &line->subdev.entity,
+						    output->pad,
+						    MEDIA_LNK_FL_IMMUTABLE |
+						    MEDIA_LNK_FL_ENABLED);
+		else
+			ret = media_create_pad_link(&line->subdev.entity,
+						    output->pad,
+						    &video->vdev.entity, 0,
+						    MEDIA_LNK_FL_IMMUTABLE |
+						    MEDIA_LNK_FL_ENABLED);
 		if (ret < 0) {
-			dev_err(dev, "Failed to link stats node: %d\n", ret);
+			dev_err(dev, "Failed to link %s node: %d\n", suffix,
+				ret);
 			msm_video_unregister(video);
 			return ret;
 		}
@@ -2545,7 +2678,7 @@ static int vfe_register_stats_node(struct vfe_device *vfe,
 	return 0;
 }
 
-static void vfe_unregister_stats_node(struct vfe_line *line)
+static void vfe_unregister_meta_nodes(struct vfe_line *line)
 {
 	unsigned int o;
 
@@ -2660,7 +2793,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 			goto error_link;
 		}
 
-		ret = vfe_register_stats_node(vfe, &vfe->line[i], v4l2_dev);
+		ret = vfe_register_meta_nodes(vfe, &vfe->line[i], v4l2_dev);
 		if (ret < 0)
 			goto error_link;
 	}
@@ -2681,7 +2814,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 		sd = &vfe->line[i].subdev;
 		video_out = &vfe->line[i].output[0].video_out;
 
-		vfe_unregister_stats_node(&vfe->line[i]);
+		vfe_unregister_meta_nodes(&vfe->line[i]);
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
 		media_entity_cleanup(&sd->entity);
@@ -2705,7 +2838,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
 		struct v4l2_subdev *sd = &vfe->line[i].subdev;
 		struct camss_video *video_out = &vfe->line[i].output[0].video_out;
 
-		vfe_unregister_stats_node(&vfe->line[i]);
+		vfe_unregister_meta_nodes(&vfe->line[i]);
 		msm_video_unregister(video_out);
 		v4l2_device_unregister_subdev(sd);
 		media_entity_cleanup(&sd->entity);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0b2634f1e4d6a..b39bce17f8dec 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -14,6 +14,7 @@
 #include <linux/spinlock_types.h>
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-isp.h>
 #include <media/v4l2-subdev.h>
 
 #include "camss-video.h"
@@ -205,6 +206,16 @@ struct vfe_hw_ops {
 	 */
 	void (*vfe_line_prepare)(struct vfe_line *line);
 
+	/*
+	 * Optional: the parameters blocks the pixel line accepts, indexed by
+	 * block type, and how to apply a validated parameters buffer. Applying
+	 * runs with output_lock held, ahead of a reg update.
+	 */
+	const struct v4l2_isp_params_block_type_info *params_info;
+	unsigned int params_num_types;
+	void (*vfe_params_apply)(struct vfe_device *vfe, struct vfe_line *line,
+				 const struct v4l2_isp_buffer *params);
+
 	/* 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);
@@ -431,6 +442,7 @@ void vfe_add_ds(struct vfe_output *output, u8 pad, u8 bus_client,
 
 void vfe_add_stats(struct vfe_output *output, u8 bus_client, u8 comp_group);
 int vfe_alloc_stats(struct vfe_device *vfe, struct vfe_output *output);
+int vfe_params_prepare(struct camss_video *vid, struct camss_buffer *buf);
 
 void vfe_add_params(struct vfe_output *output, u8 comp_group);
 

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 72/74] media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (70 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 71/74] media: qcom: camss: vfe: Register and apply a parameters node for the pixel line bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 73/74] media: qcom: camss: vfe-780: Drive the write masters through the output ops bod
                   ` (2 subsequent siblings)
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

Accept CAMSS_PARAMS_AEC_BHIST on the pixel line's parameters node and
program the region the AEC Bayer histogram counts. The region is clipped
to the Bayer frame entering the line and converted to the 2x2 quads the
histogram counts: RGN_OFFSET_CFG takes the offset and RGN_NUM_CFG the
size, less one, as vfe_setup_aec_bhist() programs the full frame.

The other CAMSS parameters blocks belong to the OPE and are rejected.
Every type up to CAMSS_PARAMS_AEC_BHIST has an entry in the block table,
so that no block passes v4l2_isp_params_validate_buffer() with a size of
zero.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c  | 103 +++++++++++++++++++++
 .../media/platform/qcom/camss/camss-vfe-880-pp.c   |  17 ++++
 .../media/platform/qcom/camss/camss-vfe-880-pp.h   |   2 +
 3 files changed, 122 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 7642d9d4500de..33247e6de898c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -9,6 +9,8 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 
+#include <linux/qcom-camss-config.h>
+
 #include "camss.h"
 #include "camss-csid-gen3.h"
 #include "camss-vfe.h"
@@ -273,7 +275,105 @@ static void vfe_line_prepare(struct vfe_line *line)
 static const struct camss_video_ops vfe_video_ops_780 = {
 	.queue_buffer = vfe_queue_buffer_v2,
 	.flush_buffers = vfe_flush_buffers,
+	.prepare_buffer = vfe_params_prepare,
+};
+
+/* Blocks the IFE does not implement, the OPE's among them */
+static int vfe_params_block_unsupported(struct device *dev,
+					const struct v4l2_isp_block_header *block)
+{
+	dev_dbg(dev, "Unsupported parameters block type %u\n", block->type);
+
+	return -EINVAL;
+}
+
+static int vfe_params_aec_bhist_validate(struct device *dev,
+					 const struct v4l2_isp_block_header *block)
+{
+	const struct camss_params_aec_bhist *bhist =
+		container_of(block, struct camss_params_aec_bhist, header);
+
+	if ((bhist->left | bhist->top | bhist->width | bhist->height) & 1 ||
+	    bhist->width < 2 || bhist->height < 2) {
+		dev_dbg(dev, "Invalid AEC BHIST region %ux%u@%u,%u\n",
+			bhist->width, bhist->height, bhist->left, bhist->top);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Every type up to the last one the IFE accepts has an entry, so that no
+ * block passes validation with a size of zero.
+ */
+static const struct v4l2_isp_params_block_type_info vfe_params_info[] = {
+	[0] = {
+		.size = sizeof(struct v4l2_isp_params_block_header),
+		.block_validate = vfe_params_block_unsupported,
+	},
+	[CAMSS_PARAMS_WB_GAIN] = {
+		.size = sizeof(struct camss_params_wb_gain),
+		.block_validate = vfe_params_block_unsupported,
+	},
+	[CAMSS_PARAMS_CHROMA_ENHAN] = {
+		.size = sizeof(struct camss_params_chroma_enhan),
+		.block_validate = vfe_params_block_unsupported,
+	},
+	[CAMSS_PARAMS_COLOR_CORRECT] = {
+		.size = sizeof(struct camss_params_color_correct),
+		.block_validate = vfe_params_block_unsupported,
+	},
+	[CAMSS_PARAMS_GAMMA] = {
+		.size = sizeof(struct camss_params_gamma),
+		.block_validate = vfe_params_block_unsupported,
+	},
+	[CAMSS_PARAMS_AEC_BHIST] = {
+		.size = sizeof(struct camss_params_aec_bhist),
+		.block_validate = vfe_params_aec_bhist_validate,
+	},
 };
+
+/* Clip the region to the Bayer frame entering the line, then count quads */
+static void vfe_params_aec_bhist(struct vfe_device *vfe, struct vfe_line *line,
+				 const struct camss_params_aec_bhist *bhist)
+{
+	u32 frame_w = line->fmt[MSM_VFE_PAD_SINK].width & ~1u;
+	u32 frame_h = line->fmt[MSM_VFE_PAD_SINK].height & ~1u;
+	u32 left, top, width, height;
+
+	if (frame_w < 2 || frame_h < 2)
+		return;
+
+	left = min_t(u32, bhist->left, frame_w - 2);
+	top = min_t(u32, bhist->top, frame_h - 2);
+	width = min_t(u32, bhist->width, frame_w - left);
+	height = min_t(u32, bhist->height, frame_h - top);
+
+	vfe_880_set_aec_bhist_region(vfe, left / 2, top / 2,
+				     width / 2 - 1, height / 2 - 1);
+}
+
+static void vfe_params_apply(struct vfe_device *vfe, struct vfe_line *line,
+			     const struct v4l2_isp_buffer *params)
+{
+	size_t offset = 0;
+
+	/* validated at prepare: every block fits and has a non-zero size */
+	while (offset < params->data_size) {
+		const struct v4l2_isp_block_header *block =
+			(const struct v4l2_isp_block_header *)&params->data[offset];
+
+		if (block->type == CAMSS_PARAMS_AEC_BHIST &&
+		    !(block->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE))
+			vfe_params_aec_bhist(vfe, line,
+					     container_of(block,
+							  struct camss_params_aec_bhist,
+							  header));
+
+		offset += block->size;
+	}
+}
 static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
 {
 	struct vfe_line *pix = &vfe->line[VFE_LINE_PIX];
@@ -336,6 +436,9 @@ const struct vfe_hw_ops vfe_ops_780 = {
 	.vfe_disable = vfe_disable,
 	.vfe_enable = vfe_enable_v2,
 	.vfe_line_prepare = vfe_line_prepare,
+	.params_info = vfe_params_info,
+	.params_num_types = ARRAY_SIZE(vfe_params_info),
+	.vfe_params_apply = vfe_params_apply,
 	.vfe_halt = vfe_halt,
 	.vfe_wm_start = vfe_wm_start,
 	.vfe_wm_stop = vfe_wm_stop,
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 a4bccedb4a2f1..9b4bdad6d3963 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.c
@@ -460,6 +460,23 @@ static void vfe_setup_aec_bhist(struct vfe_device *vfe, u32 w, u32 h)
 	writel_relaxed(0x00000000, vfe->base + IFE_STATS_AEC_BHIST_MODULE_LUT_BANK_CFG);
 }
 
+/*
+ * vfe_880_set_aec_bhist_region - Select the region the AEC BHIST counts
+ * @vfe: VFE device
+ * @h_offset: horizontal offset, in 2x2 quads
+ * @v_offset: vertical offset, in 2x2 quads
+ * @h_num: width, in 2x2 quads, minus one
+ * @v_num: height, in 2x2 quads, minus one
+ */
+void vfe_880_set_aec_bhist_region(struct vfe_device *vfe, u32 h_offset,
+				  u32 v_offset, u32 h_num, u32 v_num)
+{
+	writel_relaxed(((v_offset & 0x3fff) << 16) | (h_offset & 0x3fff),
+		       vfe->base + IFE_STATS_AEC_BHIST_RGN_OFFSET_CFG);
+	writel_relaxed(((v_num & 0x1fff) << 16) | (h_num & 0x1fff),
+		       vfe->base + IFE_STATS_AEC_BHIST_RGN_NUM_CFG);
+}
+
 /* Main output round/clamp: round mode 2, clamp 0..255 */
 static void vfe_setup_main_output_round_clamp(struct vfe_device *vfe)
 {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h
index 32f0a14e5b95a..e033880e5534d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe-880-pp.h
@@ -7,5 +7,7 @@
 struct vfe_device;
 
 void vfe_880_setup_pixel_pipe(struct vfe_device *vfe, u32 width, u32 height);
+void vfe_880_set_aec_bhist_region(struct vfe_device *vfe, u32 h_offset,
+				  u32 v_offset, u32 h_num, u32 v_num);
 
 #endif

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 73/74] media: qcom: camss: vfe-780: Drive the write masters through the output ops
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (71 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 72/74] media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters bod
@ 2026-10-05 17:14 ` bod
  2026-10-05 17:14 ` [PATCH 74/74] media: qcom: camss: vfe: Pass the write master its address again bod
  2026-10-06  7:06 ` [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Jacopo Mondi
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

vfe-780 implemented its outputs inside the write master ops: given one
write master, it ignored it, looked up the output it belongs to and
programmed every write master of that output.

Implement vfe_output_start(), vfe_output_update() and vfe_output_stop()
instead. Each gets the output and programs its group of write masters:
the Y and CbCr planes of the PIX output, the statistics write master,
or the single write master of an RDI. The reverse lookup from write
master to statistics output goes away.

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-780.c | 110 ++++++++--------------
 1 file changed, 41 insertions(+), 69 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-780.c
index 33247e6de898c..6d483f917d151 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-780.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-780.c
@@ -84,10 +84,9 @@ typedef enum {
 #define VFE_BUS_WM_MMU_PREFETCH_CFG(n)		(BUS_REG_BASE + 0x260 + (n) * 0x100)
 #define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n)	(BUS_REG_BASE + 0x264 + (n) * 0x100)
 
-/* One write master per plane of the PIX output: Y, then CbCr at half height */
-static void vfe_wm_start_pix(struct vfe_device *vfe, struct vfe_line *line)
+/* Each write master of the PIX output writes one plane: Y, then CbCr at half height */
+static void vfe_output_start_pix(struct vfe_device *vfe, struct vfe_output *output)
 {
-	struct vfe_output *output = &line->output[0];
 	struct v4l2_pix_format_mplane *pix = &output->video_out.active_fmt.fmt.pix_mp;
 	unsigned int i;
 
@@ -116,24 +115,8 @@ static void vfe_wm_start_pix(struct vfe_device *vfe, struct vfe_line *line)
 	}
 }
 
-static struct vfe_output *vfe_stats_output(struct vfe_line *line, u8 wm)
-{
-	unsigned int o;
-
-	if (!line->is_pix)
-		return NULL;
-
-	for (o = 1; o < line->num_outputs; o++)
-		if (line->output[o].pad == MSM_VFE_PAD_SRC_STATS &&
-		    line->output[o].wm_num &&
-		    line->output[o].wm[0].bus_client == wm)
-			return &line->output[o];
-
-	return NULL;
-}
-
 /* Statistics write masters are frame based and fill the output's kernel buffer */
-static void vfe_wm_start_stats(struct vfe_device *vfe, struct vfe_output *output)
+static void vfe_output_start_stats(struct vfe_device *vfe, struct vfe_output *output)
 {
 	u8 wm = output->wm[0].bus_client;
 
@@ -155,29 +138,11 @@ static void vfe_wm_start_stats(struct vfe_device *vfe, struct vfe_output *output
 	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+/* An RDI output has one line based write master dumping the CSI-2 payload */
+static void vfe_output_start_rdi(struct vfe_device *vfe, struct vfe_output *output)
 {
-	struct vfe_output *stats = vfe_stats_output(line, wm);
-
-	struct v4l2_pix_format_mplane *pix =
-		&line->output[0].video_out.active_fmt.fmt.pix_mp;
-
-	wm = line->output[0].wm[0].bus_client;
-
-	/* no clock gating at bus input */
-	writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
-
-	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
-
-	if (stats) {
-		vfe_wm_start_stats(vfe, stats);
-		return;
-	}
-
-	if (line->is_pix) {
-		vfe_wm_start_pix(vfe, line);
-		return;
-	}
+	struct v4l2_pix_format_mplane *pix = &output->video_out.active_fmt.fmt.pix_mp;
+	u8 wm = output->wm[0].bus_client;
 
 	writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8,
 	       vfe->base + VFE_BUS_WM_FRAME_INCR(wm));
@@ -200,42 +165,49 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(WM_CFG_EN | WM_CFG_MODE, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+static void vfe_output_start(struct vfe_device *vfe, struct vfe_output *output)
 {
-	struct vfe_output *output = &line->output[0];
-	unsigned int i;
+	/* no clock gating at bus input */
+	writel(WM_CGC_OVERRIDE_ALL, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
 
-	if (vfe_stats_output(line, wm)) {
-		writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
-		return;
-	}
+	writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+	if (output->pad == MSM_VFE_PAD_SRC_STATS)
+		vfe_output_start_stats(vfe, output);
+	else if (output->line->is_pix)
+		vfe_output_start_pix(vfe, output);
+	else
+		vfe_output_start_rdi(vfe, output);
+}
+
+static void vfe_output_stop(struct vfe_device *vfe, struct vfe_output *output)
+{
+	unsigned int i;
 
 	for (i = 0; i < output->wm_num; i++)
 		writel(0, vfe->base + VFE_BUS_WM_CFG(output->wm[i].bus_client));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
-			  struct vfe_line *line)
+static void vfe_output_update(struct vfe_device *vfe, struct vfe_output *output,
+			      struct camss_buffer *buf)
 {
-	struct vfe_output *output = &line->output[0];
-	struct vfe_output *stats;
 	unsigned int i;
 
-	/*
-	 * Each frame consumes one programmed address, as for images: hand the
-	 * write master the output's kernel buffer once per queued buffer.
-	 */
-	stats = vfe_stats_output(line, wm);
-	if (stats) {
-		writel(stats->dma_addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
-		return;
-	}
-
-	/* camss-video sets addr[1] = addr[0] + bytesperline * height for NV12 */
 	for (i = 0; i < output->wm_num; i++) {
-		u32 addr = buffer->addr[output->wm[i].plane];
+		u8 wm = output->wm[i].bus_client;
+		u32 addr;
+
+		/*
+		 * Each frame consumes one programmed address. Statistics land
+		 * in the output's kernel buffer, handed over once per queued
+		 * buffer; camss-video sets addr[1] = addr[0] + bytesperline *
+		 * height for NV12.
+		 */
+		if (output->pad == MSM_VFE_PAD_SRC_STATS)
+			addr = output->dma_addr;
+		else
+			addr = buf->addr[output->wm[i].plane];
 
-		wm = output->wm[i].bus_client;
 		writel(addr >> 8, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 
 		dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n",
@@ -440,8 +412,8 @@ const struct vfe_hw_ops vfe_ops_780 = {
 	.params_num_types = ARRAY_SIZE(vfe_params_info),
 	.vfe_params_apply = vfe_params_apply,
 	.vfe_halt = vfe_halt,
-	.vfe_wm_start = vfe_wm_start,
-	.vfe_wm_stop = vfe_wm_stop,
 	.vfe_buf_done = vfe_buf_done,
-	.vfe_wm_update = vfe_wm_update,
+	.vfe_output_start = vfe_output_start,
+	.vfe_output_stop = vfe_output_stop,
+	.vfe_output_update = vfe_output_update,
 };

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH 74/74] media: qcom: camss: vfe: Pass the write master its address again
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (72 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 73/74] media: qcom: camss: vfe-780: Drive the write masters through the output ops bod
@ 2026-10-05 17:14 ` bod
  2026-10-06  7:06 ` [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Jacopo Mondi
  74 siblings, 0 replies; 76+ messages in thread
From: bod @ 2026-10-05 17:14 UTC (permalink / raw)
  To: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov
  Cc: linux-media, linux-arm-msm, linux-kernel, Bryan O'Donoghue

From: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

With vfe-780 programming its planes through vfe_output_update(), no
backend needs the buffer in vfe_wm_update() any more. Go back to passing
the write master its address.

This reverts commit "media: qcom: camss: vfe: Pass the buffer to
vfe_wm_update()".

Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-17x.c | 5 ++---
 drivers/media/platform/qcom/camss/camss-vfe-340.c | 3 +--
 drivers/media/platform/qcom/camss/camss-vfe-480.c | 3 +--
 drivers/media/platform/qcom/camss/camss-vfe-680.c | 5 ++---
 drivers/media/platform/qcom/camss/camss-vfe-690.c | 4 +---
 drivers/media/platform/qcom/camss/camss-vfe.c     | 6 +++---
 drivers/media/platform/qcom/camss/camss-vfe.h     | 2 +-
 7 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index a2d336e7f7aa9..52812d34530d6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -253,13 +253,12 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
 	struct v4l2_pix_format_mplane *pix =
 		&line->output[0].video_out.active_fmt.fmt.pix_mp;
 	u32 stride = pix->plane_fmt[0].bytesperline;
-	u32 addr = buffer->addr[0];
 
 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
@@ -542,7 +541,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 	output->buf[index] = vfe_buf_get_pending(output);
 
 	if (output->buf[index])
-		vfe_wm_update(vfe, output->wm[0].bus_client, output->buf[index], line);
+		vfe_wm_update(vfe, output->wm[0].bus_client, output->buf[index]->addr[0], line);
 	else
 		output->gen2.active_num--;
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c
index 708dad42186f9..051f270a38187 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-340.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c
@@ -252,10 +252,9 @@ 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 wm, struct camss_buffer *buffer,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
-	u32 addr = buffer->addr[0];
 	u8 client = tfe_wm_client_map[wm];
 
 	writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(client));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index bb065e47fe91e..75dc73eadd6d0 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -133,10 +133,9 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
-	u32 addr = buffer->addr[0];
 	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
 	writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
 }
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-680.c b/drivers/media/platform/qcom/camss/camss-vfe-680.c
index 242bacb051cc0..d9a6402e8d928 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-680.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-680.c
@@ -144,11 +144,10 @@ static void vfe_disable_irq(struct vfe_device *vfe)
 	writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 1));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
+static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr,
 			  struct vfe_line *line)
 {
-	u32 addr = buffer->addr[0];
-	wm = RDI_WM(wm); /* map to actual WM used (from wm=RDI index) */
+	u8 wm = RDI_WM(rdi);
 
 	writel(addr, vfe->base + VFE_BUS_IMAGE_ADDR(vfe, wm));
 }
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-690.c b/drivers/media/platform/qcom/camss/camss-vfe-690.c
index efe8d963b4703..fb40560d4ab41 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-690.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-690.c
@@ -96,11 +96,9 @@ static void vfe_wm_stop(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
 	writel(0, vfe->base + VFE_BUS_WM_CFG(wm));
 }
 
-static void vfe_wm_update(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
+static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr,
 			  struct vfe_line *line)
 {
-	u32 addr = buffer->addr[0];
-
 	wm = RDI_WM(wm);
 
 	writel(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm));
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 5c72357bb8f02..485feb0bd7420 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -822,7 +822,7 @@ static struct camss_buffer *vfe_output_done(struct vfe_device *vfe,
 			ops->vfe_output_update(vfe, output, output->buf[index]);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   output->buf[index],
+					   output->buf[index]->addr[0],
 					   line);
 		ops->reg_update(vfe, line->id);
 	} else {
@@ -942,7 +942,7 @@ static int vfe_enable_one_output(struct vfe_line *line, struct vfe_output *outpu
 			ops->vfe_output_update(vfe, output, output->buf[i]);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   output->buf[i], line);
+					   output->buf[i]->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	}
 
@@ -1016,7 +1016,7 @@ int vfe_queue_buffer_v2(struct camss_video *vid,
 			ops->vfe_output_update(vfe, output, buf);
 		else
 			ops->vfe_wm_update(vfe, output->wm[0].bus_client,
-					   buf, line);
+					   buf->addr[0], line);
 		ops->reg_update(vfe, line->id);
 	} else {
 		vfe_buf_add_pending(output, buf);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index b39bce17f8dec..f7d9070391163 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -196,7 +196,7 @@ struct vfe_hw_ops {
 			    struct vfe_line *line);
 	void (*vfe_buf_done)(struct vfe_device *vfe, int port_id,
 			     struct camss_buf_done_info *buf_done_info);
-	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, struct camss_buffer *buffer,
+	void (*vfe_wm_update)(struct vfe_device *vfe, u8 wm, u32 addr,
 			      struct vfe_line *line);
 
 	/*

-- 
2.55.0


^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650
  2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
                   ` (73 preceding siblings ...)
  2026-10-05 17:14 ` [PATCH 74/74] media: qcom: camss: vfe: Pass the write master its address again bod
@ 2026-10-06  7:06 ` Jacopo Mondi
  74 siblings, 0 replies; 76+ messages in thread
From: Jacopo Mondi @ 2026-10-06  7:06 UTC (permalink / raw)
  To: Bryan O'Donoghue
  Cc: Bryan O'Donoghue, Vladimir Zapolskiy, Loic Poulain,
	Mauro Carvalho Chehab, Jacopo Mondi, Daniel Scally, Keke Li,
	Richard Acayan, Hans Verkuil, Gjorgji Rosikopulos,
	Radoslav Tsvetkov, Robert Foss, Milen Mitkov, linux-media,
	linux-arm-msm, linux-kernel, Antoine Bouyer,
	Niklas Söderlund, Sakari Ailus, stable

Hi Bryan

On Mon, Oct 05, 2026 at 07:13:30PM +0200, Bryan O'Donoghue wrote:
> This extensive series restructures CAMSS around the idea of lines and
> outputs more closely matching the concepts in the camera hardware.
>
> To begin with some bug fixing and some dependencies on the OPE series are
> pulled in.
>
> Following that a series of changes to enable the IFE hardware is introduced
> for VFE780.
>
> Supported in this drop:
>
> - YUV output on the pix path
>   YUV downscale 16 and downscale 4 work on a staging branch
>   but with this series at 60 patches I've not included that.
>
> - Stats output
>   Bayer histogram only
>
>   How many stats are intended to be brought out this way ?
>   Consider that scene in The Terminator when the guy in the gun
>   store.
>
>   Gun store owner: "So which will it be"
>   The Terminator: "All"
>
>   More seriously once this series lands then it will be possible to bring
>   out stats for Agatti mitigating the need for calculating stats in
>   software.
>
> - Params application
>   AEC Bayer hist params
>
>   Again there are no limits envisaged on which params are to be enabled.
>
>   "All"
>
> - Testing on HDK sm8650
>
>   There is a repo to test this stuff out:
>
>   https://github.com/0xB0D/ife-tests
>
> Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
> ---
> Antoine Bouyer (2):
>       media: uapi: v4l2-isp: Add extensible statistics
>       media: Documentation: uapi: Update V4L2 ISP for extensible stats
>
> Bryan O'Donoghue (66):
>       media: qcom: camss: vfe: Rename gen3 back to vfe780
>       media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880
>       media: qcom: camss: Fix invalid declaration of PIX for SDM670
>       media: qcom: camss: Fix invalid declaration of PIX for SDM845
>       media: qcom: camss: Fix invalid declaration of PIX for sc8280xp
>       media: qcom: camss: Fix invalid declaration of PIX for x1e80100
>       media: qcom: camss: csid: Configure the stream on every s_stream
>       media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845
>       media: qcom: camss: Define PIX formats for x1e PIX interface
>       media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt()
>       media: qcom: camss: vfe: Represent output as an array instead of a singleton
>       media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output
>       media: qcom: camss: vfe: Represent vfe wm inside of a struct
>       media: qcom: camss: vfe: Add is_pix to struct line
>       media: qcom: camss: vfe: Add comp_group to struct vfe_wm
>       media: qcom: camss: vfe: Define vfe v3 completion group enum
>       media: qcom: camss: vfe: Define output based VFE controls
>       media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration
>       media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init
>       media: qcom: camss: vfe: Add planes identifier to struct wm
>       media: qcom: camss: vfe: Specify number of pads via line->num_pads
>       media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group
>       media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group
>       media: qcom: camss: vfe: Update an output group's write masters on buffer done
>       media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters
>       media: qcom: camss: vfe: Stop an output group once
>       media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw
>       media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern
>       media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default()
>       media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic
>       media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX
>       media: qcom: camss: vfe-gen3: Define full array of write-masters
>       media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces
>       media: qcom: camss: vfe: Pass struct line to wm_stop
>       media: qcom: camss: vfe-780: Use bus-client to derive write master index
>       media: qcom: camss: vfe-780: Switch on YUV pix path
>       media: qcom: camss: vfe: Add support for pix pad data-types
>       media: qcom: camss: vfe: Add helper methods to enumerate output descriptors
>       media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done
>       media: qcom: camss: Add a status field to camss_buf_done_info
>       media: qcom: camss: csid-gen3: Enable the IPP path
>       media: qcom: camss: vfe: Pass the completion info to vfe_buf_done()
>       media: qcom: camss: vfe: Pass the buffer to vfe_wm_update()
>       media: qcom: camss: Add the SM8650 IFE pixel pipe configuration
>       media: qcom: camss: csid-gen3: Define the IPP reg update port in the header
>       media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock
>       media: qcom: camss: vfe: Make is_pix the only test for the pixel path
>       media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds
>       media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line
>       media: uapi: Add CAMSS ISP statistics definition
>       media: Documentation: uapi: Add qcom-camss ISP statistics
>       media: qcom: camss: vfe: Select line-based mode for the pixel path's video node
>       media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock
>       media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one
>       media: qcom: camss: video: Support metadata capture nodes
>       media: qcom: camss: vfe: Register a statistics node for the pixel line
>       media: qcom: camss: vfe: Complete pixel line outputs on their own completion group
>       media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics
>       media: uapi: Add the CAMSS AEC Bayer histogram configuration
>       media: v4l2: Add the Qualcomm CAMSS ISP parameters format
>       media: Documentation: uapi: Add the CAMSS IFE parameters
>       media: qcom: camss: video: Support metadata output nodes
>       media: qcom: camss: vfe: Register and apply a parameters node for the pixel line
>       media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters
>       media: qcom: camss: vfe-780: Drive the write masters through the output ops
>       media: qcom: camss: vfe: Pass the write master its address again
>
> Jacopo Mondi (4):
>       media: v4l2-isp: Rename v4l2_isp_params_buffer_size
>       media: v4l2-isp: Add per-block validation callback
>       media: amlogic-c3: Implement per-block validation
>       media: v4l2-isp: Add helpers for stats buffer

What branch are you based on ? This has been collected for 7.3 and
if you base your work on media-committers/next you should find it
there

Thanks
  j

>
> Loic Poulain (2):
>       media: uapi: Add CAMSS ISP configuration definition
>       media: Documentation: uapi: Add qcom-camss ISP params documentation
>
>  .../userspace-api/media/v4l/meta-formats.rst       |   1 +
>  .../userspace-api/media/v4l/metafmt-qcom-isp.rst   | 219 +++++
>  Documentation/userspace-api/media/v4l/v4l2-isp.rst |  45 +-
>  MAINTAINERS                                        |   1 +
>  .../media/platform/amlogic/c3/isp/c3-isp-params.c  |  42 +-
>  .../media/platform/arm/mali-c55/mali-c55-params.c  |  12 +-
>  drivers/media/platform/qcom/camss/Kconfig          |   2 +
>  drivers/media/platform/qcom/camss/Makefile         |   4 +-
>  drivers/media/platform/qcom/camss/camss-csid-680.c |   8 +-
>  .../media/platform/qcom/camss/camss-csid-gen3.c    | 131 ++-
>  .../media/platform/qcom/camss/camss-csid-gen3.h    |   3 +
>  drivers/media/platform/qcom/camss/camss-csid.c     |  37 +-
>  drivers/media/platform/qcom/camss/camss-csid.h     |  18 +-
>  drivers/media/platform/qcom/camss/camss-vfe-17x.c  |  10 +-
>  drivers/media/platform/qcom/camss/camss-vfe-340.c  |  12 +-
>  drivers/media/platform/qcom/camss/camss-vfe-4-1.c  |  20 +-
>  drivers/media/platform/qcom/camss/camss-vfe-4-7.c  |  34 +-
>  drivers/media/platform/qcom/camss/camss-vfe-4-8.c  |  34 +-
>  drivers/media/platform/qcom/camss/camss-vfe-480.c  |  19 +-
>  drivers/media/platform/qcom/camss/camss-vfe-680.c  |   4 +-
>  .../camss/{camss-vfe-gen3.c => camss-vfe-690.c}    |  53 +-
>  drivers/media/platform/qcom/camss/camss-vfe-780.c  | 419 +++++++++
>  .../media/platform/qcom/camss/camss-vfe-880-pp.c   | 629 +++++++++++++
>  .../media/platform/qcom/camss/camss-vfe-880-pp.h   |  13 +
>  drivers/media/platform/qcom/camss/camss-vfe-gen1.c |  96 +-
>  drivers/media/platform/qcom/camss/camss-vfe.c      | 985 ++++++++++++++++++---
>  drivers/media/platform/qcom/camss/camss-vfe.h      | 156 +++-
>  drivers/media/platform/qcom/camss/camss-video.c    | 235 ++++-
>  drivers/media/platform/qcom/camss/camss-video.h    |   8 +
>  drivers/media/platform/qcom/camss/camss.c          | 156 ++--
>  drivers/media/platform/qcom/camss/camss.h          |   8 +-
>  drivers/media/v4l2-core/v4l2-ioctl.c               |   2 +
>  drivers/media/v4l2-core/v4l2-isp.c                 |  55 ++
>  include/media/v4l2-isp.h                           |  94 +-
>  include/uapi/linux/media/v4l2-isp.h                | 125 ++-
>  include/uapi/linux/qcom-camss-config.h             | 273 ++++++
>  include/uapi/linux/videodev2.h                     |   4 +
>  37 files changed, 3464 insertions(+), 503 deletions(-)
> ---
> base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
> change-id: 20261005-linux-mainline-7-2-sm8650-hdk-rfc-0-aa75cdf2c39b
>
> Best regards,
> --
> Bryan O'Donoghue <bod@kernel.org>
>

^ permalink raw reply	[flat|nested] 76+ messages in thread

end of thread, other threads:[~2026-10-06  7:06 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-05 17:13 [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 01/74] media: qcom: camss: vfe: Rename gen3 back to vfe780 Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 02/74] media: qcom: camss: vfe: Separate VFE 690 from VFE 780/880 Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 03/74] media: uapi: v4l2-isp: Add extensible statistics bod
2026-10-05 17:13 ` [PATCH 04/74] media: Documentation: uapi: Update V4L2 ISP for extensible stats bod
2026-10-05 17:13 ` [PATCH 05/74] media: v4l2-isp: Rename v4l2_isp_params_buffer_size bod
2026-10-05 17:13 ` [PATCH 06/74] media: v4l2-isp: Add per-block validation callback bod
2026-10-05 17:13 ` [PATCH 07/74] media: amlogic-c3: Implement per-block validation bod
2026-10-05 17:13 ` [PATCH 08/74] media: v4l2-isp: Add helpers for stats buffer bod
2026-10-05 17:13 ` [PATCH 09/74] media: uapi: Add CAMSS ISP configuration definition bod
2026-10-05 17:13 ` [PATCH 10/74] media: Documentation: uapi: Add qcom-camss ISP params documentation bod
2026-10-05 17:13 ` [PATCH 11/74] media: qcom: camss: Fix invalid declaration of PIX for SDM670 bod
2026-10-05 17:13 ` [PATCH 12/74] media: qcom: camss: Fix invalid declaration of PIX for SDM845 bod
2026-10-05 17:13 ` [PATCH 13/74] media: qcom: camss: Fix invalid declaration of PIX for sc8280xp bod
2026-10-05 17:13 ` [PATCH 14/74] media: qcom: camss: Fix invalid declaration of PIX for x1e80100 bod
2026-10-05 17:13 ` [PATCH 15/74] media: qcom: camss: csid: Configure the stream on every s_stream bod
2026-10-05 17:13 ` [PATCH 16/74] media: qcom: camss: Switch existing vfe_formats_pix_845 to vfe_formats_rdi_845 Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 17/74] media: qcom: camss: Define PIX formats for x1e PIX interface Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 18/74] media: qcom: camss: vfe: Add helper vfe_bus_v3_packer_fmt() Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 19/74] media: qcom: camss: vfe: Represent output as an array instead of a singleton Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 20/74] media: qcom: camss: vfe: Move video_out from vfe_line to vfe_output Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 21/74] media: qcom: camss: vfe: Represent vfe wm inside of a struct Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 22/74] media: qcom: camss: vfe: Add is_pix to struct line Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 23/74] media: qcom: camss: vfe: Add comp_group to struct vfe_wm Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 24/74] media: qcom: camss: vfe: Define vfe v3 completion group enum Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 25/74] media: qcom: camss: vfe: Define output based VFE controls Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 26/74] media: qcom: camss: vfe: Call vfe_subdev_init after not before significant enumeration Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 27/74] media: qcom: camss: vfe: Move legacy VFE bus client assignment to msm_vfe_subdev_init Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 28/74] media: qcom: camss: vfe: Add planes identifier to struct wm Bryan O'Donoghue
2026-10-05 17:13 ` [PATCH 29/74] media: qcom: camss: vfe: Specify number of pads via line->num_pads Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 30/74] media: qcom: camss: vfe: Add support for starting multiple write-masters in one output's group Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 31/74] media: qcom: camss: vfe: Add support for updating multiple write-masters within an output group Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 32/74] media: qcom: camss: vfe: Update an output group's write masters on buffer done bod
2026-10-05 17:14 ` [PATCH 33/74] media: qcom: camss: vfe: Add support for stopping outputs which contain multiple write masters Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 34/74] media: qcom: camss: vfe: Stop an output group once bod
2026-10-05 17:14 ` [PATCH 35/74] media: qcom: camss: vfe: Add helper __vfe_pix_format_is_raw Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 36/74] media: qcom: camss: csid: Add helper function csid_ipp_bayer_pattern bod
2026-10-05 17:14 ` [PATCH 37/74] media: qcom: camss: vfe: Decompose repeated code down to __vfe_src_pad_default() Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 38/74] media: qcom: camss: vfe: Eliminate ever expanding src_pad_code switch logic Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 39/74] media: qcom: camss: vfe: Add Bayer to YUV conversion switch cases for PIX Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 40/74] media: qcom: camss: vfe-gen3: Define full array of write-masters Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 41/74] media: qcom: camss: vfe-gen3: Enable PIX formats on PIX interfaces Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 42/74] media: qcom: camss: vfe: Pass struct line to wm_stop Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 43/74] media: qcom: camss: vfe-780: Use bus-client to derive write master index Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 44/74] media: qcom: camss: vfe-780: Switch on YUV pix path Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 45/74] media: qcom: camss: vfe: Add support for pix pad data-types Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 46/74] media: qcom: camss: vfe: Add helper methods to enumerate output descriptors Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 47/74] media: qcom: camss: Pass new struct camss_buf_done_info to camss_buf_done bod
2026-10-05 17:14 ` [PATCH 48/74] media: qcom: camss: Add a status field to camss_buf_done_info bod
2026-10-05 17:14 ` [PATCH 49/74] media: qcom: camss: csid-gen3: Enable the IPP path bod
2026-10-05 17:14 ` [PATCH 50/74] media: qcom: camss: vfe: Pass the completion info to vfe_buf_done() bod
2026-10-05 17:14 ` [PATCH 51/74] media: qcom: camss: vfe: Pass the buffer to vfe_wm_update() bod
2026-10-05 17:14 ` [PATCH 52/74] media: qcom: camss: Add the SM8650 IFE pixel pipe configuration bod
2026-10-05 17:14 ` [PATCH 53/74] media: qcom: camss: csid-gen3: Define the IPP reg update port in the header bod
2026-10-05 17:14 ` [PATCH 54/74] media: qcom: camss: vfe-880: Program the pixel pipe outside output_lock Bryan O'Donoghue
2026-10-05 17:14 ` [PATCH 55/74] media: qcom: camss: vfe: Make is_pix the only test for the pixel path bod
2026-10-05 17:14 ` [PATCH 56/74] media: qcom: camss: csid-gen3: Route IPP completions to the port the IPP feeds bod
2026-10-05 17:14 ` [PATCH 57/74] media: qcom: camss: vfe-780: Add full-resolution YUV on the PIX line bod
2026-10-05 17:14 ` [PATCH 58/74] media: uapi: Add CAMSS ISP statistics definition bod
2026-10-05 17:14 ` [PATCH 59/74] media: Documentation: uapi: Add qcom-camss ISP statistics bod
2026-10-05 17:14 ` [PATCH 60/74] media: qcom: camss: vfe: Select line-based mode for the pixel path's video node bod
2026-10-05 17:14 ` [PATCH 61/74] media: qcom: camss: vfe: Size the pixel path clock by its pixels per clock bod
2026-10-05 17:14 ` [PATCH 62/74] media: qcom: camss: vfe: Size the outputs for the PIX line and set up each one bod
2026-10-05 17:14 ` [PATCH 63/74] media: qcom: camss: video: Support metadata capture nodes bod
2026-10-05 17:14 ` [PATCH 64/74] media: qcom: camss: vfe: Register a statistics node for the pixel line bod
2026-10-05 17:14 ` [PATCH 65/74] media: qcom: camss: vfe: Complete pixel line outputs on their own completion group bod
2026-10-05 17:14 ` [PATCH 66/74] media: qcom: camss: vfe-780: Produce the AEC Bayer histogram statistics bod
2026-10-05 17:14 ` [PATCH 67/74] media: uapi: Add the CAMSS AEC Bayer histogram configuration bod
2026-10-05 17:14 ` [PATCH 68/74] media: v4l2: Add the Qualcomm CAMSS ISP parameters format bod
2026-10-05 17:14 ` [PATCH 69/74] media: Documentation: uapi: Add the CAMSS IFE parameters bod
2026-10-05 17:14 ` [PATCH 70/74] media: qcom: camss: video: Support metadata output nodes bod
2026-10-05 17:14 ` [PATCH 71/74] media: qcom: camss: vfe: Register and apply a parameters node for the pixel line bod
2026-10-05 17:14 ` [PATCH 72/74] media: qcom: camss: vfe-780: Apply the AEC Bayer histogram parameters bod
2026-10-05 17:14 ` [PATCH 73/74] media: qcom: camss: vfe-780: Drive the write masters through the output ops bod
2026-10-05 17:14 ` [PATCH 74/74] media: qcom: camss: vfe: Pass the write master its address again bod
2026-10-06  7:06 ` [PATCH 00/74] RFC: Switch on IFE YUV, Stats and Params support for sm8650 Jacopo Mondi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®