From 127e57c671b3e13828e119c28d24aafdb8ee0e6c Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 25 May 2021 01:20:25 +0100 Subject: [PATCH 01/17] arm: dts: sunxi: h6: Update DT files Update the H6 DT files from the Linux 5.12 release. The changes are minimal (many LED node renames), but also help to enable USB port 0 in U-Boot (later), enable the RSB device (not yet used in U-Boot), and also introduce an MMC frequency limit. Signed-off-by: Andre Przywara --- arch/arm/dts/sun50i-h6-beelink-gs1.dts | 6 +----- arch/arm/dts/sun50i-h6-cpu-opp.dtsi | 20 ++++++++++---------- arch/arm/dts/sun50i-h6-orangepi-3.dts | 4 ++-- arch/arm/dts/sun50i-h6-orangepi.dtsi | 4 ++-- arch/arm/dts/sun50i-h6-pine-h64.dts | 7 ++++--- arch/arm/dts/sun50i-h6.dtsi | 26 ++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 22 deletions(-) diff --git a/arch/arm/dts/sun50i-h6-beelink-gs1.dts b/arch/arm/dts/sun50i-h6-beelink-gs1.dts index 7c9dbde645..b5808047d6 100644 --- a/arch/arm/dts/sun50i-h6-beelink-gs1.dts +++ b/arch/arm/dts/sun50i-h6-beelink-gs1.dts @@ -43,7 +43,7 @@ leds { compatible = "gpio-leds"; - power { + led { label = "beelink:white:power"; gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ default-state = "on"; @@ -289,10 +289,6 @@ vcc-pm-supply = <®_aldo1>; }; -&rtc { - clocks = <&ext_osc32k>; -}; - &spdif { status = "okay"; }; diff --git a/arch/arm/dts/sun50i-h6-cpu-opp.dtsi b/arch/arm/dts/sun50i-h6-cpu-opp.dtsi index 1a5eddc5a4..8c6e8536b6 100644 --- a/arch/arm/dts/sun50i-h6-cpu-opp.dtsi +++ b/arch/arm/dts/sun50i-h6-cpu-opp.dtsi @@ -8,7 +8,7 @@ nvmem-cells = <&cpu_speed_grade>; opp-shared; - opp@480000000 { + opp-480000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <480000000>; @@ -17,7 +17,7 @@ opp-microvolt-speed2 = <820000 820000 1200000>; }; - opp@720000000 { + opp-720000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <720000000>; @@ -26,7 +26,7 @@ opp-microvolt-speed2 = <820000 820000 1200000>; }; - opp@816000000 { + opp-816000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <816000000>; @@ -35,7 +35,7 @@ opp-microvolt-speed2 = <820000 820000 1200000>; }; - opp@888000000 { + opp-888000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <888000000>; @@ -44,7 +44,7 @@ opp-microvolt-speed2 = <820000 820000 1200000>; }; - opp@1080000000 { + opp-1080000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1080000000>; @@ -53,7 +53,7 @@ opp-microvolt-speed2 = <880000 880000 1200000>; }; - opp@1320000000 { + opp-1320000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1320000000>; @@ -62,7 +62,7 @@ opp-microvolt-speed2 = <940000 940000 1200000>; }; - opp@1488000000 { + opp-1488000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1488000000>; @@ -71,7 +71,7 @@ opp-microvolt-speed2 = <1000000 1000000 1200000>; }; - opp@1608000000 { + opp-1608000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1608000000>; @@ -80,7 +80,7 @@ opp-microvolt-speed2 = <1030000 1030000 1200000>; }; - opp@1704000000 { + opp-1704000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1704000000>; @@ -89,7 +89,7 @@ opp-microvolt-speed2 = <1060000 1060000 1200000>; }; - opp@1800000000 { + opp-1800000000 { clock-latency-ns = <244144>; /* 8 32k periods */ opp-hz = /bits/ 64 <1800000000>; diff --git a/arch/arm/dts/sun50i-h6-orangepi-3.dts b/arch/arm/dts/sun50i-h6-orangepi-3.dts index 15c9dd8c44..7e83f6146f 100644 --- a/arch/arm/dts/sun50i-h6-orangepi-3.dts +++ b/arch/arm/dts/sun50i-h6-orangepi-3.dts @@ -43,13 +43,13 @@ leds { compatible = "gpio-leds"; - power { + led-0 { label = "orangepi:red:power"; gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ default-state = "on"; }; - status { + led-1 { label = "orangepi:green:status"; gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */ }; diff --git a/arch/arm/dts/sun50i-h6-orangepi.dtsi b/arch/arm/dts/sun50i-h6-orangepi.dtsi index ebc120a923..da0875bd38 100644 --- a/arch/arm/dts/sun50i-h6-orangepi.dtsi +++ b/arch/arm/dts/sun50i-h6-orangepi.dtsi @@ -42,13 +42,13 @@ leds { compatible = "gpio-leds"; - power { + led-0 { label = "orangepi:red:power"; gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ default-state = "on"; }; - status { + led-1 { label = "orangepi:green:status"; gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */ }; diff --git a/arch/arm/dts/sun50i-h6-pine-h64.dts b/arch/arm/dts/sun50i-h6-pine-h64.dts index 961732c52a..b868ad17af 100644 --- a/arch/arm/dts/sun50i-h6-pine-h64.dts +++ b/arch/arm/dts/sun50i-h6-pine-h64.dts @@ -44,17 +44,17 @@ leds { compatible = "gpio-leds"; - heartbeat { + led-0 { label = "pine-h64:green:heartbeat"; gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ }; - link { + led-1 { label = "pine-h64:white:link"; gpios = <&r_pio 0 3 GPIO_ACTIVE_HIGH>; /* PL3 */ }; - status { + led-2 { label = "pine-h64:blue:status"; gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */ }; @@ -142,6 +142,7 @@ vqmmc-supply = <®_bldo2>; non-removable; cap-mmc-hw-reset; + mmc-hs200-1_8v; bus-width = <8>; status = "okay"; }; diff --git a/arch/arm/dts/sun50i-h6.dtsi b/arch/arm/dts/sun50i-h6.dtsi index 8a62a9fbe3..af8b7d0ef7 100644 --- a/arch/arm/dts/sun50i-h6.dtsi +++ b/arch/arm/dts/sun50i-h6.dtsi @@ -436,6 +436,7 @@ interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; + max-frequency = <150000000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -452,6 +453,7 @@ interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins>; + max-frequency = <150000000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -468,6 +470,7 @@ interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&mmc2_pins>; + max-frequency = <150000000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -680,6 +683,8 @@ <&ccu CLK_USB_OHCI0>; resets = <&ccu RST_BUS_OHCI0>, <&ccu RST_BUS_EHCI0>; + phys = <&usb2phy 0>; + phy-names = "usb"; status = "disabled"; }; @@ -690,6 +695,8 @@ clocks = <&ccu CLK_BUS_OHCI0>, <&ccu CLK_USB_OHCI0>; resets = <&ccu RST_BUS_OHCI0>; + phys = <&usb2phy 0>; + phy-names = "usb"; status = "disabled"; }; @@ -949,6 +956,11 @@ pins = "PL9"; function = "s_cir_rx"; }; + + r_rsb_pins: r-rsb-pins { + pins = "PL0", "PL1"; + function = "s_rsb"; + }; }; r_ir: ir@7040000 { @@ -979,6 +991,20 @@ #size-cells = <0>; }; + r_rsb: rsb@7083000 { + compatible = "allwinner,sun8i-a23-rsb"; + reg = <0x07083000 0x400>; + interrupts = ; + clocks = <&r_ccu CLK_R_APB2_RSB>; + clock-frequency = <3000000>; + resets = <&r_ccu RST_R_APB2_RSB>; + pinctrl-names = "default"; + pinctrl-0 = <&r_rsb_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + ths: thermal-sensor@5070400 { compatible = "allwinner,sun50i-h6-ths"; reg = <0x05070400 0x100>; From 58f68611df3c8db33dbd4c40a4034c767895a427 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 25 May 2021 01:20:25 +0100 Subject: [PATCH 02/17] arm: dts: sunxi: h5: Update DT files Update the H5 DT files from the Linux 5.12 release. The changes don't affect U-Boot at all, but fix Gigabit Ethernet when this DT is passed on to the Linux kernel. It also introduces DVFS. This also updates the shared sunxi-h3-h5.dtsi, but that only adds nodes that are of no concern to U-Boot. Signed-off-by: Andre Przywara --- .../dts/sun50i-h5-bananapi-m2-plus-v1.2.dts | 1 + arch/arm/dts/sun50i-h5-cpu-opp.dtsi | 79 +++++++++++++++++++ .../arm/dts/sun50i-h5-libretech-all-h3-cc.dts | 1 + .../arm/dts/sun50i-h5-libretech-all-h5-cc.dts | 2 +- arch/arm/dts/sun50i-h5-nanopi-neo-plus2.dts | 6 +- arch/arm/dts/sun50i-h5-nanopi-neo2.dts | 4 +- arch/arm/dts/sun50i-h5-orangepi-pc2.dts | 27 ++++++- arch/arm/dts/sun50i-h5-orangepi-prime.dts | 6 +- arch/arm/dts/sun50i-h5-orangepi-zero-plus.dts | 4 +- .../arm/dts/sun50i-h5-orangepi-zero-plus2.dts | 38 +++++++++ arch/arm/dts/sun50i-h5.dtsi | 61 ++++++++++++-- arch/arm/dts/sun8i-h3.dtsi | 49 +++++++++++- arch/arm/dts/sunxi-h3-h5.dtsi | 42 +++++++++- 13 files changed, 296 insertions(+), 24 deletions(-) create mode 100644 arch/arm/dts/sun50i-h5-cpu-opp.dtsi diff --git a/arch/arm/dts/sun50i-h5-bananapi-m2-plus-v1.2.dts b/arch/arm/dts/sun50i-h5-bananapi-m2-plus-v1.2.dts index 2e2b14c0ae..8857a37915 100644 --- a/arch/arm/dts/sun50i-h5-bananapi-m2-plus-v1.2.dts +++ b/arch/arm/dts/sun50i-h5-bananapi-m2-plus-v1.2.dts @@ -3,6 +3,7 @@ /dts-v1/; #include "sun50i-h5.dtsi" +#include "sun50i-h5-cpu-opp.dtsi" #include / { diff --git a/arch/arm/dts/sun50i-h5-cpu-opp.dtsi b/arch/arm/dts/sun50i-h5-cpu-opp.dtsi new file mode 100644 index 0000000000..b265720195 --- /dev/null +++ b/arch/arm/dts/sun50i-h5-cpu-opp.dtsi @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// Copyright (C) 2020 Chen-Yu Tsai + +/ { + cpu_opp_table: cpu-opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <1000000 1000000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-648000000 { + opp-hz = /bits/ 64 <648000000>; + opp-microvolt = <1040000 1040000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <1080000 1080000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-912000000 { + opp-hz = /bits/ 64 <912000000>; + opp-microvolt = <1120000 1120000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-960000000 { + opp-hz = /bits/ 64 <960000000>; + opp-microvolt = <1160000 1160000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <1200000 1200000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-1056000000 { + opp-hz = /bits/ 64 <1056000000>; + opp-microvolt = <1240000 1240000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <1260000 1260000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp-1152000000 { + opp-hz = /bits/ 64 <1152000000>; + opp-microvolt = <1300000 1300000 1310000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + }; +}; + +&cpu0 { + operating-points-v2 = <&cpu_opp_table>; +}; + +&cpu1 { + operating-points-v2 = <&cpu_opp_table>; +}; + +&cpu2 { + operating-points-v2 = <&cpu_opp_table>; +}; + +&cpu3 { + operating-points-v2 = <&cpu_opp_table>; +}; diff --git a/arch/arm/dts/sun50i-h5-libretech-all-h3-cc.dts b/arch/arm/dts/sun50i-h5-libretech-all-h3-cc.dts index a91806618e..016da3ec32 100644 --- a/arch/arm/dts/sun50i-h5-libretech-all-h3-cc.dts +++ b/arch/arm/dts/sun50i-h5-libretech-all-h3-cc.dts @@ -4,6 +4,7 @@ /dts-v1/; #include "sun50i-h5.dtsi" +#include "sun50i-h5-cpu-opp.dtsi" #include / { diff --git a/arch/arm/dts/sun50i-h5-libretech-all-h5-cc.dts b/arch/arm/dts/sun50i-h5-libretech-all-h5-cc.dts index df1b9263ad..6e30a564c8 100644 --- a/arch/arm/dts/sun50i-h5-libretech-all-h5-cc.dts +++ b/arch/arm/dts/sun50i-h5-libretech-all-h5-cc.dts @@ -36,7 +36,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; /delete-property/ allwinner,leds-active-low; status = "okay"; }; diff --git a/arch/arm/dts/sun50i-h5-nanopi-neo-plus2.dts b/arch/arm/dts/sun50i-h5-nanopi-neo-plus2.dts index 4f9ba53ffa..4c3921ac23 100644 --- a/arch/arm/dts/sun50i-h5-nanopi-neo-plus2.dts +++ b/arch/arm/dts/sun50i-h5-nanopi-neo-plus2.dts @@ -25,13 +25,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "nanopi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; default-state = "on"; }; - status { + led-1 { label = "nanopi:red:status"; gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>; }; @@ -96,7 +96,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; diff --git a/arch/arm/dts/sun50i-h5-nanopi-neo2.dts b/arch/arm/dts/sun50i-h5-nanopi-neo2.dts index b059e20813..02f8e72f0c 100644 --- a/arch/arm/dts/sun50i-h5-nanopi-neo2.dts +++ b/arch/arm/dts/sun50i-h5-nanopi-neo2.dts @@ -22,13 +22,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "nanopi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; default-state = "on"; }; - status { + led-1 { label = "nanopi:blue:status"; gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/dts/sun50i-h5-orangepi-pc2.dts b/arch/arm/dts/sun50i-h5-orangepi-pc2.dts index 70b5f09984..1010c1b22d 100644 --- a/arch/arm/dts/sun50i-h5-orangepi-pc2.dts +++ b/arch/arm/dts/sun50i-h5-orangepi-pc2.dts @@ -42,13 +42,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "orangepi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; default-state = "on"; }; - status { + led-1 { label = "orangepi:red:status"; gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>; }; @@ -61,6 +61,7 @@ label = "sw4"; linux,code = ; gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; + wakeup-source; }; }; @@ -93,6 +94,10 @@ status = "okay"; }; +&cpu0 { + cpu-supply = <®_vdd_cpux>; +}; + &de { status = "okay"; }; @@ -118,7 +123,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; @@ -168,6 +173,22 @@ status = "okay"; }; +&r_i2c { + status = "okay"; + + reg_vdd_cpux: regulator@65 { + compatible = "silergy,sy8106a"; + reg = <0x65>; + regulator-name = "vdd-cpux"; + silergy,fixed-microvolt = <1100000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <200>; + regulator-boot-on; + regulator-always-on; + }; +}; + &spi0 { status = "okay"; diff --git a/arch/arm/dts/sun50i-h5-orangepi-prime.dts b/arch/arm/dts/sun50i-h5-orangepi-prime.dts index cb44bfa598..74e0444af1 100644 --- a/arch/arm/dts/sun50i-h5-orangepi-prime.dts +++ b/arch/arm/dts/sun50i-h5-orangepi-prime.dts @@ -36,13 +36,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "orangepi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; default-state = "on"; }; - status { + led-1 { label = "orangepi:red:status"; gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>; }; @@ -124,7 +124,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; diff --git a/arch/arm/dts/sun50i-h5-orangepi-zero-plus.dts b/arch/arm/dts/sun50i-h5-orangepi-zero-plus.dts index ef5ca64442..d13980ed7a 100644 --- a/arch/arm/dts/sun50i-h5-orangepi-zero-plus.dts +++ b/arch/arm/dts/sun50i-h5-orangepi-zero-plus.dts @@ -33,13 +33,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "orangepi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */ default-state = "on"; }; - status { + led-1 { label = "orangepi:red:status"; gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>; /* PA17 */ }; diff --git a/arch/arm/dts/sun50i-h5-orangepi-zero-plus2.dts b/arch/arm/dts/sun50i-h5-orangepi-zero-plus2.dts index c95a685413..22530ace12 100644 --- a/arch/arm/dts/sun50i-h5-orangepi-zero-plus2.dts +++ b/arch/arm/dts/sun50i-h5-orangepi-zero-plus2.dts @@ -30,6 +30,21 @@ }; }; + leds { + compatible = "gpio-leds"; + + led-0 { + label = "orangepi:green:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + led-1 { + label = "orangepi:red:status"; + gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>; + }; + }; + reg_vcc3v3: vcc3v3 { compatible = "regulator-fixed"; regulator-name = "vcc3v3"; @@ -48,6 +63,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &hdmi { status = "okay"; }; @@ -92,6 +111,10 @@ status = "okay"; }; +&ohci0 { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pa_pins>; @@ -103,3 +126,18 @@ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; status = "okay"; }; + +&usb_otg { + /* + * According to schematics CN1 MicroUSB port can be used to take + * external 5V to power up the board VBUS. On the contrary CN1 MicroUSB + * port cannot provide power externally even if the board is powered + * via GPIO pins. It thus makes sense to force peripheral mode. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; diff --git a/arch/arm/dts/sun50i-h5.dtsi b/arch/arm/dts/sun50i-h5.dtsi index 3a1c8b2efd..ab860e20d0 100644 --- a/arch/arm/dts/sun50i-h5.dtsi +++ b/arch/arm/dts/sun50i-h5.dtsi @@ -3,6 +3,8 @@ #include +#include + / { cpus { #address-cells = <1>; @@ -13,6 +15,9 @@ device_type = "cpu"; reg = <0>; enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + #cooling-cells = <2>; }; cpu1: cpu@1 { @@ -20,6 +25,9 @@ device_type = "cpu"; reg = <1>; enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + #cooling-cells = <2>; }; cpu2: cpu@2 { @@ -27,6 +35,9 @@ device_type = "cpu"; reg = <2>; enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + #cooling-cells = <2>; }; cpu3: cpu@3 { @@ -34,12 +45,14 @@ device_type = "cpu"; reg = <3>; enable-method = "psci"; + clocks = <&ccu CLK_CPUX>; + clock-latency-ns = <244144>; /* 8 32k periods */ + #cooling-cells = <2>; }; }; pmu { - compatible = "arm,cortex-a53-pmu", - "arm,armv8-pmuv3"; + compatible = "arm,cortex-a53-pmu"; interrupts = , , , @@ -54,6 +67,7 @@ timer { compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; interrupts = , ; }; + deinterlace: deinterlace@1e00000 { + compatible = "allwinner,sun8i-h3-deinterlace"; + reg = <0x01e00000 0x20000>; + clocks = <&ccu CLK_BUS_DEINTERLACE>, + <&ccu CLK_DEINTERLACE>, + <&ccu CLK_DRAM_DEINTERLACE>; + clock-names = "bus", "mod", "ram"; + resets = <&ccu RST_BUS_DEINTERLACE>; + interrupts = ; + interconnects = <&mbus 9>; + interconnect-names = "dma-mem"; + }; + mali: gpu@1e80000 { compatible = "allwinner,sun50i-h5-mali", "arm,mali-450"; reg = <0x01e80000 0x30000>; @@ -126,8 +153,7 @@ , , , - , - ; + ; interrupt-names = "gp", "gpmmu", "pp", @@ -138,8 +164,7 @@ "pp2", "ppmmu2", "pp3", - "ppmmu3", - "pmu"; + "ppmmu3"; clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>; clock-names = "bus", "core"; resets = <&ccu RST_BUS_GPU>; @@ -166,6 +191,30 @@ polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&ths 0>; + + trips { + cpu_hot_trip: cpu-hot { + temperature = <80000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_very_hot_trip: cpu-very-hot { + temperature = <100000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + cpu-hot-limit { + trip = <&cpu_hot_trip>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; gpu_thermal { diff --git a/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi index 20217e2ca4..4e89701df9 100644 --- a/arch/arm/dts/sun8i-h3.dtsi +++ b/arch/arm/dts/sun8i-h3.dtsi @@ -41,6 +41,7 @@ */ #include "sunxi-h3-h5.dtsi" +#include / { cpu0_opp_table: opp_table0 { @@ -111,6 +112,26 @@ }; }; + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-120000000 { + opp-hz = /bits/ 64 <120000000>; + }; + + opp-312000000 { + opp-hz = /bits/ 64 <312000000>; + }; + + opp-432000000 { + opp-hz = /bits/ 64 <432000000>; + }; + + opp-576000000 { + opp-hz = /bits/ 64 <576000000>; + }; + }; + pmu { compatible = "arm,cortex-a7-pmu"; interrupts = , @@ -204,9 +225,7 @@ clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>; clock-names = "bus", "core"; resets = <&ccu RST_BUS_GPU>; - - assigned-clocks = <&ccu CLK_GPU>; - assigned-clock-rates = <384000000>; + operating-points-v2 = <&gpu_opp_table>; }; ths: thermal-sensor@1c25000 { @@ -227,6 +246,30 @@ polling-delay-passive = <0>; polling-delay = <0>; thermal-sensors = <&ths 0>; + + trips { + cpu_hot_trip: cpu-hot { + temperature = <80000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_very_hot_trip: cpu-very-hot { + temperature = <100000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + cpu-hot-limit { + trip = <&cpu_hot_trip>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; }; }; }; diff --git a/arch/arm/dts/sunxi-h3-h5.dtsi b/arch/arm/dts/sunxi-h3-h5.dtsi index 5e9c3060aa..9be13378d4 100644 --- a/arch/arm/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/dts/sunxi-h3-h5.dtsi @@ -114,7 +114,7 @@ display_clocks: clock@1000000 { /* compatible is in per SoC .dtsi file */ - reg = <0x01000000 0x100000>; + reg = <0x01000000 0x10000>; clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; clock-names = "bus", @@ -239,6 +239,16 @@ }; }; + msgbox: mailbox@1c17000 { + compatible = "allwinner,sun8i-h3-msgbox", + "allwinner,sun6i-a31-msgbox"; + reg = <0x01c17000 0x1000>; + clocks = <&ccu CLK_BUS_MSGBOX>; + resets = <&ccu RST_BUS_MSGBOX>; + interrupts = ; + #mbox-cells = <1>; + }; + usb_otg: usb@1c19000 { compatible = "allwinner,sun8i-h3-musb"; reg = <0x01c19000 0x400>; @@ -560,6 +570,8 @@ compatible = "allwinner,sun8i-h3-mbus"; reg = <0x01c62000 0x1000>; clocks = <&ccu CLK_MBUS>; + #address-cells = <1>; + #size-cells = <1>; dma-ranges = <0x00000000 0x40000000 0xc0000000>; #interconnect-cells = <1>; }; @@ -650,6 +662,19 @@ status = "disabled"; }; + i2s2: i2s@1c22800 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-h3-i2s"; + reg = <0x01c22800 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>; + clock-names = "apb", "mod"; + dmas = <&dma 27>; + resets = <&ccu RST_BUS_I2S2>; + dma-names = "tx"; + status = "disabled"; + }; + codec: codec@1c22c00 { #sound-dai-cells = <0>; compatible = "allwinner,sun8i-h3-codec"; @@ -892,6 +917,21 @@ pins = "PL0", "PL1"; function = "s_i2c"; }; + + r_pwm_pin: r-pwm-pin { + pins = "PL10"; + function = "s_pwm"; + }; + }; + + r_pwm: pwm@1f03800 { + compatible = "allwinner,sun8i-h3-pwm"; + reg = <0x01f03800 0x8>; + pinctrl-names = "default"; + pinctrl-0 = <&r_pwm_pin>; + clocks = <&osc24M>; + #pwm-cells = <3>; + status = "disabled"; }; }; }; From 8fcf1fa24675e49a1a5b0a525c775d7aa6202090 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 25 May 2021 01:20:25 +0100 Subject: [PATCH 03/17] arm: dts: sunxi: h3: Update DT files Update the H3 DT files from the Linux 5.12 release. The changes update some boards, and don't affect U-Boot, but fix Gigabit Ethernet when this DT is passed on to the Linux kernel. Signed-off-by: Andre Przywara --- .../dts/sun8i-h2-plus-bananapi-m2-zero.dts | 96 ++++++++++++++++++- arch/arm/dts/sun8i-h3-beelink-x2.dts | 4 +- arch/arm/dts/sun8i-h3-nanopi-duo2.dts | 4 +- arch/arm/dts/sun8i-h3-nanopi-neo-air.dts | 4 +- arch/arm/dts/sun8i-h3-nanopi.dtsi | 4 +- arch/arm/dts/sun8i-h3-orangepi-pc-plus.dts | 5 - arch/arm/dts/sun8i-h3-orangepi-plus2e.dts | 2 +- arch/arm/dts/sun8i-h3-orangepi-zero-plus2.dts | 38 ++++++++ 8 files changed, 142 insertions(+), 15 deletions(-) diff --git a/arch/arm/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/dts/sun8i-h2-plus-bananapi-m2-zero.dts index d277d04303..f3f7a2c912 100644 --- a/arch/arm/dts/sun8i-h2-plus-bananapi-m2-zero.dts +++ b/arch/arm/dts/sun8i-h2-plus-bananapi-m2-zero.dts @@ -31,7 +31,7 @@ pwr_led { label = "bananapi-m2-zero:red:pwr"; - gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ + gpios = <&r_pio 0 10 GPIO_ACTIVE_LOW>; /* PL10 */ default-state = "on"; }; }; @@ -62,6 +62,35 @@ states = <1100000 0>, <1300000 1>; }; + reg_vcc_dram: vcc-dram { + compatible = "regulator-fixed"; + regulator-name = "vcc-dram"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + enable-active-high; + gpio = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */ + vin-supply = <®_vcc5v0>; + }; + + reg_vcc1v2: vcc1v2 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + enable-active-high; + gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */ + vin-supply = <®_vcc5v0>; + }; + + poweroff { + compatible = "regulator-poweroff"; + cpu-supply = <®_vcc1v2>; + }; + wifi_pwrseq: wifi_pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ @@ -125,6 +154,7 @@ bluetooth { compatible = "brcm,bcm43438-bt"; + max-speed = <1500000>; clocks = <&rtc 1>; clock-names = "lpo"; vbat-supply = <®_vcc3v3>; @@ -136,6 +166,70 @@ }; +&pio { + gpio-line-names = + /* PA */ + "CON2-P13", "CON2-P11", "CON2-P22", "CON2-P15", + "CON3-P03", "CON3-P02", "CON2-P07", "CON2-P29", + "CON2-P31", "CON2-P33", "CON2-P35", "CON2-P05", + "CON2-P03", "CON2-P08", "CON2-P10", "CON2-P16", + "CON2-P12", "CON2-P37", "CON2-P28", "CON2-P27", + "CON2-P40", "CON2-P38", "", "", + "", "", "", "", "", "", "", "", + + /* PB */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + + /* PC */ + "CON2-P19", "CON2-P21", "CON2-P23", "CON2-P24", + "CON2-P18", "", "", "CON2-P26", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + + /* PD */ + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "CSI-PWR-EN", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + + /* PE */ + "CN3-P17", "CN3-P13", "CN3-P09", "CN3-P07", + "CN3-P19", "CN3-P21", "CN3-P22", "CN3-P20", + "CN3-P18", "CN3-P16", "CN3-P14", "CN3-P12", + "CN3-P05", "CN3-P03", "CN3-P06", "CN3-P08", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + + /* PF */ + "SDC0-D1", "SDC0-D0", "SDC0-CLK", "SDC0-CMD", "SDC0-D3", + "SDC0-D2", "SDC0-DET", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + + /* PG */ + "WL-SDIO-CLK", "WL-SDIO-CMD", "WL-SDIO-D0", "WL-SDIO-D1", + "WL-SDIO-D2", "WL-SDIO-D3", "BT-UART-TX", "BT-UART-RX", + "BT-UART-RTS", "BT-UART-CTS", "WL-WAKE-AP", "BT-WAKE-AP", + "BT-RST-N", "AP-WAKE-BT", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""; +}; + +&r_pio { + gpio-line-names = + /* PL */ + "", "CPUX-SET", "CON2-P32", "POWER-KEY", "CON2-P36", + "VCC-IO-EN", "USB0-ID", "WL-PWR-EN", + "PWR-STB", "PWR-DRAM", "PWR-LED", "IR-RX", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""; +}; + &usb_otg { dr_mode = "otg"; status = "okay"; diff --git a/arch/arm/dts/sun8i-h3-beelink-x2.dts b/arch/arm/dts/sun8i-h3-beelink-x2.dts index 45a24441ff..62b5280ec0 100644 --- a/arch/arm/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/dts/sun8i-h3-beelink-x2.dts @@ -75,13 +75,13 @@ leds { compatible = "gpio-leds"; - blue { + led-0 { label = "beelink-x2:blue:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ default-state = "on"; }; - red { + led-1 { label = "beelink-x2:red:standby"; gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */ }; diff --git a/arch/arm/dts/sun8i-h3-nanopi-duo2.dts b/arch/arm/dts/sun8i-h3-nanopi-duo2.dts index 6b149271ef..8e7dfcffe1 100644 --- a/arch/arm/dts/sun8i-h3-nanopi-duo2.dts +++ b/arch/arm/dts/sun8i-h3-nanopi-duo2.dts @@ -25,13 +25,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "nanopi:red:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ default-state = "on"; }; - status { + led-1 { label = "nanopi:green:status"; gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */ }; diff --git a/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts b/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts index 07867a0d56..be49eabbff 100644 --- a/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts +++ b/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts @@ -61,13 +61,13 @@ leds { compatible = "gpio-leds"; - pwr { + led-0 { label = "nanopi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ default-state = "on"; }; - status { + led-1 { label = "nanopi:blue:status"; gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */ }; diff --git a/arch/arm/dts/sun8i-h3-nanopi.dtsi b/arch/arm/dts/sun8i-h3-nanopi.dtsi index 4df29a6531..c7c3e7d8b3 100644 --- a/arch/arm/dts/sun8i-h3-nanopi.dtsi +++ b/arch/arm/dts/sun8i-h3-nanopi.dtsi @@ -60,13 +60,13 @@ leds { compatible = "gpio-leds"; - status { + led-0 { label = "nanopi:blue:status"; gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - pwr { + led-1 { label = "nanopi:green:pwr"; gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; default-state = "on"; diff --git a/arch/arm/dts/sun8i-h3-orangepi-pc-plus.dts b/arch/arm/dts/sun8i-h3-orangepi-pc-plus.dts index 71fb732089..babf4cf1b2 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-pc-plus.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-pc-plus.dts @@ -53,11 +53,6 @@ }; }; -&emac { - /* LEDs changed to active high on the plus */ - /delete-property/ allwinner,leds-active-low; -}; - &mmc1 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; diff --git a/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts b/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts index 6dbf7b2e0c..b6ca45d18e 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-plus2e.dts @@ -67,7 +67,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; diff --git a/arch/arm/dts/sun8i-h3-orangepi-zero-plus2.dts b/arch/arm/dts/sun8i-h3-orangepi-zero-plus2.dts index b8f46e2802..561ea1d2f8 100644 --- a/arch/arm/dts/sun8i-h3-orangepi-zero-plus2.dts +++ b/arch/arm/dts/sun8i-h3-orangepi-zero-plus2.dts @@ -70,6 +70,21 @@ }; }; + leds { + compatible = "gpio-leds"; + + led-0 { + label = "orangepi:green:pwr"; + gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + led-1 { + label = "orangepi:red:status"; + gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>; + }; + }; + reg_vcc3v3: vcc3v3 { compatible = "regulator-fixed"; regulator-name = "vcc3v3"; @@ -88,6 +103,10 @@ status = "okay"; }; +&ehci0 { + status = "okay"; +}; + &hdmi { status = "okay"; }; @@ -132,8 +151,27 @@ status = "okay"; }; +&ohci0 { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pa_pins>; status = "okay"; }; + +&usb_otg { + /* + * According to schematics CN1 MicroUSB port can be used to take + * external 5V to power up the board VBUS. On the contrary CN1 MicroUSB + * port cannot provide power externally even if the board is powered + * via GPIO pins. It thus makes sense to force peripheral mode. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; From 0d5824cbc9ee1e608c1597117aac1c129c519630 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 14 Mar 2019 10:38:00 +0000 Subject: [PATCH 04/17] phy: sun4i-usb: Fix PHY0 routing and passby configuration for MUSB Recent Allwinner platforms (starting with the H3) only use the MUSB controller for peripheral mode and use HCI for host mode. As a result, extra steps need to be taken to properly route USB signals to one or the other. More precisely, the following is required: * Routing the pins to either HCI/MUSB (controlled by PHY); * Enabling USB PHY passby in HCI mode (controlled by PMU). The current code will enable passby for each PHY and reroute PHY0 to MUSB, which is inconsistent and results in broken USB peripheral support. Passby on PHY0 must only be enabled when we want to use HCI. Since host/device mode detection is not available from the PHY code and because U-Boot does not support changing the mode dynamically anyway, we can just mux the controller to MUSB if it is enabled and mux it to HCI otherwise. This fixes USB peripheral support for platforms with PHY0 dual-route, especially H3/H5 and V3s. Signed-off-by: Paul Kocialkowski Signed-off-by: Andre Przywara --- drivers/phy/allwinner/phy-sun4i-usb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 5723c98032..82713b8381 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -313,9 +313,21 @@ static int sun4i_usb_phy_init(struct phy *phy) data->cfg->disc_thresh, PHY_DISCON_TH_LEN); } +#ifdef CONFIG_USB_MUSB_SUNXI + /* Needed for HCI and conflicts with MUSB, keep PHY0 on MUSB */ + if (usb_phy->id != 0) + sun4i_usb_phy_passby(phy, true); + + /* Route PHY0 to MUSB to allow USB gadget */ + if (data->cfg->phy0_dual_route) + sun4i_usb_phy0_reroute(data, true); +#else sun4i_usb_phy_passby(phy, true); - sun4i_usb_phy0_reroute(data, true); + /* Route PHY0 to HCI to allow USB host */ + if (data->cfg->phy0_dual_route) + sun4i_usb_phy0_reroute(data, false); +#endif return 0; } From f9d1324775a08c7892b31b26f24169e024b665ec Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 13:53:05 +0100 Subject: [PATCH 05/17] sunxi: clock: H6/H616: Fix PLL clock factor encodings Most clock factors and dividers in the H6 PLLs use a "+1 encoding", which we were missing on two occasions. This fixes the MMC clock setup on the H6, which could be slightly off due to the wrong parent frequency: mmc 2 set mod-clk req 52000000 parent 1176000000 n 2 m 12 rate 49000000 Also the CPU frequency (PLL1) was a tad too high before. For PLL5 (DRAM) we already accounted for this +1, but in the DRAM code itself, not in the bit field macro. Move this there to be aligned with what the other SoCs and other PLLs do. Signed-off-by: Andre Przywara Reviewed-by: Jernej Skrabec --- arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h | 4 ++-- arch/arm/mach-sunxi/clock_sun50i_h6.c | 2 +- arch/arm/mach-sunxi/dram_sun50i_h6.c | 2 +- arch/arm/mach-sunxi/dram_sun50i_h616.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 62abfc4ef6..2e076cf594 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -233,14 +233,14 @@ struct sunxi_ccm_reg { #define CCM_PLL1_OUT_EN BIT(27) #define CCM_PLL1_CLOCK_TIME_2 (2 << 24) #define CCM_PLL1_CTRL_P(p) ((p) << 16) -#define CCM_PLL1_CTRL_N(n) ((n) << 8) +#define CCM_PLL1_CTRL_N(n) (((n) - 1) << 8) /* pll5 bit field */ #define CCM_PLL5_CTRL_EN BIT(31) #define CCM_PLL5_LOCK_EN BIT(29) #define CCM_PLL5_LOCK BIT(28) #define CCM_PLL5_OUT_EN BIT(27) -#define CCM_PLL5_CTRL_N(n) ((n) << 8) +#define CCM_PLL5_CTRL_N(n) (((n) - 1) << 8) #define CCM_PLL5_CTRL_DIV1(div1) ((div1) << 0) #define CCM_PLL5_CTRL_DIV2(div0) ((div0) << 1) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 492fc4a3fc..a947463e0a 100644 --- a/arch/arm/mach-sunxi/clock_sun50i_h6.c +++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c @@ -94,7 +94,7 @@ unsigned int clock_get_pll6(void) int m = IS_ENABLED(CONFIG_MACH_SUN50I_H6) ? 4 : 2; uint32_t rval = readl(&ccm->pll6_cfg); - int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT); + int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1; int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >> CCM_PLL6_CTRL_DIV1_SHIFT) + 1; int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >> diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c index 32ec0bc4cd..d05375c902 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h6.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c @@ -171,7 +171,7 @@ static void mctl_sys_init(struct dram_para *para) /* Set PLL5 rate to doubled DRAM clock rate */ writel(CCM_PLL5_CTRL_EN | CCM_PLL5_LOCK_EN | - CCM_PLL5_CTRL_N(para->clk * 2 / 24 - 1), &ccm->pll5_cfg); + CCM_PLL5_CTRL_N(para->clk * 2 / 24), &ccm->pll5_cfg); mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK); /* Configure DRAM mod clock */ diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c index ef5876971c..acdfb3ceef 100644 --- a/arch/arm/mach-sunxi/dram_sun50i_h616.c +++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c @@ -113,7 +113,7 @@ static void mctl_sys_init(struct dram_para *para) /* Set PLL5 rate to doubled DRAM clock rate */ writel(CCM_PLL5_CTRL_EN | CCM_PLL5_LOCK_EN | CCM_PLL5_OUT_EN | - CCM_PLL5_CTRL_N(para->clk * 2 / 24 - 1), &ccm->pll5_cfg); + CCM_PLL5_CTRL_N(para->clk * 2 / 24), &ccm->pll5_cfg); mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK); /* Configure DRAM mod clock */ From 8e6eed574806794446aed226a2402be90bfd6d1f Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 7 Jun 2021 19:42:45 +0200 Subject: [PATCH 06/17] configs: OrangePi PC2: Update defaults OrangePi PC2 board has DRAM with ODT, so enable it. H5 SoC is also connected to voltage regulator. It's default value is reasonable at reset, but might be too low when rebooting with a lower voltage programmed. In order to avoid instability, enable driver for it and set it to appropriate voltage. Signed-off-by: Jernej Skrabec Tested-by: Andre Przywara [Andre: remove original ZQ value change, adjust commit message] Signed-off-by: Andre Przywara --- configs/orangepi_pc2_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig index 5a538e133f..528e5f33ac 100644 --- a/configs/orangepi_pc2_defconfig +++ b/configs/orangepi_pc2_defconfig @@ -5,11 +5,13 @@ CONFIG_SPL=y CONFIG_MACH_SUN50I_H5=y CONFIG_DRAM_CLK=672 CONFIG_DRAM_ZQ=3881977 -# CONFIG_DRAM_ODT_EN is not set CONFIG_MACPWR="PD6" CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPL_I2C_SUPPORT=y CONFIG_SUN8I_EMAC=y +CONFIG_SY8106A_POWER=y +CONFIG_SY8106A_VOUT1_VOLT=1100 CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_MUSB_GADGET=y From 2527b24f39d8f27ba2fd922ca27a1f14119cfa1b Mon Sep 17 00:00:00 2001 From: Yu-Tung Chang Date: Sat, 19 Jun 2021 16:16:45 +0800 Subject: [PATCH 07/17] sunxi: h3: Add initial ZeroPi support ZeroPi is a new board of high performance with low cost designed by FriendlyElec., using the Allwinner H3 SOC. ZeroPi features - Allwinner H3, Quad-core Cortex-A7@1.2GHz - 256MB/512MB DDR3 RAM - microsd slot - 10/100/1000Mbps Ethernet - Debug Serial Port - DC 5V/2A power-supply Signed-off-by: Yu-Tung Chang Reviewed-by: Andre Przywara Signed-off-by: Andre Przywara --- arch/arm/dts/Makefile | 3 +- arch/arm/dts/sun8i-h3-zeropi.dts | 85 ++++++++++++++++++++++++++++++++ board/sunxi/MAINTAINERS | 6 +++ configs/zeropi_defconfig | 13 +++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/sun8i-h3-zeropi.dts create mode 100644 configs/zeropi_defconfig diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 59d8078558..7ce3ae6caa 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -612,7 +612,8 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \ sun8i-h3-orangepi-plus.dtb \ sun8i-h3-orangepi-plus2e.dtb \ sun8i-h3-orangepi-zero-plus2.dtb \ - sun8i-h3-rervision-dvk.dtb + sun8i-h3-rervision-dvk.dtb \ + sun8i-h3-zeropi.dtb dtb-$(CONFIG_MACH_SUN8I_R40) += \ sun8i-r40-bananapi-m2-ultra.dtb \ sun8i-v40-bananapi-m2-berry.dtb diff --git a/arch/arm/dts/sun8i-h3-zeropi.dts b/arch/arm/dts/sun8i-h3-zeropi.dts new file mode 100644 index 0000000000..7d3e7323b6 --- /dev/null +++ b/arch/arm/dts/sun8i-h3-zeropi.dts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Yu-Tung Chang + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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 file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sun8i-h3-nanopi.dtsi" + +/ { + model = "FriendlyARM ZeroPi"; + compatible = "friendlyarm,zeropi", "allwinner,sun8i-h3"; + + aliases { + ethernet0 = &emac; + }; + + reg_gmac_3v3: gmac-3v3 { + compatible = "regulator-fixed"; + regulator-name = "gmac-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <100000>; + enable-active-high; + gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */ + }; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@7 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <7>; + }; +}; + +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&emac_rgmii_pins>; + phy-supply = <®_gmac_3v3>; + phy-handle = <&ext_rgmii_phy>; + phy-mode = "rgmii-id"; + + allwinner,leds-active-low; + status = "okay"; +}; + +&usb_otg { + status = "okay"; + dr_mode = "host"; +}; diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index 76eba2ad20..4fc26077b2 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -529,3 +529,9 @@ YONES TOPTECH BS1078 V2 BOARD M: Peter Korsgaard S: Maintained F: configs/Yones_Toptech_BS1078_V2_defconfig + +ZEROPI BOARD +M: Yu-Tung Chang +S: Maintained +F: configs/zeropi_defconfig +F: arch/arm/dts/sun8i-h3-zeropi.dts diff --git a/configs/zeropi_defconfig b/configs/zeropi_defconfig new file mode 100644 index 0000000000..11f3715e6d --- /dev/null +++ b/configs/zeropi_defconfig @@ -0,0 +1,13 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-zeropi" +CONFIG_SPL=y +CONFIG_MACH_SUN8I_H3=y +CONFIG_DRAM_CLK=408 +CONFIG_MACPWR="PD6" +# CONFIG_VIDEO_DE2 is not set +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_CONSOLE_MUX=y +CONFIG_SUN8I_EMAC=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y From 212224ed68f12616bcdc5384dd87d6454dc68b57 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 26 Apr 2021 00:38:04 +0100 Subject: [PATCH 08/17] sunxi: board: Add H616 MMC2 pins We hardcode the pinctrl setting for the MMC controllers in boards.c, since we need them also in the SPL, where there is no DT yet. Add the respective setting for the H616 SoC, to enable eMMC on boards with this SoC as well. Also to make diagnosing this problem easier, print a warning if a board tries to setup MMC2 pins without a respective SoC setting being defined. Signed-off-by: Andre Przywara Reviewed-by: Jagan Teki Reviewed-by: Jernej Skrabec --- board/sunxi/board.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 21651a1bfc..67acc01d83 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -555,6 +555,17 @@ static void mmc_pinmux_setup(int sdc) sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } +#elif defined(CONFIG_MACH_SUN50I_H616) + /* SDC2: PC0-PC1, PC5-PC6, PC8-PC11, PC13-PC16 */ + for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(16); pin++) { + if (pin > SUNXI_GPC(1) && pin < SUNXI_GPC(5)) + continue; + if (pin == SUNXI_GPC(7) || pin == SUNXI_GPC(12)) + continue; + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2); + sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); + sunxi_gpio_set_drv(pin, 3); + } #elif defined(CONFIG_MACH_SUN9I) /* SDC2: PC6-PC16 */ for (pin = SUNXI_GPC(6); pin <= SUNXI_GPC(16); pin++) { @@ -562,6 +573,8 @@ static void mmc_pinmux_setup(int sdc) sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP); sunxi_gpio_set_drv(pin, 2); } +#else + puts("ERROR: No pinmux setup defined for MMC2!\n"); #endif break; From b8747854de7f4aaa8d8a60842c5a97358d4ad891 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 28 Apr 2021 21:29:55 +0100 Subject: [PATCH 09/17] sunxi: H616: Enable full 4GB of DRAM The H616 is our first supported Allwinner SoC which goes beyond the 4GB address space "barrier", by having more than 32 address bits. Lift the preliminary 3GB DRAM limit for the H616, and update the page table setup on the way, to actually map that last GB as well. As not all devices are actually capable of dealing with more than 32 bits (the DMA in the EMAC for instance), we also limit U-Boot's own DRAM usage to 4GB on the way. Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/Kconfig | 4 ++-- arch/arm/mach-sunxi/board.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index bc8509b72a..8e7aa8437d 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -190,10 +190,10 @@ config MACH_SUNXI_H3_H5 select SUPPORT_SPL # TODO: try out A80's 8GiB DRAM space -# TODO: H616 supports 4 GiB DRAM space config SUNXI_DRAM_MAX_SIZE hex - default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 || MACH_SUN50I_H616 + default 0x100000000 if MACH_SUN50I_H616 + default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 default 0x80000000 choice diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 9b84132eda..e979e426dd 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -56,7 +56,7 @@ static struct mm_region sunxi_mem_map[] = { /* RAM */ .virt = 0x40000000UL, .phys = 0x40000000UL, - .size = 0xC0000000UL, + .size = CONFIG_SUNXI_DRAM_MAX_SIZE, .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE }, { @@ -65,6 +65,15 @@ static struct mm_region sunxi_mem_map[] = { } }; struct mm_region *mem_map = sunxi_mem_map; + +ulong board_get_usable_ram_top(ulong total_size) +{ + /* Some devices (like the EMAC) have a 32-bit DMA limit. */ + if (gd->ram_top > (1ULL << 32)) + return 1ULL << 32; + + return gd->ram_top; +} #endif static int gpio_init(void) From f4826fb137a4514163aeea31ca8d17e70fcb37e4 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 18 Dec 2020 22:02:11 +0000 Subject: [PATCH 10/17] mmc: sunxi: Avoid #ifdefs in delay and width setup The delay and bus-width setup are slightly different across the Allwinner SoC generations, and we covered this so far with some preprocessor conditionals. Use the more readable IS_ENABLE() instead. Signed-off-by: Andre Przywara Reviewed-by: Jaehoon Chung --- drivers/mmc/sunxi_mmc.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 3503ccdb2e..87b79fcf5e 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -156,23 +156,19 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) } else if (hz <= 25000000) { oclk_dly = 0; sclk_dly = 5; -#ifdef CONFIG_MACH_SUN9I - } else if (hz <= 52000000) { - oclk_dly = 5; - sclk_dly = 4; } else { - /* hz > 52000000 */ - oclk_dly = 2; + if (IS_ENABLED(CONFIG_MACH_SUN9I)) { + if (hz <= 52000000) + oclk_dly = 5; + else + oclk_dly = 2; + } else { + if (hz <= 52000000) + oclk_dly = 3; + else + oclk_dly = 1; + } sclk_dly = 4; -#else - } else if (hz <= 52000000) { - oclk_dly = 3; - sclk_dly = 4; - } else { - /* hz > 52000000 */ - oclk_dly = 1; - sclk_dly = 4; -#endif } if (new_mode) { @@ -521,10 +517,11 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; cfg->host_caps = MMC_MODE_4BIT; -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_SUN50I_GEN_H6) - if (sdc_no == 2) + + if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) || + IS_ENABLED(CONFIG_SUN50I_GEN_H6)) && (sdc_no == 2)) cfg->host_caps = MMC_MODE_8BIT; -#endif + cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; From ca496baf9b84913c941f8247fc416b39f158d142 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 29 Apr 2021 09:31:58 +0100 Subject: [PATCH 11/17] mmc: sunxi: Fix warnings with CONFIG_PHYS_64BIT When enabling PHYS_64BIT on 32-bit platforms, we get two warnings about pointer casts in sunxi_mmc.c. Those are related to MMIO addresses, which are always below 1GB on all Allwinner SoCs, so there is no problem with anything having more than 32 bits. Add the proper casts to make it compile cleanly. Signed-off-by: Andre Przywara Reviewed-by: Jaehoon Chung --- drivers/mmc/sunxi_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 87b79fcf5e..869af993d3 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -631,14 +631,14 @@ static int sunxi_mmc_probe(struct udevice *dev) cfg->f_min = 400000; cfg->f_max = 52000000; - priv->reg = (void *)dev_read_addr(dev); + priv->reg = dev_read_addr_ptr(dev); /* We don't have a sunxi clock driver so find the clock address here */ ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, 1, &args); if (ret) return ret; - ccu_reg = (u32 *)ofnode_get_addr(args.node); + ccu_reg = (u32 *)(uintptr_t)ofnode_get_addr(args.node); priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000; priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4; From 937ee31e32ee79393bbba29cdf2543e9020a2e88 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 09:57:47 +0100 Subject: [PATCH 12/17] mmc: sunxi: Fix MMC clock parent selection Most Allwinner SoCs which use the so called "new timing mode" in their MMC controllers actually use the double-rate PLL6/PERIPH0 clock as their parent input clock. This is interestingly enough compensated by a hidden "by 2" post-divider in the mod clock, so the divider and actual output rate stay the same. Even though for the H6 and H616 (but only for them!) we use the doubled input clock for the divider computation, we never accounted for the implicit post-divider, so the clock was only half the speed on those SoCs. This didn't really matter so far, as our slow MMIO routine limits the transfer speed anyway, but we will fix this soon. Clean up the code around that selection, to always use the normal PLL6 (PERIPH0(1x)) clock as an input. As the rate and divider are the same, that makes no difference. Explain the hardware differences in a comment. Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h | 2 +- drivers/mmc/sunxi_mmc.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h index 2e076cf594..37df4410ea 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h @@ -326,7 +326,7 @@ struct sunxi_ccm_reg { #define CCM_MMC_CTRL_M(x) ((x) - 1) #define CCM_MMC_CTRL_N(x) ((x) << 8) #define CCM_MMC_CTRL_OSCM24 (0x0 << 24) -#define CCM_MMC_CTRL_PLL6X2 (0x1 << 24) +#define CCM_MMC_CTRL_PLL6 (0x1 << 24) #define CCM_MMC_CTRL_PLL_PERIPH2X2 (0x2 << 24) #define CCM_MMC_CTRL_ENABLE (0x1 << 31) /* H6 doesn't have these delays */ diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 869af993d3..bc68debdad 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -124,10 +124,14 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) #ifdef CONFIG_MACH_SUN9I pll = CCM_MMC_CTRL_PLL_PERIPH0; pll_hz = clock_get_pll4_periph0(); -#elif defined(CONFIG_SUN50I_GEN_H6) - pll = CCM_MMC_CTRL_PLL6X2; - pll_hz = clock_get_pll6() * 2; #else + /* + * SoCs since the A64 (H5, H6, H616) actually use the doubled + * rate of PLL6/PERIPH0 as an input clock, but compensate for + * that with a fixed post-divider of 2 in the mod clock. + * This cancels each other out, so for simplicity we just + * pretend it's always PLL6 without a post divider here. + */ pll = CCM_MMC_CTRL_PLL6; pll_hz = clock_get_pll6(); #endif From f85c0912b66c503074fa28914edef144d0052922 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 09:57:47 +0100 Subject: [PATCH 13/17] mmc: sunxi: Cleanup "new timing mode" selection Among the SoCs using the "new timing mode", only the A83T needs to explicitly switch to that mode. By just defining the symbol for that one odd A83T bit to 0 for any other SoCs, we can always OR that in, and save the confusing nested #ifdefs. Clean up the also confusing new_mode setting on the way. Signed-off-by: Andre Przywara Reviewed-by: Jaehoon Chung --- drivers/mmc/sunxi_mmc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index bc68debdad..33cedb4edb 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -23,6 +23,10 @@ #include #include +#ifndef CCM_MMC_CTRL_MODE_SEL_NEW +#define CCM_MMC_CTRL_MODE_SEL_NEW 0 +#endif + struct sunxi_mmc_plat { struct mmc_config cfg; struct mmc mmc; @@ -102,13 +106,10 @@ static int mmc_resource_init(int sdc_no) static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) { unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; - bool new_mode = true; + bool new_mode = IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE); bool calibrate = false; u32 val = 0; - if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE)) - new_mode = false; - /* A83T support new mode only on eMMC */ if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) new_mode = false; @@ -176,12 +177,8 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) } if (new_mode) { -#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE -#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH - val = CCM_MMC_CTRL_MODE_SEL_NEW; -#endif + val |= CCM_MMC_CTRL_MODE_SEL_NEW; setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW); -#endif } else if (!calibrate) { /* * Use hardcoded delay values if controller doesn't support From b6e3bf1e0d2980a1ed0c07f1a6e99b62c9690538 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 10:04:41 +0100 Subject: [PATCH 14/17] mmc: sunxi: Enable "new timing mode" on all new SoCs All SoCs since the Allwinner A64 (H5, H6, R40, H616) feature the so called "new timing mode", so enable this in Kconfig for those SoCs. Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 8e7aa8437d..49f94f095c 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -152,6 +152,7 @@ config SUN50I_GEN_H6 bool select FIT select SPL_LOAD_FIT + select MMC_SUNXI_HAS_NEW_MODE select SUPPORT_SPL ---help--- Select this for sunxi SoCs which have H6 like peripherals, clocks @@ -297,6 +298,7 @@ config MACH_SUN8I_R40 select CPU_V7_HAS_VIRT select ARCH_SUPPORT_PSCI select SUNXI_GEN_SUN6I + select MMC_SUNXI_HAS_NEW_MODE select SUPPORT_SPL select SUNXI_DRAM_DW select SUNXI_DRAM_DW_32BIT @@ -346,6 +348,7 @@ config MACH_SUN50I_H5 bool "sun50i (Allwinner H5)" select ARM64 select MACH_SUNXI_H3_H5 + select MMC_SUNXI_HAS_NEW_MODE select FIT select SPL_LOAD_FIT From b5dd39c96e10a794a5ba8e858ad0da2b0ac70191 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 10:06:24 +0100 Subject: [PATCH 15/17] mmc: sunxi: Cleanup and fix self-calibration code Newer SoCs have a self calibration feature, which avoids us writing hard coded phase delay values into the controller. Consolidate the code by avoiding unnecessary #ifdefs, and also enabling the feature for all those newer SoCs. Signed-off-by: Andre Przywara --- drivers/mmc/sunxi_mmc.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 33cedb4edb..a30fd8fbdb 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -103,21 +103,29 @@ static int mmc_resource_init(int sdc_no) } #endif +/* + * All A64 and later MMC controllers feature auto-calibration. This would + * normally be detected via the compatible string, but we need something + * which works in the SPL as well. + */ +static bool sunxi_mmc_can_calibrate(void) +{ + return IS_ENABLED(CONFIG_MACH_SUN50I) || + IS_ENABLED(CONFIG_MACH_SUN50I_H5) || + IS_ENABLED(CONFIG_SUN50I_GEN_H6) || + IS_ENABLED(CONFIG_MACH_SUN8I_R40); +} + static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) { unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; bool new_mode = IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE); - bool calibrate = false; u32 val = 0; /* A83T support new mode only on eMMC */ if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) new_mode = false; -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6) - calibrate = true; -#endif - if (hz <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; pll_hz = 24000000; @@ -179,7 +187,9 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) if (new_mode) { val |= CCM_MMC_CTRL_MODE_SEL_NEW; setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW); - } else if (!calibrate) { + } + + if (!sunxi_mmc_can_calibrate()) { /* * Use hardcoded delay values if controller doesn't support * calibration @@ -237,14 +247,15 @@ static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc) rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; writel(rval, &priv->reg->clkcr); -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6) +#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) /* A64 supports calibration of delays on MMC controller and we * have to set delay of zero before starting calibration. * Allwinner BSP driver sets a delay only in the case of * using HS400 which is not supported by mainline U-Boot or * Linux at the moment */ - writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl); + if (sunxi_mmc_can_calibrate()) + writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl); #endif /* Re-enable Clock */ From 9faae5457f5221f2f036153399ab38f37114a871 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 5 May 2021 11:33:40 +0100 Subject: [PATCH 16/17] mmc: sunxi: Increase MMIO FIFO read performance To avoid the complexity of DMA operations (with chained descriptors), we use repeated MMIO reads and writes to the SD_FIFO_REG, which allows us to drain or fill the MMC data buffer FIFO very easily. However those MMIO accesses are somewhat costly, so this limits our MMC performance, to between 17 and 22 MB/s, but down to 9.5 MB/s on the H6 (partly due to the lower AHB1 frequency). As it turns out we read the FIFO status register after *every* word we read or write, which effectively doubles the number of MMIO accesses, thus effectively more than halving our performance. To avoid this overhead, we can make use of the FIFO level bits, which are in the very same FIFO status registers. So for a read request, we now can collect as many words as the FIFO level originally indicated, and only then need to update the status register. We don't know for sure the size of the FIFO (and it seems to differ across SoCs anyway), so writing is more fragile, which is why we still use the old method for that. If we find a minimum FIFO size available on all SoCs, we could use that, in a later optimisation. This patch increases the eMMC read speed on a Pine64-LTS from about 22MB/s to 44 MB/s. SD card reads don't gain that much, but with 23 MB/s we now reach the practical limit for 3.3V SD cards. On the H6 we double our transfer speed, from 9.5 MB/s to 19.7 MB/s. Signed-off-by: Andre Przywara --- arch/arm/include/asm/arch-sunxi/mmc.h | 1 + drivers/mmc/sunxi_mmc.c | 39 +++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h index 340e25b04d..5daacf10eb 100644 --- a/arch/arm/include/asm/arch-sunxi/mmc.h +++ b/arch/arm/include/asm/arch-sunxi/mmc.h @@ -119,6 +119,7 @@ struct sunxi_mmc { #define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8) #define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9) #define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10) +#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg) (((reg) >> 17) & 0x3fff) #define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index a30fd8fbdb..115b519546 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -311,8 +311,9 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc, SUNXI_MMC_STATUS_FIFO_FULL; unsigned i; unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); - unsigned byte_cnt = data->blocksize * data->blocks; - unsigned timeout_msecs = byte_cnt >> 8; + unsigned word_cnt = (data->blocksize * data->blocks) >> 2; + unsigned timeout_msecs = word_cnt >> 6; + uint32_t status; unsigned long start; if (timeout_msecs < 2000) @@ -323,16 +324,38 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc, start = get_timer(0); - for (i = 0; i < (byte_cnt >> 2); i++) { - while (readl(&priv->reg->status) & status_bit) { + for (i = 0; i < word_cnt;) { + unsigned int in_fifo; + + while ((status = readl(&priv->reg->status)) & status_bit) { if (get_timer(start) > timeout_msecs) return -1; } - if (reading) - buff[i] = readl(&priv->reg->fifo); - else - writel(buff[i], &priv->reg->fifo); + /* + * For writing we do not easily know the FIFO size, so have + * to check the FIFO status after every word written. + * TODO: For optimisation we could work out a minimum FIFO + * size across all SoCs, and use that together with the current + * fill level to write chunks of words. + */ + if (!reading) { + writel(buff[i++], &priv->reg->fifo); + continue; + } + + /* + * The status register holds the current FIFO level, so we + * can be sure to collect as many words from the FIFO + * register without checking the status register after every + * read. That saves half of the costly MMIO reads, effectively + * doubling the read performance. + */ + for (in_fifo = SUNXI_MMC_STATUS_FIFO_LEVEL(status); + in_fifo > 0; + in_fifo--) + buff[i++] = readl_relaxed(&priv->reg->fifo); + dmb(); } return 0; From ac62dadb37cb57fdf2117f191c32f9992f3e5eca Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 21 Apr 2021 09:33:04 +0100 Subject: [PATCH 17/17] mmc: sunxi: Use mmc_of_parse() At the moment the Allwinner MMC driver parses the bus-width and non-removable DT properties itself, in the probe() routine. There is actually a generic function provided by the MMC framework doing this job, also it parses more generic properties like broken-cd and advanced transfer modes. Drop our own code and call mmc_of_parse() instead, to get all new features for free. Signed-off-by: Andre Przywara Reviewed-by: Jaehoon Chung --- drivers/mmc/sunxi_mmc.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 115b519546..178b8cf106 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -37,7 +37,6 @@ struct sunxi_mmc_priv { uint32_t *mclkreg; unsigned fatal_err; struct gpio_desc cd_gpio; /* Change Detect GPIO */ - int cd_inverted; /* Inverted Card Detect */ struct sunxi_mmc *reg; struct mmc_config cfg; }; @@ -612,12 +611,21 @@ static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, static int sunxi_mmc_getcd(struct udevice *dev) { + struct mmc *mmc = mmc_get_mmc_dev(dev); struct sunxi_mmc_priv *priv = dev_get_priv(dev); + /* If polling, assume that the card is always present. */ + if ((mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE) || + (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL)) + return 1; + if (dm_gpio_is_valid(&priv->cd_gpio)) { int cd_state = dm_gpio_get_value(&priv->cd_gpio); - return cd_state ^ priv->cd_inverted; + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !cd_state; + else + return cd_state; } return 1; } @@ -649,23 +657,21 @@ static int sunxi_mmc_probe(struct udevice *dev) struct mmc_config *cfg = &plat->cfg; struct ofnode_phandle_args args; u32 *ccu_reg; - int bus_width, ret; + int ret; cfg->name = dev->name; - bus_width = dev_read_u32_default(dev, "bus-width", 1); cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; - cfg->host_caps = 0; - if (bus_width == 8) - cfg->host_caps |= MMC_MODE_8BIT; - if (bus_width >= 4) - cfg->host_caps |= MMC_MODE_4BIT; - cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; cfg->f_min = 400000; cfg->f_max = 52000000; + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; + priv->reg = dev_read_addr_ptr(dev); /* We don't have a sunxi clock driver so find the clock address here */ @@ -691,17 +697,13 @@ static int sunxi_mmc_probe(struct udevice *dev) return ret; /* This GPIO is optional */ - if (!dev_read_bool(dev, "non-removable") && - !gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, + if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN)) { int cd_pin = gpio_get_number(&priv->cd_gpio); sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP); } - /* Check if card detect is inverted */ - priv->cd_inverted = dev_read_bool(dev, "cd-inverted"); - upriv->mmc = &plat->mmc; /* Reset controller */