From 34ac02b40bcfd8ef6d9cf67848d458f8c7d99213 Mon Sep 17 00:00:00 2001 From: Yue Wang Date: Thu, 4 Apr 2019 11:18:28 +0800 Subject: [PATCH] usb: bringup TM2 usb3 [1/1] PD#SWPL-5609 Problem: bringup TM2 usb3. Solution: bringup TM2 usb3. Verify: TM2 Change-Id: Iea60a85e7d344f8f1cd44d07a634a6edd351218c Signed-off-by: Yue Wang --- MAINTAINERS | 2 + arch/arm/boot/dts/amlogic/mesontm2.dtsi | 134 ++- .../arm/boot/dts/amlogic/tm2_t962e2_ab301.dts | 18 +- .../arm/boot/dts/amlogic/tm2_t962e2_ab311.dts | 18 +- .../arm/boot/dts/amlogic/tm2_t962e2_ab319.dts | 19 +- .../arm/boot/dts/amlogic/tm2_t962x3_ab309.dts | 20 +- arch/arm64/boot/dts/amlogic/mesontm2.dtsi | 134 ++- .../boot/dts/amlogic/tm2_t962e2_ab301.dts | 18 +- .../boot/dts/amlogic/tm2_t962e2_ab311.dts | 18 +- .../boot/dts/amlogic/tm2_t962e2_ab319.dts | 19 +- .../boot/dts/amlogic/tm2_t962x3_ab309.dts | 20 +- drivers/amlogic/pci/pcie-amlogic-v2.c | 35 +- drivers/amlogic/pci/pcie-amlogic.h | 1 + drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h | 2 + .../amlogic/usb/dwc_otg/310/dwc_otg_driver.c | 16 +- .../amlogic/usb/dwc_otg/310/dwc_otg_driver.h | 1 + drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h | 1 + .../usb/dwc_otg/310/dwc_otg_pcd_intr.c | 32 +- .../usb/dwc_otg/310/dwc_otg_pcd_linux.c | 20 +- drivers/amlogic/usb/phy/Makefile | 2 + drivers/amlogic/usb/phy/phy-aml-new-otg.c | 388 ++++++++ drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c | 18 +- drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c | 918 ++++++++++++++++++ drivers/usb/dwc3/core.c | 11 + include/linux/amlogic/usb-v2.h | 60 +- 25 files changed, 1835 insertions(+), 90 deletions(-) create mode 100644 drivers/amlogic/usb/phy/phy-aml-new-otg.c create mode 100644 drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c diff --git a/MAINTAINERS b/MAINTAINERS index 78b1431fd659..c7f7f8da2bc5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13560,6 +13560,7 @@ F: drivers/amlogic/esm/* AMLOGIC DWC_OTG USB M: Yue Wang F: drivers/amlogic/usb/* +F: drivers/amlogic/usb/phy/phy-aml-new-otg.c F: drivers/usb/phy/phy-aml-new-usb.h F: drivers/usb/phy/phy-aml-new-usb.c F: drivers/usb/phy/phy-aml-new-usb2.c @@ -13568,6 +13569,7 @@ F: drivers/usb/phy/phy-aml-new-usb-v2.h F: drivers/usb/phy/phy-aml-new-usb-v2.c F: drivers/usb/phy/phy-aml-new-usb2-v2.c F: drivers/usb/phy/phy-aml-new-usb3-v2.c +F: drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c F: drivers/usb/phy/phy-aml-usb.h F: drivers/usb/phy/phy-aml-usb.c F: drivers/usb/phy/phy-aml-usb2.c diff --git a/arch/arm/boot/dts/amlogic/mesontm2.dtsi b/arch/arm/boot/dts/amlogic/mesontm2.dtsi index 8ff6e7d46338..01856ea49220 100644 --- a/arch/arm/boot/dts/amlogic/mesontm2.dtsi +++ b/arch/arm/boot/dts/amlogic/mesontm2.dtsi @@ -24,6 +24,7 @@ #include #include #include +#include #include "mesong12a-bifrost.dtsi" #include / { @@ -417,6 +418,7 @@ clock-src = "usb3.0"; clocks = <&clkc CLKID_USB_GENERAL>; clock-names = "dwc_general"; + snps,quirk-frame-length-adjustment = <0x20>; }; usb2_phy_v2: usb2phy@ffe09000 { @@ -444,22 +446,43 @@ }; usb3_phy_v2: usb3phy@ffe09080 { - compatible = "amlogic, amlogic-new-usb3-v2"; + compatible = "amlogic, amlogic-new-usb3-v3"; status = "disable"; - reg = <0xffe09080 0x20 - 0xffd01008 0x100>; - phy-reg = <0xff646000>; - phy-reg-size = <0x2000>; - usb2-phy-reg = <0xffe09000>; - usb2-phy-reg-size = <0x80>; - interrupts = <0 16 4>; + reg = <0xffe09080 0x20>; + phy0-reg = <0xff646000>; + phy0-reg-size = <0x2000>; + phy1-reg = <0xff65c000>; + phy1-reg-size = <0x2000>; + reset-reg = <0xffd01008>; + reset-reg-size = <0x100>; + clocks = <&clkc CLKID_PCIE0_GATE + &clkc CLKID_PCIE_PLL + &clkc CLKID_PCIE1_GATE>; + clock-names = "pcie0_gate", + "pcie_refpll", + "pcie1_gate"; pwr-ctl = <1>; - u3-ctrl-sleep-shift = <18>; - u3-hhi-mem-pd-shift = <26>; - u3-hhi-mem-pd-mask = <0xf>; - u3-ctrl-iso-shift = <18>; + u30-ctrl-sleep-shift = <18>; + u30-hhi-mem-pd-shift = <26>; + u30-hhi-mem-pd-mask = <0xf>; + u30-ctrl-iso-shift = <18>; + usb30-ctrl-a-rst-bit = <12>; + u31-ctrl-sleep-shift = <20>; + u31-hhi-mem-pd-shift = <4>; + u31-hhi-mem-pd-mask = <0xf>; + u31-ctrl-iso-shift = <20>; + usb31-ctrl-a-rst-bit = <28>; }; + usb_otg: usbotg@ffe09080 { + compatible = "amlogic, amlogic-new-otg"; + status = "disabled"; + usb2-phy-reg = <0xffe09000>; + usb2-phy-reg-size = <0x100>; + interrupts = <0 16 4>; + }; + + dwc2_a: dwc2_a@ff400000 { compatible = "amlogic, dwc2"; status = "disabled"; @@ -482,6 +505,7 @@ /** phy-interface: 0x0: amlogic-v1 phy, 0x1: synopsys phy **/ /** 0x2: amlogic-v2 phy **/ phy-interface = <0x2>; + phy-otg = <0x1>; clocks = <&clkc CLKID_USB_GENERAL &clkc CLKID_USB1_TO_DDR>; clock-names = "usb_general", @@ -1146,6 +1170,92 @@ pinctrl-0 = <&c_uart_pins>; }; + + pcie_A: pcieA@fc000000 { + compatible = "amlogic, amlogic-pcie-v2", "snps,dw-pcie"; + reg = <0xfc000000 0x400000 + 0xff648000 0x2000 + 0xfc400000 0x200000 + 0xff646000 0x2000 + 0xffd01080 0x10>; + reg-names = "elbi", "cfg", "config", "phy", "reset"; + interrupts = <0 221 0>; + #interrupt-cells = <1>; + bus-range = <0x0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 223 IRQ_TYPE_EDGE_RISING>; + device_type = "pci"; + ranges = <0x81000000 0 0 0xfc600000 0x0 0x100000 + /* downstream I/O */ + 0x82000000 0xfc700000 0x0 0xfc700000 0 0x1900000>; + /* non-prefetchable memory */ + num-lanes = <1>; + pcie-num = <1>; + + clocks = <&clkc CLKID_PCIE0_GATE + &clkc CLKID_PCIE1 + &clkc CLKID_PCIE0PHY>; + clock-names = "pcie_refpll", + "pcie", + "pcie_phy"; + /*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/ + gpio-type = <2>; + pcie-apb-rst-bit = <15>; + pcie-phy-rst-bit = <14>; + pcie-ctrl-a-rst-bit = <12>; + pwr-ctl = <1>; + pcie-ctrl-sleep-shift = <18>; + pcie-hhi-mem-pd-shift = <26>; + pcie-hhi-mem-pd-mask = <0xf>; + pcie-ctrl-iso-shift = <18>; + status = "disabled"; + }; + + pcie_B: pcieB@fc000000 { + compatible = "amlogic, amlogic-pcie-v2", "snps,dw-pcie"; + reg = <0xfA000000 0x400000 + 0xff65E000 0x2000 + 0xfA400000 0x200000 + 0xff65C000 0x2000 + 0xffd01080 0x10>; + reg-names = "elbi", "cfg", "config", "phy", + "reset"; + interrupts = <0 229 0>; + #interrupt-cells = <1>; + bus-range = <0x0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 231 IRQ_TYPE_EDGE_RISING>; + device_type = "pci"; + ranges = <0x81000000 0 0 0xfA600000 0x0 0x100000 + /* downstream I/O */ + 0x82000000 0xfA700000 0x0 0xfA700000 0 0x1900000>; + /* non-prefetchable memory */ + num-lanes = <1>; + pcie-num = <1>; + + clocks = <&clkc CLKID_PCIE1_GATE + &clkc CLKID_PCIE1 + &clkc CLKID_PCIE1PHY>; + clock-names = "pcie_refpll", + "pcie", + "pcie_phy"; + /*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/ + gpio-type = <2>; + pcie-apb-rst-bit = <30>; + pcie-phy-rst-bit = <29>; + pcie-ctrl-a-rst-bit = <28>; + pwr-ctl = <1>; + pcie-ctrl-sleep-shift = <20>; + pcie-hhi-mem-pd-shift = <4>; + pcie-hhi-mem-pd-mask = <0xf>; + pcie-ctrl-iso-shift = <20>; + status = "disabled"; + }; + sd_emmc_c: emmc@ffe07000 { status = "disabled"; compatible = "amlogic, meson-mmc-tm2"; diff --git a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab301.dts b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab301.dts index a5b02d1a24ba..3b78519ba49b 100644 --- a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab301.dts +++ b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab301.dts @@ -1839,7 +1839,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1849,6 +1855,16 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* ab311 only pcie a, no pcie b */ + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab311.dts b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab311.dts index 6a7775e8b44f..1a3d620da86c 100644 --- a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab311.dts +++ b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab311.dts @@ -1846,7 +1846,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1856,6 +1862,16 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* ab311 only pcie a, no pcie b */ + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab319.dts b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab319.dts index 390cff848e01..2a9ee68e9a82 100644 --- a/arch/arm/boot/dts/amlogic/tm2_t962e2_ab319.dts +++ b/arch/arm/boot/dts/amlogic/tm2_t962e2_ab319.dts @@ -1723,7 +1723,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1733,6 +1739,17 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* pcie b reset gpio is the oe pad, must be changed */ + reset-gpio = <&gpio GPIOH_22 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/amlogic/tm2_t962x3_ab309.dts b/arch/arm/boot/dts/amlogic/tm2_t962x3_ab309.dts index dfa9de0ea3c3..c4cdfba65bf8 100644 --- a/arch/arm/boot/dts/amlogic/tm2_t962x3_ab309.dts +++ b/arch/arm/boot/dts/amlogic/tm2_t962x3_ab309.dts @@ -1723,7 +1723,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1733,6 +1739,18 @@ controller-type = <1>; }; +&pcie_A { + /* pcie a reset gpio must be updated */ + reset-gpio = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* pcie b reset gpio must be updated */ + reset-gpio = <&gpio GPIOH_22 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/amlogic/mesontm2.dtsi b/arch/arm64/boot/dts/amlogic/mesontm2.dtsi index b4f593c3a19a..4736093d2a41 100644 --- a/arch/arm64/boot/dts/amlogic/mesontm2.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesontm2.dtsi @@ -24,6 +24,7 @@ #include #include #include +#include #include "mesong12a-bifrost.dtsi" #include / { @@ -398,6 +399,7 @@ clock-src = "usb3.0"; clocks = <&clkc CLKID_USB_GENERAL>; clock-names = "dwc_general"; + snps,quirk-frame-length-adjustment = <0x20>; }; usb2_phy_v2: usb2phy@ffe09000 { @@ -425,22 +427,43 @@ }; usb3_phy_v2: usb3phy@ffe09080 { - compatible = "amlogic, amlogic-new-usb3-v2"; + compatible = "amlogic, amlogic-new-usb3-v3"; status = "disable"; - reg = <0x0 0xffe09080 0x0 0x20 - 0x0 0xffd01008 0x0 0x100>; - phy-reg = <0xff646000>; - phy-reg-size = <0x2000>; - usb2-phy-reg = <0xffe09000>; - usb2-phy-reg-size = <0x80>; - interrupts = <0 16 4>; + reg = <0x0 0xffe09080 0x0 0x20>; + phy0-reg = <0xff646000>; + phy0-reg-size = <0x2000>; + phy1-reg = <0xff65c000>; + phy1-reg-size = <0x2000>; + reset-reg = <0xffd01008>; + reset-reg-size = <0x100>; + clocks = <&clkc CLKID_PCIE0_GATE + &clkc CLKID_PCIE_PLL + &clkc CLKID_PCIE1_GATE>; + clock-names = "pcie0_gate", + "pcie_refpll", + "pcie1_gate"; pwr-ctl = <1>; - u3-ctrl-sleep-shift = <18>; - u3-hhi-mem-pd-shift = <26>; - u3-hhi-mem-pd-mask = <0xf>; - u3-ctrl-iso-shift = <18>; + u30-ctrl-sleep-shift = <18>; + u30-hhi-mem-pd-shift = <26>; + u30-hhi-mem-pd-mask = <0xf>; + u30-ctrl-iso-shift = <18>; + usb30-ctrl-a-rst-bit = <12>; + u31-ctrl-sleep-shift = <20>; + u31-hhi-mem-pd-shift = <4>; + u31-hhi-mem-pd-mask = <0xf>; + u31-ctrl-iso-shift = <20>; + usb31-ctrl-a-rst-bit = <28>; }; + usb_otg: usbotg@ffe09080 { + compatible = "amlogic, amlogic-new-otg"; + status = "disabled"; + usb2-phy-reg = <0xffe09000>; + usb2-phy-reg-size = <0x100>; + interrupts = <0 16 4>; + }; + + dwc2_a: dwc2_a@ff400000 { compatible = "amlogic, dwc2"; status = "disabled"; @@ -463,6 +486,7 @@ /** phy-interface: 0x0: amlogic-v1 phy, 0x1: synopsys phy **/ /** 0x2: amlogic-v2 phy **/ phy-interface = <0x2>; + phy-otg = <0x1>; clocks = <&clkc CLKID_USB_GENERAL &clkc CLKID_USB1_TO_DDR>; clock-names = "usb_general", @@ -1126,6 +1150,92 @@ pinctrl-0 = <&c_uart_pins>; }; + + pcie_A: pcieA@fc000000 { + compatible = "amlogic, amlogic-pcie-v2", "snps,dw-pcie"; + reg = <0x0 0xfc000000 0x0 0x400000 + 0x0 0xff648000 0x0 0x2000 + 0x0 0xfc400000 0x0 0x200000 + 0x0 0xff646000 0x0 0x2000 + 0x0 0xffd01080 0x0 0x10>; + reg-names = "elbi", "cfg", "config", "phy", "reset"; + interrupts = <0 221 0>; + #interrupt-cells = <1>; + bus-range = <0x0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 223 IRQ_TYPE_EDGE_RISING>; + device_type = "pci"; + ranges = <0x81000000 0 0 0 0xfc600000 0x0 0x100000 + /* downstream I/O */ + 0x82000000 0 0xfc700000 0x0 0xfc700000 0 0x1900000>; + /* non-prefetchable memory */ + num-lanes = <1>; + pcie-num = <1>; + + clocks = <&clkc CLKID_PCIE0_GATE + &clkc CLKID_PCIE1 + &clkc CLKID_PCIE0PHY>; + clock-names = "pcie_refpll", + "pcie", + "pcie_phy"; + /*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/ + gpio-type = <2>; + pcie-apb-rst-bit = <15>; + pcie-phy-rst-bit = <14>; + pcie-ctrl-a-rst-bit = <12>; + pwr-ctl = <1>; + pcie-ctrl-sleep-shift = <18>; + pcie-hhi-mem-pd-shift = <26>; + pcie-hhi-mem-pd-mask = <0xf>; + pcie-ctrl-iso-shift = <18>; + status = "disabled"; + }; + + pcie_B: pcieB@fc000000 { + compatible = "amlogic, amlogic-pcie-v2", "snps,dw-pcie"; + reg = <0x0 0xfA000000 0x0 0x400000 + 0x0 0xff65E000 0x0 0x2000 + 0x0 0xfA400000 0x0 0x200000 + 0x0 0xff65C000 0x0 0x2000 + 0x0 0xffd01080 0x0 0x10>; + reg-names = "elbi", "cfg", "config", "phy", + "reset"; + interrupts = <0 229 0>; + #interrupt-cells = <1>; + bus-range = <0x0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 231 IRQ_TYPE_EDGE_RISING>; + device_type = "pci"; + ranges = <0x81000000 0 0 0 0xfA600000 0x0 0x100000 + /* downstream I/O */ + 0x82000000 0 0xfA700000 0x0 0xfA700000 0 0x1900000>; + /* non-prefetchable memory */ + num-lanes = <1>; + pcie-num = <1>; + + clocks = <&clkc CLKID_PCIE1_GATE + &clkc CLKID_PCIE1 + &clkc CLKID_PCIE1PHY>; + clock-names = "pcie_refpll", + "pcie", + "pcie_phy"; + /*reset-gpio-type 0:Shared pad(no reset)1:OD pad2:Normal pad*/ + gpio-type = <2>; + pcie-apb-rst-bit = <30>; + pcie-phy-rst-bit = <29>; + pcie-ctrl-a-rst-bit = <28>; + pwr-ctl = <1>; + pcie-ctrl-sleep-shift = <20>; + pcie-hhi-mem-pd-shift = <4>; + pcie-hhi-mem-pd-mask = <0xf>; + pcie-ctrl-iso-shift = <20>; + status = "disabled"; + }; + sd_emmc_c: emmc@ffe07000 { status = "disabled"; compatible = "amlogic, meson-mmc-tm2"; diff --git a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab301.dts b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab301.dts index 6b7dd05d8667..47f6b868a21a 100644 --- a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab301.dts +++ b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab301.dts @@ -1798,7 +1798,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1808,6 +1814,16 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* ab311 only pcie a, no pcie b */ + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311.dts b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311.dts index 21a2576d3264..8ca2b8c70f41 100644 --- a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311.dts +++ b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311.dts @@ -1806,7 +1806,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1816,6 +1822,16 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* ab311 only pcie a, no pcie b */ + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab319.dts b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab319.dts index ceab60c0fa63..9331d1af0a95 100644 --- a/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab319.dts +++ b/arch/arm64/boot/dts/amlogic/tm2_t962e2_ab319.dts @@ -1721,7 +1721,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1731,6 +1737,17 @@ controller-type = <1>; }; +&pcie_A { + reset-gpio = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* pcie b reset gpio is the oe pad, must be changed */ + reset-gpio = <&gpio GPIOH_22 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/amlogic/tm2_t962x3_ab309.dts b/arch/arm64/boot/dts/amlogic/tm2_t962x3_ab309.dts index 0093859facb0..294704419f60 100644 --- a/arch/arm64/boot/dts/amlogic/tm2_t962x3_ab309.dts +++ b/arch/arm64/boot/dts/amlogic/tm2_t962x3_ab309.dts @@ -1722,7 +1722,13 @@ &usb3_phy_v2 { status = "okay"; - portnum = <0>; + portnum = <2>; + portconfig-30 = <1>; + portconfig-31 = <1>; +}; + +&usb_otg { + status = "okay"; otg = <0>; }; @@ -1732,6 +1738,18 @@ controller-type = <1>; }; +&pcie_A { + /* pcie a reset gpio must be updated */ + reset-gpio = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + +&pcie_B { + /* pcie b reset gpio must be updated */ + reset-gpio = <&gpio GPIOH_22 GPIO_ACTIVE_HIGH>; + status = "disable"; +}; + &spicc0 { status = "okay"; pinctrl-names = "default"; diff --git a/drivers/amlogic/pci/pcie-amlogic-v2.c b/drivers/amlogic/pci/pcie-amlogic-v2.c index 479e445b7e76..2bb169ce0efa 100644 --- a/drivers/amlogic/pci/pcie-amlogic-v2.c +++ b/drivers/amlogic/pci/pcie-amlogic-v2.c @@ -57,7 +57,6 @@ struct amlogic_pcie { #define to_amlogic_pcie(x) container_of(x, struct amlogic_pcie, pp) struct pcie_phy_aml_regs pcie_aml_regs_v2; -struct pcie_phy *g_pcie_phy_v2; static void amlogic_elb_writel(struct amlogic_pcie *amlogic_pcie, u32 val, u32 reg) @@ -673,6 +672,7 @@ static int __init amlogic_add_pcie_port(struct amlogic_pcie *amlogic_pcie, dev_err(pp->dev, "link timeout, disable PCIE PLL\n"); clk_disable_unprepare(amlogic_pcie->bus_clk); clk_disable_unprepare(amlogic_pcie->clk); + clk_disable_unprepare(amlogic_pcie->phy_clk); dev_err(pp->dev, "power down pcie phy\n"); writel(0x1d, pcie_aml_regs_v2.pcie_phy_r[0]); amlogic_pcie->phy->power_state = 0; @@ -692,14 +692,14 @@ static void power_switch_to_pcie(struct pcie_phy *phy) udelay(100); val = readl((void __iomem *)(unsigned long)phy->reset_base); - writel((val & (~(0x1<<12))), + writel((val & (~(0x1<pcie_ctrl_a_rst_bit))), (void __iomem *)(unsigned long)phy->reset_base); udelay(100); power_ctrl_iso(1, phy->pcie_ctrl_iso_shift); val = readl((void __iomem *)(unsigned long)phy->reset_base); - writel((val | (0x1<<12)), + writel((val | (0x1<pcie_ctrl_a_rst_bit)), (void __iomem *)(unsigned long)phy->reset_base); udelay(100); } @@ -744,16 +744,6 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) pp->dev = dev; port_num++; amlogic_pcie->port_num = port_num; - if (amlogic_pcie->port_num == 1) { - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) { - port_num--; - return -ENOMEM; - } - g_pcie_phy_v2 = phy; - } - - amlogic_pcie->phy = g_pcie_phy_v2; ret = of_property_read_u32(np, "pcie-apb-rst-bit", &pcie_apb_rst_bit); if (ret) @@ -768,6 +758,15 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) if (ret) amlogic_pcie->rst_mod = 0; + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + port_num--; + return -ENOMEM; + } + phy->pcie_ctrl_a_rst_bit = pcie_ctrl_a_rst_bit; + + amlogic_pcie->phy = phy; + ret = of_property_read_u32(np, "pcie-num", &pcie_num); if (ret) amlogic_pcie->pcie_num = 0; @@ -828,8 +827,8 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) if (!amlogic_pcie->phy->reset_base) { reset_base = platform_get_resource_byname( pdev, IORESOURCE_MEM, "reset"); - amlogic_pcie->phy->reset_base = devm_ioremap_resource( - dev, reset_base); + amlogic_pcie->phy->reset_base = ioremap(reset_base->start, + resource_size(reset_base)); if (IS_ERR(amlogic_pcie->phy->reset_base)) { ret = PTR_ERR(amlogic_pcie->phy->reset_base); return ret; @@ -901,10 +900,8 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) if (!amlogic_pcie->phy->reset_state) { rate = clk_get_rate(amlogic_pcie->bus_clk); - if (rate != PCIE_PLL_RATE) { - ret = -ENODEV; - goto fail_pcie; - } + if (rate != PCIE_PLL_RATE) + dev_info(dev, "pcie ref pll is 0x%lx\n", rate); } /*RESET0[6,7] = 1*/ diff --git a/drivers/amlogic/pci/pcie-amlogic.h b/drivers/amlogic/pci/pcie-amlogic.h index 394a33a78663..38a7683988e2 100644 --- a/drivers/amlogic/pci/pcie-amlogic.h +++ b/drivers/amlogic/pci/pcie-amlogic.h @@ -166,6 +166,7 @@ struct pcie_phy { u32 pcie_hhi_mem_pd_mask; u32 pcie_ctrl_iso_shift; u32 pcie_hhi_mem_pd_shift; + u32 pcie_ctrl_a_rst_bit; }; diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h index a58ba8cb5d04..3c8ef428c127 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h @@ -1060,6 +1060,8 @@ struct dwc_otg_core_if { uint32_t phy_interface; + uint32_t phy_otg; + dwc_timer_t *device_connect_timer; uint64_t sof_counter; diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c index 3ce109bf851f..263ed2c1938f 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.c @@ -958,6 +958,7 @@ static int dwc_otg_driver_probe(struct platform_device *pdev) unsigned int p_ctrl_reg_addr = 0; unsigned int phy_reg_addr_size = 0; unsigned int phy_interface = 1; + unsigned int phy_otg = 0; const char *s_clock_name = NULL; const char *cpu_type = NULL; const char *gpio_name = NULL; @@ -1059,6 +1060,10 @@ static int dwc_otg_driver_probe(struct platform_device *pdev) if (prop) phy_interface = of_read_ulong(prop, 1); + prop = of_get_property(of_node, "phy-otg", NULL); + if (prop) + phy_otg = of_read_ulong(prop, 1); + if (is_meson_g12b_cpu()) { if (!is_meson_rev_a()) phy_interface = 2; @@ -1162,6 +1167,7 @@ static int dwc_otg_driver_probe(struct platform_device *pdev) dwc_otg_device->core_if->usb_peri_reg = (usb_peri_reg_t *)phy_reg_addr; dwc_otg_device->core_if->controller_type = controller_type; dwc_otg_device->core_if->phy_interface = phy_interface; + dwc_otg_device->core_if->phy_otg = phy_otg; /* * Attempt to ensure this device is really a DWC_otg Controller. * Read and verify the SNPSID register contents. The value should be @@ -1407,10 +1413,14 @@ static int dwc_otg_driver_probe(struct platform_device *pdev) #ifdef CONFIG_AMLOGIC_USB3PHY if (dwc_otg_device->core_if->controller_type == USB_OTG) { - if (dwc_otg_device->core_if->phy_interface == 1) + if (dwc_otg_device->core_if->phy_interface == 1) { aml_new_usb_init(); - else - aml_new_usb_v2_init(); + } else { + if (dwc_otg_device->core_if->phy_otg) + aml_new_otg_init(); + else + aml_new_usb_v2_init(); + } } #endif diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h index 897f51545164..69272923e5c7 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h @@ -47,6 +47,7 @@ #ifdef CONFIG_AMLOGIC_USB3PHY extern void aml_new_usb_init(void); extern void aml_new_usb_v2_init(void); +extern void aml_new_otg_init(void); #endif /* Type declarations */ diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h index 38a153f4c8b7..8fbe4a4401c2 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h @@ -275,6 +275,7 @@ void dwc_otg_iso_buffer_done(dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep, extern void do_test_mode(void *data); extern int aml_new_usb_get_mode(void); +extern int aml_new_otg_get_mode(void); #ifdef CONFIG_AMLOGIC_USB3PHY extern void set_usb_phy_device_tuning(int port, int default_val); #endif diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c index 3382a6a1260d..cd503c67b9cb 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c @@ -1067,14 +1067,30 @@ int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *pcd) if (GET_CORE_IF(pcd)->phy_interface != 1) { if (GET_CORE_IF(pcd)->controller_type == USB_OTG) { speed = get_device_speed(GET_CORE_IF(pcd)); - if ((speed != USB_SPEED_HIGH) && - (aml_new_usb_get_mode() != 1)) { - gintsts.d32 = 0; - gintsts.b.enumdone = 1; - DWC_WRITE_REG32(&GET_CORE_IF(pcd)-> - core_global_regs->gintsts, gintsts.d32); - DWC_DEBUGPL(DBG_PCD, "false speed emun\n"); - return 1; + if (GET_CORE_IF(pcd)->phy_otg == 1) { + if ((speed != USB_SPEED_HIGH) && + (aml_new_otg_get_mode() != 1)) { + gintsts.d32 = 0; + gintsts.b.enumdone = 1; + DWC_WRITE_REG32(&GET_CORE_IF(pcd)-> + core_global_regs->gintsts, + gintsts.d32); + DWC_DEBUGPL(DBG_PCD, + "false speed emun\n"); + return 1; + } + } else { + if ((speed != USB_SPEED_HIGH) && + (aml_new_usb_get_mode() != 1)) { + gintsts.d32 = 0; + gintsts.b.enumdone = 1; + DWC_WRITE_REG32(&GET_CORE_IF(pcd)-> + core_global_regs->gintsts, + gintsts.d32); + DWC_DEBUGPL(DBG_PCD, + "false speed emun\n"); + return 1; + } } } diff --git a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c index 6ba3f1676201..2ad6baf5ec30 100644 --- a/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c +++ b/drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_linux.c @@ -1304,10 +1304,14 @@ int pcd_init(struct platform_device *pdev) } #ifdef CONFIG_AMLOGIC_USB3PHY - if (otg_dev->core_if->phy_interface == 1) + if (otg_dev->core_if->phy_interface == 1) { aml_new_usb_register_notifier(&otg_dev->nb); - else - aml_new_usb_v2_register_notifier(&otg_dev->nb); + } else { + if (otg_dev->core_if->phy_otg == 1) + aml_new_otg_register_notifier(&otg_dev->nb); + else + aml_new_usb_v2_register_notifier(&otg_dev->nb); + } otg_dev->nb.notifier_call = dwc_usb_change; #endif @@ -1375,10 +1379,14 @@ void pcd_remove(struct platform_device *pdev) free_wrapper(gadget_wrapper); dwc_otg_pcd_remove(otg_dev->pcd); #ifdef CONFIG_AMLOGIC_USB3PHY - if (otg_dev->core_if->phy_interface == 1) + if (otg_dev->core_if->phy_interface == 1) { aml_new_usb_unregister_notifier(&otg_dev->nb); - else - aml_new_usb_v2_unregister_notifier(&otg_dev->nb); + } else { + if (otg_dev->core_if->phy_otg == 1) + aml_new_otg_unregister_notifier(&otg_dev->nb); + else + aml_new_usb_v2_unregister_notifier(&otg_dev->nb); + } #endif otg_dev->pcd = 0; } diff --git a/drivers/amlogic/usb/phy/Makefile b/drivers/amlogic/usb/phy/Makefile index 22433e19fc7b..47a6d6df259e 100644 --- a/drivers/amlogic/usb/phy/Makefile +++ b/drivers/amlogic/usb/phy/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-usb3.o obj-$(CONFIG_AMLOGIC_USBPHY) += phy-aml-new-usb-v2.o obj-$(CONFIG_AMLOGIC_USB2PHY) += phy-aml-new-usb2-v2.o obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-usb3-v2.o +obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-usb3-v3.o +obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-otg.o diff --git a/drivers/amlogic/usb/phy/phy-aml-new-otg.c b/drivers/amlogic/usb/phy/phy-aml-new-otg.c new file mode 100644 index 000000000000..d4d4f1868998 --- /dev/null +++ b/drivers/amlogic/usb/phy/phy-aml-new-otg.c @@ -0,0 +1,388 @@ +/* + * drivers/amlogic/usb/phy/phy-aml-new-otg.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "phy-aml-new-usb-v2.h" + +#define HOST_MODE 0 +#define DEVICE_MODE 1 + +struct usb_aml_regs_v2 usb_otg_aml_regs; +struct amlogic_otg *g_otg; + +struct amlogic_otg { + struct device *dev; + void __iomem *phy3_cfg; + void __iomem *phy3_cfg_r1; + void __iomem *phy3_cfg_r2; + void __iomem *phy3_cfg_r4; + void __iomem *phy3_cfg_r5; + void __iomem *usb2_phy_cfg; + /* Set VBus Power though GPIO */ + int vbus_power_pin; + int vbus_power_pin_work_mask; + struct delayed_work work; + struct gpio_desc *usb_gpio_desc; +}; + +static void set_mode(unsigned long reg_addr, int mode); +BLOCKING_NOTIFIER_HEAD(aml_new_otg_notifier_list); + +int aml_new_otg_register_notifier(struct notifier_block *nb) +{ + int ret; + + ret = blocking_notifier_chain_register + (&aml_new_otg_notifier_list, nb); + + return ret; +} +EXPORT_SYMBOL(aml_new_otg_register_notifier); + +int aml_new_otg_unregister_notifier(struct notifier_block *nb) +{ + int ret; + + ret = blocking_notifier_chain_unregister + (&aml_new_otg_notifier_list, nb); + + return ret; +} +EXPORT_SYMBOL(aml_new_otg_unregister_notifier); + +static void aml_new_usb_notifier_call(unsigned long is_device_on) +{ + blocking_notifier_call_chain + (&aml_new_otg_notifier_list, is_device_on, NULL); +} + +static void set_usb_vbus_power + (struct gpio_desc *usb_gd, int pin, char is_power_on) +{ + if (is_power_on) + /*set vbus on by gpio*/ + gpiod_direction_output(usb_gd, 1); + else + /*set vbus off by gpio first*/ + gpiod_direction_output(usb_gd, 0); +} + +static void amlogic_new_set_vbus_power + (struct amlogic_otg *phy, char is_power_on) +{ + if (phy->vbus_power_pin != -1) + set_usb_vbus_power(phy->usb_gpio_desc, + phy->vbus_power_pin, is_power_on); +} + + + +void aml_new_otg_init(void) +{ + union usb_r5_v2 r5 = {.d32 = 0}; + unsigned long reg_addr; + + if (!g_otg) + return; + + reg_addr = (unsigned long)g_otg->usb2_phy_cfg; + + r5.d32 = readl(usb_otg_aml_regs.usb_r_v2[5]); + if (r5.b.iddig_curr == 0) { + amlogic_new_set_vbus_power(g_otg, 1); + aml_new_usb_notifier_call(0); + set_mode(reg_addr, HOST_MODE); + } +} +EXPORT_SYMBOL(aml_new_otg_init); + +int aml_new_otg_get_mode(void) +{ + union usb_r5_v2 r5 = {.d32 = 0}; + + r5.d32 = readl(usb_otg_aml_regs.usb_r_v2[5]); + if (r5.b.iddig_curr == 0) + return 0; + else + return 1; +} +EXPORT_SYMBOL(aml_new_otg_get_mode); + + +static int amlogic_new_otg_init(struct amlogic_otg *phy) +{ + union usb_r1_v2 r1 = {.d32 = 0}; + union usb_r5_v2 r5 = {.d32 = 0}; + int i = 0; + + for (i = 0; i < 6; i++) { + usb_otg_aml_regs.usb_r_v2[i] = (void __iomem *) + ((unsigned long)phy->usb2_phy_cfg + 0x80 + 4*i); + } + + r1.d32 = readl(usb_otg_aml_regs.usb_r_v2[1]); + r1.b.u3h_fladj_30mhz_reg = 0x20; + writel(r1.d32, usb_otg_aml_regs.usb_r_v2[1]); + + r5.d32 = readl(usb_otg_aml_regs.usb_r_v2[5]); + r5.b.iddig_en0 = 1; + r5.b.iddig_en1 = 1; + r5.b.iddig_th = 255; + writel(r5.d32, usb_otg_aml_regs.usb_r_v2[5]); + + return 0; +} + +static void set_mode(unsigned long reg_addr, int mode) +{ + struct u2p_aml_regs_v2 u2p_aml_regs; + struct usb_aml_regs_v2 usb_gxl_aml_regs; + union u2p_r0_v2 reg0; + union usb_r0_v2 r0 = {.d32 = 0}; + union usb_r4_v2 r4 = {.d32 = 0}; + + u2p_aml_regs.u2p_r_v2[0] = (void __iomem *) + ((unsigned long)reg_addr + PHY_REGISTER_SIZE); + + usb_gxl_aml_regs.usb_r_v2[0] = (void __iomem *) + ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE + + 4*0); + usb_gxl_aml_regs.usb_r_v2[1] = (void __iomem *) + ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE + + 4*1); + usb_gxl_aml_regs.usb_r_v2[4] = (void __iomem *) + ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE + + 4*4); + + r0.d32 = readl(usb_gxl_aml_regs.usb_r_v2[0]); + if (mode == DEVICE_MODE) { + r0.b.u2d_act = 1; + r0.b.u2d_ss_scaledown_mode = 0; + } else + r0.b.u2d_act = 0; + writel(r0.d32, usb_gxl_aml_regs.usb_r_v2[0]); + + r4.d32 = readl(usb_gxl_aml_regs.usb_r_v2[4]); + if (mode == DEVICE_MODE) + r4.b.p21_SLEEPM0 = 0x1; + else + r4.b.p21_SLEEPM0 = 0x0; + writel(r4.d32, usb_gxl_aml_regs.usb_r_v2[4]); + + reg0.d32 = readl(u2p_aml_regs.u2p_r_v2[0]); + if (mode == DEVICE_MODE) { + reg0.b.host_device = 0; + reg0.b.POR = 0; + } else { + reg0.b.host_device = 1; + reg0.b.POR = 0; + } + writel(reg0.d32, u2p_aml_regs.u2p_r_v2[0]); + + udelay(500); +} + +static void amlogic_gxl_work(struct work_struct *work) +{ + struct amlogic_otg *phy = + container_of(work, struct amlogic_otg, work.work); + union usb_r5_v2 r5 = {.d32 = 0}; + unsigned long reg_addr = ((unsigned long)phy->usb2_phy_cfg); + + r5.d32 = readl(usb_otg_aml_regs.usb_r_v2[5]); + if (r5.b.iddig_curr == 0) { + amlogic_new_set_vbus_power(phy, 1); + aml_new_usb_notifier_call(0); + set_mode(reg_addr, HOST_MODE); + } else { + set_mode(reg_addr, DEVICE_MODE); + aml_new_usb_notifier_call(1); + amlogic_new_set_vbus_power(phy, 0); + } + r5.b.usb_iddig_irq = 0; + writel(r5.d32, usb_otg_aml_regs.usb_r_v2[5]); +} + +static irqreturn_t amlogic_botg_detect_irq(int irq, void *dev) +{ + struct amlogic_otg *phy = (struct amlogic_otg *)dev; + union usb_r5_v2 r5 = {.d32 = 0}; + + r5.d32 = readl(usb_otg_aml_regs.usb_r_v2[5]); + r5.b.usb_iddig_irq = 0; + writel(r5.d32, usb_otg_aml_regs.usb_r_v2[5]); + + schedule_delayed_work(&phy->work, msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +static int amlogic_new_otg_probe(struct platform_device *pdev) +{ + struct amlogic_otg *phy; + struct device *dev = &pdev->dev; + void __iomem *usb2_phy_base; + unsigned int usb2_phy_mem; + unsigned int usb2_phy_mem_size = 0; + const char *gpio_name = NULL; + struct gpio_desc *usb_gd = NULL; + const void *prop; + int irq; + int retval; + int gpio_vbus_power_pin = -1; + int otg = 0; + + gpio_name = of_get_property(dev->of_node, "gpio-vbus-power", NULL); + if (gpio_name) { + gpio_vbus_power_pin = 1; + usb_gd = gpiod_get_index(&pdev->dev, + NULL, 0, GPIOD_OUT_LOW); + if (IS_ERR(usb_gd)) + return -1; + } + + prop = of_get_property(dev->of_node, "otg", NULL); + if (prop) + otg = of_read_ulong(prop, 1); + + retval = of_property_read_u32 + (dev->of_node, "usb2-phy-reg", &usb2_phy_mem); + if (retval < 0) + return -EINVAL; + + retval = of_property_read_u32 + (dev->of_node, "usb2-phy-reg-size", &usb2_phy_mem_size); + if (retval < 0) + return -EINVAL; + + usb2_phy_base = devm_ioremap_nocache + (&(pdev->dev), (resource_size_t)usb2_phy_mem, + (unsigned long)usb2_phy_mem_size); + if (!usb2_phy_base) + return -ENOMEM; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + if (otg) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + retval = request_irq(irq, amlogic_botg_detect_irq, + IRQF_SHARED | IRQ_LEVEL, + "amlogic_botg_detect", phy); + + if (retval) { + dev_err(&pdev->dev, "request of irq%d failed\n", irq); + retval = -EBUSY; + return retval; + } + } + + dev_info(&pdev->dev, "phy_mem:0x%lx, iomap phy_base:0x%lx\n", + (unsigned long)usb2_phy_mem, + (unsigned long)usb2_phy_base); + + phy->dev = dev; + phy->usb2_phy_cfg = usb2_phy_base; + phy->vbus_power_pin = gpio_vbus_power_pin; + phy->usb_gpio_desc = usb_gd; + + INIT_DELAYED_WORK(&phy->work, amlogic_gxl_work); + + platform_set_drvdata(pdev, phy); + + pm_runtime_enable(phy->dev); + g_otg = phy; + + amlogic_new_otg_init(phy); + + return 0; +} + +static int amlogic_new_otg_remove(struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int amlogic_new_otg_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int amlogic_new_otg_runtime_resume(struct device *dev) +{ + u32 ret = 0; + + return ret; +} + +static const struct dev_pm_ops amlogic_new_otg_pm_ops = { + SET_RUNTIME_PM_OPS(amlogic_new_otg_runtime_suspend, + amlogic_new_otg_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&amlogic_new_otg_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id amlogic_new_otg_id_table[] = { + { .compatible = "amlogic, amlogic-new-otg" }, + {} +}; +MODULE_DEVICE_TABLE(of, amlogic_new_otg_id_table); +#endif + +static struct platform_driver amlogic_new_otg_driver = { + .probe = amlogic_new_otg_probe, + .remove = amlogic_new_otg_remove, + .driver = { + .name = "amlogic-new-otg", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(amlogic_new_otg_id_table), + }, +}; + +module_platform_driver(amlogic_new_otg_driver); + +MODULE_ALIAS("platform: amlogic_usb3_v2"); +MODULE_AUTHOR("Amlogic Inc."); +MODULE_DESCRIPTION("amlogic USB3 v2 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c index 3c97500bb819..ef22d475f7df 100644 --- a/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c @@ -146,6 +146,7 @@ static void cr_bus_addr(unsigned int addr) phy_r4.b.phy_cr_data_in = addr; writel(phy_r4.d32, g_phy_v2->phy3_cfg_r4); + phy_r4.b.phy_cr_cap_addr = 0; writel(phy_r4.d32, g_phy_v2->phy3_cfg_r4); phy_r4.b.phy_cr_cap_addr = 1; @@ -312,7 +313,6 @@ static int amlogic_new_usb3_init(struct usb_phy *x) p3_r2.b.phy_tx_vboost_lvl = 0x4; writel(p3_r2.d32, phy->phy3_cfg_r2); udelay(2); - /* * WORKAROUND: There is SSPHY suspend bug due to * which USB enumerates @@ -487,8 +487,9 @@ static void power_switch_to_pcie(struct amlogic_usb_v2 *phy) { u32 val; - power_ctrl_sleep(1, phy->u3_ctrl_sleep_shift); - power_ctrl_mempd0(1, phy->u3_hhi_mem_pd_mask, phy->u3_hhi_mem_pd_shift); + power_ctrl_sleep(1, phy->u30_ctrl_sleep_shift); + power_ctrl_mempd0(1, phy->u30_hhi_mem_pd_mask, + phy->u30_hhi_mem_pd_shift); udelay(100); val = readl((void __iomem *) @@ -497,7 +498,7 @@ static void power_switch_to_pcie(struct amlogic_usb_v2 *phy) ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); udelay(100); - power_ctrl_iso(1, phy->u3_ctrl_iso_shift); + power_ctrl_iso(1, phy->u30_ctrl_iso_shift); val = readl((void __iomem *) ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); @@ -695,10 +696,10 @@ static int amlogic_new_usb3_v2_probe(struct platform_device *pdev) /* set the phy from pcie to usb3 */ if (phy->portnum > 0) { if (phy->pwr_ctl) { - phy->u3_ctrl_sleep_shift = u3_ctrl_sleep_shift; - phy->u3_hhi_mem_pd_shift = u3_hhi_mem_pd_shift; - phy->u3_hhi_mem_pd_mask = u3_hhi_mem_pd_mask; - phy->u3_ctrl_iso_shift = u3_ctrl_iso_shift; + phy->u30_ctrl_sleep_shift = u3_ctrl_sleep_shift; + phy->u30_hhi_mem_pd_shift = u3_hhi_mem_pd_shift; + phy->u30_hhi_mem_pd_mask = u3_hhi_mem_pd_mask; + phy->u30_ctrl_iso_shift = u3_ctrl_iso_shift; phy->reset_regs = reset_base; power_switch_to_pcie(phy); } @@ -718,7 +719,6 @@ static int amlogic_new_usb3_v2_probe(struct platform_device *pdev) ret = PTR_ERR(phy->clk); return ret; } - phy->phy.flags = AML_USB3_PHY_ENABLE; } diff --git a/drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c new file mode 100644 index 000000000000..86b4c9fffea5 --- /dev/null +++ b/drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c @@ -0,0 +1,918 @@ +/* + * drivers/amlogic/usb/phy/phy-aml-new-usb3-v3.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "phy-aml-new-usb-v2.h" + +#define HOST_MODE 0 +#define DEVICE_MODE 1 + +struct usb_aml_regs_v2 usb_new_aml_regs_v3; + +static int amlogic_new_usb3_suspend(struct usb_phy *x, int suspend) +{ + return 0; +} + +static void amlogic_new_usb3phy_shutdown(struct usb_phy *x) +{ + struct amlogic_usb_v2 *phy = phy_to_amlusb(x); + + if (phy->phy.flags == AML_USB3_PHY_ENABLE) { + clk_disable_unprepare(phy->clk); + clk_disable_unprepare(phy->gate1_clk); + clk_disable_unprepare(phy->gate0_clk); + } + + phy->suspend_flag = 1; +} + +static void cr_bus_addr(struct amlogic_usb_v2 *phy_v3, unsigned int addr) +{ + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + phy_r4.b.phy_cr_data_in = addr; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + phy_r4.b.phy_cr_cap_addr = 1; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); +} + +static int cr_bus_read(struct amlogic_usb_v2 *phy_v3, unsigned int addr) +{ + int data; + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + cr_bus_addr(phy_v3, addr); + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + phy_r4.b.phy_cr_read = 1; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + data = phy_r5.b.phy_cr_data_out; + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); + + return data; +} + +static void cr_bus_write(struct amlogic_usb_v2 *phy_v3, + unsigned int addr, unsigned int data) +{ + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + cr_bus_addr(phy_v3, addr); + + phy_r4.b.phy_cr_data_in = data; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + phy_r4.b.phy_cr_cap_data = 1; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + phy_r4.b.phy_cr_write = 1; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, phy_v3->phy3_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy3_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); +} + +static void cr_bus_addr_31(struct amlogic_usb_v2 *phy_v3, unsigned int addr) +{ + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + phy_r4.b.phy_cr_data_in = addr; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + phy_r4.b.phy_cr_cap_addr = 1; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); +} + +static int cr_bus_read_31(struct amlogic_usb_v2 *phy_v3, unsigned int addr) +{ + int data; + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + cr_bus_addr_31(phy_v3, addr); + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + phy_r4.b.phy_cr_read = 1; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + data = phy_r5.b.phy_cr_data_out; + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); + + return data; +} + +static void cr_bus_write_31(struct amlogic_usb_v2 *phy_v3, + unsigned int addr, unsigned int data) +{ + union phy3_r4 phy_r4 = {.d32 = 0}; + union phy3_r5 phy_r5 = {.d32 = 0}; + unsigned long timeout_jiffies; + + cr_bus_addr(phy_v3, addr); + + phy_r4.b.phy_cr_data_in = data; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + phy_r4.b.phy_cr_cap_data = 1; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + phy_r4.b.phy_cr_write = 1; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 0 && + time_is_after_jiffies(timeout_jiffies)); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, phy_v3->phy31_cfg_r4); + timeout_jiffies = jiffies + + msecs_to_jiffies(1000); + do { + phy_r5.d32 = readl(phy_v3->phy31_cfg_r5); + } while (phy_r5.b.phy_cr_ack == 1 && + time_is_after_jiffies(timeout_jiffies)); +} + +static void usb3_phy_cr_config_30(struct amlogic_usb_v2 *phy) +{ + u32 data = 0; + + /* + * WORKAROUND: There is SSPHY suspend bug due to + * which USB enumerates + * in HS mode instead of SS mode. Workaround it by asserting + * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus + * mode + */ + data = cr_bus_read(phy, 0x102d); + data |= (1 << 7); + cr_bus_write(phy, 0x102D, data); + + data = cr_bus_read(phy, 0x1010); + data &= ~0xff0; + data |= 0x20; + cr_bus_write(phy, 0x1010, data); + + /* + * Fix RX Equalization setting as follows + * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 + * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 + * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 + * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 + */ + data = cr_bus_read(phy, 0x1006); + data &= ~(1 << 6); + data |= (1 << 7); + data &= ~(0x7 << 8); + data |= (0x3 << 8); + data |= (0x1 << 11); + cr_bus_write(phy, 0x1006, data); + + /* + * S et EQ and TX launch amplitudes as follows + * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 + * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 + * LANE0.TX_OVRD_DRV_LO.EN set to 1. + */ + data = cr_bus_read(phy, 0x1002); + data &= ~0x3f80; + data |= (0x16 << 7); + data &= ~0x7f; + data |= (0x7f | (1 << 14)); + cr_bus_write(phy, 0x1002, data); + + /* + * MPLL_LOOP_CTL.PROP_CNTRL + */ + data = cr_bus_read(phy, 0x30); + data &= ~(0xf << 4); + data |= (0x8 << 4); + cr_bus_write(phy, 0x30, data); + udelay(2); +} + + +static void usb3_phy_cr_config_31(struct amlogic_usb_v2 *phy) +{ + u32 data = 0; + + /* + * WORKAROUND: There is SSPHY suspend bug due to + * which USB enumerates + * in HS mode instead of SS mode. Workaround it by asserting + * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus + * mode + */ + data = cr_bus_read_31(phy, 0x102d); + data |= (1 << 7); + cr_bus_write_31(phy, 0x102D, data); + + data = cr_bus_read_31(phy, 0x1010); + data &= ~0xff0; + data |= 0x20; + cr_bus_write_31(phy, 0x1010, data); + + /* + * Fix RX Equalization setting as follows + * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 + * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 + * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 + * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 + */ + data = cr_bus_read_31(phy, 0x1006); + data &= ~(1 << 6); + data |= (1 << 7); + data &= ~(0x7 << 8); + data |= (0x3 << 8); + data |= (0x1 << 11); + cr_bus_write_31(phy, 0x1006, data); + + /* + * S et EQ and TX launch amplitudes as follows + * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 + * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 + * LANE0.TX_OVRD_DRV_LO.EN set to 1. + */ + data = cr_bus_read_31(phy, 0x1002); + data &= ~0x3f80; + data |= (0x16 << 7); + data &= ~0x7f; + data |= (0x7f | (1 << 14)); + cr_bus_write_31(phy, 0x1002, data); + + /* + * MPLL_LOOP_CTL.PROP_CNTRL + */ + data = cr_bus_read_31(phy, 0x30); + data &= ~(0xf << 4); + data |= (0x8 << 4); + cr_bus_write_31(phy, 0x30, data); + udelay(2); +} + + +static int amlogic_new_usb3_init_v3(struct usb_phy *x) +{ + struct amlogic_usb_v2 *phy = phy_to_amlusb(x); + union usb_r1_v2 r1 = {.d32 = 0}; + union usb_r2_v2 r2 = {.d32 = 0}; + union usb_r3_v2 r3 = {.d32 = 0}; + union usb_r7_v2 r7 = {.d32 = 0}; + union phy3_r2 p3_r2 = {.d32 = 0}; + union phy3_r1 p3_r1 = {.d32 = 0}; + int i = 0; + + if (phy->suspend_flag) { + if (phy->phy.flags == AML_USB3_PHY_ENABLE) { + clk_prepare_enable(phy->gate0_clk); + clk_prepare_enable(phy->gate1_clk); + clk_prepare_enable(phy->clk); + } + phy->suspend_flag = 0; + return 0; + } + + if (phy->phy.flags != AML_USB3_PHY_ENABLE) + return 0; + + for (i = 0; i < 8; i++) { + usb_new_aml_regs_v3.usb_r_v2[i] = (void __iomem *) + ((unsigned long)phy->regs + 4*i); + } + + /* config usb30 phy */ + r3.d32 = readl(usb_new_aml_regs_v3.usb_r_v2[3]); + r3.b.p30_ssc_en = 1; + r3.b.p30_ssc_range = 2; + r3.b.p30_ref_ssp_en = 1; + writel(r3.d32, usb_new_aml_regs_v3.usb_r_v2[3]); + udelay(2); + r2.d32 = readl(usb_new_aml_regs_v3.usb_r_v2[2]); + r2.b.p30_pcs_tx_deemph_3p5db = 0x15; + r2.b.p30_pcs_tx_deemph_6db = 0x20; + writel(r2.d32, usb_new_aml_regs_v3.usb_r_v2[2]); + udelay(2); + r1.d32 = readl(usb_new_aml_regs_v3.usb_r_v2[1]); + r1.b.u3h_host_port_power_control_present = 1; + r1.b.u3h_fladj_30mhz_reg = 0x20; + r1.b.p30_pcs_tx_swing_full = 127; + r1.b.u3h_host_u3_port_disable = 0; + writel(r1.d32, usb_new_aml_regs_v3.usb_r_v2[1]); + udelay(2); + p3_r2.d32 = readl(phy->phy3_cfg_r2); + p3_r2.b.phy_tx_vboost_lvl = 0x4; + writel(p3_r2.d32, phy->phy3_cfg_r2); + udelay(2); + + usb3_phy_cr_config_30(phy); + + /* + * LOS_BIAS to 0x5 + * LOS_LEVEL to 0x9 + */ + p3_r1.d32 = readl(phy->phy3_cfg_r1); + p3_r1.b.phy_los_bias = 0x4; + p3_r1.b.phy_los_level = 0x9; + writel(p3_r1.d32, phy->phy3_cfg_r1); + + /* config usb31 phy */ + r7.d32 = readl(usb_new_aml_regs_v3.usb_r_v2[7]); + r7.b.p31_ssc_en = 1; + r7.b.p31_ssc_range = 2; + r7.b.p31_ref_ssp_en = 1; + r7.b.p31_pcs_tx_deemph_6db = 0x20; + r7.b.p31_pcs_tx_swing_full = 127; + writel(r7.d32, usb_new_aml_regs_v3.usb_r_v2[7]); + + udelay(2); + p3_r2.d32 = readl(phy->phy31_cfg_r2); + p3_r2.b.phy_tx_vboost_lvl = 0x4; + writel(p3_r2.d32, phy->phy31_cfg_r2); + udelay(2); + + usb3_phy_cr_config_31(phy); + + /* + * LOS_BIAS to 0x5 + * LOS_LEVEL to 0x9 + */ + p3_r1.d32 = readl(phy->phy31_cfg_r1); + p3_r1.b.phy_los_bias = 0x4; + p3_r1.b.phy_los_level = 0x9; + writel(p3_r1.d32, phy->phy31_cfg_r1); + + return 0; +} + +static void power_switch_to_pcie(struct amlogic_usb_v2 *phy) +{ + u32 val; + + power_ctrl_sleep(1, phy->u30_ctrl_sleep_shift); + power_ctrl_mempd0(1, phy->u30_hhi_mem_pd_mask, + phy->u30_hhi_mem_pd_shift); + udelay(100); + + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + writel((val & (~(0x1 << phy->usb30_ctrl_rst_bit))), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + udelay(100); + + power_ctrl_iso(1, phy->u30_ctrl_iso_shift); + + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + writel((val | (0x1 << phy->usb30_ctrl_rst_bit)), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + udelay(100); + + power_ctrl_sleep(1, phy->u31_ctrl_sleep_shift); + power_ctrl_mempd0(1, phy->u31_hhi_mem_pd_mask, + phy->u31_hhi_mem_pd_shift); + udelay(100); + + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + writel((val & (~(0x1 << phy->usb31_ctrl_rst_bit))), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + udelay(100); + + power_ctrl_iso(1, phy->u31_ctrl_iso_shift); + + val = readl((void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + writel((val | (0x1 << phy->usb31_ctrl_rst_bit)), (void __iomem *) + ((unsigned long)phy->reset_regs + (0x20 * 4 - 0x8))); + + udelay(100); +} + +static int amlogic_new_usb3_v3_probe(struct platform_device *pdev) +{ + struct amlogic_usb_v2 *phy; + struct device *dev = &pdev->dev; + struct resource *phy_mem; + void __iomem *phy_base; + void __iomem *phy3_base; + void __iomem *phy31_base; + void __iomem *reset_base = NULL; + unsigned int phy3_mem; + unsigned int phy3_mem_size = 0; + unsigned int phy31_mem; + unsigned int phy31_mem_size = 0; + unsigned int reset_mem; + unsigned int reset_mem_size = 0; + + const void *prop; + int portnum = 0; + int retval; + int ret; + u32 pwr_ctl = 0; + u32 u30_ctrl_sleep_shift = 0; + u32 u30_hhi_mem_pd_shift = 0; + u32 u30_hhi_mem_pd_mask = 0; + u32 u30_ctrl_iso_shift = 0; + u32 usb30_ctrl_rst_bit = 0; + u32 u31_ctrl_sleep_shift = 0; + u32 u31_hhi_mem_pd_shift = 0; + u32 u31_hhi_mem_pd_mask = 0; + u32 u31_ctrl_iso_shift = 0; + u32 usb31_ctrl_rst_bit = 0; + u32 portconfig_30 = 0; + u32 portconfig_31 = 0; + unsigned long rate; +#define PCIE_PLL_RATE 100000000 + + prop = of_get_property(dev->of_node, "portnum", NULL); + if (prop) + portnum = of_read_ulong(prop, 1); + + if (!portnum) + dev_err(&pdev->dev, "This phy has no usb port\n"); + + phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy_base = devm_ioremap_resource(dev, phy_mem); + if (IS_ERR(phy_base)) + return PTR_ERR(phy_base); + + retval = of_property_read_u32(dev->of_node, "phy0-reg", &phy3_mem); + if (retval < 0) + return -EINVAL; + + retval = of_property_read_u32 + (dev->of_node, "phy0-reg-size", &phy3_mem_size); + if (retval < 0) + return -EINVAL; + + phy3_base = devm_ioremap_nocache + (&(pdev->dev), (resource_size_t)phy3_mem, + (unsigned long)phy3_mem_size); + if (!phy3_base) + return -ENOMEM; + + retval = of_property_read_u32(dev->of_node, "phy1-reg", &phy31_mem); + if (retval < 0) + return -EINVAL; + + retval = of_property_read_u32 + (dev->of_node, "phy1-reg-size", + &phy31_mem_size); + if (retval < 0) + return -EINVAL; + + phy31_base = devm_ioremap_nocache + (&(pdev->dev), (resource_size_t)phy31_mem, + (unsigned long)phy31_mem_size); + if (!phy31_base) + return -ENOMEM; + + prop = of_get_property(dev->of_node, "pwr-ctl", NULL); + if (prop) + pwr_ctl = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + if (pwr_ctl) { + retval = of_property_read_u32(dev->of_node, + "reset-reg", &reset_mem); + if (retval < 0) + return -EINVAL; + + retval = of_property_read_u32 + (dev->of_node, "reset-reg-size", + &reset_mem_size); + if (retval < 0) + return -EINVAL; + + reset_base = devm_ioremap_nocache + (&(pdev->dev), (resource_size_t)reset_mem, + (unsigned long)reset_mem_size); + if (!reset_base) + return -ENOMEM; + + prop = of_get_property(dev->of_node, + "u30-ctrl-sleep-shift", NULL); + if (prop) + u30_ctrl_sleep_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u30-hhi-mem-pd-shift", NULL); + if (prop) + u30_hhi_mem_pd_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u30-hhi-mem-pd-mask", NULL); + if (prop) + u30_hhi_mem_pd_mask = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u30-ctrl-iso-shift", NULL); + if (prop) + u30_ctrl_iso_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "usb30-ctrl-a-rst-bit", NULL); + if (prop) + usb30_ctrl_rst_bit = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u31-ctrl-sleep-shift", NULL); + if (prop) + u31_ctrl_sleep_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u31-hhi-mem-pd-shift", NULL); + if (prop) + u31_hhi_mem_pd_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u31-hhi-mem-pd-mask", NULL); + if (prop) + u31_hhi_mem_pd_mask = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "u31-ctrl-iso-shift", NULL); + if (prop) + u31_ctrl_iso_shift = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + + prop = of_get_property(dev->of_node, + "usb31-ctrl-a-rst-bit", NULL); + if (prop) + usb31_ctrl_rst_bit = of_read_ulong(prop, 1); + else + pwr_ctl = 0; + } + + prop = of_get_property(dev->of_node, + "portconfig-30", NULL); + if (prop) + portconfig_30 = of_read_ulong(prop, 1); + + prop = of_get_property(dev->of_node, + "portconfig-31", NULL); + if (prop) + portconfig_31 = of_read_ulong(prop, 1); + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + dev_info(&pdev->dev, "USB3 phy probe:phy_mem:0x%lx, iomap phy_base:0x%lx\n", + (unsigned long)phy_mem->start, (unsigned long)phy_base); + + phy->dev = dev; + phy->regs = phy_base; + phy->phy3_cfg = phy3_base; + phy->phy3_cfg_r1 = (void __iomem *) + ((unsigned long)phy->phy3_cfg + 4 * 1); + phy->phy3_cfg_r2 = (void __iomem *) + ((unsigned long)phy->phy3_cfg + 4 * 2); + phy->phy3_cfg_r4 = (void __iomem *) + ((unsigned long)phy->phy3_cfg + 4 * 4); + phy->phy3_cfg_r5 = (void __iomem *) + ((unsigned long)phy->phy3_cfg + 4 * 5); + phy->phy31_cfg = phy31_base; + phy->phy31_cfg_r1 = (void __iomem *) + ((unsigned long)phy->phy31_cfg + 4 * 1); + phy->phy31_cfg_r2 = (void __iomem *) + ((unsigned long)phy->phy31_cfg + 4 * 2); + phy->phy31_cfg_r4 = (void __iomem *) + ((unsigned long)phy->phy31_cfg + 4 * 4); + phy->phy31_cfg_r5 = (void __iomem *) + ((unsigned long)phy->phy31_cfg + 4 * 5); + phy->portnum = portnum; + phy->suspend_flag = 0; + phy->phy.dev = phy->dev; + phy->phy.label = "amlogic-usbphy3"; + phy->phy.init = amlogic_new_usb3_init_v3; + phy->phy.set_suspend = amlogic_new_usb3_suspend; + phy->phy.shutdown = amlogic_new_usb3phy_shutdown; + phy->phy.type = USB_PHY_TYPE_USB3; + phy->phy.flags = AML_USB3_PHY_DISABLE; + phy->pwr_ctl = pwr_ctl; + + /* set the phy from pcie to usb3 */ + if (phy->portnum > 0) { + if (phy->pwr_ctl) { + phy->u30_ctrl_sleep_shift = u30_ctrl_sleep_shift; + phy->u30_hhi_mem_pd_shift = u30_hhi_mem_pd_shift; + phy->u30_hhi_mem_pd_mask = u30_hhi_mem_pd_mask; + phy->u30_ctrl_iso_shift = u30_ctrl_iso_shift; + phy->reset_regs = reset_base; + phy->usb30_ctrl_rst_bit = usb30_ctrl_rst_bit; + phy->u31_ctrl_sleep_shift = u31_ctrl_sleep_shift; + phy->u31_hhi_mem_pd_shift = u31_hhi_mem_pd_shift; + phy->u31_hhi_mem_pd_mask = u31_hhi_mem_pd_mask; + phy->u31_ctrl_iso_shift = u31_ctrl_iso_shift; + phy->usb31_ctrl_rst_bit = usb31_ctrl_rst_bit; + power_switch_to_pcie(phy); + } + + if (portconfig_30) + writel((readl(phy->phy3_cfg) | (3<<5)), phy->phy3_cfg); + udelay(100); + + if (portconfig_31) + writel((readl(phy->phy31_cfg) | (3<<5)), + phy->phy31_cfg); + udelay(100); + + phy->gate0_clk = devm_clk_get(dev, "pcie0_gate"); + if (IS_ERR(phy->gate0_clk)) { + dev_err(dev, "Failed to get usb3 bus clock\n"); + ret = PTR_ERR(phy->gate0_clk); + return ret; + } + + ret = clk_prepare_enable(phy->gate0_clk); + if (ret) { + dev_err(dev, "Failed to enable usb3 bus clock\n"); + ret = PTR_ERR(phy->gate0_clk); + return ret; + } + + phy->gate1_clk = devm_clk_get(dev, "pcie1_gate"); + if (IS_ERR(phy->gate1_clk)) { + dev_err(dev, "Failed to get usb3 bus clock\n"); + ret = PTR_ERR(phy->gate1_clk); + return ret; + } + + ret = clk_prepare_enable(phy->gate1_clk); + if (ret) { + dev_err(dev, "Failed to enable usb3 bus clock\n"); + ret = PTR_ERR(phy->gate1_clk); + return ret; + } + + phy->clk = devm_clk_get(dev, "pcie_refpll"); + if (IS_ERR(phy->clk)) { + dev_err(dev, "Failed to get usb3 bus clock\n"); + ret = PTR_ERR(phy->clk); + return ret; + } + + ret = clk_prepare_enable(phy->clk); + if (ret) { + dev_err(dev, "Failed to enable usb3 bus clock\n"); + ret = PTR_ERR(phy->clk); + return ret; + } + + rate = clk_get_rate(phy->clk); + if (rate != PCIE_PLL_RATE) + dev_err(dev, "pcie_refpll is not 100M, it is %ld\n", + rate); + + phy->phy.flags = AML_USB3_PHY_ENABLE; + } + + usb_add_phy_dev(&phy->phy); + + platform_set_drvdata(pdev, phy); + + pm_runtime_enable(phy->dev); + + return 0; +} + +static int amlogic_new_usb3_v3_remove(struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int amlogic_new_usb3_v3_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int amlogic_new_usb3_v3_runtime_resume(struct device *dev) +{ + u32 ret = 0; + + return ret; +} + +static const struct dev_pm_ops amlogic_new_usb3_pm_ops = { + SET_RUNTIME_PM_OPS(amlogic_new_usb3_v3_runtime_suspend, + amlogic_new_usb3_v3_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&amlogic_new_usb3_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id amlogic_new_usb3_v3_id_table[] = { + { .compatible = "amlogic, amlogic-new-usb3-v3" }, + {} +}; +MODULE_DEVICE_TABLE(of, amlogic_new_usb3_v3_id_table); +#endif + +static struct platform_driver amlogic_new_usb3_v3_driver = { + .probe = amlogic_new_usb3_v3_probe, + .remove = amlogic_new_usb3_v3_remove, + .driver = { + .name = "amlogic-new-usb3-v3", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(amlogic_new_usb3_v3_id_table), + }, +}; + +module_platform_driver(amlogic_new_usb3_v3_driver); + +MODULE_ALIAS("platform: amlogic_usb3_v2"); +MODULE_AUTHOR("Amlogic Inc."); +MODULE_DESCRIPTION("amlogic USB3 v2 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a0846a1546fd..314238487d15 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -208,6 +208,11 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + /* Assert USB3 PHY reset */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1)); + reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); + /* Assert USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; @@ -245,6 +250,11 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + /* Clear USB3 PHY reset */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1)); + reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); + /* Clear USB2 PHY reset */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; @@ -959,6 +969,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) if (dwc->usb3_phy) if (dwc->usb3_phy->flags == AML_USB3_PHY_ENABLE) dwc->super_speed_support = 1; + #endif dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); diff --git a/include/linux/amlogic/usb-v2.h b/include/linux/amlogic/usb-v2.h index 4d5df3a8469c..8b3092c0a92d 100644 --- a/include/linux/amlogic/usb-v2.h +++ b/include/linux/amlogic/usb-v2.h @@ -30,6 +30,8 @@ int aml_new_usb_v2_register_notifier(struct notifier_block *nb); int aml_new_usb_v2_unregister_notifier(struct notifier_block *nb); +int aml_new_otg_register_notifier(struct notifier_block *nb); +int aml_new_otg_unregister_notifier(struct notifier_block *nb); struct u2p_aml_regs_v2 { void __iomem *u2p_r_v2[2]; @@ -64,7 +66,7 @@ union u2p_r1_v2 { }; struct usb_aml_regs_v2 { - void __iomem *usb_r_v2[6]; + void __iomem *usb_r_v2[8]; }; union usb_r0_v2 { @@ -88,13 +90,10 @@ union usb_r1_v2 { struct { unsigned u3h_bigendian_gs:1; unsigned u3h_pme_en:1; - unsigned u3h_hub_port_overcurrent:3; - unsigned reserved_1:2; - unsigned u3h_hub_port_perm_attach:3; - unsigned reserved_2:2; - unsigned u3h_host_u2_port_disable:2; - unsigned reserved_3:2; - unsigned u3h_host_u3_port_disable:1; + unsigned u3h_hub_port_overcurrent:5; + unsigned u3h_hub_port_perm_attach:5; + unsigned u3h_host_u2_port_disable:3; + unsigned u3h_host_u3_port_disable:2; unsigned u3h_host_port_power_control_present:1; unsigned u3h_host_msi_enable:1; unsigned u3h_fladj_30mhz_reg:6; @@ -135,7 +134,11 @@ union usb_r4_v2 { unsigned p21_SLEEPM0:1; unsigned mem_pd:2; unsigned p21_only:1; - unsigned reserved:27; + unsigned reserved:12; + unsigned p31_lane0_tx2rx_loopback:1; + unsigned p31_lane0_ext_pclk_req:1; + unsigned p31_pcs_rx_los_mask_val:10; + unsigned reserve:3; } b; }; @@ -157,6 +160,22 @@ union usb_r5_v2 { } b; }; +union usb_r7_v2 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned p31_ssc_en:1; + unsigned p31_ssc_range:3; + unsigned p31_ssc_ref_clk_sel:9; + unsigned p31_ref_ssp_en:1; + unsigned reserved:2; + unsigned p31_pcs_tx_deemph_6db:6; + unsigned reserve:3; + unsigned p31_pcs_tx_swing_full:7; + } b; +}; + struct amlogic_usb_v2 { struct usb_phy phy; struct device *dev; @@ -168,7 +187,14 @@ struct amlogic_usb_v2 { void __iomem *phy3_cfg_r2; void __iomem *phy3_cfg_r4; void __iomem *phy3_cfg_r5; + void __iomem *phy31_cfg; + void __iomem *phy31_cfg_r1; + void __iomem *phy31_cfg_r2; + void __iomem *phy31_cfg_r4; + void __iomem *phy31_cfg_r5; void __iomem *usb2_phy_cfg; + void __iomem *power_base; + void __iomem *hhi_mem_pd_base; u32 pll_setting[8]; int phy_cfg_state[4]; /* Set VBus Power though GPIO */ @@ -185,11 +211,19 @@ struct amlogic_usb_v2 { u32 u2_hhi_mem_pd_mask; u32 u2_ctrl_iso_shift; u32 u2_hhi_mem_pd_shift; - u32 u3_ctrl_sleep_shift; - u32 u3_hhi_mem_pd_mask; - u32 u3_ctrl_iso_shift; - u32 u3_hhi_mem_pd_shift; + u32 u30_ctrl_sleep_shift; + u32 u30_hhi_mem_pd_mask; + u32 u30_ctrl_iso_shift; + u32 u30_hhi_mem_pd_shift; + u32 usb30_ctrl_rst_bit; + u32 u31_ctrl_sleep_shift; + u32 u31_hhi_mem_pd_mask; + u32 u31_ctrl_iso_shift; + u32 u31_hhi_mem_pd_shift; + u32 usb31_ctrl_rst_bit; struct clk *clk; + struct clk *gate0_clk; + struct clk *gate1_clk; }; union phy3_r1 {