diff options
author | Tom Rini <trini@konsulko.com> | 2021-07-09 21:08:52 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-07-09 21:08:52 -0400 |
commit | 490101a5e5df65238b900b21b81361bc4b13da2e (patch) | |
tree | bcc328c5330a32a081c0229588b1e612da40f03d | |
parent | db473cd489002bd37a77cea4ad607fe8a2b9ca21 (diff) | |
parent | ac62dadb37cb57fdf2117f191c32f9992f3e5eca (diff) | |
download | u-boot-490101a5e5df65238b900b21b81361bc4b13da2e.zip u-boot-490101a5e5df65238b900b21b81361bc4b13da2e.tar.gz u-boot-490101a5e5df65238b900b21b81361bc4b13da2e.tar.bz2 |
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sunxiWIP/09Jul2021
Aside from the usual fixes and updates one visible change is the
MMC update, which fixes some lingering bugs and gives a decent speed
increase on some boards (9->19 MB/s on H6, 21->43 MB/s on A64 eMMC).
I am keeping an watchful eye on bug reports here, to spot any correctness
regressions.
Another change is finally the enablement of the first USB host port on
many boards without micro-USB (data) sockets, like the Pine64 family.
That doubles the number of usable USB ports from 1 to 2 on those boards.
Some smaller fixes, 4GB DRAM support (on the H616) and a new board (ZeroPi)
conclude this first round of changes.
Compile-tested for all 157 sunxi boards, boot-tested on Pine H64,
Pine64-LTS, OrangePi Zero 2 and BananaPi M2 Berry.
Summary:
- DT update for H3/H5/H6
- Enable first USB port on boards without micro-USB
- ZeroPi board support
- 4GB DRAM support for H616 boards
- MMC fixes and speed improvement
- some fixes
42 files changed, 737 insertions, 136 deletions
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 59d8078..7ce3ae6 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/sun50i-h5-bananapi-m2-plus-v1.2.dts b/arch/arm/dts/sun50i-h5-bananapi-m2-plus-v1.2.dts index 2e2b14c..8857a37 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 <arm/sunxi-bananapi-m2-plus-v1.2.dtsi> / { 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 0000000..b265720 --- /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 <wens@csie.org> + +/ { + 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 a918066..016da3e 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 <sunxi-libretech-all-h3-cc.dtsi> / { 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 df1b926..6e30a56 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 4f9ba53..4c3921a 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 b059e20..02f8e72 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 70b5f09..1010c1b 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 = <BTN_0>; 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 cb44bfa..74e0444 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 ef5ca64..d13980e 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 c95a685..22530ac 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 3a1c8b2..ab860e2 100644 --- a/arch/arm/dts/sun50i-h5.dtsi +++ b/arch/arm/dts/sun50i-h5.dtsi @@ -3,6 +3,8 @@ #include <sunxi-h3-h5.dtsi> +#include <dt-bindings/thermal/thermal.h> + / { 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 = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, @@ -54,6 +67,7 @@ timer { compatible = "arm,armv8-timer"; + arm,no-tick-in-suspend; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 @@ -107,6 +121,19 @@ resets = <&ccu RST_BUS_CE>; }; + 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 = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; + 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 @@ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>; 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/sun50i-h6-beelink-gs1.dts b/arch/arm/dts/sun50i-h6-beelink-gs1.dts index 7c9dbde..b580804 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 1a5eddc..8c6e853 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 15c9dd8..7e83f61 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 ebc120a..da0875b 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 961732c..b868ad1 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 8a62a9f..af8b7d0 100644 --- a/arch/arm/dts/sun50i-h6.dtsi +++ b/arch/arm/dts/sun50i-h6.dtsi @@ -436,6 +436,7 @@ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; + max-frequency = <150000000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -452,6 +453,7 @@ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins>; + max-frequency = <150000000>; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -468,6 +470,7 @@ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; 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 = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; + 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>; 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 d277d04..f3f7a2c 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 45a2444..62b5280 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 6b14927..8e7dfcf 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 07867a0..be49eab 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 4df29a6..c7c3e7d 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 71fb732..babf4cf 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 6dbf7b2..b6ca45d 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 b8f46e2..561ea1d 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"; +}; diff --git a/arch/arm/dts/sun8i-h3-zeropi.dts b/arch/arm/dts/sun8i-h3-zeropi.dts new file mode 100644 index 0000000..7d3e732 --- /dev/null +++ b/arch/arm/dts/sun8i-h3-zeropi.dts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Yu-Tung Chang <mtwget@gmail.com> + * + * 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/arch/arm/dts/sun8i-h3.dtsi b/arch/arm/dts/sun8i-h3.dtsi index 20217e2..4e89701 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 <dt-bindings/thermal/thermal.h> / { 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 = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, @@ -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 5e9c306..9be1337 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 = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>; + #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 = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; + 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"; }; }; }; 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 62abfc4..37df441 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) @@ -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/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h index 340e25b..5daacf1 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/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index bc8509b..49f94f0 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 @@ -190,10 +191,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 @@ -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 diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 9b84132..e979e42 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) diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c index 492fc4a..a947463 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 32ec0bc..d05375c 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 ef58769..acdfb3c 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 */ diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS index 76eba2a..4fc2607 100644 --- a/board/sunxi/MAINTAINERS +++ b/board/sunxi/MAINTAINERS @@ -529,3 +529,9 @@ YONES TOPTECH BS1078 V2 BOARD M: Peter Korsgaard <peter@korsgaard.com> S: Maintained F: configs/Yones_Toptech_BS1078_V2_defconfig + +ZEROPI BOARD +M: Yu-Tung Chang <mtwget@gmail.com> +S: Maintained +F: configs/zeropi_defconfig +F: arch/arm/dts/sun8i-h3-zeropi.dts diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 21651a1..67acc01 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; diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig index 5a538e1..528e5f3 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 diff --git a/configs/zeropi_defconfig b/configs/zeropi_defconfig new file mode 100644 index 0000000..11f3715 --- /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 diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 3503ccd..178b8cf 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -23,6 +23,10 @@ #include <asm-generic/gpio.h> #include <linux/delay.h> +#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; @@ -33,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; }; @@ -99,24 +102,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 = true; - bool calibrate = false; + bool new_mode = IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE); 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; -#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6) - calibrate = true; -#endif - if (hz <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; pll_hz = 24000000; @@ -124,10 +132,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 @@ -156,33 +168,27 @@ 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; - sclk_dly = 4; -#else - } else if (hz <= 52000000) { - oclk_dly = 3; - sclk_dly = 4; - } else { - /* hz > 52000000 */ - oclk_dly = 1; + 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; -#endif } 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) { + } + + if (!sunxi_mmc_can_calibrate()) { /* * Use hardcoded delay values if controller doesn't support * calibration @@ -240,14 +246,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 */ @@ -303,8 +310,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) @@ -315,16 +323,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; @@ -521,10 +551,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; @@ -580,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; } @@ -617,31 +657,29 @@ 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; - priv->reg = (void *)dev_read_addr(dev); + 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 */ 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; @@ -659,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 */ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 5723c98..82713b8 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; } |