Skip to contentSkip to conversation

Rockchip Type-C and DispplayPort driver

PATCH Superseded Chris Zhong 7 participants 19 messages Jun 13, 2016 – Jun 20, 2016

Subsystems (6)

v2 of 15 Superseded Latest is v15 →

lore
Share & tools
lore
#0 lore raw

v2 cover Rockchip Type-C and DispplayPort driver

Hi all

This series patch is for rockchip Type-C phy and DisplayPort controller driver.

The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates. The Type-C cable orientation detection and Power Delivery (PD) is accomplished using a PD PHY or a exernal PD chip.

The DP controller is compliant with DisplayPort Specification, Version 1.3, This IP is compatible with the rockchip type-c PHY IP. There is a uCPU in DP controller, it need a firmware to work, please put the firmware file to /lib/firmware/cdn/dptx.bin. The uCPU in charge of aux communication and link training, the host use mailbox to communicate with the ucpu.

The PHY driver has register a notification with extcon API, to get the alt mode from PD, the PD driver need call the devm_extcon_dev_allocate to create a extcon device and use extcon_set_state to notify PHY and DP controller.

About the DP audio, cdn-dp registered 2 DAIs: 0 is I2S, 1 is SPDIF. We can reference them in simple-card.

This series is based on Mark Yao's branch:
https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2016-05-23

I test this patches on the rk3399-evb board, with a fusb302 driver, this branch has no rk3399.dtsi, so the patch about dts is not included in this series.

Changes in v2:
- add some registers description
- select RESET_CONTROLLER
- alphabetic order
- modify some spelling mistakes
- make mode cleaner
- use bool for enable/disable
- check all of the return value
- return a better err number
- use more readx_poll_timeout()
- clk_disable_unprepare(tcphy->clk_ref);
- remove unuse functions, rockchip_typec_phy_power_on/off
- remove unnecessary typecast from void *
- use dts node to distinguish between phys.
- Alphabetic order
- remove excess error message
- use define clk_rate
- check all return value
- remove dev_set_name(dp->dev, "cdn-dp");
- use schedule_delayed_work
- remove never-called functions
- remove some unnecessary ()

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset
- update the licence note
- init core clock to 50MHz
- use extcon API
- remove unused global
- add some comments for magic num
- change usleep_range(1000, 2000) tousleep_range(1000, 1050)
- remove __func__ from dev_err
- return err number when get clk failed
- remove ADDR_ADJ define
- use devm_clk_get(&pdev->dev, "tcpdcore")
- add extcon node description
- add #sound-dai-cells description
- use extcon API
- use hdmi-codec for the DP Asoc
- do not initialize the "ret"
- printk a err log when drm_of_encoder_active_endpoint_id
- modify the dclk pin_pol to a single line

Chris Zhong (4):
Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
phy: Add USB Type-C PHY driver for rk3399
Documentation: bindings: add dt documentation for cdn DP controller drm/rockchip: cdn-dp: add cdn DP support for rk3399

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  |  62 ++
 .../devicetree/bindings/phy/phy-rockchip-typec.txt |  77 ++
 drivers/gpu/drm/rockchip/Kconfig                   |   9 +
 drivers/gpu/drm/rockchip/Makefile                  |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c             | 694 +++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h             | 108 +++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c              | 717 ++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h              | 404 +++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   6 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
 drivers/phy/Kconfig                                |   8 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-rockchip-typec.c                   | 952 +++++++++++++++++++++
 include/linux/phy/phy-rockchip-typec.h             |  20 +
 15 files changed, 3062 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/linux/phy/phy-rockchip-typec.h
Signature · 1 line
2.6.3
#1 lore raw

PATCH v2 1/4 Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

 .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +77 -0
new file mode 100644
index 0000000..430920c
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+			 "rockchip,rk3399-typec-phy1"
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical, except
+these registers(description below), every register node contains 3 sections:
+offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;
+ - rockchip,usb3tousb2_en : the register of type-c force usb3 to usb2 enable
+   control.
+   for type-c phy0, it must be <0xe580 3 19>;
+   for type-c phy1, it must be <0xe58c 3 19>;
+ - rockchip,external_psm : the register of type-c phy external psm clock
+   selection.
+   for type-c phy0, it must be <0xe588 14 30>;
+   for type-c phy1, it must be <0xe594 14 30>;
+ - rockchip,pipe_status : the register of type-c phy pipe status.
+   for type-c phy0, it must be <0xe5c0 0 0>;
+   for type-c phy1, it must be <0xe5c0 16 16>;
+ - rockchip,uphy_dp_sel : the register of type-c phy selection for DP
+   for type-c phy0, it must be <0x6268 19 19>;
+   for type-c phy1, it must be <0x6268 3 19>;
+
+Example:
+	tcphy0: phy at ff7c0000 {
+		compatible = "rockchip,rk3399-typec-phy0";
+		reg = <0x0 0xff7c0000 0x0 0x40000>;
+		#phy-cells = <0>;
+		extcon = <&fusb1>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY0>,
+			 <&cru SRST_UPHY0_PIPE_L00>,
+			 <&cru SRST_P_UPHY0_TCPHY>;
+		reset-names = "tcphy", "tcphy_pipe", "uphy_tcphy";
+		rockchip,typec_conn_dir = <0xe580 0 16>;
+		rockchip,usb3tousb2_en = <0xe580 3 19>;
+		rockchip,external_psm = <0xe588 14 30>;
+		rockchip,pipe_status = <0xe5c0 0 0>;
+		rockchip,uphy_dp_sel = <0x6268 19 19>;
+	};
+
+	tcphy1: phy at ff800000 {
+		compatible = "rockchip,rk3399-typec-phy1";
+		reg = <0x0 0xff800000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+			 <&cru SCLK_UPHY1_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY1>,
+		         <&cru SRST_UPHY1_PIPE_L00>,
+			 <&cru SRST_P_UPHY1_TCPHY>;
+		reset-names = "tcphy", "tcphy_pipe", "uphy_tcphy";
+		rockchip,typec_conn_dir = <0xe58c 0 16>;
+		rockchip,usb3tousb2_en = <0xe58c 3 19>;
+		rockchip,external_psm = <0xe594 14 30>;
+		rockchip,pipe_status = <0xe5c0 16 16>;
+		rockchip,uphy_dp_sel = <0x6268 3 19>;
+	};
Signature · 1 line
2.6.3
maintainer
#2 lore raw

Re: [v2 PATCH 1/4] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

Quoted 25 lines · Chris Zhong

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

 .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +0 -0
new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 6

Quoted 6 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +6 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+			 "rockchip,rk3399-typec-phy1"

Unless these blocks are different, these should be be same compat string.

Quoted 5 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +5 -0
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 21

Quoted 10 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +10 -0
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical, except
+these registers(description below), every register node contains 3 sections:
+offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,

Don't use underscores in property names.

Quoted 16 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +16 -0
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;
+ - rockchip,usb3tousb2_en : the register of type-c force usb3 to usb2 enable
+   control.
+   for type-c phy0, it must be <0xe580 3 19>;
+   for type-c phy1, it must be <0xe58c 3 19>;
+ - rockchip,external_psm : the register of type-c phy external psm clock
+   selection.
+   for type-c phy0, it must be <0xe588 14 30>;
+   for type-c phy1, it must be <0xe594 14 30>;
+ - rockchip,pipe_status : the register of type-c phy pipe status.
+   for type-c phy0, it must be <0xe5c0 0 0>;
+   for type-c phy1, it must be <0xe5c0 16 16>;
+ - rockchip,uphy_dp_sel : the register of type-c phy selection for DP
+   for type-c phy0, it must be <0x6268 19 19>;
+   for type-c phy1, it must be <0x6268 3 19>;
maintainer
#3 lore raw

Re: [v2 PATCH 1/4] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

In reply to Chris Zhong

Am Montag, 13. Juni 2016, 17:39:46 schrieb Chris Zhong:

Quoted 48 lines

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

 .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77
++++++++++++++++++++++ 1 file changed, 77 insertions(+)
 create mode 100644

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

(quoted diff) +0 -0

b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +18 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+			 "rockchip,rk3399-typec-phy1"
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical,

except +these registers(description below), every register node contains 3 sections: +offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 23

Quoted 2 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +2 -0
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;

I think I said this already, but these register-lists would be much happier being defined inside the driver - see how Frank managed this on his usb2phy please.

Heiko

#4 lore raw

Re: [v2 PATCH 1/4] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

Hi Heiko

Quoted 55 lines · Heiko Stuebner

Am Montag, 13. Juni 2016, 17:39:46 schrieb Chris Zhong:

Quoted 48 lines

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

  .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77

++++++++++++++++++++++ 1 file changed, 77 insertions(+)
create mode 100644
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

(quoted diff) +0 -0

b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +18 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+			 "rockchip,rk3399-typec-phy1"
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical,

except +these registers(description below), every register node contains 3 sections: +offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 23

Quoted 2 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +2 -0
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;

I think I said this already, but these register-lists would be much happier being defined inside the driver - see how Frank managed this on his usb2phy please.

Quoted 2 lines

Heiko

Yes, I move them into driver in v1 patch, but Rob Herring and Guenter Roeck recommend to put them back to dts.
These phy0 and phy1 are exactly the same, except these grf registers.

Quoted 1 line
#5 lore raw

Re: [v2 PATCH 1/4] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

Quoted 64 lines · Chris Zhong

Hi Heiko

Quoted 60 lines · Heiko Stuebner

Am Montag, 13. Juni 2016, 17:39:46 schrieb Chris Zhong:

Quoted 49 lines

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

  .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77

++++++++++++++++++++++ 1 file changed, 77 insertions(+)
create mode 100644
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

(quoted diff) +0 -0

b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +18 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+                        "rockchip,rk3399-typec-phy1"
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+                "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical,

except +these registers(description below), every register node contains 3 sections: +offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 23

Quoted 2 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +2 -0
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;

I think I said this already, but these register-lists would be much happier
being defined inside the driver - see how Frank managed this on his usb2phy
please.

Quoted 5 lines
Quoted 2 lines

Heiko

Yes, I move them into driver in v1 patch, but Rob Herring and Guenter Roeck recommend to put them back to dts.
These phy0 and phy1 are exactly the same, except these grf registers.

I think having the registers in dts isn't a bad idea. It might be actually even useful to bring up this PHY on new SoCs, if they happen to have the same PHY, just different plumbing.

But I suppose we don't need two separate compatible strings for phy0 and phy1 anymore as Rob pointed, just one "rockchip,rk3399-typec-phy".

After the above is fixed and underscores in property names are replaced with dashes, feel free to add my Reviewed-by.

Best regards,
Tomasz

maintainer
#6 lore raw

Re: [v2 PATCH 1/4] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

Am Donnerstag, 16. Juni 2016, 16:49:42 schrieb Tomasz Figa:

Quoted 75 lines · Chris Zhong
Quoted 67 lines

Hi Heiko

Quoted 64 lines · Heiko Stuebner

Am Montag, 13. Juni 2016, 17:39:46 schrieb Chris Zhong:

Quoted 54 lines

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

  .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77

++++++++++++++++++++++ 1 file changed, 77 insertions(+)

create mode 100644

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +18 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+                        "rockchip,rk3399-typec-phy1"
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+                "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost

identical,
except +these registers(description below), every register node contains 3 sections: +offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 23

Quoted 2 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +2 -0
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;

I think I said this already, but these register-lists would be much happier
being defined inside the driver - see how Frank managed this on his usb2phy
please.

Quoted 6 lines
Quoted 1 line

Heiko

Yes, I move them into driver in v1 patch, but Rob Herring and Guenter Roeck
recommend to put them back to dts.
These phy0 and phy1 are exactly the same, except these grf registers.

Quoted 6 lines

I think having the registers in dts isn't a bad idea. It might be actually even useful to bring up this PHY on new SoCs, if they happen to have the same PHY, just different plumbing.

But I suppose we don't need two separate compatible strings for phy0 and phy1 anymore as Rob pointed, just one "rockchip,rk3399-typec-phy".

That is true - so I guess I'm also ok with going that way.

Though with the GRF-based interfaces being as volatile as they are between soc types, I just fear that this might not hold up on future socs. For example the usb2phy is used on rk3036, rk3228, rk3366, rk3368, rk3399 and the GRF-side differs a lot - even with some features not even supported.

Quoted 2 lines

After the above is fixed and underscores in property names are replaced with dashes, feel free to add my Reviewed-by.

I guess the clock and reset-names could also use dashes instead of underscores.

#7 lore raw

PATCH v2 1/4 Documentation: bindings: add dt doc for Rockchip USB Type-C PHY

In reply to Chris Zhong

Hi Chris,

Quoted 25 lines · Chris Zhong

This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399

---

Changes in v2:
- add some registers description

Changes in v1:
- add extcon node description
- move the registers in phy driver
- remove the suffix of reset

  .../devicetree/bindings/phy/phy-rockchip-typec.txt | 77 ++++++++++++++++++++++
  1 file changed, 77 insertions(+)

create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +0 -0
new file mode 100644
index 0000000..430920c

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 6

Quoted 6 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +6 -0
@@ -0,0 +1,77 @@
+* ROCKCHIP type-c PHY
+---------------------
+
+Required properties:
+ - compatible : should be "rockchip,rk3399-typec-phy0" or
+			 "rockchip,rk3399-typec-phy1"

should be "rockchip,rk3399-typec-phy"

Quoted 25 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +25 -0
+ - reg: Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names : string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy", "tcphy_pipe", "uphy_tcphy"
+ - #phy-cells : Must be 0.  See ./phy-bindings.txt for details.
+ - extcon : extcon specifier for the Power Delivery
+
+Note, there are 2 type-c phys for RK3399, and they are almost identical, except
+these registers(description below), every register node contains 3 sections:
+offset, enable bit, write mask bit.
+ - rockchip,typec_conn_dir : the register of type-c connector direction,
+   for type-c phy0, it must be <0xe580 0 16>;
+   for type-c phy1, it must be <0xe58c 0 16>;
+ - rockchip,usb3tousb2_en : the register of type-c force usb3 to usb2 enable
+   control.
+   for type-c phy0, it must be <0xe580 3 19>;
+   for type-c phy1, it must be <0xe58c 3 19>;
+ - rockchip,external_psm : the register of type-c phy external psm clock
+   selection.
+   for type-c phy0, it must be <0xe588 14 30>;
+   for type-c phy1, it must be <0xe594 14 30>;

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 41

Quoted 10 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +10 -0
+ - rockchip,pipe_status : the register of type-c phy pipe status.
+   for type-c phy0, it must be <0xe5c0 0 0>;
+   for type-c phy1, it must be <0xe5c0 16 16>;
+ - rockchip,uphy_dp_sel : the register of type-c phy selection for DP
+   for type-c phy0, it must be <0x6268 19 19>;
+   for type-c phy1, it must be <0x6268 3 19>;
+
+Example:
+	tcphy0: phy at ff7c0000 {
+		compatible = "rockchip,rk3399-typec-phy0";

should be "rockchip,rk3399-typec-phy"

Quoted 10 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +10 -0
+		reg = <0x0 0xff7c0000 0x0 0x40000>;
+		#phy-cells = <0>;
+		extcon = <&fusb1>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY0>,
+			 <&cru SRST_UPHY0_PIPE_L00>,
+			 <&cru SRST_P_UPHY0_TCPHY>;

Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt line 61

Quoted 10 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +10 -0
+		reset-names = "tcphy", "tcphy_pipe", "uphy_tcphy";
+		rockchip,typec_conn_dir = <0xe580 0 16>;
+		rockchip,usb3tousb2_en = <0xe580 3 19>;
+		rockchip,external_psm = <0xe588 14 30>;
+		rockchip,pipe_status = <0xe5c0 0 0>;
+		rockchip,uphy_dp_sel = <0x6268 19 19>;
+	};
+
+	tcphy1: phy at ff800000 {
+		compatible = "rockchip,rk3399-typec-phy1";

should be "rockchip,rk3399-typec-phy"

Feel free to ad my Reviewed-by after these update.

Thanks,
- Kever

Quoted 16 lines
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file +16 -0
+		reg = <0x0 0xff800000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+			 <&cru SCLK_UPHY1_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY1>,
+		         <&cru SRST_UPHY1_PIPE_L00>,
+			 <&cru SRST_P_UPHY1_TCPHY>;
+		reset-names = "tcphy", "tcphy_pipe", "uphy_tcphy";
+		rockchip,typec_conn_dir = <0xe58c 0 16>;
+		rockchip,usb3tousb2_en = <0xe58c 3 19>;
+		rockchip,external_psm = <0xe594 14 30>;
+		rockchip,pipe_status = <0xe5c0 16 16>;
+		rockchip,uphy_dp_sel = <0x6268 3 19>;
+	};
#8 lore raw

PATCH v2 2/4 phy: Add USB Type-C PHY driver for rk3399

In reply to Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

---

Changes in v2:
- select RESET_CONTROLLER
- alphabetic order
- modify some spelling mistakes
- make mode cleaner
- use bool for enable/disable
- check all of the return value
- return a better err number
- use more readx_poll_timeout()
- clk_disable_unprepare(tcphy->clk_ref);
- remove unuse functions, rockchip_typec_phy_power_on/off
- remove unnecessary typecast from void *
- use dts node to distinguish between phys.

Changes in v1:
- update the licence note
- init core clock to 50MHz
- use extcon API
- remove unused global
- add some comments for magic num
- change usleep_range(1000, 2000) tousleep_range(1000, 1050)
- remove __func__ from dev_err
- return err number when get clk failed
- remove ADDR_ADJ define
- use devm_clk_get(&pdev->dev, "tcpdcore")

 drivers/phy/Kconfig                    |   8 +
 drivers/phy/Makefile                   |   1 +
 drivers/phy/phy-rockchip-typec.c       | 952 +++++++++++++++++++++++++++++++++
 include/linux/phy/phy-rockchip-typec.h |  20 +
 4 files changed, 981 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/linux/phy/phy-rockchip-typec.h
drivers/phy/Kconfig +8 -0
index 26566db..ec87b3a 100644
@@ -351,6 +351,14 @@ config PHY_ROCKCHIP_DP
 	help
 	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	select RESET_CONTROLLER
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
 config PHY_ST_SPEAR1310_MIPHY
 	tristate "ST SPEAR1310-MIPHY driver"
 	select GENERIC_PHY
drivers/phy/Makefile +1 -0
index 24596a9..91fa413 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
drivers/phy/phy-rockchip-typec.c new file +952 -0

952 lines not on this page · raw message

include/linux/phy/phy-rockchip-typec.h new file +20 -0
new file mode 100644
index 0000000..acdd8cb
@@ -0,0 +1,20 @@
+#ifndef PHY_ROCKCHIP_TYPEC_H_
+#define PHY_ROCKCHIP_TYPEC_H_
+
+#define PIN_MAP_A	BIT(0)
+#define PIN_MAP_B	BIT(1)
+#define PIN_MAP_C	BIT(2)
+#define PIN_MAP_D	BIT(3)
+#define PIN_MAP_E	BIT(4)
+#define PIN_MAP_F	BIT(5)
+
+#define SET_PIN_MAP(x)	(((x) & 0xff) << 24)
+#define SET_FLIP(x)	(((x) & 0xff) << 16)
+#define SET_DFP(x)	(((x) & 0xff) << 8)
+#define SET_PLUGGED(x)	((x) & 0xff)
+#define GET_PIN_MAP(x)	(((x) >> 24) & 0xff)
+#define GET_FLIP(x)	(((x) >> 16) & 0xff)
+#define GET_DFP(x)	(((x) >> 8) & 0xff)
+#define GET_PLUGGED(x)	((x) & 0xff)
+
+#endif
Signature · 1 line
2.6.3
Reviewed-by on v2 2/4
#9 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

Hi Chris,

Quoted 1,050 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

---

Changes in v2:
- select RESET_CONTROLLER
- alphabetic order
- modify some spelling mistakes
- make mode cleaner
- use bool for enable/disable
- check all of the return value
- return a better err number
- use more readx_poll_timeout()
- clk_disable_unprepare(tcphy->clk_ref);
- remove unuse functions, rockchip_typec_phy_power_on/off
- remove unnecessary typecast from void *
- use dts node to distinguish between phys.

Changes in v1:
- update the licence note
- init core clock to 50MHz
- use extcon API
- remove unused global
- add some comments for magic num
- change usleep_range(1000, 2000) tousleep_range(1000, 1050)
- remove __func__ from dev_err
- return err number when get clk failed
- remove ADDR_ADJ define
- use devm_clk_get(&pdev->dev, "tcpdcore")

  drivers/phy/Kconfig                    |   8 +
  drivers/phy/Makefile                   |   1 +
  drivers/phy/phy-rockchip-typec.c       | 952 +++++++++++++++++++++++++++++++++
  include/linux/phy/phy-rockchip-typec.h |  20 +
  4 files changed, 981 insertions(+)

create mode 100644 drivers/phy/phy-rockchip-typec.c create mode 100644 include/linux/phy/phy-rockchip-typec.h

drivers/phy/Kconfig +8 -0
index 26566db..ec87b3a 100644
@@ -351,6 +351,14 @@ config PHY_ROCKCHIP_DP
  	help
  	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	select RESET_CONTROLLER
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
  config PHY_ST_SPEAR1310_MIPHY
  	tristate "ST SPEAR1310-MIPHY driver"
  	select GENERIC_PHY
drivers/phy/Makefile +1 -0
index 24596a9..91fa413 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
  obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
  obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
  obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
  obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
  obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
  obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
drivers/phy/phy-rockchip-typec.c new file +952 -0
new file mode 100644
index 0000000..230e074
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Chris Zhong <[email protected]>
+ *         Kever Yang <[email protected]>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/extcon.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-rockchip-typec.h>
+
+#define CMN_SSM_BANDGAP			(0x21 << 2)
+#define CMN_SSM_BIAS			(0x22 << 2)
+#define CMN_PLLSM0_PLLEN		(0x29 << 2)
+#define CMN_PLLSM0_PLLPRE		(0x2a << 2)
+#define CMN_PLLSM0_PLLVREF		(0x2b << 2)
+#define CMN_PLLSM0_PLLLOCK		(0x2c << 2)
+#define CMN_PLLSM1_PLLEN		(0x31 << 2)
+#define CMN_PLLSM1_PLLPRE		(0x32 << 2)
+#define CMN_PLLSM1_PLLVREF		(0x33 << 2)
+#define CMN_PLLSM1_PLLLOCK		(0x34 << 2)
+#define CMN_PLLSM1_USER_DEF_CTRL	(0x37 << 2)
+#define CMN_ICAL_OVRD			(0xc1 << 2)
+#define CMN_PLL0_VCOCAL_OVRD		(0x83 << 2)
+#define CMN_PLL0_VCOCAL_INIT		(0x84 << 2)
+#define CMN_PLL0_VCOCAL_ITER		(0x85 << 2)
+#define CMN_PLL0_LOCK_REFCNT_START	(0x90 << 2)
+#define CMN_PLL0_LOCK_PLLCNT_START	(0x92 << 2)
+#define CMN_PLL0_LOCK_PLLCNT_THR	(0x93 << 2)
+#define CMN_PLL0_INTDIV			(0x94 << 2)
+#define CMN_PLL0_FRACDIV		(0x95 << 2)
+#define CMN_PLL0_HIGH_THR		(0x96 << 2)
+#define CMN_PLL0_DSM_DIAG		(0x97 << 2)
+#define CMN_PLL0_SS_CTRL1		(0x98 << 2)
+#define CMN_PLL0_SS_CTRL2		(0x99 << 2)
+#define CMN_PLL1_VCOCAL_START		(0xa1 << 2)
+#define CMN_PLL1_VCOCAL_OVRD		(0xa3 << 2)
+#define CMN_PLL1_VCOCAL_INIT		(0xa4 << 2)
+#define CMN_PLL1_VCOCAL_ITER		(0xa5 << 2)
+#define CMN_PLL1_LOCK_REFCNT_START	(0xb0 << 2)
+#define CMN_PLL1_LOCK_PLLCNT_START	(0xb2 << 2)
+#define CMN_PLL1_LOCK_PLLCNT_THR	(0xb3 << 2)
+#define CMN_PLL1_INTDIV			(0xb4 << 2)
+#define CMN_PLL1_FRACDIV		(0xb5 << 2)
+#define CMN_PLL1_HIGH_THR		(0xb6 << 2)
+#define CMN_PLL1_DSM_DIAG		(0xb7 << 2)
+#define CMN_PLL1_SS_CTRL1		(0xb8 << 2)
+#define CMN_PLL1_SS_CTRL2		(0xb9 << 2)
+#define CMN_RXCAL_OVRD			(0xd1 << 2)
+#define CMN_TXPUCAL_CTRL		(0xe0 << 2)
+#define CMN_TXPUCAL_OVRD		(0xe1 << 2)
+#define CMN_TXPDCAL_OVRD		(0xf1 << 2)
+#define CMN_DIAG_PLL0_FBH_OVRD		(0x1c0 << 2)
+#define CMN_DIAG_PLL0_FBL_OVRD		(0x1c1 << 2)
+#define CMN_DIAG_PLL0_OVRD		(0x1c2 << 2)
+#define CMN_DIAG_PLL0_V2I_TUNE		(0x1c5 << 2)
+#define CMN_DIAG_PLL0_CP_TUNE		(0x1c6 << 2)
+#define CMN_DIAG_PLL0_LF_PROG		(0x1c7 << 2)
+#define CMN_DIAG_PLL1_FBH_OVRD		(0x1d0 << 2)
+#define CMN_DIAG_PLL1_FBL_OVRD		(0x1d1 << 2)
+#define CMN_DIAG_PLL1_OVRD		(0x1d2 << 2)
+#define CMN_DIAG_PLL1_V2I_TUNE		(0x1d5 << 2)
+#define CMN_DIAG_PLL1_CP_TUNE		(0x1d6 << 2)
+#define CMN_DIAG_PLL1_LF_PROG		(0x1d7 << 2)
+#define CMN_DIAG_PLL1_PTATIS_TUNE1	(0x1d8 << 2)
+#define CMN_DIAG_PLL1_PTATIS_TUNE2	(0x1d9 << 2)
+#define CMN_DIAG_PLL1_INCLK_CTRL	(0x1da << 2)
+#define CMN_DIAG_HSCLK_SEL		(0x1e0 << 2)
+
+#define XCVR_PSM_RCTRL(n)		((0x4001 | (n << 9)) << 2)
+#define XCVR_PSM_CAL_TMR(n)		((0x4002 | (n << 9)) << 2)
+#define XCVR_PSM_A0IN_TMR(n)		((0x4003 | (n << 9)) << 2)
+#define TX_TXCC_CAL_SCLR_MULT(n)	((0x4047 | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_00(n)	((0x404c | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_01(n)	((0x404d | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_10(n)	((0x404e | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_11(n)	((0x404f | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_000(n)	((0x4050 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_001(n)	((0x4051 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_010(n)	((0x4052 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_011(n)	((0x4053 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_100(n)	((0x4054 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_101(n)	((0x4055 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_110(n)	((0x4056 | (n << 9)) << 2)
+#define TX_TXCC_MGNFS_MULT_111(n)	((0x4057 | (n << 9)) << 2)
+#define XCVR_DIAG_PLLDRC_CTRL(n)	((0x40e0 | (n << 9)) << 2)
+#define XCVR_DIAG_BIDI_CTRL(n)		((0x40e8 | (n << 9)) << 2)
+#define XCVR_DIAG_LANE_FCM_EN_MGN(n)	((0x40f2 | (n << 9)) << 2)
+#define TX_PSC_A0(n)			((0x4100 | (n << 9)) << 2)
+#define TX_PSC_A1(n)			((0x4101 | (n << 9)) << 2)
+#define TX_PSC_A2(n)			((0x4102 | (n << 9)) << 2)
+#define TX_PSC_A3(n)			((0x4103 | (n << 9)) << 2)
+#define TX_RCVDET_CTRL(n)		((0x4120 | (n << 9)) << 2)
+#define TX_RCVDET_EN_TMR(n)		((0x4122 | (n << 9)) << 2)
+#define TX_RCVDET_ST_TMR(n)		((0x4123 | (n << 9)) << 2)
+#define TX_DIAG_TX_DRV(n)		((0x41e1 | (n << 9)) << 2)
+#define TX_DIAG_BGREF_PREDRV_DELAY	(0x41e7 << 2)
+#define TX_ANA_CTRL_REG_1		(0x5020 << 2)
+#define TX_ANA_CTRL_REG_2		(0x5021 << 2)
+#define TXDA_COEFF_CALC_CTRL		(0x5022 << 2)
+#define TX_DIG_CTRL_REG_2		(0x5024 << 2)
+#define TXDA_CYA_AUXDA_CYA		(0x5025 << 2)
+#define TX_ANA_CTRL_REG_3		(0x5026 << 2)
+#define TX_ANA_CTRL_REG_4		(0x5027 << 2)
+#define TX_ANA_CTRL_REG_5		(0x5029 << 2)
+
+#define RX_PSC_A0(n)			((0x8000 | (n << 9)) << 2)
+#define RX_PSC_A1(n)			((0x8001 | (n << 9)) << 2)
+#define RX_PSC_A2(n)			((0x8002 | (n << 9)) << 2)
+#define RX_PSC_A3(n)			((0x8003 | (n << 9)) << 2)
+#define RX_PSC_CAL(n)			((0x8006 | (n << 9)) << 2)
+#define RX_PSC_RDY(n)			((0x8007 | (n << 9)) << 2)
+#define RX_IQPI_ILL_CAL_OVRD		(0x8023 << 2)
+#define RX_EPI_ILL_CAL_OVRD		(0x8033 << 2)
+#define RX_SDCAL0_OVRD			(0x8041 << 2)
+#define RX_SDCAL1_OVRD			(0x8049 << 2)
+#define RX_SLC_INIT			(0x806d << 2)
+#define RX_SLC_RUN			(0x806e << 2)
+#define RX_CDRLF_CNFG2			(0x8081 << 2)
+#define RX_SIGDET_HL_FILT_TMR(n)	((0x8090 | (n << 9)) << 2)
+#define RX_SLC_IOP0_OVRD		(0x8101 << 2)
+#define RX_SLC_IOP1_OVRD		(0x8105 << 2)
+#define RX_SLC_QOP0_OVRD		(0x8109 << 2)
+#define RX_SLC_QOP1_OVRD		(0x810d << 2)
+#define RX_SLC_EOP0_OVRD		(0x8111 << 2)
+#define RX_SLC_EOP1_OVRD		(0x8115 << 2)
+#define RX_SLC_ION0_OVRD		(0x8119 << 2)
+#define RX_SLC_ION1_OVRD		(0x811d << 2)
+#define RX_SLC_QON0_OVRD		(0x8121 << 2)
+#define RX_SLC_QON1_OVRD		(0x8125 << 2)
+#define RX_SLC_EON0_OVRD		(0x8129 << 2)
+#define RX_SLC_EON1_OVRD		(0x812d << 2)
+#define RX_SLC_IEP0_OVRD		(0x8131 << 2)
+#define RX_SLC_IEP1_OVRD		(0x8135 << 2)
+#define RX_SLC_QEP0_OVRD		(0x8139 << 2)
+#define RX_SLC_QEP1_OVRD		(0x813d << 2)
+#define RX_SLC_EEP0_OVRD		(0x8141 << 2)
+#define RX_SLC_EEP1_OVRD		(0x8145 << 2)
+#define RX_SLC_IEN0_OVRD		(0x8149 << 2)
+#define RX_SLC_IEN1_OVRD		(0x814d << 2)
+#define RX_SLC_QEN0_OVRD		(0x8151 << 2)
+#define RX_SLC_QEN1_OVRD		(0x8155 << 2)
+#define RX_SLC_EEN0_OVRD		(0x8159 << 2)
+#define RX_SLC_EEN1_OVRD		(0x815d << 2)
+#define RX_DIAG_SIGDET_TUNE(n)		((0x81dc | (n << 9)) << 2)
+#define RX_DIAG_SC2C_DELAY		(0x81e1 << 2)
+
+#define PMA_LANE_CFG			(0xc000 << 2)
+#define PIPE_CMN_CTRL1			(0xc001 << 2)
+#define PIPE_CMN_CTRL2			(0xc002 << 2)
+#define PIPE_COM_LOCK_CFG1		(0xc003 << 2)
+#define PIPE_COM_LOCK_CFG2		(0xc004 << 2)
+#define PIPE_RCV_DET_INH		(0xc005 << 2)
+#define DP_MODE_CTL			(0xc008 << 2)
+#define DP_CLK_CTL			(0xc009 << 2)
+#define STS				(0xc00F << 2)
+#define PHY_ISO_CMN_CTRL		(0xc010 << 2)
+#define PHY_DP_TX_CTL			(0xc408 << 2)
+#define PMA_CMN_CTRL1			(0xc800 << 2)
+#define PHY_PMA_ISO_CMN_CTRL		(0xc810 << 2)
+#define PHY_ISOLATION_CTRL		(0xc81f << 2)
+#define PHY_PMA_ISO_XCVR_CTRL(n)	((0xcc11 | (n << 6)) << 2)
+#define PHY_PMA_ISO_LINK_MODE(n)	((0xcc12 | (n << 6)) << 2)
+#define PHY_PMA_ISO_PWRST_CTRL(n)	((0xcc13 | (n << 6)) << 2)
+#define PHY_PMA_ISO_TX_DATA_LO(n)	((0xcc14 | (n << 6)) << 2)
+#define PHY_PMA_ISO_TX_DATA_HI(n)	((0xcc15 | (n << 6)) << 2)
+#define PHY_PMA_ISO_RX_DATA_LO(n)	((0xcc16 | (n << 6)) << 2)
+#define PHY_PMA_ISO_RX_DATA_HI(n)	((0xcc17 | (n << 6)) << 2)
+#define TX_BIST_CTRL(n)			((0x4140 | (n << 9)) << 2)
+#define TX_BIST_UDDWR(n)		((0x4141 | (n << 9)) << 2)
+
+#define CMN_READY			BIT(0)
+
+#define DP_PLL_CLOCK_ENABLE		BIT(2)
+#define DP_PLL_ENABLE			BIT(0)
+#define DP_PLL_DATA_RATE_RBR		((2 << 12) | (4 << 8))
+#define DP_PLL_DATA_RATE_HBR		((2 << 12) | (4 << 8))
+#define DP_PLL_DATA_RATE_HBR2		((1 << 12) | (2 << 8))
+
+#define GRF_SOC_CON26			0x6268
+#define UPHY_DP_SEL			BIT(3)
+#define UPHY_DP_SEL_MASK		BIT(19)
+#define DPTX_HPD_SEL			(3 << 12)
+#define DPTX_HPD_DEL			(2 << 12)
+#define DPTX_HPD_SEL_MASK		(3 << 28)
+
+#define PHY_MODE_SET_TIMEOUT		1000000
+
+#define	MODE_DISCONNECT			0
+#define	MODE_UFP_USB			BIT(0)
+#define	MODE_DFP_USB			BIT(1)
+#define	MODE_DFP_DP			BIT(2)
+
+struct usb3phy_reg {
+	u32	offset;
+	u32	enable_bit;
+	u32	write_enable;
+};
+
+struct rockchip_usb3phy_port_cfg {
+	struct usb3phy_reg	typec_conn_dir;
+	struct usb3phy_reg	usb3tousb2_en;
+	struct usb3phy_reg	external_psm;
+	struct usb3phy_reg	pipe_status;
+	struct usb3phy_reg	uphy_dp_sel;
+};
+
+struct rockchip_typec_phy {
+	struct device		*dev;
+	void __iomem		*base;
+	struct extcon_dev	*extcon;
+	struct phy		*phy;
+	struct regmap		*grf_regs;
+	struct clk		*clk_core;
+	struct clk		*clk_ref;
+	struct reset_control	*phy_rst;
+	struct reset_control	*pipe_rst;
+	struct reset_control	*uphy_rst;
+	struct rockchip_usb3phy_port_cfg	port_cfgs;
+
+	/* to receive notifier from PD */
+	struct notifier_block	event_nb;
+	struct delayed_work	event_wq;
+
+	bool flip;
+	bool hpd_status;
+	int mode;
+	int map;
+};
+
+struct phy_reg {
+	int value;
+	int addr;
+};
+
+struct phy_reg usb_pll_cfg[] = {
+	{0xf0,		CMN_PLL0_VCOCAL_INIT},
+	{0x18,		CMN_PLL0_VCOCAL_ITER},
+	{0xd0,		CMN_PLL0_INTDIV},
+	{0x4a4a,	CMN_PLL0_FRACDIV},
+	{0x34,		CMN_PLL0_HIGH_THR},
+	{0x1ee,		CMN_PLL0_SS_CTRL1},
+	{0x7f03,	CMN_PLL0_SS_CTRL2},
+	{0x20,		CMN_PLL0_DSM_DIAG},
+	{0,		CMN_DIAG_PLL0_OVRD},
+	{0,		CMN_DIAG_PLL0_FBH_OVRD},
+	{0,		CMN_DIAG_PLL0_FBL_OVRD},
+	{0x7,		CMN_DIAG_PLL0_V2I_TUNE},
+	{0x45,		CMN_DIAG_PLL0_CP_TUNE},
+	{0x8,		CMN_DIAG_PLL0_LF_PROG},
+};
+
+struct phy_reg dp_pll_cfg[] = {
+	{0xf0,		CMN_PLL1_VCOCAL_INIT},
+	{0x18,		CMN_PLL1_VCOCAL_ITER},
+	{0x30b9,	CMN_PLL1_VCOCAL_START},
+	{0x21c,		CMN_PLL1_INTDIV},
+	{0,		CMN_PLL1_FRACDIV},
+	{0x5,		CMN_PLL1_HIGH_THR},
+	{0x35,		CMN_PLL1_SS_CTRL1},
+	{0x7f1e,	CMN_PLL1_SS_CTRL2},
+	{0x20,		CMN_PLL1_DSM_DIAG},
+	{0,		CMN_PLLSM1_USER_DEF_CTRL},
+	{0,		CMN_DIAG_PLL1_OVRD},
+	{0,		CMN_DIAG_PLL1_FBH_OVRD},
+	{0,		CMN_DIAG_PLL1_FBL_OVRD},
+	{0x6,		CMN_DIAG_PLL1_V2I_TUNE},
+	{0x45,		CMN_DIAG_PLL1_CP_TUNE},
+	{0x8,		CMN_DIAG_PLL1_LF_PROG},
+	{0x100,		CMN_DIAG_PLL1_PTATIS_TUNE1},
+	{0x7,		CMN_DIAG_PLL1_PTATIS_TUNE2},
+	{0x4,		CMN_DIAG_PLL1_INCLK_CTRL},
+};
+
+static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
+			  u32 num_lanes)
+{
+	u32 i;
+
+	/*
+	 * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent
+	 * cmn_psm_clk_dig_div = 2, set the clk division to 2
+	 */
+	writel(0x830, tcphy->base + PMA_CMN_CTRL1);
+	for (i = 0; i < num_lanes; i++) {
+		/*
+		 * The following PHY configuration assumes a 24 MHz reference
+		 * clock.
+		 */
+		writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
+		writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
+		writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));
+	}
+}
+
+static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
+{
+	u32 rdata;
+	u32 i;
+
+	/*
+	 * Selects which PLL clock will be driven on the analog high speed
+	 * clock 0: PLL 0 div 1.
+	 */
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
+
+	/* load the configuration of PLL0 */
+	for (i = 0; i < ARRAY_SIZE(usb_pll_cfg); i++)
+		writel(usb_pll_cfg[i].value, tcphy->base + usb_pll_cfg[i].addr);
+}
+
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+{
+	u32 rdata;
+	u32 i;
+
+	/* set the default mode to RBR */
+	writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR,
+	       tcphy->base + DP_CLK_CTL);
+
+	/*
+	 * Selects which PLL clock will be driven on the analog high speed
+	 * clock 1: PLL 1 div 2.
+	 */
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	rdata = (rdata & 0xffcf) | 0x30;
+	writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
+
+	/* load the configuration of PLL1 */
+	for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++)
+		writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr);
+}
+
+static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  u32 lane)
+{
+	writel(0x7799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x7798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A2(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A3(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  u32 lane)
+{
+	writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
+	writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
+	writel(0xa410, tcphy->base + RX_PSC_A2(lane));
+	writel(0x2410, tcphy->base + RX_PSC_A3(lane));
+	writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
+	writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
+	writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
+	writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
+	writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
+			      u32 lane)
+{
+	u32 rdata;
+
+	writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
+	writel(0x6799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x6798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x98, tcphy->base + TX_PSC_A2(lane));
+	writel(0x98, tcphy->base + TX_PSC_A3(lane));
+
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
+
+	writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
+	writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
+
+	rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+	rdata = (rdata & 0x8fff) | 0x6000;
+	writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+}
+
+static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
+{
+	switch (tcphy->map) {
+	case PIN_MAP_A:
+		writel(0x19d5, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_B:
+		writel(0x1500, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_C:
+	case PIN_MAP_E:
+		writel(0x51d9, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_D:
+	case PIN_MAP_F:
+		writel(0x5100, tcphy->base + PMA_LANE_CFG);
+		break;
+	};
+}
+
+static inline int property_enable(struct rockchip_typec_phy *tcphy,
+				  const struct usb3phy_reg *reg, bool en)
+{
+	int mask = 1 << reg->write_enable;
+	int val = en << reg->enable_bit;
+
+	return regmap_write(tcphy->grf_regs, reg->offset, val | mask);
+}
+
+static void tcphy_lanes_config(struct rockchip_typec_phy *tcphy)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	u32 i;
+
+	property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip);
+
+	tcphy_cfg_24m(tcphy, 0x4);
+
+	switch (tcphy->mode) {
+	case MODE_UFP_USB:
+	case MODE_DFP_USB:
+		tcphy_cfg_usb_pll(tcphy);
+		if (tcphy->flip) {
+			tcphy_tx_usb_cfg_lane(tcphy, 3);
+			tcphy_rx_usb_cfg_lane(tcphy, 2);
+		} else {
+			tcphy_tx_usb_cfg_lane(tcphy, 0);
+			tcphy_rx_usb_cfg_lane(tcphy, 1);
+		}
+		break;
+	case MODE_DFP_DP:
+		tcphy_cfg_dp_pll(tcphy);
+		for (i = 0; i < 4; i++)
+			tcphy_dp_cfg_lane(tcphy, i);
+		break;
+	case MODE_DFP_USB | MODE_DFP_DP:
+		tcphy_cfg_usb_pll(tcphy);
+		tcphy_cfg_dp_pll(tcphy);
+		if (tcphy->flip) {
+			tcphy_tx_usb_cfg_lane(tcphy, 3);
+			tcphy_rx_usb_cfg_lane(tcphy, 2);
+			tcphy_dp_cfg_lane(tcphy, 0);
+			tcphy_dp_cfg_lane(tcphy, 1);
+		} else {
+			tcphy_tx_usb_cfg_lane(tcphy, 0);
+			tcphy_rx_usb_cfg_lane(tcphy, 1);
+			tcphy_dp_cfg_lane(tcphy, 2);
+			tcphy_dp_cfg_lane(tcphy, 3);
+		}
+		break;
+	}
+}
+
+static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
+{
+	int rdata, rdata2, val;
+
+	/* disable txda_cal_latch_en for rewrite the calibration values */
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	val = rdata & 0xdfff;
+	writel(val, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	/*
+	 * read a resistor calibration code from CMN_TXPUCAL_CTRL[6:0] and
+	 * write it to TX_DIG_CTRL_REG_2[6:0], and delay 1ms to make sure it
+	 * works.
+	 */
+	rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	rdata = rdata & 0xffc0;
+
+	rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
+	rdata2 = rdata2 & 0x3f;
+
+	val = rdata | rdata2;
+	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
+	usleep_range(1000, 1050);
+
+	/*
+	 * Enable signal for latch that sample and holds calibration values.
+	 * Activate this signal for 1 clock cycle to sample new calibration
+	 * values.
+	 */
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	val = rdata | 0x2000;
+	writel(val, tcphy->base + TX_ANA_CTRL_REG_1);
+	usleep_range(150, 200);
+
+	/* set TX Voltage Level and TX Deemphasis to 0 */
+	writel(0, tcphy->base + PHY_DP_TX_CTL);
+	/* re-enable decap */
+	writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+
+	/*
+	 * Programs txda_drv_ldo_prog[15:0], Sets driver LDO
+	 * voltage 16'h1001 for DP-AUX-TX and RX
+	 */
+	writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
+
+	/* re-enables Bandgap reference for LDO */
+	writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	/*
+	 * re-enables the transmitter pre-driver, driver data selection MUX,
+	 * and receiver detect circuits.
+	 */
+	writel(0x301, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
+
+	/*
+	 * Controls auxda_polarity, which selects the polarity of the xcvr
+	 * 1'b1 : Reverses the polarity (If TYPEC, Pulls ups aux_p and pull
+	 * down aux_m)
+	 * 1'b0 : Normal polarity (if TYPE_C, pulls up aux_m and pulls down
+	 * aux_p)
+	 */
+	if (tcphy->flip)
+		writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
+	else
+		writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+
+	/*
+	 * Controls low_power_swing_en, set the voltage swing of the driver
+	 * to 400mv. The values	below are peak to peak (differential) values.
+	 */
+	writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
+	writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
+
+	/* Controls tx_high_z_tm_en */
+	val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	val |= BIT(15);
+	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
+}
+
+static void tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	const struct usb3phy_reg *reg = &cfg->pipe_status;
+	int timeout;
+	unsigned int val;
+
+	/* wait TCPHY for pipe ready */
+	for (timeout = 0; timeout < 1000; timeout++) {
+		regmap_read(tcphy->grf_regs, reg->offset, &val);
+		if (!(val & BIT(reg->enable_bit)))
+			return;
+		usleep_range(10, 20);
+	}
+
+	dev_err(tcphy->dev, "wait pipe ready timeout!\n");
+}
+
+static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	int ret, val;
+
+	property_enable(tcphy, &cfg->uphy_dp_sel, 1);
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
+		return ret;
+	}
+
+	tcphy_dp_aux_calibration(tcphy);
+
+	if (tcphy->mode & MODE_DFP_USB)
+		writel(0xc101, tcphy->base + DP_MODE_CTL);
+	else
+		writel(0x0101, tcphy->base + DP_MODE_CTL);
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	int ret, val;
+
+	ret = clk_prepare_enable(tcphy->clk_core);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
+		return ret;
+	}
+
+	ret = clk_set_rate(tcphy->clk_core, 50000000);
+	if (ret) {
+		dev_err(tcphy->dev, "set type-c phy core clk rate failed\n");
+		goto clk_ref_failed;
+	}
+
+	ret = clk_prepare_enable(tcphy->clk_ref);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
+		goto clk_ref_failed;
+	}
+
+	reset_control_assert(tcphy->uphy_rst);
+	reset_control_assert(tcphy->phy_rst);
+	reset_control_assert(tcphy->pipe_rst);
+
+	/* select external psm clock */
+	property_enable(tcphy, &cfg->external_psm, 1);
+	property_enable(tcphy, &cfg->usb3tousb2_en, 0);
+
+	reset_control_deassert(tcphy->uphy_rst);
+
+	tcphy_lanes_config(tcphy);
+
+	tcphy_cfg_pin_assign(tcphy);
+
+	if (tcphy->mode & MODE_DFP_DP) {
+		if (tcphy->mode & MODE_DFP_USB)
+			writel(0xc104, tcphy->base + DP_MODE_CTL);
+		else
+			writel(0x0104, tcphy->base + DP_MODE_CTL);
+	}
+
+	reset_control_deassert(tcphy->phy_rst);
+
+	ret = readx_poll_timeout(readl, tcphy->base + PMA_CMN_CTRL1,
+				 val, val & CMN_READY, 10,
+				 PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "wait pma ready timeout\n");
+		goto timeout_failed;
+	}
+
+	reset_control_deassert(tcphy->pipe_rst);
+
+	return 0;
+
+timeout_failed:
+	clk_disable_unprepare(tcphy->clk_ref);
+clk_ref_failed:
+	clk_disable_unprepare(tcphy->clk_core);
+	return ret;
+}
+
+static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
+{
+	clk_disable_unprepare(tcphy->clk_core);
+	clk_disable_unprepare(tcphy->clk_ref);
+}
+
+static const struct phy_ops rockchip_tcphy_ops = {
+	.owner          = THIS_MODULE,
+};
+
+static int tcphy_pd_event(struct notifier_block *nb,
+			  unsigned long event, void *priv)
+{
+	struct rockchip_typec_phy *tcphy;
+	struct extcon_dev *edev = priv;
+	int value = edev->state;
+	int mode;
+	u8 is_plugged, dfp;
+
+	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+
+	is_plugged = GET_PLUGGED(value);
+	tcphy->flip = GET_FLIP(value);
+	dfp = GET_DFP(value);
+	tcphy->map = GET_PIN_MAP(value);
+
+	if (is_plugged) {
+		if (!dfp)
+			mode = MODE_UFP_USB;
+		else if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+			mode = MODE_DFP_USB | MODE_DFP_DP;
+		else if (tcphy->map & (PIN_MAP_A | PIN_MAP_C | PIN_MAP_E))
+			mode = MODE_DFP_DP;
+		else
+			mode = MODE_DFP_USB;
+	} else {
+		mode = MODE_DISCONNECT;
+	}
+
+	if (tcphy->mode != mode) {
+		tcphy->mode = mode;
+		schedule_delayed_work_on(0, &tcphy->event_wq, 0);
+	}
+
+	return 0;
+}
+
+static void tcphy_event_wq(struct work_struct *work)
+{
+	struct rockchip_typec_phy *tcphy;
+	int ret;
+
+	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
+
+	if (tcphy->mode == MODE_DISCONNECT) {
+		tcphy_phy_deinit(tcphy);
+		/* remove hpd sign for DP */
+		if (tcphy->hpd_status) {
+			regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+				     DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
+			tcphy->hpd_status = 0;
+		}
+	} else {
+		ret = tcphy_phy_init(tcphy);
+		if (ret)
+			return;
+
+		if (tcphy->mode & (MODE_UFP_USB | MODE_DFP_USB))
+			tcphy_usb3_init(tcphy);
+
+		if (tcphy->mode & MODE_DFP_DP) {
+			ret = tcphy_dp_init(tcphy);
+
+			/* set hpd sign for DP, if DP phy is ready */
+			if (!ret) {
+				regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+					     DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
+				tcphy->hpd_status = 1;
+			}
+		}
+	}
+}
+
+static int tcphy_get_param(struct device *dev,
+			   struct usb3phy_reg *reg,
+			   const char *name)
+{
+	int ret, buffer[3];
+
+	ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
+	if (ret) {
+		dev_err(dev, "Can not parse %s\n", name);
+		return ret;
+	}
+
+	reg->offset = buffer[0];
+	reg->enable_bit = buffer[1];
+	reg->write_enable = buffer[2];
+	return 0;
+}
+
+static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
+			  struct device *dev)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	int ret;
+
+	ret = tcphy_get_param(dev, &cfg->typec_conn_dir,
+			      "rockchip,typec_conn_dir");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->usb3tousb2_en,
+			      "rockchip,usb3tousb2_en");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->external_psm,
+			      "rockchip,external_psm");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->pipe_status,
+			      "rockchip,pipe_status");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->uphy_dp_sel,
+			      "rockchip,uphy_dp_sel");
+	if (ret)
+		return ret;
+
+	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+							  "rockchip,grf");
+	if (IS_ERR(tcphy->grf_regs)) {
+		dev_err(dev, "could not find grf dt node\n");
+		return PTR_ERR(tcphy->grf_regs);
+	}
+
+	tcphy->clk_core = devm_clk_get(dev, "tcpdcore");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "could not get uphy core clock\n");
+		return PTR_ERR(tcphy->clk_core);
+	}
+
+	tcphy->clk_ref = devm_clk_get(dev, "tcpdphy_ref");
+	if (IS_ERR(tcphy->clk_ref)) {
+		dev_err(dev, "could not get uphy ref clock\n");
+		return PTR_ERR(tcphy->clk_ref);
+	}
+
+	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy");
+	if (IS_ERR(tcphy->phy_rst)) {
+		dev_err(dev, "no phy_rst reset control found\n");
+		return PTR_ERR(tcphy->phy_rst);
+	}
+
+	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe");
+	if (IS_ERR(tcphy->pipe_rst)) {
+		dev_err(dev, "no pipe_rst reset control found\n");
+		return PTR_ERR(tcphy->pipe_rst);
+	}
+
+	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy");
+	if (IS_ERR(tcphy->uphy_rst)) {
+		dev_err(dev, "no uphy_rst reset control found\n");
+		return PTR_ERR(tcphy->uphy_rst);
+	}
+
+	return 0;
+}
+
+static int rockchip_typec_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_typec_phy *tcphy;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
+	if (!tcphy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tcphy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tcphy->base)) {
+		dev_err(dev, "failed to remap phy regs\n");
+		return PTR_ERR(tcphy->base);
+	}
+
+	tcphy_parse_dt(tcphy, dev);
+
+	tcphy->dev = dev;
+	platform_set_drvdata(pdev, tcphy);
+
+	tcphy->mode = MODE_DISCONNECT;
+
+	tcphy->phy = devm_phy_create(dev, NULL, &rockchip_tcphy_ops);
+	if (IS_ERR(tcphy->phy)) {
+		dev_err(dev, "failed to create Tepy-c PHY\n");
+		return PTR_ERR(tcphy->phy);
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	if (IS_ERR(phy_provider)) {
+		dev_err(dev, "Failed to register phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	tcphy->extcon = extcon_get_edev_by_phandle(dev, 0);
+	if (IS_ERR(tcphy->extcon)) {
+		if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
+			dev_err(dev, "Invalid or missing extcon\n");
+		return PTR_ERR(tcphy->extcon);
+	}
+
+	tcphy->event_nb.notifier_call = tcphy_pd_event;
+	INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
+	ret = extcon_register_notifier(tcphy->extcon, EXTCON_USB,
+				       &tcphy->event_nb);
+	if (ret) {
+		dev_err(dev, "regitster notifer failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_typec_phy_remove(struct platform_device *pdev)
+{
+	struct rockchip_typec_phy *tcphy = platform_get_drvdata(pdev);
+
+	extcon_unregister_notifier(tcphy->extcon, EXTCON_USB,
+				   &tcphy->event_nb);
+
+	return 0;
+}
+
+static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
+	{ .compatible = "rockchip,rk3399-typec-phy" },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
+
+static struct platform_driver rockchip_typec_phy_driver = {
+	.probe		= rockchip_typec_phy_probe,
+	.remove		= rockchip_typec_phy_remove,
+	.driver		= {
+		.name	= "rockchip-typec-phy",
+		.of_match_table = rockchip_typec_phy_dt_ids,
+	},
+};
+
+module_platform_driver(rockchip_typec_phy_driver);
+
+MODULE_AUTHOR("Chris Zhong <[email protected]>");
+MODULE_AUTHOR("Kever Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
+MODULE_LICENSE("GPL v2");
include/linux/phy/phy-rockchip-typec.h new file +10 -0
new file mode 100644
index 0000000..acdd8cb
@@ -0,0 +1,20 @@
+#ifndef PHY_ROCKCHIP_TYPEC_H_
+#define PHY_ROCKCHIP_TYPEC_H_
+
+#define PIN_MAP_A	BIT(0)
+#define PIN_MAP_B	BIT(1)
+#define PIN_MAP_C	BIT(2)
+#define PIN_MAP_D	BIT(3)
+#define PIN_MAP_E	BIT(4)
+#define PIN_MAP_F	BIT(5)
+

include/linux/phy/phy-rockchip-typec.h line 20

Quoted 10 lines
include/linux/phy/phy-rockchip-typec.h new file +10 -0
+#define SET_PIN_MAP(x)	(((x) & 0xff) << 24)
+#define SET_FLIP(x)	(((x) & 0xff) << 16)
+#define SET_DFP(x)	(((x) & 0xff) << 8)
+#define SET_PLUGGED(x)	((x) & 0xff)
+#define GET_PIN_MAP(x)	(((x) >> 24) & 0xff)
+#define GET_FLIP(x)	(((x) >> 16) & 0xff)
+#define GET_DFP(x)	(((x) >> 8) & 0xff)
+#define GET_PLUGGED(x)	((x) & 0xff)
+
+#endif

Thanks,
- Kever

#10 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

In reply to Chris Zhong
Quoted 81 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

---

Changes in v2:
- select RESET_CONTROLLER
- alphabetic order
- modify some spelling mistakes
- make mode cleaner
- use bool for enable/disable
- check all of the return value
- return a better err number
- use more readx_poll_timeout()
- clk_disable_unprepare(tcphy->clk_ref);
- remove unuse functions, rockchip_typec_phy_power_on/off
- remove unnecessary typecast from void *
- use dts node to distinguish between phys.

Changes in v1:
- update the licence note
- init core clock to 50MHz
- use extcon API
- remove unused global
- add some comments for magic num
- change usleep_range(1000, 2000) tousleep_range(1000, 1050)
- remove __func__ from dev_err
- return err number when get clk failed
- remove ADDR_ADJ define
- use devm_clk_get(&pdev->dev, "tcpdcore")

 drivers/phy/Kconfig                    |   8 +
 drivers/phy/Makefile                   |   1 +
 drivers/phy/phy-rockchip-typec.c       | 952 +++++++++++++++++++++++++++++++++
 include/linux/phy/phy-rockchip-typec.h |  20 +
 4 files changed, 981 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/linux/phy/phy-rockchip-typec.h
drivers/phy/Kconfig +8 -0
index 26566db..ec87b3a 100644
@@ -351,6 +351,14 @@ config PHY_ROCKCHIP_DP
 	help
 	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	select RESET_CONTROLLER
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
 config PHY_ST_SPEAR1310_MIPHY
 	tristate "ST SPEAR1310-MIPHY driver"
 	select GENERIC_PHY
drivers/phy/Makefile +1 -0
index 24596a9..91fa413 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
drivers/phy/phy-rockchip-typec.c new file +0 -0
new file mode 100644
index 0000000..230e074

<snip>

drivers/phy/phy-rockchip-typec.c line 699

Quoted 2 lines
drivers/phy/phy-rockchip-typec.c new file +2 -0
+static const struct phy_ops rockchip_tcphy_ops = {
+	.owner          = THIS_MODULE,

no ops?

Quoted 181 lines
drivers/phy/phy-rockchip-typec.c new file +181 -0
+};
+
+static int tcphy_pd_event(struct notifier_block *nb,
+			  unsigned long event, void *priv)
+{
+	struct rockchip_typec_phy *tcphy;
+	struct extcon_dev *edev = priv;
+	int value = edev->state;
+	int mode;
+	u8 is_plugged, dfp;
+
+	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+
+	is_plugged = GET_PLUGGED(value);
+	tcphy->flip = GET_FLIP(value);
+	dfp = GET_DFP(value);
+	tcphy->map = GET_PIN_MAP(value);
+
+	if (is_plugged) {
+		if (!dfp)
+			mode = MODE_UFP_USB;
+		else if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+			mode = MODE_DFP_USB | MODE_DFP_DP;
+		else if (tcphy->map & (PIN_MAP_A | PIN_MAP_C | PIN_MAP_E))
+			mode = MODE_DFP_DP;
+		else
+			mode = MODE_DFP_USB;
+	} else {
+		mode = MODE_DISCONNECT;
+	}
+
+	if (tcphy->mode != mode) {
+		tcphy->mode = mode;
+		schedule_delayed_work_on(0, &tcphy->event_wq, 0);
+	}
+
+	return 0;
+}
+
+static void tcphy_event_wq(struct work_struct *work)
+{
+	struct rockchip_typec_phy *tcphy;
+	int ret;
+
+	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
+
+	if (tcphy->mode == MODE_DISCONNECT) {
+		tcphy_phy_deinit(tcphy);
+		/* remove hpd sign for DP */
+		if (tcphy->hpd_status) {
+			regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+				     DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
+			tcphy->hpd_status = 0;
+		}
+	} else {
+		ret = tcphy_phy_init(tcphy);
+		if (ret)
+			return;
+
+		if (tcphy->mode & (MODE_UFP_USB | MODE_DFP_USB))
+			tcphy_usb3_init(tcphy);
+
+		if (tcphy->mode & MODE_DFP_DP) {
+			ret = tcphy_dp_init(tcphy);
+
+			/* set hpd sign for DP, if DP phy is ready */
+			if (!ret) {
+				regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+					     DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
+				tcphy->hpd_status = 1;
+			}
+		}
+	}
+}
+
+static int tcphy_get_param(struct device *dev,
+			   struct usb3phy_reg *reg,
+			   const char *name)
+{
+	int ret, buffer[3];
+
+	ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
+	if (ret) {
+		dev_err(dev, "Can not parse %s\n", name);
+		return ret;
+	}
+
+	reg->offset = buffer[0];
+	reg->enable_bit = buffer[1];
+	reg->write_enable = buffer[2];
+	return 0;
+}
+
+static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
+			  struct device *dev)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	int ret;
+
+	ret = tcphy_get_param(dev, &cfg->typec_conn_dir,
+			      "rockchip,typec_conn_dir");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->usb3tousb2_en,
+			      "rockchip,usb3tousb2_en");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->external_psm,
+			      "rockchip,external_psm");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->pipe_status,
+			      "rockchip,pipe_status");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->uphy_dp_sel,
+			      "rockchip,uphy_dp_sel");
+	if (ret)
+		return ret;
+
+	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+							  "rockchip,grf");
+	if (IS_ERR(tcphy->grf_regs)) {
+		dev_err(dev, "could not find grf dt node\n");
+		return PTR_ERR(tcphy->grf_regs);
+	}
+
+	tcphy->clk_core = devm_clk_get(dev, "tcpdcore");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "could not get uphy core clock\n");
+		return PTR_ERR(tcphy->clk_core);
+	}
+
+	tcphy->clk_ref = devm_clk_get(dev, "tcpdphy_ref");
+	if (IS_ERR(tcphy->clk_ref)) {
+		dev_err(dev, "could not get uphy ref clock\n");
+		return PTR_ERR(tcphy->clk_ref);
+	}
+
+	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy");
+	if (IS_ERR(tcphy->phy_rst)) {
+		dev_err(dev, "no phy_rst reset control found\n");
+		return PTR_ERR(tcphy->phy_rst);
+	}
+
+	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe");
+	if (IS_ERR(tcphy->pipe_rst)) {
+		dev_err(dev, "no pipe_rst reset control found\n");
+		return PTR_ERR(tcphy->pipe_rst);
+	}
+
+	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy");
+	if (IS_ERR(tcphy->uphy_rst)) {
+		dev_err(dev, "no uphy_rst reset control found\n");
+		return PTR_ERR(tcphy->uphy_rst);
+	}
+
+	return 0;
+}
+
+static int rockchip_typec_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_typec_phy *tcphy;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
+	if (!tcphy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tcphy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tcphy->base)) {
+		dev_err(dev, "failed to remap phy regs\n");
+		return PTR_ERR(tcphy->base);

drivers/phy/phy-rockchip-typec.c line 890

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+	}
+
+	tcphy_parse_dt(tcphy, dev);
+
+	tcphy->dev = dev;
+	platform_set_drvdata(pdev, tcphy);
+
+	tcphy->mode = MODE_DISCONNECT;
+
+	tcphy->phy = devm_phy_create(dev, NULL, &rockchip_tcphy_ops);

your phy_ops doesn't have any ops populated. Is there a reason to use the phy framework?

Thanks
Kishon

#11 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

Hi Kishon

Quoted 283 lines · Kishon Vijay Abraham I
Quoted 81 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

---

Changes in v2:
- select RESET_CONTROLLER
- alphabetic order
- modify some spelling mistakes
- make mode cleaner
- use bool for enable/disable
- check all of the return value
- return a better err number
- use more readx_poll_timeout()
- clk_disable_unprepare(tcphy->clk_ref);
- remove unuse functions, rockchip_typec_phy_power_on/off
- remove unnecessary typecast from void *
- use dts node to distinguish between phys.

Changes in v1:
- update the licence note
- init core clock to 50MHz
- use extcon API
- remove unused global
- add some comments for magic num
- change usleep_range(1000, 2000) tousleep_range(1000, 1050)
- remove __func__ from dev_err
- return err number when get clk failed
- remove ADDR_ADJ define
- use devm_clk_get(&pdev->dev, "tcpdcore")

  drivers/phy/Kconfig                    |   8 +
  drivers/phy/Makefile                   |   1 +
  drivers/phy/phy-rockchip-typec.c       | 952 +++++++++++++++++++++++++++++++++
  include/linux/phy/phy-rockchip-typec.h |  20 +
  4 files changed, 981 insertions(+)

create mode 100644 drivers/phy/phy-rockchip-typec.c create mode 100644 include/linux/phy/phy-rockchip-typec.h

drivers/phy/Kconfig +8 -0
index 26566db..ec87b3a 100644
@@ -351,6 +351,14 @@ config PHY_ROCKCHIP_DP
  	help
  	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	select RESET_CONTROLLER
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
  config PHY_ST_SPEAR1310_MIPHY
  	tristate "ST SPEAR1310-MIPHY driver"
  	select GENERIC_PHY
drivers/phy/Makefile +1 -0
index 24596a9..91fa413 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
  obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
  obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
  obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
  obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
  obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
  obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
drivers/phy/phy-rockchip-typec.c new file +0 -0
new file mode 100644
index 0000000..230e074

<snip>

drivers/phy/phy-rockchip-typec.c line 699

Quoted 2 lines
drivers/phy/phy-rockchip-typec.c new file +2 -0
+static const struct phy_ops rockchip_tcphy_ops = {
+	.owner          = THIS_MODULE,

no ops?

Quoted 181 lines
drivers/phy/phy-rockchip-typec.c new file +181 -0
+};
+
+static int tcphy_pd_event(struct notifier_block *nb,
+			  unsigned long event, void *priv)
+{
+	struct rockchip_typec_phy *tcphy;
+	struct extcon_dev *edev = priv;
+	int value = edev->state;
+	int mode;
+	u8 is_plugged, dfp;
+
+	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+
+	is_plugged = GET_PLUGGED(value);
+	tcphy->flip = GET_FLIP(value);
+	dfp = GET_DFP(value);
+	tcphy->map = GET_PIN_MAP(value);
+
+	if (is_plugged) {
+		if (!dfp)
+			mode = MODE_UFP_USB;
+		else if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+			mode = MODE_DFP_USB | MODE_DFP_DP;
+		else if (tcphy->map & (PIN_MAP_A | PIN_MAP_C | PIN_MAP_E))
+			mode = MODE_DFP_DP;
+		else
+			mode = MODE_DFP_USB;
+	} else {
+		mode = MODE_DISCONNECT;
+	}
+
+	if (tcphy->mode != mode) {
+		tcphy->mode = mode;
+		schedule_delayed_work_on(0, &tcphy->event_wq, 0);
+	}
+
+	return 0;
+}
+
+static void tcphy_event_wq(struct work_struct *work)
+{
+	struct rockchip_typec_phy *tcphy;
+	int ret;
+
+	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
+
+	if (tcphy->mode == MODE_DISCONNECT) {
+		tcphy_phy_deinit(tcphy);
+		/* remove hpd sign for DP */
+		if (tcphy->hpd_status) {
+			regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+				     DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
+			tcphy->hpd_status = 0;
+		}
+	} else {
+		ret = tcphy_phy_init(tcphy);
+		if (ret)
+			return;
+
+		if (tcphy->mode & (MODE_UFP_USB | MODE_DFP_USB))
+			tcphy_usb3_init(tcphy);
+
+		if (tcphy->mode & MODE_DFP_DP) {
+			ret = tcphy_dp_init(tcphy);
+
+			/* set hpd sign for DP, if DP phy is ready */
+			if (!ret) {
+				regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+					     DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
+				tcphy->hpd_status = 1;
+			}
+		}
+	}
+}
+
+static int tcphy_get_param(struct device *dev,
+			   struct usb3phy_reg *reg,
+			   const char *name)
+{
+	int ret, buffer[3];
+
+	ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
+	if (ret) {
+		dev_err(dev, "Can not parse %s\n", name);
+		return ret;
+	}
+
+	reg->offset = buffer[0];
+	reg->enable_bit = buffer[1];
+	reg->write_enable = buffer[2];
+	return 0;
+}
+
+static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
+			  struct device *dev)
+{
+	struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
+	int ret;
+
+	ret = tcphy_get_param(dev, &cfg->typec_conn_dir,
+			      "rockchip,typec_conn_dir");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->usb3tousb2_en,
+			      "rockchip,usb3tousb2_en");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->external_psm,
+			      "rockchip,external_psm");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->pipe_status,
+			      "rockchip,pipe_status");
+	if (ret)
+		return ret;
+
+	ret = tcphy_get_param(dev, &cfg->uphy_dp_sel,
+			      "rockchip,uphy_dp_sel");
+	if (ret)
+		return ret;
+
+	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+							  "rockchip,grf");
+	if (IS_ERR(tcphy->grf_regs)) {
+		dev_err(dev, "could not find grf dt node\n");
+		return PTR_ERR(tcphy->grf_regs);
+	}
+
+	tcphy->clk_core = devm_clk_get(dev, "tcpdcore");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "could not get uphy core clock\n");
+		return PTR_ERR(tcphy->clk_core);
+	}
+
+	tcphy->clk_ref = devm_clk_get(dev, "tcpdphy_ref");
+	if (IS_ERR(tcphy->clk_ref)) {
+		dev_err(dev, "could not get uphy ref clock\n");
+		return PTR_ERR(tcphy->clk_ref);
+	}
+
+	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy");
+	if (IS_ERR(tcphy->phy_rst)) {
+		dev_err(dev, "no phy_rst reset control found\n");
+		return PTR_ERR(tcphy->phy_rst);
+	}
+
+	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe");
+	if (IS_ERR(tcphy->pipe_rst)) {
+		dev_err(dev, "no pipe_rst reset control found\n");
+		return PTR_ERR(tcphy->pipe_rst);
+	}
+
+	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy");
+	if (IS_ERR(tcphy->uphy_rst)) {
+		dev_err(dev, "no uphy_rst reset control found\n");
+		return PTR_ERR(tcphy->uphy_rst);
+	}
+
+	return 0;
+}
+
+static int rockchip_typec_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_typec_phy *tcphy;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
+	if (!tcphy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tcphy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tcphy->base)) {
+		dev_err(dev, "failed to remap phy regs\n");
+		return PTR_ERR(tcphy->base);

drivers/phy/phy-rockchip-typec.c line 890

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+	}
+
+	tcphy_parse_dt(tcphy, dev);
+
+	tcphy->dev = dev;
+	platform_set_drvdata(pdev, tcphy);
+
+	tcphy->mode = MODE_DISCONNECT;
+
+	tcphy->phy = devm_phy_create(dev, NULL, &rockchip_tcphy_ops);

your phy_ops doesn't have any ops populated. Is there a reason to use the phy framework?

Quoted 4 lines

Thanks
Kishon

Yes, I am thinking about it, remove it would be better.

#12 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

In reply to Chris Zhong

Hi Chris,

Quoted 5 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

Please see my comments inline.

[snip]

Quoted 6 lines
drivers/phy/phy-rockchip-typec.c new file +0 -0
new file mode 100644
index 0000000..230e074
@@ -0,0 +1,952 @@

[snip]

drivers/phy/phy-rockchip-typec.c

Quoted 2 lines
drivers/phy/phy-rockchip-typec.c new file +2 -0
+
+#define XCVR_PSM_RCTRL(n)              ((0x4001 | (n << 9)) << 2)

It's not very safe to not have parentheses around the macro argument dereference. Please add to all macros, such as below:

#define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2)

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+#define XCVR_PSM_CAL_TMR(n)            ((0x4002 | (n << 9)) << 2)
+#define XCVR_PSM_A0IN_TMR(n)           ((0x4003 | (n << 9)) << 2)
+#define TX_TXCC_CAL_SCLR_MULT(n)       ((0x4047 | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_00(n)       ((0x404c | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_01(n)       ((0x404d | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_10(n)       ((0x404e | (n << 9)) << 2)
+#define TX_TXCC_CPOST_MULT_11(n)       ((0x404f | (n << 9)) << 2)

[snip]

drivers/phy/phy-rockchip-typec.c line 215

Quoted 6 lines
drivers/phy/phy-rockchip-typec.c new file +6 -0
+#define PHY_MODE_SET_TIMEOUT           1000000
+
+#define        MODE_DISCONNECT                 0
+#define        MODE_UFP_USB                    BIT(0)
+#define        MODE_DFP_USB                    BIT(1)
+#define        MODE_DFP_DP                     BIT(2)

CodingStyle: Why is there a tab between #define and name?

drivers/phy/phy-rockchip-typec.c line 220

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+
+struct usb3phy_reg {
+       u32     offset;
+       u32     enable_bit;
+       u32     write_enable;

CodingStyle: I believe it's generally preferable to just use a single space between type and name. Also applies to other structs in this file.

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+};
+
+struct rockchip_usb3phy_port_cfg {
+       struct usb3phy_reg      typec_conn_dir;
+       struct usb3phy_reg      usb3tousb2_en;

[snip]

drivers/phy/phy-rockchip-typec.c line 260

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+struct phy_reg {
+       int value;
+       int addr;
+};
+
+struct phy_reg usb_pll_cfg[] = {
+       {0xf0,          CMN_PLL0_VCOCAL_INIT},

CodingStyle: Please add spaces after opening and before closing braces.

drivers/phy/phy-rockchip-typec.c line 273

Quoted 13 lines
drivers/phy/phy-rockchip-typec.c new file +13 -0
+       {0x18,          CMN_PLL0_VCOCAL_ITER},
+       {0xd0,          CMN_PLL0_INTDIV},
+       {0x4a4a,        CMN_PLL0_FRACDIV},
+       {0x34,          CMN_PLL0_HIGH_THR},
+       {0x1ee,         CMN_PLL0_SS_CTRL1},
+       {0x7f03,        CMN_PLL0_SS_CTRL2},
+       {0x20,          CMN_PLL0_DSM_DIAG},
+       {0,             CMN_DIAG_PLL0_OVRD},
+       {0,             CMN_DIAG_PLL0_FBH_OVRD},
+       {0,             CMN_DIAG_PLL0_FBL_OVRD},
+       {0x7,           CMN_DIAG_PLL0_V2I_TUNE},
+       {0x45,          CMN_DIAG_PLL0_CP_TUNE},
+       {0x8,           CMN_DIAG_PLL0_LF_PROG},

It would be generally much, much better if these magic numbers were dissected into particular bitfields and defined using macros, if possible... The same applies to all other magic numbers in this file.

Quoted 3 lines
drivers/phy/phy-rockchip-typec.c new file +3 -0
+};
+
+struct phy_reg dp_pll_cfg[] = {

[snip]

drivers/phy/phy-rockchip-typec.c line 329

Quoted 11 lines
drivers/phy/phy-rockchip-typec.c new file +11 -0
+static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
+{
+       u32 rdata;
+       u32 i;
+
+       /*
+        * Selects which PLL clock will be driven on the analog high speed
+        * clock 0: PLL 0 div 1.
+        */
+       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+       writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);

This mask looks suspiciously. Is clearing bits 31-16 and 1-0 what we want here? I'd advise for manipulating the value in separate line and then only calling writel() with the final value already in the variable.

Quoted 4 lines
drivers/phy/phy-rockchip-typec.c new file +4 -0
+
+       /* load the configuration of PLL0 */
+       for (i = 0; i < ARRAY_SIZE(usb_pll_cfg); i++)
+               writel(usb_pll_cfg[i].value, tcphy->base + usb_pll_cfg[i].addr);

drivers/phy/phy-rockchip-typec.c line 343

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+}
+
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+{
+       u32 rdata;
+       u32 i;
+
+       /* set the default mode to RBR */
+       writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR,
+              tcphy->base + DP_CLK_CTL);

This looks (and is understandable) much better than magic numbers in other parts of this file!

drivers/phy/phy-rockchip-typec.c line 350

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+
+       /*
+        * Selects which PLL clock will be driven on the analog high speed
+        * clock 1: PLL 1 div 2.
+        */
+       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+       rdata = (rdata & 0xffcf) | 0x30;

If the & operation here is used to clear a bitfield, please use the negative notation, e.g.

rdata &= ~0x30;
rdata |= 0x30;

(By the way, the AND NOT and OR with the same value is what the code above does, which would make sense if the bitfield mask was defined by a macro, but doesn't make any sense with magic numbers.)

It looks like the registers are 16-bit. Should they really be accessed with readl() and not readw()? If they are accessed with readl(), what is returned in most significant 16 bits and what should be written there?

Quoted 6 lines
drivers/phy/phy-rockchip-typec.c new file +6 -0
+       writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
+
+       /* load the configuration of PLL1 */
+       for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++)
+               writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr);
+}

[snip]

drivers/phy/phy-rockchip-typec.c line 439

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+static inline int property_enable(struct rockchip_typec_phy *tcphy,
+                                 const struct usb3phy_reg *reg, bool en)
+{
+       int mask = 1 << reg->write_enable;
+       int val = en << reg->enable_bit;

A signed int is not really a good data type to store register values in. Please use a fixed size unsigned data type with size matching the registers, e.g. u32 or u16.

Quoted 3 lines
drivers/phy/phy-rockchip-typec.c new file +3 -0
+
+       return regmap_write(tcphy->grf_regs, reg->offset, val | mask);
+}

[snip]

drivers/phy/phy-rockchip-typec.c line 559

Quoted 11 lines
drivers/phy/phy-rockchip-typec.c new file +11 -0
+       /*
+        * Controls auxda_polarity, which selects the polarity of the xcvr
+        * 1'b1 : Reverses the polarity (If TYPEC, Pulls ups aux_p and pull
+        * down aux_m)
+        * 1'b0 : Normal polarity (if TYPE_C, pulls up aux_m and pulls down
+        * aux_p)
+        */
+       if (tcphy->flip)
+               writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
+       else
+               writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);

nit: IMHO it would be a bit more readable if done like this:

val = 0xa078; // Or proper bitfield definitions ORed together... if (!tcphy->flip)

    val |= BIT(12); // Or proper bitfield macro...

writel(val, tcphy->base + TX_ANA_CTRL_REG1);

Quoted 4 lines
drivers/phy/phy-rockchip-typec.c new file +4 -0
+
+       writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+       writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
+       writel(0, tcphy->base + TX_ANA_CTRL_REG_5);

[snip]

drivers/phy/phy-rockchip-typec.c line 641

Quoted 4 lines
drivers/phy/phy-rockchip-typec.c new file +4 -0
+       ret = clk_set_rate(tcphy->clk_core, 50000000);
+       if (ret) {
+               dev_err(tcphy->dev, "set type-c phy core clk rate failed\n");
+               goto clk_ref_failed;

CodingStyle: The convention is to name the labels after the clean-up step that is done at them, e.g. err_clk_core.

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+       }
+
+       ret = clk_prepare_enable(tcphy->clk_ref);
+       if (ret) {
+               dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
+               goto clk_ref_failed;
+       }

[snip]

drivers/phy/phy-rockchip-typec.c line 699

Quoted 8 lines
drivers/phy/phy-rockchip-typec.c new file +8 -0
+static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
+{
+       clk_disable_unprepare(tcphy->clk_core);
+       clk_disable_unprepare(tcphy->clk_ref);
+}
+
+static const struct phy_ops rockchip_tcphy_ops = {
+       .owner          = THIS_MODULE,

Hmm, if there is no phy ops, how the phy consumer drivers request the PHY to do anything?

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+};
+
+static int tcphy_pd_event(struct notifier_block *nb,
+                         unsigned long event, void *priv)
+{

[snip]

drivers/phy/phy-rockchip-typec.c line 779

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+static int tcphy_get_param(struct device *dev,
+                          struct usb3phy_reg *reg,
+                          const char *name)
+{
+       int ret, buffer[3];

Shouldn't buffer be u32[3]?

Quoted 6 lines
drivers/phy/phy-rockchip-typec.c new file +6 -0
+
+       ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
+       if (ret) {
+               dev_err(dev, "Can not parse %s\n", name);
+               return ret;
+       }

[snip]

Quoted 14 lines
include/linux/phy/phy-rockchip-typec.h new file +8 -0
new file mode 100644
index 0000000..acdd8cb
@@ -0,0 +1,20 @@
+#ifndef PHY_ROCKCHIP_TYPEC_H_
+#define PHY_ROCKCHIP_TYPEC_H_
+
+#define PIN_MAP_A      BIT(0)
+#define PIN_MAP_B      BIT(1)
+#define PIN_MAP_C      BIT(2)
+#define PIN_MAP_D      BIT(3)
+#define PIN_MAP_E      BIT(4)

include/linux/phy/phy-rockchip-typec.h line 18

Quoted 10 lines
include/linux/phy/phy-rockchip-typec.h new file +10 -0
+#define PIN_MAP_F      BIT(5)
+
+#define SET_PIN_MAP(x) (((x) & 0xff) << 24)
+#define SET_FLIP(x)    (((x) & 0xff) << 16)
+#define SET_DFP(x)     (((x) & 0xff) << 8)
+#define SET_PLUGGED(x) ((x) & 0xff)
+#define GET_PIN_MAP(x) (((x) >> 24) & 0xff)
+#define GET_FLIP(x)    (((x) >> 16) & 0xff)
+#define GET_DFP(x)     (((x) >> 8) & 0xff)
+#define GET_PLUGGED(x) ((x) & 0xff)

Who is the user of the definitions in this header?

Best regards,
Tomasz

#13 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

Hi Tomasz

Thanks for your comments.
I will modify all the the part of snip. Please find my reply in the following.

Quoted 27 lines · Tomasz Figa

Hi Chris,

[snip]

drivers/phy/phy-rockchip-typec.c line 260

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+struct phy_reg {
+       int value;
+       int addr;
+};
+
+struct phy_reg usb_pll_cfg[] = {
+       {0xf0,          CMN_PLL0_VCOCAL_INIT},

CodingStyle: Please add spaces after opening and before closing braces.

drivers/phy/phy-rockchip-typec.c line 273

Quoted 13 lines
drivers/phy/phy-rockchip-typec.c new file +13 -0
+       {0x18,          CMN_PLL0_VCOCAL_ITER},
+       {0xd0,          CMN_PLL0_INTDIV},
+       {0x4a4a,        CMN_PLL0_FRACDIV},
+       {0x34,          CMN_PLL0_HIGH_THR},
+       {0x1ee,         CMN_PLL0_SS_CTRL1},
+       {0x7f03,        CMN_PLL0_SS_CTRL2},
+       {0x20,          CMN_PLL0_DSM_DIAG},
+       {0,             CMN_DIAG_PLL0_OVRD},
+       {0,             CMN_DIAG_PLL0_FBH_OVRD},
+       {0,             CMN_DIAG_PLL0_FBL_OVRD},
+       {0x7,           CMN_DIAG_PLL0_V2I_TUNE},
+       {0x45,          CMN_DIAG_PLL0_CP_TUNE},
+       {0x8,           CMN_DIAG_PLL0_LF_PROG},
Quoted 3 lines

It would be generally much, much better if these magic numbers were dissected into particular bitfields and defined using macros, if possible... The same applies to all other magic numbers in this file.

This magic number is very hard to describe, it is a initialization sequence from vendor.
Their names are very close to the description.
From spec of cdn type-c phy:
Iteration wait timer value
pll_fb_div_integer value: Value of the pll_fb_div_integer signal.
pll_fb_div_fractional: Value of the pll_fb_div_fractional signal.
pll_fb_div_high_theshold: Value of the pll_fb_div_high_threshold signal.
...

Quoted 4 lines
Quoted 3 lines
drivers/phy/phy-rockchip-typec.c new file +3 -0
+};
+
+struct phy_reg dp_pll_cfg[] = {

[snip]

Quoted 15 lines

drivers/phy/phy-rockchip-typec.c line 329

Quoted 11 lines
drivers/phy/phy-rockchip-typec.c new file +11 -0
+static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
+{
+       u32 rdata;
+       u32 i;
+
+       /*
+        * Selects which PLL clock will be driven on the analog high speed
+        * clock 0: PLL 0 div 1.
+        */
+       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+       writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);

This mask looks suspiciously. Is clearing bits 31-16 and 1-0 what we want here? I'd advise for manipulating the value in separate line and then only calling writel() with the final value already in the variable.

Yes, the register valid length is 16 bits, but the they are stored with 32bit.
readl will return 0 in higher 16bit + valid value in lower 16bit. and writel will ignore the higher 16bit.

Quoted 31 lines
Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +4 -0
+
+       /* load the configuration of PLL0 */
+       for (i = 0; i < ARRAY_SIZE(usb_pll_cfg); i++)
+               writel(usb_pll_cfg[i].value, tcphy->base + usb_pll_cfg[i].addr);

drivers/phy/phy-rockchip-typec.c line 343

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+}
+
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+{
+       u32 rdata;
+       u32 i;
+
+       /* set the default mode to RBR */
+       writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR,
+              tcphy->base + DP_CLK_CTL);

This looks (and is understandable) much better than magic numbers in other parts of this file!

drivers/phy/phy-rockchip-typec.c line 350

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+
+       /*
+        * Selects which PLL clock will be driven on the analog high speed
+        * clock 1: PLL 1 div 2.
+        */
+       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+       rdata = (rdata & 0xffcf) | 0x30;

If the & operation here is used to clear a bitfield, please use the negative notation, e.g.

rdata &= ~0x30;
rdata |= 0x30;

Quoted 8 lines

(By the way, the AND NOT and OR with the same value is what the code above does, which would make sense if the bitfield mask was defined by a macro, but doesn't make any sense with magic numbers.)

It looks like the registers are 16-bit. Should they really be accessed with readl() and not readw()? If they are accessed with readl(), what is returned in most significant 16 bits and what should be written there?

I will use macro here at next version

Quoted 16 lines
Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +6 -0
+       writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
+
+       /* load the configuration of PLL1 */
+       for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++)
+               writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr);
+}

[snip]

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+       }
+
+       ret = clk_prepare_enable(tcphy->clk_ref);
+       if (ret) {
+               dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
+               goto clk_ref_failed;
+       }

[snip]

Quoted 10 lines

drivers/phy/phy-rockchip-typec.c line 699

Quoted 8 lines
drivers/phy/phy-rockchip-typec.c new file +8 -0
+static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
+{
+       clk_disable_unprepare(tcphy->clk_core);
+       clk_disable_unprepare(tcphy->clk_ref);
+}
+
+static const struct phy_ops rockchip_tcphy_ops = {
+       .owner          = THIS_MODULE,

Hmm, if there is no phy ops, how the phy consumer drivers request the PHY to do anything?

There is no consumer call this phy, the power on and power off are called by notification.
So I am going to delete this ops next version.

Quoted 37 lines
Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+};
+
+static int tcphy_pd_event(struct notifier_block *nb,
+                         unsigned long event, void *priv)
+{

[snip]

drivers/phy/phy-rockchip-typec.c line 779

Quoted 5 lines
drivers/phy/phy-rockchip-typec.c new file +5 -0
+static int tcphy_get_param(struct device *dev,
+                          struct usb3phy_reg *reg,
+                          const char *name)
+{
+       int ret, buffer[3];

Shouldn't buffer be u32[3]?

Quoted 6 lines
drivers/phy/phy-rockchip-typec.c new file +6 -0
+
+       ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
+       if (ret) {
+               dev_err(dev, "Can not parse %s\n", name);
+               return ret;
+       }

[snip]

Quoted 17 lines
include/linux/phy/phy-rockchip-typec.h new file +11 -0
new file mode 100644
index 0000000..acdd8cb
@@ -0,0 +1,20 @@
+#ifndef PHY_ROCKCHIP_TYPEC_H_
+#define PHY_ROCKCHIP_TYPEC_H_
+
+#define PIN_MAP_A      BIT(0)
+#define PIN_MAP_B      BIT(1)
+#define PIN_MAP_C      BIT(2)
+#define PIN_MAP_D      BIT(3)
+#define PIN_MAP_E      BIT(4)
+#define PIN_MAP_F      BIT(5)
+
+#define SET_PIN_MAP(x) (((x) & 0xff) << 24)
Quoted 8 lines

include/linux/phy/phy-rockchip-typec.h line 18

Quoted 7 lines
include/linux/phy/phy-rockchip-typec.h new file +7 -0
+#define SET_FLIP(x)    (((x) & 0xff) << 16)
+#define SET_DFP(x)     (((x) & 0xff) << 8)
+#define SET_PLUGGED(x) ((x) & 0xff)
+#define GET_PIN_MAP(x) (((x) >> 24) & 0xff)
+#define GET_FLIP(x)    (((x) >> 16) & 0xff)
+#define GET_DFP(x)     (((x) >> 8) & 0xff)
+#define GET_PLUGGED(x) ((x) & 0xff)

Who is the user of the definitions in this header?

The type-c phy, Dp controller and Power delivery are the user. Power delivery set the state and send the notification type-c phy and Dp contoller get the state.

Quoted 5 lines

Best regards,
Tomasz

#14 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

In reply to Chris Zhong

Hi Chris,

Quoted 6 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

I started integrating the driver with our code.
Doing so, I realized a problem in the way you are using extcon.

[ ... ]

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+
+static int tcphy_pd_event(struct notifier_block *nb,
+                         unsigned long event, void *priv)
+{
+       struct rockchip_typec_phy *tcphy;
+       struct extcon_dev *edev = priv;
+       int value = edev->state;

drivers/phy/phy-rockchip-typec.c line 717

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+       int mode;
+       u8 is_plugged, dfp;
+
+       tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+
+       is_plugged = GET_PLUGGED(value);
+       tcphy->flip = GET_FLIP(value);
+       dfp = GET_DFP(value);
+       tcphy->map = GET_PIN_MAP(value);
+

I don't think it is a good idea to use the extcon 'state' field like this. I don't even think it is possible.

The state is supposed to be a bit mask, each bit indicating if a specific connector (or functionality) on the cable is attached. The extcon notifier code walks through this bit mask and determines based on changed bits if the notifier should be called. So the notifier in this case would only be called if bit 1 (EXTCON_USB) of 'state' has changed, but not if one of the other bits has changed. One would have to define 32 "virtual" cables, one for each bit, for this to work, and then you would have to register a notifier for each of the bits. That would not really make sense.

Of course, that makes using the extcon notifier quite useless for our purpose, since we need the callback not only if a cable has been attached or deattached, but also if some secondary state changes. I don't really know myself how to solve the problem; I'll need to think about it some more. Maybe we can add a callback into the type-c infrastructure code and somehow tie into that code, but I don't know yet if that is feasible either.

Guenter

#15 lore raw

Re: [v2 PATCH 2/4] phy: Add USB Type-C PHY driver for rk3399

Hi Guenter

Quoted 52 lines · Guenter Roeck

Hi Chris,

Quoted 6 lines · Chris Zhong

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The PHY basically has two main components: USB3 and DisplyPort. USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates.

I started integrating the driver with our code.
Doing so, I realized a problem in the way you are using extcon.

[ ... ]

Quoted 7 lines
drivers/phy/phy-rockchip-typec.c new file +7 -0
+
+static int tcphy_pd_event(struct notifier_block *nb,
+                         unsigned long event, void *priv)
+{
+       struct rockchip_typec_phy *tcphy;
+       struct extcon_dev *edev = priv;
+       int value = edev->state;

drivers/phy/phy-rockchip-typec.c line 717

Quoted 10 lines
drivers/phy/phy-rockchip-typec.c new file +10 -0
+       int mode;
+       u8 is_plugged, dfp;
+
+       tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+
+       is_plugged = GET_PLUGGED(value);
+       tcphy->flip = GET_FLIP(value);
+       dfp = GET_DFP(value);
+       tcphy->map = GET_PIN_MAP(value);
+

I don't think it is a good idea to use the extcon 'state' field like this. I don't even think it is possible.

The state is supposed to be a bit mask, each bit indicating if a specific connector (or functionality) on the cable is attached. The extcon notifier code walks through this bit mask and determines based on changed bits if the notifier should be called. So the notifier in this case would only be called if bit 1 (EXTCON_USB) of 'state' has changed, but not if one of the other bits has changed. One would have to define 32 "virtual" cables, one for each bit, for this to work, and then you would have to register a notifier for each of the bits. That would not really make sense.

Of course, that makes using the extcon notifier quite useless for our purpose, since we need the callback not only if a cable has been attached or deattached, but also if some secondary state changes. I don't really know myself how to solve the problem; I'll need to think about it some more. Maybe we can add a callback into the type-c infrastructure code and somehow tie into that code, but I don't know yet if that is feasible either.

Quoted 3 lines

Guenter

Yes, currently, we can get the notification only when bit 0 change. So the phy driver can know plug/unplug event.
if we need more trigger, how about set the BIT 0 for changed flag.

state = extcon_get_cable_state

state = ~state | is_plugged | flip | dfp | map

extcon_set_state(state)

#16 lore raw

PATCH v2 3/4 Documentation: bindings: add dt documentation for cdn DP controller

In reply to Chris Zhong

This patch adds a binding that describes the cdn DP controller for rk3399.

---

Changes in v2: None
Changes in v1:
- add extcon node description
- add #sound-dai-cells description

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  | 62 ++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +62 -0
new file mode 100644
index 0000000..4a66fc3
@@ -0,0 +1,62 @@
+Rockchip RK3399 specific extensions to the cdn Display Port
+================================
+
+Required properties:
+- compatible: must be "rockchip,cdn-dp"
+
+- reg: physical base address of the controller and length
+
+- clocks: from common clock binding: handle to dp clock.
+
+- clock-names: from common clock binding:
+	       Required elements: "core_clk" "pclk" "spdif"
+
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+
+- ports: contain a port nodes with endpoint definitions as defined in
+	 Documentation/devicetree/bindings/media/video-interfaces.txt.
+	 contained 2 endpoints, connecting to the output of vop.
+
+- phys: from general PHY binding: the phandle for the PHY device.
+
+- extcon: extcon specifier for the Power Delivery
+
+- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF
+
+-------------------------------------------------------------------------------
+
+Example:
+	cdn_dp: dp at fec00000 {
+		compatible = "rockchip,cdn-dp";
+		reg = <0x0 0xfec00000 0x0 0x100000>;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+			 <&cru SCLK_SPDIF_REC_DPTX>;
+		clock-names = "core_clk", "pclk", "spdif";
+		phys = <&tcphy0>;
+		extcon = <&fusb1>;
+		rockchip,grf = <&grf>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#sound-dai-cells = <1>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			dp_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				dp_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_dp>;
+				};
+
+				dp_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_dp>;
+				};
+			};
+		};
+	};
Signature · 1 line
2.6.3
maintainer
#17 lore raw

Re: [v2 PATCH 3/4] Documentation: bindings: add dt documentation for cdn DP controller

Quoted 22 lines · Chris Zhong

This patch adds a binding that describes the cdn DP controller for rk3399.

---

Changes in v2: None
Changes in v1:
- add extcon node description
- add #sound-dai-cells description

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  | 62 ++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +0 -0
new file mode 100644
index 0000000..4a66fc3

Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt line 5

Quoted 5 lines
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +5 -0
@@ -0,0 +1,62 @@
+Rockchip RK3399 specific extensions to the cdn Display Port
+================================
+
+Required properties:
+- compatible: must be "rockchip,cdn-dp"

SoC specific compatible string please.

Quoted 32 lines
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +32 -0
+
+- reg: physical base address of the controller and length
+
+- clocks: from common clock binding: handle to dp clock.
+
+- clock-names: from common clock binding:
+	       Required elements: "core_clk" "pclk" "spdif"
+
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+
+- ports: contain a port nodes with endpoint definitions as defined in
+	 Documentation/devicetree/bindings/media/video-interfaces.txt.
+	 contained 2 endpoints, connecting to the output of vop.
+
+- phys: from general PHY binding: the phandle for the PHY device.
+
+- extcon: extcon specifier for the Power Delivery
+
+- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF
+
+-------------------------------------------------------------------------------
+
+Example:
+	cdn_dp: dp@fec00000 {
+		compatible = "rockchip,cdn-dp";
+		reg = <0x0 0xfec00000 0x0 0x100000>;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+			 <&cru SCLK_SPDIF_REC_DPTX>;
+		clock-names = "core_clk", "pclk", "spdif";
+		phys = <&tcphy0>;
+		extcon = <&fusb1>;

Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt line 46

Quoted 10 lines
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +9 -0
+		rockchip,grf = <&grf>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#sound-dai-cells = <1>;
+
+		ports {
 
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;

Don't need these with a single port.

Quoted 20 lines
Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt new file +16 -0
+
+			dp_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				dp_in_vopb: endpoint@0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_dp>;
+				};
+
+				dp_in_vopl: endpoint@1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_dp>;
+				};
+			};
+		};
+	};
Signature · 1 line
2.6.3
#18 lore raw

PATCH v2 4/4 drm/rockchip: cdn-dp: add cdn DP support for rk3399

In reply to Chris Zhong

Add support for cdn DP controller which is embedded in the rk3399 SoCs. The DP is compliant with DisplayPort Specification, Version 1.3, This IP is compatible with the rockchip type-c PHY IP. There is a uCPU in DP controller, it need a firmware to work, please put the firmware file to /lib/firmware/cdn/dptx.bin. The uCPU in charge of aux communication and link training, the host use mailbox to communicate with the ucpu.
The dclk pin_pol of vop must not be invert for DP.

---

Changes in v2:
- Alphabetic order
- remove excess error message
- use define clk_rate
- check all return value
- remove dev_set_name(dp->dev, "cdn-dp");
- use schedule_delayed_work
- remove never-called functions
- remove some unnecessary ()

Changes in v1:
- use extcon API
- use hdmi-codec for the DP Asoc
- do not initialize the "ret"
- printk a err log when drm_of_encoder_active_endpoint_id
- modify the dclk pin_pol to a single line

 drivers/gpu/drm/rockchip/Kconfig            |   9 +
 drivers/gpu/drm/rockchip/Makefile           |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c      | 694 +++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h      | 108 +++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c       | 717 ++++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h       | 404 ++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   6 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   2 +
 9 files changed, 1942 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
drivers/gpu/drm/rockchip/Kconfig +9 -0
index d30bdc3..20da9a8 100644
@@ -25,6 +25,15 @@ config ROCKCHIP_ANALOGIX_DP
 	  for the Analogix Core DP driver. If you want to enable DP
 	  on RK3288 based SoC, you should selet this option.
 
+config ROCKCHIP_CDN_DP
+        tristate "Rockchip cdn DP"
+        depends on DRM_ROCKCHIP
+        help
+	  This selects support for Rockchip SoC specific extensions
+	  for the cdn Dp driver. If you want to enable Dp on
+	  RK3399 based SoC, you should selet this
+	  option.
+
 config ROCKCHIP_DW_HDMI
         tristate "Rockchip specific extensions for Synopsys DW HDMI"
         depends on DRM_ROCKCHIP
drivers/gpu/drm/rockchip/Makefile +1 -0
index 05d0713..abdecd5 100644
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
+obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
 obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
drivers/gpu/drm/rockchip/cdn-dp-core.c new file +694 -0

694 lines not on this page · raw message

drivers/gpu/drm/rockchip/cdn-dp-core.h new file +108 -0

108 lines not on this page · raw message

drivers/gpu/drm/rockchip/cdn-dp-reg.c new file +717 -0

717 lines not on this page · raw message

drivers/gpu/drm/rockchip/cdn-dp-reg.h new file +404 -0

404 lines not on this page · raw message

drivers/gpu/drm/rockchip/rockchip_drm_vop.c +5 -1
index edd7ec2..98302b3 100644
@@ -969,7 +969,7 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		vop_dsp_hold_valid_irq_disable(vop);
 	}
 
-	pin_pol = 0x8;
+	pin_pol = (s->output_type == DRM_MODE_CONNECTOR_DisplayPort) ? 0 : 0x8;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
 	VOP_CTRL_SET(vop, pin_pol, pin_pol);
@@ -991,6 +991,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol);
 		VOP_CTRL_SET(vop, mipi_en, 1);
 		break;
+	case DRM_MODE_CONNECTOR_DisplayPort:
+		VOP_CTRL_SET(vop, dp_pin_pol, pin_pol);
+		VOP_CTRL_SET(vop, dp_en, 1);
+		break;
 	default:
 		DRM_ERROR("unsupport connector_type[%d]\n", s->output_type);
 	}
drivers/gpu/drm/rockchip/rockchip_drm_vop.h +2 -0
index ff4f52e..50a045c 100644
@@ -45,6 +45,7 @@ struct vop_ctrl {
 	struct vop_reg edp_en;
 	struct vop_reg hdmi_en;
 	struct vop_reg mipi_en;
+	struct vop_reg dp_en;
 	struct vop_reg out_mode;
 	struct vop_reg dither_down;
 	struct vop_reg dither_up;
@@ -53,6 +54,7 @@ struct vop_ctrl {
 	struct vop_reg hdmi_pin_pol;
 	struct vop_reg edp_pin_pol;
 	struct vop_reg mipi_pin_pol;
+	struct vop_reg dp_pin_pol;
 
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
drivers/gpu/drm/rockchip/rockchip_vop_reg.c +2 -0
index 5b1ae1f..dcf172e 100644
@@ -281,6 +281,7 @@ static const struct vop_data rk3288_vop = {
 static const struct vop_ctrl rk3399_ctrl_data = {
 	.standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22),
 	.gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23),
+	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
 	.rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12),
 	.hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13),
 	.edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14),
@@ -290,6 +291,7 @@ static const struct vop_ctrl rk3399_ctrl_data = {
 	.data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
 	.out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0),
 	.rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
+	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
 	.hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20),
 	.edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24),
 	.mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28),
Signature · 1 line
2.6.3