platform: dwc: Add of DesignWare MIPI CSI-2 Host
Subsystems (3)
v2 cover platform: dwc: Add of DesignWare MIPI CSI-2 Host
This adds support for Synopsys MIPI CSI-2 Host and MIPI D-PHY. The patch series include support for initialization/configuration of the DW MIPI CSI-2 controller and DW MIPI D-PHY and both include a reference platform driver.
This will enable future SoCs to use this standard approach and possibly create a more clean environment.
This series also documents the dt-bindings needed for the platform drivers.
This was applied in: https://git.linuxtv.org/media_tree.git
Luis Oliveira (5):
media: platform: Add a DesignWare folder to have Synopsys drivers
Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx
bindings
media: platform: dwc: Add DW MIPI DPHY Rx platform
Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
media: platform: dwc: Add MIPI CSI-2 controller driver
.../devicetree/bindings/media/snps,dw-csi-plat.txt | 74 +++ .../devicetree/bindings/phy/snps,dphy-rx.txt | 36 ++ MAINTAINERS | 11 + drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 3 + drivers/media/platform/dwc/Kconfig | 43 ++ drivers/media/platform/dwc/Makefile | 4 + drivers/media/platform/dwc/dw-csi-plat.c | 508 ++++++++++++++++++ drivers/media/platform/dwc/dw-csi-plat.h | 76 +++ drivers/media/platform/dwc/dw-dphy-plat.c | 365 +++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.c | 594 +++++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.h | 176 ++++++ drivers/media/platform/dwc/dw-mipi-csi.c | 490 +++++++++++++++++ drivers/media/platform/dwc/dw-mipi-csi.h | 202 +++++++ include/media/dwc/dw-mipi-csi-pltfrm.h | 101 ++++ 15 files changed, 2684 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefile create mode 100644 drivers/media/platform/dwc/dw-csi-plat.c create mode 100644 drivers/media/platform/dwc/dw-csi-plat.h create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.h create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.c create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.h create mode 100644 include/media/dwc/dw-mipi-csi-pltfrm.h
Signature · 1 line
2.9.3
PATCH v2 1/5 media: platform: Add a DesignWare folder to have Synopsys drivers
This patch has the intention of make the patch series more clear by creating a dwc folder.
---
Changelog
v2:
- Fix Kbuild error with no Makefile present
drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 3 +++ drivers/media/platform/dwc/Kconfig | 0 drivers/media/platform/dwc/Makefile | 0 4 files changed, 4 insertions(+) create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefile
drivers/media/platform/Kconfig +1 -0
@@ -137,6 +137,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" +source "drivers/media/platform/dwc/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver"
drivers/media/platform/Makefile +3 -0
@@ -98,3 +98,6 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += meson/ obj-y += cros-ec-cec/ + +obj-y += dwc/ +
drivers/media/platform/dwc/Kconfig new file +0 -0
drivers/media/platform/dwc/Makefile new file +0 -0
Signature · 1 line
2.9.3
Re: [V2, 1/5] media: platform: Add a DesignWare folder to have Synopsys drivers
Hi Luis,
Thank you for the patch.
Quoted 4 lines · On Thursday, 20 September 2018 14:16:39 EEST Luis Oliveira wrote:
This patch has the intention of make the patch series more clear by creating a dwc folder.
Signed-off-by Luis Oliveira <[email protected]>
No issue with the content, but you should fold this in patch 3/5, it doesn't deserve a patch on its own.
Quoted 42 lines
---
Changelog
v2:
- FixKbuilderror with noMakefilepresentdrivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 3 +++ drivers/media/platform/dwc/Kconfig | 0 drivers/media/platform/dwc/Makefile | 0 4 files changed, 4 insertions(+) create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefiledrivers/media/platform/Kconfig +1
-0@@ -137,6 +137,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" +source "drivers/media/platform/dwc/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver"(quoted diff) +0
-0b/drivers/media/platform/Makefile index 6ab6200..def2f33 100644
drivers/media/platform/Makefile +3
-0@@ -98,3 +98,6 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += meson/ obj-y += cros-ec-cec/ + +obj-y += dwc/ +(quoted diff) +0
-0b/drivers/media/platform/dwc/Kconfig new file mode 100644 index 0000000..e69de29
(quoted diff) +0
-0b/drivers/media/platform/dwc/Makefile new file mode 100644 index 0000000..e69de29
Signature · 3 lines
Regards, Laurent Pinchart
Re: [V2, 1/5] media: platform: Add a DesignWare folder to have Synopsys drivers
Quoted 5 lines · Laurent Pinchart
Hi Luis,
Thank you for the patch.
Quoted 9 lines
Quoted 4 lines · On Thursday, 20 September 2018 14:16:39 EEST Luis Oliveira wrote:
This patch has the intention of make the patch series more clear by creating a dwc folder.
Signed-off-by Luis Oliveira <[email protected]>No issue with the content, but you should fold this in patch 3/5, it doesn't deserve a patch on its own.
Thank you, I will do that in V3.
Quoted 43 lines
Quoted 42 lines
---
Changelog
v2:
- FixKbuilderror with noMakefilepresentdrivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 3 +++ drivers/media/platform/dwc/Kconfig | 0 drivers/media/platform/dwc/Makefile | 0 4 files changed, 4 insertions(+) create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefiledrivers/media/platform/Kconfig +1
-0@@ -137,6 +137,7 @@ source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" +source "drivers/media/platform/dwc/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver"(quoted diff) +0
-0b/drivers/media/platform/Makefile index 6ab6200..def2f33 100644
drivers/media/platform/Makefile +3
-0@@ -98,3 +98,6 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += meson/ obj-y += cros-ec-cec/ + +obj-y += dwc/ +(quoted diff) +0
-0b/drivers/media/platform/dwc/Kconfig new file mode 100644 index 0000000..e69de29
(quoted diff) +0
-0b/drivers/media/platform/dwc/Makefile new file mode 100644 index 0000000..e69de29
PATCH v2 2/5 Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
In reply to Luis OliveiraAdd device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
---
Changelog
v2:
- no changes
.../devicetree/bindings/phy/snps,dphy-rx.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +36 -0
@@ -0,0 +1,36 @@ +Synopsys DesignWare MIPI Rx D-PHY block details + +Description +----------- + +The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode. +Please refer to phy-bindings.txt for more information. + +Required properties: +- compatible : Shall be "snps,dphy-rx". +- #phy-cells : Must be 1. +- snps,dphy-frequency : Output frequency of the D-PHY. +- snps,dphy-te-len : Size of the communication interface (8 bits->8 or 12bits->12). +- reg : Physical base address and size of the device memory mapped + registers; + +Optional properties: +- snps,compat-mode : Compatibility mode control + +The per-board settings: +- gpios : Synopsys testchip used as reference uses this to change setup + configurations. + +Example: + + mipi_dphy_rx1: dphy@3040 { + compatible = "snps,dphy-rx"; + #phy-cells = <1>; + snps,dphy-frequency = <300000>; + snps,dphy-te-len = <12>; + snps,compat-mode = <1>; + reg = < 0x03040 0x20 + 0x08000 0x100 + 0x09000 0x100>; + }; +
Signature · 1 line
2.9.3
Re: [V2, 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
Hi Louis,
Thank you for the patch.
Quoted 22 lines · On Thursday, 20 September 2018 14:16:40 EEST Luis Oliveira wrote:
Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/phy/snps,dphy-rx.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt(quoted diff) +0
-0
b/Documentation/devicetree/bindings/phy/snps,dphy-rx.txtnew file mode 100644
index 0000000..9079f4aDocumentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +2
-0@@ -0,0 +1,36 @@ +Synopsys DesignWare MIPI Rx D-PHY block details +
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 12
Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +10
-0+Description +----------- + +The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode. +Please refer to phy-bindings.txt for more information. + +Required properties: +- compatible : Shall be "snps,dphy-rx". +- #phy-cells : Must be 1. +- snps,dphy-frequency : Output frequency of the D-PHY.
If that's the frequency of the clock on the output side of the RX PHY, doesn't it depend on the frequency on the CSI-2 (or other) bus ? Can't it vary ? Why do you need to have it in DT ?
Quoted 2 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+- snps,dphy-te-len : Size of the communication interface (8 bits->8 or12bits->12).
We have similar properties in various bindings, such as bus-width in video- interfaces.txt. Couldn't we use a more standard name ?
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 15
Quoted 2 lines
+- reg : Physical base address and size of the device memory mapped
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+ registers;
The example below shows three ranges. Could you document the ranges that are expected ?
Quoted 2 lines
+Optional properties:
+- snps,compat-mode : Compatibility mode control
What is this ?
Quoted 2 lines
+The per-board settings:
+- gpios : Synopsys testchip used as reference uses this to change
setup
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 22
Quoted 1 line
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+ configurations.
Here too, what is this for ?
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 34
Quoted 11 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +11
-0+Example: + + mipi_dphy_rx1: dphy@3040 { + compatible = "snps,dphy-rx"; + #phy-cells = <1>; + snps,dphy-frequency = <300000>; + snps,dphy-te-len = <12>; + snps,compat-mode = <1>; + reg = < 0x03040 0x20 + 0x08000 0x100 + 0x09000 0x100>;
The base addresses are pretty low, what kind of bus does this sit on ?
Quoted 2 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +2
-0+ }; +
Signature · 3 lines
Regards, Laurent Pinchart
Re: [V2, 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
Quoted 4 lines · Laurent Pinchart
Hi Louis,
Thank you for the patch.
Hi Laurent, thank you for your review, my answers are inline.
Quoted 29 lines · On Thursday, 20 September 2018 14:16:40 EEST Luis Oliveira wrote:
Quoted 28 lines
Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/phy/snps,dphy-rx.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txt(quoted diff) +0
-0
b/Documentation/devicetree/bindings/phy/snps,dphy-rx.txtnew file mode 100644
index 0000000..9079f4aDocumentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +8
-0@@ -0,0 +1,36 @@ +Synopsys DesignWare MIPI Rx D-PHY block details + +Description +----------- + +The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode. +Please refer to phy-bindings.txt for more information. +
Quoted 9 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 12
Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +4
-0+Required properties: +- compatible : Shall be "snps,dphy-rx". +- #phy-cells : Must be 1. +- snps,dphy-frequency : Output frequency of the D-PHY.If that's the frequency of the clock on the output side of the RX PHY, doesn't it depend on the frequency on the CSI-2 (or other) bus ? Can't it vary ? Why do you need to have it in DT ?
But you are right, I will move it to the CSI-2 block.
The reason for it to be on the DT is that my use case have a camera with fixed frequency connected, but of course I can change it after.
Quoted 5 lines
Quoted 2 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+- snps,dphy-te-len : Size of the communication interface (8 bits->8 or12bits->12).
We have similar properties in various bindings, such as bus-width in video- interfaces.txt. Couldn't we use a more standard name ?
I have read the bus-width property but I don't this is the same. This is not a video quite a video interface. Our D-PHY is configured using an control interface, which is called "test interface" and can have 8-bit or 12-bit.
Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 15
Quoted 3 lines
+- reg : Physical base address and size of the device memory mapped
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+ registers;The example below shows three ranges. Could you document the ranges that are expected ?
The three ranges is optional, it can be only two.
- The first is the interface from which we communicate with the d-phy. A small window the for the referenced above "test interface".
- The second and third reg are regions for configuration for the d-phy before the d-phy bring up:
a few examples:
- 4+4 data lanes max, 1 clk
- 8 data lanes max, 1clk
- 4+4 data lanes, 2 clk
Quoted 4 lines
Quoted 2 lines
+Optional properties:
+- snps,compat-mode : Compatibility mode controlWhat is this ?
This toggles a mode for a specific d-phy that we can't auto-detect. So when we use it we activate the compatibility mode for it. I can remove it if you think it's best.
Quoted 7 lines
Quoted 3 lines
+The per-board settings:
+- gpios : Synopsys testchip used as reference uses this to changesetup
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 22
Quoted 1 line
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +1
-0+ configurations.Here too, what is this for ?
Most of our d-phys have a wrapper around that can be controlled by a gpio-driver that can halt the d-phy.
Quoted 15 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 34
Quoted 12 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +11
-0+Example: + + mipi_dphy_rx1: dphy@3040 { + compatible = "snps,dphy-rx"; + #phy-cells = <1>; + snps,dphy-frequency = <300000>; + snps,dphy-te-len = <12>; + snps,compat-mode = <1>; + reg = < 0x03040 0x20 + 0x08000 0x100 + 0x09000 0x100>;The base addresses are pretty low, what kind of bus does this sit on ?
It sits on top of a bus like this for my configuration.
dx_mb {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x00000000 0x0 0xD0000000 0x10000000>;
interrupt-parent = <&he_intc>;
...Quoted 3 lines
Quoted 2 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +2
-0+ }; +
Rob Herring
maintainerRe: [V2, 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
In reply to Luis OliveiraQuoted 2 lines · Luis Oliveira
Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
"dt-bindings: phy: ..." for the subject.
Quoted 25 lines
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/phy/snps,dphy-rx.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txtDocumentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +8
-0@@ -0,0 +1,36 @@ +Synopsys DesignWare MIPI Rx D-PHY block details + +Description +----------- + +The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode. +Please refer to phy-bindings.txt for more information. +
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 18
Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +10
-0+Required properties: +- compatible : Shall be "snps,dphy-rx". +- #phy-cells : Must be 1. +- snps,dphy-frequency : Output frequency of the D-PHY. +- snps,dphy-te-len : Size of the communication interface (8 bits->8 or 12bits->12). +- reg : Physical base address and size of the device memory mapped + registers; + +Optional properties: +- snps,compat-mode : Compatibility mode control
type? values?
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 22
Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +4
-0+ +The per-board settings: +- gpios : Synopsys testchip used as reference uses this to change setup + configurations.
Preferred to be named (e.g. foo-gpios). How many? What are their functions?
Quoted 17 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +14
-0+ +Example: + + mipi_dphy_rx1: dphy@3040 { + compatible = "snps,dphy-rx"; + #phy-cells = <1>; + snps,dphy-frequency = <300000>; + snps,dphy-te-len = <12>; + snps,compat-mode = <1>; + reg = < 0x03040 0x20 + 0x08000 0x100 + 0x09000 0x100>; + }; +Signature · 1 line
2.9.3
Rob Herring
maintainerRe: [V2, 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
Quoted 8 lines · Rob Herring
Quoted 2 lines · Luis Oliveira
Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
"dt-bindings: phy: ..." for the subject.
Quoted 2 lines
Signed-off-by Luis Oliveira <[email protected]>
Also, checkpatch.pl complains the author and S-o-b emails don't match.
Rob
Re: [V2, 2/5] Documentation: dt-bindings: Document the Synopsys MIPI DPHY Rx bindings
In reply to Rob HerringHi Rob,
Quoted 6 lines · Rob Herring
Quoted 2 lines · Luis Oliveira
Add device-tree bindings documentation for SNPS DesignWare MIPI D-PHY in RX mode.
"dt-bindings: phy: ..." for the subject.
Yes, you are right.
Quoted 29 lines
Quoted 29 lines
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/phy/snps,dphy-rx.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dphy-rx.txtDocumentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +12
-0@@ -0,0 +1,36 @@ +Synopsys DesignWare MIPI Rx D-PHY block details + +Description +----------- + +The Synopsys MIPI D-PHY controller supports MIPI-DPHY in receiver mode. +Please refer to phy-bindings.txt for more information. + +Required properties: +- compatible : Shall be "snps,dphy-rx". +- #phy-cells : Must be 1. +- snps,dphy-frequency : Output frequency of the D-PHY.
Quoted 9 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 18
Quoted 6 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +6
-0+- snps,dphy-te-len : Size of the communication interface (8 bits->8 or 12bits->12). +- reg : Physical base address and size of the device memory mapped + registers; + +Optional properties: +- snps,compat-mode : Compatibility mode controltype? values?
I will remove this in V3.
Quoted 8 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt line 22
Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +4
-0+ +The per-board settings: +- gpios : Synopsys testchip used as reference uses this to change setup + configurations.Preferred to be named (e.g. foo-gpios). How many? What are their functions?
Ok, thanks for reviewing this.
Quoted 17 lines
Quoted 17 lines
Documentation/devicetree/bindings/phy/snps,dphy-rx.txt new file +14
-0+ +Example: + + mipi_dphy_rx1: dphy@3040 { + compatible = "snps,dphy-rx"; + #phy-cells = <1>; + snps,dphy-frequency = <300000>; + snps,dphy-te-len = <12>; + snps,compat-mode = <1>; + reg = < 0x03040 0x20 + 0x08000 0x100 + 0x09000 0x100>; + }; +Signature · 1 line
2.9.3
PATCH v2 3/5 media: platform: dwc: Add DW MIPI DPHY Rx platform
In reply to Luis OliveiraAdd of Synopsys MIPI D-PHY in RX mode support.
Separated in the implementation are platform dependent probing functions.
---
Changelog
v2:
- fix uninitialization warning
- fix SDPX License to match: Documentation/process/license-rules.rst
drivers/media/platform/dwc/Kconfig | 32 ++ drivers/media/platform/dwc/Makefile | 2 + drivers/media/platform/dwc/dw-dphy-plat.c | 365 ++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.c | 594 ++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.h | 176 +++++++++ 5 files changed, 1169 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.h
drivers/media/platform/dwc/Kconfig +32 -0
@@ -0,0 +1,32 @@ +# +# Synopsys DWC Platform drivers +# Most drivers here are currently for MIPI CSI-2 and MIPI DPHY support + +config DWC_MIPI_CSI2_HOST + bool "Synopsys Designware CSI-2 Host Controller and DPHY-RX support" + select VIDEO_DEV + select VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG + select GENERIC_PHY + select VIDEO_OV5647 + help + This selects the CSI-2 host controller support. + + If you have a controller with this interface, say Y. + + If unsure, say N. + +if DWC_MIPI_CSI2_HOST + +config DWC_MIPI_TC_DPHY_G128 + tristate "DesignWare platform support using a G128 Test Chip" + depends on DWC_MIPI_CSI2_HOST + help + Synopsys Test Chip is a MIPI D-PHY for prototyping purposes. + + If unsure, say N. + +endif # DWC_MIPI_CSI2_HOST +
drivers/media/platform/dwc/Makefile +2 -0
@@ -0,0 +1,2 @@ +obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128) += dw-dphy-platfrm.o +dw-dphy-platfrm-objs := dw-dphy-plat.o dw-dphy-rx.o
drivers/media/platform/dwc/dw-dphy-plat.c new file +365 -0
365 lines not on this page · raw message
drivers/media/platform/dwc/dw-dphy-rx.c new file +594 -0
594 lines not on this page · raw message
drivers/media/platform/dwc/dw-dphy-rx.h new file +176 -0
176 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [V2, 3/5] media: platform: dwc: Add DW MIPI DPHY Rx platform
Hi Louis,
Thank you for the patch.
Quoted 10 lines · On Thursday, 20 September 2018 14:16:41 EEST Luis Oliveira wrote:
Add of Synopsys MIPI D-PHY in RX mode support.
Separated in the implementation are platform dependent probing functions.Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- fix uninitialization warning
- fix SDPX License to match:Documentation/process/license-rules.rst
Quoted 5 lines
drivers/media/platform/dwc/Kconfig | 32 ++ drivers/media/platform/dwc/Makefile | 2 + drivers/media/platform/dwc/dw-dphy-plat.c | 365 ++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.c | 594 +++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.h | 176 +++++++++
Is there really a need to split this in two source files ? It smells of OS abstraction layers.
Quoted 4 lines
5 files changed, 1169 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.h
As this is a PHY driver, shouldn't it be located in drivers/phy/ ?
drivers/media/platform/dwc/Kconfig line 6
Quoted 11 lines
(quoted diff) +0
-0b/drivers/media/platform/dwc/Kconfig index e69de29..a573297 100644
drivers/media/platform/dwc/Kconfig +6
-0@@ -0,0 +1,32 @@ +# +# Synopsys DWC Platform drivers +# Most drivers here are currently for MIPI CSI-2 and MIPI DPHY support + +config DWC_MIPI_CSI2_HOST + bool "Synopsys Designware CSI-2 Host Controller and DPHY-RX support"
There's no CSI-2 host controller in this patch.
drivers/media/platform/dwc/Kconfig line 11
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ select VIDEO_DEV + select VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG
All these don't seem to be needed.
drivers/media/platform/dwc/Kconfig line 13
Quoted 2 lines
drivers/media/platform/dwc/Kconfig +2
-0+ select GENERIC_PHY + select VIDEO_OV5647
And I'm pretty sure you can use the PHY without an OV5647 sensor :-)
Quoted 32 lines
drivers/media/platform/dwc/Kconfig +19
-0+ help + This selects the CSI-2 host controller support. + + If you have a controller with this interface, say Y. + + If unsure, say N. + +if DWC_MIPI_CSI2_HOST + +config DWC_MIPI_TC_DPHY_G128 + tristate "DesignWare platform support using a G128 Test Chip" + depends on DWC_MIPI_CSI2_HOST + help + Synopsys Test Chip is a MIPI D-PHY for prototyping purposes. + + If unsure, say N. + +endif # DWC_MIPI_CSI2_HOST +(quoted diff) +0
-0b/drivers/media/platform/dwc/Makefile index e69de29..8be6f68 100644
drivers/media/platform/dwc/Makefile +2
-0@@ -0,0 +1,2 @@ +obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128) += dw-dphy-platfrm.o +dw-dphy-platfrm-objs := dw-dphy-plat.o dw-dphy-rx.o(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-plat.cnew file mode 100644 index 0000000..8e298f5
drivers/media/platform/dwc/dw-dphy-plat.c line 5
Quoted 5 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +5
-0@@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* dw-dphy-plat.c +* +* Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates.
I don't think that -present is right. The copyright notice should list the years explicitly.
Quoted 217 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +217
-0+* Luis Oliveira <[email protected]> +* +*/ + +#include "dw-dphy-rx.h" + +static struct phy *dw_dphy_xlate (struct device *dev, +struct of_phandle_args *args) +{ +struct dw_dphy_rx *dphy =dev_get_drvdata (dev); + +return dphy->phy; +} + +static ssize_t dphy_reset_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +usleep_range (100 ,200 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dphy_freq_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +int ret; +unsigned long freq; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &freq); +if (ret <0 ) +return ret; + +if (freq >2500 ) { +dev_info (dev,"Freq must be under 2500 Mhz\n" ); +return count; + } +if (freq <80 ) { +dev_info (dev,"Freq must be over 80 Mhz\n" ); +return count; + } + +dev_info (dev,"Data Rate %lu Mbps\n" , freq); + dphy->dphy_freq = freq *1000 ; + +return count; + +} + +static ssize_t dphy_freq_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +snprintf (buffer,15 ,"Freq %d\n" , dphy->dphy_freq /1000 ); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dphy_addr_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +unsigned long val; +int ret; +u8 addr, payload; + + ret =kstrtoul (buf,32 , &val); +if (ret <0 ) +return ret; + + payload = (u16 )val; + addr = (u16)(val >>16 ); + +dev_info (dev,"addr 0x%lX\n" , val); +dev_info (dev,"payload: 0x%X\n" , addr); + +dev_info (dev, +"Addr [0x%x] -> 0x%x\n" , (unsigned int )addr, +dw_dphy_te_read (dphy, addr)); + +return count; +} + +static ssize_t idelay_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +snprintf (buffer,15 ,"idelay %d\n" ,dw_dphy_if_get_idelay (dphy)); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t idelay_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +int ret; +unsigned long val; +u8 lane, delay; + + ret =kstrtoul (buf,16 , &val); +if (ret <0 ) +return ret; + + lane = (u8 )val; + delay = (u8)(val >>8 ); + +dev_dbg (dev,"Lanes %u\n" , lane); +dev_dbg (dev,"Delay %u\n" , delay); + +dw_dphy_if_set_idelay_lane (dphy, delay, lane); + +return count; +} + +static ssize_t len_config_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +int ret; +unsigned long length; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &length); +if (ret <0 ) +return ret; + +if (length ==BIT8 ) +pr_info ("Configured for 8-bit interface\n" ); +else if (length ==BIT12 ) +pr_info ("Configured for 12-bit interface\n" ); +else +return count; + + dphy->dphy_te_len = length; + +return count; + +} + +static ssize_t len_config_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[20 ]; + +snprintf (buffer,20 ,"Length %d\n" , dphy->dphy_te_len); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dw_dphy_g118_settle_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +int ret; +unsigned long lp_time; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &lp_time); +if (ret <0 ) +return ret; + +if ((lp_time >1 ) && (lp_time <10000 )) + dphy->lp_time = lp_time; +else { +pr_info ("Invalid Value configuring for 1000 ns\n" ); + dphy->lp_time =1000 ; + } + + dphy->lp_time = lp_time; + +return count; + +} + +static ssize_t dw_dphy_g118_settle_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[10 ]; + +snprintf (buffer,10 ,"Settle %d ns\n" , dphy->lp_time);
drivers/media/platform/dwc/dw-dphy-plat.c line 232
Quoted 10 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +10
-0+ +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static DEVICE_ATTR_RO (dphy_reset); +static DEVICE_ATTR_RW (dphy_freq); +static DEVICE_ATTR_WO (dphy_addr); +static DEVICE_ATTR_RW (idelay); +static DEVICE_ATTR_RW (len_config); +static DEVICE_ATTR_RW (dw_dphy_g118_settle);
If you want to expose an API through sysfs it should be properly documented. I don't think this is needed though, the PHY should be completely transparent for userspace, it should be handled fully within the kernel.
Quoted 121 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +121
-0+static struct phy_ops dw_dphy_ops = { + .init = dw_dphy_init, + .reset = dw_dphy_reset, + .power_on = dw_dphy_power_on, + .power_off = dw_dphy_power_off, + .owner =THIS_MODULE , +}; + +static int dw_dphy_rx_probe (struct platform_device *pdev) +{ +struct dw_dphy_rx *dphy; +struct device *dev = &pdev->dev; +struct resource *res; +struct phy_provider *phy_provider; +struct phy *phy; + + dphy =devm_kzalloc (dev,sizeof (*dphy),GFP_KERNEL ); +if (!dphy) +return -ENOMEM ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dphy->base_address =devm_ioremap (dev, res->start,resource_size (res)); +if (IS_ERR (dphy->base_address)) { +dev_err (dev,"error requesting base address\n" ); +return PTR_ERR (dphy->base_address); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + dphy->dphy1_if_addr =devm_ioremap_resource (dev, res); +if (IS_ERR (dphy->dphy1_if_addr)) { +dev_err (dev,"error requesting dphy 1 if regbank\n" ); +return PTR_ERR (dphy->dphy1_if_addr); + } + + dphy->max_lanes = +dw_dphy_if_read_msk (dphy,DPHYID ,DPHY_ID_LANE_SUPPORT ,4 ); + + dphy->dphy_gen =dw_dphy_if_read_msk (dphy,DPHYID ,DPHY_ID_GEN ,4 ); +dev_info (dev,"DPHY GEN %s with maximum %s lanes\n" , + dphy->dphy_gen ==GEN3 ?"3" :"2" , + dphy->max_lanes ==CTRL_8_LANES ?"8" :"4" ); + +if (dphy->max_lanes ==CTRL_8_LANES ) { + res =platform_get_resource (pdev,IORESOURCE_MEM ,2 ); + dphy->dphy2_if_addr = +devm_ioremap (dev, res->start,resource_size (res)); + +if (IS_ERR (dphy->dphy2_if_addr)) { +dev_err (dev,"error requesting dphy 2 if regbank\n" ); +return PTR_ERR (dphy->dphy2_if_addr); + } + + dphy->config_gpio =of_get_gpio (dev->of_node,0 ); +if (!gpio_is_valid (dphy->config_gpio)) { +dev_err (dev,"failed to parse config gpio\n" ); +return dphy->config_gpio; + } + } + +if (of_property_read_u32 (dev->of_node, +"snps,dphy-frequency" , + &dphy->dphy_freq)) { +dev_err (dev,"failed to find dphy frequency\n" ); +return -EINVAL ; + } + +if (of_property_read_u32 (dev->of_node, +"snps,dphy-te-len" , + &dphy->dphy_te_len)) { +dev_err (dev,"failed to find dphy te length\n" ); +return -EINVAL ; + } + +if (of_property_read_u32 (dev->of_node, +"snps,compat-mode" , + &dphy->compat_mode)) { +dev_err (dev,"failed to find compat mode\n" ); +return -EINVAL ; + } + +dev_set_drvdata (dev, dphy); +spin_lock_init (&dphy->slock); + + phy =devm_phy_create (dev,NULL , &dw_dphy_ops); +if (IS_ERR (phy)) { +dev_err (dev,"failed to create PHY\n" ); +return PTR_ERR (phy); + } + + dphy->phy = phy; +phy_set_drvdata (phy, dphy); + + phy_provider =devm_of_phy_provider_register (dev, dw_dphy_xlate); +if (IS_ERR (phy_provider)) { +dev_err (dev,"error getting phy provider\n" ); +return PTR_ERR (phy_provider); + } + + dphy->lp_time =1000 ;/* 1000 ns */ + dphy->lanes_config =dw_dphy_setup_config (dphy); +dev_dbg (dev,"rx-dphy created\n" ); + +device_create_file (&pdev->dev, &dev_attr_dphy_reset); +device_create_file (&pdev->dev, &dev_attr_dphy_freq); +device_create_file (&pdev->dev, &dev_attr_dphy_addr); +device_create_file (&pdev->dev, &dev_attr_idelay); +device_create_file (&pdev->dev, &dev_attr_len_config); +device_create_file (&pdev->dev, &dev_attr_dw_dphy_g118_settle); + +return 0 ; +} + +static const struct of_device_id dw_dphy_rx_of_match[] = { + { .compatible ="snps,dphy-rx" }, + { }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_rx_of_match); + +static struct platform_driver dw_dphy_rx_driver = { + .probe = dw_dphy_rx_probe, + .driver = {
drivers/media/platform/dwc/dw-dphy-plat.c line 364
Quoted 10 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +10
-0+ .of_match_table = dw_dphy_rx_of_match, + .name = "snps-dphy-rx", + .owner = THIS_MODULE, + } +}; +module_platform_driver (dw_dphy_rx_driver); + +MODULE_DESCRIPTION ("SNPS MIPI DPHY Rx driver" ); +MODULE_AUTHOR ("Luis Oliveira <[email protected]>" ); +MODULE_LICENSE ("GPL v2" );
"GPL v2" means just that, while the SPDX header mentions GPL-2.0+. You can pick your license of choice (or rather your employer should, as it seems they own the copyright on the code based on the copyright header above), but SPDX and MODULE_LICENSE should match.
Quoted 782 lines
(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-rx.cnew file mode 100644 index 0000000..4100ea5drivers/media/platform/dwc/dw-dphy-rx.c new file +167
-0@@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Synopsys MIPI D-PHY driver +* +* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. +* Author: Luis Oliveira <[email protected]> +* +*/ + +#include "dw-dphy-rx.h" + +struct range_dphy_gen2 { +u64 freq; +u8 hsfregrange; +}; + +struct range_dphy_gen2 range_gen2[] = { + {80 ,0x00 }, {90 ,0x10 }, {100 ,0x20 }, + {110 ,0x30 }, {120 ,0x01 }, {130 ,0x11 }, + {140 ,0x21 }, {150 ,0x31 }, {160 ,0x02 }, + {170 ,0x12 }, {180 ,0x22 }, {190 ,0x32 }, + {205 ,0x03 }, {220 ,0x13 }, {235 ,0x23 }, + {250 ,0x33 }, {275 ,0x04 }, {300 ,0x14 }, + {325 ,0x05 }, {350 ,0x15 }, {400 ,0x25 }, + {450 ,0x06 }, {500 ,0x16 }, {550 ,0x07 }, + {600 ,0x17 }, {650 ,0x08 }, {700 ,0x18 }, + {750 ,0x09 }, {800 ,0x19 }, {850 ,0x29 }, + {900 ,0x39 }, {950 ,0x0A }, {1000 ,0x1A }, + {1050 ,0x2A }, {1100 ,0x3A }, {1150 ,0x0B }, + {1200 ,0x1B }, {1250 ,0x2B }, {1300 ,0x3B }, + {1350 ,0x0C }, {1400 ,0x1C }, {1450 ,0x2C }, + {1500 ,0x3C }, {1550 ,0x0D }, {1600 ,0x1D }, + {1650 ,0x2D }, {1700 ,0x0E }, {1750 ,0x1E }, + {1800 ,0x2E }, {1850 ,0x3E }, {1900 ,0x0F }, + {1950 ,0x1F }, {2000 ,0x2F }, +}; + +struct range_dphy_gen3 { +u64 freq; +u8 hsfregrange; +u32 osc_freq_target; +}; + +struct range_dphy_gen3 range_gen3[] = { + + {80 ,0x00 ,0x1B6 }, {90 ,0x10 ,0x1B6 }, {100 ,0x20 ,0x1B6 }, + {110 ,0x30 ,0x1B6 }, {120 ,0x01 ,0x1B6 }, {130 ,0x11 ,0x1B6 }, + {140 ,0x21 ,0x1B6 }, {150 ,0x31 ,0x1B6 }, {160 ,0x02 ,0x1B6 }, + {170 ,0x12 ,0x1B6 }, {180 ,0x22 ,0x1B6 }, {190 ,0x32 ,0x1B6 }, + {205 ,0x03 ,0x1B6 }, {220 ,0x13 ,0x1B6 }, {235 ,0x23 ,0x1B6 }, + {250 ,0x33 ,0x1B6 }, {275 ,0x04 ,0x1B6 }, {300 ,0x14 ,0x1B6 }, + {325 ,0x25 ,0x1B6 }, {350 ,0x35 ,0x1B6 }, {400 ,0x05 ,0x1B6 }, + {450 ,0x16 ,0x1B6 }, {500 ,0x26 ,0x1B6 }, {550 ,0x37 ,0x1B6 }, + {600 ,0x07 ,0x1B6 }, {650 ,0x18 ,0x1B6 }, {700 ,0x28 ,0x1B6 }, + {750 ,0x39 ,0x1B6 }, {800 ,0x09 ,0x1B6 }, {850 ,0x19 ,0x1B6 }, + {900 ,0x29 ,0x1B6 }, {950 ,0x3A ,0x1B6 }, {1000 ,0x0A ,0x1B6 }, + {1050 ,0x1A ,0x1B6 }, {1100 ,0x2A ,0x1B6 }, {1150 ,0x3B ,0x1B6 }, + {1200 ,0x0B ,0x1B6 }, {1250 ,0x1B ,0x1B6 }, {1300 ,0x2B ,0x1B6 }, + {1350 ,0x3C ,0x1B6 }, {1400 ,0x0C ,0x1B6 }, {1450 ,0x1C ,0x1B6 }, + {1500 ,0x2C ,0x1B6 }, {1550 ,0x3D ,0x10F }, {1600 ,0x0D ,0x118 }, + {1650 ,0x1D ,0x121 }, {1700 ,0x2E ,0x12A }, {1750 ,0x3E ,0x132 }, + {1800 ,0x0E ,0x13B }, {1850 ,0x1E ,0x144 }, {1900 ,0x2F ,0x14D }, + {1950 ,0x3F ,0x155 }, {2000 ,0x0F ,0x15E }, {2050 ,0x40 ,0x167 }, + {2100 ,0x41 ,0x170 }, {2150 ,0x42 ,0x178 }, {2200 ,0x43 ,0x181 }, + {2250 ,0x44 ,0x18A }, {2300 ,0x45 ,0x193 }, {2350 ,0x46 ,0x19B }, + {2400 ,0x47 ,0x1A4 }, {2450 ,0x48 ,0x1AD }, {2500 ,0x49 ,0x1B6 } +}; + +u8 dw_dphy_setup_config (struct dw_dphy_rx *dphy) +{ +u8 ret; +int setup_config; + +if (dphy->max_lanes ==CTRL_4_LANES ) +return CTRL_4_LANES ; + + ret =gpio_request (dphy->config_gpio,"config" ); +if (ret <0 ) { +pr_err ("could not acquire config gpio (err=%d)\n" , ret); +return ret; + } + + setup_config =gpio_get_value (dphy->config_gpio); +pr_debug ("CONFIG %s\n" , setup_config ==CTRL_8_LANES ?"8L" :"4+4L" ); +gpio_free (dphy->config_gpio); + +return setup_config; +} +void dw_dphy_if_write (struct dw_dphy_rx *dphy,u32 address,u32 data) +{ +iowrite32 (data, dphy->dphy1_if_addr + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) +return ; + +iowrite32 (data, dphy->dphy2_if_addr + address); +} + +u32 dw_dphy_if_read (struct dw_dphy_rx *dphy,u64 address) +{ +u32 if1 =0 , if2 =0 ; + + if1 =ioread32 (dphy->dphy1_if_addr + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) + goto end; + +if (dphy->lanes_config ==DPHYID ) + goto end; + + if2 =ioread32 (dphy->dphy2_if_addr + address); + +if (if1 != if2) +pr_err ("Values read different for each interface\n" ); + +end: +return if1; +} + +void dw_dphy_write (struct dw_dphy_rx *dphy,u32 address,u32 data) +{ +iowrite32 (data, dphy->base_address + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) +return ; + +if (address ==R_CSI2_DPHY_TST_CTRL0 ) +iowrite32 (data, dphy->base_address +R_CSI2_DPHY2_TST_CTRL0 ); +else if (address ==R_CSI2_DPHY_TST_CTRL1 ) +iowrite32 (data, dphy->base_address +R_CSI2_DPHY2_TST_CTRL1 ); +} + +u32 dw_dphy_read (struct dw_dphy_rx *dphy,u64 address) +{ +u32 dphy1 =0 , dphy2 =0 ; + + dphy1 =ioread32 (dphy->base_address + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) + goto end; + +if (address ==R_CSI2_DPHY_TST_CTRL0 ) + dphy2 =ioread32 (dphy->base_address +R_CSI2_DPHY2_TST_CTRL0 ); +else if (address ==R_CSI2_DPHY_TST_CTRL1 ) + dphy2 =ioread32 (dphy->base_address +R_CSI2_DPHY2_TST_CTRL1 ); +else +return -ENODEV ; + +if (dphy1 != dphy2) +pr_err ("Values read different for each dphy\n" ); + +end: +return dphy1; +} + +void dw_dphy_write_msk (struct dw_dphy_rx *dev, +u64 address,u64 data,u8 shift,u8 width) +{ +u32 mask = (1 << width) -1 ; +u32 temp =dw_dphy_read (dev, address); + + temp &= ~(mask << shift); + temp |= (data & mask) << shift; +dw_dphy_write (dev, address, temp); +} + +static void dw_dphy_te_12b_write(struct dw_dphy_rx *dphy, u16 addr, u8data) +{
drivers/media/platform/dwc/dw-dphy-rx.c new file +426
-0+dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8) (addr >>8 ),PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) data,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +} + +static void dw_dphy_te_8b_write (struct dw_dphy_rx *dphy,u8 addr,u8 data) +{ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_TST_CTRL1 , addr); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_TST_CTRL1 , data); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +} + +static void dw_dphy_te_write (struct dw_dphy_rx *dphy,u16 addr,u8 data) +{ + +if (dphy->dphy_te_len ==BIT12 ) +dw_dphy_te_12b_write (dphy, addr, data); +else +dw_dphy_te_8b_write (dphy, addr, data); +} + +static int dw_dphy_te_12b_read (struct dw_dphy_rx *dphy,u32 addr) +{ +u8 ret; + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8) (addr >>8 ),PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,0 ,PHY_TESTDIN ); + ret =dw_dphy_read_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,PHY_TESTDOUT ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); + +return ret; +} + +static int dw_dphy_te_8b_read (struct dw_dphy_rx *dphy,u32 addr) +{ +u8 ret; + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 , addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTDIN ,8 ); + ret =dw_dphy_read_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,PHY_TESTDOUT ,8 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); + +return ret; +} + +int dw_dphy_te_read (struct dw_dphy_rx *dphy,u32 addr) +{ +int ret; + +if (dphy->dphy_te_len ==BIT12 ) + ret =dw_dphy_te_12b_read (dphy, addr); +else + ret =dw_dphy_te_8b_read (dphy, addr); + +return ret; +} + +static void dw_dphy_if_init (struct dw_dphy_rx *dphy) +{ +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,TX_PHY ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +} + +static void dw_dphy_gen3_12bit_tc_power_up (struct dw_dphy_rx *dphy) +{ +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_te_write (dphy,CFGCLKFREQRANGE_TX ,0x1C ); + +/* CLKSEL | UPDATEPLL | SHADOW_CLEAR | SHADOW_CTRL | FORCEPLL */ +dw_dphy_te_write (dphy,BYPASS ,0x3F ); + +/* IO_DS3 | IO_DS2 | IO_DS1 | IO_DS0 */ +if (dphy->dphy_freq >1500 ) +dw_dphy_te_write (dphy,IO_DS ,0x0F ); + +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +} + +static void dw_dphy_gen3_8bit_tc_power_up (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq /1000 ; + +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_te_write (dphy,CFGCLKFREQRANGE_RX ,0x1C ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX0_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX0_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX1_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX1_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX2_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX2_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX3_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX3_LSB ,0x02 ); +dw_dphy_te_write (dphy,BANDGAP_CTRL ,0x80 ); + +if (input_freq <2000 ) +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE0 ,0xC0 ); + +if (input_freq <1000 ) { +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE1 ,0xC0 ); +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE2 ,0xC0 ); +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE3 ,0xC0 ); + } +} + +int dw_dphy_g118_settle (struct dw_dphy_rx *dphy) +{ +u32 input_freq, total_settle, settle_time, byte_clk, lp_time; + + lp_time = dphy->lp_time; + input_freq = dphy->dphy_freq /1000 ; + + settle_time = (8 * (1000000 /(input_freq))) +115000 ; + byte_clk = (8000000 /(input_freq)); + total_settle = (settle_time + lp_time *1000 ) / byte_clk; + +if (total_settle >0xFF ) + total_settle =0xFF ; + +return total_settle; +} + +static void dw_dphy_pwr_down (struct dw_dphy_rx *dphy) +{ +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); + +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +if (dphy->lanes_config ==CTRL_8_LANES ) +dw_dphy_write_msk (dphy, +R_CSI2_DPHY2_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +} + +static void dw_dphy_pwr_up (struct dw_dphy_rx *dphy) +{ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +if (dphy->lanes_config ==CTRL_8_LANES ) +dw_dphy_write_msk (dphy, +R_CSI2_DPHY2_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +} + +static int dw_dphy_gen3_12bit_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 range =0 ; + +pr_debug ("PHY GEN 3 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen3) -1 ) && + ((input_freq /1000 ) > range_gen3[range].freq); range++) + ; + +dw_dphy_gen3_12bit_tc_power_up (dphy); + +dw_dphy_te_write (dphy,RX_SYS_1 , range_gen3[range].hsfregrange); +dw_dphy_te_write (dphy,RX_SYS_0 ,0x20 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_2 , + (u8 ) range_gen3[range].osc_freq_target); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_3 , + (u8) (range_gen3[range].osc_freq_target >>8 )); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_4 ,0x01 ); + +if (dphy->compat_mode) { +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_1 ,0x01 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_0 ,0x80 ); + } + +if ((dphy->compat_mode) || (input_freq <=1500 )) +dw_dphy_te_write (dphy,RX_SYS_7 ,0x38 ); + +return 0 ; +} + +static int dw_dphy_gen3_8bit_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 data; +u8 range =0 ; + +pr_debug ("PHY GEN 3 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen3) -1 ) && + ((input_freq /1000 ) > range_gen3[range].freq); range++) + ; + +dw_dphy_te_write (dphy,RX_SKEW_CAL ,dw_dphy_g118_settle (dphy)); + data =1 <<7 | range_gen3[range].hsfregrange; +dw_dphy_te_write (dphy,HSFREQRANGE_8BIT , data); +dw_dphy_gen3_8bit_tc_power_up (dphy); + +return 0 ; +} + +static int dw_dphy_gen2_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 data; +u8 range =0 ; + +/* provide an initial active-high test clear pulse in TESTCLR */ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); + +pr_debug ("PHY GEN 2 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen2) -1 ) && + ((input_freq /1000 ) > range_gen2[range].freq); range++) + ; + + data = range_gen2[range].hsfregrange <<1 ; +dw_dphy_te_write (dphy,HSFREQRANGE_8BIT , data); + +return 0 ; +} + +static int dw_dphy_configure (struct dw_dphy_rx *dphy) +{ +dw_dphy_pwr_down (dphy); + +if (dphy->dphy_gen ==GEN3 ) { +dw_dphy_if_init (dphy); + +if (dphy->dphy_te_len ==BIT12 ) +dw_dphy_gen3_12bit_configure (dphy); +else +dw_dphy_gen3_8bit_configure (dphy); + }else +dw_dphy_gen2_configure (dphy); + +dw_dphy_pwr_up (dphy); + +return 0 ; +} + +int dw_dphy_if_set_idelay (struct dw_dphy_rx *dphy,u8 dly,u8 cells) +{ +uint32_t val =0 ; + +dw_dphy_if_write (dphy,IDLYCFG ,0 ); + +dw_dphy_if_write (dphy,IDLYSEL , cells); +dw_dphy_if_write (dphy,IDLYCNTINVAL , dly); + +/* Pulse Value Set */ +dw_dphy_if_write (dphy,IDLYCFG ,1 ); +usleep_range (10 ,20 ); +dw_dphy_if_write (dphy,IDLYCFG ,0 ); + +/* Pulse IDELAY CTRL Reset */ +dw_dphy_if_write (dphy,DPHY1REGRSTN ,0 ); +usleep_range (10 ,20 ); +dw_dphy_if_write (dphy,DPHY1REGRSTN ,1 ); + +/* Get Value*/ + val =dw_dphy_if_read (dphy,IDLYCNTOUTVAL ); + +if (val != dly) { +pr_info ("odelay config failed, set %d get %d" , dly, val); +return -1 ; + } + +return 0 ; +} + +int dw_dphy_if_get_idelay (struct dw_dphy_rx *dphy) +{ +return dw_dphy_if_read (dphy,IDLYCNTOUTVAL ); +} + +int dw_dphy_if_set_idelay_lane (struct dw_dphy_rx *dphy,u8 dly,u8 lane) +{ +int cell; + +switch (lane) { +case 0 : +for (cell =3 ; cell <=10 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 1 : +for (cell =14 ; cell <=21 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 2 : +for (cell =24 ; cell <=31 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 3 : +for (cell =34 ; cell <=41 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 4 :/* ALL */ +dw_dphy_if_set_idelay (dphy, dly,0x7F ); +break ; +default : +pr_err ("Lane Value not recognized\n" ); +return -1 ; + } +return 0 ; +} + +int dw_dphy_init (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); + +return 0 ; +} + +static int dw_dphy_set_phy_state (struct dw_dphy_rx *dphy,u32 on) +{ +u8 hs_freq; + + dphy->lanes_config =dw_dphy_setup_config (dphy); + +if (dphy->dphy_te_len ==BIT12 ) + hs_freq =RX_SYS_1 ; +else + hs_freq =HSFREQRANGE_8BIT ; + +if (on) { +dw_dphy_configure (dphy); +pr_debug ("HS Code: 0X%x\n" ,dw_dphy_te_read (dphy, hs_freq)); + }else { +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); + } + +return 0 ; +} + +int dw_dphy_power_on (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +return dw_dphy_set_phy_state (dphy,1 ); +} + +int dw_dphy_power_off (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +return dw_dphy_set_phy_state (dphy,0 ); +} + +int dw_dphy_reset (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +usleep_range (100 ,200 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); + +return 0 ; +}(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-rx.hnew file mode 100644 index 0000000..5375685drivers/media/platform/dwc/dw-dphy-rx.h new file +172
-0@@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* +* Synopsys MIPI D-PHY driver +* +* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. +* Author: Luis Oliveira <[email protected]> +*/ + +#ifndef __PHY_SNPS_DPHY_RX_H__ +#define __PHY_SNPS_DPHY_RX_H__ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +/* DPHY interface register bank*/ +#define R_CSI2_DPHY_SHUTDOWNZ 0x0 +#define R_CSI2_DPHY_RSTZ 0x4 +#define R_CSI2_DPHY_RX 0x8 +#define R_CSI2_DPHY_STOPSTATE 0xC +#define R_CSI2_DPHY_TST_CTRL0 0x10 +#define R_CSI2_DPHY_TST_CTRL1 0x14 +#define R_CSI2_DPHY2_TST_CTRL0 0x18 +#define R_CSI2_DPHY2_TST_CTRL1 0x1C + +enum dphy_id_mask { +DPHY_ID_LANE_SUPPORT =0 , +DPHY_ID_IF =4 , +DPHY_ID_GEN =8 , +}; + +enum dphy_gen_values { +GEN1 =0 , +GEN2 =1 , +GEN3 =2 , +}; + +enum dphy_interface_length { +BIT8 =8 , +BIT12 =12 , +}; + +enum tst_ctrl0 { +PHY_TESTCLR =0 , +PHY_TESTCLK =1 , +}; + +enum tst_ctrl1 { +PHY_TESTDIN =0 , +PHY_TESTDOUT =8 , +PHY_TESTEN =16 , +}; + +enum lanes_config_values { +CTRL_4_LANES =0 , +CTRL_8_LANES =1 , +}; + +enum dphy_tc { +CFGCLKFREQRANGE_TX =0x02 , +CFGCLKFREQRANGE_RX =0x05 , +BYPASS =0x20 , +IO_DS =0x30 , +}; + +enum dphy_8bit_interface_addr { +BANDGAP_CTRL =0x24 , +HS_RX_CTRL_LANE0 =0x42 , +HSFREQRANGE_8BIT =0x44 , +OSC_FREQ_TARGET_RX0_LSB =0x4e , +OSC_FREQ_TARGET_RX0_MSB =0x4f , +HS_RX_CTRL_LANE1 =0x52 , +OSC_FREQ_TARGET_RX1_LSB =0x5e , +OSC_FREQ_TARGET_RX1_MSB =0x5f , +RX_SKEW_CAL =0x7e , +HS_RX_CTRL_LANE2 =0x82 , +OSC_FREQ_TARGET_RX2_LSB =0x8e , +OSC_FREQ_TARGET_RX2_MSB =0x8f , +HS_RX_CTRL_LANE3 =0x92 , +OSC_FREQ_TARGET_RX3_LSB =0x9e , +OSC_FREQ_TARGET_RX3_MSB =0x9f , +}; + +enum dphy_12bit_interface_addr { +RX_SYS_0 =0x01 , +RX_SYS_1 =0x02 , +RX_SYS_7 =0x08 , +RX_RX_STARTUP_OVR_0 =0xe0 , +RX_RX_STARTUP_OVR_1 =0xe1 , +RX_RX_STARTUP_OVR_2 =0xe2 , +RX_RX_STARTUP_OVR_3 =0xe3 , +RX_RX_STARTUP_OVR_4 =0xe4 , +}; + +/* Gen3 interface register bank*/ +#define IDLYCFG 0x00 +#define IDLYSEL 0x04 +#define IDLYCNTINVAL 0x08 +#define IDLYCNTOUTVAL 0x0c +#define DPHY1REGRSTN 0x10 +#define DPHYZCALSTAT 0x14 +#define DPHYZCALCTRL 0x18 +#define DPHYLANE0STAT 0x1c +#define DPHYLANE1STAT 0x20 +#define DPHYLANE2STAT 0x24 +#define DPHYLANE3STAT 0x28 +#define DPHYCLKSTAT 0x2c +#define DPHYZCLKCTRL 0x30 +#define TCGENPURPOSOUT 0x34 +#define TCGENPURPOSIN 0x38 +#define DPHYGENERICOUT 0x3c +#define DPHYGENERICIN 0x40 +#define DPHYGLUEIFTESTER 0x44 +#define DPHYID 0x100 + +enum glueiftester { +GLUELOGIC =0x4 , +RX_PHY =0x2 , +TX_PHY =0x1 , +RESET =0x0 , +}; + +struct dw_dphy_rx { +spinlock_t slock; +struct phy *phy; +uint32_t dphy_freq; +uint32_t dphy_gen; +uint32_t dphy_te_len; +uint32_t lanes_config; +uint32_t max_lanes; +uint32_t compat_mode; +uint32_t lp_time; + +void __iomem *base_address;/* test interface */ +void __iomem *dphy1_if_addr;/* gluelogic phy 1 */ +void __iomem *dphy2_if_addr;/* gluelogic phy 2 */ + +int config_gpio; +uint8_t setup_config; +}; + +int dw_dphy_init (struct phy *phy); +int dw_dphy_reset (struct phy *phy); +int dw_dphy_power_off (struct phy *phy); +int dw_dphy_power_on (struct phy *phy); + +u8 dw_dphy_setup_config (struct dw_dphy_rx *dphy); +u32 dw_dphy_if_read (struct dw_dphy_rx *dphy,u64 address); +void dw_dphy_write (struct dw_dphy_rx *dphy,u32 address,u32 data); +u32 dw_dphy_read (struct dw_dphy_rx *dphy,u64 address); +int dw_dphy_te_read (struct dw_dphy_rx *dphy,u32 addr); +int dw_dphy_if_get_idelay (struct dw_dphy_rx *dphy); +int dw_dphy_if_set_idelay_lane (struct dw_dphy_rx *dphy,u8 dly,u8 lane); + +static inline +u32 dw_dphy_if_read_msk (struct dw_dphy_rx *dphy, +u32 address,u8 shift,u8 width) +{ +return (dw_dphy_if_read (dphy, address) >> shift) & ((1 << width) -1 ); +} + +static inline +u32 dw_dphy_read_msk(struct dw_dphy_rx *dev, u32 address, u8 shift, u8width) +{
drivers/media/platform/dwc/dw-dphy-rx.h new file +3
-0+ return (dw_dphy_read(dev, address) >> shift) & ((1 << width) - 1); +} +#endif /*__PHY_SNPS_DPHY_RX_H__*/
Signature · 3 lines
Regards, Laurent Pinchart
Re: [V2, 3/5] media: platform: dwc: Add DW MIPI DPHY Rx platform
Quoted 3 lines · Laurent Pinchart
Hi Louis,
Thank you for the patch.
Hi Laurent,
My answers inline.
Quoted 12 lines · On Thursday, 20 September 2018 14:16:41 EEST Luis Oliveira wrote:
Quoted 10 lines
Add of Synopsys MIPI D-PHY in RX mode support.
Separated in the implementation are platform dependent probing functions.Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- fix uninitialization warning
- fix SDPX License to match:Documentation/process/license-rules.rst
Quoted 9 lines
Quoted 5 lines
drivers/media/platform/dwc/Kconfig | 32 ++ drivers/media/platform/dwc/Makefile | 2 + drivers/media/platform/dwc/dw-dphy-plat.c | 365 ++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.c | 594 +++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-dphy-rx.h | 176 +++++++++Is there really a need to split this in two source files ? It smells of OS abstraction layers.
The purpose of the division is to separate d-phy configuration from platform
dependent configuration. We will add PCI support in the future.
Quoted 7 lines
Quoted 4 lines
5 files changed, 1169 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-dphy-plat.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.c create mode 100644 drivers/media/platform/dwc/dw-dphy-rx.hAs this is a PHY driver, shouldn't it be located in
drivers/phy/?
You are right I suppose, I will move it.
Quoted 5 lines
Quoted 5 lines
(quoted diff) +0
-0b/drivers/media/platform/dwc/Kconfig index e69de29..a573297 100644
drivers/media/platform/dwc/Kconfig +0
-0@@ -0,0 +1,32 @@
Quoted 9 lines
drivers/media/platform/dwc/Kconfig line 6
Quoted 6 lines
drivers/media/platform/dwc/Kconfig +6
-0+# +# Synopsys DWC Platform drivers +# Most drivers here are currently for MIPI CSI-2 and MIPI DPHY support + +config DWC_MIPI_CSI2_HOST + bool "Synopsys Designware CSI-2 Host Controller and DPHY-RX support"There's no CSI-2 host controller in this patch.
This was initially a place holder for the
Quoted 8 lines
drivers/media/platform/dwc/Kconfig line 11
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ select VIDEO_DEV + select VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIGAll these don't seem to be needed.
Quoted 4 lines
drivers/media/platform/dwc/Kconfig line 13
Quoted 2 lines
drivers/media/platform/dwc/Kconfig +2
-0+ select GENERIC_PHY + select VIDEO_OV5647And I'm pretty sure you can use the PHY without an OV5647 sensor :-)
Yes. This is an error, I will fix it
Quoted 33 lines
Quoted 33 lines
drivers/media/platform/dwc/Kconfig +19
-0+ help + This selects the CSI-2 host controller support. + + If you have a controller with this interface, say Y. + + If unsure, say N. + +if DWC_MIPI_CSI2_HOST + +config DWC_MIPI_TC_DPHY_G128 + tristate "DesignWare platform support using a G128 Test Chip" + depends on DWC_MIPI_CSI2_HOST + help + Synopsys Test Chip is a MIPI D-PHY for prototyping purposes. + + If unsure, say N. + +endif # DWC_MIPI_CSI2_HOST +(quoted diff) +0
-0b/drivers/media/platform/dwc/Makefile index e69de29..8be6f68 100644
drivers/media/platform/dwc/Makefile +2
-0@@ -0,0 +1,2 @@ +obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128) += dw-dphy-platfrm.o +dw-dphy-platfrm-objs := dw-dphy-plat.o dw-dphy-rx.o(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-plat.cnew file mode 100644 index 0000000..8e298f5drivers/media/platform/dwc/dw-dphy-plat.c new file +0
-0@@ -0,0 +1,365 @@
Quoted 9 lines
drivers/media/platform/dwc/dw-dphy-plat.c line 5
Quoted 5 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +5
-0+// SPDX-License-Identifier: GPL-2.0+ +/* +* dw-dphy-plat.c +* +* Copyright(c) 2018-present, Synopsys, Inc. and/or its affiliates. I don't think that -present is right. The copyright notice should list the years explicitly.
Ok, I will check that
Quoted 223 lines
Quoted 223 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +223
-0+* Luis Oliveira <[email protected]> +* +*/ + +#include "dw-dphy-rx.h" + +static struct phy *dw_dphy_xlate (struct device *dev, +struct of_phandle_args *args) +{ +struct dw_dphy_rx *dphy =dev_get_drvdata (dev); + +return dphy->phy; +} + +static ssize_t dphy_reset_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +usleep_range (100 ,200 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dphy_freq_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +int ret; +unsigned long freq; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &freq); +if (ret <0 ) +return ret; + +if (freq >2500 ) { +dev_info (dev,"Freq must be under 2500 Mhz\n" ); +return count; + } +if (freq <80 ) { +dev_info (dev,"Freq must be over 80 Mhz\n" ); +return count; + } + +dev_info (dev,"Data Rate %lu Mbps\n" , freq); + dphy->dphy_freq = freq *1000 ; + +return count; + +} + +static ssize_t dphy_freq_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +snprintf (buffer,15 ,"Freq %d\n" , dphy->dphy_freq /1000 ); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dphy_addr_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +unsigned long val; +int ret; +u8 addr, payload; + + ret =kstrtoul (buf,32 , &val); +if (ret <0 ) +return ret; + + payload = (u16 )val; + addr = (u16)(val >>16 ); + +dev_info (dev,"addr 0x%lX\n" , val); +dev_info (dev,"payload: 0x%X\n" , addr); + +dev_info (dev, +"Addr [0x%x] -> 0x%x\n" , (unsigned int )addr, +dw_dphy_te_read (dphy, addr)); + +return count; +} + +static ssize_t idelay_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[15 ]; + +snprintf (buffer,15 ,"idelay %d\n" ,dw_dphy_if_get_idelay (dphy)); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t idelay_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +int ret; +unsigned long val; +u8 lane, delay; + + ret =kstrtoul (buf,16 , &val); +if (ret <0 ) +return ret; + + lane = (u8 )val; + delay = (u8)(val >>8 ); + +dev_dbg (dev,"Lanes %u\n" , lane); +dev_dbg (dev,"Delay %u\n" , delay); + +dw_dphy_if_set_idelay_lane (dphy, delay, lane); + +return count; +} + +static ssize_t len_config_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +int ret; +unsigned long length; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &length); +if (ret <0 ) +return ret; + +if (length ==BIT8 ) +pr_info ("Configured for 8-bit interface\n" ); +else if (length ==BIT12 ) +pr_info ("Configured for 12-bit interface\n" ); +else +return count; + + dphy->dphy_te_len = length; + +return count; + +} + +static ssize_t len_config_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[20 ]; + +snprintf (buffer,20 ,"Length %d\n" , dphy->dphy_te_len); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static ssize_t dw_dphy_g118_settle_store (struct device *dev, +struct device_attribute *attr, +const char *buf, +size_t count) +{ +int ret; +unsigned long lp_time; + +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); + + ret =kstrtoul (buf,10 , &lp_time); +if (ret <0 ) +return ret; + +if ((lp_time >1 ) && (lp_time <10000 )) + dphy->lp_time = lp_time; +else { +pr_info ("Invalid Value configuring for 1000 ns\n" ); + dphy->lp_time =1000 ; + } + + dphy->lp_time = lp_time; + +return count; + +} + +static ssize_t dw_dphy_g118_settle_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct platform_device *pdev =to_platform_device (dev); +struct dw_dphy_rx *dphy =platform_get_drvdata (pdev); +char buffer[10 ]; + +snprintf (buffer,10 ,"Settle %d ns\n" , dphy->lp_time); + +return strlcpy (buf, buffer,PAGE_SIZE ); +} + +static DEVICE_ATTR_RO (dphy_reset); +static DEVICE_ATTR_RW (dphy_freq);
Quoted 9 lines
drivers/media/platform/dwc/dw-dphy-plat.c line 232
Quoted 4 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +4
-0+static DEVICE_ATTR_WO (dphy_addr); +static DEVICE_ATTR_RW (idelay); +static DEVICE_ATTR_RW (len_config); +static DEVICE_ATTR_RW (dw_dphy_g118_settle);If you want to expose an API through sysfs it should be properly documented. I don't think this is needed though, the PHY should be completely transparent for userspace, it should be handled fully within the kernel.
We have clients that use this. This is very useful for debug but I will try to come up with a better solution.
Quoted 128 lines
Quoted 128 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +128
-0+static struct phy_ops dw_dphy_ops = { + .init = dw_dphy_init, + .reset = dw_dphy_reset, + .power_on = dw_dphy_power_on, + .power_off = dw_dphy_power_off, + .owner =THIS_MODULE , +}; + +static int dw_dphy_rx_probe (struct platform_device *pdev) +{ +struct dw_dphy_rx *dphy; +struct device *dev = &pdev->dev; +struct resource *res; +struct phy_provider *phy_provider; +struct phy *phy; + + dphy =devm_kzalloc (dev,sizeof (*dphy),GFP_KERNEL ); +if (!dphy) +return -ENOMEM ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dphy->base_address =devm_ioremap (dev, res->start,resource_size (res)); +if (IS_ERR (dphy->base_address)) { +dev_err (dev,"error requesting base address\n" ); +return PTR_ERR (dphy->base_address); + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + dphy->dphy1_if_addr =devm_ioremap_resource (dev, res); +if (IS_ERR (dphy->dphy1_if_addr)) { +dev_err (dev,"error requesting dphy 1 if regbank\n" ); +return PTR_ERR (dphy->dphy1_if_addr); + } + + dphy->max_lanes = +dw_dphy_if_read_msk (dphy,DPHYID ,DPHY_ID_LANE_SUPPORT ,4 ); + + dphy->dphy_gen =dw_dphy_if_read_msk (dphy,DPHYID ,DPHY_ID_GEN ,4 ); +dev_info (dev,"DPHY GEN %s with maximum %s lanes\n" , + dphy->dphy_gen ==GEN3 ?"3" :"2" , + dphy->max_lanes ==CTRL_8_LANES ?"8" :"4" ); + +if (dphy->max_lanes ==CTRL_8_LANES ) { + res =platform_get_resource (pdev,IORESOURCE_MEM ,2 ); + dphy->dphy2_if_addr = +devm_ioremap (dev, res->start,resource_size (res)); + +if (IS_ERR (dphy->dphy2_if_addr)) { +dev_err (dev,"error requesting dphy 2 if regbank\n" ); +return PTR_ERR (dphy->dphy2_if_addr); + } + + dphy->config_gpio =of_get_gpio (dev->of_node,0 ); +if (!gpio_is_valid (dphy->config_gpio)) { +dev_err (dev,"failed to parse config gpio\n" ); +return dphy->config_gpio; + } + } + +if (of_property_read_u32 (dev->of_node, +"snps,dphy-frequency" , + &dphy->dphy_freq)) { +dev_err (dev,"failed to find dphy frequency\n" ); +return -EINVAL ; + } + +if (of_property_read_u32 (dev->of_node, +"snps,dphy-te-len" , + &dphy->dphy_te_len)) { +dev_err (dev,"failed to find dphy te length\n" ); +return -EINVAL ; + } + +if (of_property_read_u32 (dev->of_node, +"snps,compat-mode" , + &dphy->compat_mode)) { +dev_err (dev,"failed to find compat mode\n" ); +return -EINVAL ; + } + +dev_set_drvdata (dev, dphy); +spin_lock_init (&dphy->slock); + + phy =devm_phy_create (dev,NULL , &dw_dphy_ops); +if (IS_ERR (phy)) { +dev_err (dev,"failed to create PHY\n" ); +return PTR_ERR (phy); + } + + dphy->phy = phy; +phy_set_drvdata (phy, dphy); + + phy_provider =devm_of_phy_provider_register (dev, dw_dphy_xlate); +if (IS_ERR (phy_provider)) { +dev_err (dev,"error getting phy provider\n" ); +return PTR_ERR (phy_provider); + } + + dphy->lp_time =1000 ;/* 1000 ns */ + dphy->lanes_config =dw_dphy_setup_config (dphy); +dev_dbg (dev,"rx-dphy created\n" ); + +device_create_file (&pdev->dev, &dev_attr_dphy_reset); +device_create_file (&pdev->dev, &dev_attr_dphy_freq); +device_create_file (&pdev->dev, &dev_attr_dphy_addr); +device_create_file (&pdev->dev, &dev_attr_idelay); +device_create_file (&pdev->dev, &dev_attr_len_config); +device_create_file (&pdev->dev, &dev_attr_dw_dphy_g118_settle); + +return 0 ; +} + +static const struct of_device_id dw_dphy_rx_of_match[] = { + { .compatible ="snps,dphy-rx" }, + { }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_rx_of_match); + +static struct platform_driver dw_dphy_rx_driver = { + .probe = dw_dphy_rx_probe, + .driver = { + .of_match_table = dw_dphy_rx_of_match, + .name ="snps-dphy-rx" , + .owner =THIS_MODULE , + } +}; +module_platform_driver (dw_dphy_rx_driver); +
Quoted 9 lines
drivers/media/platform/dwc/dw-dphy-plat.c line 364
Quoted 3 lines
drivers/media/platform/dwc/dw-dphy-plat.c new file +3
-0+MODULE_DESCRIPTION ("SNPS MIPI DPHY Rx driver" ); +MODULE_AUTHOR ("Luis Oliveira <[email protected]>" ); +MODULE_LICENSE ("GPL v2" );"GPL v2" means just that, while the SPDX header mentions GPL-2.0+. You can pick your license of choice (or rather your employer should, as it seems they own the copyright on the code based on the copyright header above), but SPDX and
MODULE_LICENSEshould match.
Ok, thank you.
Quoted 784 lines
Quoted 782 lines
(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-rx.cnew file mode 100644 index 0000000..4100ea5drivers/media/platform/dwc/dw-dphy-rx.c new file +167
-0@@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Synopsys MIPI D-PHY driver +* +* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. +* Author: Luis Oliveira <[email protected]> +* +*/ + +#include "dw-dphy-rx.h" + +struct range_dphy_gen2 { +u64 freq; +u8 hsfregrange; +}; + +struct range_dphy_gen2 range_gen2[] = { + {80 ,0x00 }, {90 ,0x10 }, {100 ,0x20 }, + {110 ,0x30 }, {120 ,0x01 }, {130 ,0x11 }, + {140 ,0x21 }, {150 ,0x31 }, {160 ,0x02 }, + {170 ,0x12 }, {180 ,0x22 }, {190 ,0x32 }, + {205 ,0x03 }, {220 ,0x13 }, {235 ,0x23 }, + {250 ,0x33 }, {275 ,0x04 }, {300 ,0x14 }, + {325 ,0x05 }, {350 ,0x15 }, {400 ,0x25 }, + {450 ,0x06 }, {500 ,0x16 }, {550 ,0x07 }, + {600 ,0x17 }, {650 ,0x08 }, {700 ,0x18 }, + {750 ,0x09 }, {800 ,0x19 }, {850 ,0x29 }, + {900 ,0x39 }, {950 ,0x0A }, {1000 ,0x1A }, + {1050 ,0x2A }, {1100 ,0x3A }, {1150 ,0x0B }, + {1200 ,0x1B }, {1250 ,0x2B }, {1300 ,0x3B }, + {1350 ,0x0C }, {1400 ,0x1C }, {1450 ,0x2C }, + {1500 ,0x3C }, {1550 ,0x0D }, {1600 ,0x1D }, + {1650 ,0x2D }, {1700 ,0x0E }, {1750 ,0x1E }, + {1800 ,0x2E }, {1850 ,0x3E }, {1900 ,0x0F }, + {1950 ,0x1F }, {2000 ,0x2F }, +}; + +struct range_dphy_gen3 { +u64 freq; +u8 hsfregrange; +u32 osc_freq_target; +}; + +struct range_dphy_gen3 range_gen3[] = { + + {80 ,0x00 ,0x1B6 }, {90 ,0x10 ,0x1B6 }, {100 ,0x20 ,0x1B6 }, + {110 ,0x30 ,0x1B6 }, {120 ,0x01 ,0x1B6 }, {130 ,0x11 ,0x1B6 }, + {140 ,0x21 ,0x1B6 }, {150 ,0x31 ,0x1B6 }, {160 ,0x02 ,0x1B6 }, + {170 ,0x12 ,0x1B6 }, {180 ,0x22 ,0x1B6 }, {190 ,0x32 ,0x1B6 }, + {205 ,0x03 ,0x1B6 }, {220 ,0x13 ,0x1B6 }, {235 ,0x23 ,0x1B6 }, + {250 ,0x33 ,0x1B6 }, {275 ,0x04 ,0x1B6 }, {300 ,0x14 ,0x1B6 }, + {325 ,0x25 ,0x1B6 }, {350 ,0x35 ,0x1B6 }, {400 ,0x05 ,0x1B6 }, + {450 ,0x16 ,0x1B6 }, {500 ,0x26 ,0x1B6 }, {550 ,0x37 ,0x1B6 }, + {600 ,0x07 ,0x1B6 }, {650 ,0x18 ,0x1B6 }, {700 ,0x28 ,0x1B6 }, + {750 ,0x39 ,0x1B6 }, {800 ,0x09 ,0x1B6 }, {850 ,0x19 ,0x1B6 }, + {900 ,0x29 ,0x1B6 }, {950 ,0x3A ,0x1B6 }, {1000 ,0x0A ,0x1B6 }, + {1050 ,0x1A ,0x1B6 }, {1100 ,0x2A ,0x1B6 }, {1150 ,0x3B ,0x1B6 }, + {1200 ,0x0B ,0x1B6 }, {1250 ,0x1B ,0x1B6 }, {1300 ,0x2B ,0x1B6 }, + {1350 ,0x3C ,0x1B6 }, {1400 ,0x0C ,0x1B6 }, {1450 ,0x1C ,0x1B6 }, + {1500 ,0x2C ,0x1B6 }, {1550 ,0x3D ,0x10F }, {1600 ,0x0D ,0x118 }, + {1650 ,0x1D ,0x121 }, {1700 ,0x2E ,0x12A }, {1750 ,0x3E ,0x132 }, + {1800 ,0x0E ,0x13B }, {1850 ,0x1E ,0x144 }, {1900 ,0x2F ,0x14D }, + {1950 ,0x3F ,0x155 }, {2000 ,0x0F ,0x15E }, {2050 ,0x40 ,0x167 }, + {2100 ,0x41 ,0x170 }, {2150 ,0x42 ,0x178 }, {2200 ,0x43 ,0x181 }, + {2250 ,0x44 ,0x18A }, {2300 ,0x45 ,0x193 }, {2350 ,0x46 ,0x19B }, + {2400 ,0x47 ,0x1A4 }, {2450 ,0x48 ,0x1AD }, {2500 ,0x49 ,0x1B6 } +}; + +u8 dw_dphy_setup_config (struct dw_dphy_rx *dphy) +{ +u8 ret; +int setup_config; + +if (dphy->max_lanes ==CTRL_4_LANES ) +return CTRL_4_LANES ; + + ret =gpio_request (dphy->config_gpio,"config" ); +if (ret <0 ) { +pr_err ("could not acquire config gpio (err=%d)\n" , ret); +return ret; + } + + setup_config =gpio_get_value (dphy->config_gpio); +pr_debug ("CONFIG %s\n" , setup_config ==CTRL_8_LANES ?"8L" :"4+4L" ); +gpio_free (dphy->config_gpio); + +return setup_config; +} +void dw_dphy_if_write (struct dw_dphy_rx *dphy,u32 address,u32 data) +{ +iowrite32 (data, dphy->dphy1_if_addr + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) +return ; + +iowrite32 (data, dphy->dphy2_if_addr + address); +} + +u32 dw_dphy_if_read (struct dw_dphy_rx *dphy,u64 address) +{ +u32 if1 =0 , if2 =0 ; + + if1 =ioread32 (dphy->dphy1_if_addr + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) + goto end; + +if (dphy->lanes_config ==DPHYID ) + goto end; + + if2 =ioread32 (dphy->dphy2_if_addr + address); + +if (if1 != if2) +pr_err ("Values read different for each interface\n" ); + +end: +return if1; +} + +void dw_dphy_write (struct dw_dphy_rx *dphy,u32 address,u32 data) +{ +iowrite32 (data, dphy->base_address + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) +return ; + +if (address ==R_CSI2_DPHY_TST_CTRL0 ) +iowrite32 (data, dphy->base_address +R_CSI2_DPHY2_TST_CTRL0 ); +else if (address ==R_CSI2_DPHY_TST_CTRL1 ) +iowrite32 (data, dphy->base_address +R_CSI2_DPHY2_TST_CTRL1 ); +} + +u32 dw_dphy_read (struct dw_dphy_rx *dphy,u64 address) +{ +u32 dphy1 =0 , dphy2 =0 ; + + dphy1 =ioread32 (dphy->base_address + address); + +if (dphy->lanes_config ==CTRL_4_LANES ) + goto end; + +if (address ==R_CSI2_DPHY_TST_CTRL0 ) + dphy2 =ioread32 (dphy->base_address +R_CSI2_DPHY2_TST_CTRL0 ); +else if (address ==R_CSI2_DPHY_TST_CTRL1 ) + dphy2 =ioread32 (dphy->base_address +R_CSI2_DPHY2_TST_CTRL1 ); +else +return -ENODEV ; + +if (dphy1 != dphy2) +pr_err ("Values read different for each dphy\n" ); + +end: +return dphy1; +} + +void dw_dphy_write_msk (struct dw_dphy_rx *dev, +u64 address,u64 data,u8 shift,u8 width) +{ +u32 mask = (1 << width) -1 ; +u32 temp =dw_dphy_read (dev, address); + + temp &= ~(mask << shift); + temp |= (data & mask) << shift; +dw_dphy_write (dev, address, temp); +} + +static void dw_dphy_te_12b_write(struct dw_dphy_rx *dphy, u16 addr, u8data) +{
drivers/media/platform/dwc/dw-dphy-rx.c new file +426
-0+dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8) (addr >>8 ),PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) data,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +} + +static void dw_dphy_te_8b_write (struct dw_dphy_rx *dphy,u8 addr,u8 data) +{ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_TST_CTRL1 , addr); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_TST_CTRL1 , data); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +} + +static void dw_dphy_te_write (struct dw_dphy_rx *dphy,u16 addr,u8 data) +{ + +if (dphy->dphy_te_len ==BIT12 ) +dw_dphy_te_12b_write (dphy, addr, data); +else +dw_dphy_te_8b_write (dphy, addr, data); +} + +static int dw_dphy_te_12b_read (struct dw_dphy_rx *dphy,u32 addr) +{ +u8 ret; + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8) (addr >>8 ),PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy, +R_CSI2_DPHY_TST_CTRL1 , (u8 ) addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0x00 ,0 ,PHY_TESTDIN ); + ret =dw_dphy_read_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,PHY_TESTDOUT ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); + +return ret; +} + +static int dw_dphy_te_8b_read (struct dw_dphy_rx *dphy,u32 addr) +{ +u8 ret; + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,1 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 , addr,PHY_TESTDIN ,8 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTEN ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,0 ,PHY_TESTDIN ,8 ); + ret =dw_dphy_read_msk (dphy,R_CSI2_DPHY_TST_CTRL1 ,PHY_TESTDOUT ,8 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); + +return ret; +} + +int dw_dphy_te_read (struct dw_dphy_rx *dphy,u32 addr) +{ +int ret; + +if (dphy->dphy_te_len ==BIT12 ) + ret =dw_dphy_te_12b_read (dphy, addr); +else + ret =dw_dphy_te_8b_read (dphy, addr); + +return ret; +} + +static void dw_dphy_if_init (struct dw_dphy_rx *dphy) +{ +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,TX_PHY ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,0 ); +dw_dphy_if_write (dphy,DPHYZCALCTRL ,1 ); +} + +static void dw_dphy_gen3_12bit_tc_power_up (struct dw_dphy_rx *dphy) +{ +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_te_write (dphy,CFGCLKFREQRANGE_TX ,0x1C ); + +/* CLKSEL | UPDATEPLL | SHADOW_CLEAR | SHADOW_CTRL | FORCEPLL */ +dw_dphy_te_write (dphy,BYPASS ,0x3F ); + +/* IO_DS3 | IO_DS2 | IO_DS1 | IO_DS0 */ +if (dphy->dphy_freq >1500 ) +dw_dphy_te_write (dphy,IO_DS ,0x0F ); + +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +} + +static void dw_dphy_gen3_8bit_tc_power_up (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq /1000 ; + +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,GLUELOGIC ); +dw_dphy_te_write (dphy,CFGCLKFREQRANGE_RX ,0x1C ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RESET ); +dw_dphy_if_write (dphy,DPHYGLUEIFTESTER ,RX_PHY ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX0_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX0_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX1_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX1_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX2_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX2_LSB ,0x02 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX3_MSB ,0x03 ); +dw_dphy_te_write (dphy,OSC_FREQ_TARGET_RX3_LSB ,0x02 ); +dw_dphy_te_write (dphy,BANDGAP_CTRL ,0x80 ); + +if (input_freq <2000 ) +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE0 ,0xC0 ); + +if (input_freq <1000 ) { +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE1 ,0xC0 ); +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE2 ,0xC0 ); +dw_dphy_te_write (dphy,HS_RX_CTRL_LANE3 ,0xC0 ); + } +} + +int dw_dphy_g118_settle (struct dw_dphy_rx *dphy) +{ +u32 input_freq, total_settle, settle_time, byte_clk, lp_time; + + lp_time = dphy->lp_time; + input_freq = dphy->dphy_freq /1000 ; + + settle_time = (8 * (1000000 /(input_freq))) +115000 ; + byte_clk = (8000000 /(input_freq)); + total_settle = (settle_time + lp_time *1000 ) / byte_clk; + +if (total_settle >0xFF ) + total_settle =0xFF ; + +return total_settle; +} + +static void dw_dphy_pwr_down (struct dw_dphy_rx *dphy) +{ +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); + +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); +if (dphy->lanes_config ==CTRL_8_LANES ) +dw_dphy_write_msk (dphy, +R_CSI2_DPHY2_TST_CTRL0 ,0 ,PHY_TESTCLK ,1 ); + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +} + +static void dw_dphy_pwr_up (struct dw_dphy_rx *dphy) +{ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); +if (dphy->lanes_config ==CTRL_8_LANES ) +dw_dphy_write_msk (dphy, +R_CSI2_DPHY2_TST_CTRL0 ,1 ,PHY_TESTCLK ,1 ); + +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,1 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); +} + +static int dw_dphy_gen3_12bit_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 range =0 ; + +pr_debug ("PHY GEN 3 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen3) -1 ) && + ((input_freq /1000 ) > range_gen3[range].freq); range++) + ; + +dw_dphy_gen3_12bit_tc_power_up (dphy); + +dw_dphy_te_write (dphy,RX_SYS_1 , range_gen3[range].hsfregrange); +dw_dphy_te_write (dphy,RX_SYS_0 ,0x20 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_2 , + (u8 ) range_gen3[range].osc_freq_target); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_3 , + (u8) (range_gen3[range].osc_freq_target >>8 )); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_4 ,0x01 ); + +if (dphy->compat_mode) { +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_1 ,0x01 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_0 ,0x80 ); + } + +if ((dphy->compat_mode) || (input_freq <=1500 )) +dw_dphy_te_write (dphy,RX_SYS_7 ,0x38 ); + +return 0 ; +} + +static int dw_dphy_gen3_8bit_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 data; +u8 range =0 ; + +pr_debug ("PHY GEN 3 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen3) -1 ) && + ((input_freq /1000 ) > range_gen3[range].freq); range++) + ; + +dw_dphy_te_write (dphy,RX_SKEW_CAL ,dw_dphy_g118_settle (dphy)); + data =1 <<7 | range_gen3[range].hsfregrange; +dw_dphy_te_write (dphy,HSFREQRANGE_8BIT , data); +dw_dphy_gen3_8bit_tc_power_up (dphy); + +return 0 ; +} + +static int dw_dphy_gen2_configure (struct dw_dphy_rx *dphy) +{ +u32 input_freq = dphy->dphy_freq; +u8 data; +u8 range =0 ; + +/* provide an initial active-high test clear pulse in TESTCLR */ +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,1 ,PHY_TESTCLR ,1 ); +dw_dphy_write_msk (dphy,R_CSI2_DPHY_TST_CTRL0 ,0 ,PHY_TESTCLR ,1 ); + +pr_debug ("PHY GEN 2 Freq: %u\n" , input_freq); +for (range =0 ; (range <ARRAY_SIZE (range_gen2) -1 ) && + ((input_freq /1000 ) > range_gen2[range].freq); range++) + ; + + data = range_gen2[range].hsfregrange <<1 ; +dw_dphy_te_write (dphy,HSFREQRANGE_8BIT , data); + +return 0 ; +} + +static int dw_dphy_configure (struct dw_dphy_rx *dphy) +{ +dw_dphy_pwr_down (dphy); + +if (dphy->dphy_gen ==GEN3 ) { +dw_dphy_if_init (dphy); + +if (dphy->dphy_te_len ==BIT12 ) +dw_dphy_gen3_12bit_configure (dphy); +else +dw_dphy_gen3_8bit_configure (dphy); + }else +dw_dphy_gen2_configure (dphy); + +dw_dphy_pwr_up (dphy); + +return 0 ; +} + +int dw_dphy_if_set_idelay (struct dw_dphy_rx *dphy,u8 dly,u8 cells) +{ +uint32_t val =0 ; + +dw_dphy_if_write (dphy,IDLYCFG ,0 ); + +dw_dphy_if_write (dphy,IDLYSEL , cells); +dw_dphy_if_write (dphy,IDLYCNTINVAL , dly); + +/* Pulse Value Set */ +dw_dphy_if_write (dphy,IDLYCFG ,1 ); +usleep_range (10 ,20 ); +dw_dphy_if_write (dphy,IDLYCFG ,0 ); + +/* Pulse IDELAY CTRL Reset */ +dw_dphy_if_write (dphy,DPHY1REGRSTN ,0 ); +usleep_range (10 ,20 ); +dw_dphy_if_write (dphy,DPHY1REGRSTN ,1 ); + +/* Get Value*/ + val =dw_dphy_if_read (dphy,IDLYCNTOUTVAL ); + +if (val != dly) { +pr_info ("odelay config failed, set %d get %d" , dly, val); +return -1 ; + } + +return 0 ; +} + +int dw_dphy_if_get_idelay (struct dw_dphy_rx *dphy) +{ +return dw_dphy_if_read (dphy,IDLYCNTOUTVAL ); +} + +int dw_dphy_if_set_idelay_lane (struct dw_dphy_rx *dphy,u8 dly,u8 lane) +{ +int cell; + +switch (lane) { +case 0 : +for (cell =3 ; cell <=10 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 1 : +for (cell =14 ; cell <=21 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 2 : +for (cell =24 ; cell <=31 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 3 : +for (cell =34 ; cell <=41 ; cell++) +dw_dphy_if_set_idelay (dphy, dly, cell); +break ; +case 4 :/* ALL */ +dw_dphy_if_set_idelay (dphy, dly,0x7F ); +break ; +default : +pr_err ("Lane Value not recognized\n" ); +return -1 ; + } +return 0 ; +} + +int dw_dphy_init (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); + +return 0 ; +} + +static int dw_dphy_set_phy_state (struct dw_dphy_rx *dphy,u32 on) +{ +u8 hs_freq; + + dphy->lanes_config =dw_dphy_setup_config (dphy); + +if (dphy->dphy_te_len ==BIT12 ) + hs_freq =RX_SYS_1 ; +else + hs_freq =HSFREQRANGE_8BIT ; + +if (on) { +dw_dphy_configure (dphy); +pr_debug ("HS Code: 0X%x\n" ,dw_dphy_te_read (dphy, hs_freq)); + }else { +dw_dphy_write (dphy,R_CSI2_DPHY_SHUTDOWNZ ,0 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); + } + +return 0 ; +} + +int dw_dphy_power_on (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +return dw_dphy_set_phy_state (dphy,1 ); +} + +int dw_dphy_power_off (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +return dw_dphy_set_phy_state (dphy,0 ); +} + +int dw_dphy_reset (struct phy *phy) +{ +struct dw_dphy_rx *dphy =phy_get_drvdata (phy); + +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,0 ); +usleep_range (100 ,200 ); +dw_dphy_write (dphy,R_CSI2_DPHY_RSTZ ,1 ); + +return 0 ; +}(quoted diff) +0
-0
b/drivers/media/platform/dwc/dw-dphy-rx.hnew file mode 100644 index 0000000..5375685drivers/media/platform/dwc/dw-dphy-rx.h new file +172
-0@@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* +* Synopsys MIPI D-PHY driver +* +* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates. +* Author: Luis Oliveira <[email protected]> +*/ + +#ifndef __PHY_SNPS_DPHY_RX_H__ +#define __PHY_SNPS_DPHY_RX_H__ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +/* DPHY interface register bank*/ +#define R_CSI2_DPHY_SHUTDOWNZ 0x0 +#define R_CSI2_DPHY_RSTZ 0x4 +#define R_CSI2_DPHY_RX 0x8 +#define R_CSI2_DPHY_STOPSTATE 0xC +#define R_CSI2_DPHY_TST_CTRL0 0x10 +#define R_CSI2_DPHY_TST_CTRL1 0x14 +#define R_CSI2_DPHY2_TST_CTRL0 0x18 +#define R_CSI2_DPHY2_TST_CTRL1 0x1C + +enum dphy_id_mask { +DPHY_ID_LANE_SUPPORT =0 , +DPHY_ID_IF =4 , +DPHY_ID_GEN =8 , +}; + +enum dphy_gen_values { +GEN1 =0 , +GEN2 =1 , +GEN3 =2 , +}; + +enum dphy_interface_length { +BIT8 =8 , +BIT12 =12 , +}; + +enum tst_ctrl0 { +PHY_TESTCLR =0 , +PHY_TESTCLK =1 , +}; + +enum tst_ctrl1 { +PHY_TESTDIN =0 , +PHY_TESTDOUT =8 , +PHY_TESTEN =16 , +}; + +enum lanes_config_values { +CTRL_4_LANES =0 , +CTRL_8_LANES =1 , +}; + +enum dphy_tc { +CFGCLKFREQRANGE_TX =0x02 , +CFGCLKFREQRANGE_RX =0x05 , +BYPASS =0x20 , +IO_DS =0x30 , +}; + +enum dphy_8bit_interface_addr { +BANDGAP_CTRL =0x24 , +HS_RX_CTRL_LANE0 =0x42 , +HSFREQRANGE_8BIT =0x44 , +OSC_FREQ_TARGET_RX0_LSB =0x4e , +OSC_FREQ_TARGET_RX0_MSB =0x4f , +HS_RX_CTRL_LANE1 =0x52 , +OSC_FREQ_TARGET_RX1_LSB =0x5e , +OSC_FREQ_TARGET_RX1_MSB =0x5f , +RX_SKEW_CAL =0x7e , +HS_RX_CTRL_LANE2 =0x82 , +OSC_FREQ_TARGET_RX2_LSB =0x8e , +OSC_FREQ_TARGET_RX2_MSB =0x8f , +HS_RX_CTRL_LANE3 =0x92 , +OSC_FREQ_TARGET_RX3_LSB =0x9e , +OSC_FREQ_TARGET_RX3_MSB =0x9f , +}; + +enum dphy_12bit_interface_addr { +RX_SYS_0 =0x01 , +RX_SYS_1 =0x02 , +RX_SYS_7 =0x08 , +RX_RX_STARTUP_OVR_0 =0xe0 , +RX_RX_STARTUP_OVR_1 =0xe1 , +RX_RX_STARTUP_OVR_2 =0xe2 , +RX_RX_STARTUP_OVR_3 =0xe3 , +RX_RX_STARTUP_OVR_4 =0xe4 , +}; + +/* Gen3 interface register bank*/ +#define IDLYCFG 0x00 +#define IDLYSEL 0x04 +#define IDLYCNTINVAL 0x08 +#define IDLYCNTOUTVAL 0x0c +#define DPHY1REGRSTN 0x10 +#define DPHYZCALSTAT 0x14 +#define DPHYZCALCTRL 0x18 +#define DPHYLANE0STAT 0x1c +#define DPHYLANE1STAT 0x20 +#define DPHYLANE2STAT 0x24 +#define DPHYLANE3STAT 0x28 +#define DPHYCLKSTAT 0x2c +#define DPHYZCLKCTRL 0x30 +#define TCGENPURPOSOUT 0x34 +#define TCGENPURPOSIN 0x38 +#define DPHYGENERICOUT 0x3c +#define DPHYGENERICIN 0x40 +#define DPHYGLUEIFTESTER 0x44 +#define DPHYID 0x100 + +enum glueiftester { +GLUELOGIC =0x4 , +RX_PHY =0x2 , +TX_PHY =0x1 , +RESET =0x0 , +}; + +struct dw_dphy_rx { +spinlock_t slock; +struct phy *phy; +uint32_t dphy_freq; +uint32_t dphy_gen; +uint32_t dphy_te_len; +uint32_t lanes_config; +uint32_t max_lanes; +uint32_t compat_mode; +uint32_t lp_time; + +void __iomem *base_address;/* test interface */ +void __iomem *dphy1_if_addr;/* gluelogic phy 1 */ +void __iomem *dphy2_if_addr;/* gluelogic phy 2 */ + +int config_gpio; +uint8_t setup_config; +}; + +int dw_dphy_init (struct phy *phy); +int dw_dphy_reset (struct phy *phy); +int dw_dphy_power_off (struct phy *phy); +int dw_dphy_power_on (struct phy *phy); + +u8 dw_dphy_setup_config (struct dw_dphy_rx *dphy); +u32 dw_dphy_if_read (struct dw_dphy_rx *dphy,u64 address); +void dw_dphy_write (struct dw_dphy_rx *dphy,u32 address,u32 data); +u32 dw_dphy_read (struct dw_dphy_rx *dphy,u64 address); +int dw_dphy_te_read (struct dw_dphy_rx *dphy,u32 addr); +int dw_dphy_if_get_idelay (struct dw_dphy_rx *dphy); +int dw_dphy_if_set_idelay_lane (struct dw_dphy_rx *dphy,u8 dly,u8 lane); + +static inline +u32 dw_dphy_if_read_msk (struct dw_dphy_rx *dphy, +u32 address,u8 shift,u8 width) +{ +return (dw_dphy_if_read (dphy, address) >> shift) & ((1 << width) -1 ); +} + +static inline +u32 dw_dphy_read_msk(struct dw_dphy_rx *dev, u32 address, u8 shift, u8width) +{
drivers/media/platform/dwc/dw-dphy-rx.h new file +3
-0+ return (dw_dphy_read(dev, address) >> shift) & ((1 << width) - 1); +} +#endif /*__PHY_SNPS_DPHY_RX_H__*/
PATCH v2 4/5 Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
In reply to Luis OliveiraAdd bindings for Synopsys DesignWare MIPI CSI-2 host.
---
Changelog
v2:
- no changes
.../devicetree/bindings/media/snps,dw-csi-plat.txt | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +74 -0
@@ -0,0 +1,74 @@ +Synopsys DesignWare CSI-2 Host controller + +Description +----------- + +This HW block is used to receive image coming from an MIPI CSI-2 compatible +camera. + +Required properties: +- compatible: shall be "snps,dw-csi-plat" +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : CSI-2 Host interrupt +- snps,output-type : Core output to be used (IPI-> 0 or IDI->1 or BOTH->2) These + values choose which of the Core outputs will be used, it + can be Image Data Interface or Image Pixel Interface. +- phys : List of one PHY specifier (as defined in + Documentation/devicetree/bindings/phy/phy-bindings.txt). + This PHY is a MIPI DPHY working in RX mode. +- resets : Reference to a reset controller (optional) + +Optional properties(if in IPI mode): +- snps,ipi-mode : Mode to be used when in IPI(Camera -> 0 or Controller -> 1) + This property defines if the controller will use the video + timings available + in the video stream or if it will use pre-defined ones. +- snps,ipi-color-mode : Bus depth to be used in IPI (48 bits -> 0 or 16 bits -> 1) + This property defines the width of the IPI bus. +- snps,ipi-auto-flush : Data auto-flush (1 -> Yes or 0 -> No). This property defines + if the data is automatically flushed in each vsync or if + this process is done manually +- snps,virtual-channel : Virtual channel where data is present when in IPI mode. This + property chooses the virtual channel which IPI will use to + retrieve the video stream. + +The per-board settings: + - port sub-node describing a single endpoint connected to the camera as + described in video-interfaces.txt[1]. + +Example: + + csi2_1: csi2@3000 { + compatible = "snps,dw-csi-plat"; + #address-cells = <1>; + #size-cells = <0>; + reg = < 0x03000 0x7FF>; + interrupts = <2>; + output-type = <2>; + resets = <&dw_rst 1>; + phys = <&mipi_dphy_rx1 0>; + phy-names = "csi2-dphy"; + + /* IPI optional Configurations */ + snps,ipi-mode = <0>; + snps,ipi-color-mode = <0>; + snps,ipi-auto-flush = <1>; + snps,virtual-channel = <0>; + + /* CSI-2 per-board settings */ + port@1 { + reg = <1>; + csi1_ep1: endpoint { + remote-endpoint = <&camera_1>; + data-lanes = <1 2>; + }; + }; + port@2 { + csi1_ep2: endpoint { + remote-endpoint = <&vif1_ep>; + }; + }; + }; + +
Signature · 1 line
2.9.3
Re: [V2, 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
Hi Luis,
Thank you for the patch.
Quoted 47 lines · On Thursday, 20 September 2018 14:16:42 EEST Luis Oliveira wrote:
Add bindings for Synopsys DesignWare MIPI CSI-2 host.
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/media/snps,dw-csi-plat.txt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt(quoted diff) +0
-0
b/Documentation/devicetree/bindings/media/snps,dw-csi-plat.txtnew file mode 100644
index 0000000..028f5ebDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +14
-0@@ -0,0 +1,74 @@ +Synopsys DesignWare CSI-2 Host controller + +Description +----------- + +This HW block is used to receive image coming from an MIPI CSI-2 compatible +camera. + +Required properties: +- compatible: shall be "snps,dw-csi-plat" +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : CSI-2 Host interrupt +- snps,output-type : Core output to be used (IPI-> 0 or IDI->1 or BOTH-2)
TheseDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +9
-0+ values choose which of the Core outputs will be used, it + can be Image Data Interface or Image Pixel Interface. +- phys : List of one PHY specifier (as defined in + Documentation/devicetree/bindings/phy/phy-bindings.txt). + This PHY is a MIPI DPHY working in RX mode. +- resets : Reference to a reset controller (optional) + +Optional properties(if in IPI mode): +- snps,ipi-mode : Mode to be used when in IPI(Camera -> 0 or Controller -1)
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 26
Quoted 3 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +3
-0+ This property defines if the controller will use the video + timings available + in the video stream or if it will use pre-defined ones.
How does one select this ?
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 28
Quoted 3 lines
+- snps,ipi-color-mode : Bus depth to be used in IPI (48 bits -> 0 or 16
bits -> 1)Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ This property defines the width of the IPI bus.
How about using the standard bus-width property in the endpoint of the output port ?
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 31
Quoted 5 lines
+- snps,ipi-auto-flush : Data auto-flush (1 -> Yes or 0 -> No). This
property definesDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ if the data is automatically flushed in each vsyncor if
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ this process is done manually
This seems like a configuration option, not a hardware property. I don't think it belongs to DT.
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 34
Quoted 4 lines
+- snps,virtual-channel : Virtual channel where data is present when in IPI
mode. ThisDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +2
-0+ property chooses the virtual channel which IPI will use to + retrieve the video stream.
The virtual channel doesn't belong to DT, it should be queried from the sensor at runtime (and when a sensor can send multiple data streams, that should even be configurable).
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 38
Quoted 3 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +3
-0+The per-board settings: + - port sub-node describing a single endpoint connected to the camera as + described in video-interfaces.txt[1].
You need to explicitly list all the ports for this device, with their number and function.
Quoted 25 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +25
-0+Example: + + csi2_1: csi2@3000 { + compatible = "snps,dw-csi-plat"; + #address-cells = <1>; + #size-cells = <0>; + reg = < 0x03000 0x7FF>; + interrupts = <2>; + output-type = <2>; + resets = <&dw_rst 1>; + phys = <&mipi_dphy_rx1 0>; + phy-names = "csi2-dphy"; + + /* IPI optional Configurations */ + snps,ipi-mode = <0>; + snps,ipi-color-mode = <0>; + snps,ipi-auto-flush = <1>; + snps,virtual-channel = <0>; + + /* CSI-2 per-board settings */ + port@1 { + reg = <1>; + csi1_ep1: endpoint { + remote-endpoint = <&camera_1>; + data-lanes = <1 2>;
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 74
Quoted 10 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +10
-0+ }; + }; + port@2 { + csi1_ep2: endpoint { + remote-endpoint = <&vif1_ep>; + }; + }; + }; + +
Extra blank lines.
Signature · 3 lines
Regards, Laurent Pinchart
Re: [V2, 4/5] Documentation: dt-bindings: Document bindings for DW MIPI CSI-2 Host
Quoted 4 lines · Laurent Pinchart
Hi Luis,
Thank you for the patch.
Hi Laurent, thank you for your review.
My answers inline.
Quoted 47 lines · On Thursday, 20 September 2018 14:16:42 EEST Luis Oliveira wrote:
Quoted 46 lines
Add bindings for Synopsys DesignWare MIPI CSI-2 host.
Signed-off-by Luis Oliveira <[email protected]>---
Changelog
v2:
- no changes.../devicetree/bindings/media/snps,dw-csi-plat.txt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt(quoted diff) +0
-0
b/Documentation/devicetree/bindings/media/snps,dw-csi-plat.txtnew file mode 100644
index 0000000..028f5ebDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +14
-0@@ -0,0 +1,74 @@ +Synopsys DesignWare CSI-2 Host controller + +Description +----------- + +This HW block is used to receive image coming from an MIPI CSI-2 compatible +camera. + +Required properties: +- compatible: shall be "snps,dw-csi-plat" +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : CSI-2 Host interrupt +- snps,output-type : Core output to be used (IPI-> 0 or IDI->1 or BOTH-2)
TheseDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +9
-0+ values choose which of the Core outputs will be used, it + can be Image Data Interface or Image Pixel Interface. +- phys : List of one PHY specifier (as defined in + Documentation/devicetree/bindings/phy/phy-bindings.txt). + This PHY is a MIPI DPHY working in RX mode. +- resets : Reference to a reset controller (optional) + +Optional properties(if in IPI mode): +- snps,ipi-mode : Mode to be used when in IPI(Camera -> 0 or Controller -
Quoted 7 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 26
Quoted 4 lines
1)
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +3
-0+ This property defines if the controller will use the video + timings available + in the video stream or if it will use pre-defined ones.How does one select this ?
This is a hardware setting for timings in IPI (Image Pixel Interface - Synopsys specific interface), default is Controller mode - 1.
This can be selected in the DT or after by the driver.
Quoted 7 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 28
Quoted 3 lines
+- snps,ipi-color-mode : Bus depth to be used in IPI (48 bits -> 0 or 16
bits -> 1)Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ This property defines the width of the IPI bus.How about using the standard bus-width property in the endpoint of the output port ?
Here I think It makes sense, I will use your suggestion.
Quoted 9 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 31
Quoted 5 lines
+- snps,ipi-auto-flush : Data auto-flush (1 -> Yes or 0 -> No). This
property definesDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ if the data is automatically flushed in each vsyncor if
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +1
-0+ this process is done manuallyThis seems like a configuration option, not a hardware property. I don't think it belongs to DT.
I see your point,
Quoted 9 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 34
Quoted 4 lines
+- snps,virtual-channel : Virtual channel where data is present when in IPI
mode. ThisDocumentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +2
-0+ property chooses the virtual channel which IPI will use to + retrieve the video stream.The virtual channel doesn't belong to DT, it should be queried from the sensor at runtime (and when a sensor can send multiple data streams, that should even be configurable).
I will do that.
I made this properties for my tests with cameras, thinking of SoCs that have fixed HW configurations. But I can remove all this fields from the DT because all of them can be made after in the driver.
Quoted 7 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 38
Quoted 3 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +3
-0+The per-board settings: + - port sub-node describing a single endpoint connected to the camera as + described in video-interfaces.txt[1].You need to explicitly list all the ports for this device, with their number and function.
Ok.
Quoted 29 lines
Quoted 29 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +29
-0+Example: + + csi2_1: csi2@3000 { + compatible = "snps,dw-csi-plat"; + #address-cells = <1>; + #size-cells = <0>; + reg = < 0x03000 0x7FF>; + interrupts = <2>; + output-type = <2>; + resets = <&dw_rst 1>; + phys = <&mipi_dphy_rx1 0>; + phy-names = "csi2-dphy"; + + /* IPI optional Configurations */ + snps,ipi-mode = <0>; + snps,ipi-color-mode = <0>; + snps,ipi-auto-flush = <1>; + snps,virtual-channel = <0>; + + /* CSI-2 per-board settings */ + port@1 { + reg = <1>; + csi1_ep1: endpoint { + remote-endpoint = <&camera_1>; + data-lanes = <1 2>; + }; + }; + port@2 { + csi1_ep2: endpoint {
Quoted 8 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt line 74
Quoted 6 lines
Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt new file +6
-0+ remote-endpoint = <&vif1_ep>; + }; + }; + }; + +Extra blank lines.
Thanks.
Quoted 1 line
PATCH v2 5/5 media: platform: dwc: Add MIPI CSI-2 controller driver
In reply to Luis OliveiraAdd the Synopsys MIPI CSI-2 controller driver. This controller driver is divided in platform dependent functions and core functions. It also includes a platform for future DesignWare drivers.
---
Changelog
v2:
- fix SDPX License to match: Documentation/process/license-rules.rst
MAINTAINERS | 11 + drivers/media/platform/dwc/Kconfig | 11 + drivers/media/platform/dwc/Makefile | 2 + drivers/media/platform/dwc/dw-csi-plat.c | 508 +++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-csi-plat.h | 76 +++++ drivers/media/platform/dwc/dw-mipi-csi.c | 490 +++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-mipi-csi.h | 202 ++++++++++++ include/media/dwc/dw-mipi-csi-pltfrm.h | 101 ++++++ 8 files changed, 1401 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-csi-plat.c create mode 100644 drivers/media/platform/dwc/dw-csi-plat.h create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.c create mode 100644 drivers/media/platform/dwc/dw-mipi-csi.h create mode 100644 include/media/dwc/dw-mipi-csi-pltfrm.h
MAINTAINERS +11 -0
@@ -14032,6 +14032,16 @@ S: Maintained F: drivers/dma/dwi-axi-dmac/ F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.txt +SYNOPSYS DESIGNWARE MIPI CSI-2 HOST VIDEO PLATFORM +M: Luis Oliveira <[email protected]> +L: [email protected] +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/platform/dwc +F: include/media/dwc/dw-mipi-csi-pltfrm.h +F: Documentation/devicetree/bindings/media/snps,dw-csi-plat.txt +F: Documentation/devicetree/bindings/phy/snps,dphy-rx.txt + SYNOPSYS DESIGNWARE DMAC DRIVER M: Viresh Kumar <[email protected]> R: Andy Shevchenko <[email protected]>
@@ -16217,3 +16227,4 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git S: Buried alive in reporters F: * F: */ +
drivers/media/platform/dwc/Kconfig +11 -0
@@ -20,6 +20,17 @@ config DWC_MIPI_CSI2_HOST if DWC_MIPI_CSI2_HOST +config DWC_MIPI_CSI2_HOST_PLATFORM + tristate "Platform bus based CSI-2 Host Controller support" + depends on HAS_DMA + help + This selects the CSI-2 host controller support. Select this if + you have an CSI-2 Host controller on Platform bus. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config DWC_MIPI_TC_DPHY_G128 tristate "DesignWare platform support using a G128 Test Chip" depends on DWC_MIPI_CSI2_HOST
drivers/media/platform/dwc/Makefile +2 -0
@@ -1,2 +1,4 @@ +obj-$(CONFIG_DWC_MIPI_CSI2_HOST_PLATFORM) += dw-csi-platfrm.o +dw-csi-platfrm-objs := dw-csi-plat.o dw-mipi-csi.o obj-$(CONFIG_DWC_MIPI_TC_DPHY_G128) += dw-dphy-platfrm.o dw-dphy-platfrm-objs := dw-dphy-plat.o dw-dphy-rx.o
drivers/media/platform/dwc/dw-csi-plat.c new file +508 -0
508 lines not on this page · raw message
drivers/media/platform/dwc/dw-csi-plat.h new file +76 -0
76 lines not on this page · raw message
drivers/media/platform/dwc/dw-mipi-csi.c new file +490 -0
490 lines not on this page · raw message
drivers/media/platform/dwc/dw-mipi-csi.h new file +202 -0
202 lines not on this page · raw message
include/media/dwc/dw-mipi-csi-pltfrm.h new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
2.9.3
Hi Luis,
Quoted 11 lines · Luis Oliveira
This adds support for Synopsys MIPI CSI-2 Host and MIPI D-PHY. The patch series include support for initialization/configuration of the DW MIPI CSI-2 controller and DW MIPI D-PHY and both include a reference platform driver.
This will enable future SoCs to use this standard approach and possibly create a more clean environment.
This series also documents the dt-bindings needed for the platform drivers.
This was applied in: https://git.linuxtv.org/media_tree.git
I'm currently working on some MIPI D-PHY support through the generic phy framework that could benefit your patches.
https://lwn.net/Articles/764173/
Feel free to comment on that serie if you have any particular constraints or if you believe that some issues should be addressed.
Thanks!
Maxime
Signature · 3 lines
Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Quoted 15 lines · Maxime Ripard
Hi Luis,
Quoted 11 lines · Luis Oliveira
This adds support for Synopsys MIPI CSI-2 Host and MIPI D-PHY. The patch series include support for initialization/configuration of the DW MIPI CSI-2 controller and DW MIPI D-PHY and both include a reference platform driver.
This will enable future SoCs to use this standard approach and possibly create a more clean environment.
This series also documents the dt-bindings needed for the platform drivers.
This was applied in: https://git.linuxtv.org/media_tree.git
Quoted 7 lines
I'm currently working on some MIPI D-PHY support through the generic phy framework that could benefit your patches.
https://lwn.net/Articles/764173/
Feel free to comment on that serie if you have any particular constraints or if you believe that some issues should be addressed.
Hi Maxime,
I will check that, thanks!
Quoted 4 lines
Thanks!
Maxime