All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 00/17] Add support for SDM845 Camera Subsystem
@ 2021-01-08 12:04 ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

This series implements support for the camera subsystem found in
the SDM845 SOCs and the Titan 170 ISP. The support is partial
in that it implements CSIPHY, CSID, and partial VFE support.

The Titan generation of the ISP diverges a fair amount from the
design of the previous architecture generation, CAMSS. As a result
some pretty invasive refactoring is done in this series. It also
means that at this time we're unable to implement support for all
of the IP blocks contained. This is due to a combination of legal
considerations with respect to the IP and its owner Qualcomm and
time & man hour constrains on the Linaro side.

The CSIPHY (CSI Physical Layer) & CSID (CSI Decoder) support is
complete, but the VFE (Video Front End, which is referred to as IFE
(Image Front End) in the Titan generation of ISPs) only has support
for the RDI (Raw Dump Interface) which allows the raw output of
the CSID to be written to memory.

The 2nd interface implemented in the VFE silicon is the PIX
interface, and camss does not support it for this generation of ISPs.
The reason for this is that the PIX interface is used for sending
image data to the BPS (Bayer Processing Section) & IPE (Image
Processing Engine), but both of these units are beyond the scope
of enabling basic ISP functionality for the SDM845.

Since the Titan architecture generation diverges quite a bit from
the CAMSS generation, a lot of pretty major refactoring is carried
out in this series. Both the CSID & VFE core paths are made more
general and hardware version specific parts are broken out.
The CSIPHY didn't require quite as radical changes and therefore
keeps its current form.

Tested on:
 - Qcom RB3 / db845c + camera mezzanine, which is SDM845 based
 - db410c + D3 Camera mezzanine, which is APQ8016 based
 
Branch:
 - https://git.linaro.org/people/robert.foss/linux.git/log/?h=camss_sdm845_v1


Robert Foss (17):
  media: camss: Fix comment using wrong function name
  media: camss: Fix vfe_isr comment typo
  media: camss: Add CAMSS_845 camss version
  media: camss: Make ISPIF subdevice optional
  media: camss: Refactor VFE HW version support
  media: camss: Add support for VFE hardware version Titan 170
  media: camss: Add missing format identifiers
  media: camss: Refactor CSID HW version support
  media: camss: Add support for CSID hardware version Titan 170
  media: camss: Add support for CSIPHY hardware version Titan 170
  media: camss: Remove per VFE power domain toggling
  media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss
  media: camss: Enable SDM845
  arm64: defconfig: Build Qcom CAMSS as module
  arm64: dts: sdm845: Add CAMSS ISP node
  arm64: dts: sdm845-db845c: Add CAMSS ISP node
  arm64: dts: sdm845-db845c: Enable ov8856 sensor and connect to ISP

 .../devicetree/bindings/media/qcom,camss.txt  |   51 +-
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts    |   28 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi          |  151 +++
 arch/arm64/configs/defconfig                  |    1 +
 drivers/media/platform/qcom/camss/Makefile    |    6 +
 .../platform/qcom/camss/camss-csid-170.c      |  602 +++++++++
 .../platform/qcom/camss/camss-csid-4-1.c      |  338 +++++
 .../platform/qcom/camss/camss-csid-4-7.c      |  406 ++++++
 .../media/platform/qcom/camss/camss-csid.c    |  620 +--------
 .../media/platform/qcom/camss/camss-csid.h    |  177 ++-
 .../qcom/camss/camss-csiphy-3ph-1-0.c         |  182 ++-
 .../media/platform/qcom/camss/camss-csiphy.c  |   66 +-
 .../media/platform/qcom/camss/camss-ispif.c   |  147 ++-
 .../media/platform/qcom/camss/camss-ispif.h   |    3 +-
 .../media/platform/qcom/camss/camss-vfe-170.c |  808 ++++++++++++
 .../media/platform/qcom/camss/camss-vfe-4-1.c |  119 +-
 .../media/platform/qcom/camss/camss-vfe-4-7.c |  240 ++--
 .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.c      |  760 +++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
 drivers/media/platform/qcom/camss/camss-vfe.c |  838 +-----------
 drivers/media/platform/qcom/camss/camss-vfe.h |  118 +-
 .../media/platform/qcom/camss/camss-video.c   |  100 ++
 drivers/media/platform/qcom/camss/camss.c     |  421 ++++--
 drivers/media/platform/qcom/camss/camss.h     |   17 +-
 25 files changed, 5630 insertions(+), 1845 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-170.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h

-- 
2.27.0


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

* [PATCH v1 00/17] Add support for SDM845 Camera Subsystem
@ 2021-01-08 12:04 ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

This series implements support for the camera subsystem found in
the SDM845 SOCs and the Titan 170 ISP. The support is partial
in that it implements CSIPHY, CSID, and partial VFE support.

The Titan generation of the ISP diverges a fair amount from the
design of the previous architecture generation, CAMSS. As a result
some pretty invasive refactoring is done in this series. It also
means that at this time we're unable to implement support for all
of the IP blocks contained. This is due to a combination of legal
considerations with respect to the IP and its owner Qualcomm and
time & man hour constrains on the Linaro side.

The CSIPHY (CSI Physical Layer) & CSID (CSI Decoder) support is
complete, but the VFE (Video Front End, which is referred to as IFE
(Image Front End) in the Titan generation of ISPs) only has support
for the RDI (Raw Dump Interface) which allows the raw output of
the CSID to be written to memory.

The 2nd interface implemented in the VFE silicon is the PIX
interface, and camss does not support it for this generation of ISPs.
The reason for this is that the PIX interface is used for sending
image data to the BPS (Bayer Processing Section) & IPE (Image
Processing Engine), but both of these units are beyond the scope
of enabling basic ISP functionality for the SDM845.

Since the Titan architecture generation diverges quite a bit from
the CAMSS generation, a lot of pretty major refactoring is carried
out in this series. Both the CSID & VFE core paths are made more
general and hardware version specific parts are broken out.
The CSIPHY didn't require quite as radical changes and therefore
keeps its current form.

Tested on:
 - Qcom RB3 / db845c + camera mezzanine, which is SDM845 based
 - db410c + D3 Camera mezzanine, which is APQ8016 based
 
Branch:
 - https://git.linaro.org/people/robert.foss/linux.git/log/?h=camss_sdm845_v1


Robert Foss (17):
  media: camss: Fix comment using wrong function name
  media: camss: Fix vfe_isr comment typo
  media: camss: Add CAMSS_845 camss version
  media: camss: Make ISPIF subdevice optional
  media: camss: Refactor VFE HW version support
  media: camss: Add support for VFE hardware version Titan 170
  media: camss: Add missing format identifiers
  media: camss: Refactor CSID HW version support
  media: camss: Add support for CSID hardware version Titan 170
  media: camss: Add support for CSIPHY hardware version Titan 170
  media: camss: Remove per VFE power domain toggling
  media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss
  media: camss: Enable SDM845
  arm64: defconfig: Build Qcom CAMSS as module
  arm64: dts: sdm845: Add CAMSS ISP node
  arm64: dts: sdm845-db845c: Add CAMSS ISP node
  arm64: dts: sdm845-db845c: Enable ov8856 sensor and connect to ISP

 .../devicetree/bindings/media/qcom,camss.txt  |   51 +-
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts    |   28 +-
 arch/arm64/boot/dts/qcom/sdm845.dtsi          |  151 +++
 arch/arm64/configs/defconfig                  |    1 +
 drivers/media/platform/qcom/camss/Makefile    |    6 +
 .../platform/qcom/camss/camss-csid-170.c      |  602 +++++++++
 .../platform/qcom/camss/camss-csid-4-1.c      |  338 +++++
 .../platform/qcom/camss/camss-csid-4-7.c      |  406 ++++++
 .../media/platform/qcom/camss/camss-csid.c    |  620 +--------
 .../media/platform/qcom/camss/camss-csid.h    |  177 ++-
 .../qcom/camss/camss-csiphy-3ph-1-0.c         |  182 ++-
 .../media/platform/qcom/camss/camss-csiphy.c  |   66 +-
 .../media/platform/qcom/camss/camss-ispif.c   |  147 ++-
 .../media/platform/qcom/camss/camss-ispif.h   |    3 +-
 .../media/platform/qcom/camss/camss-vfe-170.c |  808 ++++++++++++
 .../media/platform/qcom/camss/camss-vfe-4-1.c |  119 +-
 .../media/platform/qcom/camss/camss-vfe-4-7.c |  240 ++--
 .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.c      |  760 +++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
 drivers/media/platform/qcom/camss/camss-vfe.c |  838 +-----------
 drivers/media/platform/qcom/camss/camss-vfe.h |  118 +-
 .../media/platform/qcom/camss/camss-video.c   |  100 ++
 drivers/media/platform/qcom/camss/camss.c     |  421 ++++--
 drivers/media/platform/qcom/camss/camss.h     |   17 +-
 25 files changed, 5630 insertions(+), 1845 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-170.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h

-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 01/17] media: camss: Fix comment using wrong function name
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Function name is comment is wrong, and was changed to be
the same as the actual function name.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index fae2b513b2f9..478be4f0cab5 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 }
 
 /*
- * vfe_isr_wm_done - Process composite image done interrupt
+ * vfe_isr_comp_done - Process composite image done interrupt
  * @vfe: VFE Device
  * @comp: Composite image id
  */
-- 
2.27.0


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

* [PATCH v1 01/17] media: camss: Fix comment using wrong function name
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Function name is comment is wrong, and was changed to be
the same as the actual function name.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index fae2b513b2f9..478be4f0cab5 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
 }
 
 /*
- * vfe_isr_wm_done - Process composite image done interrupt
+ * vfe_isr_comp_done - Process composite image done interrupt
  * @vfe: VFE Device
  * @comp: Composite image id
  */
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Comment refers to ISPIF, but this is incorrect. Only
the VFE interrupts are handled by this function.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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 174a36be6f5d..a1b56b89130d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
 }
 
 /*
- * vfe_isr - ISPIF module interrupt handler
+ * vfe_isr - VFE module interrupt handler
  * @irq: Interrupt line
  * @dev: VFE device
  *
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 b5704a2f119b..84c33b8f9fe3 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
 }
 
 /*
- * vfe_isr - ISPIF module interrupt handler
+ * vfe_isr - VFE module interrupt handler
  * @irq: Interrupt line
  * @dev: VFE device
  *
-- 
2.27.0


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

* [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Comment refers to ISPIF, but this is incorrect. Only
the VFE interrupts are handled by this function.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
 drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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 174a36be6f5d..a1b56b89130d 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
 }
 
 /*
- * vfe_isr - ISPIF module interrupt handler
+ * vfe_isr - VFE module interrupt handler
  * @irq: Interrupt line
  * @dev: VFE device
  *
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 b5704a2f119b..84c33b8f9fe3 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
 }
 
 /*
- * vfe_isr - ISPIF module interrupt handler
+ * vfe_isr - VFE module interrupt handler
  * @irq: Interrupt line
  * @dev: VFE device
  *
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 03/17] media: camss: Add CAMSS_845 camss version
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add enum representing the SDM845 SOC, which incorporates version
170 of the Titan architecture ISP.

Signed-off-by: Robert Foss <robert.foss@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 3a0484683cd6..46e986452824 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -66,6 +66,7 @@ enum camss_version {
 	CAMSS_8x16,
 	CAMSS_8x96,
 	CAMSS_660,
+	CAMSS_845,
 };
 
 struct camss {
-- 
2.27.0


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

* [PATCH v1 03/17] media: camss: Add CAMSS_845 camss version
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add enum representing the SDM845 SOC, which incorporates version
170 of the Titan architecture ISP.

Signed-off-by: Robert Foss <robert.foss@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 3a0484683cd6..46e986452824 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -66,6 +66,7 @@ enum camss_version {
 	CAMSS_8x16,
 	CAMSS_8x96,
 	CAMSS_660,
+	CAMSS_845,
 };
 
 struct camss {
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

This driver supports multiple architecture versions of the Qualcomm ISP.
The CAMSS architecure which this driver is name after, and with the
introduction of this series, the Titan architecture.

The ISPIF is IP-block that is only present in the CAMSS architecture.
In order to support the Titan architecture, make the ISPIF an optional
subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
 .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
 drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
 drivers/media/platform/qcom/camss/camss.h     |   2 +-
 4 files changed, 160 insertions(+), 102 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index adeb92808998..0c804584dd65 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
 static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 {
 	struct ispif_device *ispif = dev;
+	struct camss *camss = ispif->camss;
 	u32 value0, value1, value2, value3, value4, value5;
 
 	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
@@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 		complete(&ispif->reset_complete[1]);
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
 
 	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
 
 	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
 
 	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
 
 	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
 
 	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
 
 	if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
 
 	return IRQ_HANDLED;
 }
@@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 static irqreturn_t ispif_isr_8x16(int irq, void *dev)
 {
 	struct ispif_device *ispif = dev;
+	struct camss *camss = ispif->camss;
 	u32 value0, value1, value2;
 
 	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
@@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
 		complete(&ispif->reset_complete[0]);
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
 
 	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
 
 	return IRQ_HANDLED;
 }
 
 static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
 {
+	struct camss *camss = ispif->camss;
+
 	unsigned long time;
 	u32 val;
 
-	if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
-		dev_err(to_device(ispif),
+	if (vfe_id > (camss->vfe_num - 1)) {
+		dev_err(camss->dev,
 			"Error: asked reset for invalid VFE%d\n", vfe_id);
 		return -ENOENT;
 	}
@@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
 	time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
 		msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
 	if (!time) {
-		dev_err(to_device(ispif),
+		dev_err(camss->dev,
 			"ISPIF for VFE%d reset timeout\n", vfe_id);
 		return -EIO;
 	}
@@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
  */
 static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 {
+	struct camss *camss = ispif->camss;
 	int ret;
 
-	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
+	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
 	if (ret < 0)
 		return ret;
 
-	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
+	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
 	if (ret < 0)
 		return ret;
 
 	ret = camss_enable_clocks(ispif->nclocks_for_reset,
 				  ispif->clock_for_reset,
-				  to_device(ispif));
+				  camss->dev);
 	if (ret < 0)
 		return ret;
 
 	ret = ispif_vfe_reset(ispif, vfe_id);
 	if (ret)
-		dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
+		dev_dbg(camss->dev, "ISPIF Reset failed\n");
 
 	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
 
-	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
-	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
+	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
+	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
 
 	return ret;
 }
@@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
 {
 	struct ispif_line *line = v4l2_get_subdevdata(sd);
 	struct ispif_device *ispif = line->ispif;
-	struct device *dev = to_device(ispif);
+	struct device *dev = ispif->camss->dev;
 	int ret = 0;
 
 	mutex_lock(&ispif->power_lock);
@@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
 	}
 
 	if ((val & 0xf) != 0xf) {
-		dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
+		dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
 			__func__, val);
 		ret = -EBUSY;
 	}
@@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
 				 ISPIF_TIMEOUT_SLEEP_US,
 				 ISPIF_TIMEOUT_ALL_US);
 	if (ret < 0)
-		dev_err(to_device(ispif), "%s: ispif stop timeout\n",
+		dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
 			__func__);
 
 	return ret;
@@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct ispif_line *line = v4l2_get_subdevdata(sd);
 	struct ispif_device *ispif = line->ispif;
+	struct camss *camss = ispif->camss;
 	enum ispif_intf intf = line->interface;
 	u8 csid = line->csid_id;
 	u8 vfe = line->vfe_id;
@@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 		ispif_select_csid(ispif, intf, csid, vfe, 1);
 		ispif_select_cid(ispif, intf, cid, vfe, 1);
 		ispif_config_irq(ispif, intf, vfe, 1);
-		if (to_camss(ispif)->version == CAMSS_8x96 ||
-		    to_camss(ispif)->version == CAMSS_660)
+		if (camss->version == CAMSS_8x96 ||
+		    camss->version == CAMSS_660)
 			ispif_config_pack(ispif,
 					  line->fmt[MSM_ISPIF_PAD_SINK].code,
 					  intf, cid, vfe, 1);
@@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 			return ret;
 
 		mutex_lock(&ispif->config_lock);
-		if (to_camss(ispif)->version == CAMSS_8x96 ||
-		    to_camss(ispif)->version == CAMSS_660)
+		if (camss->version == CAMSS_8x96 ||
+		    camss->version == CAMSS_660)
 			ispif_config_pack(ispif,
 					  line->fmt[MSM_ISPIF_PAD_SINK].code,
 					  intf, cid, vfe, 0);
@@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
  *
  * Return 0 on success or a negative error code otherwise
  */
-int msm_ispif_subdev_init(struct ispif_device *ispif,
+int msm_ispif_subdev_init(struct camss *camss,
 			  const struct resources_ispif *res)
 {
-	struct device *dev = to_device(ispif);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct ispif_device *ispif = camss->ispif;
+	struct platform_device *pdev = to_platform_device(camss->dev);
 	struct resource *r;
 	int i;
 	int ret;
 
+	if (res == NULL && ispif == NULL)
+		return 0;
+
+	ispif->camss = camss;
+
 	/* Number of ISPIF lines - same as number of CSID hardware modules */
-	if (to_camss(ispif)->version == CAMSS_8x16)
+	if (camss->version == CAMSS_8x16)
 		ispif->line_num = 2;
-	else if (to_camss(ispif)->version == CAMSS_8x96 ||
-		 to_camss(ispif)->version == CAMSS_660)
+	else if (camss->version == CAMSS_8x96 ||
+		 camss->version == CAMSS_660)
 		ispif->line_num = 4;
 	else
 		return -EINVAL;
 
-	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
-				   GFP_KERNEL);
+	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
+			sizeof(*ispif->line), GFP_KERNEL);
 	if (!ispif->line)
 		return -ENOMEM;
 
@@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 		ispif->line[i].ispif = ispif;
 		ispif->line[i].id = i;
 
-		if (to_camss(ispif)->version == CAMSS_8x16) {
+		if (camss->version == CAMSS_8x16) {
 			ispif->line[i].formats = ispif_formats_8x16;
 			ispif->line[i].nformats =
 					ARRAY_SIZE(ispif_formats_8x16);
-		} else if (to_camss(ispif)->version == CAMSS_8x96 ||
-			   to_camss(ispif)->version == CAMSS_660) {
+		} else if (camss->version == CAMSS_8x96 ||
+			   camss->version == CAMSS_660) {
 			ispif->line[i].formats = ispif_formats_8x96;
 			ispif->line[i].nformats =
 					ARRAY_SIZE(ispif_formats_8x96);
@@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	/* Memory */
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-	ispif->base = devm_ioremap_resource(dev, r);
+	ispif->base = devm_ioremap_resource(camss->dev, r);
 	if (IS_ERR(ispif->base)) {
-		dev_err(dev, "could not map memory\n");
+		dev_err(camss->dev, "could not map memory\n");
 		return PTR_ERR(ispif->base);
 	}
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
-	ispif->base_clk_mux = devm_ioremap_resource(dev, r);
+	ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
 	if (IS_ERR(ispif->base_clk_mux)) {
-		dev_err(dev, "could not map memory\n");
+		dev_err(camss->dev, "could not map memory\n");
 		return PTR_ERR(ispif->base_clk_mux);
 	}
 
@@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
 
 	if (!r) {
-		dev_err(dev, "missing IRQ\n");
+		dev_err(camss->dev, "missing IRQ\n");
 		return -EINVAL;
 	}
 
 	ispif->irq = r->start;
 	snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
-		 dev_name(dev), MSM_ISPIF_NAME);
-	if (to_camss(ispif)->version == CAMSS_8x16)
-		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
+		 dev_name(camss->dev), MSM_ISPIF_NAME);
+	if (camss->version == CAMSS_8x16)
+		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
 			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
-	else if (to_camss(ispif)->version == CAMSS_8x96 ||
-		 to_camss(ispif)->version == CAMSS_660)
-		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
+	else if (camss->version == CAMSS_8x96 ||
+		 camss->version == CAMSS_660)
+		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
 			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
 	else
 		ret = -EINVAL;
+
 	if (ret < 0) {
-		dev_err(dev, "request_irq failed: %d\n", ret);
+		dev_err(camss->dev, "request_irq failed: %d\n", ret);
 		return ret;
 	}
 
@@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	while (res->clock[ispif->nclocks])
 		ispif->nclocks++;
 
-	ispif->clock = devm_kcalloc(dev,
+	ispif->clock = devm_kcalloc(camss->dev,
 				    ispif->nclocks, sizeof(*ispif->clock),
 				    GFP_KERNEL);
 	if (!ispif->clock)
@@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	for (i = 0; i < ispif->nclocks; i++) {
 		struct camss_clock *clock = &ispif->clock[i];
 
-		clock->clk = devm_clk_get(dev, res->clock[i]);
+		clock->clk = devm_clk_get(camss->dev, res->clock[i]);
 		if (IS_ERR(clock->clk))
 			return PTR_ERR(clock->clk);
 
@@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	while (res->clock_for_reset[ispif->nclocks_for_reset])
 		ispif->nclocks_for_reset++;
 
-	ispif->clock_for_reset = devm_kcalloc(dev,
+	ispif->clock_for_reset = devm_kcalloc(camss->dev,
 					      ispif->nclocks_for_reset,
 					      sizeof(*ispif->clock_for_reset),
 					      GFP_KERNEL);
@@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	for (i = 0; i < ispif->nclocks_for_reset; i++) {
 		struct camss_clock *clock = &ispif->clock_for_reset[i];
 
-		clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
+		clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
 		if (IS_ERR(clock->clk))
 			return PTR_ERR(clock->clk);
 
@@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
 int msm_ispif_register_entities(struct ispif_device *ispif,
 				struct v4l2_device *v4l2_dev)
 {
-	struct device *dev = to_device(ispif);
+	struct camss *camss =  ispif->camss;
 	int ret;
 	int i;
 
+	if (!ispif)
+		return 0;
+
 	for (i = 0; i < ispif->line_num; i++) {
 		struct v4l2_subdev *sd = &ispif->line[i].subdev;
 		struct media_pad *pads = ispif->line[i].pads;
@@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
 
 		ret = ispif_init_formats(sd, NULL);
 		if (ret < 0) {
-			dev_err(dev, "Failed to init format: %d\n", ret);
+			dev_err(camss->dev, "Failed to init format: %d\n", ret);
 			goto error;
 		}
 
@@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
 		ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
 					     pads);
 		if (ret < 0) {
-			dev_err(dev, "Failed to init media entity: %d\n", ret);
+			dev_err(camss->dev, "Failed to init media entity: %d\n",
+				ret);
 			goto error;
 		}
 
 		ret = v4l2_device_register_subdev(v4l2_dev, sd);
 		if (ret < 0) {
-			dev_err(dev, "Failed to register subdev: %d\n", ret);
+			dev_err(camss->dev, "Failed to register subdev: %d\n",
+				ret);
 			media_entity_cleanup(&sd->entity);
 			goto error;
 		}
@@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
 {
 	int i;
 
+	if (!ispif)
+		return;
+
 	mutex_destroy(&ispif->power_lock);
 	mutex_destroy(&ispif->config_lock);
 
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
index 4132174f7ea1..fdf28e68cc7d 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.h
+++ b/drivers/media/platform/qcom/camss/camss-ispif.h
@@ -63,11 +63,12 @@ struct ispif_device {
 	struct mutex config_lock;
 	unsigned int line_num;
 	struct ispif_line *line;
+	struct camss *camss;
 };
 
 struct resources_ispif;
 
-int msm_ispif_subdev_init(struct ispif_device *ispif,
+int msm_ispif_subdev_init(struct camss *camss,
 			  const struct resources_ispif *res);
 
 int msm_ispif_register_entities(struct ispif_device *ispif,
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 8fefce57bc49..aeec59bc6194 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
 		}
 	}
 
-	ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
-	if (ret < 0) {
-		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
+	if (camss->ispif) {
+		ret = msm_ispif_subdev_init(camss, ispif_res);
+		if (ret < 0) {
+			dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
 			ret);
-		return ret;
+			return ret;
+		}
 	}
 
 	for (i = 0; i < camss->vfe_num; i++) {
@@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
 		}
 	}
 
-	ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
-	if (ret < 0) {
-		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
+	if (camss->ispif) {
+		ret = msm_ispif_register_entities(camss->ispif,
+						  &camss->v4l2_dev);
+		if (ret < 0) {
+			dev_err(camss->dev, "Failed to register ispif entities: %d\n",
 			ret);
-		goto err_reg_ispif;
+			goto err_reg_ispif;
+		}
 	}
 
 	for (i = 0; i < camss->vfe_num; i++) {
@@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
 		}
 	}
 
-	for (i = 0; i < camss->csid_num; i++) {
-		for (j = 0; j < camss->ispif.line_num; j++) {
-			ret = media_create_pad_link(
-				&camss->csid[i].subdev.entity,
-				MSM_CSID_PAD_SRC,
-				&camss->ispif.line[j].subdev.entity,
-				MSM_ISPIF_PAD_SINK,
-				0);
-			if (ret < 0) {
-				dev_err(camss->dev,
-					"Failed to link %s->%s entities: %d\n",
-					camss->csid[i].subdev.entity.name,
-					camss->ispif.line[j].subdev.entity.name,
-					ret);
-				goto err_link;
-			}
-		}
-	}
-
-	for (i = 0; i < camss->ispif.line_num; i++)
-		for (k = 0; k < camss->vfe_num; k++)
-			for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+	if (camss->ispif) {
+		for (i = 0; i < camss->csid_num; i++) {
+			for (j = 0; j < camss->ispif->line_num; j++) {
 				ret = media_create_pad_link(
-					&camss->ispif.line[i].subdev.entity,
-					MSM_ISPIF_PAD_SRC,
-					&camss->vfe[k].line[j].subdev.entity,
-					MSM_VFE_PAD_SINK,
+					&camss->csid[i].subdev.entity,
+					MSM_CSID_PAD_SRC,
+					&camss->ispif->line[j].subdev.entity,
+					MSM_ISPIF_PAD_SINK,
 					0);
 				if (ret < 0) {
 					dev_err(camss->dev,
 						"Failed to link %s->%s entities: %d\n",
-						camss->ispif.line[i].subdev.entity.name,
-						camss->vfe[k].line[j].subdev.entity.name,
+						camss->csid[i].subdev.entity.name,
+						camss->ispif->line[j].subdev.entity.name,
 						ret);
 					goto err_link;
 				}
 			}
+		}
+
+		for (i = 0; i < camss->ispif->line_num; i++)
+			for (k = 0; k < camss->vfe_num; k++)
+				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+					ret = media_create_pad_link(
+						&camss->ispif->line[i].subdev.entity,
+						MSM_ISPIF_PAD_SRC,
+						&camss->vfe[k].line[j].subdev.entity,
+						MSM_VFE_PAD_SINK,
+						0);
+					if (ret < 0) {
+						dev_err(camss->dev,
+							"Failed to link %s->%s entities: %d\n",
+							camss->ispif->line[i].subdev.entity.name,
+							camss->vfe[k].line[j].subdev.entity.name,
+							ret);
+						goto err_link;
+					}
+				}
+	} else {
+		for (i = 0; i < camss->csid_num; i++)
+			for (k = 0; k < camss->vfe_num; k++)
+				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+					ret = media_create_pad_link(
+						&camss->csid[i].subdev.entity,
+						MSM_CSID_PAD_SRC,
+						&camss->vfe[k].line[j].subdev.entity,
+						MSM_VFE_PAD_SINK,
+						0);
+					if (ret < 0) {
+						dev_err(camss->dev,
+							"Failed to link %s->%s entities: %d\n",
+							camss->csid[i].subdev.entity.name,
+							camss->vfe[k].line[j].subdev.entity.name,
+							ret);
+						goto err_link;
+					}
+				}
+	}
 
 	return 0;
 
@@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
 	for (i--; i >= 0; i--)
 		msm_vfe_unregister_entities(&camss->vfe[i]);
 
-	msm_ispif_unregister_entities(&camss->ispif);
 err_reg_ispif:
+	if (camss->ispif)
+		msm_ispif_unregister_entities(camss->ispif);
 
 	i = camss->csid_num;
 err_reg_csid:
@@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
 	for (i = 0; i < camss->csid_num; i++)
 		msm_csid_unregister_entity(&camss->csid[i]);
 
-	msm_ispif_unregister_entities(&camss->ispif);
+	if (camss->ispif)
+		msm_ispif_unregister_entities(camss->ispif);
 
 	for (i = 0; i < camss->vfe_num; i++)
 		msm_vfe_unregister_entities(&camss->vfe[i]);
@@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
+	if (camss->version == CAMSS_8x16 ||
+	    camss->version == CAMSS_8x96) {
+		camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);
+		if (!camss->ispif) {
+			ret = -ENOMEM;
+			goto err_free;
+		}
+	}
+
 	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
 				  GFP_KERNEL);
 	if (!camss->vfe) {
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 46e986452824..b7ad8e9f68a8 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -79,7 +79,7 @@ struct camss {
 	struct csiphy_device *csiphy;
 	int csid_num;
 	struct csid_device *csid;
-	struct ispif_device ispif;
+	struct ispif_device *ispif;
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-- 
2.27.0


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

* [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

This driver supports multiple architecture versions of the Qualcomm ISP.
The CAMSS architecure which this driver is name after, and with the
introduction of this series, the Titan architecture.

The ISPIF is IP-block that is only present in the CAMSS architecture.
In order to support the Titan architecture, make the ISPIF an optional
subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
 .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
 drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
 drivers/media/platform/qcom/camss/camss.h     |   2 +-
 4 files changed, 160 insertions(+), 102 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index adeb92808998..0c804584dd65 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
 static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 {
 	struct ispif_device *ispif = dev;
+	struct camss *camss = ispif->camss;
 	u32 value0, value1, value2, value3, value4, value5;
 
 	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
@@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 		complete(&ispif->reset_complete[1]);
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
 
 	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
 
 	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
 
 	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
 
 	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
 
 	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
 
 	if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
 
 	return IRQ_HANDLED;
 }
@@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
 static irqreturn_t ispif_isr_8x16(int irq, void *dev)
 {
 	struct ispif_device *ispif = dev;
+	struct camss *camss = ispif->camss;
 	u32 value0, value1, value2;
 
 	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
@@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
 		complete(&ispif->reset_complete[0]);
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
 
 	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
 
 	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
 
 	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
-		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
+		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
 
 	return IRQ_HANDLED;
 }
 
 static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
 {
+	struct camss *camss = ispif->camss;
+
 	unsigned long time;
 	u32 val;
 
-	if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
-		dev_err(to_device(ispif),
+	if (vfe_id > (camss->vfe_num - 1)) {
+		dev_err(camss->dev,
 			"Error: asked reset for invalid VFE%d\n", vfe_id);
 		return -ENOENT;
 	}
@@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
 	time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
 		msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
 	if (!time) {
-		dev_err(to_device(ispif),
+		dev_err(camss->dev,
 			"ISPIF for VFE%d reset timeout\n", vfe_id);
 		return -EIO;
 	}
@@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
  */
 static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 {
+	struct camss *camss = ispif->camss;
 	int ret;
 
-	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
+	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
 	if (ret < 0)
 		return ret;
 
-	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
+	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
 	if (ret < 0)
 		return ret;
 
 	ret = camss_enable_clocks(ispif->nclocks_for_reset,
 				  ispif->clock_for_reset,
-				  to_device(ispif));
+				  camss->dev);
 	if (ret < 0)
 		return ret;
 
 	ret = ispif_vfe_reset(ispif, vfe_id);
 	if (ret)
-		dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
+		dev_dbg(camss->dev, "ISPIF Reset failed\n");
 
 	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
 
-	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
-	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
+	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
+	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
 
 	return ret;
 }
@@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
 {
 	struct ispif_line *line = v4l2_get_subdevdata(sd);
 	struct ispif_device *ispif = line->ispif;
-	struct device *dev = to_device(ispif);
+	struct device *dev = ispif->camss->dev;
 	int ret = 0;
 
 	mutex_lock(&ispif->power_lock);
@@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
 	}
 
 	if ((val & 0xf) != 0xf) {
-		dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
+		dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
 			__func__, val);
 		ret = -EBUSY;
 	}
@@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
 				 ISPIF_TIMEOUT_SLEEP_US,
 				 ISPIF_TIMEOUT_ALL_US);
 	if (ret < 0)
-		dev_err(to_device(ispif), "%s: ispif stop timeout\n",
+		dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
 			__func__);
 
 	return ret;
@@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct ispif_line *line = v4l2_get_subdevdata(sd);
 	struct ispif_device *ispif = line->ispif;
+	struct camss *camss = ispif->camss;
 	enum ispif_intf intf = line->interface;
 	u8 csid = line->csid_id;
 	u8 vfe = line->vfe_id;
@@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 		ispif_select_csid(ispif, intf, csid, vfe, 1);
 		ispif_select_cid(ispif, intf, cid, vfe, 1);
 		ispif_config_irq(ispif, intf, vfe, 1);
-		if (to_camss(ispif)->version == CAMSS_8x96 ||
-		    to_camss(ispif)->version == CAMSS_660)
+		if (camss->version == CAMSS_8x96 ||
+		    camss->version == CAMSS_660)
 			ispif_config_pack(ispif,
 					  line->fmt[MSM_ISPIF_PAD_SINK].code,
 					  intf, cid, vfe, 1);
@@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
 			return ret;
 
 		mutex_lock(&ispif->config_lock);
-		if (to_camss(ispif)->version == CAMSS_8x96 ||
-		    to_camss(ispif)->version == CAMSS_660)
+		if (camss->version == CAMSS_8x96 ||
+		    camss->version == CAMSS_660)
 			ispif_config_pack(ispif,
 					  line->fmt[MSM_ISPIF_PAD_SINK].code,
 					  intf, cid, vfe, 0);
@@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
  *
  * Return 0 on success or a negative error code otherwise
  */
-int msm_ispif_subdev_init(struct ispif_device *ispif,
+int msm_ispif_subdev_init(struct camss *camss,
 			  const struct resources_ispif *res)
 {
-	struct device *dev = to_device(ispif);
-	struct platform_device *pdev = to_platform_device(dev);
+	struct ispif_device *ispif = camss->ispif;
+	struct platform_device *pdev = to_platform_device(camss->dev);
 	struct resource *r;
 	int i;
 	int ret;
 
+	if (res == NULL && ispif == NULL)
+		return 0;
+
+	ispif->camss = camss;
+
 	/* Number of ISPIF lines - same as number of CSID hardware modules */
-	if (to_camss(ispif)->version == CAMSS_8x16)
+	if (camss->version == CAMSS_8x16)
 		ispif->line_num = 2;
-	else if (to_camss(ispif)->version == CAMSS_8x96 ||
-		 to_camss(ispif)->version == CAMSS_660)
+	else if (camss->version == CAMSS_8x96 ||
+		 camss->version == CAMSS_660)
 		ispif->line_num = 4;
 	else
 		return -EINVAL;
 
-	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
-				   GFP_KERNEL);
+	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
+			sizeof(*ispif->line), GFP_KERNEL);
 	if (!ispif->line)
 		return -ENOMEM;
 
@@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 		ispif->line[i].ispif = ispif;
 		ispif->line[i].id = i;
 
-		if (to_camss(ispif)->version == CAMSS_8x16) {
+		if (camss->version == CAMSS_8x16) {
 			ispif->line[i].formats = ispif_formats_8x16;
 			ispif->line[i].nformats =
 					ARRAY_SIZE(ispif_formats_8x16);
-		} else if (to_camss(ispif)->version == CAMSS_8x96 ||
-			   to_camss(ispif)->version == CAMSS_660) {
+		} else if (camss->version == CAMSS_8x96 ||
+			   camss->version == CAMSS_660) {
 			ispif->line[i].formats = ispif_formats_8x96;
 			ispif->line[i].nformats =
 					ARRAY_SIZE(ispif_formats_8x96);
@@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	/* Memory */
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
-	ispif->base = devm_ioremap_resource(dev, r);
+	ispif->base = devm_ioremap_resource(camss->dev, r);
 	if (IS_ERR(ispif->base)) {
-		dev_err(dev, "could not map memory\n");
+		dev_err(camss->dev, "could not map memory\n");
 		return PTR_ERR(ispif->base);
 	}
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
-	ispif->base_clk_mux = devm_ioremap_resource(dev, r);
+	ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
 	if (IS_ERR(ispif->base_clk_mux)) {
-		dev_err(dev, "could not map memory\n");
+		dev_err(camss->dev, "could not map memory\n");
 		return PTR_ERR(ispif->base_clk_mux);
 	}
 
@@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
 
 	if (!r) {
-		dev_err(dev, "missing IRQ\n");
+		dev_err(camss->dev, "missing IRQ\n");
 		return -EINVAL;
 	}
 
 	ispif->irq = r->start;
 	snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
-		 dev_name(dev), MSM_ISPIF_NAME);
-	if (to_camss(ispif)->version == CAMSS_8x16)
-		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
+		 dev_name(camss->dev), MSM_ISPIF_NAME);
+	if (camss->version == CAMSS_8x16)
+		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
 			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
-	else if (to_camss(ispif)->version == CAMSS_8x96 ||
-		 to_camss(ispif)->version == CAMSS_660)
-		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
+	else if (camss->version == CAMSS_8x96 ||
+		 camss->version == CAMSS_660)
+		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
 			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
 	else
 		ret = -EINVAL;
+
 	if (ret < 0) {
-		dev_err(dev, "request_irq failed: %d\n", ret);
+		dev_err(camss->dev, "request_irq failed: %d\n", ret);
 		return ret;
 	}
 
@@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	while (res->clock[ispif->nclocks])
 		ispif->nclocks++;
 
-	ispif->clock = devm_kcalloc(dev,
+	ispif->clock = devm_kcalloc(camss->dev,
 				    ispif->nclocks, sizeof(*ispif->clock),
 				    GFP_KERNEL);
 	if (!ispif->clock)
@@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	for (i = 0; i < ispif->nclocks; i++) {
 		struct camss_clock *clock = &ispif->clock[i];
 
-		clock->clk = devm_clk_get(dev, res->clock[i]);
+		clock->clk = devm_clk_get(camss->dev, res->clock[i]);
 		if (IS_ERR(clock->clk))
 			return PTR_ERR(clock->clk);
 
@@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	while (res->clock_for_reset[ispif->nclocks_for_reset])
 		ispif->nclocks_for_reset++;
 
-	ispif->clock_for_reset = devm_kcalloc(dev,
+	ispif->clock_for_reset = devm_kcalloc(camss->dev,
 					      ispif->nclocks_for_reset,
 					      sizeof(*ispif->clock_for_reset),
 					      GFP_KERNEL);
@@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
 	for (i = 0; i < ispif->nclocks_for_reset; i++) {
 		struct camss_clock *clock = &ispif->clock_for_reset[i];
 
-		clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
+		clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
 		if (IS_ERR(clock->clk))
 			return PTR_ERR(clock->clk);
 
@@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
 int msm_ispif_register_entities(struct ispif_device *ispif,
 				struct v4l2_device *v4l2_dev)
 {
-	struct device *dev = to_device(ispif);
+	struct camss *camss =  ispif->camss;
 	int ret;
 	int i;
 
+	if (!ispif)
+		return 0;
+
 	for (i = 0; i < ispif->line_num; i++) {
 		struct v4l2_subdev *sd = &ispif->line[i].subdev;
 		struct media_pad *pads = ispif->line[i].pads;
@@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
 
 		ret = ispif_init_formats(sd, NULL);
 		if (ret < 0) {
-			dev_err(dev, "Failed to init format: %d\n", ret);
+			dev_err(camss->dev, "Failed to init format: %d\n", ret);
 			goto error;
 		}
 
@@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
 		ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
 					     pads);
 		if (ret < 0) {
-			dev_err(dev, "Failed to init media entity: %d\n", ret);
+			dev_err(camss->dev, "Failed to init media entity: %d\n",
+				ret);
 			goto error;
 		}
 
 		ret = v4l2_device_register_subdev(v4l2_dev, sd);
 		if (ret < 0) {
-			dev_err(dev, "Failed to register subdev: %d\n", ret);
+			dev_err(camss->dev, "Failed to register subdev: %d\n",
+				ret);
 			media_entity_cleanup(&sd->entity);
 			goto error;
 		}
@@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
 {
 	int i;
 
+	if (!ispif)
+		return;
+
 	mutex_destroy(&ispif->power_lock);
 	mutex_destroy(&ispif->config_lock);
 
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
index 4132174f7ea1..fdf28e68cc7d 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.h
+++ b/drivers/media/platform/qcom/camss/camss-ispif.h
@@ -63,11 +63,12 @@ struct ispif_device {
 	struct mutex config_lock;
 	unsigned int line_num;
 	struct ispif_line *line;
+	struct camss *camss;
 };
 
 struct resources_ispif;
 
-int msm_ispif_subdev_init(struct ispif_device *ispif,
+int msm_ispif_subdev_init(struct camss *camss,
 			  const struct resources_ispif *res);
 
 int msm_ispif_register_entities(struct ispif_device *ispif,
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 8fefce57bc49..aeec59bc6194 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
 		}
 	}
 
-	ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
-	if (ret < 0) {
-		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
+	if (camss->ispif) {
+		ret = msm_ispif_subdev_init(camss, ispif_res);
+		if (ret < 0) {
+			dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
 			ret);
-		return ret;
+			return ret;
+		}
 	}
 
 	for (i = 0; i < camss->vfe_num; i++) {
@@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
 		}
 	}
 
-	ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
-	if (ret < 0) {
-		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
+	if (camss->ispif) {
+		ret = msm_ispif_register_entities(camss->ispif,
+						  &camss->v4l2_dev);
+		if (ret < 0) {
+			dev_err(camss->dev, "Failed to register ispif entities: %d\n",
 			ret);
-		goto err_reg_ispif;
+			goto err_reg_ispif;
+		}
 	}
 
 	for (i = 0; i < camss->vfe_num; i++) {
@@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
 		}
 	}
 
-	for (i = 0; i < camss->csid_num; i++) {
-		for (j = 0; j < camss->ispif.line_num; j++) {
-			ret = media_create_pad_link(
-				&camss->csid[i].subdev.entity,
-				MSM_CSID_PAD_SRC,
-				&camss->ispif.line[j].subdev.entity,
-				MSM_ISPIF_PAD_SINK,
-				0);
-			if (ret < 0) {
-				dev_err(camss->dev,
-					"Failed to link %s->%s entities: %d\n",
-					camss->csid[i].subdev.entity.name,
-					camss->ispif.line[j].subdev.entity.name,
-					ret);
-				goto err_link;
-			}
-		}
-	}
-
-	for (i = 0; i < camss->ispif.line_num; i++)
-		for (k = 0; k < camss->vfe_num; k++)
-			for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+	if (camss->ispif) {
+		for (i = 0; i < camss->csid_num; i++) {
+			for (j = 0; j < camss->ispif->line_num; j++) {
 				ret = media_create_pad_link(
-					&camss->ispif.line[i].subdev.entity,
-					MSM_ISPIF_PAD_SRC,
-					&camss->vfe[k].line[j].subdev.entity,
-					MSM_VFE_PAD_SINK,
+					&camss->csid[i].subdev.entity,
+					MSM_CSID_PAD_SRC,
+					&camss->ispif->line[j].subdev.entity,
+					MSM_ISPIF_PAD_SINK,
 					0);
 				if (ret < 0) {
 					dev_err(camss->dev,
 						"Failed to link %s->%s entities: %d\n",
-						camss->ispif.line[i].subdev.entity.name,
-						camss->vfe[k].line[j].subdev.entity.name,
+						camss->csid[i].subdev.entity.name,
+						camss->ispif->line[j].subdev.entity.name,
 						ret);
 					goto err_link;
 				}
 			}
+		}
+
+		for (i = 0; i < camss->ispif->line_num; i++)
+			for (k = 0; k < camss->vfe_num; k++)
+				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+					ret = media_create_pad_link(
+						&camss->ispif->line[i].subdev.entity,
+						MSM_ISPIF_PAD_SRC,
+						&camss->vfe[k].line[j].subdev.entity,
+						MSM_VFE_PAD_SINK,
+						0);
+					if (ret < 0) {
+						dev_err(camss->dev,
+							"Failed to link %s->%s entities: %d\n",
+							camss->ispif->line[i].subdev.entity.name,
+							camss->vfe[k].line[j].subdev.entity.name,
+							ret);
+						goto err_link;
+					}
+				}
+	} else {
+		for (i = 0; i < camss->csid_num; i++)
+			for (k = 0; k < camss->vfe_num; k++)
+				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
+					ret = media_create_pad_link(
+						&camss->csid[i].subdev.entity,
+						MSM_CSID_PAD_SRC,
+						&camss->vfe[k].line[j].subdev.entity,
+						MSM_VFE_PAD_SINK,
+						0);
+					if (ret < 0) {
+						dev_err(camss->dev,
+							"Failed to link %s->%s entities: %d\n",
+							camss->csid[i].subdev.entity.name,
+							camss->vfe[k].line[j].subdev.entity.name,
+							ret);
+						goto err_link;
+					}
+				}
+	}
 
 	return 0;
 
@@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
 	for (i--; i >= 0; i--)
 		msm_vfe_unregister_entities(&camss->vfe[i]);
 
-	msm_ispif_unregister_entities(&camss->ispif);
 err_reg_ispif:
+	if (camss->ispif)
+		msm_ispif_unregister_entities(camss->ispif);
 
 	i = camss->csid_num;
 err_reg_csid:
@@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
 	for (i = 0; i < camss->csid_num; i++)
 		msm_csid_unregister_entity(&camss->csid[i]);
 
-	msm_ispif_unregister_entities(&camss->ispif);
+	if (camss->ispif)
+		msm_ispif_unregister_entities(camss->ispif);
 
 	for (i = 0; i < camss->vfe_num; i++)
 		msm_vfe_unregister_entities(&camss->vfe[i]);
@@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
+	if (camss->version == CAMSS_8x16 ||
+	    camss->version == CAMSS_8x96) {
+		camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);
+		if (!camss->ispif) {
+			ret = -ENOMEM;
+			goto err_free;
+		}
+	}
+
 	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
 				  GFP_KERNEL);
 	if (!camss->vfe) {
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 46e986452824..b7ad8e9f68a8 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -79,7 +79,7 @@ struct camss {
 	struct csiphy_device *csiphy;
 	int csid_num;
 	struct csid_device *csid;
-	struct ispif_device ispif;
+	struct ispif_device *ispif;
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 05/17] media: camss: Refactor VFE HW version support
  2021-01-08 12:04 ` Robert Foss
                   ` (4 preceding siblings ...)
  (?)
@ 2021-01-08 12:04 ` Robert Foss
  2021-01-08 16:51   ` kernel test robot
  2021-01-13 22:38   ` Andrey Konovalov
  -1 siblings, 2 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

In order to support Qualcomm ISP hardware architectures that diverge
from older architectures, the VFE subdevice driver needs to be refactored
to better abstract the different ISP architectures.

Gen1 represents the CAMSS ISP architecture. The ISP architecture developed
after CAMSS, Titan, will be referred to as Gen2.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |    2 +
 .../media/platform/qcom/camss/camss-vfe-4-1.c |  117 +-
 .../media/platform/qcom/camss/camss-vfe-4-7.c |  238 ++--
 .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.c      |  760 +++++++++++
 .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
 drivers/media/platform/qcom/camss/camss-vfe.c |  770 +----------
 drivers/media/platform/qcom/camss/camss-vfe.h |  113 +-
 8 files changed, 2241 insertions(+), 1035 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 63c1b1b2943c..940c0ae3e003 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -10,6 +10,8 @@ qcom-camss-objs += \
 		camss-ispif.o \
 		camss-vfe-4-1.o \
 		camss-vfe-4-7.o \
+		camss-vfe-4-8.o \
+		camss-vfe-gen1.o \
 		camss-vfe.o \
 		camss-video.o \
 
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 a1b56b89130d..269dc0860de9 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -12,7 +12,9 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 
+#include "camss.h"
 #include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
 
 #define VFE_0_HW_VERSION		0x000
 
@@ -283,30 +285,6 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
 			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT);
 }
 
-#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
-
-static int vfe_word_per_line(u32 format, u32 pixel_per_line)
-{
-	int val = 0;
-
-	switch (format) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-		val = CALC_WORD(pixel_per_line, 1, 8);
-		break;
-	case V4L2_PIX_FMT_YUYV:
-	case V4L2_PIX_FMT_YVYU:
-	case V4L2_PIX_FMT_UYVY:
-	case V4L2_PIX_FMT_VYUY:
-		val = CALC_WORD(pixel_per_line, 2, 8);
-		break;
-	}
-
-	return val;
-}
-
 static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
 			     u16 *width, u16 *height, u16 *bytesperline)
 {
@@ -665,20 +643,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
 	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
 }
 
-static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
-{
-	if (input / output >= 16)
-		return 0;
-
-	if (input / output >= 8)
-		return 1;
-
-	if (input / output >= 4)
-		return 2;
-
-	return 3;
-}
-
 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;
@@ -974,46 +938,61 @@ static irqreturn_t vfe_isr(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-const struct vfe_hw_ops vfe_ops_4_1 = {
-	.hw_version_read = vfe_hw_version_read,
+
+const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
+	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
+	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
+	.bus_enable_wr_if = vfe_bus_enable_wr_if,
+	.bus_reload_wm = vfe_bus_reload_wm,
+	.camif_wait_for_stop = vfe_camif_wait_for_stop,
+	.enable_irq_common = vfe_enable_irq_common,
+	.enable_irq_pix_line = vfe_enable_irq_pix_line,
+	.enable_irq_wm_line = vfe_enable_irq_wm_line,
 	.get_ub_size = vfe_get_ub_size,
-	.global_reset = vfe_global_reset,
-	.halt_request = vfe_halt_request,
 	.halt_clear = vfe_halt_clear,
+	.halt_request = vfe_halt_request,
+	.set_camif_cfg = vfe_set_camif_cfg,
+	.set_camif_cmd = vfe_set_camif_cmd,
+	.set_cgc_override = vfe_set_cgc_override,
+	.set_clamp_cfg = vfe_set_clamp_cfg,
+	.set_crop_cfg = vfe_set_crop_cfg,
+	.set_demux_cfg = vfe_set_demux_cfg,
+	.set_ds = vfe_set_ds,
+	.set_module_cfg = vfe_set_module_cfg,
+	.set_qos = vfe_set_qos,
+	.set_rdi_cid = vfe_set_rdi_cid,
+	.set_realign_cfg = vfe_set_realign_cfg,
+	.set_scale_cfg = vfe_set_scale_cfg,
+	.set_xbar_cfg = vfe_set_xbar_cfg,
 	.wm_enable = vfe_wm_enable,
 	.wm_frame_based = vfe_wm_frame_based,
+	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
 	.wm_line_based = vfe_wm_line_based,
-	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
 	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
-	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
-	.bus_reload_wm = vfe_bus_reload_wm,
+	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
 	.wm_set_ping_addr = vfe_wm_set_ping_addr,
 	.wm_set_pong_addr = vfe_wm_set_pong_addr,
-	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
-	.bus_enable_wr_if = vfe_bus_enable_wr_if,
-	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
 	.wm_set_subsample = vfe_wm_set_subsample,
-	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
-	.set_xbar_cfg = vfe_set_xbar_cfg,
-	.set_realign_cfg = vfe_set_realign_cfg,
-	.set_rdi_cid = vfe_set_rdi_cid,
-	.reg_update = vfe_reg_update,
-	.reg_update_clear = vfe_reg_update_clear,
-	.enable_irq_wm_line = vfe_enable_irq_wm_line,
-	.enable_irq_pix_line = vfe_enable_irq_pix_line,
-	.enable_irq_common = vfe_enable_irq_common,
-	.set_demux_cfg = vfe_set_demux_cfg,
-	.set_scale_cfg = vfe_set_scale_cfg,
-	.set_crop_cfg = vfe_set_crop_cfg,
-	.set_clamp_cfg = vfe_set_clamp_cfg,
-	.set_qos = vfe_set_qos,
-	.set_ds = vfe_set_ds,
-	.set_cgc_override = vfe_set_cgc_override,
-	.set_camif_cfg = vfe_set_camif_cfg,
-	.set_camif_cmd = vfe_set_camif_cmd,
-	.set_module_cfg = vfe_set_module_cfg,
-	.camif_wait_for_stop = vfe_camif_wait_for_stop,
+	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
+};
+
+static void vfe_subdev_init(struct vfe_device *vfe)
+{
+	vfe->isr_ops = vfe_isr_ops_gen1;
+	vfe->ops_gen1 = &vfe_ops_gen1_4_1;
+	vfe->video_ops = vfe_video_ops_gen1;
+}
+
+const struct vfe_hw_ops vfe_ops_4_1 = {
+	.global_reset = vfe_global_reset,
+	.hw_version_read = vfe_hw_version_read,
 	.isr_read = vfe_isr_read,
-	.violation_read = vfe_violation_read,
 	.isr = vfe_isr,
+	.reg_update_clear = vfe_reg_update_clear,
+	.reg_update = vfe_reg_update,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_gen1_disable,
+	.vfe_enable = vfe_gen1_enable,
+	.vfe_halt = vfe_gen1_halt,
+	.violation_read = vfe_violation_read,
 };
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 84c33b8f9fe3..d0d470be1c10 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -12,7 +12,10 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 
+#include "camss.h"
 #include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
+
 
 #define VFE_0_HW_VERSION		0x000
 
@@ -257,7 +260,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
 	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
 }
 
-static u16 vfe47_get_ub_size(u8 vfe_id)
+static u16 vfe_get_ub_size(u8 vfe_id)
 {
 	if (vfe_id == 0)
 		return MSM_VFE_VFE0_UB_SIZE_RDI;
@@ -295,6 +298,8 @@ static void vfe_global_reset(struct vfe_device *vfe)
 			 VFE_0_GLOBAL_RESET_CMD_CORE;
 
 	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
+
+	/* Enforce barrier between IRQ mask setup and global reset */
 	wmb();
 	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
 }
@@ -310,7 +315,7 @@ static void vfe_halt_clear(struct vfe_device *vfe)
 	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
 }
 
-static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
+static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
 {
 	if (enable)
 		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
@@ -459,8 +464,12 @@ static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
 
 static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
 {
+	/* Enforce barrier between any outstanding register write */
 	wmb();
+
 	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
+
+	/* Use barrier to make sure bus reload is issued before anything else */
 	wmb();
 }
 
@@ -674,8 +683,12 @@ static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
 static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
 {
 	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
+
+	/* Enforce barrier between line update and commit */
 	wmb();
 	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
+
+	/* Make sure register update is issued before further reg writes */
 	wmb();
 }
 
@@ -779,20 +792,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
 	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
 }
 
-static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
-{
-	if (input / output >= 16)
-		return 0;
-
-	if (input / output >= 8)
-		return 1;
-
-	if (input / output >= 4)
-		return 2;
-
-	return 3;
-}
-
 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;
@@ -894,7 +893,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe)
 	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
 }
 
-static void vfe47_set_qos(struct vfe_device *vfe)
+static void vfe_set_qos(struct vfe_device *vfe)
 {
 	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
 	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
@@ -909,7 +908,7 @@ static void vfe47_set_qos(struct vfe_device *vfe)
 	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
 }
 
-static void vfe47_set_ds(struct vfe_device *vfe)
+static void vfe_set_ds(struct vfe_device *vfe)
 {
 	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
 	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
@@ -993,6 +992,8 @@ static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
 
 	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
 	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
+
+	/* Make sure camif command is issued written before it is changed again */
 	wmb();
 
 	if (enable)
@@ -1035,24 +1036,7 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
 	return ret;
 }
 
-static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
-{
-	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
-	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
 
-	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
-	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
-
-	wmb();
-	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
-}
-
-static void vfe_violation_read(struct vfe_device *vfe)
-{
-	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
-
-	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
-}
 
 /*
  * vfe_isr - VFE module interrupt handler
@@ -1107,150 +1091,80 @@ static irqreturn_t vfe_isr(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-const struct vfe_hw_ops vfe_ops_4_7 = {
-	.hw_version_read = vfe_hw_version_read,
-	.get_ub_size = vfe47_get_ub_size,
-	.global_reset = vfe_global_reset,
-	.halt_request = vfe_halt_request,
-	.halt_clear = vfe_halt_clear,
-	.wm_enable = vfe47_wm_enable,
-	.wm_frame_based = vfe_wm_frame_based,
-	.wm_line_based = vfe_wm_line_based,
-	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
-	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
-	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
-	.bus_reload_wm = vfe_bus_reload_wm,
-	.wm_set_ping_addr = vfe_wm_set_ping_addr,
-	.wm_set_pong_addr = vfe_wm_set_pong_addr,
-	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
-	.bus_enable_wr_if = vfe_bus_enable_wr_if,
-	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
-	.wm_set_subsample = vfe_wm_set_subsample,
-	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
-	.set_xbar_cfg = vfe_set_xbar_cfg,
-	.set_realign_cfg = vfe_set_realign_cfg,
-	.set_rdi_cid = vfe_set_rdi_cid,
-	.reg_update = vfe_reg_update,
-	.reg_update_clear = vfe_reg_update_clear,
-	.enable_irq_wm_line = vfe_enable_irq_wm_line,
-	.enable_irq_pix_line = vfe_enable_irq_pix_line,
-	.enable_irq_common = vfe_enable_irq_common,
-	.set_demux_cfg = vfe_set_demux_cfg,
-	.set_scale_cfg = vfe_set_scale_cfg,
-	.set_crop_cfg = vfe_set_crop_cfg,
-	.set_clamp_cfg = vfe_set_clamp_cfg,
-	.set_qos = vfe47_set_qos,
-	.set_ds = vfe47_set_ds,
-	.set_cgc_override = vfe_set_cgc_override,
-	.set_camif_cfg = vfe_set_camif_cfg,
-	.set_camif_cmd = vfe_set_camif_cmd,
-	.set_module_cfg = vfe_set_module_cfg,
-	.camif_wait_for_stop = vfe_camif_wait_for_stop,
-	.isr_read = vfe_isr_read,
-	.violation_read = vfe_violation_read,
-	.isr = vfe_isr,
-};
-
-static u16 vfe48_get_ub_size(u8 vfe_id)
+static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
 {
-	/* On VFE4.8 the ub-size is the same on both instances */
-	return MSM_VFE_VFE0_UB_SIZE_RDI;
-}
+	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
+	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
 
-static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
-{
-	if (enable)
-		writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
-			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
-	else
-		writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
-			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
+	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
+	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
 
-	/* The WM must be enabled before sending other commands */
+	/* Enforce barrier between local & global IRQ clear */
 	wmb();
+	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
 }
 
-static void vfe48_set_qos(struct vfe_device *vfe)
-{
-	u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG;
-	u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG;
-	u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG;
-	u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG;
-
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
-	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
-	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
-	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
-	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
-	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
-}
-
-static void vfe48_set_ds(struct vfe_device *vfe)
+static void vfe_violation_read(struct vfe_device *vfe)
 {
-	u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG;
-	u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG;
+	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
 
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
-	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
-	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
+	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
 }
 
-const struct vfe_hw_ops vfe_ops_4_8 = {
-	.hw_version_read = vfe_hw_version_read,
-	.get_ub_size = vfe48_get_ub_size,
-	.global_reset = vfe_global_reset,
-	.halt_request = vfe_halt_request,
+const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = {
+	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
+	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
+	.bus_enable_wr_if = vfe_bus_enable_wr_if,
+	.bus_reload_wm = vfe_bus_reload_wm,
+	.camif_wait_for_stop = vfe_camif_wait_for_stop,
+	.enable_irq_common = vfe_enable_irq_common,
+	.enable_irq_pix_line = vfe_enable_irq_pix_line,
+	.enable_irq_wm_line = vfe_enable_irq_wm_line,
+	.get_ub_size = vfe_get_ub_size,
 	.halt_clear = vfe_halt_clear,
-	.wm_enable = vfe48_wm_enable,
+	.halt_request = vfe_halt_request,
+	.set_camif_cfg = vfe_set_camif_cfg,
+	.set_camif_cmd = vfe_set_camif_cmd,
+	.set_cgc_override = vfe_set_cgc_override,
+	.set_clamp_cfg = vfe_set_clamp_cfg,
+	.set_crop_cfg = vfe_set_crop_cfg,
+	.set_demux_cfg = vfe_set_demux_cfg,
+	.set_ds = vfe_set_ds,
+	.set_module_cfg = vfe_set_module_cfg,
+	.set_qos = vfe_set_qos,
+	.set_rdi_cid = vfe_set_rdi_cid,
+	.set_realign_cfg = vfe_set_realign_cfg,
+	.set_scale_cfg = vfe_set_scale_cfg,
+	.set_xbar_cfg = vfe_set_xbar_cfg,
+	.wm_enable = vfe_wm_enable,
 	.wm_frame_based = vfe_wm_frame_based,
+	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
 	.wm_line_based = vfe_wm_line_based,
-	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
 	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
-	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
-	.bus_reload_wm = vfe_bus_reload_wm,
+	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
 	.wm_set_ping_addr = vfe_wm_set_ping_addr,
 	.wm_set_pong_addr = vfe_wm_set_pong_addr,
-	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
-	.bus_enable_wr_if = vfe_bus_enable_wr_if,
-	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
 	.wm_set_subsample = vfe_wm_set_subsample,
-	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
-	.set_xbar_cfg = vfe_set_xbar_cfg,
-	.set_realign_cfg = vfe_set_realign_cfg,
-	.set_rdi_cid = vfe_set_rdi_cid,
-	.reg_update = vfe_reg_update,
-	.reg_update_clear = vfe_reg_update_clear,
-	.enable_irq_wm_line = vfe_enable_irq_wm_line,
-	.enable_irq_pix_line = vfe_enable_irq_pix_line,
-	.enable_irq_common = vfe_enable_irq_common,
-	.set_demux_cfg = vfe_set_demux_cfg,
-	.set_scale_cfg = vfe_set_scale_cfg,
-	.set_crop_cfg = vfe_set_crop_cfg,
-	.set_clamp_cfg = vfe_set_clamp_cfg,
-	.set_qos = vfe48_set_qos,
-	.set_ds = vfe48_set_ds,
-	.set_cgc_override = vfe_set_cgc_override,
-	.set_camif_cfg = vfe_set_camif_cfg,
-	.set_camif_cmd = vfe_set_camif_cmd,
-	.set_module_cfg = vfe_set_module_cfg,
-	.camif_wait_for_stop = vfe_camif_wait_for_stop,
+	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
+};
+
+static void vfe_subdev_init(struct vfe_device *vfe)
+{
+	vfe->isr_ops = vfe_isr_ops_gen1;
+	vfe->ops_gen1 = &vfe_ops_gen1_4_7;
+	vfe->video_ops = vfe_video_ops_gen1;
+}
+
+const struct vfe_hw_ops vfe_ops_4_7 = {
+	.global_reset = vfe_global_reset,
+	.hw_version_read = vfe_hw_version_read,
 	.isr_read = vfe_isr_read,
-	.violation_read = vfe_violation_read,
 	.isr = vfe_isr,
+	.reg_update_clear = vfe_reg_update_clear,
+	.reg_update = vfe_reg_update,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_gen1_disable,
+	.vfe_enable = vfe_gen1_enable,
+	.vfe_halt = vfe_gen1_halt,
+	.violation_read = vfe_violation_read,
 };
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
new file mode 100644
index 000000000000..609db85c5039
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -0,0 +1,1166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
+ *
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015-2018 Linaro Ltd.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
+
+
+#define VFE_0_HW_VERSION		0x000
+
+#define VFE_0_GLOBAL_RESET_CMD		0x018
+#define VFE_0_GLOBAL_RESET_CMD_CORE	BIT(0)
+#define VFE_0_GLOBAL_RESET_CMD_CAMIF	BIT(1)
+#define VFE_0_GLOBAL_RESET_CMD_BUS	BIT(2)
+#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
+#define VFE_0_GLOBAL_RESET_CMD_REGISTER	BIT(4)
+#define VFE_0_GLOBAL_RESET_CMD_PM	BIT(5)
+#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
+#define VFE_0_GLOBAL_RESET_CMD_TESTGEN	BIT(7)
+#define VFE_0_GLOBAL_RESET_CMD_DSP	BIT(8)
+#define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
+
+#define VFE_0_MODULE_LENS_EN		0x040
+#define VFE_0_MODULE_LENS_EN_DEMUX		BIT(2)
+#define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE	BIT(3)
+
+#define VFE_0_MODULE_ZOOM_EN		0x04c
+#define VFE_0_MODULE_ZOOM_EN_SCALE_ENC		BIT(1)
+#define VFE_0_MODULE_ZOOM_EN_CROP_ENC		BIT(2)
+#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF	BIT(9)
+
+#define VFE_0_CORE_CFG			0x050
+#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR	0x4
+#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB	0x5
+#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY	0x6
+#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY	0x7
+#define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
+
+#define VFE_0_IRQ_CMD			0x058
+#define VFE_0_IRQ_CMD_GLOBAL_CLEAR	BIT(0)
+
+#define VFE_0_IRQ_MASK_0		0x05c
+#define VFE_0_IRQ_MASK_0_CAMIF_SOF			BIT(0)
+#define VFE_0_IRQ_MASK_0_CAMIF_EOF			BIT(1)
+#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n)		\
+	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n))
+#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define VFE_0_IRQ_MASK_0_RESET_ACK			BIT(31)
+#define VFE_0_IRQ_MASK_1		0x060
+#define VFE_0_IRQ_MASK_1_CAMIF_ERROR			BIT(0)
+#define VFE_0_IRQ_MASK_1_VIOLATION			BIT(7)
+#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK		BIT(8)
+#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
+#define VFE_0_IRQ_MASK_1_RDIn_SOF(n)			BIT((n) + 29)
+
+#define VFE_0_IRQ_CLEAR_0		0x064
+#define VFE_0_IRQ_CLEAR_1		0x068
+
+#define VFE_0_IRQ_STATUS_0		0x06c
+#define VFE_0_IRQ_STATUS_0_CAMIF_SOF			BIT(0)
+#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n)		\
+	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n))
+#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define VFE_0_IRQ_STATUS_0_RESET_ACK			BIT(31)
+#define VFE_0_IRQ_STATUS_1		0x070
+#define VFE_0_IRQ_STATUS_1_VIOLATION			BIT(7)
+#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
+#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n)			BIT((n) + 29)
+
+#define VFE_0_IRQ_COMPOSITE_MASK_0	0x074
+#define VFE_0_VIOLATION_STATUS		0x07c
+
+#define VFE_0_BUS_CMD			0x80
+#define VFE_0_BUS_CMD_Mx_RLD_CMD(x)	BIT(x)
+
+#define VFE_0_BUS_CFG			0x084
+
+#define VFE_0_BUS_XBAR_CFG_x(x)		(0x90 + 0x4 * ((x) / 2))
+#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN			BIT(2)
+#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN			BIT(3)
+#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA		(0x1 << 4)
+#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER		(0x2 << 4)
+#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA	(0x3 << 4)
+#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT		8
+#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA		0x0
+#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0	0xc
+#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1	0xd
+#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2	0xe
+
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n)		(0x0a0 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT	0
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n)	(0x0a4 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n)	(0x0ac + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n)		(0x0b4 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT	1
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT	2
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK	(0x1f << 2)
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n)		(0x0b8 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT	16
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n)	(0x0bc + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n)	(0x0c0 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n)	\
+							(0x0c4 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n)	\
+							(0x0c8 + 0x2c * (n))
+#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF	0xffffffff
+
+#define VFE_0_BUS_PING_PONG_STATUS	0x338
+
+#define VFE_0_BUS_BDG_CMD		0x400
+#define VFE_0_BUS_BDG_CMD_HALT_REQ	1
+
+#define VFE_0_BUS_BDG_QOS_CFG_0		0x404
+#define VFE_0_BUS_BDG_QOS_CFG_0_CFG	0xaaa5aaa5
+#define VFE_0_BUS_BDG_QOS_CFG_1		0x408
+#define VFE_0_BUS_BDG_QOS_CFG_2		0x40c
+#define VFE_0_BUS_BDG_QOS_CFG_3		0x410
+#define VFE_0_BUS_BDG_QOS_CFG_3_CFG	0xaa55aaa5
+#define VFE_0_BUS_BDG_QOS_CFG_4		0x414
+#define VFE_0_BUS_BDG_QOS_CFG_4_CFG	0xaa55aa55
+#define VFE_0_BUS_BDG_QOS_CFG_5		0x418
+#define VFE_0_BUS_BDG_QOS_CFG_6		0x41c
+#define VFE_0_BUS_BDG_QOS_CFG_7		0x420
+#define VFE_0_BUS_BDG_QOS_CFG_7_CFG	0x0005aa55
+
+#define VFE_0_BUS_BDG_DS_CFG_0		0x424
+#define VFE_0_BUS_BDG_DS_CFG_0_CFG	0xcccc1111
+#define VFE_0_BUS_BDG_DS_CFG_1		0x428
+#define VFE_0_BUS_BDG_DS_CFG_2		0x42c
+#define VFE_0_BUS_BDG_DS_CFG_3		0x430
+#define VFE_0_BUS_BDG_DS_CFG_4		0x434
+#define VFE_0_BUS_BDG_DS_CFG_5		0x438
+#define VFE_0_BUS_BDG_DS_CFG_6		0x43c
+#define VFE_0_BUS_BDG_DS_CFG_7		0x440
+#define VFE_0_BUS_BDG_DS_CFG_8		0x444
+#define VFE_0_BUS_BDG_DS_CFG_9		0x448
+#define VFE_0_BUS_BDG_DS_CFG_10		0x44c
+#define VFE_0_BUS_BDG_DS_CFG_11		0x450
+#define VFE_0_BUS_BDG_DS_CFG_12		0x454
+#define VFE_0_BUS_BDG_DS_CFG_13		0x458
+#define VFE_0_BUS_BDG_DS_CFG_14		0x45c
+#define VFE_0_BUS_BDG_DS_CFG_15		0x460
+#define VFE_0_BUS_BDG_DS_CFG_16		0x464
+#define VFE_0_BUS_BDG_DS_CFG_16_CFG	0x00000110
+
+#define VFE_0_RDI_CFG_x(x)		(0x46c + (0x4 * (x)))
+#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT	28
+#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK	(0xf << 28)
+#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT	4
+#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK		(0xf << 4)
+#define VFE_0_RDI_CFG_x_RDI_EN_BIT		BIT(2)
+#define VFE_0_RDI_CFG_x_MIPI_EN_BITS		0x3
+
+#define VFE_0_CAMIF_CMD				0x478
+#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY	0
+#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY	1
+#define VFE_0_CAMIF_CMD_NO_CHANGE		3
+#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS	BIT(2)
+#define VFE_0_CAMIF_CFG				0x47c
+#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN		BIT(6)
+#define VFE_0_CAMIF_FRAME_CFG			0x484
+#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
+#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
+#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
+#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
+#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
+#define VFE_0_CAMIF_STATUS			0x4a4
+#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
+
+#define VFE_0_REG_UPDATE		0x4ac
+#define VFE_0_REG_UPDATE_RDIn(n)		BIT(1 + (n))
+#define VFE_0_REG_UPDATE_line_n(n)		\
+			((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n))
+
+#define VFE_0_DEMUX_CFG				0x560
+#define VFE_0_DEMUX_CFG_PERIOD			0x3
+#define VFE_0_DEMUX_GAIN_0			0x564
+#define VFE_0_DEMUX_GAIN_0_CH0_EVEN		(0x80 << 0)
+#define VFE_0_DEMUX_GAIN_0_CH0_ODD		(0x80 << 16)
+#define VFE_0_DEMUX_GAIN_1			0x568
+#define VFE_0_DEMUX_GAIN_1_CH1			(0x80 << 0)
+#define VFE_0_DEMUX_GAIN_1_CH2			(0x80 << 16)
+#define VFE_0_DEMUX_EVEN_CFG			0x574
+#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV	0x9cac
+#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU	0xac9c
+#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY	0xc9ca
+#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY	0xcac9
+#define VFE_0_DEMUX_ODD_CFG			0x578
+#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV	0x9cac
+#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU	0xac9c
+#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY	0xc9ca
+#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY	0xcac9
+
+#define VFE_0_SCALE_ENC_Y_CFG			0x91c
+#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE		0x920
+#define VFE_0_SCALE_ENC_Y_H_PHASE		0x924
+#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE		0x934
+#define VFE_0_SCALE_ENC_Y_V_PHASE		0x938
+#define VFE_0_SCALE_ENC_CBCR_CFG		0x948
+#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE	0x94c
+#define VFE_0_SCALE_ENC_CBCR_H_PHASE		0x950
+#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE	0x960
+#define VFE_0_SCALE_ENC_CBCR_V_PHASE		0x964
+
+#define VFE_0_CROP_ENC_Y_WIDTH			0x974
+#define VFE_0_CROP_ENC_Y_HEIGHT			0x978
+#define VFE_0_CROP_ENC_CBCR_WIDTH		0x97c
+#define VFE_0_CROP_ENC_CBCR_HEIGHT		0x980
+
+#define VFE_0_CLAMP_ENC_MAX_CFG			0x984
+#define VFE_0_CLAMP_ENC_MAX_CFG_CH0		(0xff << 0)
+#define VFE_0_CLAMP_ENC_MAX_CFG_CH1		(0xff << 8)
+#define VFE_0_CLAMP_ENC_MAX_CFG_CH2		(0xff << 16)
+#define VFE_0_CLAMP_ENC_MIN_CFG			0x988
+#define VFE_0_CLAMP_ENC_MIN_CFG_CH0		(0x0 << 0)
+#define VFE_0_CLAMP_ENC_MIN_CFG_CH1		(0x0 << 8)
+#define VFE_0_CLAMP_ENC_MIN_CFG_CH2		(0x0 << 16)
+
+#define VFE_0_REALIGN_BUF_CFG			0xaac
+#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL     BIT(2)
+#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL     BIT(3)
+#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE      BIT(4)
+
+#define VFE_0_BUS_IMAGE_MASTER_CMD		0xcec
+#define VFE_0_BUS_IMAGE_MASTER_n_SHIFT(x)	(2 * (x))
+
+#define CAMIF_TIMEOUT_SLEEP_US 1000
+#define CAMIF_TIMEOUT_ALL_US 1000000
+
+#define MSM_VFE_VFE0_UB_SIZE 2047
+#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3)
+#define MSM_VFE_VFE1_UB_SIZE 1535
+#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3)
+
+static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
+{
+	u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
+
+	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
+}
+
+static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
+}
+
+static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits | set_bits, vfe->base + reg);
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+	u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	|
+			 VFE_0_GLOBAL_RESET_CMD_DSP		|
+			 VFE_0_GLOBAL_RESET_CMD_TESTGEN		|
+			 VFE_0_GLOBAL_RESET_CMD_BUS_MISR	|
+			 VFE_0_GLOBAL_RESET_CMD_PM		|
+			 VFE_0_GLOBAL_RESET_CMD_REGISTER	|
+			 VFE_0_GLOBAL_RESET_CMD_BUS_BDG		|
+			 VFE_0_GLOBAL_RESET_CMD_BUS		|
+			 VFE_0_GLOBAL_RESET_CMD_CAMIF		|
+			 VFE_0_GLOBAL_RESET_CMD_CORE;
+
+	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
+
+	/* Enforce barrier between IRQ mask setup and global reset */
+	wmb();
+	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
+}
+
+static void vfe_halt_request(struct vfe_device *vfe)
+{
+	writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ,
+		       vfe->base + VFE_0_BUS_BDG_CMD);
+}
+
+static void vfe_halt_clear(struct vfe_device *vfe)
+{
+	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
+}
+
+static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
+{
+	if (enable)
+		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
+			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
+	else
+		vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
+			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
+}
+
+#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
+
+static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line)
+{
+	int val = 0;
+
+	switch (format) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		val = CALC_WORD(pixel_per_line, 1, 8);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+		val = CALC_WORD(pixel_per_line, 2, 8);
+		break;
+	}
+
+	return val;
+}
+
+static int vfe_word_per_line_by_bytes(u32 bytes_per_line)
+{
+	return CALC_WORD(bytes_per_line, 1, 8);
+}
+
+static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
+			     u16 *width, u16 *height, u16 *bytesperline)
+{
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+		*width = pix->width;
+		*height = pix->height;
+		*bytesperline = pix->plane_fmt[0].bytesperline;
+		if (plane == 1)
+			*height /= 2;
+		break;
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		*width = pix->width;
+		*height = pix->height;
+		*bytesperline = pix->plane_fmt[0].bytesperline;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_UYVY:
+		*width = pix->width;
+		*height = pix->height;
+		*bytesperline = pix->plane_fmt[plane].bytesperline;
+		break;
+
+	}
+}
+
+static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm,
+			      struct v4l2_pix_format_mplane *pix,
+			      u8 plane, u32 enable)
+{
+	u32 reg;
+
+	if (enable) {
+		u16 width = 0, height = 0, bytesperline = 0, wpl;
+
+		vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline);
+
+		wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width);
+
+		reg = height - 1;
+		reg |= ((wpl + 3) / 4 - 1) << 16;
+
+		writel_relaxed(reg, vfe->base +
+			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
+
+		wpl = vfe_word_per_line_by_bytes(bytesperline);
+
+		reg = 0x3;
+		reg |= (height - 1) << 2;
+		reg |= ((wpl + 1) / 2) << 16;
+
+		writel_relaxed(reg, vfe->base +
+			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
+	} else {
+		writel_relaxed(0, vfe->base +
+			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
+		writel_relaxed(0, vfe->base +
+			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
+	}
+}
+
+static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per)
+{
+	u32 reg;
+
+	reg = readl_relaxed(vfe->base +
+			    VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
+
+	reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK);
+
+	reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT)
+		& VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK;
+
+	writel_relaxed(reg,
+		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
+}
+
+static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm,
+					 u32 pattern)
+{
+	writel_relaxed(pattern,
+	       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm));
+}
+
+static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
+			      u16 offset, u16 depth)
+{
+	u32 reg;
+
+	reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) |
+		depth;
+	writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm));
+}
+
+static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
+{
+	/* Enforce barrier between any outstanding register write */
+	wmb();
+
+	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
+
+	/* Use barrier to make sure bus reload is issued before anything else */
+	wmb();
+}
+
+static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr)
+{
+	writel_relaxed(addr,
+		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm));
+}
+
+static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr)
+{
+	writel_relaxed(addr,
+		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm));
+}
+
+static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm)
+{
+	u32 reg;
+
+	reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS);
+
+	return (reg >> wm) & 0x1;
+}
+
+static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable)
+{
+	if (enable)
+		writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG);
+	else
+		writel_relaxed(0, vfe->base + VFE_0_BUS_CFG);
+}
+
+static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm,
+				      enum vfe_line_id id)
+{
+	u32 reg;
+
+	reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
+	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg);
+
+	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
+	reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) &
+		VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK;
+	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg);
+
+	switch (id) {
+	case VFE_LINE_RDI0:
+	default:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	case VFE_LINE_RDI1:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	case VFE_LINE_RDI2:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	}
+
+	if (wm % 2 == 1)
+		reg <<= 16;
+
+	vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
+}
+
+static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm)
+{
+	writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF,
+	       vfe->base +
+	       VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm));
+}
+
+static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
+					   enum vfe_line_id id)
+{
+	u32 reg;
+
+	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
+	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg);
+
+	switch (id) {
+	case VFE_LINE_RDI0:
+	default:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	case VFE_LINE_RDI1:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	case VFE_LINE_RDI2:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
+		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
+		break;
+	}
+
+	if (wm % 2 == 1)
+		reg <<= 16;
+
+	vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
+}
+
+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);
+	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
+	u32 reg;
+
+	switch (p) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		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)
+			reg <<= 16;
+
+		if (enable)
+			vfe_reg_set(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    reg);
+		else
+			vfe_reg_clr(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    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)
+			reg <<= 16;
+
+		if (enable)
+			vfe_reg_set(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    reg);
+		else
+			vfe_reg_clr(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
+				    reg);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_VYUY:
+	case V4L2_PIX_FMT_UYVY:
+		reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN;
+		reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
+
+		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)
+			reg <<= 16;
+
+		if (enable)
+			vfe_reg_set(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    reg);
+		else
+			vfe_reg_clr(vfe,
+				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
+				    reg);
+		break;
+	default:
+		break;
+	}
+}
+
+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 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
+
+	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
+			p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY)
+		return;
+
+	if (enable) {
+		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val);
+	} else {
+		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val);
+		return;
+	}
+
+	val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE;
+
+	if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV)
+		val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL;
+	else
+		val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL;
+
+	writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG);
+}
+
+static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
+{
+	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id),
+		    VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK);
+
+	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id),
+		    cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT);
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
+
+	/* Enforce barrier between line update and commit */
+	wmb();
+
+	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
+
+	/* Make sure register update is issued before further reg writes */
+	wmb();
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+					enum vfe_line_id line_id)
+{
+	vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id);
+}
+
+static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
+				   enum vfe_line_id line_id, u8 enable)
+{
+	u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) |
+		      VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
+	u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) |
+		      VFE_0_IRQ_MASK_1_RDIn_SOF(line_id);
+
+	if (enable) {
+		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
+		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
+	} else {
+		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
+		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
+	}
+}
+
+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;
+	unsigned int i;
+	u32 irq_en0;
+	u32 irq_en1;
+	u32 comp_mask = 0;
+
+	irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF;
+	irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF;
+	irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(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;
+	}
+
+	if (enable) {
+		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
+		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
+		vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
+	} else {
+		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
+		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
+		vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
+	}
+}
+
+static void vfe_enable_irq_common(struct vfe_device *vfe)
+{
+	u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK;
+	u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION |
+		      VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK;
+
+	vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
+	vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
+}
+
+static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
+{
+	u32 val, even_cfg, odd_cfg;
+
+	writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG);
+
+	val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD;
+	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0);
+
+	val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2;
+	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1);
+
+	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV;
+		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV;
+		break;
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU;
+		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU;
+		break;
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	default:
+		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY;
+		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY;
+		break;
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY;
+		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY;
+		break;
+	}
+
+	writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG);
+	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
+}
+
+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 reg;
+	u16 input, output;
+	u8 interp_reso;
+	u32 phase_mult;
+
+	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG);
+
+	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
+	output = line->compose.width - 1;
+	reg = (output << 16) | input;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE);
+
+	interp_reso = vfe_calc_interp_reso(input, output);
+	phase_mult = input * (1 << (14 + interp_reso)) / output;
+	reg = (interp_reso << 28) | phase_mult;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE);
+
+	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
+	output = line->compose.height - 1;
+	reg = (output << 16) | input;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE);
+
+	interp_reso = vfe_calc_interp_reso(input, output);
+	phase_mult = input * (1 << (14 + interp_reso)) / output;
+	reg = (interp_reso << 28) | phase_mult;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE);
+
+	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG);
+
+	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
+	output = line->compose.width / 2 - 1;
+	reg = (output << 16) | input;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE);
+
+	interp_reso = vfe_calc_interp_reso(input, output);
+	phase_mult = input * (1 << (14 + interp_reso)) / output;
+	reg = (interp_reso << 28) | phase_mult;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE);
+
+	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
+	output = line->compose.height - 1;
+	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21)
+		output = line->compose.height / 2 - 1;
+	reg = (output << 16) | input;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE);
+
+	interp_reso = vfe_calc_interp_reso(input, output);
+	phase_mult = input * (1 << (14 + interp_reso)) / output;
+	reg = (interp_reso << 28) | phase_mult;
+	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE);
+}
+
+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 reg;
+	u16 first, last;
+
+	first = line->crop.left;
+	last = line->crop.left + line->crop.width - 1;
+	reg = (first << 16) | last;
+	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH);
+
+	first = line->crop.top;
+	last = line->crop.top + line->crop.height - 1;
+	reg = (first << 16) | last;
+	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT);
+
+	first = line->crop.left / 2;
+	last = line->crop.left / 2 + line->crop.width / 2 - 1;
+	reg = (first << 16) | last;
+	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH);
+
+	first = line->crop.top;
+	last = line->crop.top + line->crop.height - 1;
+	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) {
+		first = line->crop.top / 2;
+		last = line->crop.top / 2 + line->crop.height / 2 - 1;
+	}
+	reg = (first << 16) | last;
+	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT);
+}
+
+static void vfe_set_clamp_cfg(struct vfe_device *vfe)
+{
+	u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 |
+		VFE_0_CLAMP_ENC_MAX_CFG_CH1 |
+		VFE_0_CLAMP_ENC_MAX_CFG_CH2;
+
+	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG);
+
+	val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 |
+		VFE_0_CLAMP_ENC_MIN_CFG_CH1 |
+		VFE_0_CLAMP_ENC_MIN_CFG_CH2;
+
+	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
+}
+
+static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable)
+{
+	/* empty */
+}
+
+static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line)
+{
+	u32 val;
+
+	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
+	case MEDIA_BUS_FMT_YUYV8_2X8:
+		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR;
+		break;
+	case MEDIA_BUS_FMT_YVYU8_2X8:
+		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB;
+		break;
+	case MEDIA_BUS_FMT_UYVY8_2X8:
+	default:
+		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY;
+		break;
+	case MEDIA_BUS_FMT_VYUY8_2X8:
+		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY;
+		break;
+	}
+
+	val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN;
+	writel_relaxed(val, vfe->base + VFE_0_CORE_CFG);
+
+	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
+	val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG);
+
+	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG);
+
+	val = line->fmt[MSM_VFE_PAD_SINK].height - 1;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG);
+
+	val = 0xffffffff;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG);
+
+	val = 0xffffffff;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN);
+
+	val = 0xffffffff;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN);
+
+	val = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
+	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val);
+
+	val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN;
+	writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG);
+}
+
+static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
+{
+	u32 cmd;
+
+	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
+	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
+
+	/* Make sure camif command is issued written before it is changed again */
+	wmb();
+
+	if (enable)
+		cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY;
+	else
+		cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY;
+
+	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
+}
+
+static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable)
+{
+	u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX |
+		       VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE;
+	u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC |
+		       VFE_0_MODULE_ZOOM_EN_CROP_ENC;
+
+	if (enable) {
+		vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens);
+		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
+	} else {
+		vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens);
+		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
+	}
+}
+
+static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
+{
+	u32 val;
+	int ret;
+
+	ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS,
+				 val,
+				 (val & VFE_0_CAMIF_STATUS_HALT),
+				 CAMIF_TIMEOUT_SLEEP_US,
+				 CAMIF_TIMEOUT_ALL_US);
+	if (ret < 0)
+		dev_err(dev, "%s: camif stop timeout\n", __func__);
+
+	return ret;
+}
+
+
+
+/*
+ * vfe_isr - VFE module interrupt handler
+ * @irq: Interrupt line
+ * @dev: VFE device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+	struct vfe_device *vfe = dev;
+	u32 value0, value1;
+	int i, j;
+
+	vfe->ops->isr_read(vfe, &value0, &value1);
+
+	trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n",
+		     value0, value1);
+
+	if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK)
+		vfe->isr_ops.reset_ack(vfe);
+
+	if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
+		vfe->ops->violation_read(vfe);
+
+	if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
+		vfe->isr_ops.halt_ack(vfe);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
+		if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
+			vfe->isr_ops.reg_update(vfe, i);
+
+	if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF)
+		vfe->isr_ops.sof(vfe, VFE_LINE_PIX);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
+		if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i))
+			vfe->isr_ops.sof(vfe, i);
+
+	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
+		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) {
+			vfe->isr_ops.comp_done(vfe, i);
+			for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++)
+				if (vfe->wm_output_map[j] == VFE_LINE_PIX)
+					value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j);
+		}
+
+	for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++)
+		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i))
+			vfe->isr_ops.wm_done(vfe, i);
+
+	return IRQ_HANDLED;
+}
+
+static u16 vfe_get_ub_size(u8 vfe_id)
+{
+	/* On VFE4.8 the ub-size is the same on both instances */
+	return MSM_VFE_VFE0_UB_SIZE_RDI;
+}
+
+static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
+{
+	if (enable)
+		writel_relaxed(2 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
+			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
+	else
+		writel_relaxed(1 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
+			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
+
+	/* The WM must be enabled before sending other commands */
+	wmb();
+}
+
+static void vfe_set_qos(struct vfe_device *vfe)
+{
+	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
+	u32 val3 = VFE_0_BUS_BDG_QOS_CFG_3_CFG;
+	u32 val4 = VFE_0_BUS_BDG_QOS_CFG_4_CFG;
+	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
+
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
+	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
+	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
+	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
+	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
+	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
+static void vfe_set_ds(struct vfe_device *vfe)
+{
+	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
+	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
+
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
+	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
+	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
+}
+
+static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
+{
+	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
+	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
+
+	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
+	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
+
+	/* Enforce barrier between local & global IRQ clear */
+	wmb();
+	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
+}
+
+static void vfe_violation_read(struct vfe_device *vfe)
+{
+	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
+
+	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
+}
+
+const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_8 = {
+	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
+	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
+	.bus_enable_wr_if = vfe_bus_enable_wr_if,
+	.bus_reload_wm = vfe_bus_reload_wm,
+	.camif_wait_for_stop = vfe_camif_wait_for_stop,
+	.enable_irq_common = vfe_enable_irq_common,
+	.enable_irq_pix_line = vfe_enable_irq_pix_line,
+	.enable_irq_wm_line = vfe_enable_irq_wm_line,
+	.get_ub_size = vfe_get_ub_size,
+	.halt_clear = vfe_halt_clear,
+	.halt_request = vfe_halt_request,
+	.set_camif_cfg = vfe_set_camif_cfg,
+	.set_camif_cmd = vfe_set_camif_cmd,
+	.set_cgc_override = vfe_set_cgc_override,
+	.set_clamp_cfg = vfe_set_clamp_cfg,
+	.set_crop_cfg = vfe_set_crop_cfg,
+	.set_demux_cfg = vfe_set_demux_cfg,
+	.set_ds = vfe_set_ds,
+	.set_module_cfg = vfe_set_module_cfg,
+	.set_qos = vfe_set_qos,
+	.set_rdi_cid = vfe_set_rdi_cid,
+	.set_realign_cfg = vfe_set_realign_cfg,
+	.set_scale_cfg = vfe_set_scale_cfg,
+	.set_xbar_cfg = vfe_set_xbar_cfg,
+	.wm_enable = vfe_wm_enable,
+	.wm_frame_based = vfe_wm_frame_based,
+	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
+	.wm_line_based = vfe_wm_line_based,
+	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
+	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
+	.wm_set_ping_addr = vfe_wm_set_ping_addr,
+	.wm_set_pong_addr = vfe_wm_set_pong_addr,
+	.wm_set_subsample = vfe_wm_set_subsample,
+	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
+};
+
+static void vfe_subdev_init(struct vfe_device *vfe)
+{
+	vfe->isr_ops = vfe_isr_ops_gen1;
+	vfe->ops_gen1 = &vfe_ops_gen1_4_8;
+	vfe->video_ops = vfe_video_ops_gen1;
+}
+
+const struct vfe_hw_ops vfe_ops_4_8 = {
+	.global_reset = vfe_global_reset,
+	.hw_version_read = vfe_hw_version_read,
+	.isr_read = vfe_isr_read,
+	.isr = vfe_isr,
+	.reg_update_clear = vfe_reg_update_clear,
+	.reg_update = vfe_reg_update,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_gen1_disable,
+	.vfe_enable = vfe_gen1_enable,
+	.vfe_halt = vfe_gen1_halt,
+	.violation_read = vfe_violation_read,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
new file mode 100644
index 000000000000..ffc543685081
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-gen1.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE Common functionality for Gen 1 versions of hw (4.1, 4.7..)
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+
+
+#include "camss.h"
+#include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
+
+/* Max number of frame drop updates per frame */
+#define VFE_FRAME_DROP_UPDATES 2
+#define VFE_NEXT_SOF_MS 500
+
+
+int vfe_gen1_halt(struct vfe_device *vfe)
+{
+	unsigned long time;
+
+	return 0;
+
+	reinit_completion(&vfe->halt_complete);
+
+	vfe->ops_gen1->halt_request(vfe);
+
+	time = wait_for_completion_timeout(&vfe->halt_complete,
+					   msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
+	if (!time) {
+		dev_err(vfe->camss->dev, "VFE halt timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int vfe_disable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	const struct vfe_hw_ops *ops = vfe->ops;
+	unsigned long flags;
+	unsigned long time;
+	unsigned int i;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	output->gen1.wait_sof = 1;
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	time = wait_for_completion_timeout(&output->sof, msecs_to_jiffies(VFE_NEXT_SOF_MS));
+	if (!time)
+		dev_err(vfe->camss->dev, "VFE sof timeout\n");
+
+	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);
+
+	ops->reg_update(vfe, line->id);
+	output->wait_reg_update = 1;
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	time = wait_for_completion_timeout(&output->reg_update, msecs_to_jiffies(VFE_NEXT_SOF_MS));
+	if (!time)
+		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
+
+	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);
+		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->enable_irq_pix_line(vfe, 0, line->id, 0);
+		vfe->ops_gen1->set_module_cfg(vfe, 0);
+		vfe->ops_gen1->set_realign_cfg(vfe, line, 0);
+		vfe->ops_gen1->set_xbar_cfg(vfe, output, 0);
+		vfe->ops_gen1->set_camif_cmd(vfe, 0);
+
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+		vfe->ops_gen1->camif_wait_for_stop(vfe, vfe->camss->dev);
+	}
+
+	return 0;
+}
+
+/*
+ * vfe_gen1_disable - Disable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_gen1_disable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+
+	vfe_disable_output(line);
+
+	vfe_put_output(line);
+
+	mutex_lock(&vfe->stream_lock);
+
+	if (vfe->stream_count == 1)
+		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return 0;
+}
+
+static void vfe_output_init_addrs(struct vfe_device *vfe,
+				  struct vfe_output *output, u8 sync,
+				  struct vfe_line *line)
+{
+	u32 ping_addr;
+	u32 pong_addr;
+	unsigned int i;
+
+	output->gen1.active_buf = 0;
+
+	for (i = 0; i < output->wm_num; i++) {
+		if (output->buf[0])
+			ping_addr = output->buf[0]->addr[i];
+		else
+			ping_addr = 0;
+
+		if (output->buf[1])
+			pong_addr = output->buf[1]->addr[i];
+		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);
+		if (sync)
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+	}
+}
+
+static void vfe_output_frame_drop(struct vfe_device *vfe,
+				  struct vfe_output *output,
+				  u32 drop_pattern)
+{
+	u8 drop_period;
+	unsigned int i;
+
+	/* We need to toggle update period to be valid on next frame */
+	output->drop_update_idx++;
+	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
+	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->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
+}
+
+static int vfe_enable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	const struct vfe_hw_ops *ops = vfe->ops;
+	struct media_entity *sensor;
+	unsigned long flags;
+	unsigned int frame_skip = 0;
+	unsigned int i;
+	u16 ub_size;
+
+	ub_size = vfe->ops_gen1->get_ub_size(vfe->id);
+	if (!ub_size)
+		return -EINVAL;
+
+	sensor = camss_find_sensor(&line->subdev.entity);
+	if (sensor) {
+		struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor);
+
+		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;
+	}
+	output->state = VFE_OUTPUT_IDLE;
+
+	output->buf[0] = vfe_buf_get_pending(output);
+	output->buf[1] = vfe_buf_get_pending(output);
+
+	if (!output->buf[0] && output->buf[1]) {
+		output->buf[0] = output->buf[1];
+		output->buf[1] = NULL;
+	}
+
+	if (output->buf[0])
+		output->state = VFE_OUTPUT_SINGLE;
+
+	if (output->buf[1])
+		output->state = VFE_OUTPUT_CONTINUOUS;
+
+	switch (output->state) {
+	case VFE_OUTPUT_SINGLE:
+		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
+		break;
+	case VFE_OUTPUT_CONTINUOUS:
+		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
+		break;
+	default:
+		vfe_output_frame_drop(vfe, output, 0);
+		break;
+	}
+
+	output->sequence = 0;
+	output->gen1.wait_sof = 0;
+	output->wait_reg_update = 0;
+	reinit_completion(&output->sof);
+	reinit_completion(&output->reg_update);
+
+	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_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]);
+	} 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],
+						     &line->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->enable_irq_pix_line(vfe, 0, line->id, 1);
+		vfe->ops_gen1->set_module_cfg(vfe, 1);
+		vfe->ops_gen1->set_camif_cfg(vfe, line);
+		vfe->ops_gen1->set_realign_cfg(vfe, line, 1);
+		vfe->ops_gen1->set_xbar_cfg(vfe, output, 1);
+		vfe->ops_gen1->set_demux_cfg(vfe, line);
+		vfe->ops_gen1->set_scale_cfg(vfe, line);
+		vfe->ops_gen1->set_crop_cfg(vfe, line);
+		vfe->ops_gen1->set_clamp_cfg(vfe);
+		vfe->ops_gen1->set_camif_cmd(vfe, 1);
+	}
+
+	ops->reg_update(vfe, line->id);
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+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;
+	unsigned long flags;
+	int i;
+	int wm_idx;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	output = &line->output;
+	if (output->state != VFE_OUTPUT_OFF) {
+		dev_err(vfe->camss->dev, "Output is running\n");
+		goto error;
+	}
+	output->state = VFE_OUTPUT_RESERVED;
+
+	output->gen1.active_buf = 0;
+
+	switch (f->fmt.pix_mp.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		output->wm_num = 2;
+		break;
+	default:
+		output->wm_num = 1;
+		break;
+	}
+
+	for (i = 0; i < output->wm_num; i++) {
+		wm_idx = vfe_reserve_wm(vfe, line->id);
+		if (wm_idx < 0) {
+			dev_err(vfe->camss->dev, "Can not reserve wm\n");
+			goto error_get_wm;
+		}
+		output->wm_idx[i] = wm_idx;
+	}
+
+	output->drop_update_idx = 0;
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+
+error_get_wm:
+	for (i--; i >= 0; i--)
+		vfe_release_wm(vfe, output->wm_idx[i]);
+	output->state = VFE_OUTPUT_OFF;
+error:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return -EINVAL;
+}
+
+int vfe_gen1_enable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	int ret;
+
+	mutex_lock(&vfe->stream_lock);
+
+	if (!vfe->stream_count) {
+		vfe->ops_gen1->enable_irq_common(vfe);
+		vfe->ops_gen1->bus_enable_wr_if(vfe, 1);
+		vfe->ops_gen1->set_qos(vfe);
+		vfe->ops_gen1->set_ds(vfe);
+	}
+
+	vfe->stream_count++;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	ret = vfe_get_output(line);
+	if (ret < 0)
+		goto error_get_output;
+
+	ret = vfe_enable_output(line);
+	if (ret < 0)
+		goto error_enable_output;
+
+	vfe->was_streaming = 1;
+
+	return 0;
+
+
+error_enable_output:
+	vfe_put_output(line);
+
+error_get_output:
+	mutex_lock(&vfe->stream_lock);
+
+	if (vfe->stream_count == 1)
+		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return ret;
+}
+
+static void vfe_output_update_ping_addr(struct vfe_device *vfe,
+					struct vfe_output *output, u8 sync,
+					struct vfe_line *line)
+{
+	u32 addr;
+	unsigned int i;
+
+	for (i = 0; i < output->wm_num; i++) {
+		if (output->buf[0])
+			addr = output->buf[0]->addr[i];
+		else
+			addr = 0;
+
+		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
+		if (sync)
+			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
+	}
+}
+
+static void vfe_output_update_pong_addr(struct vfe_device *vfe,
+					struct vfe_output *output, u8 sync,
+					struct vfe_line *line)
+{
+	u32 addr;
+	unsigned int i;
+
+	for (i = 0; i < output->wm_num; i++) {
+		if (output->buf[1])
+			addr = output->buf[1]->addr[i];
+		else
+			addr = 0;
+
+		// XXX
+	}
+
+}
+
+static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
+				      struct vfe_output *output)
+{
+	switch (output->state) {
+	case VFE_OUTPUT_CONTINUOUS:
+		vfe_output_frame_drop(vfe, output, 3);
+		break;
+	case VFE_OUTPUT_SINGLE:
+	default:
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Next buf in wrong state! %d\n",
+				    output->state);
+		break;
+	}
+}
+
+static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
+				      struct vfe_output *output)
+{
+	switch (output->state) {
+	case VFE_OUTPUT_CONTINUOUS:
+		output->state = VFE_OUTPUT_SINGLE;
+		vfe_output_frame_drop(vfe, output, 1);
+		break;
+	case VFE_OUTPUT_SINGLE:
+		output->state = VFE_OUTPUT_STOPPING;
+		vfe_output_frame_drop(vfe, output, 0);
+		break;
+	default:
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Last buff in wrong state! %d\n",
+				    output->state);
+		break;
+	}
+}
+
+static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
+				     struct vfe_output *output,
+				     struct camss_buffer *new_buf,
+				     struct vfe_line *line)
+{
+	int inactive_idx;
+
+	switch (output->state) {
+	case VFE_OUTPUT_SINGLE:
+		inactive_idx = !output->gen1.active_buf;
+
+		if (!output->buf[inactive_idx]) {
+			output->buf[inactive_idx] = new_buf;
+
+			if (inactive_idx)
+				vfe_output_update_pong_addr(vfe, output, 0, line);
+			else
+				vfe_output_update_ping_addr(vfe, output, 0, line);
+
+			vfe_output_frame_drop(vfe, output, 3);
+			output->state = VFE_OUTPUT_CONTINUOUS;
+		} else {
+			vfe_buf_add_pending(output, new_buf);
+			dev_err_ratelimited(vfe->camss->dev,
+					    "Inactive buffer is busy\n");
+		}
+		break;
+
+	case VFE_OUTPUT_IDLE:
+		if (!output->buf[0]) {
+			output->buf[0] = new_buf;
+
+			vfe_output_init_addrs(vfe, output, 1, line);
+			vfe_output_frame_drop(vfe, output, 1);
+
+			output->state = VFE_OUTPUT_SINGLE;
+		} else {
+			vfe_buf_add_pending(output, new_buf);
+			dev_err_ratelimited(vfe->camss->dev,
+					    "Output idle with buffer set!\n");
+		}
+		break;
+
+	case VFE_OUTPUT_CONTINUOUS:
+	default:
+		vfe_buf_add_pending(output, new_buf);
+		break;
+	}
+}
+
+/*
+ * vfe_isr_halt_ack - Process start of frame interrupt
+ * @vfe: VFE Device
+ */
+static void vfe_isr_halt_ack(struct vfe_device *vfe)
+{
+	complete(&vfe->halt_complete);
+	vfe->ops_gen1->halt_clear(vfe);
+}
+
+/*
+ * vfe_isr_sof - Process start of frame interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	struct vfe_output *output;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	output = &vfe->line[line_id].output;
+	if (output->gen1.wait_sof) {
+		output->gen1.wait_sof = 0;
+		complete(&output->sof);
+	}
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_isr_reg_update - Process reg update interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	struct vfe_output *output;
+	struct vfe_line *line = &vfe->line[line_id];
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	vfe->ops->reg_update_clear(vfe, line_id);
+
+	output = &line->output;
+
+	if (output->wait_reg_update) {
+		output->wait_reg_update = 0;
+		complete(&output->reg_update);
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+		return;
+	}
+
+	if (output->state == VFE_OUTPUT_STOPPING) {
+		/* Release last buffer when hw is idle */
+		if (output->last_buffer) {
+			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
+					VB2_BUF_STATE_DONE);
+			output->last_buffer = NULL;
+		}
+		output->state = VFE_OUTPUT_IDLE;
+
+		/* Buffers received in stopping state are queued in */
+		/* dma pending queue, start next capture here */
+
+		output->buf[0] = vfe_buf_get_pending(output);
+		output->buf[1] = vfe_buf_get_pending(output);
+
+		if (!output->buf[0] && output->buf[1]) {
+			output->buf[0] = output->buf[1];
+			output->buf[1] = NULL;
+		}
+
+		if (output->buf[0])
+			output->state = VFE_OUTPUT_SINGLE;
+
+		if (output->buf[1])
+			output->state = VFE_OUTPUT_CONTINUOUS;
+
+		switch (output->state) {
+		case VFE_OUTPUT_SINGLE:
+			vfe_output_frame_drop(vfe, output, 2);
+			break;
+		case VFE_OUTPUT_CONTINUOUS:
+			vfe_output_frame_drop(vfe, output, 3);
+			break;
+		default:
+			vfe_output_frame_drop(vfe, output, 0);
+			break;
+		}
+
+		vfe_output_init_addrs(vfe, output, 1, &vfe->line[line_id]);
+	}
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_isr_wm_done - Process write master done interrupt
+ * @vfe: VFE Device
+ * @wm: Write master id
+ */
+static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
+{
+	struct camss_buffer *ready_buf;
+	struct vfe_output *output;
+	dma_addr_t *new_addr;
+	unsigned long flags;
+	u32 active_index;
+	u64 ts = ktime_get_ns();
+	unsigned int i;
+
+	active_index = vfe->ops_gen1->wm_get_ping_pong_status(vfe, wm);
+
+	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;
+
+	if (output->gen1.active_buf == active_index && 0) {
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Active buffer mismatch!\n");
+		goto out_unlock;
+	}
+	output->gen1.active_buf = active_index;
+
+	ready_buf = output->buf[!active_index];
+	if (!ready_buf) {
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Missing ready buf %d %d!\n",
+				    !active_index, output->state);
+		goto out_unlock;
+	}
+
+	ready_buf->vb.vb2_buf.timestamp = ts;
+	ready_buf->vb.sequence = output->sequence++;
+
+	/* Get next buffer */
+	output->buf[!active_index] = vfe_buf_get_pending(output);
+	if (!output->buf[!active_index]) {
+		/* No next buffer - set same address */
+		new_addr = ready_buf->addr;
+		vfe_buf_update_wm_on_last(vfe, output);
+	} else {
+		new_addr = output->buf[!active_index]->addr;
+		vfe_buf_update_wm_on_next(vfe, output);
+	}
+
+	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]);
+	else
+		for (i = 0; i < output->wm_num; i++)
+			vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]);
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	if (output->state == VFE_OUTPUT_STOPPING)
+		output->last_buffer = ready_buf;
+	else
+		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+	return;
+
+out_unlock:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_queue_buffer - Add empty buffer
+ * @vid: Video device structure
+ * @buf: Buffer to be enqueued
+ *
+ * Add an empty buffer - depending on the current number of buffers it will be
+ * put in pending buffer queue or directly given to the hardware to be filled.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+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_device *vfe = to_vfe(line);
+	struct vfe_output *output;
+	unsigned long flags;
+
+	output = &line->output;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	vfe_buf_update_wm_on_new(vfe, output, buf, line);
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+inline u8 vfe_calc_interp_reso(u16 input, u16 output)
+{
+	if (input / output >= 16)
+		return 0;
+
+	if (input / output >= 8)
+		return 1;
+
+	if (input / output >= 4)
+		return 2;
+
+	return 3;
+}
+
+#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
+
+int vfe_word_per_line(u32 format, u32 width)
+{
+	int val = 0;
+
+	switch (format) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		val = CALC_WORD(width, 1, 8);
+		break;
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_VYUY:
+		val = CALC_WORD(width, 2, 8);
+		break;
+	}
+
+	return val;
+}
+
+const struct vfe_isr_ops vfe_isr_ops_gen1 = {
+	.reset_ack = vfe_isr_reset_ack,
+	.halt_ack = vfe_isr_halt_ack,
+	.reg_update = vfe_isr_reg_update,
+	.sof = vfe_isr_sof,
+	.comp_done = vfe_isr_comp_done,
+	.wm_done = vfe_isr_wm_done,
+};
+
+const struct camss_video_ops vfe_video_ops_gen1 = {
+	.queue_buffer = vfe_queue_buffer,
+	.flush_buffers = vfe_flush_buffers,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.h b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
new file mode 100644
index 000000000000..42e8a3333034
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * camss-vfe.h
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module
+ *
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015-2018 Linaro Ltd.
+ */
+#ifndef QC_MSM_CAMSS_VFE_GEN1_H
+#define QC_MSM_CAMSS_VFE_GEN1_H
+
+
+#include "camss-vfe.h"
+
+
+enum vfe_line_id;
+struct vfe_device;
+struct vfe_line;
+struct vfe_output;
+
+struct vfe_hw_ops_gen1 {
+	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
+	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
+	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
+	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
+	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
+	void (*enable_irq_common)(struct vfe_device *vfe);
+	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, enum vfe_line_id line_id,
+				   u8 enable);
+	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, enum vfe_line_id line_id,
+				    u8 enable);
+	u16 (*get_ub_size)(u8 vfe_id);
+	void (*halt_clear)(struct vfe_device *vfe);
+	void (*halt_request)(struct vfe_device *vfe);
+	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
+	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
+	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
+	void (*set_clamp_cfg)(struct vfe_device *vfe);
+	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
+	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
+	void (*set_ds)(struct vfe_device *vfe);
+	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
+	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
+	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid);
+	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, u8 enable);
+	void (*set_qos)(struct vfe_device *vfe);
+	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, u8 enable);
+	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
+	void (*wm_line_based)(struct vfe_device *vfe, u32 wm, struct v4l2_pix_format_mplane *pix,
+			      u8 plane, u32 enable);
+	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, u16 depth);
+	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
+	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
+	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, u32 pattern);
+	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
+	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
+	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
+	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
+};
+
+/*
+ * vfe_calc_interp_reso - Calculate interpolation mode
+ * @input: Input resolution
+ * @output: Output resolution
+ *
+ * Return interpolation mode
+ */
+inline u8 vfe_calc_interp_reso(u16 input, u16 output);
+
+/*
+ * vfe_gen1_disable - Disable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_gen1_disable(struct vfe_line *line);
+
+
+/*
+ * vfe_gen1_enable - Enable VFE module
+ * @line: VFE line
+ *
+ * Return 0 on success
+ */
+int vfe_gen1_enable(struct vfe_line *line);
+
+/*
+ * vfe_gen1_enable - Halt VFE module
+ * @vfe: VFE device
+ *
+ * Return 0 on success
+ */
+int vfe_gen1_halt(struct vfe_device *vfe);
+
+/*
+ * vfe_word_per_line - Calculate number of words per frame width
+ * @format: V4L2 format
+ * @width: Frame width
+ *
+ * Return number of words per frame width
+ */
+int vfe_word_per_line(u32 format, u32 width);
+
+
+extern const struct vfe_isr_ops vfe_isr_ops_gen1;
+extern const struct camss_video_ops vfe_video_ops_gen1;
+
+
+#endif /* QC_MSM_CAMSS_VFE_GEN1_H */
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 478be4f0cab5..2ffa5b3c5426 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -26,22 +26,8 @@
 
 #define MSM_VFE_NAME "msm_vfe"
 
-#define vfe_line_array(ptr_line)	\
-	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
-
-#define to_vfe(ptr_line)	\
-	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
-
 /* VFE reset timeout */
 #define VFE_RESET_TIMEOUT_MS 50
-/* VFE halt timeout */
-#define VFE_HALT_TIMEOUT_MS 100
-/* Max number of frame drop updates per frame */
-#define VFE_FRAME_DROP_UPDATES 2
-/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
-#define VFE_FRAME_DROP_VAL 30
-
-#define VFE_NEXT_SOF_MS 500
 
 #define SCALER_RATIO_MAX 16
 
@@ -294,30 +280,6 @@ static int vfe_reset(struct vfe_device *vfe)
 	return 0;
 }
 
-/*
- * vfe_halt - Trigger halt on VFE module and wait to complete
- * @vfe: VFE device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int vfe_halt(struct vfe_device *vfe)
-{
-	unsigned long time;
-
-	reinit_completion(&vfe->halt_complete);
-
-	vfe->ops->halt_request(vfe);
-
-	time = wait_for_completion_timeout(&vfe->halt_complete,
-		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
-	if (!time) {
-		dev_err(vfe->camss->dev, "VFE halt timeout\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
 static void vfe_init_outputs(struct vfe_device *vfe)
 {
 	int i;
@@ -340,71 +302,7 @@ static void vfe_reset_output_maps(struct vfe_device *vfe)
 		vfe->wm_output_map[i] = VFE_LINE_NONE;
 }
 
-static void vfe_output_init_addrs(struct vfe_device *vfe,
-				  struct vfe_output *output, u8 sync)
-{
-	u32 ping_addr;
-	u32 pong_addr;
-	unsigned int i;
-
-	output->active_buf = 0;
-
-	for (i = 0; i < output->wm_num; i++) {
-		if (output->buf[0])
-			ping_addr = output->buf[0]->addr[i];
-		else
-			ping_addr = 0;
-
-		if (output->buf[1])
-			pong_addr = output->buf[1]->addr[i];
-		else
-			pong_addr = ping_addr;
-
-		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
-		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
-		if (sync)
-			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
-	}
-}
-
-static void vfe_output_update_ping_addr(struct vfe_device *vfe,
-					struct vfe_output *output, u8 sync)
-{
-	u32 addr;
-	unsigned int i;
-
-	for (i = 0; i < output->wm_num; i++) {
-		if (output->buf[0])
-			addr = output->buf[0]->addr[i];
-		else
-			addr = 0;
-
-		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
-		if (sync)
-			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
-	}
-}
-
-static void vfe_output_update_pong_addr(struct vfe_device *vfe,
-					struct vfe_output *output, u8 sync)
-{
-	u32 addr;
-	unsigned int i;
-
-	for (i = 0; i < output->wm_num; i++) {
-		if (output->buf[1])
-			addr = output->buf[1]->addr[i];
-		else
-			addr = 0;
-
-		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
-		if (sync)
-			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
-	}
-
-}
-
-static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
+int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
 {
 	int ret = -EBUSY;
 	int i;
@@ -420,7 +318,7 @@ static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
 	return ret;
 }
 
-static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
+int vfe_release_wm(struct vfe_device *vfe, u8 wm)
 {
 	if (wm >= ARRAY_SIZE(vfe->wm_output_map))
 		return -EINVAL;
@@ -430,29 +328,7 @@ static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
 	return 0;
 }
 
-static void vfe_output_frame_drop(struct vfe_device *vfe,
-				  struct vfe_output *output,
-				  u32 drop_pattern)
-{
-	u8 drop_period;
-	unsigned int i;
-
-	/* We need to toggle update period to be valid on next frame */
-	output->drop_update_idx++;
-	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
-	drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
-
-	for (i = 0; i < output->wm_num; i++) {
-		vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i],
-						  drop_period);
-		vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i],
-						   drop_pattern);
-	}
-	vfe->ops->reg_update(vfe,
-			     container_of(output, struct vfe_line, output)->id);
-}
-
-static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
+struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
 {
 	struct camss_buffer *buffer = NULL;
 
@@ -466,13 +342,8 @@ static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
 	return buffer;
 }
 
-/*
- * vfe_buf_add_pending - Add output buffer to list of pending
- * @output: VFE output
- * @buffer: Video buffer
- */
-static void vfe_buf_add_pending(struct vfe_output *output,
-				struct camss_buffer *buffer)
+void vfe_buf_add_pending(struct vfe_output *output,
+			 struct camss_buffer *buffer)
 {
 	INIT_LIST_HEAD(&buffer->queue);
 	list_add_tail(&buffer->queue, &output->pending_bufs);
@@ -495,149 +366,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output,
 	}
 }
 
-static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
-				      struct vfe_output *output)
-{
-	switch (output->state) {
-	case VFE_OUTPUT_CONTINUOUS:
-		vfe_output_frame_drop(vfe, output, 3);
-		break;
-	case VFE_OUTPUT_SINGLE:
-	default:
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Next buf in wrong state! %d\n",
-				    output->state);
-		break;
-	}
-}
-
-static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
-				      struct vfe_output *output)
-{
-	switch (output->state) {
-	case VFE_OUTPUT_CONTINUOUS:
-		output->state = VFE_OUTPUT_SINGLE;
-		vfe_output_frame_drop(vfe, output, 1);
-		break;
-	case VFE_OUTPUT_SINGLE:
-		output->state = VFE_OUTPUT_STOPPING;
-		vfe_output_frame_drop(vfe, output, 0);
-		break;
-	default:
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Last buff in wrong state! %d\n",
-				    output->state);
-		break;
-	}
-}
-
-static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
-				     struct vfe_output *output,
-				     struct camss_buffer *new_buf)
-{
-	int inactive_idx;
-
-	switch (output->state) {
-	case VFE_OUTPUT_SINGLE:
-		inactive_idx = !output->active_buf;
-
-		if (!output->buf[inactive_idx]) {
-			output->buf[inactive_idx] = new_buf;
-
-			if (inactive_idx)
-				vfe_output_update_pong_addr(vfe, output, 0);
-			else
-				vfe_output_update_ping_addr(vfe, output, 0);
-
-			vfe_output_frame_drop(vfe, output, 3);
-			output->state = VFE_OUTPUT_CONTINUOUS;
-		} else {
-			vfe_buf_add_pending(output, new_buf);
-			dev_err_ratelimited(vfe->camss->dev,
-					    "Inactive buffer is busy\n");
-		}
-		break;
-
-	case VFE_OUTPUT_IDLE:
-		if (!output->buf[0]) {
-			output->buf[0] = new_buf;
-
-			vfe_output_init_addrs(vfe, output, 1);
-
-			vfe_output_frame_drop(vfe, output, 1);
-			output->state = VFE_OUTPUT_SINGLE;
-		} else {
-			vfe_buf_add_pending(output, new_buf);
-			dev_err_ratelimited(vfe->camss->dev,
-					    "Output idle with buffer set!\n");
-		}
-		break;
-
-	case VFE_OUTPUT_CONTINUOUS:
-	default:
-		vfe_buf_add_pending(output, new_buf);
-		break;
-	}
-}
-
-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;
-	unsigned long flags;
-	int i;
-	int wm_idx;
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	output = &line->output;
-	if (output->state != VFE_OUTPUT_OFF) {
-		dev_err(vfe->camss->dev, "Output is running\n");
-		goto error;
-	}
-	output->state = VFE_OUTPUT_RESERVED;
-
-	output->active_buf = 0;
-
-	switch (f->fmt.pix_mp.pixelformat) {
-	case V4L2_PIX_FMT_NV12:
-	case V4L2_PIX_FMT_NV21:
-	case V4L2_PIX_FMT_NV16:
-	case V4L2_PIX_FMT_NV61:
-		output->wm_num = 2;
-		break;
-	default:
-		output->wm_num = 1;
-		break;
-	}
-
-	for (i = 0; i < output->wm_num; i++) {
-		wm_idx = vfe_reserve_wm(vfe, line->id);
-		if (wm_idx < 0) {
-			dev_err(vfe->camss->dev, "Can not reserve wm\n");
-			goto error_get_wm;
-		}
-		output->wm_idx[i] = wm_idx;
-	}
-
-	output->drop_update_idx = 0;
-
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	return 0;
-
-error_get_wm:
-	for (i--; i >= 0; i--)
-		vfe_release_wm(vfe, output->wm_idx[i]);
-	output->state = VFE_OUTPUT_OFF;
-error:
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	return -EINVAL;
-}
-
-static int vfe_put_output(struct vfe_line *line)
+int vfe_put_output(struct vfe_line *line)
 {
 	struct vfe_device *vfe = to_vfe(line);
 	struct vfe_output *output = &line->output;
@@ -655,454 +384,27 @@ static int vfe_put_output(struct vfe_line *line)
 	return 0;
 }
 
-static int vfe_enable_output(struct vfe_line *line)
-{
-	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
-	const struct vfe_hw_ops *ops = vfe->ops;
-	struct media_entity *sensor;
-	unsigned long flags;
-	unsigned int frame_skip = 0;
-	unsigned int i;
-	u16 ub_size;
-
-	ub_size = ops->get_ub_size(vfe->id);
-	if (!ub_size)
-		return -EINVAL;
-
-	sensor = camss_find_sensor(&line->subdev.entity);
-	if (sensor) {
-		struct v4l2_subdev *subdev =
-					media_entity_to_v4l2_subdev(sensor);
-
-		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;
-	}
-	output->state = VFE_OUTPUT_IDLE;
-
-	output->buf[0] = vfe_buf_get_pending(output);
-	output->buf[1] = vfe_buf_get_pending(output);
-
-	if (!output->buf[0] && output->buf[1]) {
-		output->buf[0] = output->buf[1];
-		output->buf[1] = NULL;
-	}
-
-	if (output->buf[0])
-		output->state = VFE_OUTPUT_SINGLE;
-
-	if (output->buf[1])
-		output->state = VFE_OUTPUT_CONTINUOUS;
-
-	switch (output->state) {
-	case VFE_OUTPUT_SINGLE:
-		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
-		break;
-	case VFE_OUTPUT_CONTINUOUS:
-		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
-		break;
-	default:
-		vfe_output_frame_drop(vfe, output, 0);
-		break;
-	}
-
-	output->sequence = 0;
-	output->wait_sof = 0;
-	output->wait_reg_update = 0;
-	reinit_completion(&output->sof);
-	reinit_completion(&output->reg_update);
-
-	vfe_output_init_addrs(vfe, output, 0);
-
-	if (line->id != VFE_LINE_PIX) {
-		ops->set_cgc_override(vfe, output->wm_idx[0], 1);
-		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
-		ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
-		ops->wm_set_subsample(vfe, output->wm_idx[0]);
-		ops->set_rdi_cid(vfe, line->id, 0);
-		ops->wm_set_ub_cfg(vfe, output->wm_idx[0],
-				   (ub_size + 1) * output->wm_idx[0], ub_size);
-		ops->wm_frame_based(vfe, output->wm_idx[0], 1);
-		ops->wm_enable(vfe, output->wm_idx[0], 1);
-		ops->bus_reload_wm(vfe, output->wm_idx[0]);
-	} else {
-		ub_size /= output->wm_num;
-		for (i = 0; i < output->wm_num; i++) {
-			ops->set_cgc_override(vfe, output->wm_idx[i], 1);
-			ops->wm_set_subsample(vfe, output->wm_idx[i]);
-			ops->wm_set_ub_cfg(vfe, output->wm_idx[i],
-					   (ub_size + 1) * output->wm_idx[i],
-					   ub_size);
-			ops->wm_line_based(vfe, output->wm_idx[i],
-					&line->video_out.active_fmt.fmt.pix_mp,
-					i, 1);
-			ops->wm_enable(vfe, output->wm_idx[i], 1);
-			ops->bus_reload_wm(vfe, output->wm_idx[i]);
-		}
-		ops->enable_irq_pix_line(vfe, 0, line->id, 1);
-		ops->set_module_cfg(vfe, 1);
-		ops->set_camif_cfg(vfe, line);
-		ops->set_realign_cfg(vfe, line, 1);
-		ops->set_xbar_cfg(vfe, output, 1);
-		ops->set_demux_cfg(vfe, line);
-		ops->set_scale_cfg(vfe, line);
-		ops->set_crop_cfg(vfe, line);
-		ops->set_clamp_cfg(vfe);
-		ops->set_camif_cmd(vfe, 1);
-	}
-
-	ops->reg_update(vfe, line->id);
-
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	return 0;
-}
-
-static int vfe_disable_output(struct vfe_line *line)
-{
-	struct vfe_device *vfe = to_vfe(line);
-	struct vfe_output *output = &line->output;
-	const struct vfe_hw_ops *ops = vfe->ops;
-	unsigned long flags;
-	unsigned long time;
-	unsigned int i;
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	output->wait_sof = 1;
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	time = wait_for_completion_timeout(&output->sof,
-					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
-	if (!time)
-		dev_err(vfe->camss->dev, "VFE sof timeout\n");
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-	for (i = 0; i < output->wm_num; i++)
-		ops->wm_enable(vfe, output->wm_idx[i], 0);
-
-	ops->reg_update(vfe, line->id);
-	output->wait_reg_update = 1;
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	time = wait_for_completion_timeout(&output->reg_update,
-					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
-	if (!time)
-		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	if (line->id != VFE_LINE_PIX) {
-		ops->wm_frame_based(vfe, output->wm_idx[0], 0);
-		ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0],
-						line->id);
-		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
-		ops->set_cgc_override(vfe, output->wm_idx[0], 0);
-		spin_unlock_irqrestore(&vfe->output_lock, flags);
-	} else {
-		for (i = 0; i < output->wm_num; i++) {
-			ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
-			ops->set_cgc_override(vfe, output->wm_idx[i], 0);
-		}
-
-		ops->enable_irq_pix_line(vfe, 0, line->id, 0);
-		ops->set_module_cfg(vfe, 0);
-		ops->set_realign_cfg(vfe, line, 0);
-		ops->set_xbar_cfg(vfe, output, 0);
-
-		ops->set_camif_cmd(vfe, 0);
-		spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-		ops->camif_wait_for_stop(vfe, vfe->camss->dev);
-	}
-
-	return 0;
-}
-
-/*
- * vfe_enable - Enable streaming on VFE line
- * @line: VFE line
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int vfe_enable(struct vfe_line *line)
-{
-	struct vfe_device *vfe = to_vfe(line);
-	int ret;
-
-	mutex_lock(&vfe->stream_lock);
-
-	if (!vfe->stream_count) {
-		vfe->ops->enable_irq_common(vfe);
-
-		vfe->ops->bus_enable_wr_if(vfe, 1);
-
-		vfe->ops->set_qos(vfe);
-
-		vfe->ops->set_ds(vfe);
-	}
-
-	vfe->stream_count++;
-
-	mutex_unlock(&vfe->stream_lock);
-
-	ret = vfe_get_output(line);
-	if (ret < 0)
-		goto error_get_output;
-
-	ret = vfe_enable_output(line);
-	if (ret < 0)
-		goto error_enable_output;
-
-	vfe->was_streaming = 1;
-
-	return 0;
-
-
-error_enable_output:
-	vfe_put_output(line);
-
-error_get_output:
-	mutex_lock(&vfe->stream_lock);
-
-	if (vfe->stream_count == 1)
-		vfe->ops->bus_enable_wr_if(vfe, 0);
-
-	vfe->stream_count--;
-
-	mutex_unlock(&vfe->stream_lock);
-
-	return ret;
-}
-
-/*
- * vfe_disable - Disable streaming on VFE line
- * @line: VFE line
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int vfe_disable(struct vfe_line *line)
-{
-	struct vfe_device *vfe = to_vfe(line);
-
-	vfe_disable_output(line);
-
-	vfe_put_output(line);
-
-	mutex_lock(&vfe->stream_lock);
-
-	if (vfe->stream_count == 1)
-		vfe->ops->bus_enable_wr_if(vfe, 0);
-
-	vfe->stream_count--;
-
-	mutex_unlock(&vfe->stream_lock);
-
-	return 0;
-}
-
-/*
- * vfe_isr_sof - Process start of frame interrupt
- * @vfe: VFE Device
- * @line_id: VFE line
- */
-static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
-{
-	struct vfe_output *output;
-	unsigned long flags;
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-	output = &vfe->line[line_id].output;
-	if (output->wait_sof) {
-		output->wait_sof = 0;
-		complete(&output->sof);
-	}
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-}
-
-/*
- * vfe_isr_reg_update - Process reg update interrupt
- * @vfe: VFE Device
- * @line_id: VFE line
- */
-static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
-{
-	struct vfe_output *output;
-	unsigned long flags;
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-	vfe->ops->reg_update_clear(vfe, line_id);
-
-	output = &vfe->line[line_id].output;
-
-	if (output->wait_reg_update) {
-		output->wait_reg_update = 0;
-		complete(&output->reg_update);
-		spin_unlock_irqrestore(&vfe->output_lock, flags);
-		return;
-	}
-
-	if (output->state == VFE_OUTPUT_STOPPING) {
-		/* Release last buffer when hw is idle */
-		if (output->last_buffer) {
-			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
-					VB2_BUF_STATE_DONE);
-			output->last_buffer = NULL;
-		}
-		output->state = VFE_OUTPUT_IDLE;
-
-		/* Buffers received in stopping state are queued in */
-		/* dma pending queue, start next capture here */
-
-		output->buf[0] = vfe_buf_get_pending(output);
-		output->buf[1] = vfe_buf_get_pending(output);
-
-		if (!output->buf[0] && output->buf[1]) {
-			output->buf[0] = output->buf[1];
-			output->buf[1] = NULL;
-		}
-
-		if (output->buf[0])
-			output->state = VFE_OUTPUT_SINGLE;
-
-		if (output->buf[1])
-			output->state = VFE_OUTPUT_CONTINUOUS;
-
-		switch (output->state) {
-		case VFE_OUTPUT_SINGLE:
-			vfe_output_frame_drop(vfe, output, 2);
-			break;
-		case VFE_OUTPUT_CONTINUOUS:
-			vfe_output_frame_drop(vfe, output, 3);
-			break;
-		default:
-			vfe_output_frame_drop(vfe, output, 0);
-			break;
-		}
-
-		vfe_output_init_addrs(vfe, output, 1);
-	}
-
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-}
-
-/*
- * vfe_isr_wm_done - Process write master done interrupt
- * @vfe: VFE Device
- * @wm: Write master id
- */
-static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
-{
-	struct camss_buffer *ready_buf;
-	struct vfe_output *output;
-	dma_addr_t *new_addr;
-	unsigned long flags;
-	u32 active_index;
-	u64 ts = ktime_get_ns();
-	unsigned int i;
-
-	active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm);
-
-	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;
-
-	if (output->active_buf == active_index) {
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Active buffer mismatch!\n");
-		goto out_unlock;
-	}
-	output->active_buf = active_index;
-
-	ready_buf = output->buf[!active_index];
-	if (!ready_buf) {
-		dev_err_ratelimited(vfe->camss->dev,
-				    "Missing ready buf %d %d!\n",
-				    !active_index, output->state);
-		goto out_unlock;
-	}
-
-	ready_buf->vb.vb2_buf.timestamp = ts;
-	ready_buf->vb.sequence = output->sequence++;
-
-	/* Get next buffer */
-	output->buf[!active_index] = vfe_buf_get_pending(output);
-	if (!output->buf[!active_index]) {
-		/* No next buffer - set same address */
-		new_addr = ready_buf->addr;
-		vfe_buf_update_wm_on_last(vfe, output);
-	} else {
-		new_addr = output->buf[!active_index]->addr;
-		vfe_buf_update_wm_on_next(vfe, output);
-	}
-
-	if (active_index)
-		for (i = 0; i < output->wm_num; i++)
-			vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i],
-						   new_addr[i]);
-	else
-		for (i = 0; i < output->wm_num; i++)
-			vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i],
-						   new_addr[i]);
-
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	if (output->state == VFE_OUTPUT_STOPPING)
-		output->last_buffer = ready_buf;
-	else
-		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
-	return;
-
-out_unlock:
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-}
-
 /*
  * vfe_isr_comp_done - Process composite image done interrupt
  * @vfe: VFE Device
  * @comp: Composite image id
  */
-static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
+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) {
-			vfe_isr_wm_done(vfe, i);
+			vfe->isr_ops.wm_done(vfe, i);
 			break;
 		}
 }
 
-static inline void vfe_isr_reset_ack(struct vfe_device *vfe)
+void vfe_isr_reset_ack(struct vfe_device *vfe)
 {
 	complete(&vfe->reset_complete);
 }
 
-static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
-{
-	complete(&vfe->halt_complete);
-	vfe->ops->halt_clear(vfe);
-}
-
 /*
  * vfe_set_clock_rates - Calculate and set clock rates on VFE module
  * @vfe: VFE device
@@ -1318,7 +620,7 @@ static void vfe_put(struct vfe_device *vfe)
 	} else if (vfe->power_count == 1) {
 		if (vfe->was_streaming) {
 			vfe->was_streaming = 0;
-			vfe_halt(vfe);
+			vfe->ops->vfe_halt(vfe);
 		}
 		camss_disable_clocks(vfe->nclocks, vfe->clock);
 		pm_runtime_put_sync(vfe->camss->dev);
@@ -1331,35 +633,6 @@ static void vfe_put(struct vfe_device *vfe)
 	mutex_unlock(&vfe->power_lock);
 }
 
-/*
- * vfe_queue_buffer - Add empty buffer
- * @vid: Video device structure
- * @buf: Buffer to be enqueued
- *
- * Add an empty buffer - depending on the current number of buffers it will be
- * put in pending buffer queue or directly given to the hardware to be filled.
- *
- * Return 0 on success or a negative error code otherwise
- */
-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_device *vfe = to_vfe(line);
-	struct vfe_output *output;
-	unsigned long flags;
-
-	output = &line->output;
-
-	spin_lock_irqsave(&vfe->output_lock, flags);
-
-	vfe_buf_update_wm_on_new(vfe, output, buf);
-
-	spin_unlock_irqrestore(&vfe->output_lock, flags);
-
-	return 0;
-}
-
 /*
  * vfe_flush_buffers - Return all vb2 buffers
  * @vid: Video device structure
@@ -1370,8 +643,8 @@ static int vfe_queue_buffer(struct camss_video *vid,
  *
  * Return 0 on success or a negative error code otherwise
  */
-static int vfe_flush_buffers(struct camss_video *vid,
-			     enum vb2_buffer_state state)
+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_device *vfe = to_vfe(line);
@@ -1442,12 +715,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
 	int ret;
 
 	if (enable) {
-		ret = vfe_enable(line);
+		ret = vfe->ops->vfe_enable(line);
 		if (ret < 0)
 			dev_err(vfe->camss->dev,
 				"Failed to enable vfe outputs\n");
 	} else {
-		ret = vfe_disable(line);
+		ret = vfe->ops->vfe_disable(line);
 		if (ret < 0)
 			dev_err(vfe->camss->dev,
 				"Failed to disable vfe outputs\n");
@@ -1985,13 +1258,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 	int i, j;
 	int ret;
 
-	vfe->isr_ops.reset_ack = vfe_isr_reset_ack;
-	vfe->isr_ops.halt_ack = vfe_isr_halt_ack;
-	vfe->isr_ops.reg_update = vfe_isr_reg_update;
-	vfe->isr_ops.sof = vfe_isr_sof;
-	vfe->isr_ops.comp_done = vfe_isr_comp_done;
-	vfe->isr_ops.wm_done = vfe_isr_wm_done;
-
 	switch (camss->version) {
 	case CAMSS_8x16:
 		vfe->ops = &vfe_ops_4_1;
@@ -2005,6 +1271,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 	default:
 		return -EINVAL;
 	}
+	vfe->ops->subdev_init(vfe);
 
 	/* Memory */
 
@@ -2209,11 +1476,6 @@ static const struct media_entity_operations vfe_media_ops = {
 	.link_validate = v4l2_subdev_link_validate,
 };
 
-static const struct camss_video_ops camss_vfe_video_ops = {
-	.queue_buffer = vfe_queue_buffer,
-	.flush_buffers = vfe_flush_buffers,
-};
-
 /*
  * msm_vfe_register_entities - Register subdev node for VFE module
  * @vfe: VFE device
@@ -2279,7 +1541,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
 			goto error_reg_subdev;
 		}
 
-		video_out->ops = &camss_vfe_video_ops;
+		video_out->ops = &vfe->video_ops;
 		video_out->bpl_alignment = 8;
 		video_out->line_based = 0;
 		if (i == VFE_LINE_PIX) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 5bce6736e4bb..8629c833f130 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -17,6 +17,8 @@
 #include <media/v4l2-subdev.h>
 
 #include "camss-video.h"
+#include "camss-vfe-gen1.h"
+
 
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
@@ -26,6 +28,18 @@
 #define MSM_VFE_IMAGE_MASTERS_NUM 7
 #define MSM_VFE_COMPOSITE_IRQ_NUM 4
 
+/* VFE halt timeout */
+#define VFE_HALT_TIMEOUT_MS 100
+/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
+#define VFE_FRAME_DROP_VAL 30
+
+#define vfe_line_array(ptr_line)	\
+	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
+
+#define to_vfe(ptr_line)	\
+	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
+
+
 enum vfe_output_state {
 	VFE_OUTPUT_OFF,
 	VFE_OUTPUT_RESERVED,
@@ -47,16 +61,21 @@ struct vfe_output {
 	u8 wm_num;
 	u8 wm_idx[3];
 
-	int active_buf;
 	struct camss_buffer *buf[2];
 	struct camss_buffer *last_buffer;
 	struct list_head pending_bufs;
 
 	unsigned int drop_update_idx;
 
+	union {
+		struct {
+			int active_buf;
+			int wait_sof;
+		} gen1;
+	};
 	enum vfe_output_state state;
 	unsigned int sequence;
-	int wait_sof;
+
 	int wait_reg_update;
 	struct completion sof;
 	struct completion reg_update;
@@ -78,59 +97,19 @@ struct vfe_line {
 struct vfe_device;
 
 struct vfe_hw_ops {
-	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
-	u16 (*get_ub_size)(u8 vfe_id);
+	void (*enable_irq_common)(struct vfe_device *vfe);
 	void (*global_reset)(struct vfe_device *vfe);
-	void (*halt_request)(struct vfe_device *vfe);
-	void (*halt_clear)(struct vfe_device *vfe);
-	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
-	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
-	void (*wm_line_based)(struct vfe_device *vfe, u32 wm,
-			      struct v4l2_pix_format_mplane *pix,
-			      u8 plane, u32 enable);
-	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
-	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm,
-					 u32 pattern);
-	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset,
-			      u16 depth);
-	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
-	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
-	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
-	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
-	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
-	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm,
-				      enum vfe_line_id id);
-	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
-	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm,
-					   enum vfe_line_id id);
-	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output,
-			     u8 enable);
-	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id,
-			    u8 cid);
-	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line,
-				u8 enable);
+	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
+	irqreturn_t (*isr)(int irq, void *dev);
+	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
 	void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id);
 	void (*reg_update_clear)(struct vfe_device *vfe,
 				 enum vfe_line_id line_id);
-	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm,
-				   enum vfe_line_id line_id, u8 enable);
-	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp,
-				    enum vfe_line_id line_id, u8 enable);
-	void (*enable_irq_common)(struct vfe_device *vfe);
-	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
-	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
-	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
-	void (*set_clamp_cfg)(struct vfe_device *vfe);
-	void (*set_qos)(struct vfe_device *vfe);
-	void (*set_ds)(struct vfe_device *vfe);
-	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
-	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
-	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
-	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
-	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
-	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
+	void (*subdev_init)(struct vfe_device *vfe);
+	int (*vfe_disable)(struct vfe_line *line);
+	int (*vfe_enable)(struct vfe_line *line);
+	int (*vfe_halt)(struct vfe_device *vfe);
 	void (*violation_read)(struct vfe_device *vfe);
-	irqreturn_t (*isr)(int irq, void *dev);
 };
 
 struct vfe_isr_ops {
@@ -162,7 +141,9 @@ struct vfe_device {
 	u32 reg_update;
 	u8 was_streaming;
 	const struct vfe_hw_ops *ops;
+	const struct vfe_hw_ops_gen1 *ops_gen1;
 	struct vfe_isr_ops isr_ops;
+	struct camss_video_ops video_ops;
 };
 
 struct resources;
@@ -178,6 +159,38 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe);
 void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
 void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
 
+
+/*
+ * vfe_buf_add_pending - Add output buffer to list of pending
+ * @output: VFE output
+ * @buffer: Video buffer
+ */
+void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer);
+
+struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
+
+/*
+ * vfe_disable - Disable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_disable(struct vfe_line *line);
+
+int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
+
+/*
+ * vfe_isr_comp_done - Process composite image done interrupt
+ * @vfe: VFE Device
+ * @comp: Composite image id
+ */
+void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp);
+
+void vfe_isr_reset_ack(struct vfe_device *vfe);
+int vfe_put_output(struct vfe_line *line);
+int vfe_release_wm(struct vfe_device *vfe, u8 wm);
+int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
+
 extern const struct vfe_hw_ops vfe_ops_4_1;
 extern const struct vfe_hw_ops vfe_ops_4_7;
 extern const struct vfe_hw_ops vfe_ops_4_8;
-- 
2.27.0


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

* [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add register definitions for version 170 of the Titan architecture
and implement support for the RDI output mode.

The RDI mode as opposed to the PIX output mode for the VFE unit does
not support any ISP functionality. This means essentially only
supporting dumping the output of the whatever the CSI decoder receives
from the sensor.

For example will a sensor outputting YUV pixel format frames, only
allow the VFE to dump those frames as they are received by the ISP
to memory through the RDI interface.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   1 +
 .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
 drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
 .../media/platform/qcom/camss/camss-video.c   | 100 +++
 drivers/media/platform/qcom/camss/camss.c     |  61 ++
 6 files changed, 1034 insertions(+), 20 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 940c0ae3e003..052c4f405fa3 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -11,6 +11,7 @@ qcom-camss-objs += \
 		camss-vfe-4-1.o \
 		camss-vfe-4-7.o \
 		camss-vfe-4-8.o \
+		camss-vfe-170.o \
 		camss-vfe-gen1.o \
 		camss-vfe.o \
 		camss-video.o \
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
new file mode 100644
index 000000000000..89b6c47cca22
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
+ *
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015-2018 Linaro Ltd.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+
+#define VFE_HW_VERSION				(0x000)
+
+#define VFE_GLOBAL_RESET_CMD			(0x018)
+#define		GLOBAL_RESET_CMD_CORE		BIT(0)
+#define		GLOBAL_RESET_CMD_CAMIF		BIT(1)
+#define		GLOBAL_RESET_CMD_BUS		BIT(2)
+#define		GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
+#define		GLOBAL_RESET_CMD_REGISTER	BIT(4)
+#define		GLOBAL_RESET_CMD_PM		BIT(5)
+#define		GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
+#define		GLOBAL_RESET_CMD_TESTGEN	BIT(7)
+#define		GLOBAL_RESET_CMD_DSP		BIT(8)
+#define		GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
+
+#define VFE_CORE_CFG				(0x050)
+#define		CFG_PIXEL_PATTERN_YCBYCR	(0x4)
+#define		CFG_PIXEL_PATTERN_YCRYCB	(0x5)
+#define		CFG_PIXEL_PATTERN_CBYCRY	(0x6)
+#define		CFG_PIXEL_PATTERN_CRYCBY	(0x7)
+#define		CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
+
+#define VFE_IRQ_CMD				(0x058)
+#define		CMD_GLOBAL_CLEAR		BIT(0)
+
+#define VFE_IRQ_MASK_0					(0x05c)
+#define		MASK_0_CAMIF_SOF			BIT(0)
+#define		MASK_0_CAMIF_EOF			BIT(1)
+#define		MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define		MASK_0_line_n_REG_UPDATE(n)		\
+			((n) == VFE_LINE_PIX ? \
+				BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
+#define		MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define		MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define		MASK_0_RESET_ACK			BIT(31)
+
+#define VFE_IRQ_MASK_1					(0x060)
+#define		MASK_1_CAMIF_ERROR			BIT(0)
+#define		MASK_1_VIOLATION			BIT(7)
+#define		MASK_1_BUS_BDG_HALT_ACK			BIT(8)
+#define		MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
+#define		MASK_1_RDIn_SOF(n)			BIT((n) + 29)
+
+#define VFE_IRQ_CLEAR_0					(0x064)
+#define VFE_IRQ_CLEAR_1					(0x068)
+
+#define VFE_IRQ_STATUS_0				(0x06c)
+#define		STATUS_0_CAMIF_SOF			BIT(0)
+#define		STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define		STATUS_0_line_n_REG_UPDATE(n)		\
+			((n) == VFE_LINE_PIX ? \
+				BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
+#define		STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define		STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define		STATUS_0_RESET_ACK			BIT(31)
+
+#define VFE_IRQ_STATUS_1				(0x070)
+#define		STATUS_1_VIOLATION			BIT(7)
+#define		STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
+#define		STATUS_1_RDIn_SOF(n)			BIT((n) + 27)
+
+#define VFE_VIOLATION_STATUS			(0x07c)
+
+#define VFE_CAMIF_CMD				(0x478)
+#define		CMD_CLEAR_CAMIF_STATUS		BIT(2)
+
+#define VFE_CAMIF_CFG				(0x47c)
+#define		CFG_VSYNC_SYNC_EDGE		(0)
+#define			VSYNC_ACTIVE_HIGH	(0)
+#define			VSYNC_ACTIVE_LOW	(1)
+#define		CFG_HSYNC_SYNC_EDGE		(1)
+#define			HSYNC_ACTIVE_HIGH	(0)
+#define			HSYNC_ACTIVE_LOW	(1)
+#define		CFG_VFE_SUBSAMPLE_ENABLE	BIT(4)
+#define		CFG_BUS_SUBSAMPLE_ENABLE	BIT(5)
+#define		CFG_VFE_OUTPUT_EN		BIT(6)
+#define		CFG_BUS_OUTPUT_EN		BIT(7)
+#define		CFG_BINNING_EN			BIT(9)
+#define		CFG_FRAME_BASED_EN		BIT(10)
+#define		CFG_RAW_CROP_EN			BIT(22)
+
+// XXX different, don't exist in TITAN register docs
+#define VFE_0_CAMIF_FRAME_CFG			0x484
+#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
+#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
+#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
+#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
+#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
+#define VFE_0_CAMIF_STATUS			0x4a4
+#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
+#define CAMIF_TIMEOUT_SLEEP_US 1000
+#define CAMIF_TIMEOUT_ALL_US 1000000
+
+#define VFE_REG_UPDATE_CMD			(0x4ac)
+#define		REG_UPDATE_RDIn(n)		BIT(1 + (n))
+#define		REG_UPDATE_line_n(n)		\
+			((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
+
+
+#define VFE_BUS_IRQ_MASK(n)		(0x2044 + (n) * 4)
+#define VFE_BUS_IRQ_CLEAR(n)		(0x2050 + (n) * 4)
+
+#define VFE_BUS_IRQ_STATUS(n)		(0x205c + (n) * 4)
+#define		STATUS0_COMP_RESET_DONE		BIT(0)
+#define		STATUS0_COMP_REG_UPDATE0_DONE	BIT(1)
+#define		STATUS0_COMP_REG_UPDATE1_DONE	BIT(2)
+#define		STATUS0_COMP_REG_UPDATE2_DONE	BIT(3)
+#define		STATUS0_COMP_REG_UPDATE3_DONE	BIT(4)
+#define		STATUS0_COMP_REG_UPDATE_DONE(n)	BIT(n + 1)
+#define		STATUS0_COMP0_BUF_DONE		BIT(5)
+#define		STATUS0_COMP1_BUF_DONE		BIT(6)
+#define		STATUS0_COMP2_BUF_DONE		BIT(7)
+#define		STATUS0_COMP3_BUF_DONE		BIT(8)
+#define		STATUS0_COMP4_BUF_DONE		BIT(9)
+#define		STATUS0_COMP5_BUF_DONE		BIT(10)
+#define		STATUS0_COMP_BUF_DONE(n)	BIT(n + 5)
+#define		STATUS0_COMP_ERROR		BIT(11)
+#define		STATUS0_COMP_OVERWRITE		BIT(12)
+#define		STATUS0_OVERFLOW		BIT(13)
+#define		STATUS0_VIOLATION		BIT(14)
+/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
+#define		STATUS1_WM_CLIENT_BUF_DONE(n)		BIT(n)
+#define		STATUS1_EARLY_DONE			BIT(24)
+#define		STATUS2_DUAL_COMP0_BUF_DONE		BIT(0)
+#define		STATUS2_DUAL_COMP1_BUF_DONE		BIT(1)
+#define		STATUS2_DUAL_COMP2_BUF_DONE		BIT(2)
+#define		STATUS2_DUAL_COMP3_BUF_DONE		BIT(3)
+#define		STATUS2_DUAL_COMP4_BUF_DONE		BIT(4)
+#define		STATUS2_DUAL_COMP5_BUF_DONE		BIT(5)
+#define		STATUS2_DUAL_COMP_BUF_DONE(n)		BIT(n)
+#define		STATUS2_DUAL_COMP_ERROR			BIT(6)
+#define		STATUS2_DUAL_COMP_OVERWRITE		BIT(7)
+
+#define VFE_BUS_IRQ_CLEAR_GLOBAL		(0x2068)
+
+#define VFE_BUS_WM_DEBUG_STATUS_CFG		(0x226c)
+#define		DEBUG_STATUS_CFG_STATUS0(n)	BIT(n)
+#define		DEBUG_STATUS_CFG_STATUS1(n)	BIT(8+n)
+
+#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER	(0x2080)
+
+#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC		(0x2084)
+#define		BUS_VER2_MAX_CLIENTS (24)
+#define		WM_ADDR_NO_SYNC_DEFAULT_VAL \
+				((1 << BUS_VER2_MAX_CLIENTS) - 1)
+
+#define VFE_BUS_WM_CGC_OVERRIDE			(0x200c)
+#define		WM_CGC_OVERRIDE_ALL		(0xFFFFF)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL		(0x211c)
+
+#define VFE_BUS_WM_STATUS0(n)			(0x2200 + (n) * 0x100)
+#define VFE_BUS_WM_STATUS1(n)			(0x2204 + (n) * 0x100)
+#define VFE_BUS_WM_CFG(n)			(0x2208 + (n) * 0x100)
+#define		WM_CFG_EN			(0)
+#define		WM_CFG_MODE			(1)
+#define			MODE_QCOM_PLAIN	(0)
+#define			MODE_MIPI_RAW	(1)
+#define		WM_CFG_VIRTUALFRAME		(2)
+#define VFE_BUS_WM_HEADER_ADDR(n)		(0x220c + (n) * 0x100)
+#define VFE_BUS_WM_HEADER_CFG(n)		(0x2210 + (n) * 0x100)
+#define VFE_BUS_WM_IMAGE_ADDR(n)		(0x2214 + (n) * 0x100)
+#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)		(0x2218 + (n) * 0x100)
+#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)		(0x221c + (n) * 0x100)
+#define		WM_BUFFER_DEFAULT_WIDTH		(0xFF01)
+
+#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)		(0x2220 + (n) * 0x100)
+#define VFE_BUS_WM_PACKER_CFG(n)		(0x2224 + (n) * 0x100)
+
+#define VFE_BUS_WM_STRIDE(n)			(0x2228 + (n) * 0x100)
+#define		WM_STRIDE_DEFAULT_STRIDE	(0xFF01)
+
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(0x2248 + (n) * 0x100)
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(0x224c + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(0x2250 + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(0x2254 + (n) * 0x100)
+#define VFE_BUS_WM_FRAME_INC(n)			(0x2258 + (n) * 0x100)
+#define VFE_BUS_WM_BURST_LIMIT(n)		(0x225c + (n) * 0x100)
+
+
+static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
+{
+	u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
+
+	u32 gen = (hw_version >> 28) & 0xF;
+	u32 rev = (hw_version >> 16) & 0xFFF;
+	u32 step = hw_version & 0xFFFF;
+
+	dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
+}
+
+static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
+}
+
+static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits | set_bits, vfe->base + reg);
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+	u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC	|
+			 GLOBAL_RESET_CMD_DSP		|
+			 GLOBAL_RESET_CMD_TESTGEN	|
+			 GLOBAL_RESET_CMD_BUS_MISR	|
+			 GLOBAL_RESET_CMD_PM		|
+			 GLOBAL_RESET_CMD_REGISTER	|
+			 GLOBAL_RESET_CMD_BUS_BDG	|
+			 GLOBAL_RESET_CMD_BUS		|
+			 GLOBAL_RESET_CMD_CAMIF		|
+			 GLOBAL_RESET_CMD_CORE;
+
+	reset_bits = 0x00003F9F;
+
+	writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
+
+	/* Make sure IRQ mask has been written before resetting */
+	wmb();
+
+	writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+{
+	u32 val;
+
+	/*Set Debug Registers*/
+	val = DEBUG_STATUS_CFG_STATUS0(1) |
+	      DEBUG_STATUS_CFG_STATUS0(7);
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
+
+	/* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
+	writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
+
+	/* no clock gating at bus input */
+	val = WM_CGC_OVERRIDE_ALL;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
+
+	writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+	/* if addr_no_sync has default value then config the addr no sync reg */
+	val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
+
+	writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
+
+	val = WM_BUFFER_DEFAULT_WIDTH;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
+
+	val = 0;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
+
+	val = 0;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
+
+	/* Configure stride for RDIs */
+	//val = pix->plane_fmt[0].bytesperline;
+	val = WM_STRIDE_DEFAULT_STRIDE;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
+
+	/* Enable WM */
+	val = 1 << WM_CFG_EN |
+	      MODE_MIPI_RAW << WM_CFG_MODE;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+{
+	/* Disable WM */
+	writel_relaxed(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)
+{
+	/* XXX use cmdbuf for this ?? */
+	struct v4l2_pix_format_mplane *pix =
+		&line->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));
+	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
+
+	/* XXX enable wm ? */
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	vfe->reg_update |= REG_UPDATE_line_n(line_id);
+
+	/* Enforce ordering between previous reg writes and reg update */
+	wmb();
+
+	writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
+
+	/* Enforce ordering between reg update and subsequent reg writes */
+	wmb();
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+					enum vfe_line_id line_id)
+{
+	vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
+}
+
+static void vfe_enable_irq_common(struct vfe_device *vfe)
+{
+	vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
+	vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
+
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
+}
+
+static void vfe_isr_halt_ack(struct vfe_device *vfe)
+{
+	complete(&vfe->halt_complete);
+}
+
+static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
+{
+	*status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
+	*status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
+
+	writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
+	writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
+
+	/* Enforce ordering between IRQ Clear and Global IRQ Clear */
+	wmb();
+	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
+}
+
+static void vfe_violation_read(struct vfe_device *vfe)
+{
+	u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
+
+	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
+}
+
+/*
+ * vfe_isr - VFE module interrupt handler
+ * @irq: Interrupt line
+ * @dev: VFE device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+	struct vfe_device *vfe = dev;
+	u32 status0, status1, vfe_bus_status[3];
+	int i, wm;
+
+	status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
+	status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
+
+	writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
+	writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
+		vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
+		writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
+	}
+
+	/* Enforce ordering between IRQ reading and interpretation */
+	wmb();
+
+	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
+	writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
+
+	if (status0 & STATUS_0_RESET_ACK)
+		vfe->isr_ops.reset_ack(vfe);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
+		if (status0 & STATUS_0_line_n_REG_UPDATE(i))
+			vfe->isr_ops.reg_update(vfe, i);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
+		if (status0 & STATUS_1_RDIn_SOF(i))
+			vfe->isr_ops.sof(vfe, i);
+
+	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
+		if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
+			vfe->isr_ops.comp_done(vfe, i);
+
+	for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
+		if (status0 & BIT(9))
+			if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
+				vfe->isr_ops.wm_done(vfe, wm);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * vfe_halt - Trigger halt on VFE module and wait to complete
+ * @vfe: VFE device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_halt(struct vfe_device *vfe)
+{
+	unsigned long time;
+
+	return 0;
+
+	reinit_completion(&vfe->halt_complete);
+
+	time = wait_for_completion_timeout(&vfe->halt_complete,
+		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
+	if (!time) {
+		dev_err(vfe->camss->dev, "VFE halt timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+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;
+	unsigned long flags;
+	int i;
+	int wm_idx;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	output = &line->output;
+	if (output->state != VFE_OUTPUT_OFF) {
+		dev_err(vfe->camss->dev, "Output is running\n");
+		goto error;
+	}
+
+	switch (f->fmt.pix_mp.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		output->wm_num = 2;
+		break;
+	default:
+		output->wm_num = 1;
+		break;
+	}
+
+	for (i = 0; i < output->wm_num; i++) {
+		wm_idx = vfe_reserve_wm(vfe, line->id);
+		if (wm_idx < 0) {
+			dev_err(vfe->camss->dev, "Can not reserve wm\n");
+			goto error_get_wm;
+		}
+		output->wm_idx[i] = wm_idx;
+	}
+
+	output->drop_update_idx = 0;
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+
+error_get_wm:
+	for (i--; i >= 0; i--)
+		vfe_release_wm(vfe, output->wm_idx[i]);
+	output->state = VFE_OUTPUT_OFF;
+error:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return -EINVAL;
+}
+
+static int vfe_enable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	const struct vfe_hw_ops *ops = vfe->ops;
+	struct media_entity *sensor;
+	unsigned long flags;
+	unsigned int frame_skip = 0;
+	unsigned int i;
+
+	sensor = camss_find_sensor(&line->subdev.entity);
+	if (sensor) {
+		struct v4l2_subdev *subdev =
+					media_entity_to_v4l2_subdev(sensor);
+
+		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_OFF) {
+		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
+			output->state);
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+		return -EINVAL;
+	}
+
+	WARN_ON(output->gen2.active_num);
+
+	output->state = VFE_OUTPUT_ON;
+
+	output->sequence = 0;
+	output->wait_reg_update = 0;
+	reinit_completion(&output->reg_update);
+
+	if (line->id != VFE_LINE_PIX)
+		vfe_wm_start(vfe, output->wm_idx[0], line);
+
+	for (i = 0; i < 2; i++) {
+		output->buf[i] = vfe_buf_get_pending(output);
+		if (!output->buf[i])
+			break;
+		output->gen2.active_num++;
+		vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
+	}
+
+	ops->reg_update(vfe, line->id);
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+static int vfe_disable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	unsigned long flags;
+	unsigned int i;
+	bool done;
+	int timeout = 0;
+
+	do {
+		spin_lock_irqsave(&vfe->output_lock, flags);
+		done = !output->gen2.active_num;
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+		usleep_range(10000, 20000);
+
+		if (timeout++ == 100) {
+			dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
+			vfe_reset(vfe);
+			output->gen2.active_num = 0;
+			return 0;
+		}
+	} while (!done);
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	for (i = 0; i < output->wm_num; i++)
+		vfe_wm_stop(vfe, output->wm_idx[i]);
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+/*
+ * vfe_enable - Enable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_enable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	int ret;
+
+	mutex_lock(&vfe->stream_lock);
+
+	if (!vfe->stream_count)
+		vfe_enable_irq_common(vfe);
+
+	vfe->stream_count++;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	ret = vfe_get_output(line);
+	if (ret < 0)
+		goto error_get_output;
+
+	ret = vfe_enable_output(line);
+	if (ret < 0)
+		goto error_enable_output;
+
+	vfe->was_streaming = 1;
+
+	return 0;
+
+
+error_enable_output:
+	vfe_put_output(line);
+
+error_get_output:
+	mutex_lock(&vfe->stream_lock);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return ret;
+}
+
+/*
+ * vfe_disable - Disable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_disable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+
+	vfe_disable_output(line);
+
+	vfe_put_output(line);
+
+	mutex_lock(&vfe->stream_lock);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return 0;
+}
+
+/*
+ * vfe_isr_sof - Process start of frame interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+
+}
+
+/*
+ * vfe_isr_reg_update - Process reg update interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	struct vfe_output *output;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	vfe->ops->reg_update_clear(vfe, line_id);
+
+	output = &vfe->line[line_id].output;
+
+	if (output->wait_reg_update) {
+		output->wait_reg_update = 0;
+		complete(&output->reg_update);
+	}
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_isr_wm_done - Process write master done interrupt
+ * @vfe: VFE Device
+ * @wm: Write master id
+ */
+static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
+{
+	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
+	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;
+
+	ready_buf = output->buf[0];
+	if (!ready_buf) {
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Missing ready buf %d!\n", output->state);
+		goto out_unlock;
+	}
+
+	ready_buf->vb.vb2_buf.timestamp = ts;
+	ready_buf->vb.sequence = output->sequence++;
+
+	index = 0;
+	output->buf[0] = output->buf[1];
+	if (output->buf[0])
+		index = 1;
+
+	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);
+	else
+		output->gen2.active_num--;
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+	return;
+
+out_unlock:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_queue_buffer - Add empty buffer
+ * @vid: Video device structure
+ * @buf: Buffer to be enqueued
+ *
+ * Add an empty buffer - depending on the current number of buffers it will be
+ * put in pending buffer queue or directly given to the hardware to be filled.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+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_device *vfe = to_vfe(line);
+	struct vfe_output *output;
+	unsigned long flags;
+
+	output = &line->output;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
+		output->buf[output->gen2.active_num++] = buf;
+		vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
+	} else {
+		vfe_buf_add_pending(output, buf);
+	}
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+const struct vfe_isr_ops vfe_isr_ops_170 = {
+	.reset_ack = vfe_isr_reset_ack,
+	.halt_ack = vfe_isr_halt_ack,
+	.reg_update = vfe_isr_reg_update,
+	.sof = vfe_isr_sof,
+	.comp_done = vfe_isr_comp_done,
+	.wm_done = vfe_isr_wm_done,
+};
+
+static const struct camss_video_ops vfe_video_ops_170 = {
+	.queue_buffer = vfe_queue_buffer,
+	.flush_buffers = vfe_flush_buffers,
+};
+
+static void vfe_subdev_init(struct vfe_device *vfe)
+{
+	vfe->isr_ops = vfe_isr_ops_170;
+	vfe->video_ops = vfe_video_ops_170;
+}
+
+const struct vfe_hw_ops vfe_ops_170 = {
+	.global_reset = vfe_global_reset,
+	.hw_version_read = vfe_hw_version_read,
+	.isr_read = vfe_isr_read,
+	.isr = vfe_isr,
+	.reg_update_clear = vfe_reg_update_clear,
+	.reg_update = vfe_reg_update,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_disable,
+	.vfe_enable = vfe_enable,
+	.vfe_halt = vfe_halt,
+	.violation_read = vfe_violation_read,
+};
+
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 2ffa5b3c5426..5a874b544391 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
 	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
 };
 
+static const struct vfe_format formats_rdi_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
+	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
+	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
+};
+
+static const struct vfe_format formats_pix_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+};
+
 /*
  * vfe_get_bpp - map media bus format to bits per pixel
  * @formats: supported media bus formats array
@@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			return sink_code;
 		}
 	else if (vfe->camss->version == CAMSS_8x96 ||
-		 vfe->camss->version == CAMSS_660)
+		 vfe->camss->version == CAMSS_660 ||
+		 vfe->camss->version == CAMSS_845)
 		switch (sink_code) {
 		case MEDIA_BUS_FMT_YUYV8_2X8:
 		{
@@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 		return 0;
 }
 
-/*
- * vfe_reset - Trigger reset on VFE module and wait to complete
- * @vfe: VFE device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int vfe_reset(struct vfe_device *vfe)
+int vfe_reset(struct vfe_device *vfe)
 {
 	unsigned long time;
 
@@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
 		struct camss_clock *clock = &vfe->clock[i];
 
 		if (!strcmp(clock->name, "vfe0") ||
-		    !strcmp(clock->name, "vfe1")) {
+		    !strcmp(clock->name, "vfe1") ||
+		    !strcmp(clock->name, "vfe_lite")) {
 			u64 min_rate = 0;
 			long rate;
 
@@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 	case CAMSS_660:
 		vfe->ops = &vfe_ops_4_8;
 		break;
+
+	case CAMSS_845:
+		vfe->ops = &vfe_ops_170;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 				l->formats = formats_rdi_8x96;
 				l->nformats = ARRAY_SIZE(formats_rdi_8x96);
 			}
+		} else if (camss->version == CAMSS_845) {
+			if (i == VFE_LINE_PIX) {
+				l->formats = formats_pix_845;
+				l->nformats = ARRAY_SIZE(formats_pix_845);
+			} else {
+				l->formats = formats_rdi_845;
+				l->nformats = ARRAY_SIZE(formats_rdi_845);
+			}
 		} else {
 			return -EINVAL;
 		}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 8629c833f130..a0b618c9cec8 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -19,7 +19,6 @@
 #include "camss-video.h"
 #include "camss-vfe-gen1.h"
 
-
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
 #define MSM_VFE_PADS_NUM 2
@@ -39,14 +38,14 @@
 #define to_vfe(ptr_line)	\
 	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
 
-
 enum vfe_output_state {
 	VFE_OUTPUT_OFF,
 	VFE_OUTPUT_RESERVED,
 	VFE_OUTPUT_SINGLE,
 	VFE_OUTPUT_CONTINUOUS,
 	VFE_OUTPUT_IDLE,
-	VFE_OUTPUT_STOPPING
+	VFE_OUTPUT_STOPPING,
+	VFE_OUTPUT_ON,
 };
 
 enum vfe_line_id {
@@ -72,6 +71,9 @@ struct vfe_output {
 			int active_buf;
 			int wait_sof;
 		} gen1;
+		struct {
+			int active_num;
+		} gen2;
 	};
 	enum vfe_output_state state;
 	unsigned int sequence;
@@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
 
 struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
 
-/*
- * vfe_disable - Disable streaming on VFE line
- * @line: VFE line
- *
- * Return 0 on success or a negative error code otherwise
- */
-int vfe_disable(struct vfe_line *line);
-
 int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
 
 /*
@@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
 int vfe_release_wm(struct vfe_device *vfe, u8 wm);
 int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
 
+/*
+ * vfe_reset - Trigger reset on VFE module and wait to complete
+ * @vfe: VFE device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_reset(struct vfe_device *vfe);
+
 extern const struct vfe_hw_ops vfe_ops_4_1;
 extern const struct vfe_hw_ops vfe_ops_4_7;
 extern const struct vfe_hw_ops vfe_ops_4_8;
+extern const struct vfe_hw_ops vfe_ops_170;
 
 #endif /* QC_MSM_CAMSS_VFE_H */
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index bd9334af1c73..b4943df9eaf6 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
 	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 };
 
+static const struct camss_format_info formats_rdi_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+};
+
 static const struct camss_format_info formats_pix_8x16[] = {
 	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
@@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
 	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 };
 
+static const struct camss_format_info formats_pix_845[] = {
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+};
+
 /* -----------------------------------------------------------------------------
  * Helper functions
  */
@@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 			video->formats = formats_rdi_8x96;
 			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
 		}
+	}  else if (video->camss->version == CAMSS_845) {
+		if (is_pix) {
+			video->formats = formats_pix_845;
+			video->nformats = ARRAY_SIZE(formats_pix_845);
+		} else {
+			video->formats = formats_rdi_845;
+			video->nformats = ARRAY_SIZE(formats_rdi_845);
+		}
 	} else {
 		goto error_video_register;
 	}
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index aeec59bc6194..1c3d64d612ff 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources vfe_res_845[] = {
+	/* VFE0 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe0", "vfe0_axi",
+				"vfe0_src", "csi0",
+				"csi0_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 0 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe0" },
+		.interrupt = { "vfe0" }
+	},
+
+	/* VFE1 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe1", "vfe1_axi",
+				"vfe1_src", "csi1",
+				"csi1_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 0 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe1" },
+		.interrupt = { "vfe1" }
+	},
+
+	/* VFE-lite */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe_lite",
+				"vfe_lite_src", "csi2",
+				"csi2_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe_lite" },
+		.interrupt = { "vfe_lite" }
+	}
+};
+
 /*
  * camss_add_clock_margin - Add margin to clock frequency rate
  * @rate: Clock frequency rate
-- 
2.27.0


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

* [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add register definitions for version 170 of the Titan architecture
and implement support for the RDI output mode.

The RDI mode as opposed to the PIX output mode for the VFE unit does
not support any ISP functionality. This means essentially only
supporting dumping the output of the whatever the CSI decoder receives
from the sensor.

For example will a sensor outputting YUV pixel format frames, only
allow the VFE to dump those frames as they are received by the ISP
to memory through the RDI interface.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   1 +
 .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
 drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
 drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
 .../media/platform/qcom/camss/camss-video.c   | 100 +++
 drivers/media/platform/qcom/camss/camss.c     |  61 ++
 6 files changed, 1034 insertions(+), 20 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 940c0ae3e003..052c4f405fa3 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -11,6 +11,7 @@ qcom-camss-objs += \
 		camss-vfe-4-1.o \
 		camss-vfe-4-7.o \
 		camss-vfe-4-8.o \
+		camss-vfe-170.o \
 		camss-vfe-gen1.o \
 		camss-vfe.o \
 		camss-video.o \
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
new file mode 100644
index 000000000000..89b6c47cca22
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-vfe-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
+ *
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015-2018 Linaro Ltd.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "camss.h"
+#include "camss-vfe.h"
+
+#define VFE_HW_VERSION				(0x000)
+
+#define VFE_GLOBAL_RESET_CMD			(0x018)
+#define		GLOBAL_RESET_CMD_CORE		BIT(0)
+#define		GLOBAL_RESET_CMD_CAMIF		BIT(1)
+#define		GLOBAL_RESET_CMD_BUS		BIT(2)
+#define		GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
+#define		GLOBAL_RESET_CMD_REGISTER	BIT(4)
+#define		GLOBAL_RESET_CMD_PM		BIT(5)
+#define		GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
+#define		GLOBAL_RESET_CMD_TESTGEN	BIT(7)
+#define		GLOBAL_RESET_CMD_DSP		BIT(8)
+#define		GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
+
+#define VFE_CORE_CFG				(0x050)
+#define		CFG_PIXEL_PATTERN_YCBYCR	(0x4)
+#define		CFG_PIXEL_PATTERN_YCRYCB	(0x5)
+#define		CFG_PIXEL_PATTERN_CBYCRY	(0x6)
+#define		CFG_PIXEL_PATTERN_CRYCBY	(0x7)
+#define		CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
+
+#define VFE_IRQ_CMD				(0x058)
+#define		CMD_GLOBAL_CLEAR		BIT(0)
+
+#define VFE_IRQ_MASK_0					(0x05c)
+#define		MASK_0_CAMIF_SOF			BIT(0)
+#define		MASK_0_CAMIF_EOF			BIT(1)
+#define		MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define		MASK_0_line_n_REG_UPDATE(n)		\
+			((n) == VFE_LINE_PIX ? \
+				BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
+#define		MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define		MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define		MASK_0_RESET_ACK			BIT(31)
+
+#define VFE_IRQ_MASK_1					(0x060)
+#define		MASK_1_CAMIF_ERROR			BIT(0)
+#define		MASK_1_VIOLATION			BIT(7)
+#define		MASK_1_BUS_BDG_HALT_ACK			BIT(8)
+#define		MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
+#define		MASK_1_RDIn_SOF(n)			BIT((n) + 29)
+
+#define VFE_IRQ_CLEAR_0					(0x064)
+#define VFE_IRQ_CLEAR_1					(0x068)
+
+#define VFE_IRQ_STATUS_0				(0x06c)
+#define		STATUS_0_CAMIF_SOF			BIT(0)
+#define		STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
+#define		STATUS_0_line_n_REG_UPDATE(n)		\
+			((n) == VFE_LINE_PIX ? \
+				BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
+#define		STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
+#define		STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
+#define		STATUS_0_RESET_ACK			BIT(31)
+
+#define VFE_IRQ_STATUS_1				(0x070)
+#define		STATUS_1_VIOLATION			BIT(7)
+#define		STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
+#define		STATUS_1_RDIn_SOF(n)			BIT((n) + 27)
+
+#define VFE_VIOLATION_STATUS			(0x07c)
+
+#define VFE_CAMIF_CMD				(0x478)
+#define		CMD_CLEAR_CAMIF_STATUS		BIT(2)
+
+#define VFE_CAMIF_CFG				(0x47c)
+#define		CFG_VSYNC_SYNC_EDGE		(0)
+#define			VSYNC_ACTIVE_HIGH	(0)
+#define			VSYNC_ACTIVE_LOW	(1)
+#define		CFG_HSYNC_SYNC_EDGE		(1)
+#define			HSYNC_ACTIVE_HIGH	(0)
+#define			HSYNC_ACTIVE_LOW	(1)
+#define		CFG_VFE_SUBSAMPLE_ENABLE	BIT(4)
+#define		CFG_BUS_SUBSAMPLE_ENABLE	BIT(5)
+#define		CFG_VFE_OUTPUT_EN		BIT(6)
+#define		CFG_BUS_OUTPUT_EN		BIT(7)
+#define		CFG_BINNING_EN			BIT(9)
+#define		CFG_FRAME_BASED_EN		BIT(10)
+#define		CFG_RAW_CROP_EN			BIT(22)
+
+// XXX different, don't exist in TITAN register docs
+#define VFE_0_CAMIF_FRAME_CFG			0x484
+#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
+#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
+#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
+#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
+#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
+#define VFE_0_CAMIF_STATUS			0x4a4
+#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
+#define CAMIF_TIMEOUT_SLEEP_US 1000
+#define CAMIF_TIMEOUT_ALL_US 1000000
+
+#define VFE_REG_UPDATE_CMD			(0x4ac)
+#define		REG_UPDATE_RDIn(n)		BIT(1 + (n))
+#define		REG_UPDATE_line_n(n)		\
+			((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
+
+
+#define VFE_BUS_IRQ_MASK(n)		(0x2044 + (n) * 4)
+#define VFE_BUS_IRQ_CLEAR(n)		(0x2050 + (n) * 4)
+
+#define VFE_BUS_IRQ_STATUS(n)		(0x205c + (n) * 4)
+#define		STATUS0_COMP_RESET_DONE		BIT(0)
+#define		STATUS0_COMP_REG_UPDATE0_DONE	BIT(1)
+#define		STATUS0_COMP_REG_UPDATE1_DONE	BIT(2)
+#define		STATUS0_COMP_REG_UPDATE2_DONE	BIT(3)
+#define		STATUS0_COMP_REG_UPDATE3_DONE	BIT(4)
+#define		STATUS0_COMP_REG_UPDATE_DONE(n)	BIT(n + 1)
+#define		STATUS0_COMP0_BUF_DONE		BIT(5)
+#define		STATUS0_COMP1_BUF_DONE		BIT(6)
+#define		STATUS0_COMP2_BUF_DONE		BIT(7)
+#define		STATUS0_COMP3_BUF_DONE		BIT(8)
+#define		STATUS0_COMP4_BUF_DONE		BIT(9)
+#define		STATUS0_COMP5_BUF_DONE		BIT(10)
+#define		STATUS0_COMP_BUF_DONE(n)	BIT(n + 5)
+#define		STATUS0_COMP_ERROR		BIT(11)
+#define		STATUS0_COMP_OVERWRITE		BIT(12)
+#define		STATUS0_OVERFLOW		BIT(13)
+#define		STATUS0_VIOLATION		BIT(14)
+/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
+#define		STATUS1_WM_CLIENT_BUF_DONE(n)		BIT(n)
+#define		STATUS1_EARLY_DONE			BIT(24)
+#define		STATUS2_DUAL_COMP0_BUF_DONE		BIT(0)
+#define		STATUS2_DUAL_COMP1_BUF_DONE		BIT(1)
+#define		STATUS2_DUAL_COMP2_BUF_DONE		BIT(2)
+#define		STATUS2_DUAL_COMP3_BUF_DONE		BIT(3)
+#define		STATUS2_DUAL_COMP4_BUF_DONE		BIT(4)
+#define		STATUS2_DUAL_COMP5_BUF_DONE		BIT(5)
+#define		STATUS2_DUAL_COMP_BUF_DONE(n)		BIT(n)
+#define		STATUS2_DUAL_COMP_ERROR			BIT(6)
+#define		STATUS2_DUAL_COMP_OVERWRITE		BIT(7)
+
+#define VFE_BUS_IRQ_CLEAR_GLOBAL		(0x2068)
+
+#define VFE_BUS_WM_DEBUG_STATUS_CFG		(0x226c)
+#define		DEBUG_STATUS_CFG_STATUS0(n)	BIT(n)
+#define		DEBUG_STATUS_CFG_STATUS1(n)	BIT(8+n)
+
+#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER	(0x2080)
+
+#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC		(0x2084)
+#define		BUS_VER2_MAX_CLIENTS (24)
+#define		WM_ADDR_NO_SYNC_DEFAULT_VAL \
+				((1 << BUS_VER2_MAX_CLIENTS) - 1)
+
+#define VFE_BUS_WM_CGC_OVERRIDE			(0x200c)
+#define		WM_CGC_OVERRIDE_ALL		(0xFFFFF)
+
+#define VFE_BUS_WM_TEST_BUS_CTRL		(0x211c)
+
+#define VFE_BUS_WM_STATUS0(n)			(0x2200 + (n) * 0x100)
+#define VFE_BUS_WM_STATUS1(n)			(0x2204 + (n) * 0x100)
+#define VFE_BUS_WM_CFG(n)			(0x2208 + (n) * 0x100)
+#define		WM_CFG_EN			(0)
+#define		WM_CFG_MODE			(1)
+#define			MODE_QCOM_PLAIN	(0)
+#define			MODE_MIPI_RAW	(1)
+#define		WM_CFG_VIRTUALFRAME		(2)
+#define VFE_BUS_WM_HEADER_ADDR(n)		(0x220c + (n) * 0x100)
+#define VFE_BUS_WM_HEADER_CFG(n)		(0x2210 + (n) * 0x100)
+#define VFE_BUS_WM_IMAGE_ADDR(n)		(0x2214 + (n) * 0x100)
+#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)		(0x2218 + (n) * 0x100)
+#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)		(0x221c + (n) * 0x100)
+#define		WM_BUFFER_DEFAULT_WIDTH		(0xFF01)
+
+#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)		(0x2220 + (n) * 0x100)
+#define VFE_BUS_WM_PACKER_CFG(n)		(0x2224 + (n) * 0x100)
+
+#define VFE_BUS_WM_STRIDE(n)			(0x2228 + (n) * 0x100)
+#define		WM_STRIDE_DEFAULT_STRIDE	(0xFF01)
+
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(0x2248 + (n) * 0x100)
+#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(0x224c + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(0x2250 + (n) * 0x100)
+#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(0x2254 + (n) * 0x100)
+#define VFE_BUS_WM_FRAME_INC(n)			(0x2258 + (n) * 0x100)
+#define VFE_BUS_WM_BURST_LIMIT(n)		(0x225c + (n) * 0x100)
+
+
+static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
+{
+	u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
+
+	u32 gen = (hw_version >> 28) & 0xF;
+	u32 rev = (hw_version >> 16) & 0xFFF;
+	u32 step = hw_version & 0xFFFF;
+
+	dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
+}
+
+static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
+}
+
+static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
+{
+	u32 bits = readl_relaxed(vfe->base + reg);
+
+	writel_relaxed(bits | set_bits, vfe->base + reg);
+}
+
+static void vfe_global_reset(struct vfe_device *vfe)
+{
+	u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC	|
+			 GLOBAL_RESET_CMD_DSP		|
+			 GLOBAL_RESET_CMD_TESTGEN	|
+			 GLOBAL_RESET_CMD_BUS_MISR	|
+			 GLOBAL_RESET_CMD_PM		|
+			 GLOBAL_RESET_CMD_REGISTER	|
+			 GLOBAL_RESET_CMD_BUS_BDG	|
+			 GLOBAL_RESET_CMD_BUS		|
+			 GLOBAL_RESET_CMD_CAMIF		|
+			 GLOBAL_RESET_CMD_CORE;
+
+	reset_bits = 0x00003F9F;
+
+	writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
+
+	/* Make sure IRQ mask has been written before resetting */
+	wmb();
+
+	writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
+}
+
+static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
+{
+	u32 val;
+
+	/*Set Debug Registers*/
+	val = DEBUG_STATUS_CFG_STATUS0(1) |
+	      DEBUG_STATUS_CFG_STATUS0(7);
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
+
+	/* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
+	writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
+
+	/* no clock gating at bus input */
+	val = WM_CGC_OVERRIDE_ALL;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
+
+	writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
+
+	/* if addr_no_sync has default value then config the addr no sync reg */
+	val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
+
+	writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
+
+	val = WM_BUFFER_DEFAULT_WIDTH;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
+
+	val = 0;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
+
+	val = 0;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
+
+	/* Configure stride for RDIs */
+	//val = pix->plane_fmt[0].bytesperline;
+	val = WM_STRIDE_DEFAULT_STRIDE;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
+
+	/* Enable WM */
+	val = 1 << WM_CFG_EN |
+	      MODE_MIPI_RAW << WM_CFG_MODE;
+	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
+}
+
+static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
+{
+	/* Disable WM */
+	writel_relaxed(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)
+{
+	/* XXX use cmdbuf for this ?? */
+	struct v4l2_pix_format_mplane *pix =
+		&line->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));
+	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
+
+	/* XXX enable wm ? */
+}
+
+static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	vfe->reg_update |= REG_UPDATE_line_n(line_id);
+
+	/* Enforce ordering between previous reg writes and reg update */
+	wmb();
+
+	writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
+
+	/* Enforce ordering between reg update and subsequent reg writes */
+	wmb();
+}
+
+static inline void vfe_reg_update_clear(struct vfe_device *vfe,
+					enum vfe_line_id line_id)
+{
+	vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
+}
+
+static void vfe_enable_irq_common(struct vfe_device *vfe)
+{
+	vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
+	vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
+
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
+	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
+}
+
+static void vfe_isr_halt_ack(struct vfe_device *vfe)
+{
+	complete(&vfe->halt_complete);
+}
+
+static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
+{
+	*status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
+	*status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
+
+	writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
+	writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
+
+	/* Enforce ordering between IRQ Clear and Global IRQ Clear */
+	wmb();
+	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
+}
+
+static void vfe_violation_read(struct vfe_device *vfe)
+{
+	u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
+
+	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
+}
+
+/*
+ * vfe_isr - VFE module interrupt handler
+ * @irq: Interrupt line
+ * @dev: VFE device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t vfe_isr(int irq, void *dev)
+{
+	struct vfe_device *vfe = dev;
+	u32 status0, status1, vfe_bus_status[3];
+	int i, wm;
+
+	status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
+	status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
+
+	writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
+	writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
+		vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
+		writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
+	}
+
+	/* Enforce ordering between IRQ reading and interpretation */
+	wmb();
+
+	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
+	writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
+
+	if (status0 & STATUS_0_RESET_ACK)
+		vfe->isr_ops.reset_ack(vfe);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
+		if (status0 & STATUS_0_line_n_REG_UPDATE(i))
+			vfe->isr_ops.reg_update(vfe, i);
+
+	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
+		if (status0 & STATUS_1_RDIn_SOF(i))
+			vfe->isr_ops.sof(vfe, i);
+
+	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
+		if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
+			vfe->isr_ops.comp_done(vfe, i);
+
+	for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
+		if (status0 & BIT(9))
+			if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
+				vfe->isr_ops.wm_done(vfe, wm);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * vfe_halt - Trigger halt on VFE module and wait to complete
+ * @vfe: VFE device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_halt(struct vfe_device *vfe)
+{
+	unsigned long time;
+
+	return 0;
+
+	reinit_completion(&vfe->halt_complete);
+
+	time = wait_for_completion_timeout(&vfe->halt_complete,
+		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
+	if (!time) {
+		dev_err(vfe->camss->dev, "VFE halt timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+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;
+	unsigned long flags;
+	int i;
+	int wm_idx;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	output = &line->output;
+	if (output->state != VFE_OUTPUT_OFF) {
+		dev_err(vfe->camss->dev, "Output is running\n");
+		goto error;
+	}
+
+	switch (f->fmt.pix_mp.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
+		output->wm_num = 2;
+		break;
+	default:
+		output->wm_num = 1;
+		break;
+	}
+
+	for (i = 0; i < output->wm_num; i++) {
+		wm_idx = vfe_reserve_wm(vfe, line->id);
+		if (wm_idx < 0) {
+			dev_err(vfe->camss->dev, "Can not reserve wm\n");
+			goto error_get_wm;
+		}
+		output->wm_idx[i] = wm_idx;
+	}
+
+	output->drop_update_idx = 0;
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+
+error_get_wm:
+	for (i--; i >= 0; i--)
+		vfe_release_wm(vfe, output->wm_idx[i]);
+	output->state = VFE_OUTPUT_OFF;
+error:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return -EINVAL;
+}
+
+static int vfe_enable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	const struct vfe_hw_ops *ops = vfe->ops;
+	struct media_entity *sensor;
+	unsigned long flags;
+	unsigned int frame_skip = 0;
+	unsigned int i;
+
+	sensor = camss_find_sensor(&line->subdev.entity);
+	if (sensor) {
+		struct v4l2_subdev *subdev =
+					media_entity_to_v4l2_subdev(sensor);
+
+		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_OFF) {
+		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
+			output->state);
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+		return -EINVAL;
+	}
+
+	WARN_ON(output->gen2.active_num);
+
+	output->state = VFE_OUTPUT_ON;
+
+	output->sequence = 0;
+	output->wait_reg_update = 0;
+	reinit_completion(&output->reg_update);
+
+	if (line->id != VFE_LINE_PIX)
+		vfe_wm_start(vfe, output->wm_idx[0], line);
+
+	for (i = 0; i < 2; i++) {
+		output->buf[i] = vfe_buf_get_pending(output);
+		if (!output->buf[i])
+			break;
+		output->gen2.active_num++;
+		vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
+	}
+
+	ops->reg_update(vfe, line->id);
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+static int vfe_disable_output(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	struct vfe_output *output = &line->output;
+	unsigned long flags;
+	unsigned int i;
+	bool done;
+	int timeout = 0;
+
+	do {
+		spin_lock_irqsave(&vfe->output_lock, flags);
+		done = !output->gen2.active_num;
+		spin_unlock_irqrestore(&vfe->output_lock, flags);
+		usleep_range(10000, 20000);
+
+		if (timeout++ == 100) {
+			dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
+			vfe_reset(vfe);
+			output->gen2.active_num = 0;
+			return 0;
+		}
+	} while (!done);
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	for (i = 0; i < output->wm_num; i++)
+		vfe_wm_stop(vfe, output->wm_idx[i]);
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+/*
+ * vfe_enable - Enable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_enable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+	int ret;
+
+	mutex_lock(&vfe->stream_lock);
+
+	if (!vfe->stream_count)
+		vfe_enable_irq_common(vfe);
+
+	vfe->stream_count++;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	ret = vfe_get_output(line);
+	if (ret < 0)
+		goto error_get_output;
+
+	ret = vfe_enable_output(line);
+	if (ret < 0)
+		goto error_enable_output;
+
+	vfe->was_streaming = 1;
+
+	return 0;
+
+
+error_enable_output:
+	vfe_put_output(line);
+
+error_get_output:
+	mutex_lock(&vfe->stream_lock);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return ret;
+}
+
+/*
+ * vfe_disable - Disable streaming on VFE line
+ * @line: VFE line
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int vfe_disable(struct vfe_line *line)
+{
+	struct vfe_device *vfe = to_vfe(line);
+
+	vfe_disable_output(line);
+
+	vfe_put_output(line);
+
+	mutex_lock(&vfe->stream_lock);
+
+	vfe->stream_count--;
+
+	mutex_unlock(&vfe->stream_lock);
+
+	return 0;
+}
+
+/*
+ * vfe_isr_sof - Process start of frame interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+
+}
+
+/*
+ * vfe_isr_reg_update - Process reg update interrupt
+ * @vfe: VFE Device
+ * @line_id: VFE line
+ */
+static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
+{
+	struct vfe_output *output;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+	vfe->ops->reg_update_clear(vfe, line_id);
+
+	output = &vfe->line[line_id].output;
+
+	if (output->wait_reg_update) {
+		output->wait_reg_update = 0;
+		complete(&output->reg_update);
+	}
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_isr_wm_done - Process write master done interrupt
+ * @vfe: VFE Device
+ * @wm: Write master id
+ */
+static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
+{
+	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
+	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;
+
+	ready_buf = output->buf[0];
+	if (!ready_buf) {
+		dev_err_ratelimited(vfe->camss->dev,
+				    "Missing ready buf %d!\n", output->state);
+		goto out_unlock;
+	}
+
+	ready_buf->vb.vb2_buf.timestamp = ts;
+	ready_buf->vb.sequence = output->sequence++;
+
+	index = 0;
+	output->buf[0] = output->buf[1];
+	if (output->buf[0])
+		index = 1;
+
+	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);
+	else
+		output->gen2.active_num--;
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+	return;
+
+out_unlock:
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+}
+
+/*
+ * vfe_queue_buffer - Add empty buffer
+ * @vid: Video device structure
+ * @buf: Buffer to be enqueued
+ *
+ * Add an empty buffer - depending on the current number of buffers it will be
+ * put in pending buffer queue or directly given to the hardware to be filled.
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+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_device *vfe = to_vfe(line);
+	struct vfe_output *output;
+	unsigned long flags;
+
+	output = &line->output;
+
+	spin_lock_irqsave(&vfe->output_lock, flags);
+
+	if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
+		output->buf[output->gen2.active_num++] = buf;
+		vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
+	} else {
+		vfe_buf_add_pending(output, buf);
+	}
+
+	spin_unlock_irqrestore(&vfe->output_lock, flags);
+
+	return 0;
+}
+
+const struct vfe_isr_ops vfe_isr_ops_170 = {
+	.reset_ack = vfe_isr_reset_ack,
+	.halt_ack = vfe_isr_halt_ack,
+	.reg_update = vfe_isr_reg_update,
+	.sof = vfe_isr_sof,
+	.comp_done = vfe_isr_comp_done,
+	.wm_done = vfe_isr_wm_done,
+};
+
+static const struct camss_video_ops vfe_video_ops_170 = {
+	.queue_buffer = vfe_queue_buffer,
+	.flush_buffers = vfe_flush_buffers,
+};
+
+static void vfe_subdev_init(struct vfe_device *vfe)
+{
+	vfe->isr_ops = vfe_isr_ops_170;
+	vfe->video_ops = vfe_video_ops_170;
+}
+
+const struct vfe_hw_ops vfe_ops_170 = {
+	.global_reset = vfe_global_reset,
+	.hw_version_read = vfe_hw_version_read,
+	.isr_read = vfe_isr_read,
+	.isr = vfe_isr,
+	.reg_update_clear = vfe_reg_update_clear,
+	.reg_update = vfe_reg_update,
+	.subdev_init = vfe_subdev_init,
+	.vfe_disable = vfe_disable,
+	.vfe_enable = vfe_enable,
+	.vfe_halt = vfe_halt,
+	.violation_read = vfe_violation_read,
+};
+
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 2ffa5b3c5426..5a874b544391 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
 	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
 };
 
+static const struct vfe_format formats_rdi_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
+	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
+	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
+};
+
+static const struct vfe_format formats_pix_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+};
+
 /*
  * vfe_get_bpp - map media bus format to bits per pixel
  * @formats: supported media bus formats array
@@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 			return sink_code;
 		}
 	else if (vfe->camss->version == CAMSS_8x96 ||
-		 vfe->camss->version == CAMSS_660)
+		 vfe->camss->version == CAMSS_660 ||
+		 vfe->camss->version == CAMSS_845)
 		switch (sink_code) {
 		case MEDIA_BUS_FMT_YUYV8_2X8:
 		{
@@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
 		return 0;
 }
 
-/*
- * vfe_reset - Trigger reset on VFE module and wait to complete
- * @vfe: VFE device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int vfe_reset(struct vfe_device *vfe)
+int vfe_reset(struct vfe_device *vfe)
 {
 	unsigned long time;
 
@@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
 		struct camss_clock *clock = &vfe->clock[i];
 
 		if (!strcmp(clock->name, "vfe0") ||
-		    !strcmp(clock->name, "vfe1")) {
+		    !strcmp(clock->name, "vfe1") ||
+		    !strcmp(clock->name, "vfe_lite")) {
 			u64 min_rate = 0;
 			long rate;
 
@@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 	case CAMSS_660:
 		vfe->ops = &vfe_ops_4_8;
 		break;
+
+	case CAMSS_845:
+		vfe->ops = &vfe_ops_170;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
 				l->formats = formats_rdi_8x96;
 				l->nformats = ARRAY_SIZE(formats_rdi_8x96);
 			}
+		} else if (camss->version == CAMSS_845) {
+			if (i == VFE_LINE_PIX) {
+				l->formats = formats_pix_845;
+				l->nformats = ARRAY_SIZE(formats_pix_845);
+			} else {
+				l->formats = formats_rdi_845;
+				l->nformats = ARRAY_SIZE(formats_rdi_845);
+			}
 		} else {
 			return -EINVAL;
 		}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 8629c833f130..a0b618c9cec8 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -19,7 +19,6 @@
 #include "camss-video.h"
 #include "camss-vfe-gen1.h"
 
-
 #define MSM_VFE_PAD_SINK 0
 #define MSM_VFE_PAD_SRC 1
 #define MSM_VFE_PADS_NUM 2
@@ -39,14 +38,14 @@
 #define to_vfe(ptr_line)	\
 	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
 
-
 enum vfe_output_state {
 	VFE_OUTPUT_OFF,
 	VFE_OUTPUT_RESERVED,
 	VFE_OUTPUT_SINGLE,
 	VFE_OUTPUT_CONTINUOUS,
 	VFE_OUTPUT_IDLE,
-	VFE_OUTPUT_STOPPING
+	VFE_OUTPUT_STOPPING,
+	VFE_OUTPUT_ON,
 };
 
 enum vfe_line_id {
@@ -72,6 +71,9 @@ struct vfe_output {
 			int active_buf;
 			int wait_sof;
 		} gen1;
+		struct {
+			int active_num;
+		} gen2;
 	};
 	enum vfe_output_state state;
 	unsigned int sequence;
@@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
 
 struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
 
-/*
- * vfe_disable - Disable streaming on VFE line
- * @line: VFE line
- *
- * Return 0 on success or a negative error code otherwise
- */
-int vfe_disable(struct vfe_line *line);
-
 int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
 
 /*
@@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
 int vfe_release_wm(struct vfe_device *vfe, u8 wm);
 int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
 
+/*
+ * vfe_reset - Trigger reset on VFE module and wait to complete
+ * @vfe: VFE device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+int vfe_reset(struct vfe_device *vfe);
+
 extern const struct vfe_hw_ops vfe_ops_4_1;
 extern const struct vfe_hw_ops vfe_ops_4_7;
 extern const struct vfe_hw_ops vfe_ops_4_8;
+extern const struct vfe_hw_ops vfe_ops_170;
 
 #endif /* QC_MSM_CAMSS_VFE_H */
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index bd9334af1c73..b4943df9eaf6 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
 	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 };
 
+static const struct camss_format_info formats_rdi_845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
+	{ MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+};
+
 static const struct camss_format_info formats_pix_8x16[] = {
 	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
 	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
@@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
 	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
 };
 
+static const struct camss_format_info formats_pix_845[] = {
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
+	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
+	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
+	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
+	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
+};
+
 /* -----------------------------------------------------------------------------
  * Helper functions
  */
@@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
 			video->formats = formats_rdi_8x96;
 			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
 		}
+	}  else if (video->camss->version == CAMSS_845) {
+		if (is_pix) {
+			video->formats = formats_pix_845;
+			video->nformats = ARRAY_SIZE(formats_pix_845);
+		} else {
+			video->formats = formats_rdi_845;
+			video->nformats = ARRAY_SIZE(formats_rdi_845);
+		}
 	} else {
 		goto error_video_register;
 	}
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index aeec59bc6194..1c3d64d612ff 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources vfe_res_845[] = {
+	/* VFE0 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe0", "vfe0_axi",
+				"vfe0_src", "csi0",
+				"csi0_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 0 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe0" },
+		.interrupt = { "vfe0" }
+	},
+
+	/* VFE1 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe1", "vfe1_axi",
+				"vfe1_src", "csi1",
+				"csi1_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 0 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe1" },
+		.interrupt = { "vfe1" }
+	},
+
+	/* VFE-lite */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
+				"soc_ahb", "vfe_lite",
+				"vfe_lite_src", "csi2",
+				"csi2_src"},
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "vfe_lite" },
+		.interrupt = { "vfe_lite" }
+	}
+};
+
 /*
  * camss_add_clock_margin - Add margin to clock frequency rate
  * @rate: Clock frequency rate
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 07/17] media: camss: Add missing format identifiers
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

The CSI-2 spec defines the following types:
 - Data Type - Often abbreviated DT
 - Decode Format - Often abbreviated as DF
 - Encode Format

These definitions are as far as I can tell complete for CSI-2.

Additionally the Qualcomm internal type describing Plain Formats
has been added. Plain formats describe the size of the pixels
written by the RDI units to memory. PLAIN8 for example has the size
8 bits, and PLAIN32 32 bits. The appropriate Plain Format is
determined by the Decode Format used. The smallest Plain Format
that is able to contain a pixel of the used Decode Format is the
appropriate one to use.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-csid.h    | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 1824b3745e10..02fc34ee8a41 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -21,6 +21,56 @@
 #define MSM_CSID_PAD_SRC 1
 #define MSM_CSID_PADS_NUM 2
 
+#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
+#define DATA_TYPE_YUV420_8BIT		0x18
+#define DATA_TYPE_YUV420_10BIT		0x19
+#define DATA_TYPE_YUV420_8BIT_LEGACY	0x1a
+#define DATA_TYPE_YUV420_8BIT_SHIFTED	0x1c /* Chroma Shifted Pixel Sampling */
+#define DATA_TYPE_YUV420_10BIT_SHIFTED	0x1d /* Chroma Shifted Pixel Sampling */
+#define DATA_TYPE_YUV422_8BIT		0x1e
+#define DATA_TYPE_YUV422_10BIT		0x1f
+#define DATA_TYPE_RGB444		0x20
+#define DATA_TYPE_RGB555		0x21
+#define DATA_TYPE_RGB565		0x22
+#define DATA_TYPE_RGB666		0x23
+#define DATA_TYPE_RGB888		0x24
+#define DATA_TYPE_RAW_24BIT		0x27
+#define DATA_TYPE_RAW_6BIT		0x28
+#define DATA_TYPE_RAW_7BIT		0x29
+#define DATA_TYPE_RAW_8BIT		0x2a
+#define DATA_TYPE_RAW_10BIT		0x2b
+#define DATA_TYPE_RAW_12BIT		0x2c
+#define DATA_TYPE_RAW_14BIT		0x2d
+#define DATA_TYPE_RAW_16BIT		0x2e
+#define DATA_TYPE_RAW_20BIT		0x2f
+
+#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
+#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
+#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
+#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
+#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x4
+#define DECODE_FORMAT_UNCOMPRESSED_16_BIT	0x5
+#define DECODE_FORMAT_UNCOMPRESSED_20_BIT	0x6
+#define DECODE_FORMAT_DPCM_10_6_10		0x7
+#define DECODE_FORMAT_DPCM_10_8_10		0x8
+#define DECODE_FORMAT_DPCM_12_6_12		0x9
+#define DECODE_FORMAT_DPCM_12_8_12		0xA
+#define DECODE_FORMAT_DPCM_14_8_14		0xB
+#define DECODE_FORMAT_DPCM_14_10_14		0xC
+#define DECODE_FORMAT_USER_DEFINED		0xE
+#define DECODE_FORMAT_PAYLOAD_ONLY		0xF
+
+#define ENCODE_FORMAT_RAW_8_BIT		0x1
+#define ENCODE_FORMAT_RAW_10_BIT	0x2
+#define ENCODE_FORMAT_RAW_12_BIT	0x3
+#define ENCODE_FORMAT_RAW_14_BIT	0x4
+#define ENCODE_FORMAT_RAW_16_BIT	0x5
+
+#define PLAIN_FORMAT_PLAIN8	0x0 /* supports DPCM, UNCOMPRESSED_6/8_BIT */
+#define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
+#define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
+
+
 enum csid_payload_mode {
 	CSID_PAYLOAD_MODE_INCREMENTING = 0,
 	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
-- 
2.27.0


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

* [PATCH v1 07/17] media: camss: Add missing format identifiers
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

The CSI-2 spec defines the following types:
 - Data Type - Often abbreviated DT
 - Decode Format - Often abbreviated as DF
 - Encode Format

These definitions are as far as I can tell complete for CSI-2.

Additionally the Qualcomm internal type describing Plain Formats
has been added. Plain formats describe the size of the pixels
written by the RDI units to memory. PLAIN8 for example has the size
8 bits, and PLAIN32 32 bits. The appropriate Plain Format is
determined by the Decode Format used. The smallest Plain Format
that is able to contain a pixel of the used Decode Format is the
appropriate one to use.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-csid.h    | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 1824b3745e10..02fc34ee8a41 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -21,6 +21,56 @@
 #define MSM_CSID_PAD_SRC 1
 #define MSM_CSID_PADS_NUM 2
 
+#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
+#define DATA_TYPE_YUV420_8BIT		0x18
+#define DATA_TYPE_YUV420_10BIT		0x19
+#define DATA_TYPE_YUV420_8BIT_LEGACY	0x1a
+#define DATA_TYPE_YUV420_8BIT_SHIFTED	0x1c /* Chroma Shifted Pixel Sampling */
+#define DATA_TYPE_YUV420_10BIT_SHIFTED	0x1d /* Chroma Shifted Pixel Sampling */
+#define DATA_TYPE_YUV422_8BIT		0x1e
+#define DATA_TYPE_YUV422_10BIT		0x1f
+#define DATA_TYPE_RGB444		0x20
+#define DATA_TYPE_RGB555		0x21
+#define DATA_TYPE_RGB565		0x22
+#define DATA_TYPE_RGB666		0x23
+#define DATA_TYPE_RGB888		0x24
+#define DATA_TYPE_RAW_24BIT		0x27
+#define DATA_TYPE_RAW_6BIT		0x28
+#define DATA_TYPE_RAW_7BIT		0x29
+#define DATA_TYPE_RAW_8BIT		0x2a
+#define DATA_TYPE_RAW_10BIT		0x2b
+#define DATA_TYPE_RAW_12BIT		0x2c
+#define DATA_TYPE_RAW_14BIT		0x2d
+#define DATA_TYPE_RAW_16BIT		0x2e
+#define DATA_TYPE_RAW_20BIT		0x2f
+
+#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
+#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
+#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
+#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
+#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x4
+#define DECODE_FORMAT_UNCOMPRESSED_16_BIT	0x5
+#define DECODE_FORMAT_UNCOMPRESSED_20_BIT	0x6
+#define DECODE_FORMAT_DPCM_10_6_10		0x7
+#define DECODE_FORMAT_DPCM_10_8_10		0x8
+#define DECODE_FORMAT_DPCM_12_6_12		0x9
+#define DECODE_FORMAT_DPCM_12_8_12		0xA
+#define DECODE_FORMAT_DPCM_14_8_14		0xB
+#define DECODE_FORMAT_DPCM_14_10_14		0xC
+#define DECODE_FORMAT_USER_DEFINED		0xE
+#define DECODE_FORMAT_PAYLOAD_ONLY		0xF
+
+#define ENCODE_FORMAT_RAW_8_BIT		0x1
+#define ENCODE_FORMAT_RAW_10_BIT	0x2
+#define ENCODE_FORMAT_RAW_12_BIT	0x3
+#define ENCODE_FORMAT_RAW_14_BIT	0x4
+#define ENCODE_FORMAT_RAW_16_BIT	0x5
+
+#define PLAIN_FORMAT_PLAIN8	0x0 /* supports DPCM, UNCOMPRESSED_6/8_BIT */
+#define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
+#define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
+
+
 enum csid_payload_mode {
 	CSID_PAYLOAD_MODE_INCREMENTING = 0,
 	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 08/17] media: camss: Refactor CSID HW version support
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

In order to support Qualcomm ISP hardware architectures that diverge
from older architectures, the CSID subdevice drivers needs to be refactored
to better abstract the different ISP hardware architectures.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   2 +
 .../platform/qcom/camss/camss-csid-4-1.c      | 338 ++++++++++
 .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++
 .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------
 .../media/platform/qcom/camss/camss-csid.h    | 125 +++-
 5 files changed, 897 insertions(+), 590 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 052c4f405fa3..cff388b653ba 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -4,6 +4,8 @@
 qcom-camss-objs += \
 		camss.o \
 		camss-csid.o \
+		camss-csid-4-1.o \
+		camss-csid-4-7.o \
 		camss-csiphy-2ph-1-0.o \
 		camss-csiphy-3ph-1-0.o \
 		camss-csiphy.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
new file mode 100644
index 000000000000..84b415137555
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-1.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+ #include <linux/completion.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x00c
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x010 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x020 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x060
+#define CAMSS_CSID_IRQ_MASK		0x064
+#define CAMSS_CSID_IRQ_STATUS		0x068
+#define CAMSS_CSID_TG_CTRL		0x0a0
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0a4
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0ac + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b0 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0b4 + 0xc * (n))
+
+
+enum csid_testgen_pattern {
+	TESTGEN_PATTERN_INCREMENTING = 0,
+	TESTGEN_PATTERN_ALTERNATING_55_AA = 1,
+	TESTGEN_PATTERN_ALL_ZEROES = 2,
+	TESTGEN_PATTERN_ALL_ONES = 3,
+	TESTGEN_PATTERN_RANDOM = 4,
+	TESTGEN_PATTERN_USER_SPECIFIED = 5,
+};
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_lines, num_bytes_per_line;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	if (match_format_idx > 0)
+		return 0;
+
+	return sink_code;
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;
+}
+
+const struct csid_hw_ops csid_ops_4_1 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
new file mode 100644
index 000000000000..16a69b140f4e
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x010
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x014 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x024 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x064
+#define CAMSS_CSID_IRQ_MASK		0x068
+#define CAMSS_CSID_IRQ_STATUS		0x06c
+#define CAMSS_CSID_TG_CTRL		0x0a8
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0ac
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0b4 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b8 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0bc + 0xc * (n))
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
+	u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_bytes_per_line, num_lines;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+
+		if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
+		    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
+			val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
+		}
+
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+/*
+ * isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	switch (sink_code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_SBGGR10_1X10,
+			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	case MEDIA_BUS_FMT_Y10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_Y10_1X10,
+			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	default:
+		if (match_format_idx > 0)
+			return 0;
+
+		return sink_code;
+	}
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;
+}
+
+const struct csid_hw_ops csid_ops_4_7 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index be3fe76f3dc3..601bd810f2b0 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -26,405 +26,35 @@
 
 #define MSM_CSID_NAME "msm_csid"
 
-#define CAMSS_CSID_HW_VERSION		0x0
-#define CAMSS_CSID_CORE_CTRL_0		0x004
-#define CAMSS_CSID_CORE_CTRL_1		0x008
-#define CAMSS_CSID_RST_CMD(v)		((v) == CAMSS_8x16 ? 0x00c : 0x010)
-#define CAMSS_CSID_CID_LUT_VC_n(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
-#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
-#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
-#define CAMSS_CSID_IRQ_CLEAR_CMD(v)	((v) == CAMSS_8x16 ? 0x060 : 0x064)
-#define CAMSS_CSID_IRQ_MASK(v)		((v) == CAMSS_8x16 ? 0x064 : 0x068)
-#define CAMSS_CSID_IRQ_STATUS(v)	((v) == CAMSS_8x16 ? 0x068 : 0x06c)
-#define CAMSS_CSID_TG_CTRL(v)		((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)
-#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
-#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
-#define CAMSS_CSID_TG_VC_CFG(v)		((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)
-#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
-#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
-#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))
-
-#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
-#define DATA_TYPE_YUV422_8BIT		0x1e
-#define DATA_TYPE_RAW_6BIT		0x28
-#define DATA_TYPE_RAW_8BIT		0x2a
-#define DATA_TYPE_RAW_10BIT		0x2b
-#define DATA_TYPE_RAW_12BIT		0x2c
-#define DATA_TYPE_RAW_14BIT		0x2d
-
-#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
-#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
-#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
-#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
-#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x8
-
-#define CSID_RESET_TIMEOUT_MS 500
-
-struct csid_format {
-	u32 code;
-	u8 data_type;
-	u8 decode_format;
-	u8 bpp;
-	u8 spp; /* bus samples per pixel */
-};
-
-static const struct csid_format csid_formats_8x16[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
-
-static const struct csid_format csid_formats_8x96[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
 
-static u32 csid_find_code(u32 *code, unsigned int n_code,
-			  unsigned int index, u32 req_code)
+u32 csid_find_code(u32 *codes, unsigned int ncodes,
+		   unsigned int match_format_idx, u32 match_code)
 {
 	int i;
 
-	if (!req_code && (index >= n_code))
+	if (!match_code && (match_format_idx >= ncodes))
 		return 0;
 
-	for (i = 0; i < n_code; i++)
-		if (req_code) {
-			if (req_code == code[i])
-				return req_code;
+	for (i = 0; i < ncodes; i++)
+		if (match_code) {
+			if (codes[i] == match_code)
+				return match_code;
 		} else {
-			if (i == index)
-				return code[i];
-		}
-
-	return code[0];
-}
-
-static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
-			     unsigned int index, u32 src_req_code)
-{
-	if (csid->camss->version == CAMSS_8x16) {
-		if (index > 0)
-			return 0;
-
-		return sink_code;
-	} else if (csid->camss->version == CAMSS_8x96 ||
-		   csid->camss->version == CAMSS_660) {
-		switch (sink_code) {
-		case MEDIA_BUS_FMT_SBGGR10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_SBGGR10_1X10,
-				MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
-		}
-		case MEDIA_BUS_FMT_Y10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_Y10_1X10,
-				MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
+			if (i == match_format_idx)
+				return codes[i];
 		}
-		default:
-			if (index > 0)
-				return 0;
 
-			return sink_code;
-		}
-	} else {
-		return 0;
-	}
+	return codes[0];
 }
 
-static const struct csid_format *csid_get_fmt_entry(
+const struct csid_format *csid_get_fmt_entry(
 					const struct csid_format *formats,
-					unsigned int nformat,
+					unsigned int nformats,
 					u32 code)
 {
 	unsigned int i;
 
-	for (i = 0; i < nformat; i++)
+	for (i = 0; i < nformats; i++)
 		if (code == formats[i].code)
 			return &formats[i];
 
@@ -433,28 +63,6 @@ static const struct csid_format *csid_get_fmt_entry(
 	return &formats[0];
 }
 
-/*
- * csid_isr - CSID module interrupt handler
- * @irq: Interrupt line
- * @dev: CSID device
- *
- * Return IRQ_HANDLED on success
- */
-static irqreturn_t csid_isr(int irq, void *dev)
-{
-	struct csid_device *csid = dev;
-	enum camss_version ver = csid->camss->version;
-	u32 value;
-
-	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));
-	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));
-
-	if ((value >> 11) & 0x1)
-		complete(&csid->reset_complete);
-
-	return IRQ_HANDLED;
-}
-
 /*
  * csid_set_clock_rates - Calculate and set clock rates on CSID module
  * @csiphy: CSID device
@@ -521,31 +129,6 @@ static int csid_set_clock_rates(struct csid_device *csid)
 	return 0;
 }
 
-/*
- * csid_reset - Trigger reset on CSID module and wait to complete
- * @csid: CSID device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int csid_reset(struct csid_device *csid)
-{
-	unsigned long time;
-
-	reinit_completion(&csid->reset_complete);
-
-	writel_relaxed(0x7fff, csid->base +
-		       CAMSS_CSID_RST_CMD(csid->camss->version));
-
-	time = wait_for_completion_timeout(&csid->reset_complete,
-		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
-	if (!time) {
-		dev_err(csid->camss->dev, "CSID reset timeout\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
 /*
  * csid_set_power - Power on/off CSID module
  * @sd: CSID V4L2 subdevice
@@ -560,8 +143,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 	int ret;
 
 	if (on) {
-		u32 hw_version;
-
 		ret = pm_runtime_get_sync(dev);
 		if (ret < 0) {
 			pm_runtime_put_sync(dev);
@@ -590,7 +171,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 
 		enable_irq(csid->irq);
 
-		ret = csid_reset(csid);
+		ret = csid->ops->reset(csid);
 		if (ret < 0) {
 			disable_irq(csid->irq);
 			camss_disable_clocks(csid->nclocks, csid->clock);
@@ -599,8 +180,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 			return ret;
 		}
 
-		hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
-		dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);
+		csid->ops->hw_version(csid);
 	} else {
 		disable_irq(csid->irq);
 		camss_disable_clocks(csid->nclocks, csid->clock);
@@ -623,16 +203,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct csid_device *csid = v4l2_get_subdevdata(sd);
-	struct csid_testgen_config *tg = &csid->testgen;
-	enum camss_version ver = csid->camss->version;
-	u32 val;
+	int ret;
 
 	if (enable) {
-		u8 vc = 0; /* Virtual Channel 0 */
-		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
-		u8 dt, dt_shift, df;
-		int ret;
-
 		ret = v4l2_ctrl_handler_setup(&csid->ctrls);
 		if (ret < 0) {
 			dev_err(csid->camss->dev,
@@ -640,116 +213,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 			return ret;
 		}
 
-		if (!tg->enabled &&
+		if (!csid->testgen.enabled &&
 		    !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
 			return -ENOLINK;
-
-		if (tg->enabled) {
-			/* Config Test Generator */
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SRC];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			u32 num_bytes_per_line =
-				f->width * format->bpp * format->spp / 8;
-			u32 num_lines = f->height;
-
-			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
-			/* 1:0 VC */
-			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
-			      ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_VC_CFG(ver));
-
-			/* 28:16 bytes per lines, 12:0 num of lines */
-			val = ((num_bytes_per_line & 0x1fff) << 16) |
-			      (num_lines & 0x1fff);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));
-
-			dt = format->data_type;
-
-			/* 5:0 data type */
-			val = dt;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));
-
-			/* 2:0 output test pattern */
-			val = tg->payload_mode;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));
-
-			df = format->decode_format;
-		} else {
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SINK];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			struct csid_phy_config *phy = &csid->phy;
-
-			val = phy->lane_cnt - 1;
-			val |= phy->lane_assign << 4;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_0);
-
-			val = phy->csiphy_id << 17;
-			val |= 0x9;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_1);
-
-			dt = format->data_type;
-			df = format->decode_format;
-		}
-
-		/* Config LUT */
-
-		dt_shift = (cid % 4) * 8;
-
-		val = readl_relaxed(csid->base +
-				    CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-		val &= ~(0xff << dt_shift);
-		val |= dt << dt_shift;
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-
-		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
-		val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
-
-		if (csid->camss->version == CAMSS_8x96 ||
-		    csid->camss->version == CAMSS_660) {
-			u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
-			u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
-
-			if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
-			    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
-				val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
-			}
-		}
-
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_n_CFG(ver, cid));
-
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_ENABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
-	} else {
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_DISABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
 	}
 
+	csid->ops->configure_stream(csid, enable);
+
 	return 0;
 }
 
@@ -818,7 +288,7 @@ static void csid_try_format(struct csid_device *csid,
 
 			*fmt = *__csid_get_format(csid, cfg,
 						      MSM_CSID_PAD_SINK, which);
-			fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);
+			fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
 		} else {
 			/* Test generator is enabled, set format on source */
 			/* pad to allow test generator usage */
@@ -868,7 +338,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
 						     MSM_CSID_PAD_SINK,
 						     code->which);
 
-			code->code = csid_src_pad_code(csid, sink_fmt->code,
+			code->code = csid->ops->src_pad_code(csid, sink_fmt->code,
 						       code->index, 0);
 			if (!code->code)
 				return -EINVAL;
@@ -1004,15 +474,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	return csid_set_format(sd, fh ? fh->pad : NULL, &format);
 }
 
-static const char * const csid_test_pattern_menu[] = {
-	"Disabled",
-	"Incrementing",
-	"Alternating 0x55/0xAA",
-	"All Zeros 0x00",
-	"All Ones 0xFF",
-	"Pseudo-random Data",
-};
-
 /*
  * csid_set_test_pattern - Set test generator's pattern mode
  * @csid: CSID device
@@ -1030,25 +491,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)
 
 	tg->enabled = !!value;
 
-	switch (value) {
-	case 1:
-		tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;
-		break;
-	case 2:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;
-		break;
-	case 3:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;
-		break;
-	case 4:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;
-		break;
-	case 5:
-		tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;
-		break;
-	}
-
-	return 0;
+	return csid->ops->configure_testgen_pattern(csid, value);
 }
 
 /*
@@ -1097,17 +540,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->id = id;
 
 	if (camss->version == CAMSS_8x16) {
-		csid->formats = csid_formats_8x16;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x16);
+		csid->ops = &csid_ops_4_1;
 	} else if (camss->version == CAMSS_8x96 ||
 		   camss->version == CAMSS_660) {
-		csid->formats = csid_formats_8x96;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x96);
+		csid->ops = &csid_ops_4_7;
 	} else {
 		return -EINVAL;
 	}
+	csid->ops->subdev_init(csid);
 
 	/* Memory */
 
@@ -1130,7 +570,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->irq = r->start;
 	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
 		 dev_name(dev), MSM_CSID_NAME, csid->id);
-	ret = devm_request_irq(dev, csid->irq, csid_isr,
+	ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
 		IRQF_TRIGGER_RISING, csid->irq_name, csid);
 	if (ret < 0) {
 		dev_err(dev, "request_irq failed: %d\n", ret);
@@ -1341,8 +781,8 @@ int msm_csid_register_entity(struct csid_device *csid,
 
 	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
 				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
-				ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,
-				csid_test_pattern_menu);
+				csid->testgen.nmodes, 0, 0,
+				csid->testgen.modes);
 
 	if (csid->ctrls.error) {
 		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 02fc34ee8a41..bcc8bdb6e0ad 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -70,19 +70,50 @@
 #define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
 #define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
 
+#define CSID_RESET_TIMEOUT_MS 500
 
-enum csid_payload_mode {
+
+enum csid_testgen_mode {
 	CSID_PAYLOAD_MODE_INCREMENTING = 0,
 	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
 	CSID_PAYLOAD_MODE_ALL_ZEROES = 2,
 	CSID_PAYLOAD_MODE_ALL_ONES = 3,
 	CSID_PAYLOAD_MODE_RANDOM = 4,
 	CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,
+	CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,
+	CSID_PAYLOAD_MODE_COLOR_BOX = 7,
+	CSID_PAYLOAD_MODE_COLOR_BARS = 8,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,
+};
+
+static const char * const csid_testgen_modes[] = {
+	"Disabled",
+	"Incrementing",
+	"Alternating 0x55/0xAA",
+	"All Zeros 0x00",
+	"All Ones 0xFF",
+	"Pseudo-random Data",
+	"User Specified",
+	"Complex pattern",
+	"Color box",
+	"Color bars",
+};
+
+struct csid_format {
+	u32 code;
+	u8 data_type;
+	u8 decode_format;
+	u8 bpp;
+	u8 spp; /* bus samples per pixel */
 };
 
 struct csid_testgen_config {
+	enum csid_testgen_mode mode;
+	const char * const*modes;
+	u8 nmodes;
 	u8 enabled;
-	enum csid_payload_mode payload_mode;
 };
 
 struct csid_phy_config {
@@ -91,6 +122,65 @@ struct csid_phy_config {
 	u32 lane_assign;
 };
 
+struct csid_device;
+
+struct csid_hw_ops {
+	/*
+	 * configure_stream - Configures and starts CSID input stream
+	 * @csid: CSID device
+	 */
+	void (*configure_stream)(struct csid_device *csid, u8 enable);
+
+	/*
+	 * configure_testgen_pattern - Validates and configures output pattern mode
+	 * of test pattern generator
+	 * @csid: CSID device
+	 */
+	int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);
+
+	/*
+	 * hw_version - Read hardware version register from hardware
+	 * @csid: CSID device
+	 */
+	u32 (*hw_version)(struct csid_device *csid);
+
+	/*
+	 * isr - CSID module interrupt service routine
+	 * @irq: Interrupt line
+	 * @dev: CSID device
+	 *
+	 * Return IRQ_HANDLED on success
+	 */
+	irqreturn_t (*isr)(int irq, void *dev);
+
+	/*
+	 * reset - Trigger reset on CSID module and wait to complete
+	 * @csid: CSID device
+	 *
+	 * Return 0 on success or a negative error code otherwise
+	 */
+	int (*reset)(struct csid_device *csid);
+
+	/*
+	 * src_pad_code - Pick an output/src format based on the input/sink format
+	 * @csid: CSID device
+	 * @sink_code: The sink format of the input
+	 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.
+	 *	Set @match_code to 0 if used.
+	 * @match_code: Request preferred code, set @match_format_idx to 0 if used
+	 *
+	 * Return 0 on failure or src format code otherwise
+	 */
+	u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
+			    unsigned int match_format_idx, u32 match_code);
+
+	/*
+	 * subdev_init - Initialize CSID device according for hardware revision
+	 * @csid: CSID device
+	 */
+	void (*subdev_init)(struct csid_device *csid);
+};
+
 struct csid_device {
 	struct camss *camss;
 	u8 id;
@@ -110,10 +200,37 @@ struct csid_device {
 	struct v4l2_ctrl *testgen_mode;
 	const struct csid_format *formats;
 	unsigned int nformats;
+	const struct csid_hw_ops *ops;
 };
 
 struct resources;
 
+
+/*
+ * csid_find_code - Find a format code in an array using array index or format code
+ * @codes: Array of format codes
+ * @ncodes: Length of @code array
+ * @req_format_idx: Request preferred index, as defined by subdevice csid_format.
+ *	Set @match_code to 0 if used.
+ * @match_code: Request preferred code, set @req_format_idx to 0 if used
+ *
+ * Return 0 on failure or format code otherwise
+ */
+u32 csid_find_code(u32 *codes, unsigned int ncode,
+		   unsigned int match_format_idx, u32 match_code);
+
+/*
+ * csid_get_fmt_entry - Find csid_format entry with matching format code
+ * @formats: Array of format csid_format entries
+ * @nformats: Length of @nformats array
+ * @code: Desired format code
+ *
+ * Return formats[0] on failure to find code
+ */
+const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
+					     unsigned int nformats,
+					     u32 code);
+
 int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 			 const struct resources *res, u8 id);
 
@@ -124,4 +241,8 @@ void msm_csid_unregister_entity(struct csid_device *csid);
 
 void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
 
+
+extern const struct csid_hw_ops csid_ops_4_1;
+extern const struct csid_hw_ops csid_ops_4_7;
+
 #endif /* QC_MSM_CAMSS_CSID_H */
-- 
2.27.0


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

* [PATCH v1 08/17] media: camss: Refactor CSID HW version support
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

In order to support Qualcomm ISP hardware architectures that diverge
from older architectures, the CSID subdevice drivers needs to be refactored
to better abstract the different ISP hardware architectures.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   2 +
 .../platform/qcom/camss/camss-csid-4-1.c      | 338 ++++++++++
 .../platform/qcom/camss/camss-csid-4-7.c      | 406 ++++++++++++
 .../media/platform/qcom/camss/camss-csid.c    | 616 +-----------------
 .../media/platform/qcom/camss/camss-csid.h    | 125 +++-
 5 files changed, 897 insertions(+), 590 deletions(-)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-1.c
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-4-7.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 052c4f405fa3..cff388b653ba 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -4,6 +4,8 @@
 qcom-camss-objs += \
 		camss.o \
 		camss-csid.o \
+		camss-csid-4-1.o \
+		camss-csid-4-7.o \
 		camss-csiphy-2ph-1-0.o \
 		camss-csiphy-3ph-1-0.o \
 		camss-csiphy.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
new file mode 100644
index 000000000000..84b415137555
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-1.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+ #include <linux/completion.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x00c
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x010 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x020 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x060
+#define CAMSS_CSID_IRQ_MASK		0x064
+#define CAMSS_CSID_IRQ_STATUS		0x068
+#define CAMSS_CSID_TG_CTRL		0x0a0
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0a4
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0ac + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b0 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0b4 + 0xc * (n))
+
+
+enum csid_testgen_pattern {
+	TESTGEN_PATTERN_INCREMENTING = 0,
+	TESTGEN_PATTERN_ALTERNATING_55_AA = 1,
+	TESTGEN_PATTERN_ALL_ZEROES = 2,
+	TESTGEN_PATTERN_ALL_ONES = 3,
+	TESTGEN_PATTERN_RANDOM = 4,
+	TESTGEN_PATTERN_USER_SPECIFIED = 5,
+};
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_lines, num_bytes_per_line;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	if (match_format_idx > 0)
+		return 0;
+
+	return sink_code;
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1;
+}
+
+const struct csid_hw_ops csid_ops_4_1 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
new file mode 100644
index 000000000000..16a69b140f4e
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+#define CAMSS_CSID_HW_VERSION		0x0
+#define CAMSS_CSID_CORE_CTRL_0		0x004
+#define CAMSS_CSID_CORE_CTRL_1		0x008
+#define CAMSS_CSID_RST_CMD		0x010
+#define CAMSS_CSID_CID_LUT_VC_n(n)	(0x014 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG(n)		(0x024 + 0x4 * (n))
+#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
+#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
+#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
+#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
+#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
+#define CAMSS_CSID_IRQ_CLEAR_CMD	0x064
+#define CAMSS_CSID_IRQ_MASK		0x068
+#define CAMSS_CSID_IRQ_STATUS		0x06c
+#define CAMSS_CSID_TG_CTRL		0x0a8
+#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
+#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
+#define CAMSS_CSID_TG_VC_CFG		0x0ac
+#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
+#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
+#define CAMSS_CSID_TG_DT_n_CGG_0(n)	(0x0b4 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_1(n)	(0x0b8 + 0xc * (n))
+#define CAMSS_CSID_TG_DT_n_CGG_2(n)	(0x0bc + 0xc * (n))
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
+	u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
+	u32 val;
+
+	if (enable) {
+		struct v4l2_mbus_framefmt *input_format;
+		const struct csid_format *format;
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
+		u8 dt_shift;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			u32 num_bytes_per_line, num_lines;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SRC];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+			num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
+			num_lines = input_format->height;
+
+			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
+			/* 1:0 VC */
+			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
+				  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
+
+			/* 28:16 bytes per lines, 12:0 num of lines */
+			val = ((num_bytes_per_line & 0x1fff) << 16) |
+				  (num_lines & 0x1fff);
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
+
+			/* 5:0 data type */
+			val = format->data_type;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
+
+			/* 2:0 output test pattern */
+			val = tg->mode;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
+		} else {
+			struct csid_phy_config *phy = &csid->phy;
+
+			input_format = &csid->fmt[MSM_CSID_PAD_SINK];
+			format = csid_get_fmt_entry(csid->formats, csid->nformats,
+						    input_format->code);
+
+			val = phy->lane_cnt - 1;
+			val |= phy->lane_assign << 4;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
+
+			val = phy->csiphy_id << 17;
+			val |= 0x9;
+
+			writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
+		}
+
+		/* Config LUT */
+
+		dt_shift = (cid % 4) * 8;
+
+		val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+		val &= ~(0xff << dt_shift);
+		val |= format->data_type << dt_shift;
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
+
+		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
+		val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
+		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
+
+		if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
+		    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
+		     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
+			val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
+			val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
+		}
+
+		writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
+
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_ENABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	} else {
+		if (tg->enabled) {
+			val = CAMSS_CSID_TG_CTRL_DISABLE;
+			writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
+		}
+	}
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
+
+	dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
+
+	return hw_version;
+}
+
+/*
+ * isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 value;
+
+	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
+	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
+
+	if ((value >> 11) & 0x1)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	switch (sink_code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_SBGGR10_1X10,
+			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	case MEDIA_BUS_FMT_Y10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_Y10_1X10,
+			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	default:
+		if (match_format_idx > 0)
+			return 0;
+
+		return sink_code;
+	}
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7;
+}
+
+const struct csid_hw_ops csid_ops_4_7 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index be3fe76f3dc3..601bd810f2b0 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -26,405 +26,35 @@
 
 #define MSM_CSID_NAME "msm_csid"
 
-#define CAMSS_CSID_HW_VERSION		0x0
-#define CAMSS_CSID_CORE_CTRL_0		0x004
-#define CAMSS_CSID_CORE_CTRL_1		0x008
-#define CAMSS_CSID_RST_CMD(v)		((v) == CAMSS_8x16 ? 0x00c : 0x010)
-#define CAMSS_CSID_CID_LUT_VC_n(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n))
-#define CAMSS_CSID_CID_n_CFG_ISPIF_EN	BIT(0)
-#define CAMSS_CSID_CID_n_CFG_RDI_EN	BIT(1)
-#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT	4
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8		(0 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16		(1 << 8)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB	(0 << 9)
-#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB	(1 << 9)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP		(0 << 10)
-#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING	(1 << 10)
-#define CAMSS_CSID_IRQ_CLEAR_CMD(v)	((v) == CAMSS_8x16 ? 0x060 : 0x064)
-#define CAMSS_CSID_IRQ_MASK(v)		((v) == CAMSS_8x16 ? 0x064 : 0x068)
-#define CAMSS_CSID_IRQ_STATUS(v)	((v) == CAMSS_8x16 ? 0x068 : 0x06c)
-#define CAMSS_CSID_TG_CTRL(v)		((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8)
-#define CAMSS_CSID_TG_CTRL_DISABLE	0xa06436
-#define CAMSS_CSID_TG_CTRL_ENABLE	0xa06437
-#define CAMSS_CSID_TG_VC_CFG(v)		((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac)
-#define CAMSS_CSID_TG_VC_CFG_H_BLANKING		0x3ff
-#define CAMSS_CSID_TG_VC_CFG_V_BLANKING		0x7f
-#define CAMSS_CSID_TG_DT_n_CGG_0(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_1(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n))
-#define CAMSS_CSID_TG_DT_n_CGG_2(v, n)	\
-			(((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n))
-
-#define DATA_TYPE_EMBEDDED_DATA_8BIT	0x12
-#define DATA_TYPE_YUV422_8BIT		0x1e
-#define DATA_TYPE_RAW_6BIT		0x28
-#define DATA_TYPE_RAW_8BIT		0x2a
-#define DATA_TYPE_RAW_10BIT		0x2b
-#define DATA_TYPE_RAW_12BIT		0x2c
-#define DATA_TYPE_RAW_14BIT		0x2d
-
-#define DECODE_FORMAT_UNCOMPRESSED_6_BIT	0x0
-#define DECODE_FORMAT_UNCOMPRESSED_8_BIT	0x1
-#define DECODE_FORMAT_UNCOMPRESSED_10_BIT	0x2
-#define DECODE_FORMAT_UNCOMPRESSED_12_BIT	0x3
-#define DECODE_FORMAT_UNCOMPRESSED_14_BIT	0x8
-
-#define CSID_RESET_TIMEOUT_MS 500
-
-struct csid_format {
-	u32 code;
-	u8 data_type;
-	u8 decode_format;
-	u8 bpp;
-	u8 spp; /* bus samples per pixel */
-};
-
-static const struct csid_format csid_formats_8x16[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
-
-static const struct csid_format csid_formats_8x96[] = {
-	{
-		MEDIA_BUS_FMT_UYVY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_VYUY8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YUYV8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_YVYU8_2X8,
-		DATA_TYPE_YUV422_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		2,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB8_1X8,
-		DATA_TYPE_RAW_8BIT,
-		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
-		8,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB12_1X12,
-		DATA_TYPE_RAW_12BIT,
-		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
-		12,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SBGGR14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGBRG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SGRBG14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_SRGGB14_1X14,
-		DATA_TYPE_RAW_14BIT,
-		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
-		14,
-		1,
-	},
-	{
-		MEDIA_BUS_FMT_Y10_1X10,
-		DATA_TYPE_RAW_10BIT,
-		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
-		10,
-		1,
-	},
-};
 
-static u32 csid_find_code(u32 *code, unsigned int n_code,
-			  unsigned int index, u32 req_code)
+u32 csid_find_code(u32 *codes, unsigned int ncodes,
+		   unsigned int match_format_idx, u32 match_code)
 {
 	int i;
 
-	if (!req_code && (index >= n_code))
+	if (!match_code && (match_format_idx >= ncodes))
 		return 0;
 
-	for (i = 0; i < n_code; i++)
-		if (req_code) {
-			if (req_code == code[i])
-				return req_code;
+	for (i = 0; i < ncodes; i++)
+		if (match_code) {
+			if (codes[i] == match_code)
+				return match_code;
 		} else {
-			if (i == index)
-				return code[i];
-		}
-
-	return code[0];
-}
-
-static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
-			     unsigned int index, u32 src_req_code)
-{
-	if (csid->camss->version == CAMSS_8x16) {
-		if (index > 0)
-			return 0;
-
-		return sink_code;
-	} else if (csid->camss->version == CAMSS_8x96 ||
-		   csid->camss->version == CAMSS_660) {
-		switch (sink_code) {
-		case MEDIA_BUS_FMT_SBGGR10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_SBGGR10_1X10,
-				MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
-		}
-		case MEDIA_BUS_FMT_Y10_1X10:
-		{
-			u32 src_code[] = {
-				MEDIA_BUS_FMT_Y10_1X10,
-				MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
-			};
-
-			return csid_find_code(src_code, ARRAY_SIZE(src_code),
-					      index, src_req_code);
+			if (i == match_format_idx)
+				return codes[i];
 		}
-		default:
-			if (index > 0)
-				return 0;
 
-			return sink_code;
-		}
-	} else {
-		return 0;
-	}
+	return codes[0];
 }
 
-static const struct csid_format *csid_get_fmt_entry(
+const struct csid_format *csid_get_fmt_entry(
 					const struct csid_format *formats,
-					unsigned int nformat,
+					unsigned int nformats,
 					u32 code)
 {
 	unsigned int i;
 
-	for (i = 0; i < nformat; i++)
+	for (i = 0; i < nformats; i++)
 		if (code == formats[i].code)
 			return &formats[i];
 
@@ -433,28 +63,6 @@ static const struct csid_format *csid_get_fmt_entry(
 	return &formats[0];
 }
 
-/*
- * csid_isr - CSID module interrupt handler
- * @irq: Interrupt line
- * @dev: CSID device
- *
- * Return IRQ_HANDLED on success
- */
-static irqreturn_t csid_isr(int irq, void *dev)
-{
-	struct csid_device *csid = dev;
-	enum camss_version ver = csid->camss->version;
-	u32 value;
-
-	value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver));
-	writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver));
-
-	if ((value >> 11) & 0x1)
-		complete(&csid->reset_complete);
-
-	return IRQ_HANDLED;
-}
-
 /*
  * csid_set_clock_rates - Calculate and set clock rates on CSID module
  * @csiphy: CSID device
@@ -521,31 +129,6 @@ static int csid_set_clock_rates(struct csid_device *csid)
 	return 0;
 }
 
-/*
- * csid_reset - Trigger reset on CSID module and wait to complete
- * @csid: CSID device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int csid_reset(struct csid_device *csid)
-{
-	unsigned long time;
-
-	reinit_completion(&csid->reset_complete);
-
-	writel_relaxed(0x7fff, csid->base +
-		       CAMSS_CSID_RST_CMD(csid->camss->version));
-
-	time = wait_for_completion_timeout(&csid->reset_complete,
-		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
-	if (!time) {
-		dev_err(csid->camss->dev, "CSID reset timeout\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
 /*
  * csid_set_power - Power on/off CSID module
  * @sd: CSID V4L2 subdevice
@@ -560,8 +143,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 	int ret;
 
 	if (on) {
-		u32 hw_version;
-
 		ret = pm_runtime_get_sync(dev);
 		if (ret < 0) {
 			pm_runtime_put_sync(dev);
@@ -590,7 +171,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 
 		enable_irq(csid->irq);
 
-		ret = csid_reset(csid);
+		ret = csid->ops->reset(csid);
 		if (ret < 0) {
 			disable_irq(csid->irq);
 			camss_disable_clocks(csid->nclocks, csid->clock);
@@ -599,8 +180,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 			return ret;
 		}
 
-		hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
-		dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version);
+		csid->ops->hw_version(csid);
 	} else {
 		disable_irq(csid->irq);
 		camss_disable_clocks(csid->nclocks, csid->clock);
@@ -623,16 +203,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct csid_device *csid = v4l2_get_subdevdata(sd);
-	struct csid_testgen_config *tg = &csid->testgen;
-	enum camss_version ver = csid->camss->version;
-	u32 val;
+	int ret;
 
 	if (enable) {
-		u8 vc = 0; /* Virtual Channel 0 */
-		u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
-		u8 dt, dt_shift, df;
-		int ret;
-
 		ret = v4l2_ctrl_handler_setup(&csid->ctrls);
 		if (ret < 0) {
 			dev_err(csid->camss->dev,
@@ -640,116 +213,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
 			return ret;
 		}
 
-		if (!tg->enabled &&
+		if (!csid->testgen.enabled &&
 		    !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
 			return -ENOLINK;
-
-		if (tg->enabled) {
-			/* Config Test Generator */
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SRC];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			u32 num_bytes_per_line =
-				f->width * format->bpp * format->spp / 8;
-			u32 num_lines = f->height;
-
-			/* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
-			/* 1:0 VC */
-			val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
-			      ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_VC_CFG(ver));
-
-			/* 28:16 bytes per lines, 12:0 num of lines */
-			val = ((num_bytes_per_line & 0x1fff) << 16) |
-			      (num_lines & 0x1fff);
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_0(ver, 0));
-
-			dt = format->data_type;
-
-			/* 5:0 data type */
-			val = dt;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_1(ver, 0));
-
-			/* 2:0 output test pattern */
-			val = tg->payload_mode;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_DT_n_CGG_2(ver, 0));
-
-			df = format->decode_format;
-		} else {
-			struct v4l2_mbus_framefmt *f =
-					&csid->fmt[MSM_CSID_PAD_SINK];
-			const struct csid_format *format = csid_get_fmt_entry(
-					csid->formats, csid->nformats, f->code);
-			struct csid_phy_config *phy = &csid->phy;
-
-			val = phy->lane_cnt - 1;
-			val |= phy->lane_assign << 4;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_0);
-
-			val = phy->csiphy_id << 17;
-			val |= 0x9;
-
-			writel_relaxed(val,
-				       csid->base + CAMSS_CSID_CORE_CTRL_1);
-
-			dt = format->data_type;
-			df = format->decode_format;
-		}
-
-		/* Config LUT */
-
-		dt_shift = (cid % 4) * 8;
-
-		val = readl_relaxed(csid->base +
-				    CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-		val &= ~(0xff << dt_shift);
-		val |= dt << dt_shift;
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_LUT_VC_n(ver, vc));
-
-		val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
-		val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
-		val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
-
-		if (csid->camss->version == CAMSS_8x96 ||
-		    csid->camss->version == CAMSS_660) {
-			u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
-			u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
-
-			if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) ||
-			    (sink_code == MEDIA_BUS_FMT_Y10_1X10 &&
-			     src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) {
-				val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16;
-				val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB;
-			}
-		}
-
-		writel_relaxed(val, csid->base +
-			       CAMSS_CSID_CID_n_CFG(ver, cid));
-
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_ENABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
-	} else {
-		if (tg->enabled) {
-			val = CAMSS_CSID_TG_CTRL_DISABLE;
-			writel_relaxed(val, csid->base +
-				       CAMSS_CSID_TG_CTRL(ver));
-		}
 	}
 
+	csid->ops->configure_stream(csid, enable);
+
 	return 0;
 }
 
@@ -818,7 +288,7 @@ static void csid_try_format(struct csid_device *csid,
 
 			*fmt = *__csid_get_format(csid, cfg,
 						      MSM_CSID_PAD_SINK, which);
-			fmt->code = csid_src_pad_code(csid, fmt->code, 0, code);
+			fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
 		} else {
 			/* Test generator is enabled, set format on source */
 			/* pad to allow test generator usage */
@@ -868,7 +338,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
 						     MSM_CSID_PAD_SINK,
 						     code->which);
 
-			code->code = csid_src_pad_code(csid, sink_fmt->code,
+			code->code = csid->ops->src_pad_code(csid, sink_fmt->code,
 						       code->index, 0);
 			if (!code->code)
 				return -EINVAL;
@@ -1004,15 +474,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	return csid_set_format(sd, fh ? fh->pad : NULL, &format);
 }
 
-static const char * const csid_test_pattern_menu[] = {
-	"Disabled",
-	"Incrementing",
-	"Alternating 0x55/0xAA",
-	"All Zeros 0x00",
-	"All Ones 0xFF",
-	"Pseudo-random Data",
-};
-
 /*
  * csid_set_test_pattern - Set test generator's pattern mode
  * @csid: CSID device
@@ -1030,25 +491,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)
 
 	tg->enabled = !!value;
 
-	switch (value) {
-	case 1:
-		tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING;
-		break;
-	case 2:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA;
-		break;
-	case 3:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES;
-		break;
-	case 4:
-		tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES;
-		break;
-	case 5:
-		tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM;
-		break;
-	}
-
-	return 0;
+	return csid->ops->configure_testgen_pattern(csid, value);
 }
 
 /*
@@ -1097,17 +540,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->id = id;
 
 	if (camss->version == CAMSS_8x16) {
-		csid->formats = csid_formats_8x16;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x16);
+		csid->ops = &csid_ops_4_1;
 	} else if (camss->version == CAMSS_8x96 ||
 		   camss->version == CAMSS_660) {
-		csid->formats = csid_formats_8x96;
-		csid->nformats =
-				ARRAY_SIZE(csid_formats_8x96);
+		csid->ops = &csid_ops_4_7;
 	} else {
 		return -EINVAL;
 	}
+	csid->ops->subdev_init(csid);
 
 	/* Memory */
 
@@ -1130,7 +570,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	csid->irq = r->start;
 	snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
 		 dev_name(dev), MSM_CSID_NAME, csid->id);
-	ret = devm_request_irq(dev, csid->irq, csid_isr,
+	ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
 		IRQF_TRIGGER_RISING, csid->irq_name, csid);
 	if (ret < 0) {
 		dev_err(dev, "request_irq failed: %d\n", ret);
@@ -1341,8 +781,8 @@ int msm_csid_register_entity(struct csid_device *csid,
 
 	csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls,
 				&csid_ctrl_ops, V4L2_CID_TEST_PATTERN,
-				ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0,
-				csid_test_pattern_menu);
+				csid->testgen.nmodes, 0, 0,
+				csid->testgen.modes);
 
 	if (csid->ctrls.error) {
 		dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error);
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 02fc34ee8a41..bcc8bdb6e0ad 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -70,19 +70,50 @@
 #define PLAIN_FORMAT_PLAIN16	0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */
 #define PLAIN_FORMAT_PLAIN32	0x2 /* supports UNCOMPRESSED_20_BIT */
 
+#define CSID_RESET_TIMEOUT_MS 500
 
-enum csid_payload_mode {
+
+enum csid_testgen_mode {
 	CSID_PAYLOAD_MODE_INCREMENTING = 0,
 	CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1,
 	CSID_PAYLOAD_MODE_ALL_ZEROES = 2,
 	CSID_PAYLOAD_MODE_ALL_ONES = 3,
 	CSID_PAYLOAD_MODE_RANDOM = 4,
 	CSID_PAYLOAD_MODE_USER_SPECIFIED = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_1 = 5,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_4_7 = 5,
+	CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 6,
+	CSID_PAYLOAD_MODE_COLOR_BOX = 7,
+	CSID_PAYLOAD_MODE_COLOR_BARS = 8,
+	CSID_PAYLOAD_MODE_MAX_SUPPORTED_170 = 8,
+};
+
+static const char * const csid_testgen_modes[] = {
+	"Disabled",
+	"Incrementing",
+	"Alternating 0x55/0xAA",
+	"All Zeros 0x00",
+	"All Ones 0xFF",
+	"Pseudo-random Data",
+	"User Specified",
+	"Complex pattern",
+	"Color box",
+	"Color bars",
+};
+
+struct csid_format {
+	u32 code;
+	u8 data_type;
+	u8 decode_format;
+	u8 bpp;
+	u8 spp; /* bus samples per pixel */
 };
 
 struct csid_testgen_config {
+	enum csid_testgen_mode mode;
+	const char * const*modes;
+	u8 nmodes;
 	u8 enabled;
-	enum csid_payload_mode payload_mode;
 };
 
 struct csid_phy_config {
@@ -91,6 +122,65 @@ struct csid_phy_config {
 	u32 lane_assign;
 };
 
+struct csid_device;
+
+struct csid_hw_ops {
+	/*
+	 * configure_stream - Configures and starts CSID input stream
+	 * @csid: CSID device
+	 */
+	void (*configure_stream)(struct csid_device *csid, u8 enable);
+
+	/*
+	 * configure_testgen_pattern - Validates and configures output pattern mode
+	 * of test pattern generator
+	 * @csid: CSID device
+	 */
+	int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);
+
+	/*
+	 * hw_version - Read hardware version register from hardware
+	 * @csid: CSID device
+	 */
+	u32 (*hw_version)(struct csid_device *csid);
+
+	/*
+	 * isr - CSID module interrupt service routine
+	 * @irq: Interrupt line
+	 * @dev: CSID device
+	 *
+	 * Return IRQ_HANDLED on success
+	 */
+	irqreturn_t (*isr)(int irq, void *dev);
+
+	/*
+	 * reset - Trigger reset on CSID module and wait to complete
+	 * @csid: CSID device
+	 *
+	 * Return 0 on success or a negative error code otherwise
+	 */
+	int (*reset)(struct csid_device *csid);
+
+	/*
+	 * src_pad_code - Pick an output/src format based on the input/sink format
+	 * @csid: CSID device
+	 * @sink_code: The sink format of the input
+	 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.
+	 *	Set @match_code to 0 if used.
+	 * @match_code: Request preferred code, set @match_format_idx to 0 if used
+	 *
+	 * Return 0 on failure or src format code otherwise
+	 */
+	u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
+			    unsigned int match_format_idx, u32 match_code);
+
+	/*
+	 * subdev_init - Initialize CSID device according for hardware revision
+	 * @csid: CSID device
+	 */
+	void (*subdev_init)(struct csid_device *csid);
+};
+
 struct csid_device {
 	struct camss *camss;
 	u8 id;
@@ -110,10 +200,37 @@ struct csid_device {
 	struct v4l2_ctrl *testgen_mode;
 	const struct csid_format *formats;
 	unsigned int nformats;
+	const struct csid_hw_ops *ops;
 };
 
 struct resources;
 
+
+/*
+ * csid_find_code - Find a format code in an array using array index or format code
+ * @codes: Array of format codes
+ * @ncodes: Length of @code array
+ * @req_format_idx: Request preferred index, as defined by subdevice csid_format.
+ *	Set @match_code to 0 if used.
+ * @match_code: Request preferred code, set @req_format_idx to 0 if used
+ *
+ * Return 0 on failure or format code otherwise
+ */
+u32 csid_find_code(u32 *codes, unsigned int ncode,
+		   unsigned int match_format_idx, u32 match_code);
+
+/*
+ * csid_get_fmt_entry - Find csid_format entry with matching format code
+ * @formats: Array of format csid_format entries
+ * @nformats: Length of @nformats array
+ * @code: Desired format code
+ *
+ * Return formats[0] on failure to find code
+ */
+const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
+					     unsigned int nformats,
+					     u32 code);
+
 int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 			 const struct resources *res, u8 id);
 
@@ -124,4 +241,8 @@ void msm_csid_unregister_entity(struct csid_device *csid);
 
 void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
 
+
+extern const struct csid_hw_ops csid_ops_4_1;
+extern const struct csid_hw_ops csid_ops_4_7;
+
 #endif /* QC_MSM_CAMSS_CSID_H */
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 09/17] media: camss: Add support for CSID hardware version Titan 170
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add register definitions for version 170 of the Titan architecture
and implement support for the CSID subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   1 +
 .../platform/qcom/camss/camss-csid-170.c      | 602 ++++++++++++++++++
 .../media/platform/qcom/camss/camss-csid.c    |   4 +
 .../media/platform/qcom/camss/camss-csid.h    |   2 +
 drivers/media/platform/qcom/camss/camss.c     |  62 ++
 5 files changed, 671 insertions(+)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-170.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index cff388b653ba..0752c46ea37b 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -6,6 +6,7 @@ qcom-camss-objs += \
 		camss-csid.o \
 		camss-csid-4-1.o \
 		camss-csid-4-7.o \
+		camss-csid-170.o \
 		camss-csiphy-2ph-1-0.o \
 		camss-csiphy-3ph-1-0.o \
 		camss-csiphy.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-170.c b/drivers/media/platform/qcom/camss/camss-csid-170.c
new file mode 100644
index 000000000000..0e9b08ed38c2
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-170.c
@@ -0,0 +1,602 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+/* The CSID 2 IP-block is different from the others,
+ * and is of a bare-bones Lite version, with no PIX
+ * interface support. As a result of that it has an
+ * alternate register layout.
+ */
+#define IS_LITE		(csid->id == 2 ? 1 : 0)
+
+#define CSID_HW_VERSION		0x0
+#define		HW_VERSION_STEPPING	0
+#define		HW_VERSION_REVISION	16
+#define		HW_VERSION_GENERATION	28
+
+#define CSID_RST_STROBES	0x10
+#define		RST_STROBES	0
+
+#define CSID_CSI2_RX_IRQ_STATUS	0x20
+#define	CSID_CSI2_RX_IRQ_MASK	0x24
+#define CSID_CSI2_RX_IRQ_CLEAR	0x28
+
+#define CSID_CSI2_RDIN_IRQ_STATUS(rdi)		((IS_LITE ? 0x30 : 0x40) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_MASK(rdi)		((IS_LITE ? 0x34 : 0x44) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi)		((IS_LITE ? 0x38 : 0x48) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_SET(rdi)		((IS_LITE ? 0x3C : 0x4C) \
+						 + 0x10 * (rdi))
+
+#define CSID_TOP_IRQ_STATUS	0x70
+#define		TOP_IRQ_STATUS_RESET_DONE 0
+#define CSID_TOP_IRQ_MASK	0x74
+#define CSID_TOP_IRQ_CLEAR	0x78
+#define CSID_TOP_IRQ_SET	0x7C
+#define CSID_IRQ_CMD		0x80
+#define		IRQ_CMD_CLEAR	0
+#define		IRQ_CMD_SET	4
+
+#define CSID_CSI2_RX_CFG0	0x100
+#define		CSI2_RX_CFG0_NUM_ACTIVE_LANES	0
+#define		CSI2_RX_CFG0_DL0_INPUT_SEL	4
+#define		CSI2_RX_CFG0_DL1_INPUT_SEL	8
+#define		CSI2_RX_CFG0_DL2_INPUT_SEL	12
+#define		CSI2_RX_CFG0_DL3_INPUT_SEL	16
+#define		CSI2_RX_CFG0_PHY_NUM_SEL	20
+#define		CSI2_RX_CFG0_PHY_TYPE_SEL	24
+
+#define CSID_CSI2_RX_CFG1	0x104
+#define		CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN		0
+#define		CSI2_RX_CFG1_DE_SCRAMBLE_EN			1
+#define		CSI2_RX_CFG1_VC_MODE				2
+#define		CSI2_RX_CFG1_COMPLETE_STREAM_EN			4
+#define		CSI2_RX_CFG1_COMPLETE_STREAM_FRAME_TIMING	5
+#define		CSI2_RX_CFG1_MISR_EN				6
+#define		CSI2_RX_CFG1_CGC_MODE				7
+#define			CGC_MODE_DYNAMIC_GATING		0
+#define			CGC_MODE_ALWAYS_ON		1
+
+#define CSID_RDI_CFG0(rdi)			((IS_LITE ? 0x200 : 0x300) \
+						 + 0x100 * (rdi))
+#define		RDI_CFG0_BYTE_CNTR_EN		0
+#define		RDI_CFG0_FORMAT_MEASURE_EN	1
+#define		RDI_CFG0_TIMESTAMP_EN		2
+#define		RDI_CFG0_DROP_H_EN		3
+#define		RDI_CFG0_DROP_V_EN		4
+#define		RDI_CFG0_CROP_H_EN		5
+#define		RDI_CFG0_CROP_V_EN		6
+#define		RDI_CFG0_MISR_EN		7
+#define		RDI_CFG0_CGC_MODE		8
+#define			CGC_MODE_DYNAMIC	0
+#define			CGC_MODE_ALWAYS_ON	1
+#define		RDI_CFG0_PLAIN_ALIGNMENT	9
+#define			PLAIN_ALIGNMENT_LSB	0
+#define			PLAIN_ALIGNMENT_MSB	1
+#define		RDI_CFG0_PLAIN_FORMAT		10
+#define		RDI_CFG0_DECODE_FORMAT		12
+#define		RDI_CFG0_DATA_TYPE		16
+#define		RDI_CFG0_VIRTUAL_CHANNEL	22
+#define		RDI_CFG0_DT_ID			27
+#define		RDI_CFG0_EARLY_EOF_EN		29
+#define		RDI_CFG0_PACKING_FORMAT		30
+#define		RDI_CFG0_ENABLE			31
+
+#define CSID_RDI_CFG1(rdi)			((IS_LITE ? 0x204 : 0x304)\
+						+ 0x100 * (rdi))
+#define		RDI_CFG1_TIMESTAMP_STB_SEL	0
+
+#define CSID_RDI_CTRL(rdi)			((IS_LITE ? 0x208 : 0x308)\
+						+ 0x100 * (rdi))
+#define		RDI_CTRL_HALT_CMD		0
+#define			ALT_CMD_RESUME_AT_FRAME_BOUNDARY	1
+#define		RDI_CTRL_HALT_MODE		2
+
+#define CSID_RDI_FRM_DROP_PATTERN(rdi)			((IS_LITE ? 0x20C : 0x30C)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_FRM_DROP_PERIOD(rdi)			((IS_LITE ? 0x210 : 0x310)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi)		((IS_LITE ? 0x214 : 0x314)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi)		((IS_LITE ? 0x218 : 0x318)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi)		((IS_LITE ? 0x224 : 0x324)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi)		((IS_LITE ? 0x228 : 0x328)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi)		((IS_LITE ? 0x22C : 0x32C)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi)		((IS_LITE ? 0x230 : 0x330)\
+							+ 0x100 * (rdi))
+
+#define CSID_TPG_CTRL		0x600
+#define		TPG_CTRL_TEST_EN		0
+#define		TPG_CTRL_FS_PKT_EN		1
+#define		TPG_CTRL_FE_PKT_EN		2
+#define		TPG_CTRL_NUM_ACTIVE_LANES	4
+#define		TPG_CTRL_CYCLES_BETWEEN_PKTS	8
+#define		TPG_CTRL_NUM_TRAIL_BYTES	20
+
+#define CSID_TPG_VC_CFG0	0x604
+#define		TPG_VC_CFG0_VC_NUM			0
+#define		TPG_VC_CFG0_NUM_ACTIVE_SLOTS		8
+#define			NUM_ACTIVE_SLOTS_0_ENABLED	0
+#define			NUM_ACTIVE_SLOTS_0_1_ENABLED	1
+#define			NUM_ACTIVE_SLOTS_0_1_2_ENABLED	2
+#define			NUM_ACTIVE_SLOTS_0_1_3_ENABLED	3
+#define		TPG_VC_CFG0_LINE_INTERLEAVING_MODE	10
+#define			INTELEAVING_MODE_INTERLEAVED	0
+#define			INTELEAVING_MODE_ONE_SHOT	1
+#define		TPG_VC_CFG0_NUM_FRAMES			16
+
+#define CSID_TPG_VC_CFG1	0x608
+#define		TPG_VC_CFG1_H_BLANKING_COUNT		0
+#define		TPG_VC_CFG1_V_BLANKING_COUNT		12
+#define		TPG_VC_CFG1_V_BLANK_FRAME_WIDTH_SEL	24
+
+#define CSID_TPG_LFSR_SEED	0x60C
+
+#define CSID_TPG_DT_n_CFG_0(n)	(0x610 + (n) * 0xC)
+#define		TPG_DT_n_CFG_0_FRAME_HEIGHT	0
+#define		TPG_DT_n_CFG_0_FRAME_WIDTH	16
+
+#define CSID_TPG_DT_n_CFG_1(n)	(0x614 + (n) * 0xC)
+#define		TPG_DT_n_CFG_1_DATA_TYPE	0
+#define		TPG_DT_n_CFG_1_ECC_XOR_MASK	8
+#define		TPG_DT_n_CFG_1_CRC_XOR_MASK	16
+
+#define CSID_TPG_DT_n_CFG_2(n)	(0x618 + (n) * 0xC)
+#define		TPG_DT_n_CFG_2_PAYLOAD_MODE		0
+#define		TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD	4
+#define		TPG_DT_n_CFG_2_ENCODE_FORMAT		16
+
+#define CSID_TPG_COLOR_BARS_CFG	0x640
+#define		TPG_COLOR_BARS_CFG_UNICOLOR_BAR_EN	0
+#define		TPG_COLOR_BARS_CFG_UNICOLOR_BAR_SEL	4
+#define		TPG_COLOR_BARS_CFG_SPLIT_EN		5
+#define		TPG_COLOR_BARS_CFG_ROTATE_PERIOD	8
+
+#define CSID_TPG_COLOR_BOX_CFG	0x644
+#define		TPG_COLOR_BOX_CFG_MODE		0
+#define		TPG_COLOR_BOX_PATTERN_SEL	2
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 val;
+	u32 phy_sel = 0;
+	u8 lane_cnt = csid->phy.lane_cnt;
+	struct v4l2_mbus_framefmt *input_format =
+			&csid->fmt[MSM_CSID_PAD_SRC];
+	const struct csid_format *format = csid_get_fmt_entry(
+			csid->formats, csid->nformats, input_format->code);
+	if (!lane_cnt)
+		lane_cnt = 4;
+
+	if (!tg->enabled)
+		phy_sel = csid->phy.csiphy_id;
+
+	if (enable) {
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 dt_id = vc * 4;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			vc = 0xa;
+
+			/* configure one DT, infinite frames */
+			val = vc << TPG_VC_CFG0_VC_NUM;
+			val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE;
+			val |= 0 << TPG_VC_CFG0_NUM_FRAMES;
+			writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0);
+
+			val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT;
+			val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT;
+			writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1);
+
+			writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED);
+
+			val = input_format->height & 0x1fff << TPG_DT_n_CFG_0_FRAME_HEIGHT;
+			val |= input_format->width & 0x1fff << TPG_DT_n_CFG_0_FRAME_WIDTH;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0));
+
+			val = DATA_TYPE_RAW_10BIT << TPG_DT_n_CFG_1_DATA_TYPE;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0));
+
+			val = tg->mode << TPG_DT_n_CFG_2_PAYLOAD_MODE;
+			val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD;
+			val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0));
+
+			writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG);
+
+			writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG);
+		}
+
+		val = 1 << RDI_CFG0_BYTE_CNTR_EN;
+		val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN;
+		val |= 1 << RDI_CFG0_TIMESTAMP_EN;
+		val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
+		val |= DATA_TYPE_RAW_10BIT << RDI_CFG0_DATA_TYPE;
+		val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
+		val |= dt_id << RDI_CFG0_DT_ID;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+
+		/* CSID_TIMESTAMP_STB_POST_IRQ */
+		val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG1(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(0, csid->base + CSID_RDI_FRM_DROP_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+
+		val = readl_relaxed(csid->base + CSID_RDI_CFG0(0));
+		val |=  1 << RDI_CFG0_ENABLE;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+	}
+
+	if (tg->enabled) {
+		val = enable << TPG_CTRL_TEST_EN;
+		val |= 1 << TPG_CTRL_FS_PKT_EN;
+		val |= 1 << TPG_CTRL_FE_PKT_EN;
+		val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES;
+		val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS;
+		val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES;
+		writel_relaxed(val, csid->base + CSID_TPG_CTRL);
+	}
+
+	val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
+	val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
+	val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL;
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0);
+
+
+	val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
+	val |= 1 << CSI2_RX_CFG1_MISR_EN;
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); // csi2_vc_mode_shift_val ?
+
+	/* error irqs start at BIT(11) */
+	writel_relaxed(~0u, csid->base + CSID_CSI2_RX_IRQ_MASK);
+
+	/* RDI irq */
+	writel_relaxed(~0u, csid->base + CSID_TOP_IRQ_MASK);
+
+	val = 1 << RDI_CTRL_HALT_CMD;
+	writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_170)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+/*
+ * csid_hw_version - CSID hardware version query
+ * @csid: CSID device
+ *
+ * Return HW version or error
+ */
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version;
+	u32 hw_gen;
+	u32 hw_rev;
+	u32 hw_step;
+
+	hw_version = readl_relaxed(csid->base + CSID_HW_VERSION);
+	hw_gen = (hw_version >> HW_VERSION_GENERATION) & 0xF;
+	hw_rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF;
+	hw_step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF;
+	dev_dbg(csid->camss->dev, "CSID HW Version = %u.%u.%u\n",
+		hw_gen, hw_rev, hw_step);
+
+	return hw_version;
+}
+
+/*
+ * csid_isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 val;
+	u8 reset_done;
+
+	val = readl_relaxed(csid->base + CSID_TOP_IRQ_STATUS);
+	writel_relaxed(val, csid->base + CSID_TOP_IRQ_CLEAR);
+	reset_done = val & BIT(TOP_IRQ_STATUS_RESET_DONE);
+
+	val = readl_relaxed(csid->base + CSID_CSI2_RX_IRQ_STATUS);
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR);
+
+	val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(0));
+	writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(0));
+
+	val = 1 << IRQ_CMD_CLEAR;
+	writel_relaxed(val, csid->base + CSID_IRQ_CMD);
+
+	if (reset_done)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+	u32 val;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(1, csid->base + CSID_TOP_IRQ_CLEAR);
+	writel_relaxed(1, csid->base + CSID_IRQ_CMD);
+	writel_relaxed(1, csid->base + CSID_TOP_IRQ_MASK);
+	writel_relaxed(1, csid->base + CSID_IRQ_CMD);
+
+	/* preserve registers */
+	val = 0x1e << RST_STROBES;
+	writel_relaxed(val, csid->base + CSID_RST_STROBES);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	switch (sink_code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_SBGGR10_1X10,
+			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	case MEDIA_BUS_FMT_Y10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_Y10_1X10,
+			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	default:
+		if (match_format_idx > 0)
+			return 0;
+
+		return sink_code;
+	}
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_170;
+}
+
+const struct csid_hw_ops csid_ops_170 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 601bd810f2b0..294a0a9e4dfa 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -123,6 +123,8 @@ static int csid_set_clock_rates(struct csid_device *csid)
 				dev_err(dev, "clk set rate failed: %d\n", ret);
 				return ret;
 			}
+		} else if (clock->nfreqs) {
+			clk_set_rate(clock->clk, clock->freq[0]);
 		}
 	}
 
@@ -544,6 +546,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	} else if (camss->version == CAMSS_8x96 ||
 		   camss->version == CAMSS_660) {
 		csid->ops = &csid_ops_4_7;
+	} else if (camss->version == CAMSS_845) {
+		csid->ops = &csid_ops_170;
 	} else {
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index bcc8bdb6e0ad..fe9182ff73aa 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -244,5 +244,7 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
 
 extern const struct csid_hw_ops csid_ops_4_1;
 extern const struct csid_hw_ops csid_ops_4_7;
+extern const struct csid_hw_ops csid_ops_170;
+
 
 #endif /* QC_MSM_CAMSS_CSID_H */
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 1c3d64d612ff..a4fd8c32bfd8 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,68 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources csid_res_845[] = {
+	/* CSID0 */
+	{
+		.regulator = { "vdda-csi0" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe0", "vfe0_src",
+				"vfe0_cphy_rx", "csi0",
+				"csi0_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid0" },
+		.interrupt = { "csid0" }
+	},
+
+	/* CSID1 */
+	{
+		.regulator = { "vdda-csi1" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe1", "vfe1_src",
+				"vfe1_cphy_rx", "csi1",
+				"csi1_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid1" },
+		.interrupt = { "csid1" }
+	},
+
+	/* CSID2 */
+	{
+		.regulator = { "vdda-csi2" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe_lite", "vfe_lite_src",
+				"vfe_lite_cphy_rx", "csi2",
+				"csi2_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid2" },
+		.interrupt = { "csid2" }
+	}
+};
+
 static const struct resources vfe_res_845[] = {
 	/* VFE0 */
 	{
-- 
2.27.0


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

* [PATCH v1 09/17] media: camss: Add support for CSID hardware version Titan 170
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add register definitions for version 170 of the Titan architecture
and implement support for the CSID subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/Makefile    |   1 +
 .../platform/qcom/camss/camss-csid-170.c      | 602 ++++++++++++++++++
 .../media/platform/qcom/camss/camss-csid.c    |   4 +
 .../media/platform/qcom/camss/camss-csid.h    |   2 +
 drivers/media/platform/qcom/camss/camss.c     |  62 ++
 5 files changed, 671 insertions(+)
 create mode 100644 drivers/media/platform/qcom/camss/camss-csid-170.c

diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index cff388b653ba..0752c46ea37b 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -6,6 +6,7 @@ qcom-camss-objs += \
 		camss-csid.o \
 		camss-csid-4-1.o \
 		camss-csid-4-7.o \
+		camss-csid-170.o \
 		camss-csiphy-2ph-1-0.o \
 		camss-csiphy-3ph-1-0.o \
 		camss-csiphy.o \
diff --git a/drivers/media/platform/qcom/camss/camss-csid-170.c b/drivers/media/platform/qcom/camss/camss-csid-170.c
new file mode 100644
index 000000000000..0e9b08ed38c2
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-csid-170.c
@@ -0,0 +1,602 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-csid-4-7.c
+ *
+ * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include "camss-csid.h"
+#include "camss.h"
+
+/* The CSID 2 IP-block is different from the others,
+ * and is of a bare-bones Lite version, with no PIX
+ * interface support. As a result of that it has an
+ * alternate register layout.
+ */
+#define IS_LITE		(csid->id == 2 ? 1 : 0)
+
+#define CSID_HW_VERSION		0x0
+#define		HW_VERSION_STEPPING	0
+#define		HW_VERSION_REVISION	16
+#define		HW_VERSION_GENERATION	28
+
+#define CSID_RST_STROBES	0x10
+#define		RST_STROBES	0
+
+#define CSID_CSI2_RX_IRQ_STATUS	0x20
+#define	CSID_CSI2_RX_IRQ_MASK	0x24
+#define CSID_CSI2_RX_IRQ_CLEAR	0x28
+
+#define CSID_CSI2_RDIN_IRQ_STATUS(rdi)		((IS_LITE ? 0x30 : 0x40) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_MASK(rdi)		((IS_LITE ? 0x34 : 0x44) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi)		((IS_LITE ? 0x38 : 0x48) \
+						 + 0x10 * (rdi))
+#define CSID_CSI2_RDIN_IRQ_SET(rdi)		((IS_LITE ? 0x3C : 0x4C) \
+						 + 0x10 * (rdi))
+
+#define CSID_TOP_IRQ_STATUS	0x70
+#define		TOP_IRQ_STATUS_RESET_DONE 0
+#define CSID_TOP_IRQ_MASK	0x74
+#define CSID_TOP_IRQ_CLEAR	0x78
+#define CSID_TOP_IRQ_SET	0x7C
+#define CSID_IRQ_CMD		0x80
+#define		IRQ_CMD_CLEAR	0
+#define		IRQ_CMD_SET	4
+
+#define CSID_CSI2_RX_CFG0	0x100
+#define		CSI2_RX_CFG0_NUM_ACTIVE_LANES	0
+#define		CSI2_RX_CFG0_DL0_INPUT_SEL	4
+#define		CSI2_RX_CFG0_DL1_INPUT_SEL	8
+#define		CSI2_RX_CFG0_DL2_INPUT_SEL	12
+#define		CSI2_RX_CFG0_DL3_INPUT_SEL	16
+#define		CSI2_RX_CFG0_PHY_NUM_SEL	20
+#define		CSI2_RX_CFG0_PHY_TYPE_SEL	24
+
+#define CSID_CSI2_RX_CFG1	0x104
+#define		CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN		0
+#define		CSI2_RX_CFG1_DE_SCRAMBLE_EN			1
+#define		CSI2_RX_CFG1_VC_MODE				2
+#define		CSI2_RX_CFG1_COMPLETE_STREAM_EN			4
+#define		CSI2_RX_CFG1_COMPLETE_STREAM_FRAME_TIMING	5
+#define		CSI2_RX_CFG1_MISR_EN				6
+#define		CSI2_RX_CFG1_CGC_MODE				7
+#define			CGC_MODE_DYNAMIC_GATING		0
+#define			CGC_MODE_ALWAYS_ON		1
+
+#define CSID_RDI_CFG0(rdi)			((IS_LITE ? 0x200 : 0x300) \
+						 + 0x100 * (rdi))
+#define		RDI_CFG0_BYTE_CNTR_EN		0
+#define		RDI_CFG0_FORMAT_MEASURE_EN	1
+#define		RDI_CFG0_TIMESTAMP_EN		2
+#define		RDI_CFG0_DROP_H_EN		3
+#define		RDI_CFG0_DROP_V_EN		4
+#define		RDI_CFG0_CROP_H_EN		5
+#define		RDI_CFG0_CROP_V_EN		6
+#define		RDI_CFG0_MISR_EN		7
+#define		RDI_CFG0_CGC_MODE		8
+#define			CGC_MODE_DYNAMIC	0
+#define			CGC_MODE_ALWAYS_ON	1
+#define		RDI_CFG0_PLAIN_ALIGNMENT	9
+#define			PLAIN_ALIGNMENT_LSB	0
+#define			PLAIN_ALIGNMENT_MSB	1
+#define		RDI_CFG0_PLAIN_FORMAT		10
+#define		RDI_CFG0_DECODE_FORMAT		12
+#define		RDI_CFG0_DATA_TYPE		16
+#define		RDI_CFG0_VIRTUAL_CHANNEL	22
+#define		RDI_CFG0_DT_ID			27
+#define		RDI_CFG0_EARLY_EOF_EN		29
+#define		RDI_CFG0_PACKING_FORMAT		30
+#define		RDI_CFG0_ENABLE			31
+
+#define CSID_RDI_CFG1(rdi)			((IS_LITE ? 0x204 : 0x304)\
+						+ 0x100 * (rdi))
+#define		RDI_CFG1_TIMESTAMP_STB_SEL	0
+
+#define CSID_RDI_CTRL(rdi)			((IS_LITE ? 0x208 : 0x308)\
+						+ 0x100 * (rdi))
+#define		RDI_CTRL_HALT_CMD		0
+#define			ALT_CMD_RESUME_AT_FRAME_BOUNDARY	1
+#define		RDI_CTRL_HALT_MODE		2
+
+#define CSID_RDI_FRM_DROP_PATTERN(rdi)			((IS_LITE ? 0x20C : 0x30C)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_FRM_DROP_PERIOD(rdi)			((IS_LITE ? 0x210 : 0x310)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi)		((IS_LITE ? 0x214 : 0x314)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi)		((IS_LITE ? 0x218 : 0x318)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi)		((IS_LITE ? 0x224 : 0x324)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi)		((IS_LITE ? 0x228 : 0x328)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi)		((IS_LITE ? 0x22C : 0x32C)\
+							+ 0x100 * (rdi))
+#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi)		((IS_LITE ? 0x230 : 0x330)\
+							+ 0x100 * (rdi))
+
+#define CSID_TPG_CTRL		0x600
+#define		TPG_CTRL_TEST_EN		0
+#define		TPG_CTRL_FS_PKT_EN		1
+#define		TPG_CTRL_FE_PKT_EN		2
+#define		TPG_CTRL_NUM_ACTIVE_LANES	4
+#define		TPG_CTRL_CYCLES_BETWEEN_PKTS	8
+#define		TPG_CTRL_NUM_TRAIL_BYTES	20
+
+#define CSID_TPG_VC_CFG0	0x604
+#define		TPG_VC_CFG0_VC_NUM			0
+#define		TPG_VC_CFG0_NUM_ACTIVE_SLOTS		8
+#define			NUM_ACTIVE_SLOTS_0_ENABLED	0
+#define			NUM_ACTIVE_SLOTS_0_1_ENABLED	1
+#define			NUM_ACTIVE_SLOTS_0_1_2_ENABLED	2
+#define			NUM_ACTIVE_SLOTS_0_1_3_ENABLED	3
+#define		TPG_VC_CFG0_LINE_INTERLEAVING_MODE	10
+#define			INTELEAVING_MODE_INTERLEAVED	0
+#define			INTELEAVING_MODE_ONE_SHOT	1
+#define		TPG_VC_CFG0_NUM_FRAMES			16
+
+#define CSID_TPG_VC_CFG1	0x608
+#define		TPG_VC_CFG1_H_BLANKING_COUNT		0
+#define		TPG_VC_CFG1_V_BLANKING_COUNT		12
+#define		TPG_VC_CFG1_V_BLANK_FRAME_WIDTH_SEL	24
+
+#define CSID_TPG_LFSR_SEED	0x60C
+
+#define CSID_TPG_DT_n_CFG_0(n)	(0x610 + (n) * 0xC)
+#define		TPG_DT_n_CFG_0_FRAME_HEIGHT	0
+#define		TPG_DT_n_CFG_0_FRAME_WIDTH	16
+
+#define CSID_TPG_DT_n_CFG_1(n)	(0x614 + (n) * 0xC)
+#define		TPG_DT_n_CFG_1_DATA_TYPE	0
+#define		TPG_DT_n_CFG_1_ECC_XOR_MASK	8
+#define		TPG_DT_n_CFG_1_CRC_XOR_MASK	16
+
+#define CSID_TPG_DT_n_CFG_2(n)	(0x618 + (n) * 0xC)
+#define		TPG_DT_n_CFG_2_PAYLOAD_MODE		0
+#define		TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD	4
+#define		TPG_DT_n_CFG_2_ENCODE_FORMAT		16
+
+#define CSID_TPG_COLOR_BARS_CFG	0x640
+#define		TPG_COLOR_BARS_CFG_UNICOLOR_BAR_EN	0
+#define		TPG_COLOR_BARS_CFG_UNICOLOR_BAR_SEL	4
+#define		TPG_COLOR_BARS_CFG_SPLIT_EN		5
+#define		TPG_COLOR_BARS_CFG_ROTATE_PERIOD	8
+
+#define CSID_TPG_COLOR_BOX_CFG	0x644
+#define		TPG_COLOR_BOX_CFG_MODE		0
+#define		TPG_COLOR_BOX_PATTERN_SEL	2
+
+
+static const struct csid_format csid_formats[] = {
+	{
+		MEDIA_BUS_FMT_UYVY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_VYUY8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YUYV8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_YVYU8_2X8,
+		DATA_TYPE_YUV422_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		2,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB8_1X8,
+		DATA_TYPE_RAW_8BIT,
+		DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+		8,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_Y10_1X10,
+		DATA_TYPE_RAW_10BIT,
+		DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+		10,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB12_1X12,
+		DATA_TYPE_RAW_12BIT,
+		DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+		12,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SBGGR14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGBRG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SGRBG14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+	{
+		MEDIA_BUS_FMT_SRGGB14_1X14,
+		DATA_TYPE_RAW_14BIT,
+		DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+		14,
+		1,
+	},
+};
+
+static void csid_configure_stream(struct csid_device *csid, u8 enable)
+{
+	struct csid_testgen_config *tg = &csid->testgen;
+	u32 val;
+	u32 phy_sel = 0;
+	u8 lane_cnt = csid->phy.lane_cnt;
+	struct v4l2_mbus_framefmt *input_format =
+			&csid->fmt[MSM_CSID_PAD_SRC];
+	const struct csid_format *format = csid_get_fmt_entry(
+			csid->formats, csid->nformats, input_format->code);
+	if (!lane_cnt)
+		lane_cnt = 4;
+
+	if (!tg->enabled)
+		phy_sel = csid->phy.csiphy_id;
+
+	if (enable) {
+		u8 vc = 0; /* Virtual Channel 0 */
+		u8 dt_id = vc * 4;
+
+		if (tg->enabled) {
+			/* Config Test Generator */
+			vc = 0xa;
+
+			/* configure one DT, infinite frames */
+			val = vc << TPG_VC_CFG0_VC_NUM;
+			val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE;
+			val |= 0 << TPG_VC_CFG0_NUM_FRAMES;
+			writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0);
+
+			val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT;
+			val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT;
+			writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1);
+
+			writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED);
+
+			val = input_format->height & 0x1fff << TPG_DT_n_CFG_0_FRAME_HEIGHT;
+			val |= input_format->width & 0x1fff << TPG_DT_n_CFG_0_FRAME_WIDTH;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0));
+
+			val = DATA_TYPE_RAW_10BIT << TPG_DT_n_CFG_1_DATA_TYPE;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0));
+
+			val = tg->mode << TPG_DT_n_CFG_2_PAYLOAD_MODE;
+			val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD;
+			val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT;
+			writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0));
+
+			writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG);
+
+			writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG);
+		}
+
+		val = 1 << RDI_CFG0_BYTE_CNTR_EN;
+		val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN;
+		val |= 1 << RDI_CFG0_TIMESTAMP_EN;
+		val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
+		val |= DATA_TYPE_RAW_10BIT << RDI_CFG0_DATA_TYPE;
+		val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
+		val |= dt_id << RDI_CFG0_DT_ID;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+
+		/* CSID_TIMESTAMP_STB_POST_IRQ */
+		val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG1(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(0, csid->base + CSID_RDI_FRM_DROP_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(0));
+
+		val = 1;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(0));
+
+		val = 0;
+		writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+
+		val = readl_relaxed(csid->base + CSID_RDI_CFG0(0));
+		val |=  1 << RDI_CFG0_ENABLE;
+		writel_relaxed(val, csid->base + CSID_RDI_CFG0(0));
+	}
+
+	if (tg->enabled) {
+		val = enable << TPG_CTRL_TEST_EN;
+		val |= 1 << TPG_CTRL_FS_PKT_EN;
+		val |= 1 << TPG_CTRL_FE_PKT_EN;
+		val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES;
+		val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS;
+		val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES;
+		writel_relaxed(val, csid->base + CSID_TPG_CTRL);
+	}
+
+	val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
+	val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
+	val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL;
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0);
+
+
+	val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
+	val |= 1 << CSI2_RX_CFG1_MISR_EN;
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); // csi2_vc_mode_shift_val ?
+
+	/* error irqs start at BIT(11) */
+	writel_relaxed(~0u, csid->base + CSID_CSI2_RX_IRQ_MASK);
+
+	/* RDI irq */
+	writel_relaxed(~0u, csid->base + CSID_TOP_IRQ_MASK);
+
+	val = 1 << RDI_CTRL_HALT_CMD;
+	writel_relaxed(val, csid->base + CSID_RDI_CTRL(0));
+}
+
+static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
+{
+	s32 regval = val - 1;
+
+	if (regval > 0 || regval <= CSID_PAYLOAD_MODE_MAX_SUPPORTED_170)
+		csid->testgen.mode = regval;
+
+	return 0;
+}
+
+/*
+ * csid_hw_version - CSID hardware version query
+ * @csid: CSID device
+ *
+ * Return HW version or error
+ */
+static u32 csid_hw_version(struct csid_device *csid)
+{
+	u32 hw_version;
+	u32 hw_gen;
+	u32 hw_rev;
+	u32 hw_step;
+
+	hw_version = readl_relaxed(csid->base + CSID_HW_VERSION);
+	hw_gen = (hw_version >> HW_VERSION_GENERATION) & 0xF;
+	hw_rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF;
+	hw_step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF;
+	dev_dbg(csid->camss->dev, "CSID HW Version = %u.%u.%u\n",
+		hw_gen, hw_rev, hw_step);
+
+	return hw_version;
+}
+
+/*
+ * csid_isr - CSID module interrupt service routine
+ * @irq: Interrupt line
+ * @dev: CSID device
+ *
+ * Return IRQ_HANDLED on success
+ */
+static irqreturn_t csid_isr(int irq, void *dev)
+{
+	struct csid_device *csid = dev;
+	u32 val;
+	u8 reset_done;
+
+	val = readl_relaxed(csid->base + CSID_TOP_IRQ_STATUS);
+	writel_relaxed(val, csid->base + CSID_TOP_IRQ_CLEAR);
+	reset_done = val & BIT(TOP_IRQ_STATUS_RESET_DONE);
+
+	val = readl_relaxed(csid->base + CSID_CSI2_RX_IRQ_STATUS);
+	writel_relaxed(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR);
+
+	val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(0));
+	writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(0));
+
+	val = 1 << IRQ_CMD_CLEAR;
+	writel_relaxed(val, csid->base + CSID_IRQ_CMD);
+
+	if (reset_done)
+		complete(&csid->reset_complete);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * csid_reset - Trigger reset on CSID module and wait to complete
+ * @csid: CSID device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int csid_reset(struct csid_device *csid)
+{
+	unsigned long time;
+	u32 val;
+
+	reinit_completion(&csid->reset_complete);
+
+	writel_relaxed(1, csid->base + CSID_TOP_IRQ_CLEAR);
+	writel_relaxed(1, csid->base + CSID_IRQ_CMD);
+	writel_relaxed(1, csid->base + CSID_TOP_IRQ_MASK);
+	writel_relaxed(1, csid->base + CSID_IRQ_CMD);
+
+	/* preserve registers */
+	val = 0x1e << RST_STROBES;
+	writel_relaxed(val, csid->base + CSID_RST_STROBES);
+
+	time = wait_for_completion_timeout(&csid->reset_complete,
+		msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
+	if (!time) {
+		dev_err(csid->camss->dev, "CSID reset timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
+			     unsigned int match_format_idx, u32 match_code)
+{
+	switch (sink_code) {
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_SBGGR10_1X10,
+			MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	case MEDIA_BUS_FMT_Y10_1X10:
+	{
+		u32 src_code[] = {
+			MEDIA_BUS_FMT_Y10_1X10,
+			MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+		};
+
+		return csid_find_code(src_code, ARRAY_SIZE(src_code),
+				      match_format_idx, match_code);
+	}
+	default:
+		if (match_format_idx > 0)
+			return 0;
+
+		return sink_code;
+	}
+}
+
+static void csid_subdev_init(struct csid_device *csid)
+{
+	csid->formats = csid_formats;
+	csid->nformats = ARRAY_SIZE(csid_formats);
+	csid->testgen.modes = csid_testgen_modes;
+	csid->testgen.nmodes = CSID_PAYLOAD_MODE_MAX_SUPPORTED_170;
+}
+
+const struct csid_hw_ops csid_ops_170 = {
+	.configure_stream = csid_configure_stream,
+	.configure_testgen_pattern = csid_configure_testgen_pattern,
+	.hw_version = csid_hw_version,
+	.isr = csid_isr,
+	.reset = csid_reset,
+	.src_pad_code = csid_src_pad_code,
+	.subdev_init = csid_subdev_init,
+};
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 601bd810f2b0..294a0a9e4dfa 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -123,6 +123,8 @@ static int csid_set_clock_rates(struct csid_device *csid)
 				dev_err(dev, "clk set rate failed: %d\n", ret);
 				return ret;
 			}
+		} else if (clock->nfreqs) {
+			clk_set_rate(clock->clk, clock->freq[0]);
 		}
 	}
 
@@ -544,6 +546,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
 	} else if (camss->version == CAMSS_8x96 ||
 		   camss->version == CAMSS_660) {
 		csid->ops = &csid_ops_4_7;
+	} else if (camss->version == CAMSS_845) {
+		csid->ops = &csid_ops_170;
 	} else {
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index bcc8bdb6e0ad..fe9182ff73aa 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -244,5 +244,7 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
 
 extern const struct csid_hw_ops csid_ops_4_1;
 extern const struct csid_hw_ops csid_ops_4_7;
+extern const struct csid_hw_ops csid_ops_170;
+
 
 #endif /* QC_MSM_CAMSS_CSID_H */
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 1c3d64d612ff..a4fd8c32bfd8 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,68 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources csid_res_845[] = {
+	/* CSID0 */
+	{
+		.regulator = { "vdda-csi0" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe0", "vfe0_src",
+				"vfe0_cphy_rx", "csi0",
+				"csi0_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid0" },
+		.interrupt = { "csid0" }
+	},
+
+	/* CSID1 */
+	{
+		.regulator = { "vdda-csi1" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe1", "vfe1_src",
+				"vfe1_cphy_rx", "csi1",
+				"csi1_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid1" },
+		.interrupt = { "csid1" }
+	},
+
+	/* CSID2 */
+	{
+		.regulator = { "vdda-csi2" },
+		.clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src",
+				"soc_ahb", "vfe_lite", "vfe_lite_src",
+				"vfe_lite_cphy_rx", "csi2",
+				"csi2_src" },
+		.clock_rate = { { 0 },
+				{ 384000000 },
+				{ 80000000 },
+				{ 0 },
+				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
+				{ 320000000 },
+				{ 0 },
+				{ 19200000, 75000000, 384000000, 538666667 },
+				{ 384000000 } },
+		.reg = { "csid2" },
+		.interrupt = { "csid2" }
+	}
+};
+
 static const struct resources vfe_res_845[] = {
 	/* VFE0 */
 	{
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 10/17] media: camss: Add support for CSIPHY hardware version Titan 170
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add register definitions for version 170 of the Titan architecture
and implement support for the CSIPHY subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../qcom/camss/camss-csiphy-3ph-1-0.c         | 182 ++++++++++++++++--
 .../media/platform/qcom/camss/camss-csiphy.c  |  66 +++++--
 drivers/media/platform/qcom/camss/camss.c     |  74 +++++++
 3 files changed, 290 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
index 97cb9de85031..8cf1440b7d70 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
@@ -47,6 +47,105 @@
 #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID	BIT(1)
 #define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(n)	(0x8b0 + 0x4 * (n))
 
+#define CSIPHY_DEFAULT_PARAMS            0
+#define CSIPHY_LANE_ENABLE               1
+#define CSIPHY_SETTLE_CNT_LOWER_BYTE     2
+#define CSIPHY_SETTLE_CNT_HIGHER_BYTE    3
+#define CSIPHY_DNP_PARAMS                4
+#define CSIPHY_2PH_REGS                  5
+#define CSIPHY_3PH_REGS                  6
+
+struct csiphy_reg_t {
+	int32_t  reg_addr;
+	int32_t  reg_data;
+	int32_t  delay;
+	uint32_t csiphy_param_type;
+};
+
+static struct
+csiphy_reg_t lane_regs_sdm845[5][14] = {
+	{
+		{0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
 static void csiphy_hw_version_read(struct csiphy_device *csiphy,
 				   struct device *dev)
 {
@@ -135,26 +234,13 @@ static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes,
 	return settle_cnt;
 }
 
-static void csiphy_lanes_enable(struct csiphy_device *csiphy,
-				struct csiphy_config *cfg,
-				u32 pixel_clock, u8 bpp, u8 lane_mask)
+static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy,
+				     struct csiphy_config *cfg,
+				     u8 settle_cnt)
 {
 	struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg;
-	u8 settle_cnt;
-	u8 val, l = 0;
-	int i;
-
-	settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data,
-					    csiphy->timer_clk_rate);
-
-	val = BIT(c->clk.pos);
-	for (i = 0; i < c->num_data; i++)
-		val |= BIT(c->data[i].pos * 2);
-
-	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5));
-
-	val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B;
-	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6));
+	int i, l = 0;
+	u8 val;
 
 	for (i = 0; i <= c->num_data; i++) {
 		if (i == c->num_data)
@@ -208,6 +294,66 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy,
 
 	val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE;
 	writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_MISC1(l));
+}
+
+static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy,
+				     u8 settle_cnt)
+{
+	int i, l;
+	u32 val;
+
+	for (l = 0; l < 5; l++) {
+		for (i = 0; i < 14; i++) {
+			struct csiphy_reg_t *r = &lane_regs_sdm845[l][i];
+
+			switch (r->csiphy_param_type) {
+			case CSIPHY_SETTLE_CNT_LOWER_BYTE:
+				val = settle_cnt & 0xff;
+				break;
+			case CSIPHY_DNP_PARAMS:
+				continue;
+			default:
+				val = r->reg_data;
+				break;
+			}
+			writel_relaxed(val, csiphy->base + r->reg_addr);
+		}
+	}
+}
+
+static void csiphy_lanes_enable(struct csiphy_device *csiphy,
+				struct csiphy_config *cfg,
+				u32 pixel_clock, u8 bpp, u8 lane_mask)
+{
+	struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg;
+	u8 settle_cnt;
+	u8 val;
+	int i;
+
+	settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data,
+					    csiphy->timer_clk_rate);
+
+	val = BIT(c->clk.pos);
+	for (i = 0; i < c->num_data; i++)
+		val |= BIT(c->data[i].pos * 2);
+
+	val = 0xd5;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5));
+
+	val = 1;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6));
+
+	val = 0x02;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(7));
+
+	val = 0x00;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0));
+
+	if (csiphy->camss->version == CAMSS_8x16 ||
+	    csiphy->camss->version == CAMSS_8x96)
+		csiphy_gen1_config_lanes(csiphy, cfg, settle_cnt);
+	else if (csiphy->camss->version == CAMSS_845)
+		csiphy_gen2_config_lanes(csiphy, settle_cnt);
 
 	val = 0xff;
 	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(11));
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 509c9a59c09c..e3fdc268050c 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -73,6 +73,30 @@ static const struct csiphy_format csiphy_formats_8x96[] = {
 	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
 };
 
+static const struct csiphy_format csiphy_formats_sdm845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
+	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
+};
+
 /*
  * csiphy_get_bpp - map media bus format to bits per pixel
  * @formats: supported media bus formats array
@@ -257,16 +281,20 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
 		return -EINVAL;
 	}
 
-	val = readl_relaxed(csiphy->base_clk_mux);
-	if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
-		val &= ~0xf0;
-		val |= cfg->csid_id << 4;
-	} else {
-		val &= ~0xf;
-		val |= cfg->csid_id;
+	if (csiphy->base_clk_mux) {
+		val = readl_relaxed(csiphy->base_clk_mux);
+		if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
+			val &= ~0xf0;
+			val |= cfg->csid_id << 4;
+		} else {
+			val &= ~0xf;
+			val |= cfg->csid_id;
+		}
+		writel_relaxed(val, csiphy->base_clk_mux);
+
+		/* Enforce reg write ordering between clk mux & lane enabling */
+		wmb();
 	}
-	writel_relaxed(val, csiphy->base_clk_mux);
-	wmb();
 
 	csiphy->ops->lanes_enable(csiphy, cfg, pixel_clock, bpp, lane_mask);
 
@@ -557,6 +585,10 @@ int msm_csiphy_subdev_init(struct camss *camss,
 		csiphy->ops = &csiphy_ops_3ph_1_0;
 		csiphy->formats = csiphy_formats_8x96;
 		csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96);
+	} else if (camss->version == CAMSS_845) {
+		csiphy->ops = &csiphy_ops_3ph_1_0;
+		csiphy->formats = csiphy_formats_sdm845;
+		csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845);
 	} else {
 		return -EINVAL;
 	}
@@ -570,11 +602,17 @@ int msm_csiphy_subdev_init(struct camss *camss,
 		return PTR_ERR(csiphy->base);
 	}
 
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
-	csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
-	if (IS_ERR(csiphy->base_clk_mux)) {
-		dev_err(dev, "could not map memory\n");
-		return PTR_ERR(csiphy->base_clk_mux);
+	if (camss->version == CAMSS_8x16 ||
+	    camss->version == CAMSS_8x96) {
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			res->reg[1]);
+		csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
+		if (IS_ERR(csiphy->base_clk_mux)) {
+			dev_err(dev, "could not map memory\n");
+			return PTR_ERR(csiphy->base_clk_mux);
+		}
+	} else {
+		csiphy->base_clk_mux = NULL;
 	}
 
 	/* Interrupt */
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index a4fd8c32bfd8..b07890a9a01a 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,80 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources csiphy_res_845[] = {
+	/* CSIPHY0 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy0",
+				"csiphy0_timer_src", "csiphy0_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy0" },
+		.interrupt = { "csiphy0" }
+	},
+
+	/* CSIPHY1 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy1",
+				"csiphy1_timer_src", "csiphy1_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy1" },
+		.interrupt = { "csiphy1" }
+	},
+
+	/* CSIPHY2 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy2",
+				"csiphy2_timer_src", "csiphy2_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy2" },
+		.interrupt = { "csiphy2" }
+	},
+
+	/* CSIPHY3 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy3",
+				"csiphy3_timer_src", "csiphy3_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy3" },
+		.interrupt = { "csiphy3" }
+	}
+};
+
 static const struct resources csid_res_845[] = {
 	/* CSID0 */
 	{
-- 
2.27.0


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

* [PATCH v1 10/17] media: camss: Add support for CSIPHY hardware version Titan 170
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add register definitions for version 170 of the Titan architecture
and implement support for the CSIPHY subdevice.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../qcom/camss/camss-csiphy-3ph-1-0.c         | 182 ++++++++++++++++--
 .../media/platform/qcom/camss/camss-csiphy.c  |  66 +++++--
 drivers/media/platform/qcom/camss/camss.c     |  74 +++++++
 3 files changed, 290 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
index 97cb9de85031..8cf1440b7d70 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
@@ -47,6 +47,105 @@
 #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID	BIT(1)
 #define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(n)	(0x8b0 + 0x4 * (n))
 
+#define CSIPHY_DEFAULT_PARAMS            0
+#define CSIPHY_LANE_ENABLE               1
+#define CSIPHY_SETTLE_CNT_LOWER_BYTE     2
+#define CSIPHY_SETTLE_CNT_HIGHER_BYTE    3
+#define CSIPHY_DNP_PARAMS                4
+#define CSIPHY_2PH_REGS                  5
+#define CSIPHY_3PH_REGS                  6
+
+struct csiphy_reg_t {
+	int32_t  reg_addr;
+	int32_t  reg_data;
+	int32_t  delay;
+	uint32_t csiphy_param_type;
+};
+
+static struct
+csiphy_reg_t lane_regs_sdm845[5][14] = {
+	{
+		{0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+	{
+		{0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE},
+		{0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS},
+		{0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS},
+		{0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS},
+	},
+};
+
 static void csiphy_hw_version_read(struct csiphy_device *csiphy,
 				   struct device *dev)
 {
@@ -135,26 +234,13 @@ static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes,
 	return settle_cnt;
 }
 
-static void csiphy_lanes_enable(struct csiphy_device *csiphy,
-				struct csiphy_config *cfg,
-				u32 pixel_clock, u8 bpp, u8 lane_mask)
+static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy,
+				     struct csiphy_config *cfg,
+				     u8 settle_cnt)
 {
 	struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg;
-	u8 settle_cnt;
-	u8 val, l = 0;
-	int i;
-
-	settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data,
-					    csiphy->timer_clk_rate);
-
-	val = BIT(c->clk.pos);
-	for (i = 0; i < c->num_data; i++)
-		val |= BIT(c->data[i].pos * 2);
-
-	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5));
-
-	val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B;
-	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6));
+	int i, l = 0;
+	u8 val;
 
 	for (i = 0; i <= c->num_data; i++) {
 		if (i == c->num_data)
@@ -208,6 +294,66 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy,
 
 	val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE;
 	writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_MISC1(l));
+}
+
+static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy,
+				     u8 settle_cnt)
+{
+	int i, l;
+	u32 val;
+
+	for (l = 0; l < 5; l++) {
+		for (i = 0; i < 14; i++) {
+			struct csiphy_reg_t *r = &lane_regs_sdm845[l][i];
+
+			switch (r->csiphy_param_type) {
+			case CSIPHY_SETTLE_CNT_LOWER_BYTE:
+				val = settle_cnt & 0xff;
+				break;
+			case CSIPHY_DNP_PARAMS:
+				continue;
+			default:
+				val = r->reg_data;
+				break;
+			}
+			writel_relaxed(val, csiphy->base + r->reg_addr);
+		}
+	}
+}
+
+static void csiphy_lanes_enable(struct csiphy_device *csiphy,
+				struct csiphy_config *cfg,
+				u32 pixel_clock, u8 bpp, u8 lane_mask)
+{
+	struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg;
+	u8 settle_cnt;
+	u8 val;
+	int i;
+
+	settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data,
+					    csiphy->timer_clk_rate);
+
+	val = BIT(c->clk.pos);
+	for (i = 0; i < c->num_data; i++)
+		val |= BIT(c->data[i].pos * 2);
+
+	val = 0xd5;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5));
+
+	val = 1;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6));
+
+	val = 0x02;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(7));
+
+	val = 0x00;
+	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0));
+
+	if (csiphy->camss->version == CAMSS_8x16 ||
+	    csiphy->camss->version == CAMSS_8x96)
+		csiphy_gen1_config_lanes(csiphy, cfg, settle_cnt);
+	else if (csiphy->camss->version == CAMSS_845)
+		csiphy_gen2_config_lanes(csiphy, settle_cnt);
 
 	val = 0xff;
 	writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(11));
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 509c9a59c09c..e3fdc268050c 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -73,6 +73,30 @@ static const struct csiphy_format csiphy_formats_8x96[] = {
 	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
 };
 
+static const struct csiphy_format csiphy_formats_sdm845[] = {
+	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
+	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
+	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
+};
+
 /*
  * csiphy_get_bpp - map media bus format to bits per pixel
  * @formats: supported media bus formats array
@@ -257,16 +281,20 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
 		return -EINVAL;
 	}
 
-	val = readl_relaxed(csiphy->base_clk_mux);
-	if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
-		val &= ~0xf0;
-		val |= cfg->csid_id << 4;
-	} else {
-		val &= ~0xf;
-		val |= cfg->csid_id;
+	if (csiphy->base_clk_mux) {
+		val = readl_relaxed(csiphy->base_clk_mux);
+		if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) {
+			val &= ~0xf0;
+			val |= cfg->csid_id << 4;
+		} else {
+			val &= ~0xf;
+			val |= cfg->csid_id;
+		}
+		writel_relaxed(val, csiphy->base_clk_mux);
+
+		/* Enforce reg write ordering between clk mux & lane enabling */
+		wmb();
 	}
-	writel_relaxed(val, csiphy->base_clk_mux);
-	wmb();
 
 	csiphy->ops->lanes_enable(csiphy, cfg, pixel_clock, bpp, lane_mask);
 
@@ -557,6 +585,10 @@ int msm_csiphy_subdev_init(struct camss *camss,
 		csiphy->ops = &csiphy_ops_3ph_1_0;
 		csiphy->formats = csiphy_formats_8x96;
 		csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96);
+	} else if (camss->version == CAMSS_845) {
+		csiphy->ops = &csiphy_ops_3ph_1_0;
+		csiphy->formats = csiphy_formats_sdm845;
+		csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845);
 	} else {
 		return -EINVAL;
 	}
@@ -570,11 +602,17 @@ int msm_csiphy_subdev_init(struct camss *camss,
 		return PTR_ERR(csiphy->base);
 	}
 
-	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
-	csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
-	if (IS_ERR(csiphy->base_clk_mux)) {
-		dev_err(dev, "could not map memory\n");
-		return PTR_ERR(csiphy->base_clk_mux);
+	if (camss->version == CAMSS_8x16 ||
+	    camss->version == CAMSS_8x96) {
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			res->reg[1]);
+		csiphy->base_clk_mux = devm_ioremap_resource(dev, r);
+		if (IS_ERR(csiphy->base_clk_mux)) {
+			dev_err(dev, "could not map memory\n");
+			return PTR_ERR(csiphy->base_clk_mux);
+		}
+	} else {
+		csiphy->base_clk_mux = NULL;
 	}
 
 	/* Interrupt */
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index a4fd8c32bfd8..b07890a9a01a 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -465,6 +465,80 @@ static const struct resources vfe_res_660[] = {
 	}
 };
 
+static const struct resources csiphy_res_845[] = {
+	/* CSIPHY0 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy0",
+				"csiphy0_timer_src", "csiphy0_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy0" },
+		.interrupt = { "csiphy0" }
+	},
+
+	/* CSIPHY1 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy1",
+				"csiphy1_timer_src", "csiphy1_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy1" },
+		.interrupt = { "csiphy1" }
+	},
+
+	/* CSIPHY2 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy2",
+				"csiphy2_timer_src", "csiphy2_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy2" },
+		.interrupt = { "csiphy2" }
+	},
+
+	/* CSIPHY3 */
+	{
+		.regulator = { NULL },
+		.clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src",
+				"cpas_ahb", "cphy_rx_src", "csiphy3",
+				"csiphy3_timer_src", "csiphy3_timer" },
+		.clock_rate = { { 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 0 },
+				{ 19200000, 240000000, 269333333 } },
+		.reg = { "csiphy3" },
+		.interrupt = { "csiphy3" }
+	}
+};
+
 static const struct resources csid_res_845[] = {
 	/* CSID0 */
 	{
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 11/17] media: camss: Remove per VFE power domain toggling
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

For Titan ISPs clocks fail to re-enable during vfe_get()
after any vfe has been halted and its corresponding power
domain power has been detached.

Since all of the clocks depend on all of the PDs, per
VFE PD detaching is no option for this generation of HW.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-ispif.c   | 11 ---
 drivers/media/platform/qcom/camss/camss-vfe.c |  7 --
 drivers/media/platform/qcom/camss/camss.c     | 94 +++++++++++--------
 drivers/media/platform/qcom/camss/camss.h     | 12 +--
 4 files changed, 60 insertions(+), 64 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index 0c804584dd65..e0e744551769 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -323,14 +323,6 @@ static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 	struct camss *camss = ispif->camss;
 	int ret;
 
-	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
-	if (ret < 0)
-		return ret;
-
-	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
-	if (ret < 0)
-		return ret;
-
 	ret = camss_enable_clocks(ispif->nclocks_for_reset,
 				  ispif->clock_for_reset,
 				  camss->dev);
@@ -343,9 +335,6 @@ static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 
 	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
 
-	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
-	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
-
 	return ret;
 }
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 5a874b544391..5054cd9b570c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -587,10 +587,6 @@ static int vfe_get(struct vfe_device *vfe)
 	mutex_lock(&vfe->power_lock);
 
 	if (vfe->power_count == 0) {
-		ret = camss_pm_domain_on(vfe->camss, vfe->id);
-		if (ret < 0)
-			goto error_pm_domain;
-
 		ret = pm_runtime_get_sync(vfe->camss->dev);
 		if (ret < 0)
 			goto error_pm_runtime_get;
@@ -627,9 +623,7 @@ static int vfe_get(struct vfe_device *vfe)
 
 error_pm_runtime_get:
 	pm_runtime_put_sync(vfe->camss->dev);
-	camss_pm_domain_off(vfe->camss, vfe->id);
 
-error_pm_domain:
 	mutex_unlock(&vfe->power_lock);
 
 	return ret;
@@ -653,7 +647,6 @@ static void vfe_put(struct vfe_device *vfe)
 		}
 		camss_disable_clocks(vfe->nclocks, vfe->clock);
 		pm_runtime_put_sync(vfe->camss->dev);
-		camss_pm_domain_off(vfe->camss, vfe->id);
 	}
 
 	vfe->power_count--;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index b07890a9a01a..259ed094cee4 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -774,28 +774,6 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
 	return 0;
 }
 
-int camss_pm_domain_on(struct camss *camss, int id)
-{
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		camss->genpd_link[id] = device_link_add(camss->dev,
-				camss->genpd[id], DL_FLAG_STATELESS |
-				DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
-
-		if (!camss->genpd_link[id])
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-void camss_pm_domain_off(struct camss *camss, int id)
-{
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660)
-		device_link_del(camss->genpd_link[id]);
-}
-
 /*
  * camss_of_parse_endpoint_node - Parse port endpoint node
  * @dev: Device
@@ -1216,6 +1194,48 @@ static const struct media_device_ops camss_media_ops = {
 	.link_notify = v4l2_pipeline_link_notify,
 };
 
+
+static int camss_configure_pd(struct camss *camss)
+{
+	int nbr_pm_domains = 0;
+	int last_pm_domain = 0;
+	int i;
+	int ret;
+
+	if (camss->version == CAMSS_8x96 ||
+	    camss->version == CAMSS_660)
+		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+
+	for (i = 0; i < nbr_pm_domains; i++) {
+		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
+		if (IS_ERR(camss->genpd[i])) {
+			ret = PTR_ERR(camss->genpd[i]);
+			goto fail_pm;
+		}
+
+		camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i],
+			DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+
+		if (!camss->genpd_link[i]) {
+			dev_pm_domain_detach(camss->genpd[i], true);
+			ret = -EINVAL;
+			goto fail_pm;
+		}
+
+		last_pm_domain = i;
+	}
+
+	return 0;
+
+fail_pm:
+	for (i = 0; i < last_pm_domain; i++) {
+		device_link_del(camss->genpd_link[i]);
+		dev_pm_domain_detach(camss->genpd[i], true);
+	}
+
+	return ret;
+}
+
 /*
  * camss_probe - Probe CAMSS platform device
  * @pdev: Pointer to CAMSS platform device
@@ -1348,20 +1368,10 @@ static int camss_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
-						camss->dev, PM_DOMAIN_VFE0);
-		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
-			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]);
-
-		camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id(
-						camss->dev, PM_DOMAIN_VFE1);
-		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) {
-			dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0],
-					     true);
-			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]);
-		}
+	ret = camss_configure_pd(camss);
+	if (ret < 0) {
+		dev_err(dev, "Failed to configure power domains: %d\n", ret);
+		return ret;
 	}
 
 	pm_runtime_enable(dev);
@@ -1382,6 +1392,9 @@ static int camss_probe(struct platform_device *pdev)
 
 void camss_delete(struct camss *camss)
 {
+	int nbr_pm_domains = 0;
+	int i;
+
 	v4l2_device_unregister(&camss->v4l2_dev);
 	media_device_unregister(&camss->media_dev);
 	media_device_cleanup(&camss->media_dev);
@@ -1389,9 +1402,12 @@ void camss_delete(struct camss *camss)
 	pm_runtime_disable(camss->dev);
 
 	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
-		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
+	    camss->version == CAMSS_660)
+		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+
+	for (i = 0; i < nbr_pm_domains; i++) {
+		device_link_del(camss->genpd_link[i]);
+		dev_pm_domain_detach(camss->genpd[i], true);
 	}
 
 	kfree(camss);
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index b7ad8e9f68a8..7560d85b3352 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -57,9 +57,9 @@ struct resources_ispif {
 };
 
 enum pm_domain {
-	PM_DOMAIN_VFE0,
-	PM_DOMAIN_VFE1,
-	PM_DOMAIN_COUNT
+	PM_DOMAIN_VFE0 = 0,
+	PM_DOMAIN_VFE1 = 1,
+	PM_DOMAIN_CAMSS_COUNT = 2,	/* CAMSS series of ISPs */
 };
 
 enum camss_version {
@@ -83,8 +83,8 @@ struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-	struct device *genpd[PM_DOMAIN_COUNT];
-	struct device_link *genpd_link[PM_DOMAIN_COUNT];
+	struct device *genpd[PM_DOMAIN_CAMSS_COUNT];
+	struct device_link *genpd_link[PM_DOMAIN_CAMSS_COUNT];
 };
 
 struct camss_camera_interface {
@@ -110,8 +110,6 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock,
 void camss_disable_clocks(int nclocks, struct camss_clock *clock);
 struct media_entity *camss_find_sensor(struct media_entity *entity);
 int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock);
-int camss_pm_domain_on(struct camss *camss, int id);
-void camss_pm_domain_off(struct camss *camss, int id);
 void camss_delete(struct camss *camss);
 
 #endif /* QC_MSM_CAMSS_H */
-- 
2.27.0


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

* [PATCH v1 11/17] media: camss: Remove per VFE power domain toggling
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

For Titan ISPs clocks fail to re-enable during vfe_get()
after any vfe has been halted and its corresponding power
domain power has been detached.

Since all of the clocks depend on all of the PDs, per
VFE PD detaching is no option for this generation of HW.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../media/platform/qcom/camss/camss-ispif.c   | 11 ---
 drivers/media/platform/qcom/camss/camss-vfe.c |  7 --
 drivers/media/platform/qcom/camss/camss.c     | 94 +++++++++++--------
 drivers/media/platform/qcom/camss/camss.h     | 12 +--
 4 files changed, 60 insertions(+), 64 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index 0c804584dd65..e0e744551769 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -323,14 +323,6 @@ static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 	struct camss *camss = ispif->camss;
 	int ret;
 
-	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
-	if (ret < 0)
-		return ret;
-
-	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
-	if (ret < 0)
-		return ret;
-
 	ret = camss_enable_clocks(ispif->nclocks_for_reset,
 				  ispif->clock_for_reset,
 				  camss->dev);
@@ -343,9 +335,6 @@ static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
 
 	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
 
-	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
-	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
-
 	return ret;
 }
 
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 5a874b544391..5054cd9b570c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -587,10 +587,6 @@ static int vfe_get(struct vfe_device *vfe)
 	mutex_lock(&vfe->power_lock);
 
 	if (vfe->power_count == 0) {
-		ret = camss_pm_domain_on(vfe->camss, vfe->id);
-		if (ret < 0)
-			goto error_pm_domain;
-
 		ret = pm_runtime_get_sync(vfe->camss->dev);
 		if (ret < 0)
 			goto error_pm_runtime_get;
@@ -627,9 +623,7 @@ static int vfe_get(struct vfe_device *vfe)
 
 error_pm_runtime_get:
 	pm_runtime_put_sync(vfe->camss->dev);
-	camss_pm_domain_off(vfe->camss, vfe->id);
 
-error_pm_domain:
 	mutex_unlock(&vfe->power_lock);
 
 	return ret;
@@ -653,7 +647,6 @@ static void vfe_put(struct vfe_device *vfe)
 		}
 		camss_disable_clocks(vfe->nclocks, vfe->clock);
 		pm_runtime_put_sync(vfe->camss->dev);
-		camss_pm_domain_off(vfe->camss, vfe->id);
 	}
 
 	vfe->power_count--;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index b07890a9a01a..259ed094cee4 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -774,28 +774,6 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
 	return 0;
 }
 
-int camss_pm_domain_on(struct camss *camss, int id)
-{
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		camss->genpd_link[id] = device_link_add(camss->dev,
-				camss->genpd[id], DL_FLAG_STATELESS |
-				DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
-
-		if (!camss->genpd_link[id])
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-void camss_pm_domain_off(struct camss *camss, int id)
-{
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660)
-		device_link_del(camss->genpd_link[id]);
-}
-
 /*
  * camss_of_parse_endpoint_node - Parse port endpoint node
  * @dev: Device
@@ -1216,6 +1194,48 @@ static const struct media_device_ops camss_media_ops = {
 	.link_notify = v4l2_pipeline_link_notify,
 };
 
+
+static int camss_configure_pd(struct camss *camss)
+{
+	int nbr_pm_domains = 0;
+	int last_pm_domain = 0;
+	int i;
+	int ret;
+
+	if (camss->version == CAMSS_8x96 ||
+	    camss->version == CAMSS_660)
+		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+
+	for (i = 0; i < nbr_pm_domains; i++) {
+		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
+		if (IS_ERR(camss->genpd[i])) {
+			ret = PTR_ERR(camss->genpd[i]);
+			goto fail_pm;
+		}
+
+		camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i],
+			DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+
+		if (!camss->genpd_link[i]) {
+			dev_pm_domain_detach(camss->genpd[i], true);
+			ret = -EINVAL;
+			goto fail_pm;
+		}
+
+		last_pm_domain = i;
+	}
+
+	return 0;
+
+fail_pm:
+	for (i = 0; i < last_pm_domain; i++) {
+		device_link_del(camss->genpd_link[i]);
+		dev_pm_domain_detach(camss->genpd[i], true);
+	}
+
+	return ret;
+}
+
 /*
  * camss_probe - Probe CAMSS platform device
  * @pdev: Pointer to CAMSS platform device
@@ -1348,20 +1368,10 @@ static int camss_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
-						camss->dev, PM_DOMAIN_VFE0);
-		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
-			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]);
-
-		camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id(
-						camss->dev, PM_DOMAIN_VFE1);
-		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) {
-			dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0],
-					     true);
-			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]);
-		}
+	ret = camss_configure_pd(camss);
+	if (ret < 0) {
+		dev_err(dev, "Failed to configure power domains: %d\n", ret);
+		return ret;
 	}
 
 	pm_runtime_enable(dev);
@@ -1382,6 +1392,9 @@ static int camss_probe(struct platform_device *pdev)
 
 void camss_delete(struct camss *camss)
 {
+	int nbr_pm_domains = 0;
+	int i;
+
 	v4l2_device_unregister(&camss->v4l2_dev);
 	media_device_unregister(&camss->media_dev);
 	media_device_cleanup(&camss->media_dev);
@@ -1389,9 +1402,12 @@ void camss_delete(struct camss *camss)
 	pm_runtime_disable(camss->dev);
 
 	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660) {
-		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
-		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
+	    camss->version == CAMSS_660)
+		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+
+	for (i = 0; i < nbr_pm_domains; i++) {
+		device_link_del(camss->genpd_link[i]);
+		dev_pm_domain_detach(camss->genpd[i], true);
 	}
 
 	kfree(camss);
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index b7ad8e9f68a8..7560d85b3352 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -57,9 +57,9 @@ struct resources_ispif {
 };
 
 enum pm_domain {
-	PM_DOMAIN_VFE0,
-	PM_DOMAIN_VFE1,
-	PM_DOMAIN_COUNT
+	PM_DOMAIN_VFE0 = 0,
+	PM_DOMAIN_VFE1 = 1,
+	PM_DOMAIN_CAMSS_COUNT = 2,	/* CAMSS series of ISPs */
 };
 
 enum camss_version {
@@ -83,8 +83,8 @@ struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-	struct device *genpd[PM_DOMAIN_COUNT];
-	struct device_link *genpd_link[PM_DOMAIN_COUNT];
+	struct device *genpd[PM_DOMAIN_CAMSS_COUNT];
+	struct device_link *genpd_link[PM_DOMAIN_CAMSS_COUNT];
 };
 
 struct camss_camera_interface {
@@ -110,8 +110,6 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock,
 void camss_disable_clocks(int nclocks, struct camss_clock *clock);
 struct media_entity *camss_find_sensor(struct media_entity *entity);
 int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock);
-int camss_pm_domain_on(struct camss *camss, int id);
-void camss_pm_domain_off(struct camss *camss, int id);
 void camss_delete(struct camss *camss);
 
 #endif /* QC_MSM_CAMSS_H */
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 12/17] media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add bindings for qcom,sdm845-camss in order to support the camera
subsystem on SDM845.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../devicetree/bindings/media/qcom,camss.txt  | 51 +++++++++++++++----
 1 file changed, 40 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/qcom,camss.txt b/Documentation/devicetree/bindings/media/qcom,camss.txt
index 498234629e21..276c5d0c25cb 100644
--- a/Documentation/devicetree/bindings/media/qcom,camss.txt
+++ b/Documentation/devicetree/bindings/media/qcom,camss.txt
@@ -9,6 +9,7 @@ Qualcomm Camera Subsystem
 		- "qcom,msm8916-camss"
 		- "qcom,msm8996-camss"
 		- "qcom,sdm660-camss"
+		- "qcom,sdm845-camss"
 - reg:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -18,19 +19,21 @@ Qualcomm Camera Subsystem
 	Value type: <stringlist>
 	Definition: Should contain the following entries:
 		- "csiphy0"
-		- "csiphy0_clk_mux"
+		- "csiphy0_clk_mux"	(not 845)
 		- "csiphy1"
-		- "csiphy1_clk_mux"
-		- "csiphy2"		(8996 only)
+		- "csiphy1_clk_mux"	(not 845)
+		- "csiphy2"		(8996 & 845)
 		- "csiphy2_clk_mux"	(8996 only)
+		- "csiphy3"		(845 only)
 		- "csid0"
 		- "csid1"
-		- "csid2"		(8996 only)
-		- "csid3"		(8996 only)
+		- "csid2"		(8996 & 845)
+		- "csid3"		(8996 & 845)
 		- "ispif"
-		- "csi_clk_mux"
+		- "csi_clk_mux"		(not 845)
 		- "vfe0"
-		- "vfe1"		(8996 only)
+		- "vfe1"		(8996 & 845)
+		- "vfe_lite"		(845 only)
 - interrupts:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -41,14 +44,16 @@ Qualcomm Camera Subsystem
 	Definition: Should contain the following entries:
 		- "csiphy0"
 		- "csiphy1"
-		- "csiphy2"		(8996 only)
+		- "csiphy2"		(8996 & 845)
+		- "csiphy3"		(845 only)
 		- "csid0"
 		- "csid1"
-		- "csid2"		(8996 only)
+		- "csid2"		(8996 & 845)
 		- "csid3"		(8996 only)
 		- "ispif"
 		- "vfe0"
-		- "vfe1"		(8996 only)
+		- "vfe1"		(8996 & 845)
+		- "vfe_lite"		(845 only)
 - power-domains:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -67,27 +72,40 @@ Qualcomm Camera Subsystem
 		- "top_ahb"
 		- "throttle_axi"	(660 only)
 		- "ispif_ahb"
+		- "camnoc_axi"		(845 only)
+		- "cpas_ahb"		(845 only)
+		- "cphy_rx_src"		(856 only)
 		- "csiphy0_timer"
+		- "csiphy0"		(845 only)
+		- "csiphy0_timer_src"	(845 only)
 		- "csiphy1_timer"
-		- "csiphy2_timer"	(8996 only)
+		- "csiphy2"		(845 only)
+		- "csiphy2_timer_src"	(845 only)
+		- "csiphy2_timer"	(8996 & 845)
+		- "csiphy3"		(845 only)
+		- "csiphy3_timer_src"	(845 only)
+		- "csiphy3_timer"	(845 only)
 		- "csiphy_ahb2crif"	(660 only)
 		- "csi0_ahb"
 		- "csi0"
 		- "csi0_phy"
 		- "csi0_pix"
 		- "csi0_rdi"
+		- "csi0_src"		(845 only)
 		- "cphy_csid0"		(660 only)
 		- "csi1_ahb"
 		- "csi1"
 		- "csi1_phy"
 		- "csi1_pix"
 		- "csi1_rdi"
+		- "csi1_src"		(845 only)
 		- "cphy_csid1"		(660 only)
 		- "csi2_ahb"		(8996 only)
 		- "csi2"		(8996 only)
 		- "csi2_phy"		(8996 only)
 		- "csi2_pix"		(8996 only)
 		- "csi2_rdi"		(8996 only)
+		- "csi2_src"		(845 only)
 		- "cphy_csid2"		(660 only)
 		- "csi3_ahb"		(8996 only)
 		- "csi3"		(8996 only)
@@ -96,14 +114,25 @@ Qualcomm Camera Subsystem
 		- "csi3_rdi"		(8996 only)
 		- "cphy_csid3"		(660 only)
 		- "ahb"
+		- "slow_ahb_src"	(845 only)
+		- "soc_ahb"		(845 only)
 		- "vfe0"
 		- "csi_vfe0"
 		- "vfe0_ahb",		(8996 only)
+		- "vfe0_cphy_rx"	(845 only)
+		- "vfe0_axi",		(845 only)
+		- "vfe0_src",		(845 only)
 		- "vfe0_stream",	(8996 only)
 		- "vfe1",		(8996 only)
 		- "csi_vfe1",		(8996 only)
 		- "vfe1_ahb",		(8996 only)
+		- "vfe1_cphy_rx"	(845 only)
+		- "vfe1_axi",		(845 only)
+		- "vfe1_src",		(845 only)
 		- "vfe1_stream",	(8996 only)
+		- "vfe_lite_axi",	(845 only)
+		- "vfe_lite_cphy_rx"	(845 only)
+		- "vfe_lite_src",	(845 only)
 		- "vfe_ahb"
 		- "vfe_axi"
 - vdda-supply:
-- 
2.27.0


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

* [PATCH v1 12/17] media: dt-bindings: media: qcom, camss: Add bindings for SDM845 camss
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add bindings for qcom,sdm845-camss in order to support the camera
subsystem on SDM845.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 .../devicetree/bindings/media/qcom,camss.txt  | 51 +++++++++++++++----
 1 file changed, 40 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/qcom,camss.txt b/Documentation/devicetree/bindings/media/qcom,camss.txt
index 498234629e21..276c5d0c25cb 100644
--- a/Documentation/devicetree/bindings/media/qcom,camss.txt
+++ b/Documentation/devicetree/bindings/media/qcom,camss.txt
@@ -9,6 +9,7 @@ Qualcomm Camera Subsystem
 		- "qcom,msm8916-camss"
 		- "qcom,msm8996-camss"
 		- "qcom,sdm660-camss"
+		- "qcom,sdm845-camss"
 - reg:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -18,19 +19,21 @@ Qualcomm Camera Subsystem
 	Value type: <stringlist>
 	Definition: Should contain the following entries:
 		- "csiphy0"
-		- "csiphy0_clk_mux"
+		- "csiphy0_clk_mux"	(not 845)
 		- "csiphy1"
-		- "csiphy1_clk_mux"
-		- "csiphy2"		(8996 only)
+		- "csiphy1_clk_mux"	(not 845)
+		- "csiphy2"		(8996 & 845)
 		- "csiphy2_clk_mux"	(8996 only)
+		- "csiphy3"		(845 only)
 		- "csid0"
 		- "csid1"
-		- "csid2"		(8996 only)
-		- "csid3"		(8996 only)
+		- "csid2"		(8996 & 845)
+		- "csid3"		(8996 & 845)
 		- "ispif"
-		- "csi_clk_mux"
+		- "csi_clk_mux"		(not 845)
 		- "vfe0"
-		- "vfe1"		(8996 only)
+		- "vfe1"		(8996 & 845)
+		- "vfe_lite"		(845 only)
 - interrupts:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -41,14 +44,16 @@ Qualcomm Camera Subsystem
 	Definition: Should contain the following entries:
 		- "csiphy0"
 		- "csiphy1"
-		- "csiphy2"		(8996 only)
+		- "csiphy2"		(8996 & 845)
+		- "csiphy3"		(845 only)
 		- "csid0"
 		- "csid1"
-		- "csid2"		(8996 only)
+		- "csid2"		(8996 & 845)
 		- "csid3"		(8996 only)
 		- "ispif"
 		- "vfe0"
-		- "vfe1"		(8996 only)
+		- "vfe1"		(8996 & 845)
+		- "vfe_lite"		(845 only)
 - power-domains:
 	Usage: required
 	Value type: <prop-encoded-array>
@@ -67,27 +72,40 @@ Qualcomm Camera Subsystem
 		- "top_ahb"
 		- "throttle_axi"	(660 only)
 		- "ispif_ahb"
+		- "camnoc_axi"		(845 only)
+		- "cpas_ahb"		(845 only)
+		- "cphy_rx_src"		(856 only)
 		- "csiphy0_timer"
+		- "csiphy0"		(845 only)
+		- "csiphy0_timer_src"	(845 only)
 		- "csiphy1_timer"
-		- "csiphy2_timer"	(8996 only)
+		- "csiphy2"		(845 only)
+		- "csiphy2_timer_src"	(845 only)
+		- "csiphy2_timer"	(8996 & 845)
+		- "csiphy3"		(845 only)
+		- "csiphy3_timer_src"	(845 only)
+		- "csiphy3_timer"	(845 only)
 		- "csiphy_ahb2crif"	(660 only)
 		- "csi0_ahb"
 		- "csi0"
 		- "csi0_phy"
 		- "csi0_pix"
 		- "csi0_rdi"
+		- "csi0_src"		(845 only)
 		- "cphy_csid0"		(660 only)
 		- "csi1_ahb"
 		- "csi1"
 		- "csi1_phy"
 		- "csi1_pix"
 		- "csi1_rdi"
+		- "csi1_src"		(845 only)
 		- "cphy_csid1"		(660 only)
 		- "csi2_ahb"		(8996 only)
 		- "csi2"		(8996 only)
 		- "csi2_phy"		(8996 only)
 		- "csi2_pix"		(8996 only)
 		- "csi2_rdi"		(8996 only)
+		- "csi2_src"		(845 only)
 		- "cphy_csid2"		(660 only)
 		- "csi3_ahb"		(8996 only)
 		- "csi3"		(8996 only)
@@ -96,14 +114,25 @@ Qualcomm Camera Subsystem
 		- "csi3_rdi"		(8996 only)
 		- "cphy_csid3"		(660 only)
 		- "ahb"
+		- "slow_ahb_src"	(845 only)
+		- "soc_ahb"		(845 only)
 		- "vfe0"
 		- "csi_vfe0"
 		- "vfe0_ahb",		(8996 only)
+		- "vfe0_cphy_rx"	(845 only)
+		- "vfe0_axi",		(845 only)
+		- "vfe0_src",		(845 only)
 		- "vfe0_stream",	(8996 only)
 		- "vfe1",		(8996 only)
 		- "csi_vfe1",		(8996 only)
 		- "vfe1_ahb",		(8996 only)
+		- "vfe1_cphy_rx"	(845 only)
+		- "vfe1_axi",		(845 only)
+		- "vfe1_src",		(845 only)
 		- "vfe1_stream",	(8996 only)
+		- "vfe_lite_axi",	(845 only)
+		- "vfe_lite_cphy_rx"	(845 only)
+		- "vfe_lite_src",	(845 only)
 		- "vfe_ahb"
 		- "vfe_axi"
 - vdda-supply:
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 13/17] media: camss: Enable SDM845
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Enable support for SDM845 based Titan 170 ISPs.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 17 +++++++++++++++++
 drivers/media/platform/qcom/camss/camss.h |  6 ++++--
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 259ed094cee4..4dfae29c6327 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -897,6 +897,12 @@ static int camss_init_subdevices(struct camss *camss)
 		csid_res = csid_res_660;
 		ispif_res = &ispif_res_660;
 		vfe_res = vfe_res_660;
+	}  else if (camss->version == CAMSS_845) {
+		csiphy_res = csiphy_res_845;
+		csid_res = csid_res_845;
+		/* Titan VFEs don't have an ISPIF  */
+		ispif_res = NULL;
+		vfe_res = vfe_res_845;
 	} else {
 		return -EINVAL;
 	}
@@ -1205,6 +1211,8 @@ static int camss_configure_pd(struct camss *camss)
 	if (camss->version == CAMSS_8x96 ||
 	    camss->version == CAMSS_660)
 		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+	else if (camss->version == CAMSS_845)
+		nbr_pm_domains = PM_DOMAIN_TITAN_COUNT;
 
 	for (i = 0; i < nbr_pm_domains; i++) {
 		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
@@ -1273,6 +1281,12 @@ static int camss_probe(struct platform_device *pdev)
 		camss->csiphy_num = 3;
 		camss->csid_num = 4;
 		camss->vfe_num = 2;
+	} else if (of_device_is_compatible(dev->of_node,
+					   "qcom,sdm845-camss")) {
+		camss->version = CAMSS_845;
+		camss->csiphy_num = 4;
+		camss->csid_num = 3;
+		camss->vfe_num = 3;
 	} else {
 		ret = -EINVAL;
 		goto err_free;
@@ -1404,6 +1418,8 @@ void camss_delete(struct camss *camss)
 	if (camss->version == CAMSS_8x96 ||
 	    camss->version == CAMSS_660)
 		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+	else if (camss->version == CAMSS_845)
+		nbr_pm_domains = PM_DOMAIN_TITAN_COUNT;
 
 	for (i = 0; i < nbr_pm_domains; i++) {
 		device_link_del(camss->genpd_link[i]);
@@ -1437,6 +1453,7 @@ static const struct of_device_id camss_dt_match[] = {
 	{ .compatible = "qcom,msm8916-camss" },
 	{ .compatible = "qcom,msm8996-camss" },
 	{ .compatible = "qcom,sdm660-camss" },
+	{ .compatible = "qcom,sdm845-camss" },
 	{ }
 };
 
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 7560d85b3352..2f853557ed16 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -60,6 +60,8 @@ enum pm_domain {
 	PM_DOMAIN_VFE0 = 0,
 	PM_DOMAIN_VFE1 = 1,
 	PM_DOMAIN_CAMSS_COUNT = 2,	/* CAMSS series of ISPs */
+	PM_DOMAIN_VFELITE = 2,		/* VFELITE / TOP GDSC */
+	PM_DOMAIN_TITAN_COUNT = 3,	/* Titan series of ISPs */
 };
 
 enum camss_version {
@@ -83,8 +85,8 @@ struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-	struct device *genpd[PM_DOMAIN_CAMSS_COUNT];
-	struct device_link *genpd_link[PM_DOMAIN_CAMSS_COUNT];
+	struct device *genpd[PM_DOMAIN_TITAN_COUNT];
+	struct device_link *genpd_link[PM_DOMAIN_TITAN_COUNT];
 };
 
 struct camss_camera_interface {
-- 
2.27.0


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

* [PATCH v1 13/17] media: camss: Enable SDM845
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Enable support for SDM845 based Titan 170 ISPs.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 17 +++++++++++++++++
 drivers/media/platform/qcom/camss/camss.h |  6 ++++--
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 259ed094cee4..4dfae29c6327 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -897,6 +897,12 @@ static int camss_init_subdevices(struct camss *camss)
 		csid_res = csid_res_660;
 		ispif_res = &ispif_res_660;
 		vfe_res = vfe_res_660;
+	}  else if (camss->version == CAMSS_845) {
+		csiphy_res = csiphy_res_845;
+		csid_res = csid_res_845;
+		/* Titan VFEs don't have an ISPIF  */
+		ispif_res = NULL;
+		vfe_res = vfe_res_845;
 	} else {
 		return -EINVAL;
 	}
@@ -1205,6 +1211,8 @@ static int camss_configure_pd(struct camss *camss)
 	if (camss->version == CAMSS_8x96 ||
 	    camss->version == CAMSS_660)
 		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+	else if (camss->version == CAMSS_845)
+		nbr_pm_domains = PM_DOMAIN_TITAN_COUNT;
 
 	for (i = 0; i < nbr_pm_domains; i++) {
 		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
@@ -1273,6 +1281,12 @@ static int camss_probe(struct platform_device *pdev)
 		camss->csiphy_num = 3;
 		camss->csid_num = 4;
 		camss->vfe_num = 2;
+	} else if (of_device_is_compatible(dev->of_node,
+					   "qcom,sdm845-camss")) {
+		camss->version = CAMSS_845;
+		camss->csiphy_num = 4;
+		camss->csid_num = 3;
+		camss->vfe_num = 3;
 	} else {
 		ret = -EINVAL;
 		goto err_free;
@@ -1404,6 +1418,8 @@ void camss_delete(struct camss *camss)
 	if (camss->version == CAMSS_8x96 ||
 	    camss->version == CAMSS_660)
 		nbr_pm_domains = PM_DOMAIN_CAMSS_COUNT;
+	else if (camss->version == CAMSS_845)
+		nbr_pm_domains = PM_DOMAIN_TITAN_COUNT;
 
 	for (i = 0; i < nbr_pm_domains; i++) {
 		device_link_del(camss->genpd_link[i]);
@@ -1437,6 +1453,7 @@ static const struct of_device_id camss_dt_match[] = {
 	{ .compatible = "qcom,msm8916-camss" },
 	{ .compatible = "qcom,msm8996-camss" },
 	{ .compatible = "qcom,sdm660-camss" },
+	{ .compatible = "qcom,sdm845-camss" },
 	{ }
 };
 
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 7560d85b3352..2f853557ed16 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -60,6 +60,8 @@ enum pm_domain {
 	PM_DOMAIN_VFE0 = 0,
 	PM_DOMAIN_VFE1 = 1,
 	PM_DOMAIN_CAMSS_COUNT = 2,	/* CAMSS series of ISPs */
+	PM_DOMAIN_VFELITE = 2,		/* VFELITE / TOP GDSC */
+	PM_DOMAIN_TITAN_COUNT = 3,	/* Titan series of ISPs */
 };
 
 enum camss_version {
@@ -83,8 +85,8 @@ struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-	struct device *genpd[PM_DOMAIN_CAMSS_COUNT];
-	struct device_link *genpd_link[PM_DOMAIN_CAMSS_COUNT];
+	struct device *genpd[PM_DOMAIN_TITAN_COUNT];
+	struct device_link *genpd_link[PM_DOMAIN_TITAN_COUNT];
 };
 
 struct camss_camera_interface {
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 14/17] arm64: defconfig: Build Qcom CAMSS as module
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Build camera ISP driver as a module.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 838301650a79..cb224d2af6a0 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -640,6 +640,7 @@ CONFIG_VIDEO_RENESAS_FDP1=m
 CONFIG_VIDEO_RENESAS_FCP=m
 CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_SDR_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_QCOM_CAMSS=m
 CONFIG_VIDEO_RCAR_DRIF=m
 CONFIG_VIDEO_IMX219=m
 CONFIG_VIDEO_OV5645=m
-- 
2.27.0


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

* [PATCH v1 14/17] arm64: defconfig: Build Qcom CAMSS as module
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Build camera ISP driver as a module.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 838301650a79..cb224d2af6a0 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -640,6 +640,7 @@ CONFIG_VIDEO_RENESAS_FDP1=m
 CONFIG_VIDEO_RENESAS_FCP=m
 CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_SDR_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_QCOM_CAMSS=m
 CONFIG_VIDEO_RCAR_DRIF=m
 CONFIG_VIDEO_IMX219=m
 CONFIG_VIDEO_OV5645=m
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 15/17] arm64: dts: sdm845: Add CAMSS ISP node
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add the camss dt node for sdm845.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 151 +++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index bcf888381f14..286d50fcd9a5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -3911,6 +3911,157 @@ videocc: clock-controller@ab00000 {
 			#reset-cells = <1>;
 		};
 
+		camss: camss@a00000 {
+			compatible = "qcom,sdm845-camss";
+			reg = <0 0xac65000 0 0x1000>,
+				<0 0xac66000 0 0x1000>,
+				<0 0xac67000 0 0x1000>,
+				<0 0xac68000 0 0x1000>,
+				<0 0xacb3000 0 0x1000>,
+				<0 0xacba000 0 0x1000>,
+				<0 0xacc8000 0 0x1000>,
+				<0 0xacaf000 0 0x4000>,
+				<0 0xacb6000 0 0x4000>,
+				<0 0xacc4000 0 0x4000>;
+			reg-names = "csiphy0",
+				"csiphy1",
+				"csiphy2",
+				"csiphy3",
+				"csid0",
+				"csid1",
+				"csid2",
+				"vfe0",
+				"vfe1",
+				"vfe_lite";
+			interrupts = <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "csiphy0",
+				"csiphy1",
+				"csiphy2",
+				"csiphy3",
+				"csid0",
+				"csid1",
+				"csid2",
+				"vfe0",
+				"vfe1",
+				"vfe_lite";
+			power-domains = <&clock_camcc IFE_0_GDSC>,
+					<&clock_camcc IFE_1_GDSC>,
+					<&clock_camcc TITAN_TOP_GDSC>;
+			clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+				<&gcc GCC_CAMERA_AXI_CLK>,
+				<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+				<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+				<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+				<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+				<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSIPHY0_CLK>,
+				<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY1_CLK>,
+				<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY2_CLK>,
+				<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY3_CLK>,
+				<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_AXI_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_1_AXI_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_LITE_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>;
+			clock-names = "gcc_camera_ahb",
+				"gcc_camera_axi",
+				"camnoc_axi",
+				"cpas_ahb",
+				"slow_ahb_src",
+				"soc_ahb",
+				"cphy_rx_src",
+				"csiphy0",
+				"csiphy0_timer_src",
+				"csiphy0_timer",
+				"csiphy1",
+				"csiphy1_timer_src",
+				"csiphy1_timer",
+				"csiphy2",
+				"csiphy2_timer_src",
+				"csiphy2_timer",
+				"csiphy3",
+				"csiphy3_timer_src",
+				"csiphy3_timer",
+				"vfe0_axi",
+				"vfe0",
+				"vfe0_src",
+				"vfe0_cphy_rx",
+				"csi0", /* renamed to fit naming-scheme of older hardware */
+				"csi0_src", /* renamed to fit naming-scheme of older hardware */
+				"vfe1_axi",
+				"vfe1",
+				"vfe1_src",
+				"vfe1_cphy_rx",
+				"csi1", /* renamed to fit naming-scheme of older hardware */
+				"csi1_src", /* renamed to fit naming-scheme of older hardware */
+				"vfe_lite",
+				"vfe_lite_src",
+				"vfe_lite_cphy_rx",
+				"csi2", /* renamed to fit naming-scheme of older hardware */
+				"csi2_src"; /* renamed to fit naming-scheme of older hardware */
+
+			iommus = <&apps_smmu 0x0808 0x0>,
+				 <&apps_smmu 0x0810 0x8>,
+				 <&apps_smmu 0x0c08 0x0>,
+				 <&apps_smmu 0x0c10 0x8>;
+			status = "disabled";
+
+			interconnects =
+				<&gladiator_noc MASTER_APPSS_PROC
+				 &config_noc SLAVE_CAMERA_CFG>,
+				<&mmss_noc MASTER_CAMNOC_HF0
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_HF0_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>,
+				<&mmss_noc MASTER_CAMNOC_HF1
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_HF1_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>,
+				<&mmss_noc MASTER_CAMNOC_SF
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_SF_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>;
+			interconnect-names = "cam_ahb",
+				"hf_1_mnoc", "hf_1_camnoc",
+				"hf_2_mnoc", "hf_2_camnoc",
+				"sf_1_mnoc", "sf_1_camnoc";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
 		cci: cci@ac4a000 {
 			compatible = "qcom,sdm845-cci";
 			#address-cells = <1>;
-- 
2.27.0


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

* [PATCH v1 15/17] arm64: dts: sdm845: Add CAMSS ISP node
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add the camss dt node for sdm845.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845.dtsi | 151 +++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index bcf888381f14..286d50fcd9a5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -3911,6 +3911,157 @@ videocc: clock-controller@ab00000 {
 			#reset-cells = <1>;
 		};
 
+		camss: camss@a00000 {
+			compatible = "qcom,sdm845-camss";
+			reg = <0 0xac65000 0 0x1000>,
+				<0 0xac66000 0 0x1000>,
+				<0 0xac67000 0 0x1000>,
+				<0 0xac68000 0 0x1000>,
+				<0 0xacb3000 0 0x1000>,
+				<0 0xacba000 0 0x1000>,
+				<0 0xacc8000 0 0x1000>,
+				<0 0xacaf000 0 0x4000>,
+				<0 0xacb6000 0 0x4000>,
+				<0 0xacc4000 0 0x4000>;
+			reg-names = "csiphy0",
+				"csiphy1",
+				"csiphy2",
+				"csiphy3",
+				"csid0",
+				"csid1",
+				"csid2",
+				"vfe0",
+				"vfe1",
+				"vfe_lite";
+			interrupts = <GIC_SPI 477 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 478 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 479 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 468 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>,
+				<GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "csiphy0",
+				"csiphy1",
+				"csiphy2",
+				"csiphy3",
+				"csid0",
+				"csid1",
+				"csid2",
+				"vfe0",
+				"vfe1",
+				"vfe_lite";
+			power-domains = <&clock_camcc IFE_0_GDSC>,
+					<&clock_camcc IFE_1_GDSC>,
+					<&clock_camcc TITAN_TOP_GDSC>;
+			clocks = <&gcc GCC_CAMERA_AHB_CLK>,
+				<&gcc GCC_CAMERA_AXI_CLK>,
+				<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+				<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+				<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+				<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+				<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSIPHY0_CLK>,
+				<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY1_CLK>,
+				<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY2_CLK>,
+				<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_CSIPHY3_CLK>,
+				<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>,
+				<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_AXI_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_1_AXI_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_LITE_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>,
+				<&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>,
+				<&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>;
+			clock-names = "gcc_camera_ahb",
+				"gcc_camera_axi",
+				"camnoc_axi",
+				"cpas_ahb",
+				"slow_ahb_src",
+				"soc_ahb",
+				"cphy_rx_src",
+				"csiphy0",
+				"csiphy0_timer_src",
+				"csiphy0_timer",
+				"csiphy1",
+				"csiphy1_timer_src",
+				"csiphy1_timer",
+				"csiphy2",
+				"csiphy2_timer_src",
+				"csiphy2_timer",
+				"csiphy3",
+				"csiphy3_timer_src",
+				"csiphy3_timer",
+				"vfe0_axi",
+				"vfe0",
+				"vfe0_src",
+				"vfe0_cphy_rx",
+				"csi0", /* renamed to fit naming-scheme of older hardware */
+				"csi0_src", /* renamed to fit naming-scheme of older hardware */
+				"vfe1_axi",
+				"vfe1",
+				"vfe1_src",
+				"vfe1_cphy_rx",
+				"csi1", /* renamed to fit naming-scheme of older hardware */
+				"csi1_src", /* renamed to fit naming-scheme of older hardware */
+				"vfe_lite",
+				"vfe_lite_src",
+				"vfe_lite_cphy_rx",
+				"csi2", /* renamed to fit naming-scheme of older hardware */
+				"csi2_src"; /* renamed to fit naming-scheme of older hardware */
+
+			iommus = <&apps_smmu 0x0808 0x0>,
+				 <&apps_smmu 0x0810 0x8>,
+				 <&apps_smmu 0x0c08 0x0>,
+				 <&apps_smmu 0x0c10 0x8>;
+			status = "disabled";
+
+			interconnects =
+				<&gladiator_noc MASTER_APPSS_PROC
+				 &config_noc SLAVE_CAMERA_CFG>,
+				<&mmss_noc MASTER_CAMNOC_HF0
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_HF0_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>,
+				<&mmss_noc MASTER_CAMNOC_HF1
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_HF1_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>,
+				<&mmss_noc MASTER_CAMNOC_SF
+				 &mmss_noc SLAVE_EBI1>,
+				<&mmss_noc MASTER_CAMNOC_SF_UNCOMP
+				 &mmss_noc SLAVE_CAMNOC_UNCOMP>;
+			interconnect-names = "cam_ahb",
+				"hf_1_mnoc", "hf_1_camnoc",
+				"hf_2_mnoc", "hf_2_camnoc",
+				"sf_1_mnoc", "sf_1_camnoc";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
 		cci: cci@ac4a000 {
 			compatible = "qcom,sdm845-cci";
 			#address-cells = <1>;
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Add regulators and camss DT node.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
index a943b3f353ce..7bad0515345e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
 			regulator-max-microvolt = <1028000>;
 		};
 
+		vdda_mipi_csi0_0p9:
+		vdda_mipi_csi1_0p9:
+		vdda_mipi_csi2_0p9:
 		vreg_l1a_0p875: ldo1 {
 			regulator-min-microvolt = <880000>;
 			regulator-max-microvolt = <880000>;
@@ -1106,6 +1109,15 @@ &cci {
 	status = "okay";
 };
 
+&camss {
+	vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
+	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
+	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
+
+	status = "disabled";
+
+};
+
 &cci_i2c0 {
 	camera@10 {
 		compatible = "ovti,ov8856";
-- 
2.27.0


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

* [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Add regulators and camss DT node.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
index a943b3f353ce..7bad0515345e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
 			regulator-max-microvolt = <1028000>;
 		};
 
+		vdda_mipi_csi0_0p9:
+		vdda_mipi_csi1_0p9:
+		vdda_mipi_csi2_0p9:
 		vreg_l1a_0p875: ldo1 {
 			regulator-min-microvolt = <880000>;
 			regulator-max-microvolt = <880000>;
@@ -1106,6 +1109,15 @@ &cci {
 	status = "okay";
 };
 
+&camss {
+	vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
+	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
+	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
+
+	status = "disabled";
+
+};
+
 &cci_i2c0 {
 	camera@10 {
 		compatible = "ovti,ov8856";
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v1 17/17] arm64: dts: sdm845-db845c: Enable ov8856 sensor and connect to ISP
  2021-01-08 12:04 ` Robert Foss
@ 2021-01-08 12:04   ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Enable camss & ov8856 DT nodes.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
index 7bad0515345e..94a15d4bd05d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -1114,8 +1114,20 @@ &camss {
 	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
 	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
 
-	status = "disabled";
+	status = "ok";
 
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port@0 {
+			reg = <0>;
+			csiphy0_ep: endpoint {
+				clock-lanes = <1>;
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&ov8856_ep>;
+			};
+		};
+	};
 };
 
 &cci_i2c0 {
@@ -1147,7 +1159,7 @@ camera@10 {
 		avdd-supply = <&cam0_avdd_2v8>;
 		dvdd-supply = <&cam0_dvdd_1v2>;
 
-		status = "disable";
+		status = "ok";
 
 		port {
 			ov8856_ep: endpoint {
@@ -1155,7 +1167,7 @@ ov8856_ep: endpoint {
 				link-frequencies = /bits/ 64
 					<360000000 180000000>;
 				data-lanes = <1 2 3 4>;
-//				remote-endpoint = <&csiphy0_ep>;
+				remote-endpoint = <&csiphy0_ep>;
 			};
 		};
 	};
-- 
2.27.0


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

* [PATCH v1 17/17] arm64: dts: sdm845-db845c: Enable ov8856 sensor and connect to ISP
@ 2021-01-08 12:04   ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-08 12:04 UTC (permalink / raw)
  To: agross, bjorn.andersson, robert.foss, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno, Andrey Konovalov
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Enable camss & ov8856 DT nodes.

Signed-off-by: Robert Foss <robert.foss@linaro.org>
---
 arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
index 7bad0515345e..94a15d4bd05d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
@@ -1114,8 +1114,20 @@ &camss {
 	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
 	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
 
-	status = "disabled";
+	status = "ok";
 
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port@0 {
+			reg = <0>;
+			csiphy0_ep: endpoint {
+				clock-lanes = <1>;
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&ov8856_ep>;
+			};
+		};
+	};
 };
 
 &cci_i2c0 {
@@ -1147,7 +1159,7 @@ camera@10 {
 		avdd-supply = <&cam0_avdd_2v8>;
 		dvdd-supply = <&cam0_dvdd_1v2>;
 
-		status = "disable";
+		status = "ok";
 
 		port {
 			ov8856_ep: endpoint {
@@ -1155,7 +1167,7 @@ ov8856_ep: endpoint {
 				link-frequencies = /bits/ 64
 					<360000000 180000000>;
 				data-lanes = <1 2 3 4>;
-//				remote-endpoint = <&csiphy0_ep>;
+				remote-endpoint = <&csiphy0_ep>;
 			};
 		};
 	};
-- 
2.27.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 05/17] media: camss: Refactor VFE HW version support
  2021-01-08 12:04 ` [PATCH v1 05/17] media: camss: Refactor VFE HW version support Robert Foss
@ 2021-01-08 16:51   ` kernel test robot
  2021-01-13 22:38   ` Andrey Konovalov
  1 sibling, 0 replies; 65+ messages in thread
From: kernel test robot @ 2021-01-08 16:51 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 3491 bytes --]

Hi Robert,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on arm64/for-next/core v5.11-rc2 next-20210108]
[cannot apply to robh/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Robert-Foss/Add-support-for-SDM845-Camera-Subsystem/20210108-200847
base:   git://linuxtv.org/media_tree.git master
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/22217b7d1cc61585735ff89636574a0d88f609e0
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Robert-Foss/Add-support-for-SDM845-Camera-Subsystem/20210108-200847
        git checkout 22217b7d1cc61585735ff89636574a0d88f609e0
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/dev_printk.h:14,
                    from include/linux/device.h:15,
                    from drivers/media/platform/qcom/camss/camss.h:13,
                    from drivers/media/platform/qcom/camss/camss-vfe-gen1.c:11:
   include/linux/scatterlist.h: In function 'sg_set_buf':
   arch/m68k/include/asm/page_mm.h:174:49: warning: ordered comparison of pointer with null pointer [-Wextra]
     174 | #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
         |                                                 ^~
   include/linux/compiler.h:78:42: note: in definition of macro 'unlikely'
      78 | # define unlikely(x) __builtin_expect(!!(x), 0)
         |                                          ^
   include/linux/scatterlist.h:137:2: note: in expansion of macro 'BUG_ON'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |  ^~~~~~
   include/linux/scatterlist.h:137:10: note: in expansion of macro 'virt_addr_valid'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |          ^~~~~~~~~~~~~~~
   drivers/media/platform/qcom/camss/camss-vfe-gen1.c: In function 'vfe_output_update_pong_addr':
>> drivers/media/platform/qcom/camss/camss-vfe-gen1.c:411:6: warning: variable 'addr' set but not used [-Wunused-but-set-variable]
     411 |  u32 addr;
         |      ^~~~


vim +/addr +411 drivers/media/platform/qcom/camss/camss-vfe-gen1.c

   406	
   407	static void vfe_output_update_pong_addr(struct vfe_device *vfe,
   408						struct vfe_output *output, u8 sync,
   409						struct vfe_line *line)
   410	{
 > 411		u32 addr;
   412		unsigned int i;
   413	
   414		for (i = 0; i < output->wm_num; i++) {
   415			if (output->buf[1])
   416				addr = output->buf[1]->addr[i];
   417			else
   418				addr = 0;
   419	
   420			// XXX
   421		}
   422	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 59584 bytes --]

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

* Re: [PATCH v1 08/17] media: camss: Refactor CSID HW version support
  2021-01-08 12:04   ` Robert Foss
  (?)
@ 2021-01-08 18:02   ` kernel test robot
  -1 siblings, 0 replies; 65+ messages in thread
From: kernel test robot @ 2021-01-08 18:02 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 9826 bytes --]

Hi Robert,

I love your patch! Yet something to improve:

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on arm64/for-next/core v5.11-rc2 next-20210108]
[cannot apply to robh/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Robert-Foss/Add-support-for-SDM845-Camera-Subsystem/20210108-200847
base:   git://linuxtv.org/media_tree.git master
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/5a42146d4fd78efec431538aa957118944f135b0
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Robert-Foss/Add-support-for-SDM845-Camera-Subsystem/20210108-200847
        git checkout 5a42146d4fd78efec431538aa957118944f135b0
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from include/linux/err.h:5,
                    from include/linux/clk.h:12,
                    from drivers/media/platform/qcom/camss/camss.c:10:
   include/linux/scatterlist.h: In function 'sg_set_buf':
   arch/m68k/include/asm/page_mm.h:174:49: warning: ordered comparison of pointer with null pointer [-Wextra]
     174 | #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
         |                                                 ^~
   include/linux/compiler.h:78:42: note: in definition of macro 'unlikely'
      78 | # define unlikely(x) __builtin_expect(!!(x), 0)
         |                                          ^
   include/linux/scatterlist.h:137:2: note: in expansion of macro 'BUG_ON'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |  ^~~~~~
   include/linux/scatterlist.h:137:10: note: in expansion of macro 'virt_addr_valid'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |          ^~~~~~~~~~~~~~~
   In file included from drivers/media/platform/qcom/camss/camss.h:21,
                    from drivers/media/platform/qcom/camss/camss.c:28:
   drivers/media/platform/qcom/camss/camss-csid.h: At top level:
>> drivers/media/platform/qcom/camss/camss-csid.h:154:2: error: expected specifier-qualifier-list before 'irqreturn_t'
     154 |  irqreturn_t (*isr)(int irq, void *dev);
         |  ^~~~~~~~~~~
   drivers/media/platform/qcom/camss/camss.c:468:31: warning: 'vfe_res_845' defined but not used [-Wunused-const-variable=]
     468 | static const struct resources vfe_res_845[] = {
         |                               ^~~~~~~~~~~
   In file included from drivers/media/platform/qcom/camss/camss.h:21,
                    from drivers/media/platform/qcom/camss/camss.c:28:
   drivers/media/platform/qcom/camss/camss-csid.h:91:27: warning: 'csid_testgen_modes' defined but not used [-Wunused-const-variable=]
      91 | static const char * const csid_testgen_modes[] = {
         |                           ^~~~~~~~~~~~~~~~~~
--
   In file included from include/linux/dev_printk.h:14,
                    from include/linux/device.h:15,
                    from drivers/media/platform/qcom/camss/camss.h:13,
                    from drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c:11:
   include/linux/scatterlist.h: In function 'sg_set_buf':
   arch/m68k/include/asm/page_mm.h:174:49: warning: ordered comparison of pointer with null pointer [-Wextra]
     174 | #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
         |                                                 ^~
   include/linux/compiler.h:78:42: note: in definition of macro 'unlikely'
      78 | # define unlikely(x) __builtin_expect(!!(x), 0)
         |                                          ^
   include/linux/scatterlist.h:137:2: note: in expansion of macro 'BUG_ON'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |  ^~~~~~
   include/linux/scatterlist.h:137:10: note: in expansion of macro 'virt_addr_valid'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |          ^~~~~~~~~~~~~~~
   In file included from drivers/media/platform/qcom/camss/camss.h:21,
                    from drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c:11:
   drivers/media/platform/qcom/camss/camss-csid.h: At top level:
>> drivers/media/platform/qcom/camss/camss-csid.h:154:2: error: expected specifier-qualifier-list before 'irqreturn_t'
     154 |  irqreturn_t (*isr)(int irq, void *dev);
         |  ^~~~~~~~~~~
   drivers/media/platform/qcom/camss/camss-csid.h:91:27: warning: 'csid_testgen_modes' defined but not used [-Wunused-const-variable=]
      91 | static const char * const csid_testgen_modes[] = {
         |                           ^~~~~~~~~~~~~~~~~~
--
   In file included from include/linux/dev_printk.h:14,
                    from include/linux/device.h:15,
                    from drivers/media/platform/qcom/camss/camss.h:13,
                    from drivers/media/platform/qcom/camss/camss-vfe-gen1.c:11:
   include/linux/scatterlist.h: In function 'sg_set_buf':
   arch/m68k/include/asm/page_mm.h:174:49: warning: ordered comparison of pointer with null pointer [-Wextra]
     174 | #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
         |                                                 ^~
   include/linux/compiler.h:78:42: note: in definition of macro 'unlikely'
      78 | # define unlikely(x) __builtin_expect(!!(x), 0)
         |                                          ^
   include/linux/scatterlist.h:137:2: note: in expansion of macro 'BUG_ON'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |  ^~~~~~
   include/linux/scatterlist.h:137:10: note: in expansion of macro 'virt_addr_valid'
     137 |  BUG_ON(!virt_addr_valid(buf));
         |          ^~~~~~~~~~~~~~~
   In file included from drivers/media/platform/qcom/camss/camss.h:21,
                    from drivers/media/platform/qcom/camss/camss-vfe-gen1.c:11:
   drivers/media/platform/qcom/camss/camss-csid.h: At top level:
>> drivers/media/platform/qcom/camss/camss-csid.h:154:2: error: expected specifier-qualifier-list before 'irqreturn_t'
     154 |  irqreturn_t (*isr)(int irq, void *dev);
         |  ^~~~~~~~~~~
   drivers/media/platform/qcom/camss/camss-vfe-gen1.c: In function 'vfe_output_update_pong_addr':
   drivers/media/platform/qcom/camss/camss-vfe-gen1.c:411:6: warning: variable 'addr' set but not used [-Wunused-but-set-variable]
     411 |  u32 addr;
         |      ^~~~
   In file included from drivers/media/platform/qcom/camss/camss.h:21,
                    from drivers/media/platform/qcom/camss/camss-vfe-gen1.c:11:
   At top level:
   drivers/media/platform/qcom/camss/camss-csid.h:91:27: warning: 'csid_testgen_modes' defined but not used [-Wunused-const-variable=]
      91 | static const char * const csid_testgen_modes[] = {
         |                           ^~~~~~~~~~~~~~~~~~


vim +/irqreturn_t +154 drivers/media/platform/qcom/camss/camss-csid.h

   126	
   127	struct csid_hw_ops {
   128		/*
   129		 * configure_stream - Configures and starts CSID input stream
   130		 * @csid: CSID device
   131		 */
   132		void (*configure_stream)(struct csid_device *csid, u8 enable);
   133	
   134		/*
   135		 * configure_testgen_pattern - Validates and configures output pattern mode
   136		 * of test pattern generator
   137		 * @csid: CSID device
   138		 */
   139		int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);
   140	
   141		/*
   142		 * hw_version - Read hardware version register from hardware
   143		 * @csid: CSID device
   144		 */
   145		u32 (*hw_version)(struct csid_device *csid);
   146	
   147		/*
   148		 * isr - CSID module interrupt service routine
   149		 * @irq: Interrupt line
   150		 * @dev: CSID device
   151		 *
   152		 * Return IRQ_HANDLED on success
   153		 */
 > 154		irqreturn_t (*isr)(int irq, void *dev);
   155	
   156		/*
   157		 * reset - Trigger reset on CSID module and wait to complete
   158		 * @csid: CSID device
   159		 *
   160		 * Return 0 on success or a negative error code otherwise
   161		 */
   162		int (*reset)(struct csid_device *csid);
   163	
   164		/*
   165		 * src_pad_code - Pick an output/src format based on the input/sink format
   166		 * @csid: CSID device
   167		 * @sink_code: The sink format of the input
   168		 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.
   169		 *	Set @match_code to 0 if used.
   170		 * @match_code: Request preferred code, set @match_format_idx to 0 if used
   171		 *
   172		 * Return 0 on failure or src format code otherwise
   173		 */
   174		u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
   175				    unsigned int match_format_idx, u32 match_code);
   176	
   177		/*
   178		 * subdev_init - Initialize CSID device according for hardware revision
   179		 * @csid: CSID device
   180		 */
   181		void (*subdev_init)(struct csid_device *csid);
   182	};
   183	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 59584 bytes --]

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

* Re: [PATCH v1 01/17] media: camss: Fix comment using wrong function name
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-08 18:51     ` Bjorn Andersson
  -1 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 18:51 UTC (permalink / raw)
  To: Robert Foss
  Cc: agross, todor.too, mchehab, robh+dt, catalin.marinas, will,
	shawnguo, leoyang.li, geert+renesas, arnd, Anson.Huang, michael,
	agx, max.oss.09, linux-arm-msm, linux-media, devicetree,
	linux-kernel, linux-arm-kernel, AngeloGioacchino Del Regno,
	Andrey Konovalov, Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed,
	Sarvesh Sridutt, Laurent Pinchart

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> Function name is comment is wrong, and was changed to be
> the same as the actual function name.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index fae2b513b2f9..478be4f0cab5 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
>  }
>  
>  /*
> - * vfe_isr_wm_done - Process composite image done interrupt
> + * vfe_isr_comp_done - Process composite image done interrupt

It's a function, so it should be "vfe_isr_comp_done()", but unless the
comment is denoted kerneldoc by starting with '/' followed by two '*' it
"doesn't matter".

As a matter of fact, none of the kerneldoc in this file has the proper
'/**' start, so this file is "undocumented".

So please add another '*' and some () throughout the file.

Regards,
Bjorn

>   * @vfe: VFE Device
>   * @comp: Composite image id
>   */
> -- 
> 2.27.0
> 

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

* Re: [PATCH v1 01/17] media: camss: Fix comment using wrong function name
@ 2021-01-08 18:51     ` Bjorn Andersson
  0 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 18:51 UTC (permalink / raw)
  To: Robert Foss
  Cc: geert+renesas, catalin.marinas, agx, todor.too, Laurent Pinchart,
	AngeloGioacchino Del Regno, will, Anson.Huang, agross,
	Andrey Konovalov, linux-media, devicetree, Tomasz Figa, arnd,
	linux-arm-msm, robh+dt, mchehab, linux-arm-kernel,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> Function name is comment is wrong, and was changed to be
> the same as the actual function name.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index fae2b513b2f9..478be4f0cab5 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
>  }
>  
>  /*
> - * vfe_isr_wm_done - Process composite image done interrupt
> + * vfe_isr_comp_done - Process composite image done interrupt

It's a function, so it should be "vfe_isr_comp_done()", but unless the
comment is denoted kerneldoc by starting with '/' followed by two '*' it
"doesn't matter".

As a matter of fact, none of the kerneldoc in this file has the proper
'/**' start, so this file is "undocumented".

So please add another '*' and some () throughout the file.

Regards,
Bjorn

>   * @vfe: VFE Device
>   * @comp: Composite image id
>   */
> -- 
> 2.27.0
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-08 18:51     ` Bjorn Andersson
  -1 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 18:51 UTC (permalink / raw)
  To: Robert Foss
  Cc: agross, todor.too, mchehab, robh+dt, catalin.marinas, will,
	shawnguo, leoyang.li, geert+renesas, arnd, Anson.Huang, michael,
	agx, max.oss.09, linux-arm-msm, linux-media, devicetree,
	linux-kernel, linux-arm-kernel, AngeloGioacchino Del Regno,
	Andrey Konovalov, Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed,
	Sarvesh Sridutt, Laurent Pinchart

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> Comment refers to ISPIF, but this is incorrect. Only
> the VFE interrupts are handled by this function.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

Regards,
Bjorn

> ---
>  drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
>  drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> 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 174a36be6f5d..a1b56b89130d 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> @@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
>  }
>  
>  /*
> - * vfe_isr - ISPIF module interrupt handler
> + * vfe_isr - VFE module interrupt handler
>   * @irq: Interrupt line
>   * @dev: VFE device
>   *
> 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 b5704a2f119b..84c33b8f9fe3 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> @@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
>  }
>  
>  /*
> - * vfe_isr - ISPIF module interrupt handler
> + * vfe_isr - VFE module interrupt handler
>   * @irq: Interrupt line
>   * @dev: VFE device
>   *
> -- 
> 2.27.0
> 

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

* Re: [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
@ 2021-01-08 18:51     ` Bjorn Andersson
  0 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 18:51 UTC (permalink / raw)
  To: Robert Foss
  Cc: geert+renesas, catalin.marinas, agx, todor.too, Laurent Pinchart,
	AngeloGioacchino Del Regno, will, Anson.Huang, agross,
	Andrey Konovalov, linux-media, devicetree, Tomasz Figa, arnd,
	linux-arm-msm, robh+dt, mchehab, linux-arm-kernel,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> Comment refers to ISPIF, but this is incorrect. Only
> the VFE interrupts are handled by this function.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

Regards,
Bjorn

> ---
>  drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
>  drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> 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 174a36be6f5d..a1b56b89130d 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> @@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
>  }
>  
>  /*
> - * vfe_isr - ISPIF module interrupt handler
> + * vfe_isr - VFE module interrupt handler
>   * @irq: Interrupt line
>   * @dev: VFE device
>   *
> 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 b5704a2f119b..84c33b8f9fe3 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> @@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
>  }
>  
>  /*
> - * vfe_isr - ISPIF module interrupt handler
> + * vfe_isr - VFE module interrupt handler
>   * @irq: Interrupt line
>   * @dev: VFE device
>   *
> -- 
> 2.27.0
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-08 19:07     ` Bjorn Andersson
  -1 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 19:07 UTC (permalink / raw)
  To: Robert Foss
  Cc: agross, todor.too, mchehab, robh+dt, catalin.marinas, will,
	shawnguo, leoyang.li, geert+renesas, arnd, Anson.Huang, michael,
	agx, max.oss.09, linux-arm-msm, linux-media, devicetree,
	linux-kernel, linux-arm-kernel, AngeloGioacchino Del Regno,
	Andrey Konovalov, Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed,
	Sarvesh Sridutt, Laurent Pinchart

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> This driver supports multiple architecture versions of the Qualcomm ISP.
> The CAMSS architecure which this driver is name after, and with the
> introduction of this series, the Titan architecture.
> 
> The ISPIF is IP-block that is only present in the CAMSS architecture.

"is an IP-block"

> In order to support the Titan architecture, make the ISPIF an optional
> subdevice.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
>  .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
>  drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
>  drivers/media/platform/qcom/camss/camss.h     |   2 +-
>  4 files changed, 160 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
[..]
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>  			  const struct resources_ispif *res)
>  {
> -	struct device *dev = to_device(ispif);
> -	struct platform_device *pdev = to_platform_device(dev);
> +	struct ispif_device *ispif = camss->ispif;
> +	struct platform_device *pdev = to_platform_device(camss->dev);

It seems like several of the changes in this function is replacing
dev with camss->dev. If you retained a struct device *dev = camss->dev;
you would avoid this.

>  	struct resource *r;
>  	int i;
>  	int ret;
>  
> +	if (res == NULL && ispif == NULL)

Afaict this function is called conditional on camss->ispif != NULL, and
I don't see anything that would cause res to becomes NULL if is hasn't
been before this change.

So I think this check is unnecessary?

> +		return 0;
> +
> +	ispif->camss = camss;
> +
>  	/* Number of ISPIF lines - same as number of CSID hardware modules */
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> +	if (camss->version == CAMSS_8x16)
>  		ispif->line_num = 2;
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
>  		ispif->line_num = 4;
>  	else
>  		return -EINVAL;
>  
> -	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> -				   GFP_KERNEL);
> +	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> +			sizeof(*ispif->line), GFP_KERNEL);
>  	if (!ispif->line)
>  		return -ENOMEM;
>  
[..]
> @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
>  {
>  	int i;
>  
> +	if (!ispif)
> +		return;

I like this, but later in the patch you make the calls to this function
conditional on ispif != NULL. You should only need one of the checks.

Regards,
Bjorn

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
@ 2021-01-08 19:07     ` Bjorn Andersson
  0 siblings, 0 replies; 65+ messages in thread
From: Bjorn Andersson @ 2021-01-08 19:07 UTC (permalink / raw)
  To: Robert Foss
  Cc: geert+renesas, catalin.marinas, agx, todor.too, Laurent Pinchart,
	AngeloGioacchino Del Regno, will, Anson.Huang, agross,
	Andrey Konovalov, linux-media, devicetree, Tomasz Figa, arnd,
	linux-arm-msm, robh+dt, mchehab, linux-arm-kernel,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:

> This driver supports multiple architecture versions of the Qualcomm ISP.
> The CAMSS architecure which this driver is name after, and with the
> introduction of this series, the Titan architecture.
> 
> The ISPIF is IP-block that is only present in the CAMSS architecture.

"is an IP-block"

> In order to support the Titan architecture, make the ISPIF an optional
> subdevice.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
>  .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
>  drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
>  drivers/media/platform/qcom/camss/camss.h     |   2 +-
>  4 files changed, 160 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
[..]
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>  			  const struct resources_ispif *res)
>  {
> -	struct device *dev = to_device(ispif);
> -	struct platform_device *pdev = to_platform_device(dev);
> +	struct ispif_device *ispif = camss->ispif;
> +	struct platform_device *pdev = to_platform_device(camss->dev);

It seems like several of the changes in this function is replacing
dev with camss->dev. If you retained a struct device *dev = camss->dev;
you would avoid this.

>  	struct resource *r;
>  	int i;
>  	int ret;
>  
> +	if (res == NULL && ispif == NULL)

Afaict this function is called conditional on camss->ispif != NULL, and
I don't see anything that would cause res to becomes NULL if is hasn't
been before this change.

So I think this check is unnecessary?

> +		return 0;
> +
> +	ispif->camss = camss;
> +
>  	/* Number of ISPIF lines - same as number of CSID hardware modules */
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> +	if (camss->version == CAMSS_8x16)
>  		ispif->line_num = 2;
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
>  		ispif->line_num = 4;
>  	else
>  		return -EINVAL;
>  
> -	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> -				   GFP_KERNEL);
> +	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> +			sizeof(*ispif->line), GFP_KERNEL);
>  	if (!ispif->line)
>  		return -ENOMEM;
>  
[..]
> @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
>  {
>  	int i;
>  
> +	if (!ispif)
> +		return;

I like this, but later in the patch you make the calls to this function
conditional on ispif != NULL. You should only need one of the checks.

Regards,
Bjorn

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 12/17] media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss
  2021-01-08 12:04   ` [PATCH v1 12/17] media: dt-bindings: media: qcom, camss: " Robert Foss
@ 2021-01-09  1:44     ` Laurent Pinchart
  -1 siblings, 0 replies; 65+ messages in thread
From: Laurent Pinchart @ 2021-01-09  1:44 UTC (permalink / raw)
  To: Robert Foss
  Cc: agross, bjorn.andersson, todor.too, mchehab, robh+dt,
	catalin.marinas, will, shawnguo, leoyang.li, geert+renesas, arnd,
	Anson.Huang, michael, agx, max.oss.09, linux-arm-msm,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt

Hi Rob,

Thank you for the patch.

On Fri, Jan 08, 2021 at 01:04:24PM +0100, Robert Foss wrote:
> Add bindings for qcom,sdm845-camss in order to support the camera
> subsystem on SDM845.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  .../devicetree/bindings/media/qcom,camss.txt  | 51 +++++++++++++++----
>  1 file changed, 40 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/qcom,camss.txt b/Documentation/devicetree/bindings/media/qcom,camss.txt
> index 498234629e21..276c5d0c25cb 100644
> --- a/Documentation/devicetree/bindings/media/qcom,camss.txt
> +++ b/Documentation/devicetree/bindings/media/qcom,camss.txt
> @@ -9,6 +9,7 @@ Qualcomm Camera Subsystem
>  		- "qcom,msm8916-camss"
>  		- "qcom,msm8996-camss"
>  		- "qcom,sdm660-camss"
> +		- "qcom,sdm845-camss"
>  - reg:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -18,19 +19,21 @@ Qualcomm Camera Subsystem
>  	Value type: <stringlist>
>  	Definition: Should contain the following entries:
>  		- "csiphy0"
> -		- "csiphy0_clk_mux"
> +		- "csiphy0_clk_mux"	(not 845)
>  		- "csiphy1"
> -		- "csiphy1_clk_mux"
> -		- "csiphy2"		(8996 only)
> +		- "csiphy1_clk_mux"	(not 845)
> +		- "csiphy2"		(8996 & 845)
>  		- "csiphy2_clk_mux"	(8996 only)
> +		- "csiphy3"		(845 only)
>  		- "csid0"
>  		- "csid1"
> -		- "csid2"		(8996 only)
> -		- "csid3"		(8996 only)
> +		- "csid2"		(8996 & 845)
> +		- "csid3"		(8996 & 845)
>  		- "ispif"
> -		- "csi_clk_mux"
> +		- "csi_clk_mux"		(not 845)
>  		- "vfe0"
> -		- "vfe1"		(8996 only)
> +		- "vfe1"		(8996 & 845)
> +		- "vfe_lite"		(845 only)

All this would be more readable after a conversion to YAML ;-)

>  - interrupts:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -41,14 +44,16 @@ Qualcomm Camera Subsystem
>  	Definition: Should contain the following entries:
>  		- "csiphy0"
>  		- "csiphy1"
> -		- "csiphy2"		(8996 only)
> +		- "csiphy2"		(8996 & 845)
> +		- "csiphy3"		(845 only)
>  		- "csid0"
>  		- "csid1"
> -		- "csid2"		(8996 only)
> +		- "csid2"		(8996 & 845)
>  		- "csid3"		(8996 only)
>  		- "ispif"
>  		- "vfe0"
> -		- "vfe1"		(8996 only)
> +		- "vfe1"		(8996 & 845)
> +		- "vfe_lite"		(845 only)
>  - power-domains:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -67,27 +72,40 @@ Qualcomm Camera Subsystem
>  		- "top_ahb"
>  		- "throttle_axi"	(660 only)
>  		- "ispif_ahb"
> +		- "camnoc_axi"		(845 only)
> +		- "cpas_ahb"		(845 only)
> +		- "cphy_rx_src"		(856 only)
>  		- "csiphy0_timer"
> +		- "csiphy0"		(845 only)
> +		- "csiphy0_timer_src"	(845 only)
>  		- "csiphy1_timer"
> -		- "csiphy2_timer"	(8996 only)
> +		- "csiphy2"		(845 only)
> +		- "csiphy2_timer_src"	(845 only)
> +		- "csiphy2_timer"	(8996 & 845)
> +		- "csiphy3"		(845 only)
> +		- "csiphy3_timer_src"	(845 only)
> +		- "csiphy3_timer"	(845 only)
>  		- "csiphy_ahb2crif"	(660 only)
>  		- "csi0_ahb"
>  		- "csi0"
>  		- "csi0_phy"
>  		- "csi0_pix"
>  		- "csi0_rdi"
> +		- "csi0_src"		(845 only)
>  		- "cphy_csid0"		(660 only)
>  		- "csi1_ahb"
>  		- "csi1"
>  		- "csi1_phy"
>  		- "csi1_pix"
>  		- "csi1_rdi"
> +		- "csi1_src"		(845 only)
>  		- "cphy_csid1"		(660 only)
>  		- "csi2_ahb"		(8996 only)
>  		- "csi2"		(8996 only)
>  		- "csi2_phy"		(8996 only)
>  		- "csi2_pix"		(8996 only)
>  		- "csi2_rdi"		(8996 only)
> +		- "csi2_src"		(845 only)
>  		- "cphy_csid2"		(660 only)
>  		- "csi3_ahb"		(8996 only)
>  		- "csi3"		(8996 only)
> @@ -96,14 +114,25 @@ Qualcomm Camera Subsystem
>  		- "csi3_rdi"		(8996 only)
>  		- "cphy_csid3"		(660 only)
>  		- "ahb"
> +		- "slow_ahb_src"	(845 only)
> +		- "soc_ahb"		(845 only)
>  		- "vfe0"
>  		- "csi_vfe0"
>  		- "vfe0_ahb",		(8996 only)
> +		- "vfe0_cphy_rx"	(845 only)
> +		- "vfe0_axi",		(845 only)
> +		- "vfe0_src",		(845 only)
>  		- "vfe0_stream",	(8996 only)
>  		- "vfe1",		(8996 only)
>  		- "csi_vfe1",		(8996 only)
>  		- "vfe1_ahb",		(8996 only)
> +		- "vfe1_cphy_rx"	(845 only)
> +		- "vfe1_axi",		(845 only)
> +		- "vfe1_src",		(845 only)
>  		- "vfe1_stream",	(8996 only)
> +		- "vfe_lite_axi",	(845 only)
> +		- "vfe_lite_cphy_rx"	(845 only)
> +		- "vfe_lite_src",	(845 only)
>  		- "vfe_ahb"
>  		- "vfe_axi"
>  - vdda-supply:

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v1 12/17] media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss
@ 2021-01-09  1:44     ` Laurent Pinchart
  0 siblings, 0 replies; 65+ messages in thread
From: Laurent Pinchart @ 2021-01-09  1:44 UTC (permalink / raw)
  To: Robert Foss
  Cc: geert+renesas, catalin.marinas, agx, todor.too, bjorn.andersson,
	AngeloGioacchino Del Regno, will, Anson.Huang, agross,
	Andrey Konovalov, linux-media, devicetree, Tomasz Figa, arnd,
	linux-arm-msm, robh+dt, mchehab, linux-arm-kernel,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Hi Rob,

Thank you for the patch.

On Fri, Jan 08, 2021 at 01:04:24PM +0100, Robert Foss wrote:
> Add bindings for qcom,sdm845-camss in order to support the camera
> subsystem on SDM845.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  .../devicetree/bindings/media/qcom,camss.txt  | 51 +++++++++++++++----
>  1 file changed, 40 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/qcom,camss.txt b/Documentation/devicetree/bindings/media/qcom,camss.txt
> index 498234629e21..276c5d0c25cb 100644
> --- a/Documentation/devicetree/bindings/media/qcom,camss.txt
> +++ b/Documentation/devicetree/bindings/media/qcom,camss.txt
> @@ -9,6 +9,7 @@ Qualcomm Camera Subsystem
>  		- "qcom,msm8916-camss"
>  		- "qcom,msm8996-camss"
>  		- "qcom,sdm660-camss"
> +		- "qcom,sdm845-camss"
>  - reg:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -18,19 +19,21 @@ Qualcomm Camera Subsystem
>  	Value type: <stringlist>
>  	Definition: Should contain the following entries:
>  		- "csiphy0"
> -		- "csiphy0_clk_mux"
> +		- "csiphy0_clk_mux"	(not 845)
>  		- "csiphy1"
> -		- "csiphy1_clk_mux"
> -		- "csiphy2"		(8996 only)
> +		- "csiphy1_clk_mux"	(not 845)
> +		- "csiphy2"		(8996 & 845)
>  		- "csiphy2_clk_mux"	(8996 only)
> +		- "csiphy3"		(845 only)
>  		- "csid0"
>  		- "csid1"
> -		- "csid2"		(8996 only)
> -		- "csid3"		(8996 only)
> +		- "csid2"		(8996 & 845)
> +		- "csid3"		(8996 & 845)
>  		- "ispif"
> -		- "csi_clk_mux"
> +		- "csi_clk_mux"		(not 845)
>  		- "vfe0"
> -		- "vfe1"		(8996 only)
> +		- "vfe1"		(8996 & 845)
> +		- "vfe_lite"		(845 only)

All this would be more readable after a conversion to YAML ;-)

>  - interrupts:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -41,14 +44,16 @@ Qualcomm Camera Subsystem
>  	Definition: Should contain the following entries:
>  		- "csiphy0"
>  		- "csiphy1"
> -		- "csiphy2"		(8996 only)
> +		- "csiphy2"		(8996 & 845)
> +		- "csiphy3"		(845 only)
>  		- "csid0"
>  		- "csid1"
> -		- "csid2"		(8996 only)
> +		- "csid2"		(8996 & 845)
>  		- "csid3"		(8996 only)
>  		- "ispif"
>  		- "vfe0"
> -		- "vfe1"		(8996 only)
> +		- "vfe1"		(8996 & 845)
> +		- "vfe_lite"		(845 only)
>  - power-domains:
>  	Usage: required
>  	Value type: <prop-encoded-array>
> @@ -67,27 +72,40 @@ Qualcomm Camera Subsystem
>  		- "top_ahb"
>  		- "throttle_axi"	(660 only)
>  		- "ispif_ahb"
> +		- "camnoc_axi"		(845 only)
> +		- "cpas_ahb"		(845 only)
> +		- "cphy_rx_src"		(856 only)
>  		- "csiphy0_timer"
> +		- "csiphy0"		(845 only)
> +		- "csiphy0_timer_src"	(845 only)
>  		- "csiphy1_timer"
> -		- "csiphy2_timer"	(8996 only)
> +		- "csiphy2"		(845 only)
> +		- "csiphy2_timer_src"	(845 only)
> +		- "csiphy2_timer"	(8996 & 845)
> +		- "csiphy3"		(845 only)
> +		- "csiphy3_timer_src"	(845 only)
> +		- "csiphy3_timer"	(845 only)
>  		- "csiphy_ahb2crif"	(660 only)
>  		- "csi0_ahb"
>  		- "csi0"
>  		- "csi0_phy"
>  		- "csi0_pix"
>  		- "csi0_rdi"
> +		- "csi0_src"		(845 only)
>  		- "cphy_csid0"		(660 only)
>  		- "csi1_ahb"
>  		- "csi1"
>  		- "csi1_phy"
>  		- "csi1_pix"
>  		- "csi1_rdi"
> +		- "csi1_src"		(845 only)
>  		- "cphy_csid1"		(660 only)
>  		- "csi2_ahb"		(8996 only)
>  		- "csi2"		(8996 only)
>  		- "csi2_phy"		(8996 only)
>  		- "csi2_pix"		(8996 only)
>  		- "csi2_rdi"		(8996 only)
> +		- "csi2_src"		(845 only)
>  		- "cphy_csid2"		(660 only)
>  		- "csi3_ahb"		(8996 only)
>  		- "csi3"		(8996 only)
> @@ -96,14 +114,25 @@ Qualcomm Camera Subsystem
>  		- "csi3_rdi"		(8996 only)
>  		- "cphy_csid3"		(660 only)
>  		- "ahb"
> +		- "slow_ahb_src"	(845 only)
> +		- "soc_ahb"		(845 only)
>  		- "vfe0"
>  		- "csi_vfe0"
>  		- "vfe0_ahb",		(8996 only)
> +		- "vfe0_cphy_rx"	(845 only)
> +		- "vfe0_axi",		(845 only)
> +		- "vfe0_src",		(845 only)
>  		- "vfe0_stream",	(8996 only)
>  		- "vfe1",		(8996 only)
>  		- "csi_vfe1",		(8996 only)
>  		- "vfe1_ahb",		(8996 only)
> +		- "vfe1_cphy_rx"	(845 only)
> +		- "vfe1_axi",		(845 only)
> +		- "vfe1_src",		(845 only)
>  		- "vfe1_stream",	(8996 only)
> +		- "vfe_lite_axi",	(845 only)
> +		- "vfe_lite_cphy_rx"	(845 only)
> +		- "vfe_lite_src",	(845 only)
>  		- "vfe_ahb"
>  		- "vfe_axi"
>  - vdda-supply:

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-09  1:47     ` Laurent Pinchart
  -1 siblings, 0 replies; 65+ messages in thread
From: Laurent Pinchart @ 2021-01-09  1:47 UTC (permalink / raw)
  To: Robert Foss
  Cc: agross, bjorn.andersson, todor.too, mchehab, robh+dt,
	catalin.marinas, will, shawnguo, leoyang.li, geert+renesas, arnd,
	Anson.Huang, michael, agx, max.oss.09, linux-arm-msm,
	linux-media, devicetree, linux-kernel, linux-arm-kernel,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt

Hi Rob,

Thank you for the patch.

The subject line doesn't match the patch.

On Fri, Jan 08, 2021 at 01:04:28PM +0100, Robert Foss wrote:
> Add regulators and camss DT node.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> index a943b3f353ce..7bad0515345e 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> @@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
>  			regulator-max-microvolt = <1028000>;
>  		};
>  
> +		vdda_mipi_csi0_0p9:
> +		vdda_mipi_csi1_0p9:
> +		vdda_mipi_csi2_0p9:

No need for new labels, you can simply use vreg_l1a_0p875 below.

>  		vreg_l1a_0p875: ldo1 {
>  			regulator-min-microvolt = <880000>;
>  			regulator-max-microvolt = <880000>;
> @@ -1106,6 +1109,15 @@ &cci {
>  	status = "okay";
>  };
>  
> +&camss {
> +	vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
> +	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
> +	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
> +
> +	status = "disabled";

This isn't needed.

> +

Extra blank line.

> +};
> +
>  &cci_i2c0 {
>  	camera@10 {
>  		compatible = "ovti,ov8856";

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
@ 2021-01-09  1:47     ` Laurent Pinchart
  0 siblings, 0 replies; 65+ messages in thread
From: Laurent Pinchart @ 2021-01-09  1:47 UTC (permalink / raw)
  To: Robert Foss
  Cc: geert+renesas, catalin.marinas, agx, todor.too, bjorn.andersson,
	AngeloGioacchino Del Regno, will, Anson.Huang, agross,
	Andrey Konovalov, linux-media, devicetree, Tomasz Figa, arnd,
	linux-arm-msm, robh+dt, mchehab, linux-arm-kernel,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Hi Rob,

Thank you for the patch.

The subject line doesn't match the patch.

On Fri, Jan 08, 2021 at 01:04:28PM +0100, Robert Foss wrote:
> Add regulators and camss DT node.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>  arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> index a943b3f353ce..7bad0515345e 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> @@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
>  			regulator-max-microvolt = <1028000>;
>  		};
>  
> +		vdda_mipi_csi0_0p9:
> +		vdda_mipi_csi1_0p9:
> +		vdda_mipi_csi2_0p9:

No need for new labels, you can simply use vreg_l1a_0p875 below.

>  		vreg_l1a_0p875: ldo1 {
>  			regulator-min-microvolt = <880000>;
>  			regulator-max-microvolt = <880000>;
> @@ -1106,6 +1109,15 @@ &cci {
>  	status = "okay";
>  };
>  
> +&camss {
> +	vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
> +	vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
> +	vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
> +
> +	status = "disabled";

This isn't needed.

> +

Extra blank line.

> +};
> +
>  &cci_i2c0 {
>  	camera@10 {
>  		compatible = "ovti,ov8856";

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
  2021-01-09  1:47     ` Laurent Pinchart
@ 2021-01-13 10:03       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:03 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Andy Gross, Bjorn Andersson, Todor Tomov, Mauro Carvalho Chehab,
	Rob Herring, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt

Thanks Laurent!

On Sat, 9 Jan 2021 at 02:47, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Rob,
>
> Thank you for the patch.
>
> The subject line doesn't match the patch.
>
> On Fri, Jan 08, 2021 at 01:04:28PM +0100, Robert Foss wrote:
> > Add regulators and camss DT node.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > index a943b3f353ce..7bad0515345e 100644
> > --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > @@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
> >                       regulator-max-microvolt = <1028000>;
> >               };
> >
> > +             vdda_mipi_csi0_0p9:
> > +             vdda_mipi_csi1_0p9:
> > +             vdda_mipi_csi2_0p9:
>
> No need for new labels, you can simply use vreg_l1a_0p875 below.

Ack

>
> >               vreg_l1a_0p875: ldo1 {
> >                       regulator-min-microvolt = <880000>;
> >                       regulator-max-microvolt = <880000>;
> > @@ -1106,6 +1109,15 @@ &cci {
> >       status = "okay";
> >  };
> >
> > +&camss {
> > +     vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
> > +     vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
> > +     vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
> > +
> > +     status = "disabled";
>
> This isn't needed.

Ack

>
> > +
>
> Extra blank line.

Ack

>
> > +};
> > +
> >  &cci_i2c0 {
> >       camera@10 {
> >               compatible = "ovti,ov8856";
>
> --
> Regards,
>
> Laurent Pinchart

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

* Re: [PATCH v1 16/17] arm64: dts: sdm845-db845c: Add CAMSS ISP node
@ 2021-01-13 10:03       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:03 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Bjorn Andersson, AngeloGioacchino Del Regno, will, Anson.Huang,
	Andy Gross, Andrey Konovalov, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Thanks Laurent!

On Sat, 9 Jan 2021 at 02:47, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Rob,
>
> Thank you for the patch.
>
> The subject line doesn't match the patch.
>
> On Fri, Jan 08, 2021 at 01:04:28PM +0100, Robert Foss wrote:
> > Add regulators and camss DT node.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  arch/arm64/boot/dts/qcom/sdm845-db845c.dts | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > index a943b3f353ce..7bad0515345e 100644
> > --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts
> > @@ -294,6 +294,9 @@ vreg_s7a_1p025: smps7 {
> >                       regulator-max-microvolt = <1028000>;
> >               };
> >
> > +             vdda_mipi_csi0_0p9:
> > +             vdda_mipi_csi1_0p9:
> > +             vdda_mipi_csi2_0p9:
>
> No need for new labels, you can simply use vreg_l1a_0p875 below.

Ack

>
> >               vreg_l1a_0p875: ldo1 {
> >                       regulator-min-microvolt = <880000>;
> >                       regulator-max-microvolt = <880000>;
> > @@ -1106,6 +1109,15 @@ &cci {
> >       status = "okay";
> >  };
> >
> > +&camss {
> > +     vdda-csi0-supply = <&vdda_mipi_csi0_0p9>;
> > +     vdda-csi1-supply = <&vdda_mipi_csi1_0p9>;
> > +     vdda-csi2-supply = <&vdda_mipi_csi2_0p9>;
> > +
> > +     status = "disabled";
>
> This isn't needed.

Ack

>
> > +
>
> Extra blank line.

Ack

>
> > +};
> > +
> >  &cci_i2c0 {
> >       camera@10 {
> >               compatible = "ovti,ov8856";
>
> --
> Regards,
>
> Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 01/17] media: camss: Fix comment using wrong function name
  2021-01-08 18:51     ` Bjorn Andersson
@ 2021-01-13 10:04       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:04 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Andy Gross, Todor Tomov, Mauro Carvalho Chehab, Rob Herring,
	catalin.marinas, will, shawnguo, leoyang.li, geert+renesas, arnd,
	Anson.Huang, michael, agx, max.oss.09, linux-arm-msm,
	linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Thanks Björn!

On Fri, 8 Jan 2021 at 19:51, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > Function name is comment is wrong, and was changed to be
> > the same as the actual function name.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> > index fae2b513b2f9..478be4f0cab5 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> > @@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> >  }
> >
> >  /*
> > - * vfe_isr_wm_done - Process composite image done interrupt
> > + * vfe_isr_comp_done - Process composite image done interrupt
>
> It's a function, so it should be "vfe_isr_comp_done()", but unless the
> comment is denoted kerneldoc by starting with '/' followed by two '*' it
> "doesn't matter".
>
> As a matter of fact, none of the kerneldoc in this file has the proper
> '/**' start, so this file is "undocumented".
>
> So please add another '*' and some () throughout the file.

Ack

>
> Regards,
> Bjorn
>
> >   * @vfe: VFE Device
> >   * @comp: Composite image id
> >   */
> > --
> > 2.27.0
> >

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

* Re: [PATCH v1 01/17] media: camss: Fix comment using wrong function name
@ 2021-01-13 10:04       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:04 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Laurent Pinchart, AngeloGioacchino Del Regno, will, Anson.Huang,
	Andy Gross, Andrey Konovalov, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Thanks Björn!

On Fri, 8 Jan 2021 at 19:51, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > Function name is comment is wrong, and was changed to be
> > the same as the actual function name.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  drivers/media/platform/qcom/camss/camss-vfe.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> > index fae2b513b2f9..478be4f0cab5 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> > @@ -1077,7 +1077,7 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> >  }
> >
> >  /*
> > - * vfe_isr_wm_done - Process composite image done interrupt
> > + * vfe_isr_comp_done - Process composite image done interrupt
>
> It's a function, so it should be "vfe_isr_comp_done()", but unless the
> comment is denoted kerneldoc by starting with '/' followed by two '*' it
> "doesn't matter".
>
> As a matter of fact, none of the kerneldoc in this file has the proper
> '/**' start, so this file is "undocumented".
>
> So please add another '*' and some () throughout the file.

Ack

>
> Regards,
> Bjorn
>
> >   * @vfe: VFE Device
> >   * @comp: Composite image id
> >   */
> > --
> > 2.27.0
> >

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
  2021-01-08 18:51     ` Bjorn Andersson
@ 2021-01-13 10:04       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:04 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Andy Gross, Todor Tomov, Mauro Carvalho Chehab, Rob Herring,
	catalin.marinas, will, shawnguo, leoyang.li, geert+renesas, arnd,
	Anson.Huang, michael, agx, max.oss.09, linux-arm-msm,
	linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Thanks!

On Fri, 8 Jan 2021 at 19:51, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > Comment refers to ISPIF, but this is incorrect. Only
> > the VFE interrupts are handled by this function.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
>
> Regards,
> Bjorn
>
> > ---
> >  drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
> >  drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > 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 174a36be6f5d..a1b56b89130d 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > @@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
> >  }
> >
> >  /*
> > - * vfe_isr - ISPIF module interrupt handler
> > + * vfe_isr - VFE module interrupt handler
> >   * @irq: Interrupt line
> >   * @dev: VFE device
> >   *
> > 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 b5704a2f119b..84c33b8f9fe3 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > @@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
> >  }
> >
> >  /*
> > - * vfe_isr - ISPIF module interrupt handler
> > + * vfe_isr - VFE module interrupt handler
> >   * @irq: Interrupt line
> >   * @dev: VFE device
> >   *
> > --
> > 2.27.0
> >

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

* Re: [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo
@ 2021-01-13 10:04       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 10:04 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Laurent Pinchart, AngeloGioacchino Del Regno, will, Anson.Huang,
	Andy Gross, Andrey Konovalov, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Thanks!

On Fri, 8 Jan 2021 at 19:51, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > Comment refers to ISPIF, but this is incorrect. Only
> > the VFE interrupts are handled by this function.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
>
> Regards,
> Bjorn
>
> > ---
> >  drivers/media/platform/qcom/camss/camss-vfe-4-1.c | 2 +-
> >  drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > 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 174a36be6f5d..a1b56b89130d 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > @@ -922,7 +922,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
> >  }
> >
> >  /*
> > - * vfe_isr - ISPIF module interrupt handler
> > + * vfe_isr - VFE module interrupt handler
> >   * @irq: Interrupt line
> >   * @dev: VFE device
> >   *
> > 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 b5704a2f119b..84c33b8f9fe3 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > @@ -1055,7 +1055,7 @@ static void vfe_violation_read(struct vfe_device *vfe)
> >  }
> >
> >  /*
> > - * vfe_isr - ISPIF module interrupt handler
> > + * vfe_isr - VFE module interrupt handler
> >   * @irq: Interrupt line
> >   * @dev: VFE device
> >   *
> > --
> > 2.27.0
> >

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
  2021-01-08 19:07     ` Bjorn Andersson
@ 2021-01-13 15:02       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 15:02 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Andy Gross, Todor Tomov, Mauro Carvalho Chehab, Rob Herring,
	catalin.marinas, will, shawnguo, leoyang.li, geert+renesas, arnd,
	Anson.Huang, michael, agx, max.oss.09, linux-arm-msm,
	linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Andrey Konovalov, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Thanks Björn!

On Fri, 8 Jan 2021 at 20:07, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > This driver supports multiple architecture versions of the Qualcomm ISP.
> > The CAMSS architecure which this driver is name after, and with the
> > introduction of this series, the Titan architecture.
> >
> > The ISPIF is IP-block that is only present in the CAMSS architecture.
>
> "is an IP-block"

Ack

I cleaned up the message a little bit further in order to be more
clear about camss & titan being the names of architecture generations.

>
> > In order to support the Titan architecture, make the ISPIF an optional
> > subdevice.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
> >  .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
> >  drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
> >  drivers/media/platform/qcom/camss/camss.h     |   2 +-
> >  4 files changed, 160 insertions(+), 102 deletions(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> [..]
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res)
> >  {
> > -     struct device *dev = to_device(ispif);
> > -     struct platform_device *pdev = to_platform_device(dev);
> > +     struct ispif_device *ispif = camss->ispif;
> > +     struct platform_device *pdev = to_platform_device(camss->dev);
>
> It seems like several of the changes in this function is replacing
> dev with camss->dev. If you retained a struct device *dev = camss->dev;
> you would avoid this.

Ack.

>
> >       struct resource *r;
> >       int i;
> >       int ret;
> >
> > +     if (res == NULL && ispif == NULL)
>
> Afaict this function is called conditional on camss->ispif != NULL, and
> I don't see anything that would cause res to becomes NULL if is hasn't
> been before this change.
>
> So I think this check is unnecessary?

Nice catch, thank you!

>
> > +             return 0;
> > +
> > +     ispif->camss = camss;
> > +
> >       /* Number of ISPIF lines - same as number of CSID hardware modules */
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > +     if (camss->version == CAMSS_8x16)
> >               ispif->line_num = 2;
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> >               ispif->line_num = 4;
> >       else
> >               return -EINVAL;
> >
> > -     ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> > -                                GFP_KERNEL);
> > +     ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> > +                     sizeof(*ispif->line), GFP_KERNEL);
> >       if (!ispif->line)
> >               return -ENOMEM;
> >
> [..]
> > @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
> >  {
> >       int i;
> >
> > +     if (!ispif)
> > +             return;
>
> I like this, but later in the patch you make the calls to this function
> conditional on ispif != NULL. You should only need one of the checks.

Ack, removing the external checks and keeping the internal one then.

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
@ 2021-01-13 15:02       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-13 15:02 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Laurent Pinchart, AngeloGioacchino Del Regno, will, Anson.Huang,
	Andy Gross, Andrey Konovalov, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Thanks Björn!

On Fri, 8 Jan 2021 at 20:07, Bjorn Andersson <bjorn.andersson@linaro.org> wrote:
>
> On Fri 08 Jan 06:04 CST 2021, Robert Foss wrote:
>
> > This driver supports multiple architecture versions of the Qualcomm ISP.
> > The CAMSS architecure which this driver is name after, and with the
> > introduction of this series, the Titan architecture.
> >
> > The ISPIF is IP-block that is only present in the CAMSS architecture.
>
> "is an IP-block"

Ack

I cleaned up the message a little bit further in order to be more
clear about camss & titan being the names of architecture generations.

>
> > In order to support the Titan architecture, make the ISPIF an optional
> > subdevice.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >  .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
> >  .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
> >  drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
> >  drivers/media/platform/qcom/camss/camss.h     |   2 +-
> >  4 files changed, 160 insertions(+), 102 deletions(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> [..]
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res)
> >  {
> > -     struct device *dev = to_device(ispif);
> > -     struct platform_device *pdev = to_platform_device(dev);
> > +     struct ispif_device *ispif = camss->ispif;
> > +     struct platform_device *pdev = to_platform_device(camss->dev);
>
> It seems like several of the changes in this function is replacing
> dev with camss->dev. If you retained a struct device *dev = camss->dev;
> you would avoid this.

Ack.

>
> >       struct resource *r;
> >       int i;
> >       int ret;
> >
> > +     if (res == NULL && ispif == NULL)
>
> Afaict this function is called conditional on camss->ispif != NULL, and
> I don't see anything that would cause res to becomes NULL if is hasn't
> been before this change.
>
> So I think this check is unnecessary?

Nice catch, thank you!

>
> > +             return 0;
> > +
> > +     ispif->camss = camss;
> > +
> >       /* Number of ISPIF lines - same as number of CSID hardware modules */
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > +     if (camss->version == CAMSS_8x16)
> >               ispif->line_num = 2;
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> >               ispif->line_num = 4;
> >       else
> >               return -EINVAL;
> >
> > -     ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> > -                                GFP_KERNEL);
> > +     ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> > +                     sizeof(*ispif->line), GFP_KERNEL);
> >       if (!ispif->line)
> >               return -ENOMEM;
> >
> [..]
> > @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
> >  {
> >       int i;
> >
> > +     if (!ispif)
> > +             return;
>
> I like this, but later in the patch you make the calls to this function
> conditional on ispif != NULL. You should only need one of the checks.

Ack, removing the external checks and keeping the internal one then.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-13 22:28     ` Andrey Konovalov
  -1 siblings, 0 replies; 65+ messages in thread
From: Andrey Konovalov @ 2021-01-13 22:28 UTC (permalink / raw)
  To: Robert Foss, agross, bjorn.andersson, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Hi Robert,

Thanks for the patch!

On 08.01.2021 15:04, Robert Foss wrote:
> This driver supports multiple architecture versions of the Qualcomm ISP.
> The CAMSS architecure which this driver is name after, and with the
> introduction of this series, the Titan architecture.
> 
> The ISPIF is IP-block that is only present in the CAMSS architecture.
> In order to support the Titan architecture, make the ISPIF an optional
> subdevice.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>   .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
>   .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
>   drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
>   drivers/media/platform/qcom/camss/camss.h     |   2 +-
>   4 files changed, 160 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> index adeb92808998..0c804584dd65 100644
> --- a/drivers/media/platform/qcom/camss/camss-ispif.c
> +++ b/drivers/media/platform/qcom/camss/camss-ispif.c
> @@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
>   static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   {
>   	struct ispif_device *ispif = dev;
> +	struct camss *camss = ispif->camss;
>   	u32 value0, value1, value2, value3, value4, value5;
>   
>   	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> @@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   		complete(&ispif->reset_complete[1]);
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
>   
>   	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
>   
>   	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
>   
>   	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
>   
>   	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
>   
>   	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
>   
>   	if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
>   
>   	return IRQ_HANDLED;
>   }
> @@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   static irqreturn_t ispif_isr_8x16(int irq, void *dev)
>   {
>   	struct ispif_device *ispif = dev;
> +	struct camss *camss = ispif->camss;
>   	u32 value0, value1, value2;
>   
>   	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> @@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
>   		complete(&ispif->reset_complete[0]);
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
>   
>   	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
>   
>   	return IRQ_HANDLED;
>   }
>   
>   static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>   {
> +	struct camss *camss = ispif->camss;
> +
>   	unsigned long time;
>   	u32 val;
>   
> -	if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
> -		dev_err(to_device(ispif),
> +	if (vfe_id > (camss->vfe_num - 1)) {
> +		dev_err(camss->dev,
>   			"Error: asked reset for invalid VFE%d\n", vfe_id);
>   		return -ENOENT;
>   	}
> @@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>   	time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
>   		msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
>   	if (!time) {
> -		dev_err(to_device(ispif),
> +		dev_err(camss->dev,
>   			"ISPIF for VFE%d reset timeout\n", vfe_id);
>   		return -EIO;
>   	}
> @@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>    */
>   static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
>   {
> +	struct camss *camss = ispif->camss;
>   	int ret;
>   
> -	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
> +	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
>   	if (ret < 0)
>   		return ret;
>   
> -	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
> +	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
>   	if (ret < 0)
>   		return ret;
>   
>   	ret = camss_enable_clocks(ispif->nclocks_for_reset,
>   				  ispif->clock_for_reset,
> -				  to_device(ispif));
> +				  camss->dev);
>   	if (ret < 0)
>   		return ret;
>   
>   	ret = ispif_vfe_reset(ispif, vfe_id);
>   	if (ret)
> -		dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
> +		dev_dbg(camss->dev, "ISPIF Reset failed\n");
>   
>   	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
>   
> -	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
> -	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
> +	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
> +	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
>   
>   	return ret;
>   }
> @@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
>   {
>   	struct ispif_line *line = v4l2_get_subdevdata(sd);
>   	struct ispif_device *ispif = line->ispif;
> -	struct device *dev = to_device(ispif);
> +	struct device *dev = ispif->camss->dev;
>   	int ret = 0;
>   
>   	mutex_lock(&ispif->power_lock);
> @@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
>   	}
>   
>   	if ((val & 0xf) != 0xf) {
> -		dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
> +		dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
>   			__func__, val);
>   		ret = -EBUSY;
>   	}
> @@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
>   				 ISPIF_TIMEOUT_SLEEP_US,
>   				 ISPIF_TIMEOUT_ALL_US);
>   	if (ret < 0)
> -		dev_err(to_device(ispif), "%s: ispif stop timeout\n",
> +		dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
>   			__func__);
>   
>   	return ret;
> @@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   {
>   	struct ispif_line *line = v4l2_get_subdevdata(sd);
>   	struct ispif_device *ispif = line->ispif;
> +	struct camss *camss = ispif->camss;
>   	enum ispif_intf intf = line->interface;
>   	u8 csid = line->csid_id;
>   	u8 vfe = line->vfe_id;
> @@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   		ispif_select_csid(ispif, intf, csid, vfe, 1);
>   		ispif_select_cid(ispif, intf, cid, vfe, 1);
>   		ispif_config_irq(ispif, intf, vfe, 1);
> -		if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		    to_camss(ispif)->version == CAMSS_660)
> +		if (camss->version == CAMSS_8x96 ||
> +		    camss->version == CAMSS_660)
>   			ispif_config_pack(ispif,
>   					  line->fmt[MSM_ISPIF_PAD_SINK].code,
>   					  intf, cid, vfe, 1);
> @@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   			return ret;
>   
>   		mutex_lock(&ispif->config_lock);
> -		if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		    to_camss(ispif)->version == CAMSS_660)
> +		if (camss->version == CAMSS_8x96 ||
> +		    camss->version == CAMSS_660)
>   			ispif_config_pack(ispif,
>   					  line->fmt[MSM_ISPIF_PAD_SINK].code,
>   					  intf, cid, vfe, 0);
> @@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>    *
>    * Return 0 on success or a negative error code otherwise
>    */
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>   			  const struct resources_ispif *res)
>   {
> -	struct device *dev = to_device(ispif);
> -	struct platform_device *pdev = to_platform_device(dev);
> +	struct ispif_device *ispif = camss->ispif;
> +	struct platform_device *pdev = to_platform_device(camss->dev);
>   	struct resource *r;
>   	int i;
>   	int ret;
>   
> +	if (res == NULL && ispif == NULL)
> +		return 0;
> +
> +	ispif->camss = camss;
> +
>   	/* Number of ISPIF lines - same as number of CSID hardware modules */
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> +	if (camss->version == CAMSS_8x16)
>   		ispif->line_num = 2;
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
>   		ispif->line_num = 4;
>   	else
>   		return -EINVAL;
>   
> -	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> -				   GFP_KERNEL);
> +	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> +			sizeof(*ispif->line), GFP_KERNEL);
>   	if (!ispif->line)
>   		return -ENOMEM;
>   
> @@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   		ispif->line[i].ispif = ispif;
>   		ispif->line[i].id = i;
>   
> -		if (to_camss(ispif)->version == CAMSS_8x16) {
> +		if (camss->version == CAMSS_8x16) {
>   			ispif->line[i].formats = ispif_formats_8x16;
>   			ispif->line[i].nformats =
>   					ARRAY_SIZE(ispif_formats_8x16);
> -		} else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -			   to_camss(ispif)->version == CAMSS_660) {
> +		} else if (camss->version == CAMSS_8x96 ||
> +			   camss->version == CAMSS_660) {
>   			ispif->line[i].formats = ispif_formats_8x96;
>   			ispif->line[i].nformats =
>   					ARRAY_SIZE(ispif_formats_8x96);
> @@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	/* Memory */
>   
>   	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
> -	ispif->base = devm_ioremap_resource(dev, r);
> +	ispif->base = devm_ioremap_resource(camss->dev, r);
>   	if (IS_ERR(ispif->base)) {
> -		dev_err(dev, "could not map memory\n");
> +		dev_err(camss->dev, "could not map memory\n");
>   		return PTR_ERR(ispif->base);
>   	}
>   
>   	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
> -	ispif->base_clk_mux = devm_ioremap_resource(dev, r);
> +	ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
>   	if (IS_ERR(ispif->base_clk_mux)) {
> -		dev_err(dev, "could not map memory\n");
> +		dev_err(camss->dev, "could not map memory\n");
>   		return PTR_ERR(ispif->base_clk_mux);
>   	}
>   
> @@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
>   
>   	if (!r) {
> -		dev_err(dev, "missing IRQ\n");
> +		dev_err(camss->dev, "missing IRQ\n");
>   		return -EINVAL;
>   	}
>   
>   	ispif->irq = r->start;
>   	snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
> -		 dev_name(dev), MSM_ISPIF_NAME);
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> -		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
> +		 dev_name(camss->dev), MSM_ISPIF_NAME);
> +	if (camss->version == CAMSS_8x16)
> +		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
>   			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> -		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
> +		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
>   			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
>   	else
>   		ret = -EINVAL;
> +
>   	if (ret < 0) {
> -		dev_err(dev, "request_irq failed: %d\n", ret);
> +		dev_err(camss->dev, "request_irq failed: %d\n", ret);
>   		return ret;
>   	}
>   
> @@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	while (res->clock[ispif->nclocks])
>   		ispif->nclocks++;
>   
> -	ispif->clock = devm_kcalloc(dev,
> +	ispif->clock = devm_kcalloc(camss->dev,
>   				    ispif->nclocks, sizeof(*ispif->clock),
>   				    GFP_KERNEL);
>   	if (!ispif->clock)
> @@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	for (i = 0; i < ispif->nclocks; i++) {
>   		struct camss_clock *clock = &ispif->clock[i];
>   
> -		clock->clk = devm_clk_get(dev, res->clock[i]);
> +		clock->clk = devm_clk_get(camss->dev, res->clock[i]);
>   		if (IS_ERR(clock->clk))
>   			return PTR_ERR(clock->clk);
>   
> @@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	while (res->clock_for_reset[ispif->nclocks_for_reset])
>   		ispif->nclocks_for_reset++;
>   
> -	ispif->clock_for_reset = devm_kcalloc(dev,
> +	ispif->clock_for_reset = devm_kcalloc(camss->dev,
>   					      ispif->nclocks_for_reset,
>   					      sizeof(*ispif->clock_for_reset),
>   					      GFP_KERNEL);
> @@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	for (i = 0; i < ispif->nclocks_for_reset; i++) {
>   		struct camss_clock *clock = &ispif->clock_for_reset[i];
>   
> -		clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
> +		clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
>   		if (IS_ERR(clock->clk))
>   			return PTR_ERR(clock->clk);
>   
> @@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
>   int msm_ispif_register_entities(struct ispif_device *ispif,
>   				struct v4l2_device *v4l2_dev)
>   {
> -	struct device *dev = to_device(ispif);
> +	struct camss *camss =  ispif->camss;
>   	int ret;
>   	int i;
>   
> +	if (!ispif)
> +		return 0;
> +
>   	for (i = 0; i < ispif->line_num; i++) {
>   		struct v4l2_subdev *sd = &ispif->line[i].subdev;
>   		struct media_pad *pads = ispif->line[i].pads;
> @@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
>   
>   		ret = ispif_init_formats(sd, NULL);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to init format: %d\n", ret);
> +			dev_err(camss->dev, "Failed to init format: %d\n", ret);
>   			goto error;
>   		}
>   
> @@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
>   		ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
>   					     pads);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to init media entity: %d\n", ret);
> +			dev_err(camss->dev, "Failed to init media entity: %d\n",
> +				ret);
>   			goto error;
>   		}
>   
>   		ret = v4l2_device_register_subdev(v4l2_dev, sd);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to register subdev: %d\n", ret);
> +			dev_err(camss->dev, "Failed to register subdev: %d\n",
> +				ret);
>   			media_entity_cleanup(&sd->entity);
>   			goto error;
>   		}
> @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
>   {
>   	int i;
>   
> +	if (!ispif)
> +		return;
> +
>   	mutex_destroy(&ispif->power_lock);
>   	mutex_destroy(&ispif->config_lock);
>   
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
> index 4132174f7ea1..fdf28e68cc7d 100644
> --- a/drivers/media/platform/qcom/camss/camss-ispif.h
> +++ b/drivers/media/platform/qcom/camss/camss-ispif.h
> @@ -63,11 +63,12 @@ struct ispif_device {
>   	struct mutex config_lock;
>   	unsigned int line_num;
>   	struct ispif_line *line;
> +	struct camss *camss;
>   };
>   
>   struct resources_ispif;
>   
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>   			  const struct resources_ispif *res);
>   
>   int msm_ispif_register_entities(struct ispif_device *ispif,
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index 8fefce57bc49..aeec59bc6194 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
>   		}
>   	}
>   
> -	ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
> -	if (ret < 0) {
> -		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> +	if (camss->ispif) {
> +		ret = msm_ispif_subdev_init(camss, ispif_res);
> +		if (ret < 0) {
> +			dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
>   			ret);
> -		return ret;
> +			return ret;
> +		}
>   	}
>   
>   	for (i = 0; i < camss->vfe_num; i++) {
> @@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
>   		}
>   	}
>   
> -	ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
> -	if (ret < 0) {
> -		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> +	if (camss->ispif) {
> +		ret = msm_ispif_register_entities(camss->ispif,
> +						  &camss->v4l2_dev);
> +		if (ret < 0) {
> +			dev_err(camss->dev, "Failed to register ispif entities: %d\n",
>   			ret);
> -		goto err_reg_ispif;
> +			goto err_reg_ispif;
> +		}
>   	}
>   
>   	for (i = 0; i < camss->vfe_num; i++) {
> @@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
>   		}
>   	}
>   
> -	for (i = 0; i < camss->csid_num; i++) {
> -		for (j = 0; j < camss->ispif.line_num; j++) {
> -			ret = media_create_pad_link(
> -				&camss->csid[i].subdev.entity,
> -				MSM_CSID_PAD_SRC,
> -				&camss->ispif.line[j].subdev.entity,
> -				MSM_ISPIF_PAD_SINK,
> -				0);
> -			if (ret < 0) {
> -				dev_err(camss->dev,
> -					"Failed to link %s->%s entities: %d\n",
> -					camss->csid[i].subdev.entity.name,
> -					camss->ispif.line[j].subdev.entity.name,
> -					ret);
> -				goto err_link;
> -			}
> -		}
> -	}
> -
> -	for (i = 0; i < camss->ispif.line_num; i++)
> -		for (k = 0; k < camss->vfe_num; k++)
> -			for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +	if (camss->ispif) {
> +		for (i = 0; i < camss->csid_num; i++) {
> +			for (j = 0; j < camss->ispif->line_num; j++) {
>   				ret = media_create_pad_link(
> -					&camss->ispif.line[i].subdev.entity,
> -					MSM_ISPIF_PAD_SRC,
> -					&camss->vfe[k].line[j].subdev.entity,
> -					MSM_VFE_PAD_SINK,
> +					&camss->csid[i].subdev.entity,
> +					MSM_CSID_PAD_SRC,
> +					&camss->ispif->line[j].subdev.entity,
> +					MSM_ISPIF_PAD_SINK,
>   					0);
>   				if (ret < 0) {
>   					dev_err(camss->dev,
>   						"Failed to link %s->%s entities: %d\n",
> -						camss->ispif.line[i].subdev.entity.name,
> -						camss->vfe[k].line[j].subdev.entity.name,
> +						camss->csid[i].subdev.entity.name,
> +						camss->ispif->line[j].subdev.entity.name,
>   						ret);
>   					goto err_link;
>   				}
>   			}
> +		}
> +
> +		for (i = 0; i < camss->ispif->line_num; i++)
> +			for (k = 0; k < camss->vfe_num; k++)
> +				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +					ret = media_create_pad_link(
> +						&camss->ispif->line[i].subdev.entity,
> +						MSM_ISPIF_PAD_SRC,
> +						&camss->vfe[k].line[j].subdev.entity,
> +						MSM_VFE_PAD_SINK,
> +						0);
> +					if (ret < 0) {
> +						dev_err(camss->dev,
> +							"Failed to link %s->%s entities: %d\n",
> +							camss->ispif->line[i].subdev.entity.name,
> +							camss->vfe[k].line[j].subdev.entity.name,
> +							ret);
> +						goto err_link;
> +					}
> +				}
> +	} else {
> +		for (i = 0; i < camss->csid_num; i++)
> +			for (k = 0; k < camss->vfe_num; k++)
> +				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +					ret = media_create_pad_link(
> +						&camss->csid[i].subdev.entity,
> +						MSM_CSID_PAD_SRC,
> +						&camss->vfe[k].line[j].subdev.entity,
> +						MSM_VFE_PAD_SINK,
> +						0);
> +					if (ret < 0) {
> +						dev_err(camss->dev,
> +							"Failed to link %s->%s entities: %d\n",
> +							camss->csid[i].subdev.entity.name,
> +							camss->vfe[k].line[j].subdev.entity.name,
> +							ret);
> +						goto err_link;
> +					}
> +				}
> +	}
>   
>   	return 0;
>   
> @@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
>   	for (i--; i >= 0; i--)
>   		msm_vfe_unregister_entities(&camss->vfe[i]);
>   
> -	msm_ispif_unregister_entities(&camss->ispif);
>   err_reg_ispif:
> +	if (camss->ispif)
> +		msm_ispif_unregister_entities(camss->ispif);
>   
>   	i = camss->csid_num;
>   err_reg_csid:
> @@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
>   	for (i = 0; i < camss->csid_num; i++)
>   		msm_csid_unregister_entity(&camss->csid[i]);
>   
> -	msm_ispif_unregister_entities(&camss->ispif);
> +	if (camss->ispif)
> +		msm_ispif_unregister_entities(camss->ispif);
>   
>   	for (i = 0; i < camss->vfe_num; i++)
>   		msm_vfe_unregister_entities(&camss->vfe[i]);
> @@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
>   		goto err_free;
>   	}
>   
> +	if (camss->version == CAMSS_8x16 ||
> +	    camss->version == CAMSS_8x96) {
> +		camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);

- shouldn't it be sizeof(*camss->ispif) instead?

Thanks,
Andrey

> +		if (!camss->ispif) {
> +			ret = -ENOMEM;
> +			goto err_free;
> +		}
> +	}
> +
>   	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
>   				  GFP_KERNEL);
>   	if (!camss->vfe) {
> diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
> index 46e986452824..b7ad8e9f68a8 100644
> --- a/drivers/media/platform/qcom/camss/camss.h
> +++ b/drivers/media/platform/qcom/camss/camss.h
> @@ -79,7 +79,7 @@ struct camss {
>   	struct csiphy_device *csiphy;
>   	int csid_num;
>   	struct csid_device *csid;
> -	struct ispif_device ispif;
> +	struct ispif_device *ispif;
>   	int vfe_num;
>   	struct vfe_device *vfe;
>   	atomic_t ref_count;
> 

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
@ 2021-01-13 22:28     ` Andrey Konovalov
  0 siblings, 0 replies; 65+ messages in thread
From: Andrey Konovalov @ 2021-01-13 22:28 UTC (permalink / raw)
  To: Robert Foss, agross, bjorn.andersson, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Hi Robert,

Thanks for the patch!

On 08.01.2021 15:04, Robert Foss wrote:
> This driver supports multiple architecture versions of the Qualcomm ISP.
> The CAMSS architecure which this driver is name after, and with the
> introduction of this series, the Titan architecture.
> 
> The ISPIF is IP-block that is only present in the CAMSS architecture.
> In order to support the Titan architecture, make the ISPIF an optional
> subdevice.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>   .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
>   .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
>   drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
>   drivers/media/platform/qcom/camss/camss.h     |   2 +-
>   4 files changed, 160 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> index adeb92808998..0c804584dd65 100644
> --- a/drivers/media/platform/qcom/camss/camss-ispif.c
> +++ b/drivers/media/platform/qcom/camss/camss-ispif.c
> @@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
>   static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   {
>   	struct ispif_device *ispif = dev;
> +	struct camss *camss = ispif->camss;
>   	u32 value0, value1, value2, value3, value4, value5;
>   
>   	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> @@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   		complete(&ispif->reset_complete[1]);
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
>   
>   	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
>   
>   	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
>   
>   	if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
>   
>   	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
>   
>   	if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
>   
>   	if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
>   
>   	return IRQ_HANDLED;
>   }
> @@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
>   static irqreturn_t ispif_isr_8x16(int irq, void *dev)
>   {
>   	struct ispif_device *ispif = dev;
> +	struct camss *camss = ispif->camss;
>   	u32 value0, value1, value2;
>   
>   	value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> @@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
>   		complete(&ispif->reset_complete[0]);
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
>   
>   	if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
>   
>   	if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
>   
>   	if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> -		dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> +		dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
>   
>   	return IRQ_HANDLED;
>   }
>   
>   static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>   {
> +	struct camss *camss = ispif->camss;
> +
>   	unsigned long time;
>   	u32 val;
>   
> -	if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
> -		dev_err(to_device(ispif),
> +	if (vfe_id > (camss->vfe_num - 1)) {
> +		dev_err(camss->dev,
>   			"Error: asked reset for invalid VFE%d\n", vfe_id);
>   		return -ENOENT;
>   	}
> @@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>   	time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
>   		msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
>   	if (!time) {
> -		dev_err(to_device(ispif),
> +		dev_err(camss->dev,
>   			"ISPIF for VFE%d reset timeout\n", vfe_id);
>   		return -EIO;
>   	}
> @@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
>    */
>   static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
>   {
> +	struct camss *camss = ispif->camss;
>   	int ret;
>   
> -	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
> +	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
>   	if (ret < 0)
>   		return ret;
>   
> -	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
> +	ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
>   	if (ret < 0)
>   		return ret;
>   
>   	ret = camss_enable_clocks(ispif->nclocks_for_reset,
>   				  ispif->clock_for_reset,
> -				  to_device(ispif));
> +				  camss->dev);
>   	if (ret < 0)
>   		return ret;
>   
>   	ret = ispif_vfe_reset(ispif, vfe_id);
>   	if (ret)
> -		dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
> +		dev_dbg(camss->dev, "ISPIF Reset failed\n");
>   
>   	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
>   
> -	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
> -	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
> +	camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
> +	camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
>   
>   	return ret;
>   }
> @@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
>   {
>   	struct ispif_line *line = v4l2_get_subdevdata(sd);
>   	struct ispif_device *ispif = line->ispif;
> -	struct device *dev = to_device(ispif);
> +	struct device *dev = ispif->camss->dev;
>   	int ret = 0;
>   
>   	mutex_lock(&ispif->power_lock);
> @@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
>   	}
>   
>   	if ((val & 0xf) != 0xf) {
> -		dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
> +		dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
>   			__func__, val);
>   		ret = -EBUSY;
>   	}
> @@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
>   				 ISPIF_TIMEOUT_SLEEP_US,
>   				 ISPIF_TIMEOUT_ALL_US);
>   	if (ret < 0)
> -		dev_err(to_device(ispif), "%s: ispif stop timeout\n",
> +		dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
>   			__func__);
>   
>   	return ret;
> @@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   {
>   	struct ispif_line *line = v4l2_get_subdevdata(sd);
>   	struct ispif_device *ispif = line->ispif;
> +	struct camss *camss = ispif->camss;
>   	enum ispif_intf intf = line->interface;
>   	u8 csid = line->csid_id;
>   	u8 vfe = line->vfe_id;
> @@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   		ispif_select_csid(ispif, intf, csid, vfe, 1);
>   		ispif_select_cid(ispif, intf, cid, vfe, 1);
>   		ispif_config_irq(ispif, intf, vfe, 1);
> -		if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		    to_camss(ispif)->version == CAMSS_660)
> +		if (camss->version == CAMSS_8x96 ||
> +		    camss->version == CAMSS_660)
>   			ispif_config_pack(ispif,
>   					  line->fmt[MSM_ISPIF_PAD_SINK].code,
>   					  intf, cid, vfe, 1);
> @@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
>   			return ret;
>   
>   		mutex_lock(&ispif->config_lock);
> -		if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		    to_camss(ispif)->version == CAMSS_660)
> +		if (camss->version == CAMSS_8x96 ||
> +		    camss->version == CAMSS_660)
>   			ispif_config_pack(ispif,
>   					  line->fmt[MSM_ISPIF_PAD_SINK].code,
>   					  intf, cid, vfe, 0);
> @@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>    *
>    * Return 0 on success or a negative error code otherwise
>    */
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>   			  const struct resources_ispif *res)
>   {
> -	struct device *dev = to_device(ispif);
> -	struct platform_device *pdev = to_platform_device(dev);
> +	struct ispif_device *ispif = camss->ispif;
> +	struct platform_device *pdev = to_platform_device(camss->dev);
>   	struct resource *r;
>   	int i;
>   	int ret;
>   
> +	if (res == NULL && ispif == NULL)
> +		return 0;
> +
> +	ispif->camss = camss;
> +
>   	/* Number of ISPIF lines - same as number of CSID hardware modules */
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> +	if (camss->version == CAMSS_8x16)
>   		ispif->line_num = 2;
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
>   		ispif->line_num = 4;
>   	else
>   		return -EINVAL;
>   
> -	ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> -				   GFP_KERNEL);
> +	ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> +			sizeof(*ispif->line), GFP_KERNEL);
>   	if (!ispif->line)
>   		return -ENOMEM;
>   
> @@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   		ispif->line[i].ispif = ispif;
>   		ispif->line[i].id = i;
>   
> -		if (to_camss(ispif)->version == CAMSS_8x16) {
> +		if (camss->version == CAMSS_8x16) {
>   			ispif->line[i].formats = ispif_formats_8x16;
>   			ispif->line[i].nformats =
>   					ARRAY_SIZE(ispif_formats_8x16);
> -		} else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -			   to_camss(ispif)->version == CAMSS_660) {
> +		} else if (camss->version == CAMSS_8x96 ||
> +			   camss->version == CAMSS_660) {
>   			ispif->line[i].formats = ispif_formats_8x96;
>   			ispif->line[i].nformats =
>   					ARRAY_SIZE(ispif_formats_8x96);
> @@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	/* Memory */
>   
>   	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
> -	ispif->base = devm_ioremap_resource(dev, r);
> +	ispif->base = devm_ioremap_resource(camss->dev, r);
>   	if (IS_ERR(ispif->base)) {
> -		dev_err(dev, "could not map memory\n");
> +		dev_err(camss->dev, "could not map memory\n");
>   		return PTR_ERR(ispif->base);
>   	}
>   
>   	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
> -	ispif->base_clk_mux = devm_ioremap_resource(dev, r);
> +	ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
>   	if (IS_ERR(ispif->base_clk_mux)) {
> -		dev_err(dev, "could not map memory\n");
> +		dev_err(camss->dev, "could not map memory\n");
>   		return PTR_ERR(ispif->base_clk_mux);
>   	}
>   
> @@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
>   
>   	if (!r) {
> -		dev_err(dev, "missing IRQ\n");
> +		dev_err(camss->dev, "missing IRQ\n");
>   		return -EINVAL;
>   	}
>   
>   	ispif->irq = r->start;
>   	snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
> -		 dev_name(dev), MSM_ISPIF_NAME);
> -	if (to_camss(ispif)->version == CAMSS_8x16)
> -		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
> +		 dev_name(camss->dev), MSM_ISPIF_NAME);
> +	if (camss->version == CAMSS_8x16)
> +		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
>   			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> -	else if (to_camss(ispif)->version == CAMSS_8x96 ||
> -		 to_camss(ispif)->version == CAMSS_660)
> -		ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
> +	else if (camss->version == CAMSS_8x96 ||
> +		 camss->version == CAMSS_660)
> +		ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
>   			       IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
>   	else
>   		ret = -EINVAL;
> +
>   	if (ret < 0) {
> -		dev_err(dev, "request_irq failed: %d\n", ret);
> +		dev_err(camss->dev, "request_irq failed: %d\n", ret);
>   		return ret;
>   	}
>   
> @@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	while (res->clock[ispif->nclocks])
>   		ispif->nclocks++;
>   
> -	ispif->clock = devm_kcalloc(dev,
> +	ispif->clock = devm_kcalloc(camss->dev,
>   				    ispif->nclocks, sizeof(*ispif->clock),
>   				    GFP_KERNEL);
>   	if (!ispif->clock)
> @@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	for (i = 0; i < ispif->nclocks; i++) {
>   		struct camss_clock *clock = &ispif->clock[i];
>   
> -		clock->clk = devm_clk_get(dev, res->clock[i]);
> +		clock->clk = devm_clk_get(camss->dev, res->clock[i]);
>   		if (IS_ERR(clock->clk))
>   			return PTR_ERR(clock->clk);
>   
> @@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	while (res->clock_for_reset[ispif->nclocks_for_reset])
>   		ispif->nclocks_for_reset++;
>   
> -	ispif->clock_for_reset = devm_kcalloc(dev,
> +	ispif->clock_for_reset = devm_kcalloc(camss->dev,
>   					      ispif->nclocks_for_reset,
>   					      sizeof(*ispif->clock_for_reset),
>   					      GFP_KERNEL);
> @@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
>   	for (i = 0; i < ispif->nclocks_for_reset; i++) {
>   		struct camss_clock *clock = &ispif->clock_for_reset[i];
>   
> -		clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
> +		clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
>   		if (IS_ERR(clock->clk))
>   			return PTR_ERR(clock->clk);
>   
> @@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
>   int msm_ispif_register_entities(struct ispif_device *ispif,
>   				struct v4l2_device *v4l2_dev)
>   {
> -	struct device *dev = to_device(ispif);
> +	struct camss *camss =  ispif->camss;
>   	int ret;
>   	int i;
>   
> +	if (!ispif)
> +		return 0;
> +
>   	for (i = 0; i < ispif->line_num; i++) {
>   		struct v4l2_subdev *sd = &ispif->line[i].subdev;
>   		struct media_pad *pads = ispif->line[i].pads;
> @@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
>   
>   		ret = ispif_init_formats(sd, NULL);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to init format: %d\n", ret);
> +			dev_err(camss->dev, "Failed to init format: %d\n", ret);
>   			goto error;
>   		}
>   
> @@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
>   		ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
>   					     pads);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to init media entity: %d\n", ret);
> +			dev_err(camss->dev, "Failed to init media entity: %d\n",
> +				ret);
>   			goto error;
>   		}
>   
>   		ret = v4l2_device_register_subdev(v4l2_dev, sd);
>   		if (ret < 0) {
> -			dev_err(dev, "Failed to register subdev: %d\n", ret);
> +			dev_err(camss->dev, "Failed to register subdev: %d\n",
> +				ret);
>   			media_entity_cleanup(&sd->entity);
>   			goto error;
>   		}
> @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
>   {
>   	int i;
>   
> +	if (!ispif)
> +		return;
> +
>   	mutex_destroy(&ispif->power_lock);
>   	mutex_destroy(&ispif->config_lock);
>   
> diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
> index 4132174f7ea1..fdf28e68cc7d 100644
> --- a/drivers/media/platform/qcom/camss/camss-ispif.h
> +++ b/drivers/media/platform/qcom/camss/camss-ispif.h
> @@ -63,11 +63,12 @@ struct ispif_device {
>   	struct mutex config_lock;
>   	unsigned int line_num;
>   	struct ispif_line *line;
> +	struct camss *camss;
>   };
>   
>   struct resources_ispif;
>   
> -int msm_ispif_subdev_init(struct ispif_device *ispif,
> +int msm_ispif_subdev_init(struct camss *camss,
>   			  const struct resources_ispif *res);
>   
>   int msm_ispif_register_entities(struct ispif_device *ispif,
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index 8fefce57bc49..aeec59bc6194 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
>   		}
>   	}
>   
> -	ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
> -	if (ret < 0) {
> -		dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> +	if (camss->ispif) {
> +		ret = msm_ispif_subdev_init(camss, ispif_res);
> +		if (ret < 0) {
> +			dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
>   			ret);
> -		return ret;
> +			return ret;
> +		}
>   	}
>   
>   	for (i = 0; i < camss->vfe_num; i++) {
> @@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
>   		}
>   	}
>   
> -	ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
> -	if (ret < 0) {
> -		dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> +	if (camss->ispif) {
> +		ret = msm_ispif_register_entities(camss->ispif,
> +						  &camss->v4l2_dev);
> +		if (ret < 0) {
> +			dev_err(camss->dev, "Failed to register ispif entities: %d\n",
>   			ret);
> -		goto err_reg_ispif;
> +			goto err_reg_ispif;
> +		}
>   	}
>   
>   	for (i = 0; i < camss->vfe_num; i++) {
> @@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
>   		}
>   	}
>   
> -	for (i = 0; i < camss->csid_num; i++) {
> -		for (j = 0; j < camss->ispif.line_num; j++) {
> -			ret = media_create_pad_link(
> -				&camss->csid[i].subdev.entity,
> -				MSM_CSID_PAD_SRC,
> -				&camss->ispif.line[j].subdev.entity,
> -				MSM_ISPIF_PAD_SINK,
> -				0);
> -			if (ret < 0) {
> -				dev_err(camss->dev,
> -					"Failed to link %s->%s entities: %d\n",
> -					camss->csid[i].subdev.entity.name,
> -					camss->ispif.line[j].subdev.entity.name,
> -					ret);
> -				goto err_link;
> -			}
> -		}
> -	}
> -
> -	for (i = 0; i < camss->ispif.line_num; i++)
> -		for (k = 0; k < camss->vfe_num; k++)
> -			for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +	if (camss->ispif) {
> +		for (i = 0; i < camss->csid_num; i++) {
> +			for (j = 0; j < camss->ispif->line_num; j++) {
>   				ret = media_create_pad_link(
> -					&camss->ispif.line[i].subdev.entity,
> -					MSM_ISPIF_PAD_SRC,
> -					&camss->vfe[k].line[j].subdev.entity,
> -					MSM_VFE_PAD_SINK,
> +					&camss->csid[i].subdev.entity,
> +					MSM_CSID_PAD_SRC,
> +					&camss->ispif->line[j].subdev.entity,
> +					MSM_ISPIF_PAD_SINK,
>   					0);
>   				if (ret < 0) {
>   					dev_err(camss->dev,
>   						"Failed to link %s->%s entities: %d\n",
> -						camss->ispif.line[i].subdev.entity.name,
> -						camss->vfe[k].line[j].subdev.entity.name,
> +						camss->csid[i].subdev.entity.name,
> +						camss->ispif->line[j].subdev.entity.name,
>   						ret);
>   					goto err_link;
>   				}
>   			}
> +		}
> +
> +		for (i = 0; i < camss->ispif->line_num; i++)
> +			for (k = 0; k < camss->vfe_num; k++)
> +				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +					ret = media_create_pad_link(
> +						&camss->ispif->line[i].subdev.entity,
> +						MSM_ISPIF_PAD_SRC,
> +						&camss->vfe[k].line[j].subdev.entity,
> +						MSM_VFE_PAD_SINK,
> +						0);
> +					if (ret < 0) {
> +						dev_err(camss->dev,
> +							"Failed to link %s->%s entities: %d\n",
> +							camss->ispif->line[i].subdev.entity.name,
> +							camss->vfe[k].line[j].subdev.entity.name,
> +							ret);
> +						goto err_link;
> +					}
> +				}
> +	} else {
> +		for (i = 0; i < camss->csid_num; i++)
> +			for (k = 0; k < camss->vfe_num; k++)
> +				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +					ret = media_create_pad_link(
> +						&camss->csid[i].subdev.entity,
> +						MSM_CSID_PAD_SRC,
> +						&camss->vfe[k].line[j].subdev.entity,
> +						MSM_VFE_PAD_SINK,
> +						0);
> +					if (ret < 0) {
> +						dev_err(camss->dev,
> +							"Failed to link %s->%s entities: %d\n",
> +							camss->csid[i].subdev.entity.name,
> +							camss->vfe[k].line[j].subdev.entity.name,
> +							ret);
> +						goto err_link;
> +					}
> +				}
> +	}
>   
>   	return 0;
>   
> @@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
>   	for (i--; i >= 0; i--)
>   		msm_vfe_unregister_entities(&camss->vfe[i]);
>   
> -	msm_ispif_unregister_entities(&camss->ispif);
>   err_reg_ispif:
> +	if (camss->ispif)
> +		msm_ispif_unregister_entities(camss->ispif);
>   
>   	i = camss->csid_num;
>   err_reg_csid:
> @@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
>   	for (i = 0; i < camss->csid_num; i++)
>   		msm_csid_unregister_entity(&camss->csid[i]);
>   
> -	msm_ispif_unregister_entities(&camss->ispif);
> +	if (camss->ispif)
> +		msm_ispif_unregister_entities(camss->ispif);
>   
>   	for (i = 0; i < camss->vfe_num; i++)
>   		msm_vfe_unregister_entities(&camss->vfe[i]);
> @@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
>   		goto err_free;
>   	}
>   
> +	if (camss->version == CAMSS_8x16 ||
> +	    camss->version == CAMSS_8x96) {
> +		camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);

- shouldn't it be sizeof(*camss->ispif) instead?

Thanks,
Andrey

> +		if (!camss->ispif) {
> +			ret = -ENOMEM;
> +			goto err_free;
> +		}
> +	}
> +
>   	camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
>   				  GFP_KERNEL);
>   	if (!camss->vfe) {
> diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
> index 46e986452824..b7ad8e9f68a8 100644
> --- a/drivers/media/platform/qcom/camss/camss.h
> +++ b/drivers/media/platform/qcom/camss/camss.h
> @@ -79,7 +79,7 @@ struct camss {
>   	struct csiphy_device *csiphy;
>   	int csid_num;
>   	struct csid_device *csid;
> -	struct ispif_device ispif;
> +	struct ispif_device *ispif;
>   	int vfe_num;
>   	struct vfe_device *vfe;
>   	atomic_t ref_count;
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 05/17] media: camss: Refactor VFE HW version support
  2021-01-08 12:04 ` [PATCH v1 05/17] media: camss: Refactor VFE HW version support Robert Foss
  2021-01-08 16:51   ` kernel test robot
@ 2021-01-13 22:38   ` Andrey Konovalov
  2021-01-14 10:07     ` Robert Foss
  1 sibling, 1 reply; 65+ messages in thread
From: Andrey Konovalov @ 2021-01-13 22:38 UTC (permalink / raw)
  To: Robert Foss, agross, bjorn.andersson, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Hi Robert,

Thank you for the patch!

On 08.01.2021 15:04, Robert Foss wrote:
> In order to support Qualcomm ISP hardware architectures that diverge
> from older architectures, the VFE subdevice driver needs to be refactored
> to better abstract the different ISP architectures.
> 
> Gen1 represents the CAMSS ISP architecture. The ISP architecture developed
> after CAMSS, Titan, will be referred to as Gen2.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>   drivers/media/platform/qcom/camss/Makefile    |    2 +
>   .../media/platform/qcom/camss/camss-vfe-4-1.c |  117 +-
>   .../media/platform/qcom/camss/camss-vfe-4-7.c |  238 ++--
>   .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
>   .../platform/qcom/camss/camss-vfe-gen1.c      |  760 +++++++++++
>   .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
>   drivers/media/platform/qcom/camss/camss-vfe.c |  770 +----------
>   drivers/media/platform/qcom/camss/camss-vfe.h |  113 +-
>   8 files changed, 2241 insertions(+), 1035 deletions(-)
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> 
> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> index 63c1b1b2943c..940c0ae3e003 100644
> --- a/drivers/media/platform/qcom/camss/Makefile
> +++ b/drivers/media/platform/qcom/camss/Makefile
> @@ -10,6 +10,8 @@ qcom-camss-objs += \
>   		camss-ispif.o \
>   		camss-vfe-4-1.o \
>   		camss-vfe-4-7.o \
> +		camss-vfe-4-8.o \
> +		camss-vfe-gen1.o \
>   		camss-vfe.o \
>   		camss-video.o \
>   
> 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 a1b56b89130d..269dc0860de9 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> @@ -12,7 +12,9 @@
>   #include <linux/io.h>
>   #include <linux/iopoll.h>
>   
> +#include "camss.h"
>   #include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
>   
>   #define VFE_0_HW_VERSION		0x000
>   
> @@ -283,30 +285,6 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
>   			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT);
>   }
>   
> -#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> -
> -static int vfe_word_per_line(u32 format, u32 pixel_per_line)
> -{
> -	int val = 0;
> -
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		val = CALC_WORD(pixel_per_line, 1, 8);
> -		break;
> -	case V4L2_PIX_FMT_YUYV:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_VYUY:
> -		val = CALC_WORD(pixel_per_line, 2, 8);
> -		break;
> -	}
> -
> -	return val;
> -}
> -
>   static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
>   			     u16 *width, u16 *height, u16 *bytesperline)
>   {
> @@ -665,20 +643,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
>   }
>   
> -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> -{
> -	if (input / output >= 16)
> -		return 0;
> -
> -	if (input / output >= 8)
> -		return 1;
> -
> -	if (input / output >= 4)
> -		return 2;
> -
> -	return 3;
> -}
> -
>   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;
> @@ -974,46 +938,61 @@ static irqreturn_t vfe_isr(int irq, void *dev)
>   	return IRQ_HANDLED;
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_1 = {
> -	.hw_version_read = vfe_hw_version_read,
> +
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
>   	.get_ub_size = vfe_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
>   	.halt_clear = vfe_halt_clear,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
>   	.wm_enable = vfe_wm_enable,
>   	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
>   	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_ping_addr = vfe_wm_set_ping_addr,
>   	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
>   	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe_set_qos,
> -	.set_ds = vfe_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_1;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_1 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
>   	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
>   	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
>   };
> 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 84c33b8f9fe3..d0d470be1c10 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> @@ -12,7 +12,10 @@
>   #include <linux/io.h>
>   #include <linux/iopoll.h>
>   
> +#include "camss.h"
>   #include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
>   
>   #define VFE_0_HW_VERSION		0x000
>   
> @@ -257,7 +260,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
>   	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
>   }
>   
> -static u16 vfe47_get_ub_size(u8 vfe_id)
> +static u16 vfe_get_ub_size(u8 vfe_id)
>   {
>   	if (vfe_id == 0)
>   		return MSM_VFE_VFE0_UB_SIZE_RDI;
> @@ -295,6 +298,8 @@ static void vfe_global_reset(struct vfe_device *vfe)
>   			 VFE_0_GLOBAL_RESET_CMD_CORE;
>   
>   	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> +
> +	/* Enforce barrier between IRQ mask setup and global reset */
>   	wmb();
>   	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
>   }
> @@ -310,7 +315,7 @@ static void vfe_halt_clear(struct vfe_device *vfe)
>   	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
>   }
>   
> -static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
>   {
>   	if (enable)
>   		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
> @@ -459,8 +464,12 @@ static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
>   
>   static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
>   {
> +	/* Enforce barrier between any outstanding register write */
>   	wmb();
> +
>   	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> +
> +	/* Use barrier to make sure bus reload is issued before anything else */
>   	wmb();
>   }
>   
> @@ -674,8 +683,12 @@ static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
>   static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
>   {
>   	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce barrier between line update and commit */
>   	wmb();
>   	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> +
> +	/* Make sure register update is issued before further reg writes */
>   	wmb();
>   }
>   
> @@ -779,20 +792,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
>   }
>   
> -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> -{
> -	if (input / output >= 16)
> -		return 0;
> -
> -	if (input / output >= 8)
> -		return 1;
> -
> -	if (input / output >= 4)
> -		return 2;
> -
> -	return 3;
> -}
> -
>   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;
> @@ -894,7 +893,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe)
>   	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
>   }
>   
> -static void vfe47_set_qos(struct vfe_device *vfe)
> +static void vfe_set_qos(struct vfe_device *vfe)
>   {
>   	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
>   	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> @@ -909,7 +908,7 @@ static void vfe47_set_qos(struct vfe_device *vfe)
>   	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
>   }
>   
> -static void vfe47_set_ds(struct vfe_device *vfe)
> +static void vfe_set_ds(struct vfe_device *vfe)
>   {
>   	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
>   	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> @@ -993,6 +992,8 @@ static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
>   
>   	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
>   	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +
> +	/* Make sure camif command is issued written before it is changed again */
>   	wmb();
>   
>   	if (enable)
> @@ -1035,24 +1036,7 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
>   	return ret;
>   }
>   
> -static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> -{
> -	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> -	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
>   
> -	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> -	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> -
> -	wmb();
> -	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> -}
> -
> -static void vfe_violation_read(struct vfe_device *vfe)
> -{
> -	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> -
> -	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> -}
>   
>   /*
>    * vfe_isr - VFE module interrupt handler
> @@ -1107,150 +1091,80 @@ static irqreturn_t vfe_isr(int irq, void *dev)
>   	return IRQ_HANDLED;
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_7 = {
> -	.hw_version_read = vfe_hw_version_read,
> -	.get_ub_size = vfe47_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
> -	.halt_clear = vfe_halt_clear,
> -	.wm_enable = vfe47_wm_enable,
> -	.wm_frame_based = vfe_wm_frame_based,
> -	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> -	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> -	.wm_set_ping_addr = vfe_wm_set_ping_addr,
> -	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> -	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe47_set_qos,
> -	.set_ds = vfe47_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> -	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
> -	.isr = vfe_isr,
> -};
> -
> -static u16 vfe48_get_ub_size(u8 vfe_id)
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
>   {
> -	/* On VFE4.8 the ub-size is the same on both instances */
> -	return MSM_VFE_VFE0_UB_SIZE_RDI;
> -}
> +	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> +	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
>   
> -static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> -{
> -	if (enable)
> -		writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> -			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> -	else
> -		writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> -			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> +	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> +	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
>   
> -	/* The WM must be enabled before sending other commands */
> +	/* Enforce barrier between local & global IRQ clear */
>   	wmb();
> +	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
>   }
>   
> -static void vfe48_set_qos(struct vfe_device *vfe)
> -{
> -	u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG;
> -	u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG;
> -	u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG;
> -	u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG;
> -
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> -	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> -	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> -}
> -
> -static void vfe48_set_ds(struct vfe_device *vfe)
> +static void vfe_violation_read(struct vfe_device *vfe)
>   {
> -	u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG;
> -	u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG;
> +	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
>   
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> -	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_8 = {
> -	.hw_version_read = vfe_hw_version_read,
> -	.get_ub_size = vfe48_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> +	.get_ub_size = vfe_get_ub_size,
>   	.halt_clear = vfe_halt_clear,
> -	.wm_enable = vfe48_wm_enable,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
> +	.wm_enable = vfe_wm_enable,
>   	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
>   	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_ping_addr = vfe_wm_set_ping_addr,
>   	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
>   	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe48_set_qos,
> -	.set_ds = vfe48_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_7;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_7 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
>   	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
>   	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
>   };
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> new file mode 100644
> index 000000000000..609db85c5039
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> @@ -0,0 +1,1166 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-4-7.c

camss-vfe-4-8.c ?

> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7

- same here: v4.8

Thanks,
Andrey

> + *
> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2018 Linaro Ltd.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
> +
> +#define VFE_0_HW_VERSION		0x000
> +
> +#define VFE_0_GLOBAL_RESET_CMD		0x018
> +#define VFE_0_GLOBAL_RESET_CMD_CORE	BIT(0)
> +#define VFE_0_GLOBAL_RESET_CMD_CAMIF	BIT(1)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS	BIT(2)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
> +#define VFE_0_GLOBAL_RESET_CMD_REGISTER	BIT(4)
> +#define VFE_0_GLOBAL_RESET_CMD_PM	BIT(5)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
> +#define VFE_0_GLOBAL_RESET_CMD_TESTGEN	BIT(7)
> +#define VFE_0_GLOBAL_RESET_CMD_DSP	BIT(8)
> +#define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
> +
> +#define VFE_0_MODULE_LENS_EN		0x040
> +#define VFE_0_MODULE_LENS_EN_DEMUX		BIT(2)
> +#define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE	BIT(3)
> +
> +#define VFE_0_MODULE_ZOOM_EN		0x04c
> +#define VFE_0_MODULE_ZOOM_EN_SCALE_ENC		BIT(1)
> +#define VFE_0_MODULE_ZOOM_EN_CROP_ENC		BIT(2)
> +#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF	BIT(9)
> +
> +#define VFE_0_CORE_CFG			0x050
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR	0x4
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB	0x5
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY	0x6
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY	0x7
> +#define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
> +
> +#define VFE_0_IRQ_CMD			0x058
> +#define VFE_0_IRQ_CMD_GLOBAL_CLEAR	BIT(0)
> +
> +#define VFE_0_IRQ_MASK_0		0x05c
> +#define VFE_0_IRQ_MASK_0_CAMIF_SOF			BIT(0)
> +#define VFE_0_IRQ_MASK_0_CAMIF_EOF			BIT(1)
> +#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n)		\
> +	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n))
> +#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define VFE_0_IRQ_MASK_0_RESET_ACK			BIT(31)
> +#define VFE_0_IRQ_MASK_1		0x060
> +#define VFE_0_IRQ_MASK_1_CAMIF_ERROR			BIT(0)
> +#define VFE_0_IRQ_MASK_1_VIOLATION			BIT(7)
> +#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
> +#define VFE_0_IRQ_MASK_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_0_IRQ_CLEAR_0		0x064
> +#define VFE_0_IRQ_CLEAR_1		0x068
> +
> +#define VFE_0_IRQ_STATUS_0		0x06c
> +#define VFE_0_IRQ_STATUS_0_CAMIF_SOF			BIT(0)
> +#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n)		\
> +	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n))
> +#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define VFE_0_IRQ_STATUS_0_RESET_ACK			BIT(31)
> +#define VFE_0_IRQ_STATUS_1		0x070
> +#define VFE_0_IRQ_STATUS_1_VIOLATION			BIT(7)
> +#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_0_IRQ_COMPOSITE_MASK_0	0x074
> +#define VFE_0_VIOLATION_STATUS		0x07c
> +
> +#define VFE_0_BUS_CMD			0x80
> +#define VFE_0_BUS_CMD_Mx_RLD_CMD(x)	BIT(x)
> +
> +#define VFE_0_BUS_CFG			0x084
> +
> +#define VFE_0_BUS_XBAR_CFG_x(x)		(0x90 + 0x4 * ((x) / 2))
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN			BIT(2)
> +#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN			BIT(3)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA		(0x1 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER		(0x2 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA	(0x3 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT		8
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA		0x0
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0	0xc
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1	0xd
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2	0xe
> +
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n)		(0x0a0 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT	0
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n)	(0x0a4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n)	(0x0ac + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n)		(0x0b4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT	1
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT	2
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK	(0x1f << 2)
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n)		(0x0b8 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT	16
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n)	(0x0bc + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n)	(0x0c0 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n)	\
> +							(0x0c4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n)	\
> +							(0x0c8 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF	0xffffffff
> +
> +#define VFE_0_BUS_PING_PONG_STATUS	0x338
> +
> +#define VFE_0_BUS_BDG_CMD		0x400
> +#define VFE_0_BUS_BDG_CMD_HALT_REQ	1
> +
> +#define VFE_0_BUS_BDG_QOS_CFG_0		0x404
> +#define VFE_0_BUS_BDG_QOS_CFG_0_CFG	0xaaa5aaa5
> +#define VFE_0_BUS_BDG_QOS_CFG_1		0x408
> +#define VFE_0_BUS_BDG_QOS_CFG_2		0x40c
> +#define VFE_0_BUS_BDG_QOS_CFG_3		0x410
> +#define VFE_0_BUS_BDG_QOS_CFG_3_CFG	0xaa55aaa5
> +#define VFE_0_BUS_BDG_QOS_CFG_4		0x414
> +#define VFE_0_BUS_BDG_QOS_CFG_4_CFG	0xaa55aa55
> +#define VFE_0_BUS_BDG_QOS_CFG_5		0x418
> +#define VFE_0_BUS_BDG_QOS_CFG_6		0x41c
> +#define VFE_0_BUS_BDG_QOS_CFG_7		0x420
> +#define VFE_0_BUS_BDG_QOS_CFG_7_CFG	0x0005aa55
> +
> +#define VFE_0_BUS_BDG_DS_CFG_0		0x424
> +#define VFE_0_BUS_BDG_DS_CFG_0_CFG	0xcccc1111
> +#define VFE_0_BUS_BDG_DS_CFG_1		0x428
> +#define VFE_0_BUS_BDG_DS_CFG_2		0x42c
> +#define VFE_0_BUS_BDG_DS_CFG_3		0x430
> +#define VFE_0_BUS_BDG_DS_CFG_4		0x434
> +#define VFE_0_BUS_BDG_DS_CFG_5		0x438
> +#define VFE_0_BUS_BDG_DS_CFG_6		0x43c
> +#define VFE_0_BUS_BDG_DS_CFG_7		0x440
> +#define VFE_0_BUS_BDG_DS_CFG_8		0x444
> +#define VFE_0_BUS_BDG_DS_CFG_9		0x448
> +#define VFE_0_BUS_BDG_DS_CFG_10		0x44c
> +#define VFE_0_BUS_BDG_DS_CFG_11		0x450
> +#define VFE_0_BUS_BDG_DS_CFG_12		0x454
> +#define VFE_0_BUS_BDG_DS_CFG_13		0x458
> +#define VFE_0_BUS_BDG_DS_CFG_14		0x45c
> +#define VFE_0_BUS_BDG_DS_CFG_15		0x460
> +#define VFE_0_BUS_BDG_DS_CFG_16		0x464
> +#define VFE_0_BUS_BDG_DS_CFG_16_CFG	0x00000110
> +
> +#define VFE_0_RDI_CFG_x(x)		(0x46c + (0x4 * (x)))
> +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT	28
> +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK	(0xf << 28)
> +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT	4
> +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK		(0xf << 4)
> +#define VFE_0_RDI_CFG_x_RDI_EN_BIT		BIT(2)
> +#define VFE_0_RDI_CFG_x_MIPI_EN_BITS		0x3
> +
> +#define VFE_0_CAMIF_CMD				0x478
> +#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY	0
> +#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY	1
> +#define VFE_0_CAMIF_CMD_NO_CHANGE		3
> +#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS	BIT(2)
> +#define VFE_0_CAMIF_CFG				0x47c
> +#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN		BIT(6)
> +#define VFE_0_CAMIF_FRAME_CFG			0x484
> +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
> +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
> +#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
> +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
> +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
> +#define VFE_0_CAMIF_STATUS			0x4a4
> +#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
> +
> +#define VFE_0_REG_UPDATE		0x4ac
> +#define VFE_0_REG_UPDATE_RDIn(n)		BIT(1 + (n))
> +#define VFE_0_REG_UPDATE_line_n(n)		\
> +			((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n))
> +
> +#define VFE_0_DEMUX_CFG				0x560
> +#define VFE_0_DEMUX_CFG_PERIOD			0x3
> +#define VFE_0_DEMUX_GAIN_0			0x564
> +#define VFE_0_DEMUX_GAIN_0_CH0_EVEN		(0x80 << 0)
> +#define VFE_0_DEMUX_GAIN_0_CH0_ODD		(0x80 << 16)
> +#define VFE_0_DEMUX_GAIN_1			0x568
> +#define VFE_0_DEMUX_GAIN_1_CH1			(0x80 << 0)
> +#define VFE_0_DEMUX_GAIN_1_CH2			(0x80 << 16)
> +#define VFE_0_DEMUX_EVEN_CFG			0x574
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV	0x9cac
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU	0xac9c
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY	0xc9ca
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY	0xcac9
> +#define VFE_0_DEMUX_ODD_CFG			0x578
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV	0x9cac
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU	0xac9c
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY	0xc9ca
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY	0xcac9
> +
> +#define VFE_0_SCALE_ENC_Y_CFG			0x91c
> +#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE		0x920
> +#define VFE_0_SCALE_ENC_Y_H_PHASE		0x924
> +#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE		0x934
> +#define VFE_0_SCALE_ENC_Y_V_PHASE		0x938
> +#define VFE_0_SCALE_ENC_CBCR_CFG		0x948
> +#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE	0x94c
> +#define VFE_0_SCALE_ENC_CBCR_H_PHASE		0x950
> +#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE	0x960
> +#define VFE_0_SCALE_ENC_CBCR_V_PHASE		0x964
> +
> +#define VFE_0_CROP_ENC_Y_WIDTH			0x974
> +#define VFE_0_CROP_ENC_Y_HEIGHT			0x978
> +#define VFE_0_CROP_ENC_CBCR_WIDTH		0x97c
> +#define VFE_0_CROP_ENC_CBCR_HEIGHT		0x980
> +
> +#define VFE_0_CLAMP_ENC_MAX_CFG			0x984
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH0		(0xff << 0)
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH1		(0xff << 8)
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH2		(0xff << 16)
> +#define VFE_0_CLAMP_ENC_MIN_CFG			0x988
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH0		(0x0 << 0)
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH1		(0x0 << 8)
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH2		(0x0 << 16)
> +
> +#define VFE_0_REALIGN_BUF_CFG			0xaac
> +#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL     BIT(2)
> +#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL     BIT(3)
> +#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE      BIT(4)
> +
> +#define VFE_0_BUS_IMAGE_MASTER_CMD		0xcec
> +#define VFE_0_BUS_IMAGE_MASTER_n_SHIFT(x)	(2 * (x))
> +
> +#define CAMIF_TIMEOUT_SLEEP_US 1000
> +#define CAMIF_TIMEOUT_ALL_US 1000000
> +
> +#define MSM_VFE_VFE0_UB_SIZE 2047
> +#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3)
> +#define MSM_VFE_VFE1_UB_SIZE 1535
> +#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3)
> +
> +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
> +
> +	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
> +}
> +
> +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> +}
> +
> +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits | set_bits, vfe->base + reg);
> +}
> +
> +static void vfe_global_reset(struct vfe_device *vfe)
> +{
> +	u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	|
> +			 VFE_0_GLOBAL_RESET_CMD_DSP		|
> +			 VFE_0_GLOBAL_RESET_CMD_TESTGEN		|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS_MISR	|
> +			 VFE_0_GLOBAL_RESET_CMD_PM		|
> +			 VFE_0_GLOBAL_RESET_CMD_REGISTER	|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS_BDG		|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS		|
> +			 VFE_0_GLOBAL_RESET_CMD_CAMIF		|
> +			 VFE_0_GLOBAL_RESET_CMD_CORE;
> +
> +	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> +
> +	/* Enforce barrier between IRQ mask setup and global reset */
> +	wmb();
> +	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
> +}
> +
> +static void vfe_halt_request(struct vfe_device *vfe)
> +{
> +	writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ,
> +		       vfe->base + VFE_0_BUS_BDG_CMD);
> +}
> +
> +static void vfe_halt_clear(struct vfe_device *vfe)
> +{
> +	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
> +}
> +
> +static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	if (enable)
> +		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> +			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> +	else
> +		vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> +			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> +}
> +
> +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> +
> +static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line)
> +{
> +	int val = 0;
> +
> +	switch (format) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		val = CALC_WORD(pixel_per_line, 1, 8);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_UYVY:
> +	case V4L2_PIX_FMT_VYUY:
> +		val = CALC_WORD(pixel_per_line, 2, 8);
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +static int vfe_word_per_line_by_bytes(u32 bytes_per_line)
> +{
> +	return CALC_WORD(bytes_per_line, 1, 8);
> +}
> +
> +static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
> +			     u16 *width, u16 *height, u16 *bytesperline)
> +{
> +	switch (pix->pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[0].bytesperline;
> +		if (plane == 1)
> +			*height /= 2;
> +		break;
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[0].bytesperline;
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_VYUY:
> +	case V4L2_PIX_FMT_UYVY:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[plane].bytesperline;
> +		break;
> +
> +	}
> +}
> +
> +static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm,
> +			      struct v4l2_pix_format_mplane *pix,
> +			      u8 plane, u32 enable)
> +{
> +	u32 reg;
> +
> +	if (enable) {
> +		u16 width = 0, height = 0, bytesperline = 0, wpl;
> +
> +		vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline);
> +
> +		wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width);
> +
> +		reg = height - 1;
> +		reg |= ((wpl + 3) / 4 - 1) << 16;
> +
> +		writel_relaxed(reg, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> +
> +		wpl = vfe_word_per_line_by_bytes(bytesperline);
> +
> +		reg = 0x3;
> +		reg |= (height - 1) << 2;
> +		reg |= ((wpl + 1) / 2) << 16;
> +
> +		writel_relaxed(reg, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> +	} else {
> +		writel_relaxed(0, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> +		writel_relaxed(0, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> +	}
> +}
> +
> +static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(vfe->base +
> +			    VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> +
> +	reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK);
> +
> +	reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT)
> +		& VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK;
> +
> +	writel_relaxed(reg,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> +}
> +
> +static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm,
> +					 u32 pattern)
> +{
> +	writel_relaxed(pattern,
> +	       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm));
> +}
> +
> +static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
> +			      u16 offset, u16 depth)
> +{
> +	u32 reg;
> +
> +	reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) |
> +		depth;
> +	writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm));
> +}
> +
> +static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
> +{
> +	/* Enforce barrier between any outstanding register write */
> +	wmb();
> +
> +	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> +
> +	/* Use barrier to make sure bus reload is issued before anything else */
> +	wmb();
> +}
> +
> +static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> +{
> +	writel_relaxed(addr,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm));
> +}
> +
> +static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> +{
> +	writel_relaxed(addr,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm));
> +}
> +
> +static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS);
> +
> +	return (reg >> wm) & 0x1;
> +}
> +
> +static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable)
> +{
> +	if (enable)
> +		writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG);
> +	else
> +		writel_relaxed(0, vfe->base + VFE_0_BUS_CFG);
> +}
> +
> +static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm,
> +				      enum vfe_line_id id)
> +{
> +	u32 reg;
> +
> +	reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg);
> +
> +	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> +	reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) &
> +		VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg);
> +
> +	switch (id) {
> +	case VFE_LINE_RDI0:
> +	default:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI1:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI2:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	}
> +
> +	if (wm % 2 == 1)
> +		reg <<= 16;
> +
> +	vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> +}
> +
> +static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm)
> +{
> +	writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF,
> +	       vfe->base +
> +	       VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm));
> +}
> +
> +static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
> +					   enum vfe_line_id id)
> +{
> +	u32 reg;
> +
> +	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> +	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg);
> +
> +	switch (id) {
> +	case VFE_LINE_RDI0:
> +	default:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI1:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI2:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	}
> +
> +	if (wm % 2 == 1)
> +		reg <<= 16;
> +
> +	vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> +}
> +
> +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);
> +	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> +	u32 reg;
> +
> +	switch (p) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		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)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    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)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> +				    reg);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_VYUY:
> +	case V4L2_PIX_FMT_UYVY:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN;
> +		reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
> +
> +		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)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +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 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
> +
> +	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
> +			p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY)
> +		return;
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val);
> +		return;
> +	}
> +
> +	val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE;
> +
> +	if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV)
> +		val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL;
> +	else
> +		val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG);
> +}
> +
> +static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
> +{
> +	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id),
> +		    VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK);
> +
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id),
> +		    cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT);
> +}
> +
> +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce barrier between line update and commit */
> +	wmb();
> +
> +	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> +
> +	/* Make sure register update is issued before further reg writes */
> +	wmb();
> +}
> +
> +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> +					enum vfe_line_id line_id)
> +{
> +	vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id);
> +}
> +
> +static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
> +				   enum vfe_line_id line_id, u8 enable)
> +{
> +	u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) |
> +		      VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
> +	u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) |
> +		      VFE_0_IRQ_MASK_1_RDIn_SOF(line_id);
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +	}
> +}
> +
> +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;
> +	unsigned int i;
> +	u32 irq_en0;
> +	u32 irq_en1;
> +	u32 comp_mask = 0;
> +
> +	irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF;
> +	irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF;
> +	irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(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;
> +	}
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +		vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> +	}
> +}
> +
> +static void vfe_enable_irq_common(struct vfe_device *vfe)
> +{
> +	u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK;
> +	u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION |
> +		      VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK;
> +
> +	vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +	vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +}
> +
> +static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 val, even_cfg, odd_cfg;
> +
> +	writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG);
> +
> +	val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD;
> +	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0);
> +
> +	val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2;
> +	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1);
> +
> +	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> +	case MEDIA_BUS_FMT_YUYV8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV;
> +		break;
> +	case MEDIA_BUS_FMT_YVYU8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_2X8:
> +	default:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY;
> +		break;
> +	case MEDIA_BUS_FMT_VYUY8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY;
> +		break;
> +	}
> +
> +	writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG);
> +	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
> +}
> +
> +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 reg;
> +	u16 input, output;
> +	u8 interp_reso;
> +	u32 phase_mult;
> +
> +	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> +	output = line->compose.width - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	output = line->compose.height - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE);
> +
> +	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> +	output = line->compose.width / 2 - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	output = line->compose.height - 1;
> +	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21)
> +		output = line->compose.height / 2 - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE);
> +}
> +
> +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 reg;
> +	u16 first, last;
> +
> +	first = line->crop.left;
> +	last = line->crop.left + line->crop.width - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH);
> +
> +	first = line->crop.top;
> +	last = line->crop.top + line->crop.height - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT);
> +
> +	first = line->crop.left / 2;
> +	last = line->crop.left / 2 + line->crop.width / 2 - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH);
> +
> +	first = line->crop.top;
> +	last = line->crop.top + line->crop.height - 1;
> +	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) {
> +		first = line->crop.top / 2;
> +		last = line->crop.top / 2 + line->crop.height / 2 - 1;
> +	}
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT);
> +}
> +
> +static void vfe_set_clamp_cfg(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 |
> +		VFE_0_CLAMP_ENC_MAX_CFG_CH1 |
> +		VFE_0_CLAMP_ENC_MAX_CFG_CH2;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG);
> +
> +	val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 |
> +		VFE_0_CLAMP_ENC_MIN_CFG_CH1 |
> +		VFE_0_CLAMP_ENC_MIN_CFG_CH2;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
> +}
> +
> +static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	/* empty */
> +}
> +
> +static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 val;
> +
> +	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> +	case MEDIA_BUS_FMT_YUYV8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR;
> +		break;
> +	case MEDIA_BUS_FMT_YVYU8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_2X8:
> +	default:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY;
> +		break;
> +	case MEDIA_BUS_FMT_VYUY8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY;
> +		break;
> +	}
> +
> +	val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN;
> +	writel_relaxed(val, vfe->base + VFE_0_CORE_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> +	val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN);
> +
> +	val = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val);
> +
> +	val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG);
> +}
> +
> +static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
> +{
> +	u32 cmd;
> +
> +	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
> +	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +
> +	/* Make sure camif command is issued written before it is changed again */
> +	wmb();
> +
> +	if (enable)
> +		cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY;
> +	else
> +		cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY;
> +
> +	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +}
> +
> +static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable)
> +{
> +	u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX |
> +		       VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE;
> +	u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC |
> +		       VFE_0_MODULE_ZOOM_EN_CROP_ENC;
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> +		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> +		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> +	}
> +}
> +
> +static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS,
> +				 val,
> +				 (val & VFE_0_CAMIF_STATUS_HALT),
> +				 CAMIF_TIMEOUT_SLEEP_US,
> +				 CAMIF_TIMEOUT_ALL_US);
> +	if (ret < 0)
> +		dev_err(dev, "%s: camif stop timeout\n", __func__);
> +
> +	return ret;
> +}
> +
> +
> +
> +/*
> + * vfe_isr - VFE module interrupt handler
> + * @irq: Interrupt line
> + * @dev: VFE device
> + *
> + * Return IRQ_HANDLED on success
> + */
> +static irqreturn_t vfe_isr(int irq, void *dev)
> +{
> +	struct vfe_device *vfe = dev;
> +	u32 value0, value1;
> +	int i, j;
> +
> +	vfe->ops->isr_read(vfe, &value0, &value1);
> +
> +	trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n",
> +		     value0, value1);
> +
> +	if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK)
> +		vfe->isr_ops.reset_ack(vfe);
> +
> +	if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
> +		vfe->ops->violation_read(vfe);
> +
> +	if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
> +		vfe->isr_ops.halt_ack(vfe);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
> +			vfe->isr_ops.reg_update(vfe, i);
> +
> +	if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF)
> +		vfe->isr_ops.sof(vfe, VFE_LINE_PIX);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> +		if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i))
> +			vfe->isr_ops.sof(vfe, i);
> +
> +	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) {
> +			vfe->isr_ops.comp_done(vfe, i);
> +			for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++)
> +				if (vfe->wm_output_map[j] == VFE_LINE_PIX)
> +					value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j);
> +		}
> +
> +	for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i))
> +			vfe->isr_ops.wm_done(vfe, i);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static u16 vfe_get_ub_size(u8 vfe_id)
> +{
> +	/* On VFE4.8 the ub-size is the same on both instances */
> +	return MSM_VFE_VFE0_UB_SIZE_RDI;
> +}
> +
> +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	if (enable)
> +		writel_relaxed(2 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> +			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> +	else
> +		writel_relaxed(1 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> +			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> +
> +	/* The WM must be enabled before sending other commands */
> +	wmb();
> +}
> +
> +static void vfe_set_qos(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
> +	u32 val3 = VFE_0_BUS_BDG_QOS_CFG_3_CFG;
> +	u32 val4 = VFE_0_BUS_BDG_QOS_CFG_4_CFG;
> +	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> +	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> +	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> +}
> +
> +static void vfe_set_ds(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
> +	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> +	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> +}
> +
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> +{
> +	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> +	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
> +
> +	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> +	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> +
> +	/* Enforce barrier between local & global IRQ clear */
> +	wmb();
> +	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> +}
> +
> +static void vfe_violation_read(struct vfe_device *vfe)
> +{
> +	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> +
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> +}
> +
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_8 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> +	.get_ub_size = vfe_get_ub_size,
> +	.halt_clear = vfe_halt_clear,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
> +	.wm_enable = vfe_wm_enable,
> +	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> +	.wm_line_based = vfe_wm_line_based,
> +	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> +	.wm_set_ping_addr = vfe_wm_set_ping_addr,
> +	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> +	.wm_set_subsample = vfe_wm_set_subsample,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_8;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_8 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
> +	.isr_read = vfe_isr_read,
> +	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
> +};
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> new file mode 100644
> index 000000000000..ffc543685081
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> @@ -0,0 +1,760 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-gen1.c
> + *
> + * Qualcomm MSM Camera Subsystem - VFE Common functionality for Gen 1 versions of hw (4.1, 4.7..)
> + *
> + * Copyright (C) 2020 Linaro Ltd.
> + */
> +
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
> +/* Max number of frame drop updates per frame */
> +#define VFE_FRAME_DROP_UPDATES 2
> +#define VFE_NEXT_SOF_MS 500
> +
> +
> +int vfe_gen1_halt(struct vfe_device *vfe)
> +{
> +	unsigned long time;
> +
> +	return 0;
> +
> +	reinit_completion(&vfe->halt_complete);
> +
> +	vfe->ops_gen1->halt_request(vfe);
> +
> +	time = wait_for_completion_timeout(&vfe->halt_complete,
> +					   msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> +	if (!time) {
> +		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vfe_disable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	unsigned long flags;
> +	unsigned long time;
> +	unsigned int i;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output->gen1.wait_sof = 1;
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	time = wait_for_completion_timeout(&output->sof, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> +	if (!time)
> +		dev_err(vfe->camss->dev, "VFE sof timeout\n");
> +
> +	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);
> +
> +	ops->reg_update(vfe, line->id);
> +	output->wait_reg_update = 1;
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	time = wait_for_completion_timeout(&output->reg_update, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> +	if (!time)
> +		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> +
> +	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);
> +		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->enable_irq_pix_line(vfe, 0, line->id, 0);
> +		vfe->ops_gen1->set_module_cfg(vfe, 0);
> +		vfe->ops_gen1->set_realign_cfg(vfe, line, 0);
> +		vfe->ops_gen1->set_xbar_cfg(vfe, output, 0);
> +		vfe->ops_gen1->set_camif_cmd(vfe, 0);
> +
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +		vfe->ops_gen1->camif_wait_for_stop(vfe, vfe->camss->dev);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_gen1_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_gen1_disable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +
> +	vfe_disable_output(line);
> +
> +	vfe_put_output(line);
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (vfe->stream_count == 1)
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return 0;
> +}
> +
> +static void vfe_output_init_addrs(struct vfe_device *vfe,
> +				  struct vfe_output *output, u8 sync,
> +				  struct vfe_line *line)
> +{
> +	u32 ping_addr;
> +	u32 pong_addr;
> +	unsigned int i;
> +
> +	output->gen1.active_buf = 0;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[0])
> +			ping_addr = output->buf[0]->addr[i];
> +		else
> +			ping_addr = 0;
> +
> +		if (output->buf[1])
> +			pong_addr = output->buf[1]->addr[i];
> +		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);
> +		if (sync)
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +	}
> +}
> +
> +static void vfe_output_frame_drop(struct vfe_device *vfe,
> +				  struct vfe_output *output,
> +				  u32 drop_pattern)
> +{
> +	u8 drop_period;
> +	unsigned int i;
> +
> +	/* We need to toggle update period to be valid on next frame */
> +	output->drop_update_idx++;
> +	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> +	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->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
> +}
> +
> +static int vfe_enable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	struct media_entity *sensor;
> +	unsigned long flags;
> +	unsigned int frame_skip = 0;
> +	unsigned int i;
> +	u16 ub_size;
> +
> +	ub_size = vfe->ops_gen1->get_ub_size(vfe->id);
> +	if (!ub_size)
> +		return -EINVAL;
> +
> +	sensor = camss_find_sensor(&line->subdev.entity);
> +	if (sensor) {
> +		struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor);
> +
> +		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;
> +	}
> +	output->state = VFE_OUTPUT_IDLE;
> +
> +	output->buf[0] = vfe_buf_get_pending(output);
> +	output->buf[1] = vfe_buf_get_pending(output);
> +
> +	if (!output->buf[0] && output->buf[1]) {
> +		output->buf[0] = output->buf[1];
> +		output->buf[1] = NULL;
> +	}
> +
> +	if (output->buf[0])
> +		output->state = VFE_OUTPUT_SINGLE;
> +
> +	if (output->buf[1])
> +		output->state = VFE_OUTPUT_CONTINUOUS;
> +
> +	switch (output->state) {
> +	case VFE_OUTPUT_SINGLE:
> +		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> +		break;
> +	case VFE_OUTPUT_CONTINUOUS:
> +		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> +		break;
> +	default:
> +		vfe_output_frame_drop(vfe, output, 0);
> +		break;
> +	}
> +
> +	output->sequence = 0;
> +	output->gen1.wait_sof = 0;
> +	output->wait_reg_update = 0;
> +	reinit_completion(&output->sof);
> +	reinit_completion(&output->reg_update);
> +
> +	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_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]);
> +	} 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],
> +						     &line->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->enable_irq_pix_line(vfe, 0, line->id, 1);
> +		vfe->ops_gen1->set_module_cfg(vfe, 1);
> +		vfe->ops_gen1->set_camif_cfg(vfe, line);
> +		vfe->ops_gen1->set_realign_cfg(vfe, line, 1);
> +		vfe->ops_gen1->set_xbar_cfg(vfe, output, 1);
> +		vfe->ops_gen1->set_demux_cfg(vfe, line);
> +		vfe->ops_gen1->set_scale_cfg(vfe, line);
> +		vfe->ops_gen1->set_crop_cfg(vfe, line);
> +		vfe->ops_gen1->set_clamp_cfg(vfe);
> +		vfe->ops_gen1->set_camif_cmd(vfe, 1);
> +	}
> +
> +	ops->reg_update(vfe, line->id);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +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;
> +	unsigned long flags;
> +	int i;
> +	int wm_idx;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output = &line->output;
> +	if (output->state != VFE_OUTPUT_OFF) {
> +		dev_err(vfe->camss->dev, "Output is running\n");
> +		goto error;
> +	}
> +	output->state = VFE_OUTPUT_RESERVED;
> +
> +	output->gen1.active_buf = 0;
> +
> +	switch (f->fmt.pix_mp.pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		output->wm_num = 2;
> +		break;
> +	default:
> +		output->wm_num = 1;
> +		break;
> +	}
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		wm_idx = vfe_reserve_wm(vfe, line->id);
> +		if (wm_idx < 0) {
> +			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> +			goto error_get_wm;
> +		}
> +		output->wm_idx[i] = wm_idx;
> +	}
> +
> +	output->drop_update_idx = 0;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +
> +error_get_wm:
> +	for (i--; i >= 0; i--)
> +		vfe_release_wm(vfe, output->wm_idx[i]);
> +	output->state = VFE_OUTPUT_OFF;
> +error:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return -EINVAL;
> +}
> +
> +int vfe_gen1_enable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	int ret;
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (!vfe->stream_count) {
> +		vfe->ops_gen1->enable_irq_common(vfe);
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 1);
> +		vfe->ops_gen1->set_qos(vfe);
> +		vfe->ops_gen1->set_ds(vfe);
> +	}
> +
> +	vfe->stream_count++;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	ret = vfe_get_output(line);
> +	if (ret < 0)
> +		goto error_get_output;
> +
> +	ret = vfe_enable_output(line);
> +	if (ret < 0)
> +		goto error_enable_output;
> +
> +	vfe->was_streaming = 1;
> +
> +	return 0;
> +
> +
> +error_enable_output:
> +	vfe_put_output(line);
> +
> +error_get_output:
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (vfe->stream_count == 1)
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return ret;
> +}
> +
> +static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> +					struct vfe_output *output, u8 sync,
> +					struct vfe_line *line)
> +{
> +	u32 addr;
> +	unsigned int i;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[0])
> +			addr = output->buf[0]->addr[i];
> +		else
> +			addr = 0;
> +
> +		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> +		if (sync)
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +	}
> +}
> +
> +static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> +					struct vfe_output *output, u8 sync,
> +					struct vfe_line *line)
> +{
> +	u32 addr;
> +	unsigned int i;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[1])
> +			addr = output->buf[1]->addr[i];
> +		else
> +			addr = 0;
> +
> +		// XXX
> +	}
> +
> +}
> +
> +static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> +				      struct vfe_output *output)
> +{
> +	switch (output->state) {
> +	case VFE_OUTPUT_CONTINUOUS:
> +		vfe_output_frame_drop(vfe, output, 3);
> +		break;
> +	case VFE_OUTPUT_SINGLE:
> +	default:
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Next buf in wrong state! %d\n",
> +				    output->state);
> +		break;
> +	}
> +}
> +
> +static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> +				      struct vfe_output *output)
> +{
> +	switch (output->state) {
> +	case VFE_OUTPUT_CONTINUOUS:
> +		output->state = VFE_OUTPUT_SINGLE;
> +		vfe_output_frame_drop(vfe, output, 1);
> +		break;
> +	case VFE_OUTPUT_SINGLE:
> +		output->state = VFE_OUTPUT_STOPPING;
> +		vfe_output_frame_drop(vfe, output, 0);
> +		break;
> +	default:
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Last buff in wrong state! %d\n",
> +				    output->state);
> +		break;
> +	}
> +}
> +
> +static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> +				     struct vfe_output *output,
> +				     struct camss_buffer *new_buf,
> +				     struct vfe_line *line)
> +{
> +	int inactive_idx;
> +
> +	switch (output->state) {
> +	case VFE_OUTPUT_SINGLE:
> +		inactive_idx = !output->gen1.active_buf;
> +
> +		if (!output->buf[inactive_idx]) {
> +			output->buf[inactive_idx] = new_buf;
> +
> +			if (inactive_idx)
> +				vfe_output_update_pong_addr(vfe, output, 0, line);
> +			else
> +				vfe_output_update_ping_addr(vfe, output, 0, line);
> +
> +			vfe_output_frame_drop(vfe, output, 3);
> +			output->state = VFE_OUTPUT_CONTINUOUS;
> +		} else {
> +			vfe_buf_add_pending(output, new_buf);
> +			dev_err_ratelimited(vfe->camss->dev,
> +					    "Inactive buffer is busy\n");
> +		}
> +		break;
> +
> +	case VFE_OUTPUT_IDLE:
> +		if (!output->buf[0]) {
> +			output->buf[0] = new_buf;
> +
> +			vfe_output_init_addrs(vfe, output, 1, line);
> +			vfe_output_frame_drop(vfe, output, 1);
> +
> +			output->state = VFE_OUTPUT_SINGLE;
> +		} else {
> +			vfe_buf_add_pending(output, new_buf);
> +			dev_err_ratelimited(vfe->camss->dev,
> +					    "Output idle with buffer set!\n");
> +		}
> +		break;
> +
> +	case VFE_OUTPUT_CONTINUOUS:
> +	default:
> +		vfe_buf_add_pending(output, new_buf);
> +		break;
> +	}
> +}
> +
> +/*
> + * vfe_isr_halt_ack - Process start of frame interrupt
> + * @vfe: VFE Device
> + */
> +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> +{
> +	complete(&vfe->halt_complete);
> +	vfe->ops_gen1->halt_clear(vfe);
> +}
> +
> +/*
> + * vfe_isr_sof - Process start of frame interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	output = &vfe->line[line_id].output;
> +	if (output->gen1.wait_sof) {
> +		output->gen1.wait_sof = 0;
> +		complete(&output->sof);
> +	}
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_reg_update - Process reg update interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	struct vfe_line *line = &vfe->line[line_id];
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	vfe->ops->reg_update_clear(vfe, line_id);
> +
> +	output = &line->output;
> +
> +	if (output->wait_reg_update) {
> +		output->wait_reg_update = 0;
> +		complete(&output->reg_update);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		return;
> +	}
> +
> +	if (output->state == VFE_OUTPUT_STOPPING) {
> +		/* Release last buffer when hw is idle */
> +		if (output->last_buffer) {
> +			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> +					VB2_BUF_STATE_DONE);
> +			output->last_buffer = NULL;
> +		}
> +		output->state = VFE_OUTPUT_IDLE;
> +
> +		/* Buffers received in stopping state are queued in */
> +		/* dma pending queue, start next capture here */
> +
> +		output->buf[0] = vfe_buf_get_pending(output);
> +		output->buf[1] = vfe_buf_get_pending(output);
> +
> +		if (!output->buf[0] && output->buf[1]) {
> +			output->buf[0] = output->buf[1];
> +			output->buf[1] = NULL;
> +		}
> +
> +		if (output->buf[0])
> +			output->state = VFE_OUTPUT_SINGLE;
> +
> +		if (output->buf[1])
> +			output->state = VFE_OUTPUT_CONTINUOUS;
> +
> +		switch (output->state) {
> +		case VFE_OUTPUT_SINGLE:
> +			vfe_output_frame_drop(vfe, output, 2);
> +			break;
> +		case VFE_OUTPUT_CONTINUOUS:
> +			vfe_output_frame_drop(vfe, output, 3);
> +			break;
> +		default:
> +			vfe_output_frame_drop(vfe, output, 0);
> +			break;
> +		}
> +
> +		vfe_output_init_addrs(vfe, output, 1, &vfe->line[line_id]);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_wm_done - Process write master done interrupt
> + * @vfe: VFE Device
> + * @wm: Write master id
> + */
> +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> +{
> +	struct camss_buffer *ready_buf;
> +	struct vfe_output *output;
> +	dma_addr_t *new_addr;
> +	unsigned long flags;
> +	u32 active_index;
> +	u64 ts = ktime_get_ns();
> +	unsigned int i;
> +
> +	active_index = vfe->ops_gen1->wm_get_ping_pong_status(vfe, wm);
> +
> +	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;
> +
> +	if (output->gen1.active_buf == active_index && 0) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Active buffer mismatch!\n");
> +		goto out_unlock;
> +	}
> +	output->gen1.active_buf = active_index;
> +
> +	ready_buf = output->buf[!active_index];
> +	if (!ready_buf) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Missing ready buf %d %d!\n",
> +				    !active_index, output->state);
> +		goto out_unlock;
> +	}
> +
> +	ready_buf->vb.vb2_buf.timestamp = ts;
> +	ready_buf->vb.sequence = output->sequence++;
> +
> +	/* Get next buffer */
> +	output->buf[!active_index] = vfe_buf_get_pending(output);
> +	if (!output->buf[!active_index]) {
> +		/* No next buffer - set same address */
> +		new_addr = ready_buf->addr;
> +		vfe_buf_update_wm_on_last(vfe, output);
> +	} else {
> +		new_addr = output->buf[!active_index]->addr;
> +		vfe_buf_update_wm_on_next(vfe, output);
> +	}
> +
> +	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]);
> +	else
> +		for (i = 0; i < output->wm_num; i++)
> +			vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	if (output->state == VFE_OUTPUT_STOPPING)
> +		output->last_buffer = ready_buf;
> +	else
> +		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +	return;
> +
> +out_unlock:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_queue_buffer - Add empty buffer
> + * @vid: Video device structure
> + * @buf: Buffer to be enqueued
> + *
> + * Add an empty buffer - depending on the current number of buffers it will be
> + * put in pending buffer queue or directly given to the hardware to be filled.
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +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_device *vfe = to_vfe(line);
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	output = &line->output;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	vfe_buf_update_wm_on_new(vfe, output, buf, line);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> +{
> +	if (input / output >= 16)
> +		return 0;
> +
> +	if (input / output >= 8)
> +		return 1;
> +
> +	if (input / output >= 4)
> +		return 2;
> +
> +	return 3;
> +}
> +
> +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> +
> +int vfe_word_per_line(u32 format, u32 width)
> +{
> +	int val = 0;
> +
> +	switch (format) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		val = CALC_WORD(width, 1, 8);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_UYVY:
> +	case V4L2_PIX_FMT_VYUY:
> +		val = CALC_WORD(width, 2, 8);
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +const struct vfe_isr_ops vfe_isr_ops_gen1 = {
> +	.reset_ack = vfe_isr_reset_ack,
> +	.halt_ack = vfe_isr_halt_ack,
> +	.reg_update = vfe_isr_reg_update,
> +	.sof = vfe_isr_sof,
> +	.comp_done = vfe_isr_comp_done,
> +	.wm_done = vfe_isr_wm_done,
> +};
> +
> +const struct camss_video_ops vfe_video_ops_gen1 = {
> +	.queue_buffer = vfe_queue_buffer,
> +	.flush_buffers = vfe_flush_buffers,
> +};
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.h b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> new file mode 100644
> index 000000000000..42e8a3333034
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> @@ -0,0 +1,110 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * camss-vfe.h
> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module
> + *
> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2018 Linaro Ltd.
> + */
> +#ifndef QC_MSM_CAMSS_VFE_GEN1_H
> +#define QC_MSM_CAMSS_VFE_GEN1_H
> +
> +
> +#include "camss-vfe.h"
> +
> +
> +enum vfe_line_id;
> +struct vfe_device;
> +struct vfe_line;
> +struct vfe_output;
> +
> +struct vfe_hw_ops_gen1 {
> +	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> +	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> +	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> +	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> +	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> +	void (*enable_irq_common)(struct vfe_device *vfe);
> +	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, enum vfe_line_id line_id,
> +				   u8 enable);
> +	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, enum vfe_line_id line_id,
> +				    u8 enable);
> +	u16 (*get_ub_size)(u8 vfe_id);
> +	void (*halt_clear)(struct vfe_device *vfe);
> +	void (*halt_request)(struct vfe_device *vfe);
> +	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> +	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> +	void (*set_clamp_cfg)(struct vfe_device *vfe);
> +	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_ds)(struct vfe_device *vfe);
> +	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> +	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid);
> +	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, u8 enable);
> +	void (*set_qos)(struct vfe_device *vfe);
> +	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, u8 enable);
> +	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> +	void (*wm_line_based)(struct vfe_device *vfe, u32 wm, struct v4l2_pix_format_mplane *pix,
> +			      u8 plane, u32 enable);
> +	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, u16 depth);
> +	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> +	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> +	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, u32 pattern);
> +	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> +	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> +	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> +	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> +};
> +
> +/*
> + * vfe_calc_interp_reso - Calculate interpolation mode
> + * @input: Input resolution
> + * @output: Output resolution
> + *
> + * Return interpolation mode
> + */
> +inline u8 vfe_calc_interp_reso(u16 input, u16 output);
> +
> +/*
> + * vfe_gen1_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_gen1_disable(struct vfe_line *line);
> +
> +
> +/*
> + * vfe_gen1_enable - Enable VFE module
> + * @line: VFE line
> + *
> + * Return 0 on success
> + */
> +int vfe_gen1_enable(struct vfe_line *line);
> +
> +/*
> + * vfe_gen1_enable - Halt VFE module
> + * @vfe: VFE device
> + *
> + * Return 0 on success
> + */
> +int vfe_gen1_halt(struct vfe_device *vfe);
> +
> +/*
> + * vfe_word_per_line - Calculate number of words per frame width
> + * @format: V4L2 format
> + * @width: Frame width
> + *
> + * Return number of words per frame width
> + */
> +int vfe_word_per_line(u32 format, u32 width);
> +
> +
> +extern const struct vfe_isr_ops vfe_isr_ops_gen1;
> +extern const struct camss_video_ops vfe_video_ops_gen1;
> +
> +
> +#endif /* QC_MSM_CAMSS_VFE_GEN1_H */
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index 478be4f0cab5..2ffa5b3c5426 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -26,22 +26,8 @@
>   
>   #define MSM_VFE_NAME "msm_vfe"
>   
> -#define vfe_line_array(ptr_line)	\
> -	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> -
> -#define to_vfe(ptr_line)	\
> -	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> -
>   /* VFE reset timeout */
>   #define VFE_RESET_TIMEOUT_MS 50
> -/* VFE halt timeout */
> -#define VFE_HALT_TIMEOUT_MS 100
> -/* Max number of frame drop updates per frame */
> -#define VFE_FRAME_DROP_UPDATES 2
> -/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> -#define VFE_FRAME_DROP_VAL 30
> -
> -#define VFE_NEXT_SOF_MS 500
>   
>   #define SCALER_RATIO_MAX 16
>   
> @@ -294,30 +280,6 @@ static int vfe_reset(struct vfe_device *vfe)
>   	return 0;
>   }
>   
> -/*
> - * vfe_halt - Trigger halt on VFE module and wait to complete
> - * @vfe: VFE device
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_halt(struct vfe_device *vfe)
> -{
> -	unsigned long time;
> -
> -	reinit_completion(&vfe->halt_complete);
> -
> -	vfe->ops->halt_request(vfe);
> -
> -	time = wait_for_completion_timeout(&vfe->halt_complete,
> -		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> -	if (!time) {
> -		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> -		return -EIO;
> -	}
> -
> -	return 0;
> -}
> -
>   static void vfe_init_outputs(struct vfe_device *vfe)
>   {
>   	int i;
> @@ -340,71 +302,7 @@ static void vfe_reset_output_maps(struct vfe_device *vfe)
>   		vfe->wm_output_map[i] = VFE_LINE_NONE;
>   }
>   
> -static void vfe_output_init_addrs(struct vfe_device *vfe,
> -				  struct vfe_output *output, u8 sync)
> -{
> -	u32 ping_addr;
> -	u32 pong_addr;
> -	unsigned int i;
> -
> -	output->active_buf = 0;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[0])
> -			ping_addr = output->buf[0]->addr[i];
> -		else
> -			ping_addr = 0;
> -
> -		if (output->buf[1])
> -			pong_addr = output->buf[1]->addr[i];
> -		else
> -			pong_addr = ping_addr;
> -
> -		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
> -		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -}
> -
> -static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> -					struct vfe_output *output, u8 sync)
> -{
> -	u32 addr;
> -	unsigned int i;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[0])
> -			addr = output->buf[0]->addr[i];
> -		else
> -			addr = 0;
> -
> -		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -}
> -
> -static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> -					struct vfe_output *output, u8 sync)
> -{
> -	u32 addr;
> -	unsigned int i;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[1])
> -			addr = output->buf[1]->addr[i];
> -		else
> -			addr = 0;
> -
> -		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -
> -}
> -
> -static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
> +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
>   {
>   	int ret = -EBUSY;
>   	int i;
> @@ -420,7 +318,7 @@ static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
>   	return ret;
>   }
>   
> -static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
> +int vfe_release_wm(struct vfe_device *vfe, u8 wm)
>   {
>   	if (wm >= ARRAY_SIZE(vfe->wm_output_map))
>   		return -EINVAL;
> @@ -430,29 +328,7 @@ static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
>   	return 0;
>   }
>   
> -static void vfe_output_frame_drop(struct vfe_device *vfe,
> -				  struct vfe_output *output,
> -				  u32 drop_pattern)
> -{
> -	u8 drop_period;
> -	unsigned int i;
> -
> -	/* We need to toggle update period to be valid on next frame */
> -	output->drop_update_idx++;
> -	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> -	drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i],
> -						  drop_period);
> -		vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i],
> -						   drop_pattern);
> -	}
> -	vfe->ops->reg_update(vfe,
> -			     container_of(output, struct vfe_line, output)->id);
> -}
> -
> -static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
> +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
>   {
>   	struct camss_buffer *buffer = NULL;
>   
> @@ -466,13 +342,8 @@ static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
>   	return buffer;
>   }
>   
> -/*
> - * vfe_buf_add_pending - Add output buffer to list of pending
> - * @output: VFE output
> - * @buffer: Video buffer
> - */
> -static void vfe_buf_add_pending(struct vfe_output *output,
> -				struct camss_buffer *buffer)
> +void vfe_buf_add_pending(struct vfe_output *output,
> +			 struct camss_buffer *buffer)
>   {
>   	INIT_LIST_HEAD(&buffer->queue);
>   	list_add_tail(&buffer->queue, &output->pending_bufs);
> @@ -495,149 +366,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output,
>   	}
>   }
>   
> -static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> -				      struct vfe_output *output)
> -{
> -	switch (output->state) {
> -	case VFE_OUTPUT_CONTINUOUS:
> -		vfe_output_frame_drop(vfe, output, 3);
> -		break;
> -	case VFE_OUTPUT_SINGLE:
> -	default:
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Next buf in wrong state! %d\n",
> -				    output->state);
> -		break;
> -	}
> -}
> -
> -static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> -				      struct vfe_output *output)
> -{
> -	switch (output->state) {
> -	case VFE_OUTPUT_CONTINUOUS:
> -		output->state = VFE_OUTPUT_SINGLE;
> -		vfe_output_frame_drop(vfe, output, 1);
> -		break;
> -	case VFE_OUTPUT_SINGLE:
> -		output->state = VFE_OUTPUT_STOPPING;
> -		vfe_output_frame_drop(vfe, output, 0);
> -		break;
> -	default:
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Last buff in wrong state! %d\n",
> -				    output->state);
> -		break;
> -	}
> -}
> -
> -static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> -				     struct vfe_output *output,
> -				     struct camss_buffer *new_buf)
> -{
> -	int inactive_idx;
> -
> -	switch (output->state) {
> -	case VFE_OUTPUT_SINGLE:
> -		inactive_idx = !output->active_buf;
> -
> -		if (!output->buf[inactive_idx]) {
> -			output->buf[inactive_idx] = new_buf;
> -
> -			if (inactive_idx)
> -				vfe_output_update_pong_addr(vfe, output, 0);
> -			else
> -				vfe_output_update_ping_addr(vfe, output, 0);
> -
> -			vfe_output_frame_drop(vfe, output, 3);
> -			output->state = VFE_OUTPUT_CONTINUOUS;
> -		} else {
> -			vfe_buf_add_pending(output, new_buf);
> -			dev_err_ratelimited(vfe->camss->dev,
> -					    "Inactive buffer is busy\n");
> -		}
> -		break;
> -
> -	case VFE_OUTPUT_IDLE:
> -		if (!output->buf[0]) {
> -			output->buf[0] = new_buf;
> -
> -			vfe_output_init_addrs(vfe, output, 1);
> -
> -			vfe_output_frame_drop(vfe, output, 1);
> -			output->state = VFE_OUTPUT_SINGLE;
> -		} else {
> -			vfe_buf_add_pending(output, new_buf);
> -			dev_err_ratelimited(vfe->camss->dev,
> -					    "Output idle with buffer set!\n");
> -		}
> -		break;
> -
> -	case VFE_OUTPUT_CONTINUOUS:
> -	default:
> -		vfe_buf_add_pending(output, new_buf);
> -		break;
> -	}
> -}
> -
> -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;
> -	unsigned long flags;
> -	int i;
> -	int wm_idx;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	output = &line->output;
> -	if (output->state != VFE_OUTPUT_OFF) {
> -		dev_err(vfe->camss->dev, "Output is running\n");
> -		goto error;
> -	}
> -	output->state = VFE_OUTPUT_RESERVED;
> -
> -	output->active_buf = 0;
> -
> -	switch (f->fmt.pix_mp.pixelformat) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		output->wm_num = 2;
> -		break;
> -	default:
> -		output->wm_num = 1;
> -		break;
> -	}
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		wm_idx = vfe_reserve_wm(vfe, line->id);
> -		if (wm_idx < 0) {
> -			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> -			goto error_get_wm;
> -		}
> -		output->wm_idx[i] = wm_idx;
> -	}
> -
> -	output->drop_update_idx = 0;
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -
> -error_get_wm:
> -	for (i--; i >= 0; i--)
> -		vfe_release_wm(vfe, output->wm_idx[i]);
> -	output->state = VFE_OUTPUT_OFF;
> -error:
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return -EINVAL;
> -}
> -
> -static int vfe_put_output(struct vfe_line *line)
> +int vfe_put_output(struct vfe_line *line)
>   {
>   	struct vfe_device *vfe = to_vfe(line);
>   	struct vfe_output *output = &line->output;
> @@ -655,454 +384,27 @@ static int vfe_put_output(struct vfe_line *line)
>   	return 0;
>   }
>   
> -static int vfe_enable_output(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output = &line->output;
> -	const struct vfe_hw_ops *ops = vfe->ops;
> -	struct media_entity *sensor;
> -	unsigned long flags;
> -	unsigned int frame_skip = 0;
> -	unsigned int i;
> -	u16 ub_size;
> -
> -	ub_size = ops->get_ub_size(vfe->id);
> -	if (!ub_size)
> -		return -EINVAL;
> -
> -	sensor = camss_find_sensor(&line->subdev.entity);
> -	if (sensor) {
> -		struct v4l2_subdev *subdev =
> -					media_entity_to_v4l2_subdev(sensor);
> -
> -		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;
> -	}
> -	output->state = VFE_OUTPUT_IDLE;
> -
> -	output->buf[0] = vfe_buf_get_pending(output);
> -	output->buf[1] = vfe_buf_get_pending(output);
> -
> -	if (!output->buf[0] && output->buf[1]) {
> -		output->buf[0] = output->buf[1];
> -		output->buf[1] = NULL;
> -	}
> -
> -	if (output->buf[0])
> -		output->state = VFE_OUTPUT_SINGLE;
> -
> -	if (output->buf[1])
> -		output->state = VFE_OUTPUT_CONTINUOUS;
> -
> -	switch (output->state) {
> -	case VFE_OUTPUT_SINGLE:
> -		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> -		break;
> -	case VFE_OUTPUT_CONTINUOUS:
> -		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> -		break;
> -	default:
> -		vfe_output_frame_drop(vfe, output, 0);
> -		break;
> -	}
> -
> -	output->sequence = 0;
> -	output->wait_sof = 0;
> -	output->wait_reg_update = 0;
> -	reinit_completion(&output->sof);
> -	reinit_completion(&output->reg_update);
> -
> -	vfe_output_init_addrs(vfe, output, 0);
> -
> -	if (line->id != VFE_LINE_PIX) {
> -		ops->set_cgc_override(vfe, output->wm_idx[0], 1);
> -		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
> -		ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
> -		ops->wm_set_subsample(vfe, output->wm_idx[0]);
> -		ops->set_rdi_cid(vfe, line->id, 0);
> -		ops->wm_set_ub_cfg(vfe, output->wm_idx[0],
> -				   (ub_size + 1) * output->wm_idx[0], ub_size);
> -		ops->wm_frame_based(vfe, output->wm_idx[0], 1);
> -		ops->wm_enable(vfe, output->wm_idx[0], 1);
> -		ops->bus_reload_wm(vfe, output->wm_idx[0]);
> -	} else {
> -		ub_size /= output->wm_num;
> -		for (i = 0; i < output->wm_num; i++) {
> -			ops->set_cgc_override(vfe, output->wm_idx[i], 1);
> -			ops->wm_set_subsample(vfe, output->wm_idx[i]);
> -			ops->wm_set_ub_cfg(vfe, output->wm_idx[i],
> -					   (ub_size + 1) * output->wm_idx[i],
> -					   ub_size);
> -			ops->wm_line_based(vfe, output->wm_idx[i],
> -					&line->video_out.active_fmt.fmt.pix_mp,
> -					i, 1);
> -			ops->wm_enable(vfe, output->wm_idx[i], 1);
> -			ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -		}
> -		ops->enable_irq_pix_line(vfe, 0, line->id, 1);
> -		ops->set_module_cfg(vfe, 1);
> -		ops->set_camif_cfg(vfe, line);
> -		ops->set_realign_cfg(vfe, line, 1);
> -		ops->set_xbar_cfg(vfe, output, 1);
> -		ops->set_demux_cfg(vfe, line);
> -		ops->set_scale_cfg(vfe, line);
> -		ops->set_crop_cfg(vfe, line);
> -		ops->set_clamp_cfg(vfe);
> -		ops->set_camif_cmd(vfe, 1);
> -	}
> -
> -	ops->reg_update(vfe, line->id);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -}
> -
> -static int vfe_disable_output(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output = &line->output;
> -	const struct vfe_hw_ops *ops = vfe->ops;
> -	unsigned long flags;
> -	unsigned long time;
> -	unsigned int i;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	output->wait_sof = 1;
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	time = wait_for_completion_timeout(&output->sof,
> -					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
> -	if (!time)
> -		dev_err(vfe->camss->dev, "VFE sof timeout\n");
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	for (i = 0; i < output->wm_num; i++)
> -		ops->wm_enable(vfe, output->wm_idx[i], 0);
> -
> -	ops->reg_update(vfe, line->id);
> -	output->wait_reg_update = 1;
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	time = wait_for_completion_timeout(&output->reg_update,
> -					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
> -	if (!time)
> -		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	if (line->id != VFE_LINE_PIX) {
> -		ops->wm_frame_based(vfe, output->wm_idx[0], 0);
> -		ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0],
> -						line->id);
> -		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
> -		ops->set_cgc_override(vfe, output->wm_idx[0], 0);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -	} else {
> -		for (i = 0; i < output->wm_num; i++) {
> -			ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
> -			ops->set_cgc_override(vfe, output->wm_idx[i], 0);
> -		}
> -
> -		ops->enable_irq_pix_line(vfe, 0, line->id, 0);
> -		ops->set_module_cfg(vfe, 0);
> -		ops->set_realign_cfg(vfe, line, 0);
> -		ops->set_xbar_cfg(vfe, output, 0);
> -
> -		ops->set_camif_cmd(vfe, 0);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -		ops->camif_wait_for_stop(vfe, vfe->camss->dev);
> -	}
> -
> -	return 0;
> -}
> -
> -/*
> - * vfe_enable - Enable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_enable(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	int ret;
> -
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (!vfe->stream_count) {
> -		vfe->ops->enable_irq_common(vfe);
> -
> -		vfe->ops->bus_enable_wr_if(vfe, 1);
> -
> -		vfe->ops->set_qos(vfe);
> -
> -		vfe->ops->set_ds(vfe);
> -	}
> -
> -	vfe->stream_count++;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	ret = vfe_get_output(line);
> -	if (ret < 0)
> -		goto error_get_output;
> -
> -	ret = vfe_enable_output(line);
> -	if (ret < 0)
> -		goto error_enable_output;
> -
> -	vfe->was_streaming = 1;
> -
> -	return 0;
> -
> -
> -error_enable_output:
> -	vfe_put_output(line);
> -
> -error_get_output:
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (vfe->stream_count == 1)
> -		vfe->ops->bus_enable_wr_if(vfe, 0);
> -
> -	vfe->stream_count--;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	return ret;
> -}
> -
> -/*
> - * vfe_disable - Disable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_disable(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -
> -	vfe_disable_output(line);
> -
> -	vfe_put_output(line);
> -
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (vfe->stream_count == 1)
> -		vfe->ops->bus_enable_wr_if(vfe, 0);
> -
> -	vfe->stream_count--;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	return 0;
> -}
> -
> -/*
> - * vfe_isr_sof - Process start of frame interrupt
> - * @vfe: VFE Device
> - * @line_id: VFE line
> - */
> -static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> -{
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	output = &vfe->line[line_id].output;
> -	if (output->wait_sof) {
> -		output->wait_sof = 0;
> -		complete(&output->sof);
> -	}
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
> -/*
> - * vfe_isr_reg_update - Process reg update interrupt
> - * @vfe: VFE Device
> - * @line_id: VFE line
> - */
> -static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> -{
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	vfe->ops->reg_update_clear(vfe, line_id);
> -
> -	output = &vfe->line[line_id].output;
> -
> -	if (output->wait_reg_update) {
> -		output->wait_reg_update = 0;
> -		complete(&output->reg_update);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -		return;
> -	}
> -
> -	if (output->state == VFE_OUTPUT_STOPPING) {
> -		/* Release last buffer when hw is idle */
> -		if (output->last_buffer) {
> -			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> -					VB2_BUF_STATE_DONE);
> -			output->last_buffer = NULL;
> -		}
> -		output->state = VFE_OUTPUT_IDLE;
> -
> -		/* Buffers received in stopping state are queued in */
> -		/* dma pending queue, start next capture here */
> -
> -		output->buf[0] = vfe_buf_get_pending(output);
> -		output->buf[1] = vfe_buf_get_pending(output);
> -
> -		if (!output->buf[0] && output->buf[1]) {
> -			output->buf[0] = output->buf[1];
> -			output->buf[1] = NULL;
> -		}
> -
> -		if (output->buf[0])
> -			output->state = VFE_OUTPUT_SINGLE;
> -
> -		if (output->buf[1])
> -			output->state = VFE_OUTPUT_CONTINUOUS;
> -
> -		switch (output->state) {
> -		case VFE_OUTPUT_SINGLE:
> -			vfe_output_frame_drop(vfe, output, 2);
> -			break;
> -		case VFE_OUTPUT_CONTINUOUS:
> -			vfe_output_frame_drop(vfe, output, 3);
> -			break;
> -		default:
> -			vfe_output_frame_drop(vfe, output, 0);
> -			break;
> -		}
> -
> -		vfe_output_init_addrs(vfe, output, 1);
> -	}
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
> -/*
> - * vfe_isr_wm_done - Process write master done interrupt
> - * @vfe: VFE Device
> - * @wm: Write master id
> - */
> -static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> -{
> -	struct camss_buffer *ready_buf;
> -	struct vfe_output *output;
> -	dma_addr_t *new_addr;
> -	unsigned long flags;
> -	u32 active_index;
> -	u64 ts = ktime_get_ns();
> -	unsigned int i;
> -
> -	active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm);
> -
> -	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;
> -
> -	if (output->active_buf == active_index) {
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Active buffer mismatch!\n");
> -		goto out_unlock;
> -	}
> -	output->active_buf = active_index;
> -
> -	ready_buf = output->buf[!active_index];
> -	if (!ready_buf) {
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Missing ready buf %d %d!\n",
> -				    !active_index, output->state);
> -		goto out_unlock;
> -	}
> -
> -	ready_buf->vb.vb2_buf.timestamp = ts;
> -	ready_buf->vb.sequence = output->sequence++;
> -
> -	/* Get next buffer */
> -	output->buf[!active_index] = vfe_buf_get_pending(output);
> -	if (!output->buf[!active_index]) {
> -		/* No next buffer - set same address */
> -		new_addr = ready_buf->addr;
> -		vfe_buf_update_wm_on_last(vfe, output);
> -	} else {
> -		new_addr = output->buf[!active_index]->addr;
> -		vfe_buf_update_wm_on_next(vfe, output);
> -	}
> -
> -	if (active_index)
> -		for (i = 0; i < output->wm_num; i++)
> -			vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i],
> -						   new_addr[i]);
> -	else
> -		for (i = 0; i < output->wm_num; i++)
> -			vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i],
> -						   new_addr[i]);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	if (output->state == VFE_OUTPUT_STOPPING)
> -		output->last_buffer = ready_buf;
> -	else
> -		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> -
> -	return;
> -
> -out_unlock:
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
>   /*
>    * vfe_isr_comp_done - Process composite image done interrupt
>    * @vfe: VFE Device
>    * @comp: Composite image id
>    */
> -static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
> +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) {
> -			vfe_isr_wm_done(vfe, i);
> +			vfe->isr_ops.wm_done(vfe, i);
>   			break;
>   		}
>   }
>   
> -static inline void vfe_isr_reset_ack(struct vfe_device *vfe)
> +void vfe_isr_reset_ack(struct vfe_device *vfe)
>   {
>   	complete(&vfe->reset_complete);
>   }
>   
> -static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
> -{
> -	complete(&vfe->halt_complete);
> -	vfe->ops->halt_clear(vfe);
> -}
> -
>   /*
>    * vfe_set_clock_rates - Calculate and set clock rates on VFE module
>    * @vfe: VFE device
> @@ -1318,7 +620,7 @@ static void vfe_put(struct vfe_device *vfe)
>   	} else if (vfe->power_count == 1) {
>   		if (vfe->was_streaming) {
>   			vfe->was_streaming = 0;
> -			vfe_halt(vfe);
> +			vfe->ops->vfe_halt(vfe);
>   		}
>   		camss_disable_clocks(vfe->nclocks, vfe->clock);
>   		pm_runtime_put_sync(vfe->camss->dev);
> @@ -1331,35 +633,6 @@ static void vfe_put(struct vfe_device *vfe)
>   	mutex_unlock(&vfe->power_lock);
>   }
>   
> -/*
> - * vfe_queue_buffer - Add empty buffer
> - * @vid: Video device structure
> - * @buf: Buffer to be enqueued
> - *
> - * Add an empty buffer - depending on the current number of buffers it will be
> - * put in pending buffer queue or directly given to the hardware to be filled.
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -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_device *vfe = to_vfe(line);
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	output = &line->output;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	vfe_buf_update_wm_on_new(vfe, output, buf);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -}
> -
>   /*
>    * vfe_flush_buffers - Return all vb2 buffers
>    * @vid: Video device structure
> @@ -1370,8 +643,8 @@ static int vfe_queue_buffer(struct camss_video *vid,
>    *
>    * Return 0 on success or a negative error code otherwise
>    */
> -static int vfe_flush_buffers(struct camss_video *vid,
> -			     enum vb2_buffer_state state)
> +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_device *vfe = to_vfe(line);
> @@ -1442,12 +715,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
>   	int ret;
>   
>   	if (enable) {
> -		ret = vfe_enable(line);
> +		ret = vfe->ops->vfe_enable(line);
>   		if (ret < 0)
>   			dev_err(vfe->camss->dev,
>   				"Failed to enable vfe outputs\n");
>   	} else {
> -		ret = vfe_disable(line);
> +		ret = vfe->ops->vfe_disable(line);
>   		if (ret < 0)
>   			dev_err(vfe->camss->dev,
>   				"Failed to disable vfe outputs\n");
> @@ -1985,13 +1258,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	int i, j;
>   	int ret;
>   
> -	vfe->isr_ops.reset_ack = vfe_isr_reset_ack;
> -	vfe->isr_ops.halt_ack = vfe_isr_halt_ack;
> -	vfe->isr_ops.reg_update = vfe_isr_reg_update;
> -	vfe->isr_ops.sof = vfe_isr_sof;
> -	vfe->isr_ops.comp_done = vfe_isr_comp_done;
> -	vfe->isr_ops.wm_done = vfe_isr_wm_done;
> -
>   	switch (camss->version) {
>   	case CAMSS_8x16:
>   		vfe->ops = &vfe_ops_4_1;
> @@ -2005,6 +1271,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	default:
>   		return -EINVAL;
>   	}
> +	vfe->ops->subdev_init(vfe);
>   
>   	/* Memory */
>   
> @@ -2209,11 +1476,6 @@ static const struct media_entity_operations vfe_media_ops = {
>   	.link_validate = v4l2_subdev_link_validate,
>   };
>   
> -static const struct camss_video_ops camss_vfe_video_ops = {
> -	.queue_buffer = vfe_queue_buffer,
> -	.flush_buffers = vfe_flush_buffers,
> -};
> -
>   /*
>    * msm_vfe_register_entities - Register subdev node for VFE module
>    * @vfe: VFE device
> @@ -2279,7 +1541,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
>   			goto error_reg_subdev;
>   		}
>   
> -		video_out->ops = &camss_vfe_video_ops;
> +		video_out->ops = &vfe->video_ops;
>   		video_out->bpl_alignment = 8;
>   		video_out->line_based = 0;
>   		if (i == VFE_LINE_PIX) {
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> index 5bce6736e4bb..8629c833f130 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> @@ -17,6 +17,8 @@
>   #include <media/v4l2-subdev.h>
>   
>   #include "camss-video.h"
> +#include "camss-vfe-gen1.h"
> +
>   
>   #define MSM_VFE_PAD_SINK 0
>   #define MSM_VFE_PAD_SRC 1
> @@ -26,6 +28,18 @@
>   #define MSM_VFE_IMAGE_MASTERS_NUM 7
>   #define MSM_VFE_COMPOSITE_IRQ_NUM 4
>   
> +/* VFE halt timeout */
> +#define VFE_HALT_TIMEOUT_MS 100
> +/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> +#define VFE_FRAME_DROP_VAL 30
> +
> +#define vfe_line_array(ptr_line)	\
> +	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> +
> +#define to_vfe(ptr_line)	\
> +	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> +
> +
>   enum vfe_output_state {
>   	VFE_OUTPUT_OFF,
>   	VFE_OUTPUT_RESERVED,
> @@ -47,16 +61,21 @@ struct vfe_output {
>   	u8 wm_num;
>   	u8 wm_idx[3];
>   
> -	int active_buf;
>   	struct camss_buffer *buf[2];
>   	struct camss_buffer *last_buffer;
>   	struct list_head pending_bufs;
>   
>   	unsigned int drop_update_idx;
>   
> +	union {
> +		struct {
> +			int active_buf;
> +			int wait_sof;
> +		} gen1;
> +	};
>   	enum vfe_output_state state;
>   	unsigned int sequence;
> -	int wait_sof;
> +
>   	int wait_reg_update;
>   	struct completion sof;
>   	struct completion reg_update;
> @@ -78,59 +97,19 @@ struct vfe_line {
>   struct vfe_device;
>   
>   struct vfe_hw_ops {
> -	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> -	u16 (*get_ub_size)(u8 vfe_id);
> +	void (*enable_irq_common)(struct vfe_device *vfe);
>   	void (*global_reset)(struct vfe_device *vfe);
> -	void (*halt_request)(struct vfe_device *vfe);
> -	void (*halt_clear)(struct vfe_device *vfe);
> -	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*wm_line_based)(struct vfe_device *vfe, u32 wm,
> -			      struct v4l2_pix_format_mplane *pix,
> -			      u8 plane, u32 enable);
> -	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> -	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm,
> -					 u32 pattern);
> -	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset,
> -			      u16 depth);
> -	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> -	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> -	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> -	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> -	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> -	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm,
> -				      enum vfe_line_id id);
> -	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> -	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm,
> -					   enum vfe_line_id id);
> -	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output,
> -			     u8 enable);
> -	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id,
> -			    u8 cid);
> -	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line,
> -				u8 enable);
> +	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> +	irqreturn_t (*isr)(int irq, void *dev);
> +	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
>   	void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id);
>   	void (*reg_update_clear)(struct vfe_device *vfe,
>   				 enum vfe_line_id line_id);
> -	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm,
> -				   enum vfe_line_id line_id, u8 enable);
> -	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp,
> -				    enum vfe_line_id line_id, u8 enable);
> -	void (*enable_irq_common)(struct vfe_device *vfe);
> -	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_clamp_cfg)(struct vfe_device *vfe);
> -	void (*set_qos)(struct vfe_device *vfe);
> -	void (*set_ds)(struct vfe_device *vfe);
> -	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> -	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> -	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> -	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
> +	void (*subdev_init)(struct vfe_device *vfe);
> +	int (*vfe_disable)(struct vfe_line *line);
> +	int (*vfe_enable)(struct vfe_line *line);
> +	int (*vfe_halt)(struct vfe_device *vfe);
>   	void (*violation_read)(struct vfe_device *vfe);
> -	irqreturn_t (*isr)(int irq, void *dev);
>   };
>   
>   struct vfe_isr_ops {
> @@ -162,7 +141,9 @@ struct vfe_device {
>   	u32 reg_update;
>   	u8 was_streaming;
>   	const struct vfe_hw_ops *ops;
> +	const struct vfe_hw_ops_gen1 *ops_gen1;
>   	struct vfe_isr_ops isr_ops;
> +	struct camss_video_ops video_ops;
>   };
>   
>   struct resources;
> @@ -178,6 +159,38 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe);
>   void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
>   void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
>   
> +
> +/*
> + * vfe_buf_add_pending - Add output buffer to list of pending
> + * @output: VFE output
> + * @buffer: Video buffer
> + */
> +void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer);
> +
> +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
> +
> +/*
> + * vfe_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_disable(struct vfe_line *line);
> +
> +int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
> +
> +/*
> + * vfe_isr_comp_done - Process composite image done interrupt
> + * @vfe: VFE Device
> + * @comp: Composite image id
> + */
> +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp);
> +
> +void vfe_isr_reset_ack(struct vfe_device *vfe);
> +int vfe_put_output(struct vfe_line *line);
> +int vfe_release_wm(struct vfe_device *vfe, u8 wm);
> +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
> +
>   extern const struct vfe_hw_ops vfe_ops_4_1;
>   extern const struct vfe_hw_ops vfe_ops_4_7;
>   extern const struct vfe_hw_ops vfe_ops_4_8;
> 

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
  2021-01-13 22:28     ` Andrey Konovalov
@ 2021-01-14  9:55       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-14  9:55 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: Andy Gross, Bjorn Andersson, Todor Tomov, Mauro Carvalho Chehab,
	Rob Herring, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Hey Andrey,

Thanks for the review!

On Wed, 13 Jan 2021 at 23:28, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>
> Hi Robert,
>
> Thanks for the patch!
>
> On 08.01.2021 15:04, Robert Foss wrote:
> > This driver supports multiple architecture versions of the Qualcomm ISP.
> > The CAMSS architecure which this driver is name after, and with the
> > introduction of this series, the Titan architecture.
> >
> > The ISPIF is IP-block that is only present in the CAMSS architecture.
> > In order to support the Titan architecture, make the ISPIF an optional
> > subdevice.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >   .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
> >   .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
> >   drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
> >   drivers/media/platform/qcom/camss/camss.h     |   2 +-
> >   4 files changed, 160 insertions(+), 102 deletions(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> > index adeb92808998..0c804584dd65 100644
> > --- a/drivers/media/platform/qcom/camss/camss-ispif.c
> > +++ b/drivers/media/platform/qcom/camss/camss-ispif.c
> > @@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
> >   static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >   {
> >       struct ispif_device *ispif = dev;
> > +     struct camss *camss = ispif->camss;
> >       u32 value0, value1, value2, value3, value4, value5;
> >
> >       value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> > @@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >               complete(&ispif->reset_complete[1]);
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
> >
> >       if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
> >
> >       if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
> >
> >       if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
> >
> >       if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
> >
> >       if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
> >
> >       if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
> >
> >       return IRQ_HANDLED;
> >   }
> > @@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >   static irqreturn_t ispif_isr_8x16(int irq, void *dev)
> >   {
> >       struct ispif_device *ispif = dev;
> > +     struct camss *camss = ispif->camss;
> >       u32 value0, value1, value2;
> >
> >       value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> > @@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
> >               complete(&ispif->reset_complete[0]);
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
> >
> >       if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
> >
> >       return IRQ_HANDLED;
> >   }
> >
> >   static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >   {
> > +     struct camss *camss = ispif->camss;
> > +
> >       unsigned long time;
> >       u32 val;
> >
> > -     if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
> > -             dev_err(to_device(ispif),
> > +     if (vfe_id > (camss->vfe_num - 1)) {
> > +             dev_err(camss->dev,
> >                       "Error: asked reset for invalid VFE%d\n", vfe_id);
> >               return -ENOENT;
> >       }
> > @@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >       time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
> >               msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
> >       if (!time) {
> > -             dev_err(to_device(ispif),
> > +             dev_err(camss->dev,
> >                       "ISPIF for VFE%d reset timeout\n", vfe_id);
> >               return -EIO;
> >       }
> > @@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >    */
> >   static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
> >   {
> > +     struct camss *camss = ispif->camss;
> >       int ret;
> >
> > -     ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
> > +     ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
> >       if (ret < 0)
> >               return ret;
> >
> > -     ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
> > +     ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
> >       if (ret < 0)
> >               return ret;
> >
> >       ret = camss_enable_clocks(ispif->nclocks_for_reset,
> >                                 ispif->clock_for_reset,
> > -                               to_device(ispif));
> > +                               camss->dev);
> >       if (ret < 0)
> >               return ret;
> >
> >       ret = ispif_vfe_reset(ispif, vfe_id);
> >       if (ret)
> > -             dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
> > +             dev_dbg(camss->dev, "ISPIF Reset failed\n");
> >
> >       camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
> >
> > -     camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
> > -     camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
> > +     camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
> > +     camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
> >
> >       return ret;
> >   }
> > @@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
> >   {
> >       struct ispif_line *line = v4l2_get_subdevdata(sd);
> >       struct ispif_device *ispif = line->ispif;
> > -     struct device *dev = to_device(ispif);
> > +     struct device *dev = ispif->camss->dev;
> >       int ret = 0;
> >
> >       mutex_lock(&ispif->power_lock);
> > @@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
> >       }
> >
> >       if ((val & 0xf) != 0xf) {
> > -             dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
> > +             dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
> >                       __func__, val);
> >               ret = -EBUSY;
> >       }
> > @@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
> >                                ISPIF_TIMEOUT_SLEEP_US,
> >                                ISPIF_TIMEOUT_ALL_US);
> >       if (ret < 0)
> > -             dev_err(to_device(ispif), "%s: ispif stop timeout\n",
> > +             dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
> >                       __func__);
> >
> >       return ret;
> > @@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >   {
> >       struct ispif_line *line = v4l2_get_subdevdata(sd);
> >       struct ispif_device *ispif = line->ispif;
> > +     struct camss *camss = ispif->camss;
> >       enum ispif_intf intf = line->interface;
> >       u8 csid = line->csid_id;
> >       u8 vfe = line->vfe_id;
> > @@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >               ispif_select_csid(ispif, intf, csid, vfe, 1);
> >               ispif_select_cid(ispif, intf, cid, vfe, 1);
> >               ispif_config_irq(ispif, intf, vfe, 1);
> > -             if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                 to_camss(ispif)->version == CAMSS_660)
> > +             if (camss->version == CAMSS_8x96 ||
> > +                 camss->version == CAMSS_660)
> >                       ispif_config_pack(ispif,
> >                                         line->fmt[MSM_ISPIF_PAD_SINK].code,
> >                                         intf, cid, vfe, 1);
> > @@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >                       return ret;
> >
> >               mutex_lock(&ispif->config_lock);
> > -             if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                 to_camss(ispif)->version == CAMSS_660)
> > +             if (camss->version == CAMSS_8x96 ||
> > +                 camss->version == CAMSS_660)
> >                       ispif_config_pack(ispif,
> >                                         line->fmt[MSM_ISPIF_PAD_SINK].code,
> >                                         intf, cid, vfe, 0);
> > @@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> >    *
> >    * Return 0 on success or a negative error code otherwise
> >    */
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res)
> >   {
> > -     struct device *dev = to_device(ispif);
> > -     struct platform_device *pdev = to_platform_device(dev);
> > +     struct ispif_device *ispif = camss->ispif;
> > +     struct platform_device *pdev = to_platform_device(camss->dev);
> >       struct resource *r;
> >       int i;
> >       int ret;
> >
> > +     if (res == NULL && ispif == NULL)
> > +             return 0;
> > +
> > +     ispif->camss = camss;
> > +
> >       /* Number of ISPIF lines - same as number of CSID hardware modules */
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > +     if (camss->version == CAMSS_8x16)
> >               ispif->line_num = 2;
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> >               ispif->line_num = 4;
> >       else
> >               return -EINVAL;
> >
> > -     ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> > -                                GFP_KERNEL);
> > +     ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> > +                     sizeof(*ispif->line), GFP_KERNEL);
> >       if (!ispif->line)
> >               return -ENOMEM;
> >
> > @@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >               ispif->line[i].ispif = ispif;
> >               ispif->line[i].id = i;
> >
> > -             if (to_camss(ispif)->version == CAMSS_8x16) {
> > +             if (camss->version == CAMSS_8x16) {
> >                       ispif->line[i].formats = ispif_formats_8x16;
> >                       ispif->line[i].nformats =
> >                                       ARRAY_SIZE(ispif_formats_8x16);
> > -             } else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                        to_camss(ispif)->version == CAMSS_660) {
> > +             } else if (camss->version == CAMSS_8x96 ||
> > +                        camss->version == CAMSS_660) {
> >                       ispif->line[i].formats = ispif_formats_8x96;
> >                       ispif->line[i].nformats =
> >                                       ARRAY_SIZE(ispif_formats_8x96);
> > @@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       /* Memory */
> >
> >       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
> > -     ispif->base = devm_ioremap_resource(dev, r);
> > +     ispif->base = devm_ioremap_resource(camss->dev, r);
> >       if (IS_ERR(ispif->base)) {
> > -             dev_err(dev, "could not map memory\n");
> > +             dev_err(camss->dev, "could not map memory\n");
> >               return PTR_ERR(ispif->base);
> >       }
> >
> >       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
> > -     ispif->base_clk_mux = devm_ioremap_resource(dev, r);
> > +     ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
> >       if (IS_ERR(ispif->base_clk_mux)) {
> > -             dev_err(dev, "could not map memory\n");
> > +             dev_err(camss->dev, "could not map memory\n");
> >               return PTR_ERR(ispif->base_clk_mux);
> >       }
> >
> > @@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
> >
> >       if (!r) {
> > -             dev_err(dev, "missing IRQ\n");
> > +             dev_err(camss->dev, "missing IRQ\n");
> >               return -EINVAL;
> >       }
> >
> >       ispif->irq = r->start;
> >       snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
> > -              dev_name(dev), MSM_ISPIF_NAME);
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > -             ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
> > +              dev_name(camss->dev), MSM_ISPIF_NAME);
> > +     if (camss->version == CAMSS_8x16)
> > +             ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
> >                              IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > -             ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> > +             ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
> >                              IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> >       else
> >               ret = -EINVAL;
> > +
> >       if (ret < 0) {
> > -             dev_err(dev, "request_irq failed: %d\n", ret);
> > +             dev_err(camss->dev, "request_irq failed: %d\n", ret);
> >               return ret;
> >       }
> >
> > @@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       while (res->clock[ispif->nclocks])
> >               ispif->nclocks++;
> >
> > -     ispif->clock = devm_kcalloc(dev,
> > +     ispif->clock = devm_kcalloc(camss->dev,
> >                                   ispif->nclocks, sizeof(*ispif->clock),
> >                                   GFP_KERNEL);
> >       if (!ispif->clock)
> > @@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       for (i = 0; i < ispif->nclocks; i++) {
> >               struct camss_clock *clock = &ispif->clock[i];
> >
> > -             clock->clk = devm_clk_get(dev, res->clock[i]);
> > +             clock->clk = devm_clk_get(camss->dev, res->clock[i]);
> >               if (IS_ERR(clock->clk))
> >                       return PTR_ERR(clock->clk);
> >
> > @@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       while (res->clock_for_reset[ispif->nclocks_for_reset])
> >               ispif->nclocks_for_reset++;
> >
> > -     ispif->clock_for_reset = devm_kcalloc(dev,
> > +     ispif->clock_for_reset = devm_kcalloc(camss->dev,
> >                                             ispif->nclocks_for_reset,
> >                                             sizeof(*ispif->clock_for_reset),
> >                                             GFP_KERNEL);
> > @@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       for (i = 0; i < ispif->nclocks_for_reset; i++) {
> >               struct camss_clock *clock = &ispif->clock_for_reset[i];
> >
> > -             clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
> > +             clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
> >               if (IS_ERR(clock->clk))
> >                       return PTR_ERR(clock->clk);
> >
> > @@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
> >   int msm_ispif_register_entities(struct ispif_device *ispif,
> >                               struct v4l2_device *v4l2_dev)
> >   {
> > -     struct device *dev = to_device(ispif);
> > +     struct camss *camss =  ispif->camss;
> >       int ret;
> >       int i;
> >
> > +     if (!ispif)
> > +             return 0;
> > +
> >       for (i = 0; i < ispif->line_num; i++) {
> >               struct v4l2_subdev *sd = &ispif->line[i].subdev;
> >               struct media_pad *pads = ispif->line[i].pads;
> > @@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
> >
> >               ret = ispif_init_formats(sd, NULL);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to init format: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to init format: %d\n", ret);
> >                       goto error;
> >               }
> >
> > @@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
> >               ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
> >                                            pads);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to init media entity: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to init media entity: %d\n",
> > +                             ret);
> >                       goto error;
> >               }
> >
> >               ret = v4l2_device_register_subdev(v4l2_dev, sd);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to register subdev: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to register subdev: %d\n",
> > +                             ret);
> >                       media_entity_cleanup(&sd->entity);
> >                       goto error;
> >               }
> > @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
> >   {
> >       int i;
> >
> > +     if (!ispif)
> > +             return;
> > +
> >       mutex_destroy(&ispif->power_lock);
> >       mutex_destroy(&ispif->config_lock);
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
> > index 4132174f7ea1..fdf28e68cc7d 100644
> > --- a/drivers/media/platform/qcom/camss/camss-ispif.h
> > +++ b/drivers/media/platform/qcom/camss/camss-ispif.h
> > @@ -63,11 +63,12 @@ struct ispif_device {
> >       struct mutex config_lock;
> >       unsigned int line_num;
> >       struct ispif_line *line;
> > +     struct camss *camss;
> >   };
> >
> >   struct resources_ispif;
> >
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res);
> >
> >   int msm_ispif_register_entities(struct ispif_device *ispif,
> > diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> > index 8fefce57bc49..aeec59bc6194 100644
> > --- a/drivers/media/platform/qcom/camss/camss.c
> > +++ b/drivers/media/platform/qcom/camss/camss.c
> > @@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
> >               }
> >       }
> >
> > -     ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
> > -     if (ret < 0) {
> > -             dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> > +     if (camss->ispif) {
> > +             ret = msm_ispif_subdev_init(camss, ispif_res);
> > +             if (ret < 0) {
> > +                     dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> >                       ret);
> > -             return ret;
> > +                     return ret;
> > +             }
> >       }
> >
> >       for (i = 0; i < camss->vfe_num; i++) {
> > @@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
> >               }
> >       }
> >
> > -     ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
> > -     if (ret < 0) {
> > -             dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> > +     if (camss->ispif) {
> > +             ret = msm_ispif_register_entities(camss->ispif,
> > +                                               &camss->v4l2_dev);
> > +             if (ret < 0) {
> > +                     dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> >                       ret);
> > -             goto err_reg_ispif;
> > +                     goto err_reg_ispif;
> > +             }
> >       }
> >
> >       for (i = 0; i < camss->vfe_num; i++) {
> > @@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
> >               }
> >       }
> >
> > -     for (i = 0; i < camss->csid_num; i++) {
> > -             for (j = 0; j < camss->ispif.line_num; j++) {
> > -                     ret = media_create_pad_link(
> > -                             &camss->csid[i].subdev.entity,
> > -                             MSM_CSID_PAD_SRC,
> > -                             &camss->ispif.line[j].subdev.entity,
> > -                             MSM_ISPIF_PAD_SINK,
> > -                             0);
> > -                     if (ret < 0) {
> > -                             dev_err(camss->dev,
> > -                                     "Failed to link %s->%s entities: %d\n",
> > -                                     camss->csid[i].subdev.entity.name,
> > -                                     camss->ispif.line[j].subdev.entity.name,
> > -                                     ret);
> > -                             goto err_link;
> > -                     }
> > -             }
> > -     }
> > -
> > -     for (i = 0; i < camss->ispif.line_num; i++)
> > -             for (k = 0; k < camss->vfe_num; k++)
> > -                     for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +     if (camss->ispif) {
> > +             for (i = 0; i < camss->csid_num; i++) {
> > +                     for (j = 0; j < camss->ispif->line_num; j++) {
> >                               ret = media_create_pad_link(
> > -                                     &camss->ispif.line[i].subdev.entity,
> > -                                     MSM_ISPIF_PAD_SRC,
> > -                                     &camss->vfe[k].line[j].subdev.entity,
> > -                                     MSM_VFE_PAD_SINK,
> > +                                     &camss->csid[i].subdev.entity,
> > +                                     MSM_CSID_PAD_SRC,
> > +                                     &camss->ispif->line[j].subdev.entity,
> > +                                     MSM_ISPIF_PAD_SINK,
> >                                       0);
> >                               if (ret < 0) {
> >                                       dev_err(camss->dev,
> >                                               "Failed to link %s->%s entities: %d\n",
> > -                                             camss->ispif.line[i].subdev.entity.name,
> > -                                             camss->vfe[k].line[j].subdev.entity.name,
> > +                                             camss->csid[i].subdev.entity.name,
> > +                                             camss->ispif->line[j].subdev.entity.name,
> >                                               ret);
> >                                       goto err_link;
> >                               }
> >                       }
> > +             }
> > +
> > +             for (i = 0; i < camss->ispif->line_num; i++)
> > +                     for (k = 0; k < camss->vfe_num; k++)
> > +                             for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +                                     ret = media_create_pad_link(
> > +                                             &camss->ispif->line[i].subdev.entity,
> > +                                             MSM_ISPIF_PAD_SRC,
> > +                                             &camss->vfe[k].line[j].subdev.entity,
> > +                                             MSM_VFE_PAD_SINK,
> > +                                             0);
> > +                                     if (ret < 0) {
> > +                                             dev_err(camss->dev,
> > +                                                     "Failed to link %s->%s entities: %d\n",
> > +                                                     camss->ispif->line[i].subdev.entity.name,
> > +                                                     camss->vfe[k].line[j].subdev.entity.name,
> > +                                                     ret);
> > +                                             goto err_link;
> > +                                     }
> > +                             }
> > +     } else {
> > +             for (i = 0; i < camss->csid_num; i++)
> > +                     for (k = 0; k < camss->vfe_num; k++)
> > +                             for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +                                     ret = media_create_pad_link(
> > +                                             &camss->csid[i].subdev.entity,
> > +                                             MSM_CSID_PAD_SRC,
> > +                                             &camss->vfe[k].line[j].subdev.entity,
> > +                                             MSM_VFE_PAD_SINK,
> > +                                             0);
> > +                                     if (ret < 0) {
> > +                                             dev_err(camss->dev,
> > +                                                     "Failed to link %s->%s entities: %d\n",
> > +                                                     camss->csid[i].subdev.entity.name,
> > +                                                     camss->vfe[k].line[j].subdev.entity.name,
> > +                                                     ret);
> > +                                             goto err_link;
> > +                                     }
> > +                             }
> > +     }
> >
> >       return 0;
> >
> > @@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
> >       for (i--; i >= 0; i--)
> >               msm_vfe_unregister_entities(&camss->vfe[i]);
> >
> > -     msm_ispif_unregister_entities(&camss->ispif);
> >   err_reg_ispif:
> > +     if (camss->ispif)
> > +             msm_ispif_unregister_entities(camss->ispif);
> >
> >       i = camss->csid_num;
> >   err_reg_csid:
> > @@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
> >       for (i = 0; i < camss->csid_num; i++)
> >               msm_csid_unregister_entity(&camss->csid[i]);
> >
> > -     msm_ispif_unregister_entities(&camss->ispif);
> > +     if (camss->ispif)
> > +             msm_ispif_unregister_entities(camss->ispif);
> >
> >       for (i = 0; i < camss->vfe_num; i++)
> >               msm_vfe_unregister_entities(&camss->vfe[i]);
> > @@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
> >               goto err_free;
> >       }
> >
> > +     if (camss->version == CAMSS_8x16 ||
> > +         camss->version == CAMSS_8x96) {
> > +             camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);
>
> - shouldn't it be sizeof(*camss->ispif) instead?

Very much so, thanks for catching this.

>
> Thanks,
> Andrey
>
> > +             if (!camss->ispif) {
> > +                     ret = -ENOMEM;
> > +                     goto err_free;
> > +             }
> > +     }
> > +
> >       camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
> >                                 GFP_KERNEL);
> >       if (!camss->vfe) {
> > diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
> > index 46e986452824..b7ad8e9f68a8 100644
> > --- a/drivers/media/platform/qcom/camss/camss.h
> > +++ b/drivers/media/platform/qcom/camss/camss.h
> > @@ -79,7 +79,7 @@ struct camss {
> >       struct csiphy_device *csiphy;
> >       int csid_num;
> >       struct csid_device *csid;
> > -     struct ispif_device ispif;
> > +     struct ispif_device *ispif;
> >       int vfe_num;
> >       struct vfe_device *vfe;
> >       atomic_t ref_count;
> >

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

* Re: [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional
@ 2021-01-14  9:55       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-14  9:55 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Bjorn Andersson, Laurent Pinchart, AngeloGioacchino Del Regno,
	will, Anson.Huang, Andy Gross, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

Hey Andrey,

Thanks for the review!

On Wed, 13 Jan 2021 at 23:28, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>
> Hi Robert,
>
> Thanks for the patch!
>
> On 08.01.2021 15:04, Robert Foss wrote:
> > This driver supports multiple architecture versions of the Qualcomm ISP.
> > The CAMSS architecure which this driver is name after, and with the
> > introduction of this series, the Titan architecture.
> >
> > The ISPIF is IP-block that is only present in the CAMSS architecture.
> > In order to support the Titan architecture, make the ISPIF an optional
> > subdevice.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >   .../media/platform/qcom/camss/camss-ispif.c   | 144 ++++++++++--------
> >   .../media/platform/qcom/camss/camss-ispif.h   |   3 +-
> >   drivers/media/platform/qcom/camss/camss.c     | 113 +++++++++-----
> >   drivers/media/platform/qcom/camss/camss.h     |   2 +-
> >   4 files changed, 160 insertions(+), 102 deletions(-)
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
> > index adeb92808998..0c804584dd65 100644
> > --- a/drivers/media/platform/qcom/camss/camss-ispif.c
> > +++ b/drivers/media/platform/qcom/camss/camss-ispif.c
> > @@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = {
> >   static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >   {
> >       struct ispif_device *ispif = dev;
> > +     struct camss *camss = ispif->camss;
> >       u32 value0, value1, value2, value3, value4, value5;
> >
> >       value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> > @@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >               complete(&ispif->reset_complete[1]);
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
> >
> >       if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
> >
> >       if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n");
> >
> >       if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n");
> >
> >       if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n");
> >
> >       if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n");
> >
> >       if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n");
> >
> >       return IRQ_HANDLED;
> >   }
> > @@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
> >   static irqreturn_t ispif_isr_8x16(int irq, void *dev)
> >   {
> >       struct ispif_device *ispif = dev;
> > +     struct camss *camss = ispif->camss;
> >       u32 value0, value1, value2;
> >
> >       value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0));
> > @@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
> >               complete(&ispif->reset_complete[0]);
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n");
> >
> >       if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n");
> >
> >       if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n");
> >
> >       if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW))
> > -             dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n");
> > +             dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n");
> >
> >       return IRQ_HANDLED;
> >   }
> >
> >   static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >   {
> > +     struct camss *camss = ispif->camss;
> > +
> >       unsigned long time;
> >       u32 val;
> >
> > -     if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
> > -             dev_err(to_device(ispif),
> > +     if (vfe_id > (camss->vfe_num - 1)) {
> > +             dev_err(camss->dev,
> >                       "Error: asked reset for invalid VFE%d\n", vfe_id);
> >               return -ENOENT;
> >       }
> > @@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >       time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
> >               msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
> >       if (!time) {
> > -             dev_err(to_device(ispif),
> > +             dev_err(camss->dev,
> >                       "ISPIF for VFE%d reset timeout\n", vfe_id);
> >               return -EIO;
> >       }
> > @@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
> >    */
> >   static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
> >   {
> > +     struct camss *camss = ispif->camss;
> >       int ret;
> >
> > -     ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
> > +     ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0);
> >       if (ret < 0)
> >               return ret;
> >
> > -     ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
> > +     ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1);
> >       if (ret < 0)
> >               return ret;
> >
> >       ret = camss_enable_clocks(ispif->nclocks_for_reset,
> >                                 ispif->clock_for_reset,
> > -                               to_device(ispif));
> > +                               camss->dev);
> >       if (ret < 0)
> >               return ret;
> >
> >       ret = ispif_vfe_reset(ispif, vfe_id);
> >       if (ret)
> > -             dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
> > +             dev_dbg(camss->dev, "ISPIF Reset failed\n");
> >
> >       camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
> >
> > -     camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
> > -     camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
> > +     camss_pm_domain_off(camss, PM_DOMAIN_VFE0);
> > +     camss_pm_domain_off(camss, PM_DOMAIN_VFE1);
> >
> >       return ret;
> >   }
> > @@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
> >   {
> >       struct ispif_line *line = v4l2_get_subdevdata(sd);
> >       struct ispif_device *ispif = line->ispif;
> > -     struct device *dev = to_device(ispif);
> > +     struct device *dev = ispif->camss->dev;
> >       int ret = 0;
> >
> >       mutex_lock(&ispif->power_lock);
> > @@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif,
> >       }
> >
> >       if ((val & 0xf) != 0xf) {
> > -             dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n",
> > +             dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n",
> >                       __func__, val);
> >               ret = -EBUSY;
> >       }
> > @@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif,
> >                                ISPIF_TIMEOUT_SLEEP_US,
> >                                ISPIF_TIMEOUT_ALL_US);
> >       if (ret < 0)
> > -             dev_err(to_device(ispif), "%s: ispif stop timeout\n",
> > +             dev_err(ispif->camss->dev, "%s: ispif stop timeout\n",
> >                       __func__);
> >
> >       return ret;
> > @@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >   {
> >       struct ispif_line *line = v4l2_get_subdevdata(sd);
> >       struct ispif_device *ispif = line->ispif;
> > +     struct camss *camss = ispif->camss;
> >       enum ispif_intf intf = line->interface;
> >       u8 csid = line->csid_id;
> >       u8 vfe = line->vfe_id;
> > @@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >               ispif_select_csid(ispif, intf, csid, vfe, 1);
> >               ispif_select_cid(ispif, intf, cid, vfe, 1);
> >               ispif_config_irq(ispif, intf, vfe, 1);
> > -             if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                 to_camss(ispif)->version == CAMSS_660)
> > +             if (camss->version == CAMSS_8x96 ||
> > +                 camss->version == CAMSS_660)
> >                       ispif_config_pack(ispif,
> >                                         line->fmt[MSM_ISPIF_PAD_SINK].code,
> >                                         intf, cid, vfe, 1);
> > @@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
> >                       return ret;
> >
> >               mutex_lock(&ispif->config_lock);
> > -             if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                 to_camss(ispif)->version == CAMSS_660)
> > +             if (camss->version == CAMSS_8x96 ||
> > +                 camss->version == CAMSS_660)
> >                       ispif_config_pack(ispif,
> >                                         line->fmt[MSM_ISPIF_PAD_SINK].code,
> >                                         intf, cid, vfe, 0);
> > @@ -1088,26 +1094,31 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> >    *
> >    * Return 0 on success or a negative error code otherwise
> >    */
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res)
> >   {
> > -     struct device *dev = to_device(ispif);
> > -     struct platform_device *pdev = to_platform_device(dev);
> > +     struct ispif_device *ispif = camss->ispif;
> > +     struct platform_device *pdev = to_platform_device(camss->dev);
> >       struct resource *r;
> >       int i;
> >       int ret;
> >
> > +     if (res == NULL && ispif == NULL)
> > +             return 0;
> > +
> > +     ispif->camss = camss;
> > +
> >       /* Number of ISPIF lines - same as number of CSID hardware modules */
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > +     if (camss->version == CAMSS_8x16)
> >               ispif->line_num = 2;
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> >               ispif->line_num = 4;
> >       else
> >               return -EINVAL;
> >
> > -     ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line),
> > -                                GFP_KERNEL);
> > +     ispif->line = devm_kcalloc(camss->dev, ispif->line_num,
> > +                     sizeof(*ispif->line), GFP_KERNEL);
> >       if (!ispif->line)
> >               return -ENOMEM;
> >
> > @@ -1115,12 +1126,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >               ispif->line[i].ispif = ispif;
> >               ispif->line[i].id = i;
> >
> > -             if (to_camss(ispif)->version == CAMSS_8x16) {
> > +             if (camss->version == CAMSS_8x16) {
> >                       ispif->line[i].formats = ispif_formats_8x16;
> >                       ispif->line[i].nformats =
> >                                       ARRAY_SIZE(ispif_formats_8x16);
> > -             } else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -                        to_camss(ispif)->version == CAMSS_660) {
> > +             } else if (camss->version == CAMSS_8x96 ||
> > +                        camss->version == CAMSS_660) {
> >                       ispif->line[i].formats = ispif_formats_8x96;
> >                       ispif->line[i].nformats =
> >                                       ARRAY_SIZE(ispif_formats_8x96);
> > @@ -1132,16 +1143,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       /* Memory */
> >
> >       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]);
> > -     ispif->base = devm_ioremap_resource(dev, r);
> > +     ispif->base = devm_ioremap_resource(camss->dev, r);
> >       if (IS_ERR(ispif->base)) {
> > -             dev_err(dev, "could not map memory\n");
> > +             dev_err(camss->dev, "could not map memory\n");
> >               return PTR_ERR(ispif->base);
> >       }
> >
> >       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]);
> > -     ispif->base_clk_mux = devm_ioremap_resource(dev, r);
> > +     ispif->base_clk_mux = devm_ioremap_resource(camss->dev, r);
> >       if (IS_ERR(ispif->base_clk_mux)) {
> > -             dev_err(dev, "could not map memory\n");
> > +             dev_err(camss->dev, "could not map memory\n");
> >               return PTR_ERR(ispif->base_clk_mux);
> >       }
> >
> > @@ -1150,24 +1161,25 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt);
> >
> >       if (!r) {
> > -             dev_err(dev, "missing IRQ\n");
> > +             dev_err(camss->dev, "missing IRQ\n");
> >               return -EINVAL;
> >       }
> >
> >       ispif->irq = r->start;
> >       snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s",
> > -              dev_name(dev), MSM_ISPIF_NAME);
> > -     if (to_camss(ispif)->version == CAMSS_8x16)
> > -             ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
> > +              dev_name(camss->dev), MSM_ISPIF_NAME);
> > +     if (camss->version == CAMSS_8x16)
> > +             ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x16,
> >                              IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> > -     else if (to_camss(ispif)->version == CAMSS_8x96 ||
> > -              to_camss(ispif)->version == CAMSS_660)
> > -             ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
> > +     else if (camss->version == CAMSS_8x96 ||
> > +              camss->version == CAMSS_660)
> > +             ret = devm_request_irq(camss->dev, ispif->irq, ispif_isr_8x96,
> >                              IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
> >       else
> >               ret = -EINVAL;
> > +
> >       if (ret < 0) {
> > -             dev_err(dev, "request_irq failed: %d\n", ret);
> > +             dev_err(camss->dev, "request_irq failed: %d\n", ret);
> >               return ret;
> >       }
> >
> > @@ -1177,7 +1189,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       while (res->clock[ispif->nclocks])
> >               ispif->nclocks++;
> >
> > -     ispif->clock = devm_kcalloc(dev,
> > +     ispif->clock = devm_kcalloc(camss->dev,
> >                                   ispif->nclocks, sizeof(*ispif->clock),
> >                                   GFP_KERNEL);
> >       if (!ispif->clock)
> > @@ -1186,7 +1198,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       for (i = 0; i < ispif->nclocks; i++) {
> >               struct camss_clock *clock = &ispif->clock[i];
> >
> > -             clock->clk = devm_clk_get(dev, res->clock[i]);
> > +             clock->clk = devm_clk_get(camss->dev, res->clock[i]);
> >               if (IS_ERR(clock->clk))
> >                       return PTR_ERR(clock->clk);
> >
> > @@ -1198,7 +1210,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       while (res->clock_for_reset[ispif->nclocks_for_reset])
> >               ispif->nclocks_for_reset++;
> >
> > -     ispif->clock_for_reset = devm_kcalloc(dev,
> > +     ispif->clock_for_reset = devm_kcalloc(camss->dev,
> >                                             ispif->nclocks_for_reset,
> >                                             sizeof(*ispif->clock_for_reset),
> >                                             GFP_KERNEL);
> > @@ -1208,7 +1220,7 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
> >       for (i = 0; i < ispif->nclocks_for_reset; i++) {
> >               struct camss_clock *clock = &ispif->clock_for_reset[i];
> >
> > -             clock->clk = devm_clk_get(dev, res->clock_for_reset[i]);
> > +             clock->clk = devm_clk_get(camss->dev, res->clock_for_reset[i]);
> >               if (IS_ERR(clock->clk))
> >                       return PTR_ERR(clock->clk);
> >
> > @@ -1331,10 +1343,13 @@ static const struct media_entity_operations ispif_media_ops = {
> >   int msm_ispif_register_entities(struct ispif_device *ispif,
> >                               struct v4l2_device *v4l2_dev)
> >   {
> > -     struct device *dev = to_device(ispif);
> > +     struct camss *camss =  ispif->camss;
> >       int ret;
> >       int i;
> >
> > +     if (!ispif)
> > +             return 0;
> > +
> >       for (i = 0; i < ispif->line_num; i++) {
> >               struct v4l2_subdev *sd = &ispif->line[i].subdev;
> >               struct media_pad *pads = ispif->line[i].pads;
> > @@ -1348,7 +1363,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
> >
> >               ret = ispif_init_formats(sd, NULL);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to init format: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to init format: %d\n", ret);
> >                       goto error;
> >               }
> >
> > @@ -1360,13 +1375,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif,
> >               ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM,
> >                                            pads);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to init media entity: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to init media entity: %d\n",
> > +                             ret);
> >                       goto error;
> >               }
> >
> >               ret = v4l2_device_register_subdev(v4l2_dev, sd);
> >               if (ret < 0) {
> > -                     dev_err(dev, "Failed to register subdev: %d\n", ret);
> > +                     dev_err(camss->dev, "Failed to register subdev: %d\n",
> > +                             ret);
> >                       media_entity_cleanup(&sd->entity);
> >                       goto error;
> >               }
> > @@ -1393,6 +1410,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif)
> >   {
> >       int i;
> >
> > +     if (!ispif)
> > +             return;
> > +
> >       mutex_destroy(&ispif->power_lock);
> >       mutex_destroy(&ispif->config_lock);
> >
> > diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
> > index 4132174f7ea1..fdf28e68cc7d 100644
> > --- a/drivers/media/platform/qcom/camss/camss-ispif.h
> > +++ b/drivers/media/platform/qcom/camss/camss-ispif.h
> > @@ -63,11 +63,12 @@ struct ispif_device {
> >       struct mutex config_lock;
> >       unsigned int line_num;
> >       struct ispif_line *line;
> > +     struct camss *camss;
> >   };
> >
> >   struct resources_ispif;
> >
> > -int msm_ispif_subdev_init(struct ispif_device *ispif,
> > +int msm_ispif_subdev_init(struct camss *camss,
> >                         const struct resources_ispif *res);
> >
> >   int msm_ispif_register_entities(struct ispif_device *ispif,
> > diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> > index 8fefce57bc49..aeec59bc6194 100644
> > --- a/drivers/media/platform/qcom/camss/camss.c
> > +++ b/drivers/media/platform/qcom/camss/camss.c
> > @@ -748,11 +748,13 @@ static int camss_init_subdevices(struct camss *camss)
> >               }
> >       }
> >
> > -     ret = msm_ispif_subdev_init(&camss->ispif, ispif_res);
> > -     if (ret < 0) {
> > -             dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> > +     if (camss->ispif) {
> > +             ret = msm_ispif_subdev_init(camss, ispif_res);
> > +             if (ret < 0) {
> > +                     dev_err(camss->dev, "Failed to init ispif sub-device: %d\n",
> >                       ret);
> > -             return ret;
> > +                     return ret;
> > +             }
> >       }
> >
> >       for (i = 0; i < camss->vfe_num; i++) {
> > @@ -801,11 +803,14 @@ static int camss_register_entities(struct camss *camss)
> >               }
> >       }
> >
> > -     ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev);
> > -     if (ret < 0) {
> > -             dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> > +     if (camss->ispif) {
> > +             ret = msm_ispif_register_entities(camss->ispif,
> > +                                               &camss->v4l2_dev);
> > +             if (ret < 0) {
> > +                     dev_err(camss->dev, "Failed to register ispif entities: %d\n",
> >                       ret);
> > -             goto err_reg_ispif;
> > +                     goto err_reg_ispif;
> > +             }
> >       }
> >
> >       for (i = 0; i < camss->vfe_num; i++) {
> > @@ -838,43 +843,64 @@ static int camss_register_entities(struct camss *camss)
> >               }
> >       }
> >
> > -     for (i = 0; i < camss->csid_num; i++) {
> > -             for (j = 0; j < camss->ispif.line_num; j++) {
> > -                     ret = media_create_pad_link(
> > -                             &camss->csid[i].subdev.entity,
> > -                             MSM_CSID_PAD_SRC,
> > -                             &camss->ispif.line[j].subdev.entity,
> > -                             MSM_ISPIF_PAD_SINK,
> > -                             0);
> > -                     if (ret < 0) {
> > -                             dev_err(camss->dev,
> > -                                     "Failed to link %s->%s entities: %d\n",
> > -                                     camss->csid[i].subdev.entity.name,
> > -                                     camss->ispif.line[j].subdev.entity.name,
> > -                                     ret);
> > -                             goto err_link;
> > -                     }
> > -             }
> > -     }
> > -
> > -     for (i = 0; i < camss->ispif.line_num; i++)
> > -             for (k = 0; k < camss->vfe_num; k++)
> > -                     for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +     if (camss->ispif) {
> > +             for (i = 0; i < camss->csid_num; i++) {
> > +                     for (j = 0; j < camss->ispif->line_num; j++) {
> >                               ret = media_create_pad_link(
> > -                                     &camss->ispif.line[i].subdev.entity,
> > -                                     MSM_ISPIF_PAD_SRC,
> > -                                     &camss->vfe[k].line[j].subdev.entity,
> > -                                     MSM_VFE_PAD_SINK,
> > +                                     &camss->csid[i].subdev.entity,
> > +                                     MSM_CSID_PAD_SRC,
> > +                                     &camss->ispif->line[j].subdev.entity,
> > +                                     MSM_ISPIF_PAD_SINK,
> >                                       0);
> >                               if (ret < 0) {
> >                                       dev_err(camss->dev,
> >                                               "Failed to link %s->%s entities: %d\n",
> > -                                             camss->ispif.line[i].subdev.entity.name,
> > -                                             camss->vfe[k].line[j].subdev.entity.name,
> > +                                             camss->csid[i].subdev.entity.name,
> > +                                             camss->ispif->line[j].subdev.entity.name,
> >                                               ret);
> >                                       goto err_link;
> >                               }
> >                       }
> > +             }
> > +
> > +             for (i = 0; i < camss->ispif->line_num; i++)
> > +                     for (k = 0; k < camss->vfe_num; k++)
> > +                             for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +                                     ret = media_create_pad_link(
> > +                                             &camss->ispif->line[i].subdev.entity,
> > +                                             MSM_ISPIF_PAD_SRC,
> > +                                             &camss->vfe[k].line[j].subdev.entity,
> > +                                             MSM_VFE_PAD_SINK,
> > +                                             0);
> > +                                     if (ret < 0) {
> > +                                             dev_err(camss->dev,
> > +                                                     "Failed to link %s->%s entities: %d\n",
> > +                                                     camss->ispif->line[i].subdev.entity.name,
> > +                                                     camss->vfe[k].line[j].subdev.entity.name,
> > +                                                     ret);
> > +                                             goto err_link;
> > +                                     }
> > +                             }
> > +     } else {
> > +             for (i = 0; i < camss->csid_num; i++)
> > +                     for (k = 0; k < camss->vfe_num; k++)
> > +                             for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> > +                                     ret = media_create_pad_link(
> > +                                             &camss->csid[i].subdev.entity,
> > +                                             MSM_CSID_PAD_SRC,
> > +                                             &camss->vfe[k].line[j].subdev.entity,
> > +                                             MSM_VFE_PAD_SINK,
> > +                                             0);
> > +                                     if (ret < 0) {
> > +                                             dev_err(camss->dev,
> > +                                                     "Failed to link %s->%s entities: %d\n",
> > +                                                     camss->csid[i].subdev.entity.name,
> > +                                                     camss->vfe[k].line[j].subdev.entity.name,
> > +                                                     ret);
> > +                                             goto err_link;
> > +                                     }
> > +                             }
> > +     }
> >
> >       return 0;
> >
> > @@ -884,8 +910,9 @@ static int camss_register_entities(struct camss *camss)
> >       for (i--; i >= 0; i--)
> >               msm_vfe_unregister_entities(&camss->vfe[i]);
> >
> > -     msm_ispif_unregister_entities(&camss->ispif);
> >   err_reg_ispif:
> > +     if (camss->ispif)
> > +             msm_ispif_unregister_entities(camss->ispif);
> >
> >       i = camss->csid_num;
> >   err_reg_csid:
> > @@ -916,7 +943,8 @@ static void camss_unregister_entities(struct camss *camss)
> >       for (i = 0; i < camss->csid_num; i++)
> >               msm_csid_unregister_entity(&camss->csid[i]);
> >
> > -     msm_ispif_unregister_entities(&camss->ispif);
> > +     if (camss->ispif)
> > +             msm_ispif_unregister_entities(camss->ispif);
> >
> >       for (i = 0; i < camss->vfe_num; i++)
> >               msm_vfe_unregister_entities(&camss->vfe[i]);
> > @@ -1047,6 +1075,15 @@ static int camss_probe(struct platform_device *pdev)
> >               goto err_free;
> >       }
> >
> > +     if (camss->version == CAMSS_8x16 ||
> > +         camss->version == CAMSS_8x96) {
> > +             camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->csid), GFP_KERNEL);
>
> - shouldn't it be sizeof(*camss->ispif) instead?

Very much so, thanks for catching this.

>
> Thanks,
> Andrey
>
> > +             if (!camss->ispif) {
> > +                     ret = -ENOMEM;
> > +                     goto err_free;
> > +             }
> > +     }
> > +
> >       camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
> >                                 GFP_KERNEL);
> >       if (!camss->vfe) {
> > diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
> > index 46e986452824..b7ad8e9f68a8 100644
> > --- a/drivers/media/platform/qcom/camss/camss.h
> > +++ b/drivers/media/platform/qcom/camss/camss.h
> > @@ -79,7 +79,7 @@ struct camss {
> >       struct csiphy_device *csiphy;
> >       int csid_num;
> >       struct csid_device *csid;
> > -     struct ispif_device ispif;
> > +     struct ispif_device *ispif;
> >       int vfe_num;
> >       struct vfe_device *vfe;
> >       atomic_t ref_count;
> >

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 05/17] media: camss: Refactor VFE HW version support
  2021-01-13 22:38   ` Andrey Konovalov
@ 2021-01-14 10:07     ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-14 10:07 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: Andy Gross, Bjorn Andersson, Todor Tomov, Mauro Carvalho Chehab,
	Rob Herring, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Hey Andrey,

On Wed, 13 Jan 2021 at 23:39, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>
> Hi Robert,
>
> Thank you for the patch!
>
> On 08.01.2021 15:04, Robert Foss wrote:
> > In order to support Qualcomm ISP hardware architectures that diverge
> > from older architectures, the VFE subdevice driver needs to be refactored
> > to better abstract the different ISP architectures.
> >
> > Gen1 represents the CAMSS ISP architecture. The ISP architecture developed
> > after CAMSS, Titan, will be referred to as Gen2.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >   drivers/media/platform/qcom/camss/Makefile    |    2 +
> >   .../media/platform/qcom/camss/camss-vfe-4-1.c |  117 +-
> >   .../media/platform/qcom/camss/camss-vfe-4-7.c |  238 ++--
> >   .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
> >   .../platform/qcom/camss/camss-vfe-gen1.c      |  760 +++++++++++
> >   .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
> >   drivers/media/platform/qcom/camss/camss-vfe.c |  770 +----------
> >   drivers/media/platform/qcom/camss/camss-vfe.h |  113 +-
> >   8 files changed, 2241 insertions(+), 1035 deletions(-)
> >   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> >   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> >   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> >
> > diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> > index 63c1b1b2943c..940c0ae3e003 100644
> > --- a/drivers/media/platform/qcom/camss/Makefile
> > +++ b/drivers/media/platform/qcom/camss/Makefile
> > @@ -10,6 +10,8 @@ qcom-camss-objs += \
> >               camss-ispif.o \
> >               camss-vfe-4-1.o \
> >               camss-vfe-4-7.o \
> > +             camss-vfe-4-8.o \
> > +             camss-vfe-gen1.o \
> >               camss-vfe.o \
> >               camss-video.o \
> >
> > 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 a1b56b89130d..269dc0860de9 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> > @@ -12,7 +12,9 @@
> >   #include <linux/io.h>
> >   #include <linux/iopoll.h>
> >
> > +#include "camss.h"
> >   #include "camss-vfe.h"
> > +#include "camss-vfe-gen1.h"
> >
> >   #define VFE_0_HW_VERSION            0x000
> >
> > @@ -283,30 +285,6 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
> >                       1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT);
> >   }
> >
> > -#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> > -
> > -static int vfe_word_per_line(u32 format, u32 pixel_per_line)
> > -{
> > -     int val = 0;
> > -
> > -     switch (format) {
> > -     case V4L2_PIX_FMT_NV12:
> > -     case V4L2_PIX_FMT_NV21:
> > -     case V4L2_PIX_FMT_NV16:
> > -     case V4L2_PIX_FMT_NV61:
> > -             val = CALC_WORD(pixel_per_line, 1, 8);
> > -             break;
> > -     case V4L2_PIX_FMT_YUYV:
> > -     case V4L2_PIX_FMT_YVYU:
> > -     case V4L2_PIX_FMT_UYVY:
> > -     case V4L2_PIX_FMT_VYUY:
> > -             val = CALC_WORD(pixel_per_line, 2, 8);
> > -             break;
> > -     }
> > -
> > -     return val;
> > -}
> > -
> >   static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
> >                            u16 *width, u16 *height, u16 *bytesperline)
> >   {
> > @@ -665,20 +643,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
> >       writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
> >   }
> >
> > -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> > -{
> > -     if (input / output >= 16)
> > -             return 0;
> > -
> > -     if (input / output >= 8)
> > -             return 1;
> > -
> > -     if (input / output >= 4)
> > -             return 2;
> > -
> > -     return 3;
> > -}
> > -
> >   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;
> > @@ -974,46 +938,61 @@ static irqreturn_t vfe_isr(int irq, void *dev)
> >       return IRQ_HANDLED;
> >   }
> >
> > -const struct vfe_hw_ops vfe_ops_4_1 = {
> > -     .hw_version_read = vfe_hw_version_read,
> > +
> > +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
> > +     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> > +     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > +     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > +     .bus_reload_wm = vfe_bus_reload_wm,
> > +     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > +     .enable_irq_common = vfe_enable_irq_common,
> > +     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > +     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> >       .get_ub_size = vfe_get_ub_size,
> > -     .global_reset = vfe_global_reset,
> > -     .halt_request = vfe_halt_request,
> >       .halt_clear = vfe_halt_clear,
> > +     .halt_request = vfe_halt_request,
> > +     .set_camif_cfg = vfe_set_camif_cfg,
> > +     .set_camif_cmd = vfe_set_camif_cmd,
> > +     .set_cgc_override = vfe_set_cgc_override,
> > +     .set_clamp_cfg = vfe_set_clamp_cfg,
> > +     .set_crop_cfg = vfe_set_crop_cfg,
> > +     .set_demux_cfg = vfe_set_demux_cfg,
> > +     .set_ds = vfe_set_ds,
> > +     .set_module_cfg = vfe_set_module_cfg,
> > +     .set_qos = vfe_set_qos,
> > +     .set_rdi_cid = vfe_set_rdi_cid,
> > +     .set_realign_cfg = vfe_set_realign_cfg,
> > +     .set_scale_cfg = vfe_set_scale_cfg,
> > +     .set_xbar_cfg = vfe_set_xbar_cfg,
> >       .wm_enable = vfe_wm_enable,
> >       .wm_frame_based = vfe_wm_frame_based,
> > +     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> >       .wm_line_based = vfe_wm_line_based,
> > -     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> >       .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> > -     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > -     .bus_reload_wm = vfe_bus_reload_wm,
> > +     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> >       .wm_set_ping_addr = vfe_wm_set_ping_addr,
> >       .wm_set_pong_addr = vfe_wm_set_pong_addr,
> > -     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> > -     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > -     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> >       .wm_set_subsample = vfe_wm_set_subsample,
> > -     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > -     .set_xbar_cfg = vfe_set_xbar_cfg,
> > -     .set_realign_cfg = vfe_set_realign_cfg,
> > -     .set_rdi_cid = vfe_set_rdi_cid,
> > -     .reg_update = vfe_reg_update,
> > -     .reg_update_clear = vfe_reg_update_clear,
> > -     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> > -     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > -     .enable_irq_common = vfe_enable_irq_common,
> > -     .set_demux_cfg = vfe_set_demux_cfg,
> > -     .set_scale_cfg = vfe_set_scale_cfg,
> > -     .set_crop_cfg = vfe_set_crop_cfg,
> > -     .set_clamp_cfg = vfe_set_clamp_cfg,
> > -     .set_qos = vfe_set_qos,
> > -     .set_ds = vfe_set_ds,
> > -     .set_cgc_override = vfe_set_cgc_override,
> > -     .set_camif_cfg = vfe_set_camif_cfg,
> > -     .set_camif_cmd = vfe_set_camif_cmd,
> > -     .set_module_cfg = vfe_set_module_cfg,
> > -     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > +     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > +};
> > +
> > +static void vfe_subdev_init(struct vfe_device *vfe)
> > +{
> > +     vfe->isr_ops = vfe_isr_ops_gen1;
> > +     vfe->ops_gen1 = &vfe_ops_gen1_4_1;
> > +     vfe->video_ops = vfe_video_ops_gen1;
> > +}
> > +
> > +const struct vfe_hw_ops vfe_ops_4_1 = {
> > +     .global_reset = vfe_global_reset,
> > +     .hw_version_read = vfe_hw_version_read,
> >       .isr_read = vfe_isr_read,
> > -     .violation_read = vfe_violation_read,
> >       .isr = vfe_isr,
> > +     .reg_update_clear = vfe_reg_update_clear,
> > +     .reg_update = vfe_reg_update,
> > +     .subdev_init = vfe_subdev_init,
> > +     .vfe_disable = vfe_gen1_disable,
> > +     .vfe_enable = vfe_gen1_enable,
> > +     .vfe_halt = vfe_gen1_halt,
> > +     .violation_read = vfe_violation_read,
> >   };
> > 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 84c33b8f9fe3..d0d470be1c10 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> > @@ -12,7 +12,10 @@
> >   #include <linux/io.h>
> >   #include <linux/iopoll.h>
> >
> > +#include "camss.h"
> >   #include "camss-vfe.h"
> > +#include "camss-vfe-gen1.h"
> > +
> >
> >   #define VFE_0_HW_VERSION            0x000
> >
> > @@ -257,7 +260,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> >       dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
> >   }
> >
> > -static u16 vfe47_get_ub_size(u8 vfe_id)
> > +static u16 vfe_get_ub_size(u8 vfe_id)
> >   {
> >       if (vfe_id == 0)
> >               return MSM_VFE_VFE0_UB_SIZE_RDI;
> > @@ -295,6 +298,8 @@ static void vfe_global_reset(struct vfe_device *vfe)
> >                        VFE_0_GLOBAL_RESET_CMD_CORE;
> >
> >       writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> > +
> > +     /* Enforce barrier between IRQ mask setup and global reset */
> >       wmb();
> >       writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
> >   }
> > @@ -310,7 +315,7 @@ static void vfe_halt_clear(struct vfe_device *vfe)
> >       writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
> >   }
> >
> > -static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> > +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> >   {
> >       if (enable)
> >               vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
> > @@ -459,8 +464,12 @@ static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
> >
> >   static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
> >   {
> > +     /* Enforce barrier between any outstanding register write */
> >       wmb();
> > +
> >       writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> > +
> > +     /* Use barrier to make sure bus reload is issued before anything else */
> >       wmb();
> >   }
> >
> > @@ -674,8 +683,12 @@ static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
> >   static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> >   {
> >       vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> > +
> > +     /* Enforce barrier between line update and commit */
> >       wmb();
> >       writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> > +
> > +     /* Make sure register update is issued before further reg writes */
> >       wmb();
> >   }
> >
> > @@ -779,20 +792,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
> >       writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
> >   }
> >
> > -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> > -{
> > -     if (input / output >= 16)
> > -             return 0;
> > -
> > -     if (input / output >= 8)
> > -             return 1;
> > -
> > -     if (input / output >= 4)
> > -             return 2;
> > -
> > -     return 3;
> > -}
> > -
> >   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;
> > @@ -894,7 +893,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe)
> >       writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
> >   }
> >
> > -static void vfe47_set_qos(struct vfe_device *vfe)
> > +static void vfe_set_qos(struct vfe_device *vfe)
> >   {
> >       u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
> >       u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> > @@ -909,7 +908,7 @@ static void vfe47_set_qos(struct vfe_device *vfe)
> >       writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> >   }
> >
> > -static void vfe47_set_ds(struct vfe_device *vfe)
> > +static void vfe_set_ds(struct vfe_device *vfe)
> >   {
> >       u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
> >       u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> > @@ -993,6 +992,8 @@ static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
> >
> >       cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
> >       writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> > +
> > +     /* Make sure camif command is issued written before it is changed again */
> >       wmb();
> >
> >       if (enable)
> > @@ -1035,24 +1036,7 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
> >       return ret;
> >   }
> >
> > -static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> > -{
> > -     *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> > -     *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
> >
> > -     writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> > -     writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> > -
> > -     wmb();
> > -     writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> > -}
> > -
> > -static void vfe_violation_read(struct vfe_device *vfe)
> > -{
> > -     u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> > -
> > -     pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> > -}
> >
> >   /*
> >    * vfe_isr - VFE module interrupt handler
> > @@ -1107,150 +1091,80 @@ static irqreturn_t vfe_isr(int irq, void *dev)
> >       return IRQ_HANDLED;
> >   }
> >
> > -const struct vfe_hw_ops vfe_ops_4_7 = {
> > -     .hw_version_read = vfe_hw_version_read,
> > -     .get_ub_size = vfe47_get_ub_size,
> > -     .global_reset = vfe_global_reset,
> > -     .halt_request = vfe_halt_request,
> > -     .halt_clear = vfe_halt_clear,
> > -     .wm_enable = vfe47_wm_enable,
> > -     .wm_frame_based = vfe_wm_frame_based,
> > -     .wm_line_based = vfe_wm_line_based,
> > -     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> > -     .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> > -     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > -     .bus_reload_wm = vfe_bus_reload_wm,
> > -     .wm_set_ping_addr = vfe_wm_set_ping_addr,
> > -     .wm_set_pong_addr = vfe_wm_set_pong_addr,
> > -     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> > -     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > -     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> > -     .wm_set_subsample = vfe_wm_set_subsample,
> > -     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > -     .set_xbar_cfg = vfe_set_xbar_cfg,
> > -     .set_realign_cfg = vfe_set_realign_cfg,
> > -     .set_rdi_cid = vfe_set_rdi_cid,
> > -     .reg_update = vfe_reg_update,
> > -     .reg_update_clear = vfe_reg_update_clear,
> > -     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> > -     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > -     .enable_irq_common = vfe_enable_irq_common,
> > -     .set_demux_cfg = vfe_set_demux_cfg,
> > -     .set_scale_cfg = vfe_set_scale_cfg,
> > -     .set_crop_cfg = vfe_set_crop_cfg,
> > -     .set_clamp_cfg = vfe_set_clamp_cfg,
> > -     .set_qos = vfe47_set_qos,
> > -     .set_ds = vfe47_set_ds,
> > -     .set_cgc_override = vfe_set_cgc_override,
> > -     .set_camif_cfg = vfe_set_camif_cfg,
> > -     .set_camif_cmd = vfe_set_camif_cmd,
> > -     .set_module_cfg = vfe_set_module_cfg,
> > -     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > -     .isr_read = vfe_isr_read,
> > -     .violation_read = vfe_violation_read,
> > -     .isr = vfe_isr,
> > -};
> > -
> > -static u16 vfe48_get_ub_size(u8 vfe_id)
> > +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> >   {
> > -     /* On VFE4.8 the ub-size is the same on both instances */
> > -     return MSM_VFE_VFE0_UB_SIZE_RDI;
> > -}
> > +     *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> > +     *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
> >
> > -static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> > -{
> > -     if (enable)
> > -             writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> > -                            vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> > -     else
> > -             writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> > -                            vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> > +     writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> > +     writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> >
> > -     /* The WM must be enabled before sending other commands */
> > +     /* Enforce barrier between local & global IRQ clear */
> >       wmb();
> > +     writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> >   }
> >
> > -static void vfe48_set_qos(struct vfe_device *vfe)
> > -{
> > -     u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG;
> > -     u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG;
> > -     u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG;
> > -     u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG;
> > -
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> > -     writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> > -     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> > -     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> > -     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> > -     writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> > -}
> > -
> > -static void vfe48_set_ds(struct vfe_device *vfe)
> > +static void vfe_violation_read(struct vfe_device *vfe)
> >   {
> > -     u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG;
> > -     u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG;
> > +     u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> >
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> > -     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> > -     writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> > +     pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> >   }
> >
> > -const struct vfe_hw_ops vfe_ops_4_8 = {
> > -     .hw_version_read = vfe_hw_version_read,
> > -     .get_ub_size = vfe48_get_ub_size,
> > -     .global_reset = vfe_global_reset,
> > -     .halt_request = vfe_halt_request,
> > +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = {
> > +     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> > +     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > +     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > +     .bus_reload_wm = vfe_bus_reload_wm,
> > +     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > +     .enable_irq_common = vfe_enable_irq_common,
> > +     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > +     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> > +     .get_ub_size = vfe_get_ub_size,
> >       .halt_clear = vfe_halt_clear,
> > -     .wm_enable = vfe48_wm_enable,
> > +     .halt_request = vfe_halt_request,
> > +     .set_camif_cfg = vfe_set_camif_cfg,
> > +     .set_camif_cmd = vfe_set_camif_cmd,
> > +     .set_cgc_override = vfe_set_cgc_override,
> > +     .set_clamp_cfg = vfe_set_clamp_cfg,
> > +     .set_crop_cfg = vfe_set_crop_cfg,
> > +     .set_demux_cfg = vfe_set_demux_cfg,
> > +     .set_ds = vfe_set_ds,
> > +     .set_module_cfg = vfe_set_module_cfg,
> > +     .set_qos = vfe_set_qos,
> > +     .set_rdi_cid = vfe_set_rdi_cid,
> > +     .set_realign_cfg = vfe_set_realign_cfg,
> > +     .set_scale_cfg = vfe_set_scale_cfg,
> > +     .set_xbar_cfg = vfe_set_xbar_cfg,
> > +     .wm_enable = vfe_wm_enable,
> >       .wm_frame_based = vfe_wm_frame_based,
> > +     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> >       .wm_line_based = vfe_wm_line_based,
> > -     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> >       .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> > -     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > -     .bus_reload_wm = vfe_bus_reload_wm,
> > +     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> >       .wm_set_ping_addr = vfe_wm_set_ping_addr,
> >       .wm_set_pong_addr = vfe_wm_set_pong_addr,
> > -     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> > -     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > -     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> >       .wm_set_subsample = vfe_wm_set_subsample,
> > -     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > -     .set_xbar_cfg = vfe_set_xbar_cfg,
> > -     .set_realign_cfg = vfe_set_realign_cfg,
> > -     .set_rdi_cid = vfe_set_rdi_cid,
> > -     .reg_update = vfe_reg_update,
> > -     .reg_update_clear = vfe_reg_update_clear,
> > -     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> > -     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > -     .enable_irq_common = vfe_enable_irq_common,
> > -     .set_demux_cfg = vfe_set_demux_cfg,
> > -     .set_scale_cfg = vfe_set_scale_cfg,
> > -     .set_crop_cfg = vfe_set_crop_cfg,
> > -     .set_clamp_cfg = vfe_set_clamp_cfg,
> > -     .set_qos = vfe48_set_qos,
> > -     .set_ds = vfe48_set_ds,
> > -     .set_cgc_override = vfe_set_cgc_override,
> > -     .set_camif_cfg = vfe_set_camif_cfg,
> > -     .set_camif_cmd = vfe_set_camif_cmd,
> > -     .set_module_cfg = vfe_set_module_cfg,
> > -     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > +     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > +};
> > +
> > +static void vfe_subdev_init(struct vfe_device *vfe)
> > +{
> > +     vfe->isr_ops = vfe_isr_ops_gen1;
> > +     vfe->ops_gen1 = &vfe_ops_gen1_4_7;
> > +     vfe->video_ops = vfe_video_ops_gen1;
> > +}
> > +
> > +const struct vfe_hw_ops vfe_ops_4_7 = {
> > +     .global_reset = vfe_global_reset,
> > +     .hw_version_read = vfe_hw_version_read,
> >       .isr_read = vfe_isr_read,
> > -     .violation_read = vfe_violation_read,
> >       .isr = vfe_isr,
> > +     .reg_update_clear = vfe_reg_update_clear,
> > +     .reg_update = vfe_reg_update,
> > +     .subdev_init = vfe_subdev_init,
> > +     .vfe_disable = vfe_gen1_disable,
> > +     .vfe_enable = vfe_gen1_enable,
> > +     .vfe_halt = vfe_gen1_halt,
> > +     .violation_read = vfe_violation_read,
> >   };
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> > new file mode 100644
> > index 000000000000..609db85c5039
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> > @@ -0,0 +1,1166 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * camss-vfe-4-7.c
>
> camss-vfe-4-8.c ?

Ah, thanks!

>
> > + *
> > + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
>
> - same here: v4.8

Ack!

>
> Thanks,
> Andrey
>
> > + *
> > + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> > + * Copyright (C) 2015-2018 Linaro Ltd.
> > + */
> > +
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +
> > +#include "camss.h"
> > +#include "camss-vfe.h"
> > +#include "camss-vfe-gen1.h"
> > +
> > +
> > +#define VFE_0_HW_VERSION             0x000
> > +
> > +#define VFE_0_GLOBAL_RESET_CMD               0x018
> > +#define VFE_0_GLOBAL_RESET_CMD_CORE  BIT(0)
> > +#define VFE_0_GLOBAL_RESET_CMD_CAMIF BIT(1)
> > +#define VFE_0_GLOBAL_RESET_CMD_BUS   BIT(2)
> > +#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG       BIT(3)
> > +#define VFE_0_GLOBAL_RESET_CMD_REGISTER      BIT(4)
> > +#define VFE_0_GLOBAL_RESET_CMD_PM    BIT(5)
> > +#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR      BIT(6)
> > +#define VFE_0_GLOBAL_RESET_CMD_TESTGEN       BIT(7)
> > +#define VFE_0_GLOBAL_RESET_CMD_DSP   BIT(8)
> > +#define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC      BIT(9)
> > +
> > +#define VFE_0_MODULE_LENS_EN         0x040
> > +#define VFE_0_MODULE_LENS_EN_DEMUX           BIT(2)
> > +#define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE BIT(3)
> > +
> > +#define VFE_0_MODULE_ZOOM_EN         0x04c
> > +#define VFE_0_MODULE_ZOOM_EN_SCALE_ENC               BIT(1)
> > +#define VFE_0_MODULE_ZOOM_EN_CROP_ENC                BIT(2)
> > +#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF     BIT(9)
> > +
> > +#define VFE_0_CORE_CFG                       0x050
> > +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR  0x4
> > +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB  0x5
> > +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY  0x6
> > +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY  0x7
> > +#define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN       BIT(4)
> > +
> > +#define VFE_0_IRQ_CMD                        0x058
> > +#define VFE_0_IRQ_CMD_GLOBAL_CLEAR   BIT(0)
> > +
> > +#define VFE_0_IRQ_MASK_0             0x05c
> > +#define VFE_0_IRQ_MASK_0_CAMIF_SOF                   BIT(0)
> > +#define VFE_0_IRQ_MASK_0_CAMIF_EOF                   BIT(1)
> > +#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)          BIT((n) + 5)
> > +#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n)                \
> > +     ((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n))
> > +#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n) BIT((n) + 8)
> > +#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n)   BIT((n) + 25)
> > +#define VFE_0_IRQ_MASK_0_RESET_ACK                   BIT(31)
> > +#define VFE_0_IRQ_MASK_1             0x060
> > +#define VFE_0_IRQ_MASK_1_CAMIF_ERROR                 BIT(0)
> > +#define VFE_0_IRQ_MASK_1_VIOLATION                   BIT(7)
> > +#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK            BIT(8)
> > +#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)      BIT((n) + 9)
> > +#define VFE_0_IRQ_MASK_1_RDIn_SOF(n)                 BIT((n) + 29)
> > +
> > +#define VFE_0_IRQ_CLEAR_0            0x064
> > +#define VFE_0_IRQ_CLEAR_1            0x068
> > +
> > +#define VFE_0_IRQ_STATUS_0           0x06c
> > +#define VFE_0_IRQ_STATUS_0_CAMIF_SOF                 BIT(0)
> > +#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)                BIT((n) + 5)
> > +#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n)              \
> > +     ((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n))
> > +#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n)       BIT((n) + 8)
> > +#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n) BIT((n) + 25)
> > +#define VFE_0_IRQ_STATUS_0_RESET_ACK                 BIT(31)
> > +#define VFE_0_IRQ_STATUS_1           0x070
> > +#define VFE_0_IRQ_STATUS_1_VIOLATION                 BIT(7)
> > +#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK          BIT(8)
> > +#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n)                       BIT((n) + 29)
> > +
> > +#define VFE_0_IRQ_COMPOSITE_MASK_0   0x074
> > +#define VFE_0_VIOLATION_STATUS               0x07c
> > +
> > +#define VFE_0_BUS_CMD                        0x80
> > +#define VFE_0_BUS_CMD_Mx_RLD_CMD(x)  BIT(x)
> > +
> > +#define VFE_0_BUS_CFG                        0x084
> > +
> > +#define VFE_0_BUS_XBAR_CFG_x(x)              (0x90 + 0x4 * ((x) / 2))
> > +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN                        BIT(2)
> > +#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN                        BIT(3)
> > +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA                (0x1 << 4)
> > +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER                (0x2 << 4)
> > +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA  (0x3 << 4)
> > +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT               8
> > +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA                0x0
> > +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0    0xc
> > +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1    0xd
> > +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2    0xe
> > +
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n)           (0x0a0 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT        0
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n)     (0x0a4 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n)     (0x0ac + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n)              (0x0b4 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT 1
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT      2
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK       (0x1f << 2)
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n)                (0x0b8 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT      16
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n)    (0x0bc + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n)    (0x0c0 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n)     \
> > +                                                     (0x0c4 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n) \
> > +                                                     (0x0c8 + 0x2c * (n))
> > +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF        0xffffffff
> > +
> > +#define VFE_0_BUS_PING_PONG_STATUS   0x338
> > +
> > +#define VFE_0_BUS_BDG_CMD            0x400
> > +#define VFE_0_BUS_BDG_CMD_HALT_REQ   1
> > +
> > +#define VFE_0_BUS_BDG_QOS_CFG_0              0x404
> > +#define VFE_0_BUS_BDG_QOS_CFG_0_CFG  0xaaa5aaa5
> > +#define VFE_0_BUS_BDG_QOS_CFG_1              0x408
> > +#define VFE_0_BUS_BDG_QOS_CFG_2              0x40c
> > +#define VFE_0_BUS_BDG_QOS_CFG_3              0x410
> > +#define VFE_0_BUS_BDG_QOS_CFG_3_CFG  0xaa55aaa5
> > +#define VFE_0_BUS_BDG_QOS_CFG_4              0x414
> > +#define VFE_0_BUS_BDG_QOS_CFG_4_CFG  0xaa55aa55
> > +#define VFE_0_BUS_BDG_QOS_CFG_5              0x418
> > +#define VFE_0_BUS_BDG_QOS_CFG_6              0x41c
> > +#define VFE_0_BUS_BDG_QOS_CFG_7              0x420
> > +#define VFE_0_BUS_BDG_QOS_CFG_7_CFG  0x0005aa55
> > +
> > +#define VFE_0_BUS_BDG_DS_CFG_0               0x424
> > +#define VFE_0_BUS_BDG_DS_CFG_0_CFG   0xcccc1111
> > +#define VFE_0_BUS_BDG_DS_CFG_1               0x428
> > +#define VFE_0_BUS_BDG_DS_CFG_2               0x42c
> > +#define VFE_0_BUS_BDG_DS_CFG_3               0x430
> > +#define VFE_0_BUS_BDG_DS_CFG_4               0x434
> > +#define VFE_0_BUS_BDG_DS_CFG_5               0x438
> > +#define VFE_0_BUS_BDG_DS_CFG_6               0x43c
> > +#define VFE_0_BUS_BDG_DS_CFG_7               0x440
> > +#define VFE_0_BUS_BDG_DS_CFG_8               0x444
> > +#define VFE_0_BUS_BDG_DS_CFG_9               0x448
> > +#define VFE_0_BUS_BDG_DS_CFG_10              0x44c
> > +#define VFE_0_BUS_BDG_DS_CFG_11              0x450
> > +#define VFE_0_BUS_BDG_DS_CFG_12              0x454
> > +#define VFE_0_BUS_BDG_DS_CFG_13              0x458
> > +#define VFE_0_BUS_BDG_DS_CFG_14              0x45c
> > +#define VFE_0_BUS_BDG_DS_CFG_15              0x460
> > +#define VFE_0_BUS_BDG_DS_CFG_16              0x464
> > +#define VFE_0_BUS_BDG_DS_CFG_16_CFG  0x00000110
> > +
> > +#define VFE_0_RDI_CFG_x(x)           (0x46c + (0x4 * (x)))
> > +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT 28
> > +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK  (0xf << 28)
> > +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT     4
> > +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK              (0xf << 4)
> > +#define VFE_0_RDI_CFG_x_RDI_EN_BIT           BIT(2)
> > +#define VFE_0_RDI_CFG_x_MIPI_EN_BITS         0x3
> > +
> > +#define VFE_0_CAMIF_CMD                              0x478
> > +#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY       0
> > +#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY        1
> > +#define VFE_0_CAMIF_CMD_NO_CHANGE            3
> > +#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS   BIT(2)
> > +#define VFE_0_CAMIF_CFG                              0x47c
> > +#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN                BIT(6)
> > +#define VFE_0_CAMIF_FRAME_CFG                        0x484
> > +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG         0x488
> > +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG                0x48c
> > +#define VFE_0_CAMIF_SUBSAMPLE_CFG            0x490
> > +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN    0x498
> > +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN    0x49c
> > +#define VFE_0_CAMIF_STATUS                   0x4a4
> > +#define VFE_0_CAMIF_STATUS_HALT                      BIT(31)
> > +
> > +#define VFE_0_REG_UPDATE             0x4ac
> > +#define VFE_0_REG_UPDATE_RDIn(n)             BIT(1 + (n))
> > +#define VFE_0_REG_UPDATE_line_n(n)           \
> > +                     ((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n))
> > +
> > +#define VFE_0_DEMUX_CFG                              0x560
> > +#define VFE_0_DEMUX_CFG_PERIOD                       0x3
> > +#define VFE_0_DEMUX_GAIN_0                   0x564
> > +#define VFE_0_DEMUX_GAIN_0_CH0_EVEN          (0x80 << 0)
> > +#define VFE_0_DEMUX_GAIN_0_CH0_ODD           (0x80 << 16)
> > +#define VFE_0_DEMUX_GAIN_1                   0x568
> > +#define VFE_0_DEMUX_GAIN_1_CH1                       (0x80 << 0)
> > +#define VFE_0_DEMUX_GAIN_1_CH2                       (0x80 << 16)
> > +#define VFE_0_DEMUX_EVEN_CFG                 0x574
> > +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV    0x9cac
> > +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU    0xac9c
> > +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY    0xc9ca
> > +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY    0xcac9
> > +#define VFE_0_DEMUX_ODD_CFG                  0x578
> > +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV     0x9cac
> > +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU     0xac9c
> > +#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY     0xc9ca
> > +#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY     0xcac9
> > +
> > +#define VFE_0_SCALE_ENC_Y_CFG                        0x91c
> > +#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE               0x920
> > +#define VFE_0_SCALE_ENC_Y_H_PHASE            0x924
> > +#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE               0x934
> > +#define VFE_0_SCALE_ENC_Y_V_PHASE            0x938
> > +#define VFE_0_SCALE_ENC_CBCR_CFG             0x948
> > +#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE    0x94c
> > +#define VFE_0_SCALE_ENC_CBCR_H_PHASE         0x950
> > +#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE    0x960
> > +#define VFE_0_SCALE_ENC_CBCR_V_PHASE         0x964
> > +
> > +#define VFE_0_CROP_ENC_Y_WIDTH                       0x974
> > +#define VFE_0_CROP_ENC_Y_HEIGHT                      0x978
> > +#define VFE_0_CROP_ENC_CBCR_WIDTH            0x97c
> > +#define VFE_0_CROP_ENC_CBCR_HEIGHT           0x980
> > +
> > +#define VFE_0_CLAMP_ENC_MAX_CFG                      0x984
> > +#define VFE_0_CLAMP_ENC_MAX_CFG_CH0          (0xff << 0)
> > +#define VFE_0_CLAMP_ENC_MAX_CFG_CH1          (0xff << 8)
> > +#define VFE_0_CLAMP_ENC_MAX_CFG_CH2          (0xff << 16)
> > +#define VFE_0_CLAMP_ENC_MIN_CFG                      0x988
> > +#define VFE_0_CLAMP_ENC_MIN_CFG_CH0          (0x0 << 0)
> > +#define VFE_0_CLAMP_ENC_MIN_CFG_CH1          (0x0 << 8)
> > +#define VFE_0_CLAMP_ENC_MIN_CFG_CH2          (0x0 << 16)
> > +
> > +#define VFE_0_REALIGN_BUF_CFG                        0xaac
> > +#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL     BIT(2)
> > +#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL     BIT(3)
> > +#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE      BIT(4)
> > +
> > +#define VFE_0_BUS_IMAGE_MASTER_CMD           0xcec
> > +#define VFE_0_BUS_IMAGE_MASTER_n_SHIFT(x)    (2 * (x))
> > +
> > +#define CAMIF_TIMEOUT_SLEEP_US 1000
> > +#define CAMIF_TIMEOUT_ALL_US 1000000
> > +
> > +#define MSM_VFE_VFE0_UB_SIZE 2047
> > +#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3)
> > +#define MSM_VFE_VFE1_UB_SIZE 1535
> > +#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3)
> > +
> > +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> > +{
> > +     u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
> > +
> > +     dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
> > +}
> > +
> > +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> > +}
> > +
> > +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits | set_bits, vfe->base + reg);
> > +}
> > +
> > +static void vfe_global_reset(struct vfe_device *vfe)
> > +{
> > +     u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC        |
> > +                      VFE_0_GLOBAL_RESET_CMD_DSP             |
> > +                      VFE_0_GLOBAL_RESET_CMD_TESTGEN         |
> > +                      VFE_0_GLOBAL_RESET_CMD_BUS_MISR        |
> > +                      VFE_0_GLOBAL_RESET_CMD_PM              |
> > +                      VFE_0_GLOBAL_RESET_CMD_REGISTER        |
> > +                      VFE_0_GLOBAL_RESET_CMD_BUS_BDG         |
> > +                      VFE_0_GLOBAL_RESET_CMD_BUS             |
> > +                      VFE_0_GLOBAL_RESET_CMD_CAMIF           |
> > +                      VFE_0_GLOBAL_RESET_CMD_CORE;
> > +
> > +     writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> > +
> > +     /* Enforce barrier between IRQ mask setup and global reset */
> > +     wmb();
> > +     writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
> > +}
> > +
> > +static void vfe_halt_request(struct vfe_device *vfe)
> > +{
> > +     writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ,
> > +                    vfe->base + VFE_0_BUS_BDG_CMD);
> > +}
> > +
> > +static void vfe_halt_clear(struct vfe_device *vfe)
> > +{
> > +     writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
> > +}
> > +
> > +static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
> > +{
> > +     if (enable)
> > +             vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> > +                     1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> > +     else
> > +             vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> > +                     1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> > +}
> > +
> > +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> > +
> > +static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line)
> > +{
> > +     int val = 0;
> > +
> > +     switch (format) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             val = CALC_WORD(pixel_per_line, 1, 8);
> > +             break;
> > +     case V4L2_PIX_FMT_YUYV:
> > +     case V4L2_PIX_FMT_YVYU:
> > +     case V4L2_PIX_FMT_UYVY:
> > +     case V4L2_PIX_FMT_VYUY:
> > +             val = CALC_WORD(pixel_per_line, 2, 8);
> > +             break;
> > +     }
> > +
> > +     return val;
> > +}
> > +
> > +static int vfe_word_per_line_by_bytes(u32 bytes_per_line)
> > +{
> > +     return CALC_WORD(bytes_per_line, 1, 8);
> > +}
> > +
> > +static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
> > +                          u16 *width, u16 *height, u16 *bytesperline)
> > +{
> > +     switch (pix->pixelformat) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +             *width = pix->width;
> > +             *height = pix->height;
> > +             *bytesperline = pix->plane_fmt[0].bytesperline;
> > +             if (plane == 1)
> > +                     *height /= 2;
> > +             break;
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             *width = pix->width;
> > +             *height = pix->height;
> > +             *bytesperline = pix->plane_fmt[0].bytesperline;
> > +             break;
> > +     case V4L2_PIX_FMT_YUYV:
> > +     case V4L2_PIX_FMT_YVYU:
> > +     case V4L2_PIX_FMT_VYUY:
> > +     case V4L2_PIX_FMT_UYVY:
> > +             *width = pix->width;
> > +             *height = pix->height;
> > +             *bytesperline = pix->plane_fmt[plane].bytesperline;
> > +             break;
> > +
> > +     }
> > +}
> > +
> > +static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm,
> > +                           struct v4l2_pix_format_mplane *pix,
> > +                           u8 plane, u32 enable)
> > +{
> > +     u32 reg;
> > +
> > +     if (enable) {
> > +             u16 width = 0, height = 0, bytesperline = 0, wpl;
> > +
> > +             vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline);
> > +
> > +             wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width);
> > +
> > +             reg = height - 1;
> > +             reg |= ((wpl + 3) / 4 - 1) << 16;
> > +
> > +             writel_relaxed(reg, vfe->base +
> > +                            VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> > +
> > +             wpl = vfe_word_per_line_by_bytes(bytesperline);
> > +
> > +             reg = 0x3;
> > +             reg |= (height - 1) << 2;
> > +             reg |= ((wpl + 1) / 2) << 16;
> > +
> > +             writel_relaxed(reg, vfe->base +
> > +                            VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> > +     } else {
> > +             writel_relaxed(0, vfe->base +
> > +                            VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> > +             writel_relaxed(0, vfe->base +
> > +                            VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> > +     }
> > +}
> > +
> > +static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per)
> > +{
> > +     u32 reg;
> > +
> > +     reg = readl_relaxed(vfe->base +
> > +                         VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> > +
> > +     reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK);
> > +
> > +     reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT)
> > +             & VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK;
> > +
> > +     writel_relaxed(reg,
> > +                    vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> > +}
> > +
> > +static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm,
> > +                                      u32 pattern)
> > +{
> > +     writel_relaxed(pattern,
> > +            vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm));
> > +}
> > +
> > +static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
> > +                           u16 offset, u16 depth)
> > +{
> > +     u32 reg;
> > +
> > +     reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) |
> > +             depth;
> > +     writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm));
> > +}
> > +
> > +static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
> > +{
> > +     /* Enforce barrier between any outstanding register write */
> > +     wmb();
> > +
> > +     writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> > +
> > +     /* Use barrier to make sure bus reload is issued before anything else */
> > +     wmb();
> > +}
> > +
> > +static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> > +{
> > +     writel_relaxed(addr,
> > +                    vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm));
> > +}
> > +
> > +static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> > +{
> > +     writel_relaxed(addr,
> > +                    vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm));
> > +}
> > +
> > +static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm)
> > +{
> > +     u32 reg;
> > +
> > +     reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS);
> > +
> > +     return (reg >> wm) & 0x1;
> > +}
> > +
> > +static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable)
> > +{
> > +     if (enable)
> > +             writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG);
> > +     else
> > +             writel_relaxed(0, vfe->base + VFE_0_BUS_CFG);
> > +}
> > +
> > +static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm,
> > +                                   enum vfe_line_id id)
> > +{
> > +     u32 reg;
> > +
> > +     reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> > +     vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg);
> > +
> > +     reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> > +     reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) &
> > +             VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK;
> > +     vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg);
> > +
> > +     switch (id) {
> > +     case VFE_LINE_RDI0:
> > +     default:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     case VFE_LINE_RDI1:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     case VFE_LINE_RDI2:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     }
> > +
> > +     if (wm % 2 == 1)
> > +             reg <<= 16;
> > +
> > +     vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> > +}
> > +
> > +static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm)
> > +{
> > +     writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF,
> > +            vfe->base +
> > +            VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm));
> > +}
> > +
> > +static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
> > +                                        enum vfe_line_id id)
> > +{
> > +     u32 reg;
> > +
> > +     reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> > +     vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg);
> > +
> > +     switch (id) {
> > +     case VFE_LINE_RDI0:
> > +     default:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     case VFE_LINE_RDI1:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     case VFE_LINE_RDI2:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> > +                   VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> > +             break;
> > +     }
> > +
> > +     if (wm % 2 == 1)
> > +             reg <<= 16;
> > +
> > +     vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> > +}
> > +
> > +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);
> > +     u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> > +     u32 reg;
> > +
> > +     switch (p) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             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)
> > +                     reg <<= 16;
> > +
> > +             if (enable)
> > +                     vfe_reg_set(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> > +                                 reg);
> > +             else
> > +                     vfe_reg_clr(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> > +                                 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)
> > +                     reg <<= 16;
> > +
> > +             if (enable)
> > +                     vfe_reg_set(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> > +                                 reg);
> > +             else
> > +                     vfe_reg_clr(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> > +                                 reg);
> > +             break;
> > +     case V4L2_PIX_FMT_YUYV:
> > +     case V4L2_PIX_FMT_YVYU:
> > +     case V4L2_PIX_FMT_VYUY:
> > +     case V4L2_PIX_FMT_UYVY:
> > +             reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN;
> > +             reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
> > +
> > +             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)
> > +                     reg <<= 16;
> > +
> > +             if (enable)
> > +                     vfe_reg_set(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> > +                                 reg);
> > +             else
> > +                     vfe_reg_clr(vfe,
> > +                                 VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> > +                                 reg);
> > +             break;
> > +     default:
> > +             break;
> > +     }
> > +}
> > +
> > +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 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
> > +
> > +     if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
> > +                     p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY)
> > +             return;
> > +
> > +     if (enable) {
> > +             vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val);
> > +     } else {
> > +             vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val);
> > +             return;
> > +     }
> > +
> > +     val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE;
> > +
> > +     if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV)
> > +             val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL;
> > +     else
> > +             val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL;
> > +
> > +     writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG);
> > +}
> > +
> > +static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
> > +{
> > +     vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id),
> > +                 VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK);
> > +
> > +     vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id),
> > +                 cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT);
> > +}
> > +
> > +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> > +
> > +     /* Enforce barrier between line update and commit */
> > +     wmb();
> > +
> > +     writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> > +
> > +     /* Make sure register update is issued before further reg writes */
> > +     wmb();
> > +}
> > +
> > +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> > +                                     enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id);
> > +}
> > +
> > +static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
> > +                                enum vfe_line_id line_id, u8 enable)
> > +{
> > +     u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) |
> > +                   VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
> > +     u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) |
> > +                   VFE_0_IRQ_MASK_1_RDIn_SOF(line_id);
> > +
> > +     if (enable) {
> > +             vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> > +             vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> > +     } else {
> > +             vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> > +             vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> > +     }
> > +}
> > +
> > +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;
> > +     unsigned int i;
> > +     u32 irq_en0;
> > +     u32 irq_en1;
> > +     u32 comp_mask = 0;
> > +
> > +     irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF;
> > +     irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF;
> > +     irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(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;
> > +     }
> > +
> > +     if (enable) {
> > +             vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> > +             vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> > +             vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> > +     } else {
> > +             vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> > +             vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> > +             vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> > +     }
> > +}
> > +
> > +static void vfe_enable_irq_common(struct vfe_device *vfe)
> > +{
> > +     u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK;
> > +     u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION |
> > +                   VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK;
> > +
> > +     vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> > +     vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> > +}
> > +
> > +static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
> > +{
> > +     u32 val, even_cfg, odd_cfg;
> > +
> > +     writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG);
> > +
> > +     val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD;
> > +     writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0);
> > +
> > +     val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2;
> > +     writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1);
> > +
> > +     switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> > +     case MEDIA_BUS_FMT_YUYV8_2X8:
> > +             even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV;
> > +             odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV;
> > +             break;
> > +     case MEDIA_BUS_FMT_YVYU8_2X8:
> > +             even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU;
> > +             odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU;
> > +             break;
> > +     case MEDIA_BUS_FMT_UYVY8_2X8:
> > +     default:
> > +             even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY;
> > +             odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY;
> > +             break;
> > +     case MEDIA_BUS_FMT_VYUY8_2X8:
> > +             even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY;
> > +             odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY;
> > +             break;
> > +     }
> > +
> > +     writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG);
> > +     writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
> > +}
> > +
> > +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 reg;
> > +     u16 input, output;
> > +     u8 interp_reso;
> > +     u32 phase_mult;
> > +
> > +     writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG);
> > +
> > +     input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> > +     output = line->compose.width - 1;
> > +     reg = (output << 16) | input;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE);
> > +
> > +     interp_reso = vfe_calc_interp_reso(input, output);
> > +     phase_mult = input * (1 << (14 + interp_reso)) / output;
> > +     reg = (interp_reso << 28) | phase_mult;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE);
> > +
> > +     input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> > +     output = line->compose.height - 1;
> > +     reg = (output << 16) | input;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE);
> > +
> > +     interp_reso = vfe_calc_interp_reso(input, output);
> > +     phase_mult = input * (1 << (14 + interp_reso)) / output;
> > +     reg = (interp_reso << 28) | phase_mult;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE);
> > +
> > +     writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG);
> > +
> > +     input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> > +     output = line->compose.width / 2 - 1;
> > +     reg = (output << 16) | input;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE);
> > +
> > +     interp_reso = vfe_calc_interp_reso(input, output);
> > +     phase_mult = input * (1 << (14 + interp_reso)) / output;
> > +     reg = (interp_reso << 28) | phase_mult;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE);
> > +
> > +     input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> > +     output = line->compose.height - 1;
> > +     if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21)
> > +             output = line->compose.height / 2 - 1;
> > +     reg = (output << 16) | input;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE);
> > +
> > +     interp_reso = vfe_calc_interp_reso(input, output);
> > +     phase_mult = input * (1 << (14 + interp_reso)) / output;
> > +     reg = (interp_reso << 28) | phase_mult;
> > +     writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE);
> > +}
> > +
> > +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 reg;
> > +     u16 first, last;
> > +
> > +     first = line->crop.left;
> > +     last = line->crop.left + line->crop.width - 1;
> > +     reg = (first << 16) | last;
> > +     writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH);
> > +
> > +     first = line->crop.top;
> > +     last = line->crop.top + line->crop.height - 1;
> > +     reg = (first << 16) | last;
> > +     writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT);
> > +
> > +     first = line->crop.left / 2;
> > +     last = line->crop.left / 2 + line->crop.width / 2 - 1;
> > +     reg = (first << 16) | last;
> > +     writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH);
> > +
> > +     first = line->crop.top;
> > +     last = line->crop.top + line->crop.height - 1;
> > +     if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) {
> > +             first = line->crop.top / 2;
> > +             last = line->crop.top / 2 + line->crop.height / 2 - 1;
> > +     }
> > +     reg = (first << 16) | last;
> > +     writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT);
> > +}
> > +
> > +static void vfe_set_clamp_cfg(struct vfe_device *vfe)
> > +{
> > +     u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 |
> > +             VFE_0_CLAMP_ENC_MAX_CFG_CH1 |
> > +             VFE_0_CLAMP_ENC_MAX_CFG_CH2;
> > +
> > +     writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG);
> > +
> > +     val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 |
> > +             VFE_0_CLAMP_ENC_MIN_CFG_CH1 |
> > +             VFE_0_CLAMP_ENC_MIN_CFG_CH2;
> > +
> > +     writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
> > +}
> > +
> > +static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable)
> > +{
> > +     /* empty */
> > +}
> > +
> > +static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line)
> > +{
> > +     u32 val;
> > +
> > +     switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> > +     case MEDIA_BUS_FMT_YUYV8_2X8:
> > +             val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR;
> > +             break;
> > +     case MEDIA_BUS_FMT_YVYU8_2X8:
> > +             val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB;
> > +             break;
> > +     case MEDIA_BUS_FMT_UYVY8_2X8:
> > +     default:
> > +             val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY;
> > +             break;
> > +     case MEDIA_BUS_FMT_VYUY8_2X8:
> > +             val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY;
> > +             break;
> > +     }
> > +
> > +     val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN;
> > +     writel_relaxed(val, vfe->base + VFE_0_CORE_CFG);
> > +
> > +     val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> > +     val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG);
> > +
> > +     val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG);
> > +
> > +     val = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG);
> > +
> > +     val = 0xffffffff;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG);
> > +
> > +     val = 0xffffffff;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN);
> > +
> > +     val = 0xffffffff;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN);
> > +
> > +     val = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> > +     vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val);
> > +
> > +     val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN;
> > +     writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG);
> > +}
> > +
> > +static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
> > +{
> > +     u32 cmd;
> > +
> > +     cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
> > +     writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> > +
> > +     /* Make sure camif command is issued written before it is changed again */
> > +     wmb();
> > +
> > +     if (enable)
> > +             cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY;
> > +     else
> > +             cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY;
> > +
> > +     writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> > +}
> > +
> > +static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable)
> > +{
> > +     u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX |
> > +                    VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE;
> > +     u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC |
> > +                    VFE_0_MODULE_ZOOM_EN_CROP_ENC;
> > +
> > +     if (enable) {
> > +             vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> > +             vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> > +     } else {
> > +             vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> > +             vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> > +     }
> > +}
> > +
> > +static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
> > +{
> > +     u32 val;
> > +     int ret;
> > +
> > +     ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS,
> > +                              val,
> > +                              (val & VFE_0_CAMIF_STATUS_HALT),
> > +                              CAMIF_TIMEOUT_SLEEP_US,
> > +                              CAMIF_TIMEOUT_ALL_US);
> > +     if (ret < 0)
> > +             dev_err(dev, "%s: camif stop timeout\n", __func__);
> > +
> > +     return ret;
> > +}
> > +
> > +
> > +
> > +/*
> > + * vfe_isr - VFE module interrupt handler
> > + * @irq: Interrupt line
> > + * @dev: VFE device
> > + *
> > + * Return IRQ_HANDLED on success
> > + */
> > +static irqreturn_t vfe_isr(int irq, void *dev)
> > +{
> > +     struct vfe_device *vfe = dev;
> > +     u32 value0, value1;
> > +     int i, j;
> > +
> > +     vfe->ops->isr_read(vfe, &value0, &value1);
> > +
> > +     trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n",
> > +                  value0, value1);
> > +
> > +     if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK)
> > +             vfe->isr_ops.reset_ack(vfe);
> > +
> > +     if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
> > +             vfe->ops->violation_read(vfe);
> > +
> > +     if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
> > +             vfe->isr_ops.halt_ack(vfe);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> > +             if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
> > +                     vfe->isr_ops.reg_update(vfe, i);
> > +
> > +     if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF)
> > +             vfe->isr_ops.sof(vfe, VFE_LINE_PIX);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> > +             if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i))
> > +                     vfe->isr_ops.sof(vfe, i);
> > +
> > +     for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> > +             if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) {
> > +                     vfe->isr_ops.comp_done(vfe, i);
> > +                     for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++)
> > +                             if (vfe->wm_output_map[j] == VFE_LINE_PIX)
> > +                                     value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j);
> > +             }
> > +
> > +     for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++)
> > +             if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i))
> > +                     vfe->isr_ops.wm_done(vfe, i);
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +static u16 vfe_get_ub_size(u8 vfe_id)
> > +{
> > +     /* On VFE4.8 the ub-size is the same on both instances */
> > +     return MSM_VFE_VFE0_UB_SIZE_RDI;
> > +}
> > +
> > +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> > +{
> > +     if (enable)
> > +             writel_relaxed(2 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> > +                            vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> > +     else
> > +             writel_relaxed(1 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> > +                            vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> > +
> > +     /* The WM must be enabled before sending other commands */
> > +     wmb();
> > +}
> > +
> > +static void vfe_set_qos(struct vfe_device *vfe)
> > +{
> > +     u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
> > +     u32 val3 = VFE_0_BUS_BDG_QOS_CFG_3_CFG;
> > +     u32 val4 = VFE_0_BUS_BDG_QOS_CFG_4_CFG;
> > +     u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> > +
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> > +     writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> > +     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> > +     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> > +     writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> > +     writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> > +}
> > +
> > +static void vfe_set_ds(struct vfe_device *vfe)
> > +{
> > +     u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
> > +     u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> > +
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> > +     writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> > +     writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> > +}
> > +
> > +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> > +{
> > +     *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> > +     *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
> > +
> > +     writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> > +     writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> > +
> > +     /* Enforce barrier between local & global IRQ clear */
> > +     wmb();
> > +     writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> > +}
> > +
> > +static void vfe_violation_read(struct vfe_device *vfe)
> > +{
> > +     u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> > +
> > +     pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> > +}
> > +
> > +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_8 = {
> > +     .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> > +     .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> > +     .bus_enable_wr_if = vfe_bus_enable_wr_if,
> > +     .bus_reload_wm = vfe_bus_reload_wm,
> > +     .camif_wait_for_stop = vfe_camif_wait_for_stop,
> > +     .enable_irq_common = vfe_enable_irq_common,
> > +     .enable_irq_pix_line = vfe_enable_irq_pix_line,
> > +     .enable_irq_wm_line = vfe_enable_irq_wm_line,
> > +     .get_ub_size = vfe_get_ub_size,
> > +     .halt_clear = vfe_halt_clear,
> > +     .halt_request = vfe_halt_request,
> > +     .set_camif_cfg = vfe_set_camif_cfg,
> > +     .set_camif_cmd = vfe_set_camif_cmd,
> > +     .set_cgc_override = vfe_set_cgc_override,
> > +     .set_clamp_cfg = vfe_set_clamp_cfg,
> > +     .set_crop_cfg = vfe_set_crop_cfg,
> > +     .set_demux_cfg = vfe_set_demux_cfg,
> > +     .set_ds = vfe_set_ds,
> > +     .set_module_cfg = vfe_set_module_cfg,
> > +     .set_qos = vfe_set_qos,
> > +     .set_rdi_cid = vfe_set_rdi_cid,
> > +     .set_realign_cfg = vfe_set_realign_cfg,
> > +     .set_scale_cfg = vfe_set_scale_cfg,
> > +     .set_xbar_cfg = vfe_set_xbar_cfg,
> > +     .wm_enable = vfe_wm_enable,
> > +     .wm_frame_based = vfe_wm_frame_based,
> > +     .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> > +     .wm_line_based = vfe_wm_line_based,
> > +     .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> > +     .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> > +     .wm_set_ping_addr = vfe_wm_set_ping_addr,
> > +     .wm_set_pong_addr = vfe_wm_set_pong_addr,
> > +     .wm_set_subsample = vfe_wm_set_subsample,
> > +     .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> > +};
> > +
> > +static void vfe_subdev_init(struct vfe_device *vfe)
> > +{
> > +     vfe->isr_ops = vfe_isr_ops_gen1;
> > +     vfe->ops_gen1 = &vfe_ops_gen1_4_8;
> > +     vfe->video_ops = vfe_video_ops_gen1;
> > +}
> > +
> > +const struct vfe_hw_ops vfe_ops_4_8 = {
> > +     .global_reset = vfe_global_reset,
> > +     .hw_version_read = vfe_hw_version_read,
> > +     .isr_read = vfe_isr_read,
> > +     .isr = vfe_isr,
> > +     .reg_update_clear = vfe_reg_update_clear,
> > +     .reg_update = vfe_reg_update,
> > +     .subdev_init = vfe_subdev_init,
> > +     .vfe_disable = vfe_gen1_disable,
> > +     .vfe_enable = vfe_gen1_enable,
> > +     .vfe_halt = vfe_gen1_halt,
> > +     .violation_read = vfe_violation_read,
> > +};
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> > new file mode 100644
> > index 000000000000..ffc543685081
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> > @@ -0,0 +1,760 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * camss-vfe-gen1.c
> > + *
> > + * Qualcomm MSM Camera Subsystem - VFE Common functionality for Gen 1 versions of hw (4.1, 4.7..)
> > + *
> > + * Copyright (C) 2020 Linaro Ltd.
> > + */
> > +
> > +
> > +#include "camss.h"
> > +#include "camss-vfe.h"
> > +#include "camss-vfe-gen1.h"
> > +
> > +/* Max number of frame drop updates per frame */
> > +#define VFE_FRAME_DROP_UPDATES 2
> > +#define VFE_NEXT_SOF_MS 500
> > +
> > +
> > +int vfe_gen1_halt(struct vfe_device *vfe)
> > +{
> > +     unsigned long time;
> > +
> > +     return 0;
> > +
> > +     reinit_completion(&vfe->halt_complete);
> > +
> > +     vfe->ops_gen1->halt_request(vfe);
> > +
> > +     time = wait_for_completion_timeout(&vfe->halt_complete,
> > +                                        msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> > +     if (!time) {
> > +             dev_err(vfe->camss->dev, "VFE halt timeout\n");
> > +             return -EIO;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int vfe_disable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     const struct vfe_hw_ops *ops = vfe->ops;
> > +     unsigned long flags;
> > +     unsigned long time;
> > +     unsigned int i;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     output->gen1.wait_sof = 1;
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     time = wait_for_completion_timeout(&output->sof, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> > +     if (!time)
> > +             dev_err(vfe->camss->dev, "VFE sof timeout\n");
> > +
> > +     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);
> > +
> > +     ops->reg_update(vfe, line->id);
> > +     output->wait_reg_update = 1;
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     time = wait_for_completion_timeout(&output->reg_update, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> > +     if (!time)
> > +             dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> > +
> > +     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);
> > +             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->enable_irq_pix_line(vfe, 0, line->id, 0);
> > +             vfe->ops_gen1->set_module_cfg(vfe, 0);
> > +             vfe->ops_gen1->set_realign_cfg(vfe, line, 0);
> > +             vfe->ops_gen1->set_xbar_cfg(vfe, output, 0);
> > +             vfe->ops_gen1->set_camif_cmd(vfe, 0);
> > +
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +             vfe->ops_gen1->camif_wait_for_stop(vfe, vfe->camss->dev);
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * vfe_gen1_disable - Disable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +int vfe_gen1_disable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +
> > +     vfe_disable_output(line);
> > +
> > +     vfe_put_output(line);
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     if (vfe->stream_count == 1)
> > +             vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return 0;
> > +}
> > +
> > +static void vfe_output_init_addrs(struct vfe_device *vfe,
> > +                               struct vfe_output *output, u8 sync,
> > +                               struct vfe_line *line)
> > +{
> > +     u32 ping_addr;
> > +     u32 pong_addr;
> > +     unsigned int i;
> > +
> > +     output->gen1.active_buf = 0;
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             if (output->buf[0])
> > +                     ping_addr = output->buf[0]->addr[i];
> > +             else
> > +                     ping_addr = 0;
> > +
> > +             if (output->buf[1])
> > +                     pong_addr = output->buf[1]->addr[i];
> > +             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);
> > +             if (sync)
> > +                     vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> > +     }
> > +}
> > +
> > +static void vfe_output_frame_drop(struct vfe_device *vfe,
> > +                               struct vfe_output *output,
> > +                               u32 drop_pattern)
> > +{
> > +     u8 drop_period;
> > +     unsigned int i;
> > +
> > +     /* We need to toggle update period to be valid on next frame */
> > +     output->drop_update_idx++;
> > +     output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> > +     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->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
> > +}
> > +
> > +static int vfe_enable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     const struct vfe_hw_ops *ops = vfe->ops;
> > +     struct media_entity *sensor;
> > +     unsigned long flags;
> > +     unsigned int frame_skip = 0;
> > +     unsigned int i;
> > +     u16 ub_size;
> > +
> > +     ub_size = vfe->ops_gen1->get_ub_size(vfe->id);
> > +     if (!ub_size)
> > +             return -EINVAL;
> > +
> > +     sensor = camss_find_sensor(&line->subdev.entity);
> > +     if (sensor) {
> > +             struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor);
> > +
> > +             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;
> > +     }
> > +     output->state = VFE_OUTPUT_IDLE;
> > +
> > +     output->buf[0] = vfe_buf_get_pending(output);
> > +     output->buf[1] = vfe_buf_get_pending(output);
> > +
> > +     if (!output->buf[0] && output->buf[1]) {
> > +             output->buf[0] = output->buf[1];
> > +             output->buf[1] = NULL;
> > +     }
> > +
> > +     if (output->buf[0])
> > +             output->state = VFE_OUTPUT_SINGLE;
> > +
> > +     if (output->buf[1])
> > +             output->state = VFE_OUTPUT_CONTINUOUS;
> > +
> > +     switch (output->state) {
> > +     case VFE_OUTPUT_SINGLE:
> > +             vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> > +             break;
> > +     case VFE_OUTPUT_CONTINUOUS:
> > +             vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> > +             break;
> > +     default:
> > +             vfe_output_frame_drop(vfe, output, 0);
> > +             break;
> > +     }
> > +
> > +     output->sequence = 0;
> > +     output->gen1.wait_sof = 0;
> > +     output->wait_reg_update = 0;
> > +     reinit_completion(&output->sof);
> > +     reinit_completion(&output->reg_update);
> > +
> > +     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_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]);
> > +     } 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],
> > +                                                  &line->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->enable_irq_pix_line(vfe, 0, line->id, 1);
> > +             vfe->ops_gen1->set_module_cfg(vfe, 1);
> > +             vfe->ops_gen1->set_camif_cfg(vfe, line);
> > +             vfe->ops_gen1->set_realign_cfg(vfe, line, 1);
> > +             vfe->ops_gen1->set_xbar_cfg(vfe, output, 1);
> > +             vfe->ops_gen1->set_demux_cfg(vfe, line);
> > +             vfe->ops_gen1->set_scale_cfg(vfe, line);
> > +             vfe->ops_gen1->set_crop_cfg(vfe, line);
> > +             vfe->ops_gen1->set_clamp_cfg(vfe);
> > +             vfe->ops_gen1->set_camif_cmd(vfe, 1);
> > +     }
> > +
> > +     ops->reg_update(vfe, line->id);
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +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;
> > +     unsigned long flags;
> > +     int i;
> > +     int wm_idx;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     output = &line->output;
> > +     if (output->state != VFE_OUTPUT_OFF) {
> > +             dev_err(vfe->camss->dev, "Output is running\n");
> > +             goto error;
> > +     }
> > +     output->state = VFE_OUTPUT_RESERVED;
> > +
> > +     output->gen1.active_buf = 0;
> > +
> > +     switch (f->fmt.pix_mp.pixelformat) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             output->wm_num = 2;
> > +             break;
> > +     default:
> > +             output->wm_num = 1;
> > +             break;
> > +     }
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             wm_idx = vfe_reserve_wm(vfe, line->id);
> > +             if (wm_idx < 0) {
> > +                     dev_err(vfe->camss->dev, "Can not reserve wm\n");
> > +                     goto error_get_wm;
> > +             }
> > +             output->wm_idx[i] = wm_idx;
> > +     }
> > +
> > +     output->drop_update_idx = 0;
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +
> > +error_get_wm:
> > +     for (i--; i >= 0; i--)
> > +             vfe_release_wm(vfe, output->wm_idx[i]);
> > +     output->state = VFE_OUTPUT_OFF;
> > +error:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return -EINVAL;
> > +}
> > +
> > +int vfe_gen1_enable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     int ret;
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     if (!vfe->stream_count) {
> > +             vfe->ops_gen1->enable_irq_common(vfe);
> > +             vfe->ops_gen1->bus_enable_wr_if(vfe, 1);
> > +             vfe->ops_gen1->set_qos(vfe);
> > +             vfe->ops_gen1->set_ds(vfe);
> > +     }
> > +
> > +     vfe->stream_count++;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     ret = vfe_get_output(line);
> > +     if (ret < 0)
> > +             goto error_get_output;
> > +
> > +     ret = vfe_enable_output(line);
> > +     if (ret < 0)
> > +             goto error_enable_output;
> > +
> > +     vfe->was_streaming = 1;
> > +
> > +     return 0;
> > +
> > +
> > +error_enable_output:
> > +     vfe_put_output(line);
> > +
> > +error_get_output:
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     if (vfe->stream_count == 1)
> > +             vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return ret;
> > +}
> > +
> > +static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> > +                                     struct vfe_output *output, u8 sync,
> > +                                     struct vfe_line *line)
> > +{
> > +     u32 addr;
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             if (output->buf[0])
> > +                     addr = output->buf[0]->addr[i];
> > +             else
> > +                     addr = 0;
> > +
> > +             vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> > +             if (sync)
> > +                     vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> > +     }
> > +}
> > +
> > +static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> > +                                     struct vfe_output *output, u8 sync,
> > +                                     struct vfe_line *line)
> > +{
> > +     u32 addr;
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             if (output->buf[1])
> > +                     addr = output->buf[1]->addr[i];
> > +             else
> > +                     addr = 0;
> > +
> > +             // XXX
> > +     }
> > +
> > +}
> > +
> > +static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> > +                                   struct vfe_output *output)
> > +{
> > +     switch (output->state) {
> > +     case VFE_OUTPUT_CONTINUOUS:
> > +             vfe_output_frame_drop(vfe, output, 3);
> > +             break;
> > +     case VFE_OUTPUT_SINGLE:
> > +     default:
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Next buf in wrong state! %d\n",
> > +                                 output->state);
> > +             break;
> > +     }
> > +}
> > +
> > +static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> > +                                   struct vfe_output *output)
> > +{
> > +     switch (output->state) {
> > +     case VFE_OUTPUT_CONTINUOUS:
> > +             output->state = VFE_OUTPUT_SINGLE;
> > +             vfe_output_frame_drop(vfe, output, 1);
> > +             break;
> > +     case VFE_OUTPUT_SINGLE:
> > +             output->state = VFE_OUTPUT_STOPPING;
> > +             vfe_output_frame_drop(vfe, output, 0);
> > +             break;
> > +     default:
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Last buff in wrong state! %d\n",
> > +                                 output->state);
> > +             break;
> > +     }
> > +}
> > +
> > +static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> > +                                  struct vfe_output *output,
> > +                                  struct camss_buffer *new_buf,
> > +                                  struct vfe_line *line)
> > +{
> > +     int inactive_idx;
> > +
> > +     switch (output->state) {
> > +     case VFE_OUTPUT_SINGLE:
> > +             inactive_idx = !output->gen1.active_buf;
> > +
> > +             if (!output->buf[inactive_idx]) {
> > +                     output->buf[inactive_idx] = new_buf;
> > +
> > +                     if (inactive_idx)
> > +                             vfe_output_update_pong_addr(vfe, output, 0, line);
> > +                     else
> > +                             vfe_output_update_ping_addr(vfe, output, 0, line);
> > +
> > +                     vfe_output_frame_drop(vfe, output, 3);
> > +                     output->state = VFE_OUTPUT_CONTINUOUS;
> > +             } else {
> > +                     vfe_buf_add_pending(output, new_buf);
> > +                     dev_err_ratelimited(vfe->camss->dev,
> > +                                         "Inactive buffer is busy\n");
> > +             }
> > +             break;
> > +
> > +     case VFE_OUTPUT_IDLE:
> > +             if (!output->buf[0]) {
> > +                     output->buf[0] = new_buf;
> > +
> > +                     vfe_output_init_addrs(vfe, output, 1, line);
> > +                     vfe_output_frame_drop(vfe, output, 1);
> > +
> > +                     output->state = VFE_OUTPUT_SINGLE;
> > +             } else {
> > +                     vfe_buf_add_pending(output, new_buf);
> > +                     dev_err_ratelimited(vfe->camss->dev,
> > +                                         "Output idle with buffer set!\n");
> > +             }
> > +             break;
> > +
> > +     case VFE_OUTPUT_CONTINUOUS:
> > +     default:
> > +             vfe_buf_add_pending(output, new_buf);
> > +             break;
> > +     }
> > +}
> > +
> > +/*
> > + * vfe_isr_halt_ack - Process start of frame interrupt
> > + * @vfe: VFE Device
> > + */
> > +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> > +{
> > +     complete(&vfe->halt_complete);
> > +     vfe->ops_gen1->halt_clear(vfe);
> > +}
> > +
> > +/*
> > + * vfe_isr_sof - Process start of frame interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     output = &vfe->line[line_id].output;
> > +     if (output->gen1.wait_sof) {
> > +             output->gen1.wait_sof = 0;
> > +             complete(&output->sof);
> > +     }
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_isr_reg_update - Process reg update interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     struct vfe_output *output;
> > +     struct vfe_line *line = &vfe->line[line_id];
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     vfe->ops->reg_update_clear(vfe, line_id);
> > +
> > +     output = &line->output;
> > +
> > +     if (output->wait_reg_update) {
> > +             output->wait_reg_update = 0;
> > +             complete(&output->reg_update);
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +             return;
> > +     }
> > +
> > +     if (output->state == VFE_OUTPUT_STOPPING) {
> > +             /* Release last buffer when hw is idle */
> > +             if (output->last_buffer) {
> > +                     vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> > +                                     VB2_BUF_STATE_DONE);
> > +                     output->last_buffer = NULL;
> > +             }
> > +             output->state = VFE_OUTPUT_IDLE;
> > +
> > +             /* Buffers received in stopping state are queued in */
> > +             /* dma pending queue, start next capture here */
> > +
> > +             output->buf[0] = vfe_buf_get_pending(output);
> > +             output->buf[1] = vfe_buf_get_pending(output);
> > +
> > +             if (!output->buf[0] && output->buf[1]) {
> > +                     output->buf[0] = output->buf[1];
> > +                     output->buf[1] = NULL;
> > +             }
> > +
> > +             if (output->buf[0])
> > +                     output->state = VFE_OUTPUT_SINGLE;
> > +
> > +             if (output->buf[1])
> > +                     output->state = VFE_OUTPUT_CONTINUOUS;
> > +
> > +             switch (output->state) {
> > +             case VFE_OUTPUT_SINGLE:
> > +                     vfe_output_frame_drop(vfe, output, 2);
> > +                     break;
> > +             case VFE_OUTPUT_CONTINUOUS:
> > +                     vfe_output_frame_drop(vfe, output, 3);
> > +                     break;
> > +             default:
> > +                     vfe_output_frame_drop(vfe, output, 0);
> > +                     break;
> > +             }
> > +
> > +             vfe_output_init_addrs(vfe, output, 1, &vfe->line[line_id]);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_isr_wm_done - Process write master done interrupt
> > + * @vfe: VFE Device
> > + * @wm: Write master id
> > + */
> > +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> > +{
> > +     struct camss_buffer *ready_buf;
> > +     struct vfe_output *output;
> > +     dma_addr_t *new_addr;
> > +     unsigned long flags;
> > +     u32 active_index;
> > +     u64 ts = ktime_get_ns();
> > +     unsigned int i;
> > +
> > +     active_index = vfe->ops_gen1->wm_get_ping_pong_status(vfe, wm);
> > +
> > +     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;
> > +
> > +     if (output->gen1.active_buf == active_index && 0) {
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Active buffer mismatch!\n");
> > +             goto out_unlock;
> > +     }
> > +     output->gen1.active_buf = active_index;
> > +
> > +     ready_buf = output->buf[!active_index];
> > +     if (!ready_buf) {
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Missing ready buf %d %d!\n",
> > +                                 !active_index, output->state);
> > +             goto out_unlock;
> > +     }
> > +
> > +     ready_buf->vb.vb2_buf.timestamp = ts;
> > +     ready_buf->vb.sequence = output->sequence++;
> > +
> > +     /* Get next buffer */
> > +     output->buf[!active_index] = vfe_buf_get_pending(output);
> > +     if (!output->buf[!active_index]) {
> > +             /* No next buffer - set same address */
> > +             new_addr = ready_buf->addr;
> > +             vfe_buf_update_wm_on_last(vfe, output);
> > +     } else {
> > +             new_addr = output->buf[!active_index]->addr;
> > +             vfe_buf_update_wm_on_next(vfe, output);
> > +     }
> > +
> > +     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]);
> > +     else
> > +             for (i = 0; i < output->wm_num; i++)
> > +                     vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]);
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     if (output->state == VFE_OUTPUT_STOPPING)
> > +             output->last_buffer = ready_buf;
> > +     else
> > +             vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +
> > +     return;
> > +
> > +out_unlock:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_queue_buffer - Add empty buffer
> > + * @vid: Video device structure
> > + * @buf: Buffer to be enqueued
> > + *
> > + * Add an empty buffer - depending on the current number of buffers it will be
> > + * put in pending buffer queue or directly given to the hardware to be filled.
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +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_device *vfe = to_vfe(line);
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     output = &line->output;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     vfe_buf_update_wm_on_new(vfe, output, buf, line);
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> > +{
> > +     if (input / output >= 16)
> > +             return 0;
> > +
> > +     if (input / output >= 8)
> > +             return 1;
> > +
> > +     if (input / output >= 4)
> > +             return 2;
> > +
> > +     return 3;
> > +}
> > +
> > +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> > +
> > +int vfe_word_per_line(u32 format, u32 width)
> > +{
> > +     int val = 0;
> > +
> > +     switch (format) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             val = CALC_WORD(width, 1, 8);
> > +             break;
> > +     case V4L2_PIX_FMT_YUYV:
> > +     case V4L2_PIX_FMT_YVYU:
> > +     case V4L2_PIX_FMT_UYVY:
> > +     case V4L2_PIX_FMT_VYUY:
> > +             val = CALC_WORD(width, 2, 8);
> > +             break;
> > +     }
> > +
> > +     return val;
> > +}
> > +
> > +const struct vfe_isr_ops vfe_isr_ops_gen1 = {
> > +     .reset_ack = vfe_isr_reset_ack,
> > +     .halt_ack = vfe_isr_halt_ack,
> > +     .reg_update = vfe_isr_reg_update,
> > +     .sof = vfe_isr_sof,
> > +     .comp_done = vfe_isr_comp_done,
> > +     .wm_done = vfe_isr_wm_done,
> > +};
> > +
> > +const struct camss_video_ops vfe_video_ops_gen1 = {
> > +     .queue_buffer = vfe_queue_buffer,
> > +     .flush_buffers = vfe_flush_buffers,
> > +};
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.h b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> > new file mode 100644
> > index 000000000000..42e8a3333034
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> > @@ -0,0 +1,110 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * camss-vfe.h
> > + *
> > + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module
> > + *
> > + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> > + * Copyright (C) 2015-2018 Linaro Ltd.
> > + */
> > +#ifndef QC_MSM_CAMSS_VFE_GEN1_H
> > +#define QC_MSM_CAMSS_VFE_GEN1_H
> > +
> > +
> > +#include "camss-vfe.h"
> > +
> > +
> > +enum vfe_line_id;
> > +struct vfe_device;
> > +struct vfe_line;
> > +struct vfe_output;
> > +
> > +struct vfe_hw_ops_gen1 {
> > +     void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> > +     void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> > +     void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> > +     void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> > +     int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> > +     void (*enable_irq_common)(struct vfe_device *vfe);
> > +     void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, enum vfe_line_id line_id,
> > +                                u8 enable);
> > +     void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, enum vfe_line_id line_id,
> > +                                 u8 enable);
> > +     u16 (*get_ub_size)(u8 vfe_id);
> > +     void (*halt_clear)(struct vfe_device *vfe);
> > +     void (*halt_request)(struct vfe_device *vfe);
> > +     void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > +     void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> > +     void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> > +     void (*set_clamp_cfg)(struct vfe_device *vfe);
> > +     void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > +     void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > +     void (*set_ds)(struct vfe_device *vfe);
> > +     void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> > +     void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > +     void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid);
> > +     void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, u8 enable);
> > +     void (*set_qos)(struct vfe_device *vfe);
> > +     void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, u8 enable);
> > +     void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> > +     void (*wm_line_based)(struct vfe_device *vfe, u32 wm, struct v4l2_pix_format_mplane *pix,
> > +                           u8 plane, u32 enable);
> > +     void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, u16 depth);
> > +     void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> > +     void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> > +     void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, u32 pattern);
> > +     void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> > +     void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> > +     int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> > +     void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> > +};
> > +
> > +/*
> > + * vfe_calc_interp_reso - Calculate interpolation mode
> > + * @input: Input resolution
> > + * @output: Output resolution
> > + *
> > + * Return interpolation mode
> > + */
> > +inline u8 vfe_calc_interp_reso(u16 input, u16 output);
> > +
> > +/*
> > + * vfe_gen1_disable - Disable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +int vfe_gen1_disable(struct vfe_line *line);
> > +
> > +
> > +/*
> > + * vfe_gen1_enable - Enable VFE module
> > + * @line: VFE line
> > + *
> > + * Return 0 on success
> > + */
> > +int vfe_gen1_enable(struct vfe_line *line);
> > +
> > +/*
> > + * vfe_gen1_enable - Halt VFE module
> > + * @vfe: VFE device
> > + *
> > + * Return 0 on success
> > + */
> > +int vfe_gen1_halt(struct vfe_device *vfe);
> > +
> > +/*
> > + * vfe_word_per_line - Calculate number of words per frame width
> > + * @format: V4L2 format
> > + * @width: Frame width
> > + *
> > + * Return number of words per frame width
> > + */
> > +int vfe_word_per_line(u32 format, u32 width);
> > +
> > +
> > +extern const struct vfe_isr_ops vfe_isr_ops_gen1;
> > +extern const struct camss_video_ops vfe_video_ops_gen1;
> > +
> > +
> > +#endif /* QC_MSM_CAMSS_VFE_GEN1_H */
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> > index 478be4f0cab5..2ffa5b3c5426 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> > @@ -26,22 +26,8 @@
> >
> >   #define MSM_VFE_NAME "msm_vfe"
> >
> > -#define vfe_line_array(ptr_line)     \
> > -     ((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> > -
> > -#define to_vfe(ptr_line)     \
> > -     container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> > -
> >   /* VFE reset timeout */
> >   #define VFE_RESET_TIMEOUT_MS 50
> > -/* VFE halt timeout */
> > -#define VFE_HALT_TIMEOUT_MS 100
> > -/* Max number of frame drop updates per frame */
> > -#define VFE_FRAME_DROP_UPDATES 2
> > -/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> > -#define VFE_FRAME_DROP_VAL 30
> > -
> > -#define VFE_NEXT_SOF_MS 500
> >
> >   #define SCALER_RATIO_MAX 16
> >
> > @@ -294,30 +280,6 @@ static int vfe_reset(struct vfe_device *vfe)
> >       return 0;
> >   }
> >
> > -/*
> > - * vfe_halt - Trigger halt on VFE module and wait to complete
> > - * @vfe: VFE device
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -static int vfe_halt(struct vfe_device *vfe)
> > -{
> > -     unsigned long time;
> > -
> > -     reinit_completion(&vfe->halt_complete);
> > -
> > -     vfe->ops->halt_request(vfe);
> > -
> > -     time = wait_for_completion_timeout(&vfe->halt_complete,
> > -             msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> > -     if (!time) {
> > -             dev_err(vfe->camss->dev, "VFE halt timeout\n");
> > -             return -EIO;
> > -     }
> > -
> > -     return 0;
> > -}
> > -
> >   static void vfe_init_outputs(struct vfe_device *vfe)
> >   {
> >       int i;
> > @@ -340,71 +302,7 @@ static void vfe_reset_output_maps(struct vfe_device *vfe)
> >               vfe->wm_output_map[i] = VFE_LINE_NONE;
> >   }
> >
> > -static void vfe_output_init_addrs(struct vfe_device *vfe,
> > -                               struct vfe_output *output, u8 sync)
> > -{
> > -     u32 ping_addr;
> > -     u32 pong_addr;
> > -     unsigned int i;
> > -
> > -     output->active_buf = 0;
> > -
> > -     for (i = 0; i < output->wm_num; i++) {
> > -             if (output->buf[0])
> > -                     ping_addr = output->buf[0]->addr[i];
> > -             else
> > -                     ping_addr = 0;
> > -
> > -             if (output->buf[1])
> > -                     pong_addr = output->buf[1]->addr[i];
> > -             else
> > -                     pong_addr = ping_addr;
> > -
> > -             vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
> > -             vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
> > -             if (sync)
> > -                     vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> > -     }
> > -}
> > -
> > -static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> > -                                     struct vfe_output *output, u8 sync)
> > -{
> > -     u32 addr;
> > -     unsigned int i;
> > -
> > -     for (i = 0; i < output->wm_num; i++) {
> > -             if (output->buf[0])
> > -                     addr = output->buf[0]->addr[i];
> > -             else
> > -                     addr = 0;
> > -
> > -             vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> > -             if (sync)
> > -                     vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> > -     }
> > -}
> > -
> > -static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> > -                                     struct vfe_output *output, u8 sync)
> > -{
> > -     u32 addr;
> > -     unsigned int i;
> > -
> > -     for (i = 0; i < output->wm_num; i++) {
> > -             if (output->buf[1])
> > -                     addr = output->buf[1]->addr[i];
> > -             else
> > -                     addr = 0;
> > -
> > -             vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
> > -             if (sync)
> > -                     vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> > -     }
> > -
> > -}
> > -
> > -static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
> >   {
> >       int ret = -EBUSY;
> >       int i;
> > @@ -420,7 +318,7 @@ static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
> >       return ret;
> >   }
> >
> > -static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
> > +int vfe_release_wm(struct vfe_device *vfe, u8 wm)
> >   {
> >       if (wm >= ARRAY_SIZE(vfe->wm_output_map))
> >               return -EINVAL;
> > @@ -430,29 +328,7 @@ static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
> >       return 0;
> >   }
> >
> > -static void vfe_output_frame_drop(struct vfe_device *vfe,
> > -                               struct vfe_output *output,
> > -                               u32 drop_pattern)
> > -{
> > -     u8 drop_period;
> > -     unsigned int i;
> > -
> > -     /* We need to toggle update period to be valid on next frame */
> > -     output->drop_update_idx++;
> > -     output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> > -     drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
> > -
> > -     for (i = 0; i < output->wm_num; i++) {
> > -             vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i],
> > -                                               drop_period);
> > -             vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i],
> > -                                                drop_pattern);
> > -     }
> > -     vfe->ops->reg_update(vfe,
> > -                          container_of(output, struct vfe_line, output)->id);
> > -}
> > -
> > -static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
> > +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
> >   {
> >       struct camss_buffer *buffer = NULL;
> >
> > @@ -466,13 +342,8 @@ static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
> >       return buffer;
> >   }
> >
> > -/*
> > - * vfe_buf_add_pending - Add output buffer to list of pending
> > - * @output: VFE output
> > - * @buffer: Video buffer
> > - */
> > -static void vfe_buf_add_pending(struct vfe_output *output,
> > -                             struct camss_buffer *buffer)
> > +void vfe_buf_add_pending(struct vfe_output *output,
> > +                      struct camss_buffer *buffer)
> >   {
> >       INIT_LIST_HEAD(&buffer->queue);
> >       list_add_tail(&buffer->queue, &output->pending_bufs);
> > @@ -495,149 +366,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output,
> >       }
> >   }
> >
> > -static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> > -                                   struct vfe_output *output)
> > -{
> > -     switch (output->state) {
> > -     case VFE_OUTPUT_CONTINUOUS:
> > -             vfe_output_frame_drop(vfe, output, 3);
> > -             break;
> > -     case VFE_OUTPUT_SINGLE:
> > -     default:
> > -             dev_err_ratelimited(vfe->camss->dev,
> > -                                 "Next buf in wrong state! %d\n",
> > -                                 output->state);
> > -             break;
> > -     }
> > -}
> > -
> > -static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> > -                                   struct vfe_output *output)
> > -{
> > -     switch (output->state) {
> > -     case VFE_OUTPUT_CONTINUOUS:
> > -             output->state = VFE_OUTPUT_SINGLE;
> > -             vfe_output_frame_drop(vfe, output, 1);
> > -             break;
> > -     case VFE_OUTPUT_SINGLE:
> > -             output->state = VFE_OUTPUT_STOPPING;
> > -             vfe_output_frame_drop(vfe, output, 0);
> > -             break;
> > -     default:
> > -             dev_err_ratelimited(vfe->camss->dev,
> > -                                 "Last buff in wrong state! %d\n",
> > -                                 output->state);
> > -             break;
> > -     }
> > -}
> > -
> > -static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> > -                                  struct vfe_output *output,
> > -                                  struct camss_buffer *new_buf)
> > -{
> > -     int inactive_idx;
> > -
> > -     switch (output->state) {
> > -     case VFE_OUTPUT_SINGLE:
> > -             inactive_idx = !output->active_buf;
> > -
> > -             if (!output->buf[inactive_idx]) {
> > -                     output->buf[inactive_idx] = new_buf;
> > -
> > -                     if (inactive_idx)
> > -                             vfe_output_update_pong_addr(vfe, output, 0);
> > -                     else
> > -                             vfe_output_update_ping_addr(vfe, output, 0);
> > -
> > -                     vfe_output_frame_drop(vfe, output, 3);
> > -                     output->state = VFE_OUTPUT_CONTINUOUS;
> > -             } else {
> > -                     vfe_buf_add_pending(output, new_buf);
> > -                     dev_err_ratelimited(vfe->camss->dev,
> > -                                         "Inactive buffer is busy\n");
> > -             }
> > -             break;
> > -
> > -     case VFE_OUTPUT_IDLE:
> > -             if (!output->buf[0]) {
> > -                     output->buf[0] = new_buf;
> > -
> > -                     vfe_output_init_addrs(vfe, output, 1);
> > -
> > -                     vfe_output_frame_drop(vfe, output, 1);
> > -                     output->state = VFE_OUTPUT_SINGLE;
> > -             } else {
> > -                     vfe_buf_add_pending(output, new_buf);
> > -                     dev_err_ratelimited(vfe->camss->dev,
> > -                                         "Output idle with buffer set!\n");
> > -             }
> > -             break;
> > -
> > -     case VFE_OUTPUT_CONTINUOUS:
> > -     default:
> > -             vfe_buf_add_pending(output, new_buf);
> > -             break;
> > -     }
> > -}
> > -
> > -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;
> > -     unsigned long flags;
> > -     int i;
> > -     int wm_idx;
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -
> > -     output = &line->output;
> > -     if (output->state != VFE_OUTPUT_OFF) {
> > -             dev_err(vfe->camss->dev, "Output is running\n");
> > -             goto error;
> > -     }
> > -     output->state = VFE_OUTPUT_RESERVED;
> > -
> > -     output->active_buf = 0;
> > -
> > -     switch (f->fmt.pix_mp.pixelformat) {
> > -     case V4L2_PIX_FMT_NV12:
> > -     case V4L2_PIX_FMT_NV21:
> > -     case V4L2_PIX_FMT_NV16:
> > -     case V4L2_PIX_FMT_NV61:
> > -             output->wm_num = 2;
> > -             break;
> > -     default:
> > -             output->wm_num = 1;
> > -             break;
> > -     }
> > -
> > -     for (i = 0; i < output->wm_num; i++) {
> > -             wm_idx = vfe_reserve_wm(vfe, line->id);
> > -             if (wm_idx < 0) {
> > -                     dev_err(vfe->camss->dev, "Can not reserve wm\n");
> > -                     goto error_get_wm;
> > -             }
> > -             output->wm_idx[i] = wm_idx;
> > -     }
> > -
> > -     output->drop_update_idx = 0;
> > -
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     return 0;
> > -
> > -error_get_wm:
> > -     for (i--; i >= 0; i--)
> > -             vfe_release_wm(vfe, output->wm_idx[i]);
> > -     output->state = VFE_OUTPUT_OFF;
> > -error:
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     return -EINVAL;
> > -}
> > -
> > -static int vfe_put_output(struct vfe_line *line)
> > +int vfe_put_output(struct vfe_line *line)
> >   {
> >       struct vfe_device *vfe = to_vfe(line);
> >       struct vfe_output *output = &line->output;
> > @@ -655,454 +384,27 @@ static int vfe_put_output(struct vfe_line *line)
> >       return 0;
> >   }
> >
> > -static int vfe_enable_output(struct vfe_line *line)
> > -{
> > -     struct vfe_device *vfe = to_vfe(line);
> > -     struct vfe_output *output = &line->output;
> > -     const struct vfe_hw_ops *ops = vfe->ops;
> > -     struct media_entity *sensor;
> > -     unsigned long flags;
> > -     unsigned int frame_skip = 0;
> > -     unsigned int i;
> > -     u16 ub_size;
> > -
> > -     ub_size = ops->get_ub_size(vfe->id);
> > -     if (!ub_size)
> > -             return -EINVAL;
> > -
> > -     sensor = camss_find_sensor(&line->subdev.entity);
> > -     if (sensor) {
> > -             struct v4l2_subdev *subdev =
> > -                                     media_entity_to_v4l2_subdev(sensor);
> > -
> > -             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;
> > -     }
> > -     output->state = VFE_OUTPUT_IDLE;
> > -
> > -     output->buf[0] = vfe_buf_get_pending(output);
> > -     output->buf[1] = vfe_buf_get_pending(output);
> > -
> > -     if (!output->buf[0] && output->buf[1]) {
> > -             output->buf[0] = output->buf[1];
> > -             output->buf[1] = NULL;
> > -     }
> > -
> > -     if (output->buf[0])
> > -             output->state = VFE_OUTPUT_SINGLE;
> > -
> > -     if (output->buf[1])
> > -             output->state = VFE_OUTPUT_CONTINUOUS;
> > -
> > -     switch (output->state) {
> > -     case VFE_OUTPUT_SINGLE:
> > -             vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> > -             break;
> > -     case VFE_OUTPUT_CONTINUOUS:
> > -             vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> > -             break;
> > -     default:
> > -             vfe_output_frame_drop(vfe, output, 0);
> > -             break;
> > -     }
> > -
> > -     output->sequence = 0;
> > -     output->wait_sof = 0;
> > -     output->wait_reg_update = 0;
> > -     reinit_completion(&output->sof);
> > -     reinit_completion(&output->reg_update);
> > -
> > -     vfe_output_init_addrs(vfe, output, 0);
> > -
> > -     if (line->id != VFE_LINE_PIX) {
> > -             ops->set_cgc_override(vfe, output->wm_idx[0], 1);
> > -             ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
> > -             ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
> > -             ops->wm_set_subsample(vfe, output->wm_idx[0]);
> > -             ops->set_rdi_cid(vfe, line->id, 0);
> > -             ops->wm_set_ub_cfg(vfe, output->wm_idx[0],
> > -                                (ub_size + 1) * output->wm_idx[0], ub_size);
> > -             ops->wm_frame_based(vfe, output->wm_idx[0], 1);
> > -             ops->wm_enable(vfe, output->wm_idx[0], 1);
> > -             ops->bus_reload_wm(vfe, output->wm_idx[0]);
> > -     } else {
> > -             ub_size /= output->wm_num;
> > -             for (i = 0; i < output->wm_num; i++) {
> > -                     ops->set_cgc_override(vfe, output->wm_idx[i], 1);
> > -                     ops->wm_set_subsample(vfe, output->wm_idx[i]);
> > -                     ops->wm_set_ub_cfg(vfe, output->wm_idx[i],
> > -                                        (ub_size + 1) * output->wm_idx[i],
> > -                                        ub_size);
> > -                     ops->wm_line_based(vfe, output->wm_idx[i],
> > -                                     &line->video_out.active_fmt.fmt.pix_mp,
> > -                                     i, 1);
> > -                     ops->wm_enable(vfe, output->wm_idx[i], 1);
> > -                     ops->bus_reload_wm(vfe, output->wm_idx[i]);
> > -             }
> > -             ops->enable_irq_pix_line(vfe, 0, line->id, 1);
> > -             ops->set_module_cfg(vfe, 1);
> > -             ops->set_camif_cfg(vfe, line);
> > -             ops->set_realign_cfg(vfe, line, 1);
> > -             ops->set_xbar_cfg(vfe, output, 1);
> > -             ops->set_demux_cfg(vfe, line);
> > -             ops->set_scale_cfg(vfe, line);
> > -             ops->set_crop_cfg(vfe, line);
> > -             ops->set_clamp_cfg(vfe);
> > -             ops->set_camif_cmd(vfe, 1);
> > -     }
> > -
> > -     ops->reg_update(vfe, line->id);
> > -
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     return 0;
> > -}
> > -
> > -static int vfe_disable_output(struct vfe_line *line)
> > -{
> > -     struct vfe_device *vfe = to_vfe(line);
> > -     struct vfe_output *output = &line->output;
> > -     const struct vfe_hw_ops *ops = vfe->ops;
> > -     unsigned long flags;
> > -     unsigned long time;
> > -     unsigned int i;
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -
> > -     output->wait_sof = 1;
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     time = wait_for_completion_timeout(&output->sof,
> > -                                        msecs_to_jiffies(VFE_NEXT_SOF_MS));
> > -     if (!time)
> > -             dev_err(vfe->camss->dev, "VFE sof timeout\n");
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -     for (i = 0; i < output->wm_num; i++)
> > -             ops->wm_enable(vfe, output->wm_idx[i], 0);
> > -
> > -     ops->reg_update(vfe, line->id);
> > -     output->wait_reg_update = 1;
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     time = wait_for_completion_timeout(&output->reg_update,
> > -                                        msecs_to_jiffies(VFE_NEXT_SOF_MS));
> > -     if (!time)
> > -             dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -
> > -     if (line->id != VFE_LINE_PIX) {
> > -             ops->wm_frame_based(vfe, output->wm_idx[0], 0);
> > -             ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0],
> > -                                             line->id);
> > -             ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
> > -             ops->set_cgc_override(vfe, output->wm_idx[0], 0);
> > -             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -     } else {
> > -             for (i = 0; i < output->wm_num; i++) {
> > -                     ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
> > -                     ops->set_cgc_override(vfe, output->wm_idx[i], 0);
> > -             }
> > -
> > -             ops->enable_irq_pix_line(vfe, 0, line->id, 0);
> > -             ops->set_module_cfg(vfe, 0);
> > -             ops->set_realign_cfg(vfe, line, 0);
> > -             ops->set_xbar_cfg(vfe, output, 0);
> > -
> > -             ops->set_camif_cmd(vfe, 0);
> > -             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -             ops->camif_wait_for_stop(vfe, vfe->camss->dev);
> > -     }
> > -
> > -     return 0;
> > -}
> > -
> > -/*
> > - * vfe_enable - Enable streaming on VFE line
> > - * @line: VFE line
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -static int vfe_enable(struct vfe_line *line)
> > -{
> > -     struct vfe_device *vfe = to_vfe(line);
> > -     int ret;
> > -
> > -     mutex_lock(&vfe->stream_lock);
> > -
> > -     if (!vfe->stream_count) {
> > -             vfe->ops->enable_irq_common(vfe);
> > -
> > -             vfe->ops->bus_enable_wr_if(vfe, 1);
> > -
> > -             vfe->ops->set_qos(vfe);
> > -
> > -             vfe->ops->set_ds(vfe);
> > -     }
> > -
> > -     vfe->stream_count++;
> > -
> > -     mutex_unlock(&vfe->stream_lock);
> > -
> > -     ret = vfe_get_output(line);
> > -     if (ret < 0)
> > -             goto error_get_output;
> > -
> > -     ret = vfe_enable_output(line);
> > -     if (ret < 0)
> > -             goto error_enable_output;
> > -
> > -     vfe->was_streaming = 1;
> > -
> > -     return 0;
> > -
> > -
> > -error_enable_output:
> > -     vfe_put_output(line);
> > -
> > -error_get_output:
> > -     mutex_lock(&vfe->stream_lock);
> > -
> > -     if (vfe->stream_count == 1)
> > -             vfe->ops->bus_enable_wr_if(vfe, 0);
> > -
> > -     vfe->stream_count--;
> > -
> > -     mutex_unlock(&vfe->stream_lock);
> > -
> > -     return ret;
> > -}
> > -
> > -/*
> > - * vfe_disable - Disable streaming on VFE line
> > - * @line: VFE line
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -static int vfe_disable(struct vfe_line *line)
> > -{
> > -     struct vfe_device *vfe = to_vfe(line);
> > -
> > -     vfe_disable_output(line);
> > -
> > -     vfe_put_output(line);
> > -
> > -     mutex_lock(&vfe->stream_lock);
> > -
> > -     if (vfe->stream_count == 1)
> > -             vfe->ops->bus_enable_wr_if(vfe, 0);
> > -
> > -     vfe->stream_count--;
> > -
> > -     mutex_unlock(&vfe->stream_lock);
> > -
> > -     return 0;
> > -}
> > -
> > -/*
> > - * vfe_isr_sof - Process start of frame interrupt
> > - * @vfe: VFE Device
> > - * @line_id: VFE line
> > - */
> > -static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> > -{
> > -     struct vfe_output *output;
> > -     unsigned long flags;
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -     output = &vfe->line[line_id].output;
> > -     if (output->wait_sof) {
> > -             output->wait_sof = 0;
> > -             complete(&output->sof);
> > -     }
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -}
> > -
> > -/*
> > - * vfe_isr_reg_update - Process reg update interrupt
> > - * @vfe: VFE Device
> > - * @line_id: VFE line
> > - */
> > -static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > -{
> > -     struct vfe_output *output;
> > -     unsigned long flags;
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -     vfe->ops->reg_update_clear(vfe, line_id);
> > -
> > -     output = &vfe->line[line_id].output;
> > -
> > -     if (output->wait_reg_update) {
> > -             output->wait_reg_update = 0;
> > -             complete(&output->reg_update);
> > -             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -             return;
> > -     }
> > -
> > -     if (output->state == VFE_OUTPUT_STOPPING) {
> > -             /* Release last buffer when hw is idle */
> > -             if (output->last_buffer) {
> > -                     vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> > -                                     VB2_BUF_STATE_DONE);
> > -                     output->last_buffer = NULL;
> > -             }
> > -             output->state = VFE_OUTPUT_IDLE;
> > -
> > -             /* Buffers received in stopping state are queued in */
> > -             /* dma pending queue, start next capture here */
> > -
> > -             output->buf[0] = vfe_buf_get_pending(output);
> > -             output->buf[1] = vfe_buf_get_pending(output);
> > -
> > -             if (!output->buf[0] && output->buf[1]) {
> > -                     output->buf[0] = output->buf[1];
> > -                     output->buf[1] = NULL;
> > -             }
> > -
> > -             if (output->buf[0])
> > -                     output->state = VFE_OUTPUT_SINGLE;
> > -
> > -             if (output->buf[1])
> > -                     output->state = VFE_OUTPUT_CONTINUOUS;
> > -
> > -             switch (output->state) {
> > -             case VFE_OUTPUT_SINGLE:
> > -                     vfe_output_frame_drop(vfe, output, 2);
> > -                     break;
> > -             case VFE_OUTPUT_CONTINUOUS:
> > -                     vfe_output_frame_drop(vfe, output, 3);
> > -                     break;
> > -             default:
> > -                     vfe_output_frame_drop(vfe, output, 0);
> > -                     break;
> > -             }
> > -
> > -             vfe_output_init_addrs(vfe, output, 1);
> > -     }
> > -
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -}
> > -
> > -/*
> > - * vfe_isr_wm_done - Process write master done interrupt
> > - * @vfe: VFE Device
> > - * @wm: Write master id
> > - */
> > -static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> > -{
> > -     struct camss_buffer *ready_buf;
> > -     struct vfe_output *output;
> > -     dma_addr_t *new_addr;
> > -     unsigned long flags;
> > -     u32 active_index;
> > -     u64 ts = ktime_get_ns();
> > -     unsigned int i;
> > -
> > -     active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm);
> > -
> > -     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;
> > -
> > -     if (output->active_buf == active_index) {
> > -             dev_err_ratelimited(vfe->camss->dev,
> > -                                 "Active buffer mismatch!\n");
> > -             goto out_unlock;
> > -     }
> > -     output->active_buf = active_index;
> > -
> > -     ready_buf = output->buf[!active_index];
> > -     if (!ready_buf) {
> > -             dev_err_ratelimited(vfe->camss->dev,
> > -                                 "Missing ready buf %d %d!\n",
> > -                                 !active_index, output->state);
> > -             goto out_unlock;
> > -     }
> > -
> > -     ready_buf->vb.vb2_buf.timestamp = ts;
> > -     ready_buf->vb.sequence = output->sequence++;
> > -
> > -     /* Get next buffer */
> > -     output->buf[!active_index] = vfe_buf_get_pending(output);
> > -     if (!output->buf[!active_index]) {
> > -             /* No next buffer - set same address */
> > -             new_addr = ready_buf->addr;
> > -             vfe_buf_update_wm_on_last(vfe, output);
> > -     } else {
> > -             new_addr = output->buf[!active_index]->addr;
> > -             vfe_buf_update_wm_on_next(vfe, output);
> > -     }
> > -
> > -     if (active_index)
> > -             for (i = 0; i < output->wm_num; i++)
> > -                     vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i],
> > -                                                new_addr[i]);
> > -     else
> > -             for (i = 0; i < output->wm_num; i++)
> > -                     vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i],
> > -                                                new_addr[i]);
> > -
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     if (output->state == VFE_OUTPUT_STOPPING)
> > -             output->last_buffer = ready_buf;
> > -     else
> > -             vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > -
> > -     return;
> > -
> > -out_unlock:
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -}
> > -
> >   /*
> >    * vfe_isr_comp_done - Process composite image done interrupt
> >    * @vfe: VFE Device
> >    * @comp: Composite image id
> >    */
> > -static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
> > +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) {
> > -                     vfe_isr_wm_done(vfe, i);
> > +                     vfe->isr_ops.wm_done(vfe, i);
> >                       break;
> >               }
> >   }
> >
> > -static inline void vfe_isr_reset_ack(struct vfe_device *vfe)
> > +void vfe_isr_reset_ack(struct vfe_device *vfe)
> >   {
> >       complete(&vfe->reset_complete);
> >   }
> >
> > -static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
> > -{
> > -     complete(&vfe->halt_complete);
> > -     vfe->ops->halt_clear(vfe);
> > -}
> > -
> >   /*
> >    * vfe_set_clock_rates - Calculate and set clock rates on VFE module
> >    * @vfe: VFE device
> > @@ -1318,7 +620,7 @@ static void vfe_put(struct vfe_device *vfe)
> >       } else if (vfe->power_count == 1) {
> >               if (vfe->was_streaming) {
> >                       vfe->was_streaming = 0;
> > -                     vfe_halt(vfe);
> > +                     vfe->ops->vfe_halt(vfe);
> >               }
> >               camss_disable_clocks(vfe->nclocks, vfe->clock);
> >               pm_runtime_put_sync(vfe->camss->dev);
> > @@ -1331,35 +633,6 @@ static void vfe_put(struct vfe_device *vfe)
> >       mutex_unlock(&vfe->power_lock);
> >   }
> >
> > -/*
> > - * vfe_queue_buffer - Add empty buffer
> > - * @vid: Video device structure
> > - * @buf: Buffer to be enqueued
> > - *
> > - * Add an empty buffer - depending on the current number of buffers it will be
> > - * put in pending buffer queue or directly given to the hardware to be filled.
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -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_device *vfe = to_vfe(line);
> > -     struct vfe_output *output;
> > -     unsigned long flags;
> > -
> > -     output = &line->output;
> > -
> > -     spin_lock_irqsave(&vfe->output_lock, flags);
> > -
> > -     vfe_buf_update_wm_on_new(vfe, output, buf);
> > -
> > -     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > -
> > -     return 0;
> > -}
> > -
> >   /*
> >    * vfe_flush_buffers - Return all vb2 buffers
> >    * @vid: Video device structure
> > @@ -1370,8 +643,8 @@ static int vfe_queue_buffer(struct camss_video *vid,
> >    *
> >    * Return 0 on success or a negative error code otherwise
> >    */
> > -static int vfe_flush_buffers(struct camss_video *vid,
> > -                          enum vb2_buffer_state state)
> > +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_device *vfe = to_vfe(line);
> > @@ -1442,12 +715,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
> >       int ret;
> >
> >       if (enable) {
> > -             ret = vfe_enable(line);
> > +             ret = vfe->ops->vfe_enable(line);
> >               if (ret < 0)
> >                       dev_err(vfe->camss->dev,
> >                               "Failed to enable vfe outputs\n");
> >       } else {
> > -             ret = vfe_disable(line);
> > +             ret = vfe->ops->vfe_disable(line);
> >               if (ret < 0)
> >                       dev_err(vfe->camss->dev,
> >                               "Failed to disable vfe outputs\n");
> > @@ -1985,13 +1258,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >       int i, j;
> >       int ret;
> >
> > -     vfe->isr_ops.reset_ack = vfe_isr_reset_ack;
> > -     vfe->isr_ops.halt_ack = vfe_isr_halt_ack;
> > -     vfe->isr_ops.reg_update = vfe_isr_reg_update;
> > -     vfe->isr_ops.sof = vfe_isr_sof;
> > -     vfe->isr_ops.comp_done = vfe_isr_comp_done;
> > -     vfe->isr_ops.wm_done = vfe_isr_wm_done;
> > -
> >       switch (camss->version) {
> >       case CAMSS_8x16:
> >               vfe->ops = &vfe_ops_4_1;
> > @@ -2005,6 +1271,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >       default:
> >               return -EINVAL;
> >       }
> > +     vfe->ops->subdev_init(vfe);
> >
> >       /* Memory */
> >
> > @@ -2209,11 +1476,6 @@ static const struct media_entity_operations vfe_media_ops = {
> >       .link_validate = v4l2_subdev_link_validate,
> >   };
> >
> > -static const struct camss_video_ops camss_vfe_video_ops = {
> > -     .queue_buffer = vfe_queue_buffer,
> > -     .flush_buffers = vfe_flush_buffers,
> > -};
> > -
> >   /*
> >    * msm_vfe_register_entities - Register subdev node for VFE module
> >    * @vfe: VFE device
> > @@ -2279,7 +1541,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
> >                       goto error_reg_subdev;
> >               }
> >
> > -             video_out->ops = &camss_vfe_video_ops;
> > +             video_out->ops = &vfe->video_ops;
> >               video_out->bpl_alignment = 8;
> >               video_out->line_based = 0;
> >               if (i == VFE_LINE_PIX) {
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> > index 5bce6736e4bb..8629c833f130 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> > @@ -17,6 +17,8 @@
> >   #include <media/v4l2-subdev.h>
> >
> >   #include "camss-video.h"
> > +#include "camss-vfe-gen1.h"
> > +
> >
> >   #define MSM_VFE_PAD_SINK 0
> >   #define MSM_VFE_PAD_SRC 1
> > @@ -26,6 +28,18 @@
> >   #define MSM_VFE_IMAGE_MASTERS_NUM 7
> >   #define MSM_VFE_COMPOSITE_IRQ_NUM 4
> >
> > +/* VFE halt timeout */
> > +#define VFE_HALT_TIMEOUT_MS 100
> > +/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> > +#define VFE_FRAME_DROP_VAL 30
> > +
> > +#define vfe_line_array(ptr_line)     \
> > +     ((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> > +
> > +#define to_vfe(ptr_line)     \
> > +     container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> > +
> > +
> >   enum vfe_output_state {
> >       VFE_OUTPUT_OFF,
> >       VFE_OUTPUT_RESERVED,
> > @@ -47,16 +61,21 @@ struct vfe_output {
> >       u8 wm_num;
> >       u8 wm_idx[3];
> >
> > -     int active_buf;
> >       struct camss_buffer *buf[2];
> >       struct camss_buffer *last_buffer;
> >       struct list_head pending_bufs;
> >
> >       unsigned int drop_update_idx;
> >
> > +     union {
> > +             struct {
> > +                     int active_buf;
> > +                     int wait_sof;
> > +             } gen1;
> > +     };
> >       enum vfe_output_state state;
> >       unsigned int sequence;
> > -     int wait_sof;
> > +
> >       int wait_reg_update;
> >       struct completion sof;
> >       struct completion reg_update;
> > @@ -78,59 +97,19 @@ struct vfe_line {
> >   struct vfe_device;
> >
> >   struct vfe_hw_ops {
> > -     void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> > -     u16 (*get_ub_size)(u8 vfe_id);
> > +     void (*enable_irq_common)(struct vfe_device *vfe);
> >       void (*global_reset)(struct vfe_device *vfe);
> > -     void (*halt_request)(struct vfe_device *vfe);
> > -     void (*halt_clear)(struct vfe_device *vfe);
> > -     void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> > -     void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> > -     void (*wm_line_based)(struct vfe_device *vfe, u32 wm,
> > -                           struct v4l2_pix_format_mplane *pix,
> > -                           u8 plane, u32 enable);
> > -     void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> > -     void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm,
> > -                                      u32 pattern);
> > -     void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset,
> > -                           u16 depth);
> > -     void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> > -     void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> > -     void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> > -     int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> > -     void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> > -     void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm,
> > -                                   enum vfe_line_id id);
> > -     void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> > -     void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm,
> > -                                        enum vfe_line_id id);
> > -     void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output,
> > -                          u8 enable);
> > -     void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id,
> > -                         u8 cid);
> > -     void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line,
> > -                             u8 enable);
> > +     void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> > +     irqreturn_t (*isr)(int irq, void *dev);
> > +     void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
> >       void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id);
> >       void (*reg_update_clear)(struct vfe_device *vfe,
> >                                enum vfe_line_id line_id);
> > -     void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm,
> > -                                enum vfe_line_id line_id, u8 enable);
> > -     void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp,
> > -                                 enum vfe_line_id line_id, u8 enable);
> > -     void (*enable_irq_common)(struct vfe_device *vfe);
> > -     void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > -     void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > -     void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > -     void (*set_clamp_cfg)(struct vfe_device *vfe);
> > -     void (*set_qos)(struct vfe_device *vfe);
> > -     void (*set_ds)(struct vfe_device *vfe);
> > -     void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> > -     void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> > -     void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> > -     void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> > -     int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> > -     void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
> > +     void (*subdev_init)(struct vfe_device *vfe);
> > +     int (*vfe_disable)(struct vfe_line *line);
> > +     int (*vfe_enable)(struct vfe_line *line);
> > +     int (*vfe_halt)(struct vfe_device *vfe);
> >       void (*violation_read)(struct vfe_device *vfe);
> > -     irqreturn_t (*isr)(int irq, void *dev);
> >   };
> >
> >   struct vfe_isr_ops {
> > @@ -162,7 +141,9 @@ struct vfe_device {
> >       u32 reg_update;
> >       u8 was_streaming;
> >       const struct vfe_hw_ops *ops;
> > +     const struct vfe_hw_ops_gen1 *ops_gen1;
> >       struct vfe_isr_ops isr_ops;
> > +     struct camss_video_ops video_ops;
> >   };
> >
> >   struct resources;
> > @@ -178,6 +159,38 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe);
> >   void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
> >   void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
> >
> > +
> > +/*
> > + * vfe_buf_add_pending - Add output buffer to list of pending
> > + * @output: VFE output
> > + * @buffer: Video buffer
> > + */
> > +void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer);
> > +
> > +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
> > +
> > +/*
> > + * vfe_disable - Disable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +int vfe_disable(struct vfe_line *line);
> > +
> > +int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
> > +
> > +/*
> > + * vfe_isr_comp_done - Process composite image done interrupt
> > + * @vfe: VFE Device
> > + * @comp: Composite image id
> > + */
> > +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp);
> > +
> > +void vfe_isr_reset_ack(struct vfe_device *vfe);
> > +int vfe_put_output(struct vfe_line *line);
> > +int vfe_release_wm(struct vfe_device *vfe, u8 wm);
> > +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
> > +
> >   extern const struct vfe_hw_ops vfe_ops_4_1;
> >   extern const struct vfe_hw_ops vfe_ops_4_7;
> >   extern const struct vfe_hw_ops vfe_ops_4_8;
> >

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

* Re: [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
  2021-01-08 12:04   ` Robert Foss
@ 2021-01-14 10:48     ` Andrey Konovalov
  -1 siblings, 0 replies; 65+ messages in thread
From: Andrey Konovalov @ 2021-01-14 10:48 UTC (permalink / raw)
  To: Robert Foss, agross, bjorn.andersson, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno
  Cc: Tomasz Figa, Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

Hi Robert,

Thank you for the patch!

On 08.01.2021 15:04, Robert Foss wrote:
> Add register definitions for version 170 of the Titan architecture
> and implement support for the RDI output mode.
> 
> The RDI mode as opposed to the PIX output mode for the VFE unit does
> not support any ISP functionality. This means essentially only
> supporting dumping the output of the whatever the CSI decoder receives
> from the sensor.
> 
> For example will a sensor outputting YUV pixel format frames, only
> allow the VFE to dump those frames as they are received by the ISP
> to memory through the RDI interface.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>   drivers/media/platform/qcom/camss/Makefile    |   1 +
>   .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
>   drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
>   drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
>   .../media/platform/qcom/camss/camss-video.c   | 100 +++
>   drivers/media/platform/qcom/camss/camss.c     |  61 ++
>   6 files changed, 1034 insertions(+), 20 deletions(-)
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
> 
> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> index 940c0ae3e003..052c4f405fa3 100644
> --- a/drivers/media/platform/qcom/camss/Makefile
> +++ b/drivers/media/platform/qcom/camss/Makefile
> @@ -11,6 +11,7 @@ qcom-camss-objs += \
>   		camss-vfe-4-1.o \
>   		camss-vfe-4-7.o \
>   		camss-vfe-4-8.o \
> +		camss-vfe-170.o \
>   		camss-vfe-gen1.o \
>   		camss-vfe.o \
>   		camss-video.o \
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> new file mode 100644
> index 000000000000..89b6c47cca22
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> @@ -0,0 +1,808 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-4-7.c
> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7

- the above two lines aren't updated to vfe-170

> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2018 Linaro Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +
> +#define VFE_HW_VERSION				(0x000)
> +
> +#define VFE_GLOBAL_RESET_CMD			(0x018)
> +#define		GLOBAL_RESET_CMD_CORE		BIT(0)
> +#define		GLOBAL_RESET_CMD_CAMIF		BIT(1)
> +#define		GLOBAL_RESET_CMD_BUS		BIT(2)
> +#define		GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
> +#define		GLOBAL_RESET_CMD_REGISTER	BIT(4)
> +#define		GLOBAL_RESET_CMD_PM		BIT(5)
> +#define		GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
> +#define		GLOBAL_RESET_CMD_TESTGEN	BIT(7)
> +#define		GLOBAL_RESET_CMD_DSP		BIT(8)
> +#define		GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
> +
> +#define VFE_CORE_CFG				(0x050)
> +#define		CFG_PIXEL_PATTERN_YCBYCR	(0x4)
> +#define		CFG_PIXEL_PATTERN_YCRYCB	(0x5)
> +#define		CFG_PIXEL_PATTERN_CBYCRY	(0x6)
> +#define		CFG_PIXEL_PATTERN_CRYCBY	(0x7)
> +#define		CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
> +
> +#define VFE_IRQ_CMD				(0x058)
> +#define		CMD_GLOBAL_CLEAR		BIT(0)
> +
> +#define VFE_IRQ_MASK_0					(0x05c)
> +#define		MASK_0_CAMIF_SOF			BIT(0)
> +#define		MASK_0_CAMIF_EOF			BIT(1)
> +#define		MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define		MASK_0_line_n_REG_UPDATE(n)		\
> +			((n) == VFE_LINE_PIX ? \
> +				BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
> +#define		MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define		MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define		MASK_0_RESET_ACK			BIT(31)
> +
> +#define VFE_IRQ_MASK_1					(0x060)
> +#define		MASK_1_CAMIF_ERROR			BIT(0)
> +#define		MASK_1_VIOLATION			BIT(7)
> +#define		MASK_1_BUS_BDG_HALT_ACK			BIT(8)
> +#define		MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
> +#define		MASK_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_IRQ_CLEAR_0					(0x064)
> +#define VFE_IRQ_CLEAR_1					(0x068)
> +
> +#define VFE_IRQ_STATUS_0				(0x06c)
> +#define		STATUS_0_CAMIF_SOF			BIT(0)
> +#define		STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define		STATUS_0_line_n_REG_UPDATE(n)		\
> +			((n) == VFE_LINE_PIX ? \
> +				BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
> +#define		STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define		STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define		STATUS_0_RESET_ACK			BIT(31)
> +
> +#define VFE_IRQ_STATUS_1				(0x070)
> +#define		STATUS_1_VIOLATION			BIT(7)
> +#define		STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define		STATUS_1_RDIn_SOF(n)			BIT((n) + 27)
> +
> +#define VFE_VIOLATION_STATUS			(0x07c)
> +
> +#define VFE_CAMIF_CMD				(0x478)
> +#define		CMD_CLEAR_CAMIF_STATUS		BIT(2)
> +
> +#define VFE_CAMIF_CFG				(0x47c)
> +#define		CFG_VSYNC_SYNC_EDGE		(0)
> +#define			VSYNC_ACTIVE_HIGH	(0)
> +#define			VSYNC_ACTIVE_LOW	(1)
> +#define		CFG_HSYNC_SYNC_EDGE		(1)
> +#define			HSYNC_ACTIVE_HIGH	(0)
> +#define			HSYNC_ACTIVE_LOW	(1)
> +#define		CFG_VFE_SUBSAMPLE_ENABLE	BIT(4)
> +#define		CFG_BUS_SUBSAMPLE_ENABLE	BIT(5)
> +#define		CFG_VFE_OUTPUT_EN		BIT(6)
> +#define		CFG_BUS_OUTPUT_EN		BIT(7)
> +#define		CFG_BINNING_EN			BIT(9)
> +#define		CFG_FRAME_BASED_EN		BIT(10)
> +#define		CFG_RAW_CROP_EN			BIT(22)
> +
> +// XXX different, don't exist in TITAN register docs
> +#define VFE_0_CAMIF_FRAME_CFG			0x484
> +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
> +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
> +#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
> +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
> +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
> +#define VFE_0_CAMIF_STATUS			0x4a4
> +#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
> +#define CAMIF_TIMEOUT_SLEEP_US 1000
> +#define CAMIF_TIMEOUT_ALL_US 1000000
> +
> +#define VFE_REG_UPDATE_CMD			(0x4ac)
> +#define		REG_UPDATE_RDIn(n)		BIT(1 + (n))
> +#define		REG_UPDATE_line_n(n)		\
> +			((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
> +
> +
> +#define VFE_BUS_IRQ_MASK(n)		(0x2044 + (n) * 4)
> +#define VFE_BUS_IRQ_CLEAR(n)		(0x2050 + (n) * 4)
> +
> +#define VFE_BUS_IRQ_STATUS(n)		(0x205c + (n) * 4)
> +#define		STATUS0_COMP_RESET_DONE		BIT(0)
> +#define		STATUS0_COMP_REG_UPDATE0_DONE	BIT(1)
> +#define		STATUS0_COMP_REG_UPDATE1_DONE	BIT(2)
> +#define		STATUS0_COMP_REG_UPDATE2_DONE	BIT(3)
> +#define		STATUS0_COMP_REG_UPDATE3_DONE	BIT(4)
> +#define		STATUS0_COMP_REG_UPDATE_DONE(n)	BIT(n + 1)
> +#define		STATUS0_COMP0_BUF_DONE		BIT(5)
> +#define		STATUS0_COMP1_BUF_DONE		BIT(6)
> +#define		STATUS0_COMP2_BUF_DONE		BIT(7)
> +#define		STATUS0_COMP3_BUF_DONE		BIT(8)
> +#define		STATUS0_COMP4_BUF_DONE		BIT(9)
> +#define		STATUS0_COMP5_BUF_DONE		BIT(10)
> +#define		STATUS0_COMP_BUF_DONE(n)	BIT(n + 5)
> +#define		STATUS0_COMP_ERROR		BIT(11)
> +#define		STATUS0_COMP_OVERWRITE		BIT(12)
> +#define		STATUS0_OVERFLOW		BIT(13)
> +#define		STATUS0_VIOLATION		BIT(14)
> +/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
> +#define		STATUS1_WM_CLIENT_BUF_DONE(n)		BIT(n)
> +#define		STATUS1_EARLY_DONE			BIT(24)
> +#define		STATUS2_DUAL_COMP0_BUF_DONE		BIT(0)
> +#define		STATUS2_DUAL_COMP1_BUF_DONE		BIT(1)
> +#define		STATUS2_DUAL_COMP2_BUF_DONE		BIT(2)
> +#define		STATUS2_DUAL_COMP3_BUF_DONE		BIT(3)
> +#define		STATUS2_DUAL_COMP4_BUF_DONE		BIT(4)
> +#define		STATUS2_DUAL_COMP5_BUF_DONE		BIT(5)
> +#define		STATUS2_DUAL_COMP_BUF_DONE(n)		BIT(n)
> +#define		STATUS2_DUAL_COMP_ERROR			BIT(6)
> +#define		STATUS2_DUAL_COMP_OVERWRITE		BIT(7)
> +
> +#define VFE_BUS_IRQ_CLEAR_GLOBAL		(0x2068)
> +
> +#define VFE_BUS_WM_DEBUG_STATUS_CFG		(0x226c)
> +#define		DEBUG_STATUS_CFG_STATUS0(n)	BIT(n)
> +#define		DEBUG_STATUS_CFG_STATUS1(n)	BIT(8+n)
> +
> +#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER	(0x2080)
> +
> +#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC		(0x2084)
> +#define		BUS_VER2_MAX_CLIENTS (24)
> +#define		WM_ADDR_NO_SYNC_DEFAULT_VAL \
> +				((1 << BUS_VER2_MAX_CLIENTS) - 1)
> +
> +#define VFE_BUS_WM_CGC_OVERRIDE			(0x200c)
> +#define		WM_CGC_OVERRIDE_ALL		(0xFFFFF)
> +
> +#define VFE_BUS_WM_TEST_BUS_CTRL		(0x211c)
> +
> +#define VFE_BUS_WM_STATUS0(n)			(0x2200 + (n) * 0x100)
> +#define VFE_BUS_WM_STATUS1(n)			(0x2204 + (n) * 0x100)
> +#define VFE_BUS_WM_CFG(n)			(0x2208 + (n) * 0x100)
> +#define		WM_CFG_EN			(0)
> +#define		WM_CFG_MODE			(1)
> +#define			MODE_QCOM_PLAIN	(0)
> +#define			MODE_MIPI_RAW	(1)
> +#define		WM_CFG_VIRTUALFRAME		(2)
> +#define VFE_BUS_WM_HEADER_ADDR(n)		(0x220c + (n) * 0x100)
> +#define VFE_BUS_WM_HEADER_CFG(n)		(0x2210 + (n) * 0x100)
> +#define VFE_BUS_WM_IMAGE_ADDR(n)		(0x2214 + (n) * 0x100)
> +#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)		(0x2218 + (n) * 0x100)
> +#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)		(0x221c + (n) * 0x100)
> +#define		WM_BUFFER_DEFAULT_WIDTH		(0xFF01)
> +
> +#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)		(0x2220 + (n) * 0x100)
> +#define VFE_BUS_WM_PACKER_CFG(n)		(0x2224 + (n) * 0x100)
> +
> +#define VFE_BUS_WM_STRIDE(n)			(0x2228 + (n) * 0x100)
> +#define		WM_STRIDE_DEFAULT_STRIDE	(0xFF01)
> +
> +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(0x2248 + (n) * 0x100)
> +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(0x224c + (n) * 0x100)
> +#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(0x2250 + (n) * 0x100)
> +#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(0x2254 + (n) * 0x100)
> +#define VFE_BUS_WM_FRAME_INC(n)			(0x2258 + (n) * 0x100)
> +#define VFE_BUS_WM_BURST_LIMIT(n)		(0x225c + (n) * 0x100)
> +
> +
> +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
> +
> +	u32 gen = (hw_version >> 28) & 0xF;
> +	u32 rev = (hw_version >> 16) & 0xFFF;
> +	u32 step = hw_version & 0xFFFF;
> +
> +	dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
> +}
> +
> +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> +}
> +
> +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits | set_bits, vfe->base + reg);
> +}
> +
> +static void vfe_global_reset(struct vfe_device *vfe)
> +{
> +	u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC	|
> +			 GLOBAL_RESET_CMD_DSP		|
> +			 GLOBAL_RESET_CMD_TESTGEN	|
> +			 GLOBAL_RESET_CMD_BUS_MISR	|
> +			 GLOBAL_RESET_CMD_PM		|
> +			 GLOBAL_RESET_CMD_REGISTER	|
> +			 GLOBAL_RESET_CMD_BUS_BDG	|
> +			 GLOBAL_RESET_CMD_BUS		|
> +			 GLOBAL_RESET_CMD_CAMIF		|
> +			 GLOBAL_RESET_CMD_CORE;

- the above settings are overwritten by this assignment:

> +	reset_bits = 0x00003F9F;
> +
> +	writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
> +
> +	/* Make sure IRQ mask has been written before resetting */
> +	wmb();
> +
> +	writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
> +}
> +
> +static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
> +{
> +	u32 val;
> +
> +	/*Set Debug Registers*/
> +	val = DEBUG_STATUS_CFG_STATUS0(1) |
> +	      DEBUG_STATUS_CFG_STATUS0(7);
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
> +
> +	/* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
> +	writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
> +
> +	/* no clock gating at bus input */
> +	val = WM_CGC_OVERRIDE_ALL;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
> +
> +	writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
> +
> +	/* if addr_no_sync has default value then config the addr no sync reg */
> +	val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
> +
> +	writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
> +
> +	val = WM_BUFFER_DEFAULT_WIDTH;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
> +
> +	val = 0;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
> +
> +	val = 0;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?

- C++ style comment

   Also here and in several comments below you use the XXX tag which looks
   more confusing than helpful for me. Would it be possible to expand such comments
   to make them more explicit? Just a nitpick though.

> +
> +	/* Configure stride for RDIs */
> +	//val = pix->plane_fmt[0].bytesperline;

- the commented out line should probably be removed. Or changed into real
   comment.

Thanks,
Andrey

> +	val = WM_STRIDE_DEFAULT_STRIDE;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
> +
> +	/* Enable WM */
> +	val = 1 << WM_CFG_EN |
> +	      MODE_MIPI_RAW << WM_CFG_MODE;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
> +}
> +
> +static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
> +{
> +	/* Disable WM */
> +	writel_relaxed(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)
> +{
> +	/* XXX use cmdbuf for this ?? */
> +	struct v4l2_pix_format_mplane *pix =
> +		&line->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));
> +	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
> +
> +	/* XXX enable wm ? */
> +}
> +
> +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	vfe->reg_update |= REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce ordering between previous reg writes and reg update */
> +	wmb();
> +
> +	writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
> +
> +	/* Enforce ordering between reg update and subsequent reg writes */
> +	wmb();
> +}
> +
> +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> +					enum vfe_line_id line_id)
> +{
> +	vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
> +}
> +
> +static void vfe_enable_irq_common(struct vfe_device *vfe)
> +{
> +	vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
> +	vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
> +
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
> +}
> +
> +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> +{
> +	complete(&vfe->halt_complete);
> +}
> +
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
> +{
> +	*status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> +	*status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> +
> +	writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
> +	writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
> +
> +	/* Enforce ordering between IRQ Clear and Global IRQ Clear */
> +	wmb();
> +	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> +}
> +
> +static void vfe_violation_read(struct vfe_device *vfe)
> +{
> +	u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
> +
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> +}
> +
> +/*
> + * vfe_isr - VFE module interrupt handler
> + * @irq: Interrupt line
> + * @dev: VFE device
> + *
> + * Return IRQ_HANDLED on success
> + */
> +static irqreturn_t vfe_isr(int irq, void *dev)
> +{
> +	struct vfe_device *vfe = dev;
> +	u32 status0, status1, vfe_bus_status[3];
> +	int i, wm;
> +
> +	status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> +	status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> +
> +	writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
> +	writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
> +		vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
> +		writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
> +	}
> +
> +	/* Enforce ordering between IRQ reading and interpretation */
> +	wmb();
> +
> +	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> +	writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
> +
> +	if (status0 & STATUS_0_RESET_ACK)
> +		vfe->isr_ops.reset_ack(vfe);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> +		if (status0 & STATUS_0_line_n_REG_UPDATE(i))
> +			vfe->isr_ops.reg_update(vfe, i);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> +		if (status0 & STATUS_1_RDIn_SOF(i))
> +			vfe->isr_ops.sof(vfe, i);
> +
> +	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> +		if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
> +			vfe->isr_ops.comp_done(vfe, i);
> +
> +	for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
> +		if (status0 & BIT(9))
> +			if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
> +				vfe->isr_ops.wm_done(vfe, wm);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * vfe_halt - Trigger halt on VFE module and wait to complete
> + * @vfe: VFE device
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_halt(struct vfe_device *vfe)
> +{
> +	unsigned long time;
> +
> +	return 0;
> +
> +	reinit_completion(&vfe->halt_complete);
> +
> +	time = wait_for_completion_timeout(&vfe->halt_complete,
> +		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> +	if (!time) {
> +		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +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;
> +	unsigned long flags;
> +	int i;
> +	int wm_idx;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output = &line->output;
> +	if (output->state != VFE_OUTPUT_OFF) {
> +		dev_err(vfe->camss->dev, "Output is running\n");
> +		goto error;
> +	}
> +
> +	switch (f->fmt.pix_mp.pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		output->wm_num = 2;
> +		break;
> +	default:
> +		output->wm_num = 1;
> +		break;
> +	}
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		wm_idx = vfe_reserve_wm(vfe, line->id);
> +		if (wm_idx < 0) {
> +			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> +			goto error_get_wm;
> +		}
> +		output->wm_idx[i] = wm_idx;
> +	}
> +
> +	output->drop_update_idx = 0;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +
> +error_get_wm:
> +	for (i--; i >= 0; i--)
> +		vfe_release_wm(vfe, output->wm_idx[i]);
> +	output->state = VFE_OUTPUT_OFF;
> +error:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return -EINVAL;
> +}
> +
> +static int vfe_enable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	struct media_entity *sensor;
> +	unsigned long flags;
> +	unsigned int frame_skip = 0;
> +	unsigned int i;
> +
> +	sensor = camss_find_sensor(&line->subdev.entity);
> +	if (sensor) {
> +		struct v4l2_subdev *subdev =
> +					media_entity_to_v4l2_subdev(sensor);
> +
> +		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_OFF) {
> +		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
> +			output->state);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	WARN_ON(output->gen2.active_num);
> +
> +	output->state = VFE_OUTPUT_ON;
> +
> +	output->sequence = 0;
> +	output->wait_reg_update = 0;
> +	reinit_completion(&output->reg_update);
> +
> +	if (line->id != VFE_LINE_PIX)
> +		vfe_wm_start(vfe, output->wm_idx[0], line);
> +
> +	for (i = 0; i < 2; i++) {
> +		output->buf[i] = vfe_buf_get_pending(output);
> +		if (!output->buf[i])
> +			break;
> +		output->gen2.active_num++;
> +		vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
> +	}
> +
> +	ops->reg_update(vfe, line->id);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +static int vfe_disable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	unsigned long flags;
> +	unsigned int i;
> +	bool done;
> +	int timeout = 0;
> +
> +	do {
> +		spin_lock_irqsave(&vfe->output_lock, flags);
> +		done = !output->gen2.active_num;
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		usleep_range(10000, 20000);
> +
> +		if (timeout++ == 100) {
> +			dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
> +			vfe_reset(vfe);
> +			output->gen2.active_num = 0;
> +			return 0;
> +		}
> +	} while (!done);
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	for (i = 0; i < output->wm_num; i++)
> +		vfe_wm_stop(vfe, output->wm_idx[i]);
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_enable - Enable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_enable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	int ret;
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (!vfe->stream_count)
> +		vfe_enable_irq_common(vfe);
> +
> +	vfe->stream_count++;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	ret = vfe_get_output(line);
> +	if (ret < 0)
> +		goto error_get_output;
> +
> +	ret = vfe_enable_output(line);
> +	if (ret < 0)
> +		goto error_enable_output;
> +
> +	vfe->was_streaming = 1;
> +
> +	return 0;
> +
> +
> +error_enable_output:
> +	vfe_put_output(line);
> +
> +error_get_output:
> +	mutex_lock(&vfe->stream_lock);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return ret;
> +}
> +
> +/*
> + * vfe_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_disable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +
> +	vfe_disable_output(line);
> +
> +	vfe_put_output(line);
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_isr_sof - Process start of frame interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +
> +}
> +
> +/*
> + * vfe_isr_reg_update - Process reg update interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	vfe->ops->reg_update_clear(vfe, line_id);
> +
> +	output = &vfe->line[line_id].output;
> +
> +	if (output->wait_reg_update) {
> +		output->wait_reg_update = 0;
> +		complete(&output->reg_update);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_wm_done - Process write master done interrupt
> + * @vfe: VFE Device
> + * @wm: Write master id
> + */
> +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> +{
> +	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
> +	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;
> +
> +	ready_buf = output->buf[0];
> +	if (!ready_buf) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Missing ready buf %d!\n", output->state);
> +		goto out_unlock;
> +	}
> +
> +	ready_buf->vb.vb2_buf.timestamp = ts;
> +	ready_buf->vb.sequence = output->sequence++;
> +
> +	index = 0;
> +	output->buf[0] = output->buf[1];
> +	if (output->buf[0])
> +		index = 1;
> +
> +	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);
> +	else
> +		output->gen2.active_num--;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +	return;
> +
> +out_unlock:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_queue_buffer - Add empty buffer
> + * @vid: Video device structure
> + * @buf: Buffer to be enqueued
> + *
> + * Add an empty buffer - depending on the current number of buffers it will be
> + * put in pending buffer queue or directly given to the hardware to be filled.
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +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_device *vfe = to_vfe(line);
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	output = &line->output;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
> +		output->buf[output->gen2.active_num++] = buf;
> +		vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
> +	} else {
> +		vfe_buf_add_pending(output, buf);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +const struct vfe_isr_ops vfe_isr_ops_170 = {
> +	.reset_ack = vfe_isr_reset_ack,
> +	.halt_ack = vfe_isr_halt_ack,
> +	.reg_update = vfe_isr_reg_update,
> +	.sof = vfe_isr_sof,
> +	.comp_done = vfe_isr_comp_done,
> +	.wm_done = vfe_isr_wm_done,
> +};
> +
> +static const struct camss_video_ops vfe_video_ops_170 = {
> +	.queue_buffer = vfe_queue_buffer,
> +	.flush_buffers = vfe_flush_buffers,
> +};
> +
> +static void vfe_subdev_init(struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_170;
> +	vfe->video_ops = vfe_video_ops_170;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_170 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
> +	.isr_read = vfe_isr_read,
> +	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_disable,
> +	.vfe_enable = vfe_enable,
> +	.vfe_halt = vfe_halt,
> +	.violation_read = vfe_violation_read,
> +};
> +
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index 2ffa5b3c5426..5a874b544391 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
>   	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
>   };
>   
> +static const struct vfe_format formats_rdi_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
> +	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
> +};
> +
> +static const struct vfe_format formats_pix_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> +};
> +
>   /*
>    * vfe_get_bpp - map media bus format to bits per pixel
>    * @formats: supported media bus formats array
> @@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
>   			return sink_code;
>   		}
>   	else if (vfe->camss->version == CAMSS_8x96 ||
> -		 vfe->camss->version == CAMSS_660)
> +		 vfe->camss->version == CAMSS_660 ||
> +		 vfe->camss->version == CAMSS_845)
>   		switch (sink_code) {
>   		case MEDIA_BUS_FMT_YUYV8_2X8:
>   		{
> @@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
>   		return 0;
>   }
>   
> -/*
> - * vfe_reset - Trigger reset on VFE module and wait to complete
> - * @vfe: VFE device
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_reset(struct vfe_device *vfe)
> +int vfe_reset(struct vfe_device *vfe)
>   {
>   	unsigned long time;
>   
> @@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
>   		struct camss_clock *clock = &vfe->clock[i];
>   
>   		if (!strcmp(clock->name, "vfe0") ||
> -		    !strcmp(clock->name, "vfe1")) {
> +		    !strcmp(clock->name, "vfe1") ||
> +		    !strcmp(clock->name, "vfe_lite")) {
>   			u64 min_rate = 0;
>   			long rate;
>   
> @@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	case CAMSS_660:
>   		vfe->ops = &vfe_ops_4_8;
>   		break;
> +
> +	case CAMSS_845:
> +		vfe->ops = &vfe_ops_170;
> +		break;
>   	default:
>   		return -EINVAL;
>   	}
> @@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   				l->formats = formats_rdi_8x96;
>   				l->nformats = ARRAY_SIZE(formats_rdi_8x96);
>   			}
> +		} else if (camss->version == CAMSS_845) {
> +			if (i == VFE_LINE_PIX) {
> +				l->formats = formats_pix_845;
> +				l->nformats = ARRAY_SIZE(formats_pix_845);
> +			} else {
> +				l->formats = formats_rdi_845;
> +				l->nformats = ARRAY_SIZE(formats_rdi_845);
> +			}
>   		} else {
>   			return -EINVAL;
>   		}
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> index 8629c833f130..a0b618c9cec8 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> @@ -19,7 +19,6 @@
>   #include "camss-video.h"
>   #include "camss-vfe-gen1.h"
>   
> -
>   #define MSM_VFE_PAD_SINK 0
>   #define MSM_VFE_PAD_SRC 1
>   #define MSM_VFE_PADS_NUM 2
> @@ -39,14 +38,14 @@
>   #define to_vfe(ptr_line)	\
>   	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
>   
> -
>   enum vfe_output_state {
>   	VFE_OUTPUT_OFF,
>   	VFE_OUTPUT_RESERVED,
>   	VFE_OUTPUT_SINGLE,
>   	VFE_OUTPUT_CONTINUOUS,
>   	VFE_OUTPUT_IDLE,
> -	VFE_OUTPUT_STOPPING
> +	VFE_OUTPUT_STOPPING,
> +	VFE_OUTPUT_ON,
>   };
>   
>   enum vfe_line_id {
> @@ -72,6 +71,9 @@ struct vfe_output {
>   			int active_buf;
>   			int wait_sof;
>   		} gen1;
> +		struct {
> +			int active_num;
> +		} gen2;
>   	};
>   	enum vfe_output_state state;
>   	unsigned int sequence;
> @@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
>   
>   struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
>   
> -/*
> - * vfe_disable - Disable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -int vfe_disable(struct vfe_line *line);
> -
>   int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
>   
>   /*
> @@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
>   int vfe_release_wm(struct vfe_device *vfe, u8 wm);
>   int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
>   
> +/*
> + * vfe_reset - Trigger reset on VFE module and wait to complete
> + * @vfe: VFE device
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_reset(struct vfe_device *vfe);
> +
>   extern const struct vfe_hw_ops vfe_ops_4_1;
>   extern const struct vfe_hw_ops vfe_ops_4_7;
>   extern const struct vfe_hw_ops vfe_ops_4_8;
> +extern const struct vfe_hw_ops vfe_ops_170;
>   
>   #endif /* QC_MSM_CAMSS_VFE_H */
> diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
> index bd9334af1c73..b4943df9eaf6 100644
> --- a/drivers/media/platform/qcom/camss/camss-video.c
> +++ b/drivers/media/platform/qcom/camss/camss-video.c
> @@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
>   	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
>   };
>   
> +static const struct camss_format_info formats_rdi_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +};
> +
>   static const struct camss_format_info formats_pix_8x16[] = {
>   	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
>   	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> @@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
>   	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
>   };
>   
> +static const struct camss_format_info formats_pix_845[] = {
> +	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +};
> +
>   /* -----------------------------------------------------------------------------
>    * Helper functions
>    */
> @@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
>   			video->formats = formats_rdi_8x96;
>   			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
>   		}
> +	}  else if (video->camss->version == CAMSS_845) {
> +		if (is_pix) {
> +			video->formats = formats_pix_845;
> +			video->nformats = ARRAY_SIZE(formats_pix_845);
> +		} else {
> +			video->formats = formats_rdi_845;
> +			video->nformats = ARRAY_SIZE(formats_rdi_845);
> +		}
>   	} else {
>   		goto error_video_register;
>   	}
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index aeec59bc6194..1c3d64d612ff 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
>   	}
>   };
>   
> +static const struct resources vfe_res_845[] = {
> +	/* VFE0 */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe0", "vfe0_axi",
> +				"vfe0_src", "csi0",
> +				"csi0_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 0 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe0" },
> +		.interrupt = { "vfe0" }
> +	},
> +
> +	/* VFE1 */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe1", "vfe1_axi",
> +				"vfe1_src", "csi1",
> +				"csi1_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 0 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe1" },
> +		.interrupt = { "vfe1" }
> +	},
> +
> +	/* VFE-lite */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe_lite",
> +				"vfe_lite_src", "csi2",
> +				"csi2_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe_lite" },
> +		.interrupt = { "vfe_lite" }
> +	}
> +};
> +
>   /*
>    * camss_add_clock_margin - Add margin to clock frequency rate
>    * @rate: Clock frequency rate
> 

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

* Re: [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
@ 2021-01-14 10:48     ` Andrey Konovalov
  0 siblings, 0 replies; 65+ messages in thread
From: Andrey Konovalov @ 2021-01-14 10:48 UTC (permalink / raw)
  To: Robert Foss, agross, bjorn.andersson, todor.too, mchehab,
	robh+dt, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media, devicetree, linux-kernel,
	linux-arm-kernel, AngeloGioacchino Del Regno
  Cc: Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart, Tomasz Figa

Hi Robert,

Thank you for the patch!

On 08.01.2021 15:04, Robert Foss wrote:
> Add register definitions for version 170 of the Titan architecture
> and implement support for the RDI output mode.
> 
> The RDI mode as opposed to the PIX output mode for the VFE unit does
> not support any ISP functionality. This means essentially only
> supporting dumping the output of the whatever the CSI decoder receives
> from the sensor.
> 
> For example will a sensor outputting YUV pixel format frames, only
> allow the VFE to dump those frames as they are received by the ISP
> to memory through the RDI interface.
> 
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>   drivers/media/platform/qcom/camss/Makefile    |   1 +
>   .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
>   drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
>   drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
>   .../media/platform/qcom/camss/camss-video.c   | 100 +++
>   drivers/media/platform/qcom/camss/camss.c     |  61 ++
>   6 files changed, 1034 insertions(+), 20 deletions(-)
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
> 
> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> index 940c0ae3e003..052c4f405fa3 100644
> --- a/drivers/media/platform/qcom/camss/Makefile
> +++ b/drivers/media/platform/qcom/camss/Makefile
> @@ -11,6 +11,7 @@ qcom-camss-objs += \
>   		camss-vfe-4-1.o \
>   		camss-vfe-4-7.o \
>   		camss-vfe-4-8.o \
> +		camss-vfe-170.o \
>   		camss-vfe-gen1.o \
>   		camss-vfe.o \
>   		camss-video.o \
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> new file mode 100644
> index 000000000000..89b6c47cca22
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> @@ -0,0 +1,808 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-4-7.c
> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7

- the above two lines aren't updated to vfe-170

> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2018 Linaro Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +
> +#define VFE_HW_VERSION				(0x000)
> +
> +#define VFE_GLOBAL_RESET_CMD			(0x018)
> +#define		GLOBAL_RESET_CMD_CORE		BIT(0)
> +#define		GLOBAL_RESET_CMD_CAMIF		BIT(1)
> +#define		GLOBAL_RESET_CMD_BUS		BIT(2)
> +#define		GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
> +#define		GLOBAL_RESET_CMD_REGISTER	BIT(4)
> +#define		GLOBAL_RESET_CMD_PM		BIT(5)
> +#define		GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
> +#define		GLOBAL_RESET_CMD_TESTGEN	BIT(7)
> +#define		GLOBAL_RESET_CMD_DSP		BIT(8)
> +#define		GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
> +
> +#define VFE_CORE_CFG				(0x050)
> +#define		CFG_PIXEL_PATTERN_YCBYCR	(0x4)
> +#define		CFG_PIXEL_PATTERN_YCRYCB	(0x5)
> +#define		CFG_PIXEL_PATTERN_CBYCRY	(0x6)
> +#define		CFG_PIXEL_PATTERN_CRYCBY	(0x7)
> +#define		CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
> +
> +#define VFE_IRQ_CMD				(0x058)
> +#define		CMD_GLOBAL_CLEAR		BIT(0)
> +
> +#define VFE_IRQ_MASK_0					(0x05c)
> +#define		MASK_0_CAMIF_SOF			BIT(0)
> +#define		MASK_0_CAMIF_EOF			BIT(1)
> +#define		MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define		MASK_0_line_n_REG_UPDATE(n)		\
> +			((n) == VFE_LINE_PIX ? \
> +				BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
> +#define		MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define		MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define		MASK_0_RESET_ACK			BIT(31)
> +
> +#define VFE_IRQ_MASK_1					(0x060)
> +#define		MASK_1_CAMIF_ERROR			BIT(0)
> +#define		MASK_1_VIOLATION			BIT(7)
> +#define		MASK_1_BUS_BDG_HALT_ACK			BIT(8)
> +#define		MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
> +#define		MASK_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_IRQ_CLEAR_0					(0x064)
> +#define VFE_IRQ_CLEAR_1					(0x068)
> +
> +#define VFE_IRQ_STATUS_0				(0x06c)
> +#define		STATUS_0_CAMIF_SOF			BIT(0)
> +#define		STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define		STATUS_0_line_n_REG_UPDATE(n)		\
> +			((n) == VFE_LINE_PIX ? \
> +				BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
> +#define		STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define		STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define		STATUS_0_RESET_ACK			BIT(31)
> +
> +#define VFE_IRQ_STATUS_1				(0x070)
> +#define		STATUS_1_VIOLATION			BIT(7)
> +#define		STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define		STATUS_1_RDIn_SOF(n)			BIT((n) + 27)
> +
> +#define VFE_VIOLATION_STATUS			(0x07c)
> +
> +#define VFE_CAMIF_CMD				(0x478)
> +#define		CMD_CLEAR_CAMIF_STATUS		BIT(2)
> +
> +#define VFE_CAMIF_CFG				(0x47c)
> +#define		CFG_VSYNC_SYNC_EDGE		(0)
> +#define			VSYNC_ACTIVE_HIGH	(0)
> +#define			VSYNC_ACTIVE_LOW	(1)
> +#define		CFG_HSYNC_SYNC_EDGE		(1)
> +#define			HSYNC_ACTIVE_HIGH	(0)
> +#define			HSYNC_ACTIVE_LOW	(1)
> +#define		CFG_VFE_SUBSAMPLE_ENABLE	BIT(4)
> +#define		CFG_BUS_SUBSAMPLE_ENABLE	BIT(5)
> +#define		CFG_VFE_OUTPUT_EN		BIT(6)
> +#define		CFG_BUS_OUTPUT_EN		BIT(7)
> +#define		CFG_BINNING_EN			BIT(9)
> +#define		CFG_FRAME_BASED_EN		BIT(10)
> +#define		CFG_RAW_CROP_EN			BIT(22)
> +
> +// XXX different, don't exist in TITAN register docs
> +#define VFE_0_CAMIF_FRAME_CFG			0x484
> +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
> +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
> +#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
> +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
> +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
> +#define VFE_0_CAMIF_STATUS			0x4a4
> +#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
> +#define CAMIF_TIMEOUT_SLEEP_US 1000
> +#define CAMIF_TIMEOUT_ALL_US 1000000
> +
> +#define VFE_REG_UPDATE_CMD			(0x4ac)
> +#define		REG_UPDATE_RDIn(n)		BIT(1 + (n))
> +#define		REG_UPDATE_line_n(n)		\
> +			((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
> +
> +
> +#define VFE_BUS_IRQ_MASK(n)		(0x2044 + (n) * 4)
> +#define VFE_BUS_IRQ_CLEAR(n)		(0x2050 + (n) * 4)
> +
> +#define VFE_BUS_IRQ_STATUS(n)		(0x205c + (n) * 4)
> +#define		STATUS0_COMP_RESET_DONE		BIT(0)
> +#define		STATUS0_COMP_REG_UPDATE0_DONE	BIT(1)
> +#define		STATUS0_COMP_REG_UPDATE1_DONE	BIT(2)
> +#define		STATUS0_COMP_REG_UPDATE2_DONE	BIT(3)
> +#define		STATUS0_COMP_REG_UPDATE3_DONE	BIT(4)
> +#define		STATUS0_COMP_REG_UPDATE_DONE(n)	BIT(n + 1)
> +#define		STATUS0_COMP0_BUF_DONE		BIT(5)
> +#define		STATUS0_COMP1_BUF_DONE		BIT(6)
> +#define		STATUS0_COMP2_BUF_DONE		BIT(7)
> +#define		STATUS0_COMP3_BUF_DONE		BIT(8)
> +#define		STATUS0_COMP4_BUF_DONE		BIT(9)
> +#define		STATUS0_COMP5_BUF_DONE		BIT(10)
> +#define		STATUS0_COMP_BUF_DONE(n)	BIT(n + 5)
> +#define		STATUS0_COMP_ERROR		BIT(11)
> +#define		STATUS0_COMP_OVERWRITE		BIT(12)
> +#define		STATUS0_OVERFLOW		BIT(13)
> +#define		STATUS0_VIOLATION		BIT(14)
> +/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
> +#define		STATUS1_WM_CLIENT_BUF_DONE(n)		BIT(n)
> +#define		STATUS1_EARLY_DONE			BIT(24)
> +#define		STATUS2_DUAL_COMP0_BUF_DONE		BIT(0)
> +#define		STATUS2_DUAL_COMP1_BUF_DONE		BIT(1)
> +#define		STATUS2_DUAL_COMP2_BUF_DONE		BIT(2)
> +#define		STATUS2_DUAL_COMP3_BUF_DONE		BIT(3)
> +#define		STATUS2_DUAL_COMP4_BUF_DONE		BIT(4)
> +#define		STATUS2_DUAL_COMP5_BUF_DONE		BIT(5)
> +#define		STATUS2_DUAL_COMP_BUF_DONE(n)		BIT(n)
> +#define		STATUS2_DUAL_COMP_ERROR			BIT(6)
> +#define		STATUS2_DUAL_COMP_OVERWRITE		BIT(7)
> +
> +#define VFE_BUS_IRQ_CLEAR_GLOBAL		(0x2068)
> +
> +#define VFE_BUS_WM_DEBUG_STATUS_CFG		(0x226c)
> +#define		DEBUG_STATUS_CFG_STATUS0(n)	BIT(n)
> +#define		DEBUG_STATUS_CFG_STATUS1(n)	BIT(8+n)
> +
> +#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER	(0x2080)
> +
> +#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC		(0x2084)
> +#define		BUS_VER2_MAX_CLIENTS (24)
> +#define		WM_ADDR_NO_SYNC_DEFAULT_VAL \
> +				((1 << BUS_VER2_MAX_CLIENTS) - 1)
> +
> +#define VFE_BUS_WM_CGC_OVERRIDE			(0x200c)
> +#define		WM_CGC_OVERRIDE_ALL		(0xFFFFF)
> +
> +#define VFE_BUS_WM_TEST_BUS_CTRL		(0x211c)
> +
> +#define VFE_BUS_WM_STATUS0(n)			(0x2200 + (n) * 0x100)
> +#define VFE_BUS_WM_STATUS1(n)			(0x2204 + (n) * 0x100)
> +#define VFE_BUS_WM_CFG(n)			(0x2208 + (n) * 0x100)
> +#define		WM_CFG_EN			(0)
> +#define		WM_CFG_MODE			(1)
> +#define			MODE_QCOM_PLAIN	(0)
> +#define			MODE_MIPI_RAW	(1)
> +#define		WM_CFG_VIRTUALFRAME		(2)
> +#define VFE_BUS_WM_HEADER_ADDR(n)		(0x220c + (n) * 0x100)
> +#define VFE_BUS_WM_HEADER_CFG(n)		(0x2210 + (n) * 0x100)
> +#define VFE_BUS_WM_IMAGE_ADDR(n)		(0x2214 + (n) * 0x100)
> +#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)		(0x2218 + (n) * 0x100)
> +#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)		(0x221c + (n) * 0x100)
> +#define		WM_BUFFER_DEFAULT_WIDTH		(0xFF01)
> +
> +#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)		(0x2220 + (n) * 0x100)
> +#define VFE_BUS_WM_PACKER_CFG(n)		(0x2224 + (n) * 0x100)
> +
> +#define VFE_BUS_WM_STRIDE(n)			(0x2228 + (n) * 0x100)
> +#define		WM_STRIDE_DEFAULT_STRIDE	(0xFF01)
> +
> +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)	(0x2248 + (n) * 0x100)
> +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)	(0x224c + (n) * 0x100)
> +#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)		(0x2250 + (n) * 0x100)
> +#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)		(0x2254 + (n) * 0x100)
> +#define VFE_BUS_WM_FRAME_INC(n)			(0x2258 + (n) * 0x100)
> +#define VFE_BUS_WM_BURST_LIMIT(n)		(0x225c + (n) * 0x100)
> +
> +
> +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
> +
> +	u32 gen = (hw_version >> 28) & 0xF;
> +	u32 rev = (hw_version >> 16) & 0xFFF;
> +	u32 step = hw_version & 0xFFFF;
> +
> +	dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
> +}
> +
> +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> +}
> +
> +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits | set_bits, vfe->base + reg);
> +}
> +
> +static void vfe_global_reset(struct vfe_device *vfe)
> +{
> +	u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC	|
> +			 GLOBAL_RESET_CMD_DSP		|
> +			 GLOBAL_RESET_CMD_TESTGEN	|
> +			 GLOBAL_RESET_CMD_BUS_MISR	|
> +			 GLOBAL_RESET_CMD_PM		|
> +			 GLOBAL_RESET_CMD_REGISTER	|
> +			 GLOBAL_RESET_CMD_BUS_BDG	|
> +			 GLOBAL_RESET_CMD_BUS		|
> +			 GLOBAL_RESET_CMD_CAMIF		|
> +			 GLOBAL_RESET_CMD_CORE;

- the above settings are overwritten by this assignment:

> +	reset_bits = 0x00003F9F;
> +
> +	writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
> +
> +	/* Make sure IRQ mask has been written before resetting */
> +	wmb();
> +
> +	writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
> +}
> +
> +static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
> +{
> +	u32 val;
> +
> +	/*Set Debug Registers*/
> +	val = DEBUG_STATUS_CFG_STATUS0(1) |
> +	      DEBUG_STATUS_CFG_STATUS0(7);
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
> +
> +	/* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
> +	writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
> +
> +	/* no clock gating at bus input */
> +	val = WM_CGC_OVERRIDE_ALL;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
> +
> +	writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
> +
> +	/* if addr_no_sync has default value then config the addr no sync reg */
> +	val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
> +
> +	writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
> +
> +	val = WM_BUFFER_DEFAULT_WIDTH;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
> +
> +	val = 0;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
> +
> +	val = 0;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?

- C++ style comment

   Also here and in several comments below you use the XXX tag which looks
   more confusing than helpful for me. Would it be possible to expand such comments
   to make them more explicit? Just a nitpick though.

> +
> +	/* Configure stride for RDIs */
> +	//val = pix->plane_fmt[0].bytesperline;

- the commented out line should probably be removed. Or changed into real
   comment.

Thanks,
Andrey

> +	val = WM_STRIDE_DEFAULT_STRIDE;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
> +
> +	/* Enable WM */
> +	val = 1 << WM_CFG_EN |
> +	      MODE_MIPI_RAW << WM_CFG_MODE;
> +	writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
> +}
> +
> +static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
> +{
> +	/* Disable WM */
> +	writel_relaxed(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)
> +{
> +	/* XXX use cmdbuf for this ?? */
> +	struct v4l2_pix_format_mplane *pix =
> +		&line->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));
> +	writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
> +
> +	/* XXX enable wm ? */
> +}
> +
> +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	vfe->reg_update |= REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce ordering between previous reg writes and reg update */
> +	wmb();
> +
> +	writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
> +
> +	/* Enforce ordering between reg update and subsequent reg writes */
> +	wmb();
> +}
> +
> +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> +					enum vfe_line_id line_id)
> +{
> +	vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
> +}
> +
> +static void vfe_enable_irq_common(struct vfe_device *vfe)
> +{
> +	vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
> +	vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
> +
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
> +	writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
> +}
> +
> +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> +{
> +	complete(&vfe->halt_complete);
> +}
> +
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
> +{
> +	*status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> +	*status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> +
> +	writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
> +	writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
> +
> +	/* Enforce ordering between IRQ Clear and Global IRQ Clear */
> +	wmb();
> +	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> +}
> +
> +static void vfe_violation_read(struct vfe_device *vfe)
> +{
> +	u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
> +
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> +}
> +
> +/*
> + * vfe_isr - VFE module interrupt handler
> + * @irq: Interrupt line
> + * @dev: VFE device
> + *
> + * Return IRQ_HANDLED on success
> + */
> +static irqreturn_t vfe_isr(int irq, void *dev)
> +{
> +	struct vfe_device *vfe = dev;
> +	u32 status0, status1, vfe_bus_status[3];
> +	int i, wm;
> +
> +	status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> +	status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> +
> +	writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
> +	writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
> +		vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
> +		writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
> +	}
> +
> +	/* Enforce ordering between IRQ reading and interpretation */
> +	wmb();
> +
> +	writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> +	writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
> +
> +	if (status0 & STATUS_0_RESET_ACK)
> +		vfe->isr_ops.reset_ack(vfe);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> +		if (status0 & STATUS_0_line_n_REG_UPDATE(i))
> +			vfe->isr_ops.reg_update(vfe, i);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> +		if (status0 & STATUS_1_RDIn_SOF(i))
> +			vfe->isr_ops.sof(vfe, i);
> +
> +	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> +		if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
> +			vfe->isr_ops.comp_done(vfe, i);
> +
> +	for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
> +		if (status0 & BIT(9))
> +			if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
> +				vfe->isr_ops.wm_done(vfe, wm);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * vfe_halt - Trigger halt on VFE module and wait to complete
> + * @vfe: VFE device
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_halt(struct vfe_device *vfe)
> +{
> +	unsigned long time;
> +
> +	return 0;
> +
> +	reinit_completion(&vfe->halt_complete);
> +
> +	time = wait_for_completion_timeout(&vfe->halt_complete,
> +		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> +	if (!time) {
> +		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +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;
> +	unsigned long flags;
> +	int i;
> +	int wm_idx;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output = &line->output;
> +	if (output->state != VFE_OUTPUT_OFF) {
> +		dev_err(vfe->camss->dev, "Output is running\n");
> +		goto error;
> +	}
> +
> +	switch (f->fmt.pix_mp.pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		output->wm_num = 2;
> +		break;
> +	default:
> +		output->wm_num = 1;
> +		break;
> +	}
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		wm_idx = vfe_reserve_wm(vfe, line->id);
> +		if (wm_idx < 0) {
> +			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> +			goto error_get_wm;
> +		}
> +		output->wm_idx[i] = wm_idx;
> +	}
> +
> +	output->drop_update_idx = 0;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +
> +error_get_wm:
> +	for (i--; i >= 0; i--)
> +		vfe_release_wm(vfe, output->wm_idx[i]);
> +	output->state = VFE_OUTPUT_OFF;
> +error:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return -EINVAL;
> +}
> +
> +static int vfe_enable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	struct media_entity *sensor;
> +	unsigned long flags;
> +	unsigned int frame_skip = 0;
> +	unsigned int i;
> +
> +	sensor = camss_find_sensor(&line->subdev.entity);
> +	if (sensor) {
> +		struct v4l2_subdev *subdev =
> +					media_entity_to_v4l2_subdev(sensor);
> +
> +		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_OFF) {
> +		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
> +			output->state);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		return -EINVAL;
> +	}
> +
> +	WARN_ON(output->gen2.active_num);
> +
> +	output->state = VFE_OUTPUT_ON;
> +
> +	output->sequence = 0;
> +	output->wait_reg_update = 0;
> +	reinit_completion(&output->reg_update);
> +
> +	if (line->id != VFE_LINE_PIX)
> +		vfe_wm_start(vfe, output->wm_idx[0], line);
> +
> +	for (i = 0; i < 2; i++) {
> +		output->buf[i] = vfe_buf_get_pending(output);
> +		if (!output->buf[i])
> +			break;
> +		output->gen2.active_num++;
> +		vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
> +	}
> +
> +	ops->reg_update(vfe, line->id);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +static int vfe_disable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	unsigned long flags;
> +	unsigned int i;
> +	bool done;
> +	int timeout = 0;
> +
> +	do {
> +		spin_lock_irqsave(&vfe->output_lock, flags);
> +		done = !output->gen2.active_num;
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		usleep_range(10000, 20000);
> +
> +		if (timeout++ == 100) {
> +			dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
> +			vfe_reset(vfe);
> +			output->gen2.active_num = 0;
> +			return 0;
> +		}
> +	} while (!done);
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	for (i = 0; i < output->wm_num; i++)
> +		vfe_wm_stop(vfe, output->wm_idx[i]);
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_enable - Enable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_enable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	int ret;
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (!vfe->stream_count)
> +		vfe_enable_irq_common(vfe);
> +
> +	vfe->stream_count++;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	ret = vfe_get_output(line);
> +	if (ret < 0)
> +		goto error_get_output;
> +
> +	ret = vfe_enable_output(line);
> +	if (ret < 0)
> +		goto error_enable_output;
> +
> +	vfe->was_streaming = 1;
> +
> +	return 0;
> +
> +
> +error_enable_output:
> +	vfe_put_output(line);
> +
> +error_get_output:
> +	mutex_lock(&vfe->stream_lock);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return ret;
> +}
> +
> +/*
> + * vfe_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_disable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +
> +	vfe_disable_output(line);
> +
> +	vfe_put_output(line);
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_isr_sof - Process start of frame interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +
> +}
> +
> +/*
> + * vfe_isr_reg_update - Process reg update interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	vfe->ops->reg_update_clear(vfe, line_id);
> +
> +	output = &vfe->line[line_id].output;
> +
> +	if (output->wait_reg_update) {
> +		output->wait_reg_update = 0;
> +		complete(&output->reg_update);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_wm_done - Process write master done interrupt
> + * @vfe: VFE Device
> + * @wm: Write master id
> + */
> +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> +{
> +	struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
> +	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;
> +
> +	ready_buf = output->buf[0];
> +	if (!ready_buf) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Missing ready buf %d!\n", output->state);
> +		goto out_unlock;
> +	}
> +
> +	ready_buf->vb.vb2_buf.timestamp = ts;
> +	ready_buf->vb.sequence = output->sequence++;
> +
> +	index = 0;
> +	output->buf[0] = output->buf[1];
> +	if (output->buf[0])
> +		index = 1;
> +
> +	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);
> +	else
> +		output->gen2.active_num--;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +	return;
> +
> +out_unlock:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_queue_buffer - Add empty buffer
> + * @vid: Video device structure
> + * @buf: Buffer to be enqueued
> + *
> + * Add an empty buffer - depending on the current number of buffers it will be
> + * put in pending buffer queue or directly given to the hardware to be filled.
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +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_device *vfe = to_vfe(line);
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	output = &line->output;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
> +		output->buf[output->gen2.active_num++] = buf;
> +		vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
> +	} else {
> +		vfe_buf_add_pending(output, buf);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +const struct vfe_isr_ops vfe_isr_ops_170 = {
> +	.reset_ack = vfe_isr_reset_ack,
> +	.halt_ack = vfe_isr_halt_ack,
> +	.reg_update = vfe_isr_reg_update,
> +	.sof = vfe_isr_sof,
> +	.comp_done = vfe_isr_comp_done,
> +	.wm_done = vfe_isr_wm_done,
> +};
> +
> +static const struct camss_video_ops vfe_video_ops_170 = {
> +	.queue_buffer = vfe_queue_buffer,
> +	.flush_buffers = vfe_flush_buffers,
> +};
> +
> +static void vfe_subdev_init(struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_170;
> +	vfe->video_ops = vfe_video_ops_170;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_170 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
> +	.isr_read = vfe_isr_read,
> +	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_disable,
> +	.vfe_enable = vfe_enable,
> +	.vfe_halt = vfe_halt,
> +	.violation_read = vfe_violation_read,
> +};
> +
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index 2ffa5b3c5426..5a874b544391 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
>   	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
>   };
>   
> +static const struct vfe_format formats_rdi_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
> +	{ MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
> +	{ MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
> +	{ MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
> +	{ MEDIA_BUS_FMT_Y10_1X10, 10 },
> +	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
> +};
> +
> +static const struct vfe_format formats_pix_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> +};
> +
>   /*
>    * vfe_get_bpp - map media bus format to bits per pixel
>    * @formats: supported media bus formats array
> @@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
>   			return sink_code;
>   		}
>   	else if (vfe->camss->version == CAMSS_8x96 ||
> -		 vfe->camss->version == CAMSS_660)
> +		 vfe->camss->version == CAMSS_660 ||
> +		 vfe->camss->version == CAMSS_845)
>   		switch (sink_code) {
>   		case MEDIA_BUS_FMT_YUYV8_2X8:
>   		{
> @@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
>   		return 0;
>   }
>   
> -/*
> - * vfe_reset - Trigger reset on VFE module and wait to complete
> - * @vfe: VFE device
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_reset(struct vfe_device *vfe)
> +int vfe_reset(struct vfe_device *vfe)
>   {
>   	unsigned long time;
>   
> @@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
>   		struct camss_clock *clock = &vfe->clock[i];
>   
>   		if (!strcmp(clock->name, "vfe0") ||
> -		    !strcmp(clock->name, "vfe1")) {
> +		    !strcmp(clock->name, "vfe1") ||
> +		    !strcmp(clock->name, "vfe_lite")) {
>   			u64 min_rate = 0;
>   			long rate;
>   
> @@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	case CAMSS_660:
>   		vfe->ops = &vfe_ops_4_8;
>   		break;
> +
> +	case CAMSS_845:
> +		vfe->ops = &vfe_ops_170;
> +		break;
>   	default:
>   		return -EINVAL;
>   	}
> @@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   				l->formats = formats_rdi_8x96;
>   				l->nformats = ARRAY_SIZE(formats_rdi_8x96);
>   			}
> +		} else if (camss->version == CAMSS_845) {
> +			if (i == VFE_LINE_PIX) {
> +				l->formats = formats_pix_845;
> +				l->nformats = ARRAY_SIZE(formats_pix_845);
> +			} else {
> +				l->formats = formats_rdi_845;
> +				l->nformats = ARRAY_SIZE(formats_rdi_845);
> +			}
>   		} else {
>   			return -EINVAL;
>   		}
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> index 8629c833f130..a0b618c9cec8 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> @@ -19,7 +19,6 @@
>   #include "camss-video.h"
>   #include "camss-vfe-gen1.h"
>   
> -
>   #define MSM_VFE_PAD_SINK 0
>   #define MSM_VFE_PAD_SRC 1
>   #define MSM_VFE_PADS_NUM 2
> @@ -39,14 +38,14 @@
>   #define to_vfe(ptr_line)	\
>   	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
>   
> -
>   enum vfe_output_state {
>   	VFE_OUTPUT_OFF,
>   	VFE_OUTPUT_RESERVED,
>   	VFE_OUTPUT_SINGLE,
>   	VFE_OUTPUT_CONTINUOUS,
>   	VFE_OUTPUT_IDLE,
> -	VFE_OUTPUT_STOPPING
> +	VFE_OUTPUT_STOPPING,
> +	VFE_OUTPUT_ON,
>   };
>   
>   enum vfe_line_id {
> @@ -72,6 +71,9 @@ struct vfe_output {
>   			int active_buf;
>   			int wait_sof;
>   		} gen1;
> +		struct {
> +			int active_num;
> +		} gen2;
>   	};
>   	enum vfe_output_state state;
>   	unsigned int sequence;
> @@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
>   
>   struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
>   
> -/*
> - * vfe_disable - Disable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -int vfe_disable(struct vfe_line *line);
> -
>   int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
>   
>   /*
> @@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
>   int vfe_release_wm(struct vfe_device *vfe, u8 wm);
>   int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
>   
> +/*
> + * vfe_reset - Trigger reset on VFE module and wait to complete
> + * @vfe: VFE device
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_reset(struct vfe_device *vfe);
> +
>   extern const struct vfe_hw_ops vfe_ops_4_1;
>   extern const struct vfe_hw_ops vfe_ops_4_7;
>   extern const struct vfe_hw_ops vfe_ops_4_8;
> +extern const struct vfe_hw_ops vfe_ops_170;
>   
>   #endif /* QC_MSM_CAMSS_VFE_H */
> diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
> index bd9334af1c73..b4943df9eaf6 100644
> --- a/drivers/media/platform/qcom/camss/camss-video.c
> +++ b/drivers/media/platform/qcom/camss/camss-video.c
> @@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
>   	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
>   };
>   
> +static const struct camss_format_info formats_rdi_845[] = {
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> +	{ MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> +	{ MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> +	{ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +};
> +
>   static const struct camss_format_info formats_pix_8x16[] = {
>   	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
>   	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> @@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
>   	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
>   };
>   
> +static const struct camss_format_info formats_pix_845[] = {
> +	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> +	  { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
> +	  { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> +	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +	{ MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> +	  { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> +};
> +
>   /* -----------------------------------------------------------------------------
>    * Helper functions
>    */
> @@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
>   			video->formats = formats_rdi_8x96;
>   			video->nformats = ARRAY_SIZE(formats_rdi_8x96);
>   		}
> +	}  else if (video->camss->version == CAMSS_845) {
> +		if (is_pix) {
> +			video->formats = formats_pix_845;
> +			video->nformats = ARRAY_SIZE(formats_pix_845);
> +		} else {
> +			video->formats = formats_rdi_845;
> +			video->nformats = ARRAY_SIZE(formats_rdi_845);
> +		}
>   	} else {
>   		goto error_video_register;
>   	}
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index aeec59bc6194..1c3d64d612ff 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
>   	}
>   };
>   
> +static const struct resources vfe_res_845[] = {
> +	/* VFE0 */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe0", "vfe0_axi",
> +				"vfe0_src", "csi0",
> +				"csi0_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 0 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe0" },
> +		.interrupt = { "vfe0" }
> +	},
> +
> +	/* VFE1 */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe1", "vfe1_axi",
> +				"vfe1_src", "csi1",
> +				"csi1_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 0 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe1" },
> +		.interrupt = { "vfe1" }
> +	},
> +
> +	/* VFE-lite */
> +	{
> +		.regulator = { NULL },
> +		.clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> +				"soc_ahb", "vfe_lite",
> +				"vfe_lite_src", "csi2",
> +				"csi2_src"},
> +		.clock_rate = { { 0 },
> +				{ 0 },
> +				{ 80000000 },
> +				{ 0 },
> +				{ 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> +				{ 320000000 },
> +				{ 19200000, 75000000, 384000000, 538666667 },
> +				{ 384000000 } },
> +		.reg = { "vfe_lite" },
> +		.interrupt = { "vfe_lite" }
> +	}
> +};
> +
>   /*
>    * camss_add_clock_margin - Add margin to clock frequency rate
>    * @rate: Clock frequency rate
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
  2021-01-14 10:48     ` Andrey Konovalov
@ 2021-01-14 12:07       ` Robert Foss
  -1 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-14 12:07 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: Andy Gross, Bjorn Andersson, Todor Tomov, Mauro Carvalho Chehab,
	Rob Herring, catalin.marinas, will, shawnguo, leoyang.li,
	geert+renesas, arnd, Anson.Huang, michael, agx, max.oss.09,
	linux-arm-msm, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	AngeloGioacchino Del Regno, Tomasz Figa,
	Azam Sadiq Pasha Kapatrala Syed, Sarvesh Sridutt,
	Laurent Pinchart

On Thu, 14 Jan 2021 at 11:48, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>
> Hi Robert,
>
> Thank you for the patch!
>
> On 08.01.2021 15:04, Robert Foss wrote:
> > Add register definitions for version 170 of the Titan architecture
> > and implement support for the RDI output mode.
> >
> > The RDI mode as opposed to the PIX output mode for the VFE unit does
> > not support any ISP functionality. This means essentially only
> > supporting dumping the output of the whatever the CSI decoder receives
> > from the sensor.
> >
> > For example will a sensor outputting YUV pixel format frames, only
> > allow the VFE to dump those frames as they are received by the ISP
> > to memory through the RDI interface.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >   drivers/media/platform/qcom/camss/Makefile    |   1 +
> >   .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
> >   drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
> >   drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
> >   .../media/platform/qcom/camss/camss-video.c   | 100 +++
> >   drivers/media/platform/qcom/camss/camss.c     |  61 ++
> >   6 files changed, 1034 insertions(+), 20 deletions(-)
> >   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
> >
> > diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> > index 940c0ae3e003..052c4f405fa3 100644
> > --- a/drivers/media/platform/qcom/camss/Makefile
> > +++ b/drivers/media/platform/qcom/camss/Makefile
> > @@ -11,6 +11,7 @@ qcom-camss-objs += \
> >               camss-vfe-4-1.o \
> >               camss-vfe-4-7.o \
> >               camss-vfe-4-8.o \
> > +             camss-vfe-170.o \
> >               camss-vfe-gen1.o \
> >               camss-vfe.o \
> >               camss-video.o \
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> > new file mode 100644
> > index 000000000000..89b6c47cca22
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> > @@ -0,0 +1,808 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * camss-vfe-4-7.c
> > + *
> > + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
>
> - the above two lines aren't updated to vfe-170
>
> > + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> > + * Copyright (C) 2015-2018 Linaro Ltd.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +
> > +#include "camss.h"
> > +#include "camss-vfe.h"
> > +
> > +#define VFE_HW_VERSION                               (0x000)
> > +
> > +#define VFE_GLOBAL_RESET_CMD                 (0x018)
> > +#define              GLOBAL_RESET_CMD_CORE           BIT(0)
> > +#define              GLOBAL_RESET_CMD_CAMIF          BIT(1)
> > +#define              GLOBAL_RESET_CMD_BUS            BIT(2)
> > +#define              GLOBAL_RESET_CMD_BUS_BDG        BIT(3)
> > +#define              GLOBAL_RESET_CMD_REGISTER       BIT(4)
> > +#define              GLOBAL_RESET_CMD_PM             BIT(5)
> > +#define              GLOBAL_RESET_CMD_BUS_MISR       BIT(6)
> > +#define              GLOBAL_RESET_CMD_TESTGEN        BIT(7)
> > +#define              GLOBAL_RESET_CMD_DSP            BIT(8)
> > +#define              GLOBAL_RESET_CMD_IDLE_CGC       BIT(9)
> > +
> > +#define VFE_CORE_CFG                         (0x050)
> > +#define              CFG_PIXEL_PATTERN_YCBYCR        (0x4)
> > +#define              CFG_PIXEL_PATTERN_YCRYCB        (0x5)
> > +#define              CFG_PIXEL_PATTERN_CBYCRY        (0x6)
> > +#define              CFG_PIXEL_PATTERN_CRYCBY        (0x7)
> > +#define              CFG_COMPOSITE_REG_UPDATE_EN     BIT(4)
> > +
> > +#define VFE_IRQ_CMD                          (0x058)
> > +#define              CMD_GLOBAL_CLEAR                BIT(0)
> > +
> > +#define VFE_IRQ_MASK_0                                       (0x05c)
> > +#define              MASK_0_CAMIF_SOF                        BIT(0)
> > +#define              MASK_0_CAMIF_EOF                        BIT(1)
> > +#define              MASK_0_RDIn_REG_UPDATE(n)               BIT((n) + 5)
> > +#define              MASK_0_line_n_REG_UPDATE(n)             \
> > +                     ((n) == VFE_LINE_PIX ? \
> > +                             BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
> > +#define              MASK_0_IMAGE_MASTER_n_PING_PONG(n)      BIT((n) + 8)
> > +#define              MASK_0_IMAGE_COMPOSITE_DONE_n(n)        BIT((n) + 25)
> > +#define              MASK_0_RESET_ACK                        BIT(31)
> > +
> > +#define VFE_IRQ_MASK_1                                       (0x060)
> > +#define              MASK_1_CAMIF_ERROR                      BIT(0)
> > +#define              MASK_1_VIOLATION                        BIT(7)
> > +#define              MASK_1_BUS_BDG_HALT_ACK                 BIT(8)
> > +#define              MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)   BIT((n) + 9)
> > +#define              MASK_1_RDIn_SOF(n)                      BIT((n) + 29)
> > +
> > +#define VFE_IRQ_CLEAR_0                                      (0x064)
> > +#define VFE_IRQ_CLEAR_1                                      (0x068)
> > +
> > +#define VFE_IRQ_STATUS_0                             (0x06c)
> > +#define              STATUS_0_CAMIF_SOF                      BIT(0)
> > +#define              STATUS_0_RDIn_REG_UPDATE(n)             BIT((n) + 5)
> > +#define              STATUS_0_line_n_REG_UPDATE(n)           \
> > +                     ((n) == VFE_LINE_PIX ? \
> > +                             BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
> > +#define              STATUS_0_IMAGE_MASTER_n_PING_PONG(n)    BIT((n) + 8)
> > +#define              STATUS_0_IMAGE_COMPOSITE_DONE_n(n)      BIT((n) + 25)
> > +#define              STATUS_0_RESET_ACK                      BIT(31)
> > +
> > +#define VFE_IRQ_STATUS_1                             (0x070)
> > +#define              STATUS_1_VIOLATION                      BIT(7)
> > +#define              STATUS_1_BUS_BDG_HALT_ACK               BIT(8)
> > +#define              STATUS_1_RDIn_SOF(n)                    BIT((n) + 27)
> > +
> > +#define VFE_VIOLATION_STATUS                 (0x07c)
> > +
> > +#define VFE_CAMIF_CMD                                (0x478)
> > +#define              CMD_CLEAR_CAMIF_STATUS          BIT(2)
> > +
> > +#define VFE_CAMIF_CFG                                (0x47c)
> > +#define              CFG_VSYNC_SYNC_EDGE             (0)
> > +#define                      VSYNC_ACTIVE_HIGH       (0)
> > +#define                      VSYNC_ACTIVE_LOW        (1)
> > +#define              CFG_HSYNC_SYNC_EDGE             (1)
> > +#define                      HSYNC_ACTIVE_HIGH       (0)
> > +#define                      HSYNC_ACTIVE_LOW        (1)
> > +#define              CFG_VFE_SUBSAMPLE_ENABLE        BIT(4)
> > +#define              CFG_BUS_SUBSAMPLE_ENABLE        BIT(5)
> > +#define              CFG_VFE_OUTPUT_EN               BIT(6)
> > +#define              CFG_BUS_OUTPUT_EN               BIT(7)
> > +#define              CFG_BINNING_EN                  BIT(9)
> > +#define              CFG_FRAME_BASED_EN              BIT(10)
> > +#define              CFG_RAW_CROP_EN                 BIT(22)
> > +
> > +// XXX different, don't exist in TITAN register docs
> > +#define VFE_0_CAMIF_FRAME_CFG                        0x484
> > +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG         0x488
> > +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG                0x48c
> > +#define VFE_0_CAMIF_SUBSAMPLE_CFG            0x490
> > +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN    0x498
> > +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN    0x49c
> > +#define VFE_0_CAMIF_STATUS                   0x4a4
> > +#define VFE_0_CAMIF_STATUS_HALT                      BIT(31)
> > +#define CAMIF_TIMEOUT_SLEEP_US 1000
> > +#define CAMIF_TIMEOUT_ALL_US 1000000
> > +
> > +#define VFE_REG_UPDATE_CMD                   (0x4ac)
> > +#define              REG_UPDATE_RDIn(n)              BIT(1 + (n))
> > +#define              REG_UPDATE_line_n(n)            \
> > +                     ((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
> > +
> > +
> > +#define VFE_BUS_IRQ_MASK(n)          (0x2044 + (n) * 4)
> > +#define VFE_BUS_IRQ_CLEAR(n)         (0x2050 + (n) * 4)
> > +
> > +#define VFE_BUS_IRQ_STATUS(n)                (0x205c + (n) * 4)
> > +#define              STATUS0_COMP_RESET_DONE         BIT(0)
> > +#define              STATUS0_COMP_REG_UPDATE0_DONE   BIT(1)
> > +#define              STATUS0_COMP_REG_UPDATE1_DONE   BIT(2)
> > +#define              STATUS0_COMP_REG_UPDATE2_DONE   BIT(3)
> > +#define              STATUS0_COMP_REG_UPDATE3_DONE   BIT(4)
> > +#define              STATUS0_COMP_REG_UPDATE_DONE(n) BIT(n + 1)
> > +#define              STATUS0_COMP0_BUF_DONE          BIT(5)
> > +#define              STATUS0_COMP1_BUF_DONE          BIT(6)
> > +#define              STATUS0_COMP2_BUF_DONE          BIT(7)
> > +#define              STATUS0_COMP3_BUF_DONE          BIT(8)
> > +#define              STATUS0_COMP4_BUF_DONE          BIT(9)
> > +#define              STATUS0_COMP5_BUF_DONE          BIT(10)
> > +#define              STATUS0_COMP_BUF_DONE(n)        BIT(n + 5)
> > +#define              STATUS0_COMP_ERROR              BIT(11)
> > +#define              STATUS0_COMP_OVERWRITE          BIT(12)
> > +#define              STATUS0_OVERFLOW                BIT(13)
> > +#define              STATUS0_VIOLATION               BIT(14)
> > +/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
> > +#define              STATUS1_WM_CLIENT_BUF_DONE(n)           BIT(n)
> > +#define              STATUS1_EARLY_DONE                      BIT(24)
> > +#define              STATUS2_DUAL_COMP0_BUF_DONE             BIT(0)
> > +#define              STATUS2_DUAL_COMP1_BUF_DONE             BIT(1)
> > +#define              STATUS2_DUAL_COMP2_BUF_DONE             BIT(2)
> > +#define              STATUS2_DUAL_COMP3_BUF_DONE             BIT(3)
> > +#define              STATUS2_DUAL_COMP4_BUF_DONE             BIT(4)
> > +#define              STATUS2_DUAL_COMP5_BUF_DONE             BIT(5)
> > +#define              STATUS2_DUAL_COMP_BUF_DONE(n)           BIT(n)
> > +#define              STATUS2_DUAL_COMP_ERROR                 BIT(6)
> > +#define              STATUS2_DUAL_COMP_OVERWRITE             BIT(7)
> > +
> > +#define VFE_BUS_IRQ_CLEAR_GLOBAL             (0x2068)
> > +
> > +#define VFE_BUS_WM_DEBUG_STATUS_CFG          (0x226c)
> > +#define              DEBUG_STATUS_CFG_STATUS0(n)     BIT(n)
> > +#define              DEBUG_STATUS_CFG_STATUS1(n)     BIT(8+n)
> > +
> > +#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER    (0x2080)
> > +
> > +#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC         (0x2084)
> > +#define              BUS_VER2_MAX_CLIENTS (24)
> > +#define              WM_ADDR_NO_SYNC_DEFAULT_VAL \
> > +                             ((1 << BUS_VER2_MAX_CLIENTS) - 1)
> > +
> > +#define VFE_BUS_WM_CGC_OVERRIDE                      (0x200c)
> > +#define              WM_CGC_OVERRIDE_ALL             (0xFFFFF)
> > +
> > +#define VFE_BUS_WM_TEST_BUS_CTRL             (0x211c)
> > +
> > +#define VFE_BUS_WM_STATUS0(n)                        (0x2200 + (n) * 0x100)
> > +#define VFE_BUS_WM_STATUS1(n)                        (0x2204 + (n) * 0x100)
> > +#define VFE_BUS_WM_CFG(n)                    (0x2208 + (n) * 0x100)
> > +#define              WM_CFG_EN                       (0)
> > +#define              WM_CFG_MODE                     (1)
> > +#define                      MODE_QCOM_PLAIN (0)
> > +#define                      MODE_MIPI_RAW   (1)
> > +#define              WM_CFG_VIRTUALFRAME             (2)
> > +#define VFE_BUS_WM_HEADER_ADDR(n)            (0x220c + (n) * 0x100)
> > +#define VFE_BUS_WM_HEADER_CFG(n)             (0x2210 + (n) * 0x100)
> > +#define VFE_BUS_WM_IMAGE_ADDR(n)             (0x2214 + (n) * 0x100)
> > +#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)              (0x2218 + (n) * 0x100)
> > +#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)               (0x221c + (n) * 0x100)
> > +#define              WM_BUFFER_DEFAULT_WIDTH         (0xFF01)
> > +
> > +#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)              (0x2220 + (n) * 0x100)
> > +#define VFE_BUS_WM_PACKER_CFG(n)             (0x2224 + (n) * 0x100)
> > +
> > +#define VFE_BUS_WM_STRIDE(n)                 (0x2228 + (n) * 0x100)
> > +#define              WM_STRIDE_DEFAULT_STRIDE        (0xFF01)
> > +
> > +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)   (0x2248 + (n) * 0x100)
> > +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)  (0x224c + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)               (0x2250 + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)              (0x2254 + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAME_INC(n)                      (0x2258 + (n) * 0x100)
> > +#define VFE_BUS_WM_BURST_LIMIT(n)            (0x225c + (n) * 0x100)
> > +
> > +
> > +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> > +{
> > +     u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
> > +
> > +     u32 gen = (hw_version >> 28) & 0xF;
> > +     u32 rev = (hw_version >> 16) & 0xFFF;
> > +     u32 step = hw_version & 0xFFFF;
> > +
> > +     dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
> > +}
> > +
> > +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> > +}
> > +
> > +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits | set_bits, vfe->base + reg);
> > +}
> > +
> > +static void vfe_global_reset(struct vfe_device *vfe)
> > +{
> > +     u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC      |
> > +                      GLOBAL_RESET_CMD_DSP           |
> > +                      GLOBAL_RESET_CMD_TESTGEN       |
> > +                      GLOBAL_RESET_CMD_BUS_MISR      |
> > +                      GLOBAL_RESET_CMD_PM            |
> > +                      GLOBAL_RESET_CMD_REGISTER      |
> > +                      GLOBAL_RESET_CMD_BUS_BDG       |
> > +                      GLOBAL_RESET_CMD_BUS           |
> > +                      GLOBAL_RESET_CMD_CAMIF         |
> > +                      GLOBAL_RESET_CMD_CORE;
>
> - the above settings are overwritten by this assignment:
>
> > +     reset_bits = 0x00003F9F;
> > +
> > +     writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
> > +
> > +     /* Make sure IRQ mask has been written before resetting */
> > +     wmb();
> > +
> > +     writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
> > +}
> > +
> > +static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
> > +{
> > +     u32 val;
> > +
> > +     /*Set Debug Registers*/
> > +     val = DEBUG_STATUS_CFG_STATUS0(1) |
> > +           DEBUG_STATUS_CFG_STATUS0(7);
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
> > +
> > +     /* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
> > +     writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
> > +
> > +     /* no clock gating at bus input */
> > +     val = WM_CGC_OVERRIDE_ALL;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
> > +
> > +     writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
> > +
> > +     /* if addr_no_sync has default value then config the addr no sync reg */
> > +     val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
> > +
> > +     writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
> > +
> > +     val = WM_BUFFER_DEFAULT_WIDTH;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
> > +
> > +     val = 0;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
> > +
> > +     val = 0;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
>
> - C++ style comment
>
>    Also here and in several comments below you use the XXX tag which looks
>    more confusing than helpful for me. Would it be possible to expand such comments
>    to make them more explicit? Just a nitpick though.
>
> > +
> > +     /* Configure stride for RDIs */
> > +     //val = pix->plane_fmt[0].bytesperline;
>
> - the commented out line should probably be removed. Or changed into real
>    comment.

Will do! Thanks for finding this.

>
> Thanks,
> Andrey
>
> > +     val = WM_STRIDE_DEFAULT_STRIDE;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
> > +
> > +     /* Enable WM */
> > +     val = 1 << WM_CFG_EN |
> > +           MODE_MIPI_RAW << WM_CFG_MODE;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
> > +}
> > +
> > +static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
> > +{
> > +     /* Disable WM */
> > +     writel_relaxed(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)
> > +{
> > +     /* XXX use cmdbuf for this ?? */
> > +     struct v4l2_pix_format_mplane *pix =
> > +             &line->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));
> > +     writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
> > +
> > +     /* XXX enable wm ? */
> > +}
> > +
> > +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update |= REG_UPDATE_line_n(line_id);
> > +
> > +     /* Enforce ordering between previous reg writes and reg update */
> > +     wmb();
> > +
> > +     writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
> > +
> > +     /* Enforce ordering between reg update and subsequent reg writes */
> > +     wmb();
> > +}
> > +
> > +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> > +                                     enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
> > +}
> > +
> > +static void vfe_enable_irq_common(struct vfe_device *vfe)
> > +{
> > +     vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
> > +     vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
> > +
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
> > +}
> > +
> > +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> > +{
> > +     complete(&vfe->halt_complete);
> > +}
> > +
> > +static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
> > +{
> > +     *status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> > +     *status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> > +
> > +     writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
> > +     writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
> > +
> > +     /* Enforce ordering between IRQ Clear and Global IRQ Clear */
> > +     wmb();
> > +     writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> > +}
> > +
> > +static void vfe_violation_read(struct vfe_device *vfe)
> > +{
> > +     u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
> > +
> > +     pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> > +}
> > +
> > +/*
> > + * vfe_isr - VFE module interrupt handler
> > + * @irq: Interrupt line
> > + * @dev: VFE device
> > + *
> > + * Return IRQ_HANDLED on success
> > + */
> > +static irqreturn_t vfe_isr(int irq, void *dev)
> > +{
> > +     struct vfe_device *vfe = dev;
> > +     u32 status0, status1, vfe_bus_status[3];
> > +     int i, wm;
> > +
> > +     status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> > +     status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> > +
> > +     writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
> > +     writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
> > +             vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
> > +             writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
> > +     }
> > +
> > +     /* Enforce ordering between IRQ reading and interpretation */
> > +     wmb();
> > +
> > +     writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> > +     writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
> > +
> > +     if (status0 & STATUS_0_RESET_ACK)
> > +             vfe->isr_ops.reset_ack(vfe);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> > +             if (status0 & STATUS_0_line_n_REG_UPDATE(i))
> > +                     vfe->isr_ops.reg_update(vfe, i);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> > +             if (status0 & STATUS_1_RDIn_SOF(i))
> > +                     vfe->isr_ops.sof(vfe, i);
> > +
> > +     for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> > +             if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
> > +                     vfe->isr_ops.comp_done(vfe, i);
> > +
> > +     for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
> > +             if (status0 & BIT(9))
> > +                     if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
> > +                             vfe->isr_ops.wm_done(vfe, wm);
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +/*
> > + * vfe_halt - Trigger halt on VFE module and wait to complete
> > + * @vfe: VFE device
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_halt(struct vfe_device *vfe)
> > +{
> > +     unsigned long time;
> > +
> > +     return 0;
> > +
> > +     reinit_completion(&vfe->halt_complete);
> > +
> > +     time = wait_for_completion_timeout(&vfe->halt_complete,
> > +             msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> > +     if (!time) {
> > +             dev_err(vfe->camss->dev, "VFE halt timeout\n");
> > +             return -EIO;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +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;
> > +     unsigned long flags;
> > +     int i;
> > +     int wm_idx;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     output = &line->output;
> > +     if (output->state != VFE_OUTPUT_OFF) {
> > +             dev_err(vfe->camss->dev, "Output is running\n");
> > +             goto error;
> > +     }
> > +
> > +     switch (f->fmt.pix_mp.pixelformat) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             output->wm_num = 2;
> > +             break;
> > +     default:
> > +             output->wm_num = 1;
> > +             break;
> > +     }
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             wm_idx = vfe_reserve_wm(vfe, line->id);
> > +             if (wm_idx < 0) {
> > +                     dev_err(vfe->camss->dev, "Can not reserve wm\n");
> > +                     goto error_get_wm;
> > +             }
> > +             output->wm_idx[i] = wm_idx;
> > +     }
> > +
> > +     output->drop_update_idx = 0;
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +
> > +error_get_wm:
> > +     for (i--; i >= 0; i--)
> > +             vfe_release_wm(vfe, output->wm_idx[i]);
> > +     output->state = VFE_OUTPUT_OFF;
> > +error:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return -EINVAL;
> > +}
> > +
> > +static int vfe_enable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     const struct vfe_hw_ops *ops = vfe->ops;
> > +     struct media_entity *sensor;
> > +     unsigned long flags;
> > +     unsigned int frame_skip = 0;
> > +     unsigned int i;
> > +
> > +     sensor = camss_find_sensor(&line->subdev.entity);
> > +     if (sensor) {
> > +             struct v4l2_subdev *subdev =
> > +                                     media_entity_to_v4l2_subdev(sensor);
> > +
> > +             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_OFF) {
> > +             dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
> > +                     output->state);
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +             return -EINVAL;
> > +     }
> > +
> > +     WARN_ON(output->gen2.active_num);
> > +
> > +     output->state = VFE_OUTPUT_ON;
> > +
> > +     output->sequence = 0;
> > +     output->wait_reg_update = 0;
> > +     reinit_completion(&output->reg_update);
> > +
> > +     if (line->id != VFE_LINE_PIX)
> > +             vfe_wm_start(vfe, output->wm_idx[0], line);
> > +
> > +     for (i = 0; i < 2; i++) {
> > +             output->buf[i] = vfe_buf_get_pending(output);
> > +             if (!output->buf[i])
> > +                     break;
> > +             output->gen2.active_num++;
> > +             vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
> > +     }
> > +
> > +     ops->reg_update(vfe, line->id);
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static int vfe_disable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     unsigned long flags;
> > +     unsigned int i;
> > +     bool done;
> > +     int timeout = 0;
> > +
> > +     do {
> > +             spin_lock_irqsave(&vfe->output_lock, flags);
> > +             done = !output->gen2.active_num;
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +             usleep_range(10000, 20000);
> > +
> > +             if (timeout++ == 100) {
> > +                     dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
> > +                     vfe_reset(vfe);
> > +                     output->gen2.active_num = 0;
> > +                     return 0;
> > +             }
> > +     } while (!done);
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     for (i = 0; i < output->wm_num; i++)
> > +             vfe_wm_stop(vfe, output->wm_idx[i]);
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * vfe_enable - Enable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_enable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     int ret;
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     if (!vfe->stream_count)
> > +             vfe_enable_irq_common(vfe);
> > +
> > +     vfe->stream_count++;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     ret = vfe_get_output(line);
> > +     if (ret < 0)
> > +             goto error_get_output;
> > +
> > +     ret = vfe_enable_output(line);
> > +     if (ret < 0)
> > +             goto error_enable_output;
> > +
> > +     vfe->was_streaming = 1;
> > +
> > +     return 0;
> > +
> > +
> > +error_enable_output:
> > +     vfe_put_output(line);
> > +
> > +error_get_output:
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return ret;
> > +}
> > +
> > +/*
> > + * vfe_disable - Disable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_disable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +
> > +     vfe_disable_output(line);
> > +
> > +     vfe_put_output(line);
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * vfe_isr_sof - Process start of frame interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +
> > +}
> > +
> > +/*
> > + * vfe_isr_reg_update - Process reg update interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     vfe->ops->reg_update_clear(vfe, line_id);
> > +
> > +     output = &vfe->line[line_id].output;
> > +
> > +     if (output->wait_reg_update) {
> > +             output->wait_reg_update = 0;
> > +             complete(&output->reg_update);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_isr_wm_done - Process write master done interrupt
> > + * @vfe: VFE Device
> > + * @wm: Write master id
> > + */
> > +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> > +{
> > +     struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
> > +     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;
> > +
> > +     ready_buf = output->buf[0];
> > +     if (!ready_buf) {
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Missing ready buf %d!\n", output->state);
> > +             goto out_unlock;
> > +     }
> > +
> > +     ready_buf->vb.vb2_buf.timestamp = ts;
> > +     ready_buf->vb.sequence = output->sequence++;
> > +
> > +     index = 0;
> > +     output->buf[0] = output->buf[1];
> > +     if (output->buf[0])
> > +             index = 1;
> > +
> > +     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);
> > +     else
> > +             output->gen2.active_num--;
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +
> > +     return;
> > +
> > +out_unlock:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_queue_buffer - Add empty buffer
> > + * @vid: Video device structure
> > + * @buf: Buffer to be enqueued
> > + *
> > + * Add an empty buffer - depending on the current number of buffers it will be
> > + * put in pending buffer queue or directly given to the hardware to be filled.
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +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_device *vfe = to_vfe(line);
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     output = &line->output;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
> > +             output->buf[output->gen2.active_num++] = buf;
> > +             vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
> > +     } else {
> > +             vfe_buf_add_pending(output, buf);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +const struct vfe_isr_ops vfe_isr_ops_170 = {
> > +     .reset_ack = vfe_isr_reset_ack,
> > +     .halt_ack = vfe_isr_halt_ack,
> > +     .reg_update = vfe_isr_reg_update,
> > +     .sof = vfe_isr_sof,
> > +     .comp_done = vfe_isr_comp_done,
> > +     .wm_done = vfe_isr_wm_done,
> > +};
> > +
> > +static const struct camss_video_ops vfe_video_ops_170 = {
> > +     .queue_buffer = vfe_queue_buffer,
> > +     .flush_buffers = vfe_flush_buffers,
> > +};
> > +
> > +static void vfe_subdev_init(struct vfe_device *vfe)
> > +{
> > +     vfe->isr_ops = vfe_isr_ops_170;
> > +     vfe->video_ops = vfe_video_ops_170;
> > +}
> > +
> > +const struct vfe_hw_ops vfe_ops_170 = {
> > +     .global_reset = vfe_global_reset,
> > +     .hw_version_read = vfe_hw_version_read,
> > +     .isr_read = vfe_isr_read,
> > +     .isr = vfe_isr,
> > +     .reg_update_clear = vfe_reg_update_clear,
> > +     .reg_update = vfe_reg_update,
> > +     .subdev_init = vfe_subdev_init,
> > +     .vfe_disable = vfe_disable,
> > +     .vfe_enable = vfe_enable,
> > +     .vfe_halt = vfe_halt,
> > +     .violation_read = vfe_violation_read,
> > +};
> > +
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> > index 2ffa5b3c5426..5a874b544391 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> > @@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
> >       { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> >   };
> >
> > +static const struct vfe_format formats_rdi_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
> > +     { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_Y10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
> > +};
> > +
> > +static const struct vfe_format formats_pix_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> > +};
> > +
> >   /*
> >    * vfe_get_bpp - map media bus format to bits per pixel
> >    * @formats: supported media bus formats array
> > @@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
> >                       return sink_code;
> >               }
> >       else if (vfe->camss->version == CAMSS_8x96 ||
> > -              vfe->camss->version == CAMSS_660)
> > +              vfe->camss->version == CAMSS_660 ||
> > +              vfe->camss->version == CAMSS_845)
> >               switch (sink_code) {
> >               case MEDIA_BUS_FMT_YUYV8_2X8:
> >               {
> > @@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
> >               return 0;
> >   }
> >
> > -/*
> > - * vfe_reset - Trigger reset on VFE module and wait to complete
> > - * @vfe: VFE device
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -static int vfe_reset(struct vfe_device *vfe)
> > +int vfe_reset(struct vfe_device *vfe)
> >   {
> >       unsigned long time;
> >
> > @@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
> >               struct camss_clock *clock = &vfe->clock[i];
> >
> >               if (!strcmp(clock->name, "vfe0") ||
> > -                 !strcmp(clock->name, "vfe1")) {
> > +                 !strcmp(clock->name, "vfe1") ||
> > +                 !strcmp(clock->name, "vfe_lite")) {
> >                       u64 min_rate = 0;
> >                       long rate;
> >
> > @@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >       case CAMSS_660:
> >               vfe->ops = &vfe_ops_4_8;
> >               break;
> > +
> > +     case CAMSS_845:
> > +             vfe->ops = &vfe_ops_170;
> > +             break;
> >       default:
> >               return -EINVAL;
> >       }
> > @@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >                               l->formats = formats_rdi_8x96;
> >                               l->nformats = ARRAY_SIZE(formats_rdi_8x96);
> >                       }
> > +             } else if (camss->version == CAMSS_845) {
> > +                     if (i == VFE_LINE_PIX) {
> > +                             l->formats = formats_pix_845;
> > +                             l->nformats = ARRAY_SIZE(formats_pix_845);
> > +                     } else {
> > +                             l->formats = formats_rdi_845;
> > +                             l->nformats = ARRAY_SIZE(formats_rdi_845);
> > +                     }
> >               } else {
> >                       return -EINVAL;
> >               }
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> > index 8629c833f130..a0b618c9cec8 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> > @@ -19,7 +19,6 @@
> >   #include "camss-video.h"
> >   #include "camss-vfe-gen1.h"
> >
> > -
> >   #define MSM_VFE_PAD_SINK 0
> >   #define MSM_VFE_PAD_SRC 1
> >   #define MSM_VFE_PADS_NUM 2
> > @@ -39,14 +38,14 @@
> >   #define to_vfe(ptr_line)    \
> >       container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> >
> > -
> >   enum vfe_output_state {
> >       VFE_OUTPUT_OFF,
> >       VFE_OUTPUT_RESERVED,
> >       VFE_OUTPUT_SINGLE,
> >       VFE_OUTPUT_CONTINUOUS,
> >       VFE_OUTPUT_IDLE,
> > -     VFE_OUTPUT_STOPPING
> > +     VFE_OUTPUT_STOPPING,
> > +     VFE_OUTPUT_ON,
> >   };
> >
> >   enum vfe_line_id {
> > @@ -72,6 +71,9 @@ struct vfe_output {
> >                       int active_buf;
> >                       int wait_sof;
> >               } gen1;
> > +             struct {
> > +                     int active_num;
> > +             } gen2;
> >       };
> >       enum vfe_output_state state;
> >       unsigned int sequence;
> > @@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
> >
> >   struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
> >
> > -/*
> > - * vfe_disable - Disable streaming on VFE line
> > - * @line: VFE line
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -int vfe_disable(struct vfe_line *line);
> > -
> >   int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
> >
> >   /*
> > @@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
> >   int vfe_release_wm(struct vfe_device *vfe, u8 wm);
> >   int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
> >
> > +/*
> > + * vfe_reset - Trigger reset on VFE module and wait to complete
> > + * @vfe: VFE device
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +int vfe_reset(struct vfe_device *vfe);
> > +
> >   extern const struct vfe_hw_ops vfe_ops_4_1;
> >   extern const struct vfe_hw_ops vfe_ops_4_7;
> >   extern const struct vfe_hw_ops vfe_ops_4_8;
> > +extern const struct vfe_hw_ops vfe_ops_170;
> >
> >   #endif /* QC_MSM_CAMSS_VFE_H */
> > diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
> > index bd9334af1c73..b4943df9eaf6 100644
> > --- a/drivers/media/platform/qcom/camss/camss-video.c
> > +++ b/drivers/media/platform/qcom/camss/camss-video.c
> > @@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
> >         { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> >   };
> >
> > +static const struct camss_format_info formats_rdi_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +};
> > +
> >   static const struct camss_format_info formats_pix_8x16[] = {
> >       { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> >         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > @@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
> >         { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> >   };
> >
> > +static const struct camss_format_info formats_pix_845[] = {
> > +     { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +};
> > +
> >   /* -----------------------------------------------------------------------------
> >    * Helper functions
> >    */
> > @@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
> >                       video->formats = formats_rdi_8x96;
> >                       video->nformats = ARRAY_SIZE(formats_rdi_8x96);
> >               }
> > +     }  else if (video->camss->version == CAMSS_845) {
> > +             if (is_pix) {
> > +                     video->formats = formats_pix_845;
> > +                     video->nformats = ARRAY_SIZE(formats_pix_845);
> > +             } else {
> > +                     video->formats = formats_rdi_845;
> > +                     video->nformats = ARRAY_SIZE(formats_rdi_845);
> > +             }
> >       } else {
> >               goto error_video_register;
> >       }
> > diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> > index aeec59bc6194..1c3d64d612ff 100644
> > --- a/drivers/media/platform/qcom/camss/camss.c
> > +++ b/drivers/media/platform/qcom/camss/camss.c
> > @@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
> >       }
> >   };
> >
> > +static const struct resources vfe_res_845[] = {
> > +     /* VFE0 */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe0", "vfe0_axi",
> > +                             "vfe0_src", "csi0",
> > +                             "csi0_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 0 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe0" },
> > +             .interrupt = { "vfe0" }
> > +     },
> > +
> > +     /* VFE1 */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe1", "vfe1_axi",
> > +                             "vfe1_src", "csi1",
> > +                             "csi1_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 0 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe1" },
> > +             .interrupt = { "vfe1" }
> > +     },
> > +
> > +     /* VFE-lite */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe_lite",
> > +                             "vfe_lite_src", "csi2",
> > +                             "csi2_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe_lite" },
> > +             .interrupt = { "vfe_lite" }
> > +     }
> > +};
> > +
> >   /*
> >    * camss_add_clock_margin - Add margin to clock frequency rate
> >    * @rate: Clock frequency rate
> >

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

* Re: [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170
@ 2021-01-14 12:07       ` Robert Foss
  0 siblings, 0 replies; 65+ messages in thread
From: Robert Foss @ 2021-01-14 12:07 UTC (permalink / raw)
  To: Andrey Konovalov
  Cc: geert+renesas, catalin.marinas, agx, Todor Tomov,
	Bjorn Andersson, Laurent Pinchart, AngeloGioacchino Del Regno,
	will, Anson.Huang, Andy Gross, linux-media,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Tomasz Figa, arnd, linux-arm-msm, Rob Herring,
	Mauro Carvalho Chehab,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Sarvesh Sridutt, max.oss.09, linux-kernel, leoyang.li, michael,
	Azam Sadiq Pasha Kapatrala Syed, shawnguo

On Thu, 14 Jan 2021 at 11:48, Andrey Konovalov
<andrey.konovalov@linaro.org> wrote:
>
> Hi Robert,
>
> Thank you for the patch!
>
> On 08.01.2021 15:04, Robert Foss wrote:
> > Add register definitions for version 170 of the Titan architecture
> > and implement support for the RDI output mode.
> >
> > The RDI mode as opposed to the PIX output mode for the VFE unit does
> > not support any ISP functionality. This means essentially only
> > supporting dumping the output of the whatever the CSI decoder receives
> > from the sensor.
> >
> > For example will a sensor outputting YUV pixel format frames, only
> > allow the VFE to dump those frames as they are received by the ISP
> > to memory through the RDI interface.
> >
> > Signed-off-by: Robert Foss <robert.foss@linaro.org>
> > ---
> >   drivers/media/platform/qcom/camss/Makefile    |   1 +
> >   .../media/platform/qcom/camss/camss-vfe-170.c | 808 ++++++++++++++++++
> >   drivers/media/platform/qcom/camss/camss-vfe.c |  59 +-
> >   drivers/media/platform/qcom/camss/camss-vfe.h |  25 +-
> >   .../media/platform/qcom/camss/camss-video.c   | 100 +++
> >   drivers/media/platform/qcom/camss/camss.c     |  61 ++
> >   6 files changed, 1034 insertions(+), 20 deletions(-)
> >   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-170.c
> >
> > diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> > index 940c0ae3e003..052c4f405fa3 100644
> > --- a/drivers/media/platform/qcom/camss/Makefile
> > +++ b/drivers/media/platform/qcom/camss/Makefile
> > @@ -11,6 +11,7 @@ qcom-camss-objs += \
> >               camss-vfe-4-1.o \
> >               camss-vfe-4-7.o \
> >               camss-vfe-4-8.o \
> > +             camss-vfe-170.o \
> >               camss-vfe-gen1.o \
> >               camss-vfe.o \
> >               camss-video.o \
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> > new file mode 100644
> > index 000000000000..89b6c47cca22
> > --- /dev/null
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
> > @@ -0,0 +1,808 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * camss-vfe-4-7.c
> > + *
> > + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.7
>
> - the above two lines aren't updated to vfe-170
>
> > + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> > + * Copyright (C) 2015-2018 Linaro Ltd.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +
> > +#include "camss.h"
> > +#include "camss-vfe.h"
> > +
> > +#define VFE_HW_VERSION                               (0x000)
> > +
> > +#define VFE_GLOBAL_RESET_CMD                 (0x018)
> > +#define              GLOBAL_RESET_CMD_CORE           BIT(0)
> > +#define              GLOBAL_RESET_CMD_CAMIF          BIT(1)
> > +#define              GLOBAL_RESET_CMD_BUS            BIT(2)
> > +#define              GLOBAL_RESET_CMD_BUS_BDG        BIT(3)
> > +#define              GLOBAL_RESET_CMD_REGISTER       BIT(4)
> > +#define              GLOBAL_RESET_CMD_PM             BIT(5)
> > +#define              GLOBAL_RESET_CMD_BUS_MISR       BIT(6)
> > +#define              GLOBAL_RESET_CMD_TESTGEN        BIT(7)
> > +#define              GLOBAL_RESET_CMD_DSP            BIT(8)
> > +#define              GLOBAL_RESET_CMD_IDLE_CGC       BIT(9)
> > +
> > +#define VFE_CORE_CFG                         (0x050)
> > +#define              CFG_PIXEL_PATTERN_YCBYCR        (0x4)
> > +#define              CFG_PIXEL_PATTERN_YCRYCB        (0x5)
> > +#define              CFG_PIXEL_PATTERN_CBYCRY        (0x6)
> > +#define              CFG_PIXEL_PATTERN_CRYCBY        (0x7)
> > +#define              CFG_COMPOSITE_REG_UPDATE_EN     BIT(4)
> > +
> > +#define VFE_IRQ_CMD                          (0x058)
> > +#define              CMD_GLOBAL_CLEAR                BIT(0)
> > +
> > +#define VFE_IRQ_MASK_0                                       (0x05c)
> > +#define              MASK_0_CAMIF_SOF                        BIT(0)
> > +#define              MASK_0_CAMIF_EOF                        BIT(1)
> > +#define              MASK_0_RDIn_REG_UPDATE(n)               BIT((n) + 5)
> > +#define              MASK_0_line_n_REG_UPDATE(n)             \
> > +                     ((n) == VFE_LINE_PIX ? \
> > +                             BIT(4) : MASK_0_RDIn_REG_UPDATE(n))
> > +#define              MASK_0_IMAGE_MASTER_n_PING_PONG(n)      BIT((n) + 8)
> > +#define              MASK_0_IMAGE_COMPOSITE_DONE_n(n)        BIT((n) + 25)
> > +#define              MASK_0_RESET_ACK                        BIT(31)
> > +
> > +#define VFE_IRQ_MASK_1                                       (0x060)
> > +#define              MASK_1_CAMIF_ERROR                      BIT(0)
> > +#define              MASK_1_VIOLATION                        BIT(7)
> > +#define              MASK_1_BUS_BDG_HALT_ACK                 BIT(8)
> > +#define              MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)   BIT((n) + 9)
> > +#define              MASK_1_RDIn_SOF(n)                      BIT((n) + 29)
> > +
> > +#define VFE_IRQ_CLEAR_0                                      (0x064)
> > +#define VFE_IRQ_CLEAR_1                                      (0x068)
> > +
> > +#define VFE_IRQ_STATUS_0                             (0x06c)
> > +#define              STATUS_0_CAMIF_SOF                      BIT(0)
> > +#define              STATUS_0_RDIn_REG_UPDATE(n)             BIT((n) + 5)
> > +#define              STATUS_0_line_n_REG_UPDATE(n)           \
> > +                     ((n) == VFE_LINE_PIX ? \
> > +                             BIT(4) : STATUS_0_RDIn_REG_UPDATE(n))
> > +#define              STATUS_0_IMAGE_MASTER_n_PING_PONG(n)    BIT((n) + 8)
> > +#define              STATUS_0_IMAGE_COMPOSITE_DONE_n(n)      BIT((n) + 25)
> > +#define              STATUS_0_RESET_ACK                      BIT(31)
> > +
> > +#define VFE_IRQ_STATUS_1                             (0x070)
> > +#define              STATUS_1_VIOLATION                      BIT(7)
> > +#define              STATUS_1_BUS_BDG_HALT_ACK               BIT(8)
> > +#define              STATUS_1_RDIn_SOF(n)                    BIT((n) + 27)
> > +
> > +#define VFE_VIOLATION_STATUS                 (0x07c)
> > +
> > +#define VFE_CAMIF_CMD                                (0x478)
> > +#define              CMD_CLEAR_CAMIF_STATUS          BIT(2)
> > +
> > +#define VFE_CAMIF_CFG                                (0x47c)
> > +#define              CFG_VSYNC_SYNC_EDGE             (0)
> > +#define                      VSYNC_ACTIVE_HIGH       (0)
> > +#define                      VSYNC_ACTIVE_LOW        (1)
> > +#define              CFG_HSYNC_SYNC_EDGE             (1)
> > +#define                      HSYNC_ACTIVE_HIGH       (0)
> > +#define                      HSYNC_ACTIVE_LOW        (1)
> > +#define              CFG_VFE_SUBSAMPLE_ENABLE        BIT(4)
> > +#define              CFG_BUS_SUBSAMPLE_ENABLE        BIT(5)
> > +#define              CFG_VFE_OUTPUT_EN               BIT(6)
> > +#define              CFG_BUS_OUTPUT_EN               BIT(7)
> > +#define              CFG_BINNING_EN                  BIT(9)
> > +#define              CFG_FRAME_BASED_EN              BIT(10)
> > +#define              CFG_RAW_CROP_EN                 BIT(22)
> > +
> > +// XXX different, don't exist in TITAN register docs
> > +#define VFE_0_CAMIF_FRAME_CFG                        0x484
> > +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG         0x488
> > +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG                0x48c
> > +#define VFE_0_CAMIF_SUBSAMPLE_CFG            0x490
> > +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN    0x498
> > +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN    0x49c
> > +#define VFE_0_CAMIF_STATUS                   0x4a4
> > +#define VFE_0_CAMIF_STATUS_HALT                      BIT(31)
> > +#define CAMIF_TIMEOUT_SLEEP_US 1000
> > +#define CAMIF_TIMEOUT_ALL_US 1000000
> > +
> > +#define VFE_REG_UPDATE_CMD                   (0x4ac)
> > +#define              REG_UPDATE_RDIn(n)              BIT(1 + (n))
> > +#define              REG_UPDATE_line_n(n)            \
> > +                     ((n) == VFE_LINE_PIX ? 1 : REG_UPDATE_RDIn(n))
> > +
> > +
> > +#define VFE_BUS_IRQ_MASK(n)          (0x2044 + (n) * 4)
> > +#define VFE_BUS_IRQ_CLEAR(n)         (0x2050 + (n) * 4)
> > +
> > +#define VFE_BUS_IRQ_STATUS(n)                (0x205c + (n) * 4)
> > +#define              STATUS0_COMP_RESET_DONE         BIT(0)
> > +#define              STATUS0_COMP_REG_UPDATE0_DONE   BIT(1)
> > +#define              STATUS0_COMP_REG_UPDATE1_DONE   BIT(2)
> > +#define              STATUS0_COMP_REG_UPDATE2_DONE   BIT(3)
> > +#define              STATUS0_COMP_REG_UPDATE3_DONE   BIT(4)
> > +#define              STATUS0_COMP_REG_UPDATE_DONE(n) BIT(n + 1)
> > +#define              STATUS0_COMP0_BUF_DONE          BIT(5)
> > +#define              STATUS0_COMP1_BUF_DONE          BIT(6)
> > +#define              STATUS0_COMP2_BUF_DONE          BIT(7)
> > +#define              STATUS0_COMP3_BUF_DONE          BIT(8)
> > +#define              STATUS0_COMP4_BUF_DONE          BIT(9)
> > +#define              STATUS0_COMP5_BUF_DONE          BIT(10)
> > +#define              STATUS0_COMP_BUF_DONE(n)        BIT(n + 5)
> > +#define              STATUS0_COMP_ERROR              BIT(11)
> > +#define              STATUS0_COMP_OVERWRITE          BIT(12)
> > +#define              STATUS0_OVERFLOW                BIT(13)
> > +#define              STATUS0_VIOLATION               BIT(14)
> > +/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */
> > +#define              STATUS1_WM_CLIENT_BUF_DONE(n)           BIT(n)
> > +#define              STATUS1_EARLY_DONE                      BIT(24)
> > +#define              STATUS2_DUAL_COMP0_BUF_DONE             BIT(0)
> > +#define              STATUS2_DUAL_COMP1_BUF_DONE             BIT(1)
> > +#define              STATUS2_DUAL_COMP2_BUF_DONE             BIT(2)
> > +#define              STATUS2_DUAL_COMP3_BUF_DONE             BIT(3)
> > +#define              STATUS2_DUAL_COMP4_BUF_DONE             BIT(4)
> > +#define              STATUS2_DUAL_COMP5_BUF_DONE             BIT(5)
> > +#define              STATUS2_DUAL_COMP_BUF_DONE(n)           BIT(n)
> > +#define              STATUS2_DUAL_COMP_ERROR                 BIT(6)
> > +#define              STATUS2_DUAL_COMP_OVERWRITE             BIT(7)
> > +
> > +#define VFE_BUS_IRQ_CLEAR_GLOBAL             (0x2068)
> > +
> > +#define VFE_BUS_WM_DEBUG_STATUS_CFG          (0x226c)
> > +#define              DEBUG_STATUS_CFG_STATUS0(n)     BIT(n)
> > +#define              DEBUG_STATUS_CFG_STATUS1(n)     BIT(8+n)
> > +
> > +#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER    (0x2080)
> > +
> > +#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC         (0x2084)
> > +#define              BUS_VER2_MAX_CLIENTS (24)
> > +#define              WM_ADDR_NO_SYNC_DEFAULT_VAL \
> > +                             ((1 << BUS_VER2_MAX_CLIENTS) - 1)
> > +
> > +#define VFE_BUS_WM_CGC_OVERRIDE                      (0x200c)
> > +#define              WM_CGC_OVERRIDE_ALL             (0xFFFFF)
> > +
> > +#define VFE_BUS_WM_TEST_BUS_CTRL             (0x211c)
> > +
> > +#define VFE_BUS_WM_STATUS0(n)                        (0x2200 + (n) * 0x100)
> > +#define VFE_BUS_WM_STATUS1(n)                        (0x2204 + (n) * 0x100)
> > +#define VFE_BUS_WM_CFG(n)                    (0x2208 + (n) * 0x100)
> > +#define              WM_CFG_EN                       (0)
> > +#define              WM_CFG_MODE                     (1)
> > +#define                      MODE_QCOM_PLAIN (0)
> > +#define                      MODE_MIPI_RAW   (1)
> > +#define              WM_CFG_VIRTUALFRAME             (2)
> > +#define VFE_BUS_WM_HEADER_ADDR(n)            (0x220c + (n) * 0x100)
> > +#define VFE_BUS_WM_HEADER_CFG(n)             (0x2210 + (n) * 0x100)
> > +#define VFE_BUS_WM_IMAGE_ADDR(n)             (0x2214 + (n) * 0x100)
> > +#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n)              (0x2218 + (n) * 0x100)
> > +#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n)               (0x221c + (n) * 0x100)
> > +#define              WM_BUFFER_DEFAULT_WIDTH         (0xFF01)
> > +
> > +#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n)              (0x2220 + (n) * 0x100)
> > +#define VFE_BUS_WM_PACKER_CFG(n)             (0x2224 + (n) * 0x100)
> > +
> > +#define VFE_BUS_WM_STRIDE(n)                 (0x2228 + (n) * 0x100)
> > +#define              WM_STRIDE_DEFAULT_STRIDE        (0xFF01)
> > +
> > +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n)   (0x2248 + (n) * 0x100)
> > +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n)  (0x224c + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAMEDROP_PERIOD(n)               (0x2250 + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAMEDROP_PATTERN(n)              (0x2254 + (n) * 0x100)
> > +#define VFE_BUS_WM_FRAME_INC(n)                      (0x2258 + (n) * 0x100)
> > +#define VFE_BUS_WM_BURST_LIMIT(n)            (0x225c + (n) * 0x100)
> > +
> > +
> > +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> > +{
> > +     u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION);
> > +
> > +     u32 gen = (hw_version >> 28) & 0xF;
> > +     u32 rev = (hw_version >> 16) & 0xFFF;
> > +     u32 step = hw_version & 0xFFFF;
> > +
> > +     dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step);
> > +}
> > +
> > +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> > +}
> > +
> > +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> > +{
> > +     u32 bits = readl_relaxed(vfe->base + reg);
> > +
> > +     writel_relaxed(bits | set_bits, vfe->base + reg);
> > +}
> > +
> > +static void vfe_global_reset(struct vfe_device *vfe)
> > +{
> > +     u32 reset_bits = GLOBAL_RESET_CMD_IDLE_CGC      |
> > +                      GLOBAL_RESET_CMD_DSP           |
> > +                      GLOBAL_RESET_CMD_TESTGEN       |
> > +                      GLOBAL_RESET_CMD_BUS_MISR      |
> > +                      GLOBAL_RESET_CMD_PM            |
> > +                      GLOBAL_RESET_CMD_REGISTER      |
> > +                      GLOBAL_RESET_CMD_BUS_BDG       |
> > +                      GLOBAL_RESET_CMD_BUS           |
> > +                      GLOBAL_RESET_CMD_CAMIF         |
> > +                      GLOBAL_RESET_CMD_CORE;
>
> - the above settings are overwritten by this assignment:
>
> > +     reset_bits = 0x00003F9F;
> > +
> > +     writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0);
> > +
> > +     /* Make sure IRQ mask has been written before resetting */
> > +     wmb();
> > +
> > +     writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD);
> > +}
> > +
> > +static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line)
> > +{
> > +     u32 val;
> > +
> > +     /*Set Debug Registers*/
> > +     val = DEBUG_STATUS_CFG_STATUS0(1) |
> > +           DEBUG_STATUS_CFG_STATUS0(7);
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG);
> > +
> > +     /* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */
> > +     writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER);
> > +
> > +     /* no clock gating at bus input */
> > +     val = WM_CGC_OVERRIDE_ALL;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE);
> > +
> > +     writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL);
> > +
> > +     /* if addr_no_sync has default value then config the addr no sync reg */
> > +     val = WM_ADDR_NO_SYNC_DEFAULT_VAL;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC);
> > +
> > +     writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm));
> > +
> > +     val = WM_BUFFER_DEFAULT_WIDTH;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm));
> > +
> > +     val = 0;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm));
> > +
> > +     val = 0;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8?
>
> - C++ style comment
>
>    Also here and in several comments below you use the XXX tag which looks
>    more confusing than helpful for me. Would it be possible to expand such comments
>    to make them more explicit? Just a nitpick though.
>
> > +
> > +     /* Configure stride for RDIs */
> > +     //val = pix->plane_fmt[0].bytesperline;
>
> - the commented out line should probably be removed. Or changed into real
>    comment.

Will do! Thanks for finding this.

>
> Thanks,
> Andrey
>
> > +     val = WM_STRIDE_DEFAULT_STRIDE;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm));
> > +
> > +     /* Enable WM */
> > +     val = 1 << WM_CFG_EN |
> > +           MODE_MIPI_RAW << WM_CFG_MODE;
> > +     writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm));
> > +}
> > +
> > +static void vfe_wm_stop(struct vfe_device *vfe, u8 wm)
> > +{
> > +     /* Disable WM */
> > +     writel_relaxed(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)
> > +{
> > +     /* XXX use cmdbuf for this ?? */
> > +     struct v4l2_pix_format_mplane *pix =
> > +             &line->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));
> > +     writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm));
> > +
> > +     /* XXX enable wm ? */
> > +}
> > +
> > +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update |= REG_UPDATE_line_n(line_id);
> > +
> > +     /* Enforce ordering between previous reg writes and reg update */
> > +     wmb();
> > +
> > +     writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD);
> > +
> > +     /* Enforce ordering between reg update and subsequent reg writes */
> > +     wmb();
> > +}
> > +
> > +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> > +                                     enum vfe_line_id line_id)
> > +{
> > +     vfe->reg_update &= ~REG_UPDATE_line_n(line_id);
> > +}
> > +
> > +static void vfe_enable_irq_common(struct vfe_device *vfe)
> > +{
> > +     vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u);
> > +     vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u);
> > +
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0));
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1));
> > +     writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2));
> > +}
> > +
> > +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> > +{
> > +     complete(&vfe->halt_complete);
> > +}
> > +
> > +static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1)
> > +{
> > +     *status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> > +     *status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> > +
> > +     writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0);
> > +     writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1);
> > +
> > +     /* Enforce ordering between IRQ Clear and Global IRQ Clear */
> > +     wmb();
> > +     writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> > +}
> > +
> > +static void vfe_violation_read(struct vfe_device *vfe)
> > +{
> > +     u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS);
> > +
> > +     pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> > +}
> > +
> > +/*
> > + * vfe_isr - VFE module interrupt handler
> > + * @irq: Interrupt line
> > + * @dev: VFE device
> > + *
> > + * Return IRQ_HANDLED on success
> > + */
> > +static irqreturn_t vfe_isr(int irq, void *dev)
> > +{
> > +     struct vfe_device *vfe = dev;
> > +     u32 status0, status1, vfe_bus_status[3];
> > +     int i, wm;
> > +
> > +     status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0);
> > +     status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1);
> > +
> > +     writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
> > +     writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) {
> > +             vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
> > +             writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
> > +     }
> > +
> > +     /* Enforce ordering between IRQ reading and interpretation */
> > +     wmb();
> > +
> > +     writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD);
> > +     writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL);
> > +
> > +     if (status0 & STATUS_0_RESET_ACK)
> > +             vfe->isr_ops.reset_ack(vfe);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> > +             if (status0 & STATUS_0_line_n_REG_UPDATE(i))
> > +                     vfe->isr_ops.reg_update(vfe, i);
> > +
> > +     for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> > +             if (status0 & STATUS_1_RDIn_SOF(i))
> > +                     vfe->isr_ops.sof(vfe, i);
> > +
> > +     for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> > +             if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i))
> > +                     vfe->isr_ops.comp_done(vfe, i);
> > +
> > +     for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++)
> > +             if (status0 & BIT(9))
> > +                     if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm))
> > +                             vfe->isr_ops.wm_done(vfe, wm);
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +/*
> > + * vfe_halt - Trigger halt on VFE module and wait to complete
> > + * @vfe: VFE device
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_halt(struct vfe_device *vfe)
> > +{
> > +     unsigned long time;
> > +
> > +     return 0;
> > +
> > +     reinit_completion(&vfe->halt_complete);
> > +
> > +     time = wait_for_completion_timeout(&vfe->halt_complete,
> > +             msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> > +     if (!time) {
> > +             dev_err(vfe->camss->dev, "VFE halt timeout\n");
> > +             return -EIO;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +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;
> > +     unsigned long flags;
> > +     int i;
> > +     int wm_idx;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     output = &line->output;
> > +     if (output->state != VFE_OUTPUT_OFF) {
> > +             dev_err(vfe->camss->dev, "Output is running\n");
> > +             goto error;
> > +     }
> > +
> > +     switch (f->fmt.pix_mp.pixelformat) {
> > +     case V4L2_PIX_FMT_NV12:
> > +     case V4L2_PIX_FMT_NV21:
> > +     case V4L2_PIX_FMT_NV16:
> > +     case V4L2_PIX_FMT_NV61:
> > +             output->wm_num = 2;
> > +             break;
> > +     default:
> > +             output->wm_num = 1;
> > +             break;
> > +     }
> > +
> > +     for (i = 0; i < output->wm_num; i++) {
> > +             wm_idx = vfe_reserve_wm(vfe, line->id);
> > +             if (wm_idx < 0) {
> > +                     dev_err(vfe->camss->dev, "Can not reserve wm\n");
> > +                     goto error_get_wm;
> > +             }
> > +             output->wm_idx[i] = wm_idx;
> > +     }
> > +
> > +     output->drop_update_idx = 0;
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +
> > +error_get_wm:
> > +     for (i--; i >= 0; i--)
> > +             vfe_release_wm(vfe, output->wm_idx[i]);
> > +     output->state = VFE_OUTPUT_OFF;
> > +error:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return -EINVAL;
> > +}
> > +
> > +static int vfe_enable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     const struct vfe_hw_ops *ops = vfe->ops;
> > +     struct media_entity *sensor;
> > +     unsigned long flags;
> > +     unsigned int frame_skip = 0;
> > +     unsigned int i;
> > +
> > +     sensor = camss_find_sensor(&line->subdev.entity);
> > +     if (sensor) {
> > +             struct v4l2_subdev *subdev =
> > +                                     media_entity_to_v4l2_subdev(sensor);
> > +
> > +             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_OFF) {
> > +             dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
> > +                     output->state);
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +             return -EINVAL;
> > +     }
> > +
> > +     WARN_ON(output->gen2.active_num);
> > +
> > +     output->state = VFE_OUTPUT_ON;
> > +
> > +     output->sequence = 0;
> > +     output->wait_reg_update = 0;
> > +     reinit_completion(&output->reg_update);
> > +
> > +     if (line->id != VFE_LINE_PIX)
> > +             vfe_wm_start(vfe, output->wm_idx[0], line);
> > +
> > +     for (i = 0; i < 2; i++) {
> > +             output->buf[i] = vfe_buf_get_pending(output);
> > +             if (!output->buf[i])
> > +                     break;
> > +             output->gen2.active_num++;
> > +             vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line);
> > +     }
> > +
> > +     ops->reg_update(vfe, line->id);
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +static int vfe_disable_output(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     struct vfe_output *output = &line->output;
> > +     unsigned long flags;
> > +     unsigned int i;
> > +     bool done;
> > +     int timeout = 0;
> > +
> > +     do {
> > +             spin_lock_irqsave(&vfe->output_lock, flags);
> > +             done = !output->gen2.active_num;
> > +             spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +             usleep_range(10000, 20000);
> > +
> > +             if (timeout++ == 100) {
> > +                     dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n");
> > +                     vfe_reset(vfe);
> > +                     output->gen2.active_num = 0;
> > +                     return 0;
> > +             }
> > +     } while (!done);
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     for (i = 0; i < output->wm_num; i++)
> > +             vfe_wm_stop(vfe, output->wm_idx[i]);
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * vfe_enable - Enable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_enable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +     int ret;
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     if (!vfe->stream_count)
> > +             vfe_enable_irq_common(vfe);
> > +
> > +     vfe->stream_count++;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     ret = vfe_get_output(line);
> > +     if (ret < 0)
> > +             goto error_get_output;
> > +
> > +     ret = vfe_enable_output(line);
> > +     if (ret < 0)
> > +             goto error_enable_output;
> > +
> > +     vfe->was_streaming = 1;
> > +
> > +     return 0;
> > +
> > +
> > +error_enable_output:
> > +     vfe_put_output(line);
> > +
> > +error_get_output:
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return ret;
> > +}
> > +
> > +/*
> > + * vfe_disable - Disable streaming on VFE line
> > + * @line: VFE line
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +static int vfe_disable(struct vfe_line *line)
> > +{
> > +     struct vfe_device *vfe = to_vfe(line);
> > +
> > +     vfe_disable_output(line);
> > +
> > +     vfe_put_output(line);
> > +
> > +     mutex_lock(&vfe->stream_lock);
> > +
> > +     vfe->stream_count--;
> > +
> > +     mutex_unlock(&vfe->stream_lock);
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * vfe_isr_sof - Process start of frame interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +
> > +}
> > +
> > +/*
> > + * vfe_isr_reg_update - Process reg update interrupt
> > + * @vfe: VFE Device
> > + * @line_id: VFE line
> > + */
> > +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> > +{
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +     vfe->ops->reg_update_clear(vfe, line_id);
> > +
> > +     output = &vfe->line[line_id].output;
> > +
> > +     if (output->wait_reg_update) {
> > +             output->wait_reg_update = 0;
> > +             complete(&output->reg_update);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_isr_wm_done - Process write master done interrupt
> > + * @vfe: VFE Device
> > + * @wm: Write master id
> > + */
> > +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> > +{
> > +     struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]];
> > +     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;
> > +
> > +     ready_buf = output->buf[0];
> > +     if (!ready_buf) {
> > +             dev_err_ratelimited(vfe->camss->dev,
> > +                                 "Missing ready buf %d!\n", output->state);
> > +             goto out_unlock;
> > +     }
> > +
> > +     ready_buf->vb.vb2_buf.timestamp = ts;
> > +     ready_buf->vb.sequence = output->sequence++;
> > +
> > +     index = 0;
> > +     output->buf[0] = output->buf[1];
> > +     if (output->buf[0])
> > +             index = 1;
> > +
> > +     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);
> > +     else
> > +             output->gen2.active_num--;
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +
> > +     return;
> > +
> > +out_unlock:
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +}
> > +
> > +/*
> > + * vfe_queue_buffer - Add empty buffer
> > + * @vid: Video device structure
> > + * @buf: Buffer to be enqueued
> > + *
> > + * Add an empty buffer - depending on the current number of buffers it will be
> > + * put in pending buffer queue or directly given to the hardware to be filled.
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +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_device *vfe = to_vfe(line);
> > +     struct vfe_output *output;
> > +     unsigned long flags;
> > +
> > +     output = &line->output;
> > +
> > +     spin_lock_irqsave(&vfe->output_lock, flags);
> > +
> > +     if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) {
> > +             output->buf[output->gen2.active_num++] = buf;
> > +             vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line);
> > +     } else {
> > +             vfe_buf_add_pending(output, buf);
> > +     }
> > +
> > +     spin_unlock_irqrestore(&vfe->output_lock, flags);
> > +
> > +     return 0;
> > +}
> > +
> > +const struct vfe_isr_ops vfe_isr_ops_170 = {
> > +     .reset_ack = vfe_isr_reset_ack,
> > +     .halt_ack = vfe_isr_halt_ack,
> > +     .reg_update = vfe_isr_reg_update,
> > +     .sof = vfe_isr_sof,
> > +     .comp_done = vfe_isr_comp_done,
> > +     .wm_done = vfe_isr_wm_done,
> > +};
> > +
> > +static const struct camss_video_ops vfe_video_ops_170 = {
> > +     .queue_buffer = vfe_queue_buffer,
> > +     .flush_buffers = vfe_flush_buffers,
> > +};
> > +
> > +static void vfe_subdev_init(struct vfe_device *vfe)
> > +{
> > +     vfe->isr_ops = vfe_isr_ops_170;
> > +     vfe->video_ops = vfe_video_ops_170;
> > +}
> > +
> > +const struct vfe_hw_ops vfe_ops_170 = {
> > +     .global_reset = vfe_global_reset,
> > +     .hw_version_read = vfe_hw_version_read,
> > +     .isr_read = vfe_isr_read,
> > +     .isr = vfe_isr,
> > +     .reg_update_clear = vfe_reg_update_clear,
> > +     .reg_update = vfe_reg_update,
> > +     .subdev_init = vfe_subdev_init,
> > +     .vfe_disable = vfe_disable,
> > +     .vfe_enable = vfe_enable,
> > +     .vfe_halt = vfe_halt,
> > +     .violation_read = vfe_violation_read,
> > +};
> > +
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> > index 2ffa5b3c5426..5a874b544391 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> > @@ -96,6 +96,39 @@ static const struct vfe_format formats_pix_8x96[] = {
> >       { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> >   };
> >
> > +static const struct vfe_format formats_rdi_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
> > +     { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
> > +     { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
> > +     { MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
> > +     { MEDIA_BUS_FMT_Y10_1X10, 10 },
> > +     { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
> > +};
> > +
> > +static const struct vfe_format formats_pix_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, 8 },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, 8 },
> > +};
> > +
> >   /*
> >    * vfe_get_bpp - map media bus format to bits per pixel
> >    * @formats: supported media bus formats array
> > @@ -192,7 +225,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
> >                       return sink_code;
> >               }
> >       else if (vfe->camss->version == CAMSS_8x96 ||
> > -              vfe->camss->version == CAMSS_660)
> > +              vfe->camss->version == CAMSS_660 ||
> > +              vfe->camss->version == CAMSS_845)
> >               switch (sink_code) {
> >               case MEDIA_BUS_FMT_YUYV8_2X8:
> >               {
> > @@ -256,13 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
> >               return 0;
> >   }
> >
> > -/*
> > - * vfe_reset - Trigger reset on VFE module and wait to complete
> > - * @vfe: VFE device
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -static int vfe_reset(struct vfe_device *vfe)
> > +int vfe_reset(struct vfe_device *vfe)
> >   {
> >       unsigned long time;
> >
> > @@ -429,7 +457,8 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
> >               struct camss_clock *clock = &vfe->clock[i];
> >
> >               if (!strcmp(clock->name, "vfe0") ||
> > -                 !strcmp(clock->name, "vfe1")) {
> > +                 !strcmp(clock->name, "vfe1") ||
> > +                 !strcmp(clock->name, "vfe_lite")) {
> >                       u64 min_rate = 0;
> >                       long rate;
> >
> > @@ -1268,6 +1297,10 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >       case CAMSS_660:
> >               vfe->ops = &vfe_ops_4_8;
> >               break;
> > +
> > +     case CAMSS_845:
> > +             vfe->ops = &vfe_ops_170;
> > +             break;
> >       default:
> >               return -EINVAL;
> >       }
> > @@ -1379,6 +1412,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
> >                               l->formats = formats_rdi_8x96;
> >                               l->nformats = ARRAY_SIZE(formats_rdi_8x96);
> >                       }
> > +             } else if (camss->version == CAMSS_845) {
> > +                     if (i == VFE_LINE_PIX) {
> > +                             l->formats = formats_pix_845;
> > +                             l->nformats = ARRAY_SIZE(formats_pix_845);
> > +                     } else {
> > +                             l->formats = formats_rdi_845;
> > +                             l->nformats = ARRAY_SIZE(formats_rdi_845);
> > +                     }
> >               } else {
> >                       return -EINVAL;
> >               }
> > diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> > index 8629c833f130..a0b618c9cec8 100644
> > --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> > +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> > @@ -19,7 +19,6 @@
> >   #include "camss-video.h"
> >   #include "camss-vfe-gen1.h"
> >
> > -
> >   #define MSM_VFE_PAD_SINK 0
> >   #define MSM_VFE_PAD_SRC 1
> >   #define MSM_VFE_PADS_NUM 2
> > @@ -39,14 +38,14 @@
> >   #define to_vfe(ptr_line)    \
> >       container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> >
> > -
> >   enum vfe_output_state {
> >       VFE_OUTPUT_OFF,
> >       VFE_OUTPUT_RESERVED,
> >       VFE_OUTPUT_SINGLE,
> >       VFE_OUTPUT_CONTINUOUS,
> >       VFE_OUTPUT_IDLE,
> > -     VFE_OUTPUT_STOPPING
> > +     VFE_OUTPUT_STOPPING,
> > +     VFE_OUTPUT_ON,
> >   };
> >
> >   enum vfe_line_id {
> > @@ -72,6 +71,9 @@ struct vfe_output {
> >                       int active_buf;
> >                       int wait_sof;
> >               } gen1;
> > +             struct {
> > +                     int active_num;
> > +             } gen2;
> >       };
> >       enum vfe_output_state state;
> >       unsigned int sequence;
> > @@ -169,14 +171,6 @@ void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer)
> >
> >   struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
> >
> > -/*
> > - * vfe_disable - Disable streaming on VFE line
> > - * @line: VFE line
> > - *
> > - * Return 0 on success or a negative error code otherwise
> > - */
> > -int vfe_disable(struct vfe_line *line);
> > -
> >   int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
> >
> >   /*
> > @@ -191,8 +185,17 @@ int vfe_put_output(struct vfe_line *line);
> >   int vfe_release_wm(struct vfe_device *vfe, u8 wm);
> >   int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
> >
> > +/*
> > + * vfe_reset - Trigger reset on VFE module and wait to complete
> > + * @vfe: VFE device
> > + *
> > + * Return 0 on success or a negative error code otherwise
> > + */
> > +int vfe_reset(struct vfe_device *vfe);
> > +
> >   extern const struct vfe_hw_ops vfe_ops_4_1;
> >   extern const struct vfe_hw_ops vfe_ops_4_7;
> >   extern const struct vfe_hw_ops vfe_ops_4_8;
> > +extern const struct vfe_hw_ops vfe_ops_170;
> >
> >   #endif /* QC_MSM_CAMSS_VFE_H */
> > diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
> > index bd9334af1c73..b4943df9eaf6 100644
> > --- a/drivers/media/platform/qcom/camss/camss-video.c
> > +++ b/drivers/media/platform/qcom/camss/camss-video.c
> > @@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = {
> >         { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> >   };
> >
> > +static const struct camss_format_info formats_rdi_845[] = {
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 12 } },
> > +     { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 14 } },
> > +     { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 10 } },
> > +     { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +};
> > +
> >   static const struct camss_format_info formats_pix_8x16[] = {
> >       { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> >         { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > @@ -211,6 +260,49 @@ static const struct camss_format_info formats_pix_8x96[] = {
> >         { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> >   };
> >
> > +static const struct camss_format_info formats_pix_845[] = {
> > +     { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
> > +       { { 1, 1 } }, { { 2, 3 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1,
> > +       { { 1, 1 } }, { { 1, 2 } }, { 8 } },
> > +     { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +     { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1,
> > +       { { 1, 1 } }, { { 1, 1 } }, { 16 } },
> > +};
> > +
> >   /* -----------------------------------------------------------------------------
> >    * Helper functions
> >    */
> > @@ -960,6 +1052,14 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
> >                       video->formats = formats_rdi_8x96;
> >                       video->nformats = ARRAY_SIZE(formats_rdi_8x96);
> >               }
> > +     }  else if (video->camss->version == CAMSS_845) {
> > +             if (is_pix) {
> > +                     video->formats = formats_pix_845;
> > +                     video->nformats = ARRAY_SIZE(formats_pix_845);
> > +             } else {
> > +                     video->formats = formats_rdi_845;
> > +                     video->nformats = ARRAY_SIZE(formats_rdi_845);
> > +             }
> >       } else {
> >               goto error_video_register;
> >       }
> > diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> > index aeec59bc6194..1c3d64d612ff 100644
> > --- a/drivers/media/platform/qcom/camss/camss.c
> > +++ b/drivers/media/platform/qcom/camss/camss.c
> > @@ -465,6 +465,67 @@ static const struct resources vfe_res_660[] = {
> >       }
> >   };
> >
> > +static const struct resources vfe_res_845[] = {
> > +     /* VFE0 */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe0", "vfe0_axi",
> > +                             "vfe0_src", "csi0",
> > +                             "csi0_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 0 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe0" },
> > +             .interrupt = { "vfe0" }
> > +     },
> > +
> > +     /* VFE1 */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe1", "vfe1_axi",
> > +                             "vfe1_src", "csi1",
> > +                             "csi1_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 0 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe1" },
> > +             .interrupt = { "vfe1" }
> > +     },
> > +
> > +     /* VFE-lite */
> > +     {
> > +             .regulator = { NULL },
> > +             .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src",
> > +                             "soc_ahb", "vfe_lite",
> > +                             "vfe_lite_src", "csi2",
> > +                             "csi2_src"},
> > +             .clock_rate = { { 0 },
> > +                             { 0 },
> > +                             { 80000000 },
> > +                             { 0 },
> > +                             { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 },
> > +                             { 320000000 },
> > +                             { 19200000, 75000000, 384000000, 538666667 },
> > +                             { 384000000 } },
> > +             .reg = { "vfe_lite" },
> > +             .interrupt = { "vfe_lite" }
> > +     }
> > +};
> > +
> >   /*
> >    * camss_add_clock_margin - Add margin to clock frequency rate
> >    * @rate: Clock frequency rate
> >

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2021-01-14 12:09 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-08 12:04 [PATCH v1 00/17] Add support for SDM845 Camera Subsystem Robert Foss
2021-01-08 12:04 ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 01/17] media: camss: Fix comment using wrong function name Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 18:51   ` Bjorn Andersson
2021-01-08 18:51     ` Bjorn Andersson
2021-01-13 10:04     ` Robert Foss
2021-01-13 10:04       ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 02/17] media: camss: Fix vfe_isr comment typo Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 18:51   ` Bjorn Andersson
2021-01-08 18:51     ` Bjorn Andersson
2021-01-13 10:04     ` Robert Foss
2021-01-13 10:04       ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 03/17] media: camss: Add CAMSS_845 camss version Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 04/17] media: camss: Make ISPIF subdevice optional Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 19:07   ` Bjorn Andersson
2021-01-08 19:07     ` Bjorn Andersson
2021-01-13 15:02     ` Robert Foss
2021-01-13 15:02       ` Robert Foss
2021-01-13 22:28   ` Andrey Konovalov
2021-01-13 22:28     ` Andrey Konovalov
2021-01-14  9:55     ` Robert Foss
2021-01-14  9:55       ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 05/17] media: camss: Refactor VFE HW version support Robert Foss
2021-01-08 16:51   ` kernel test robot
2021-01-13 22:38   ` Andrey Konovalov
2021-01-14 10:07     ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 06/17] media: camss: Add support for VFE hardware version Titan 170 Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-14 10:48   ` Andrey Konovalov
2021-01-14 10:48     ` Andrey Konovalov
2021-01-14 12:07     ` Robert Foss
2021-01-14 12:07       ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 07/17] media: camss: Add missing format identifiers Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 08/17] media: camss: Refactor CSID HW version support Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 18:02   ` kernel test robot
2021-01-08 12:04 ` [PATCH v1 09/17] media: camss: Add support for CSID hardware version Titan 170 Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 10/17] media: camss: Add support for CSIPHY " Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 11/17] media: camss: Remove per VFE power domain toggling Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 12/17] media: dt-bindings: media: qcom,camss: Add bindings for SDM845 camss Robert Foss
2021-01-08 12:04   ` [PATCH v1 12/17] media: dt-bindings: media: qcom, camss: " Robert Foss
2021-01-09  1:44   ` [PATCH v1 12/17] media: dt-bindings: media: qcom,camss: " Laurent Pinchart
2021-01-09  1:44     ` Laurent Pinchart
2021-01-08 12:04 ` [PATCH v1 13/17] media: camss: Enable SDM845 Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 14/17] arm64: defconfig: Build Qcom CAMSS as module Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 15/17] arm64: dts: sdm845: Add CAMSS ISP node Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 16/17] arm64: dts: sdm845-db845c: " Robert Foss
2021-01-08 12:04   ` Robert Foss
2021-01-09  1:47   ` Laurent Pinchart
2021-01-09  1:47     ` Laurent Pinchart
2021-01-13 10:03     ` Robert Foss
2021-01-13 10:03       ` Robert Foss
2021-01-08 12:04 ` [PATCH v1 17/17] arm64: dts: sdm845-db845c: Enable ov8856 sensor and connect to ISP Robert Foss
2021-01-08 12:04   ` Robert Foss

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.