aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-01-25 19:46:02 -0500
committerTom Rini <trini@konsulko.com>2021-01-25 19:46:02 -0500
commite262b2973e22174da666038514d17f0f7171466b (patch)
tree0b0b605f1192d4d2e18c956b6e8ef340b2799bfd
parentc99be953e787cfb2414de67390427e00b6812240 (diff)
parent38be6b838780e8ad0ee80e716752c8843cd87e05 (diff)
downloadu-boot-e262b2973e22174da666038514d17f0f7171466b.zip
u-boot-e262b2973e22174da666038514d17f0f7171466b.tar.gz
u-boot-e262b2973e22174da666038514d17f0f7171466b.tar.bz2
Merge https://gitlab.denx.de/u-boot/custodians/u-boot-sunxiWIP/25Jan2021
- New Allwinner H616 SoC support (sans Ethernet & USB) - H6 DT update - Tanix TX6 TV box support - OrangePi 3 support - OrangePi Zero2 (H616) support
-rw-r--r--arch/arm/cpu/armv8/fel_utils.S5
-rw-r--r--arch/arm/dts/Makefile6
-rw-r--r--arch/arm/dts/sun50i-h6-beelink-gs1.dts70
-rw-r--r--arch/arm/dts/sun50i-h6-cpu-opp.dtsi117
-rw-r--r--arch/arm/dts/sun50i-h6-orangepi-3.dts345
-rw-r--r--arch/arm/dts/sun50i-h6-orangepi-lite2.dts71
-rw-r--r--arch/arm/dts/sun50i-h6-orangepi-one-plus.dts41
-rw-r--r--arch/arm/dts/sun50i-h6-orangepi.dtsi72
-rw-r--r--arch/arm/dts/sun50i-h6-pine-h64.dts102
-rw-r--r--arch/arm/dts/sun50i-h6-tanix-tx6.dts124
-rw-r--r--arch/arm/dts/sun50i-h6.dtsi394
-rw-r--r--arch/arm/dts/sun50i-h616-orangepi-zero2.dts242
-rw-r--r--arch/arm/dts/sun50i-h616.dtsi750
-rw-r--r--arch/arm/dts/sunxi-u-boot.dtsi8
-rw-r--r--arch/arm/include/asm/arch-sunxi/boot0.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h19
-rw-r--r--arch/arm/include/asm/arch-sunxi/cpu.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h7
-rw-r--r--arch/arm/include/asm/arch-sunxi/dram.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h159
-rw-r--r--arch/arm/include/asm/arch-sunxi/gpio.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/mmc.h2
-rw-r--r--arch/arm/include/asm/arch-sunxi/prcm.h247
-rw-r--r--arch/arm/include/asm/arch-sunxi/prcm_sun50i.h47
-rw-r--r--arch/arm/include/asm/arch-sunxi/prcm_sun6i.h247
-rw-r--r--arch/arm/include/asm/arch-sunxi/timer.h2
-rw-r--r--arch/arm/mach-sunxi/Kconfig75
-rw-r--r--arch/arm/mach-sunxi/Makefile4
-rw-r--r--arch/arm/mach-sunxi/board.c26
-rw-r--r--arch/arm/mach-sunxi/clock_sun50i_h6.c37
-rw-r--r--arch/arm/mach-sunxi/cpu_info.c2
-rw-r--r--arch/arm/mach-sunxi/dram_sun50i_h616.c1023
-rw-r--r--arch/arm/mach-sunxi/dram_timings/Makefile2
-rw-r--r--arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c94
-rw-r--r--arch/arm/mach-sunxi/pmic_bus.c6
-rw-r--r--arch/arm/mach-sunxi/rmr_switch.S2
-rw-r--r--board/sunxi/MAINTAINERS16
-rw-r--r--board/sunxi/board.c48
-rw-r--r--common/spl/Kconfig7
-rw-r--r--configs/orangepi_3_defconfig12
-rw-r--r--configs/orangepi_zero2_defconfig13
-rw-r--r--configs/tanix_tx6_defconfig10
-rw-r--r--drivers/clk/sunxi/Kconfig7
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk_h616.c120
-rw-r--r--drivers/gpio/sunxi_gpio.c2
-rw-r--r--drivers/i2c/mvtwsi.c2
-rw-r--r--drivers/mmc/sunxi_mmc.c96
-rw-r--r--drivers/net/sun8i_emac.c3
-rw-r--r--drivers/power/Kconfig14
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/axp305.c83
-rw-r--r--include/axp305.h17
-rw-r--r--include/axp_pmic.h3
-rw-r--r--include/configs/sun50i.h2
-rw-r--r--include/configs/sunxi-common.h7
-rw-r--r--include/dt-bindings/clock/sun50i-h6-r-ccu.h2
-rw-r--r--include/dt-bindings/clock/sun50i-h616-ccu.h115
-rw-r--r--include/dt-bindings/reset/sun50i-h6-r-ccu.h1
-rw-r--r--include/dt-bindings/reset/sun50i-h616-ccu.h70
61 files changed, 4587 insertions, 423 deletions
diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
index 9510dcd..7def44a 100644
--- a/arch/arm/cpu/armv8/fel_utils.S
+++ b/arch/arm/cpu/armv8/fel_utils.S
@@ -40,7 +40,10 @@ ENTRY(return_to_fel)
str w2, [x1]
ldr x0, =0xfa50392f // CPU hotplug magic
-#ifdef CONFIG_MACH_SUN50I_H6
+#ifdef CONFIG_MACH_SUN50I_H616
+ ldr x2, =(SUNXI_R_CPUCFG_BASE + 0x1c0)
+ str w0, [x2], #0x4
+#elif CONFIG_MACH_SUN50I_H6
ldr x2, =(SUNXI_RTC_BASE + 0x1b8) // BOOT_CPU_HP_FLAG_REG
str w0, [x2], #0x4
#else
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 5ff1a31..858b79a 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -612,9 +612,13 @@ dtb-$(CONFIG_MACH_SUN50I_H5) += \
sun50i-h5-orangepi-zero-plus2.dtb
dtb-$(CONFIG_MACH_SUN50I_H6) += \
sun50i-h6-beelink-gs1.dtb \
+ sun50i-h6-orangepi-3.dtb \
sun50i-h6-orangepi-lite2.dtb \
sun50i-h6-orangepi-one-plus.dtb \
- sun50i-h6-pine-h64.dtb
+ sun50i-h6-pine-h64.dtb \
+ sun50i-h6-tanix-tx6.dtb
+dtb-$(CONFIG_MACH_SUN50I_H616) += \
+ sun50i-h616-orangepi-zero2.dtb
dtb-$(CONFIG_MACH_SUN50I) += \
sun50i-a64-amarula-relic.dtb \
sun50i-a64-bananapi-m64.dtb \
diff --git a/arch/arm/dts/sun50i-h6-beelink-gs1.dts b/arch/arm/dts/sun50i-h6-beelink-gs1.dts
index 0dc33c9..7c9dbde 100644
--- a/arch/arm/dts/sun50i-h6-beelink-gs1.dts
+++ b/arch/arm/dts/sun50i-h6-beelink-gs1.dts
@@ -1,11 +1,10 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (C) 2019 Clément Péron <peron.clem@gmail.com>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2019 Clément Péron <peron.clem@gmail.com>
/dts-v1/;
#include "sun50i-h6.dtsi"
+#include "sun50i-h6-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
@@ -25,6 +24,7 @@
connector {
compatible = "hdmi-connector";
type = "a";
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
port {
hdmi_con_in: endpoint {
@@ -33,6 +33,13 @@
};
};
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
leds {
compatible = "gpio-leds";
@@ -51,12 +58,38 @@
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
+
+ sound-spdif {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "sun50i-h6-spdif";
+
+ simple-audio-card,cpu {
+ sound-dai = <&spdif>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&spdif_out>;
+ };
+ };
+
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdca>;
};
&de {
status = "okay";
};
+&dwc3 {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -64,12 +97,17 @@
&emac {
pinctrl-names = "default";
pinctrl-0 = <&ext_rgmii_pins>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-handle = <&ext_rgmii_phy>;
phy-supply = <&reg_aldo2>;
status = "okay";
};
+&gpu {
+ mali-supply = <&reg_dcdcc>;
+ status = "okay";
+};
+
&hdmi {
status = "okay";
};
@@ -201,13 +239,16 @@
reg_dcdca: dcdca {
regulator-always-on;
regulator-min-microvolt = <810000>;
- regulator-max-microvolt = <1080000>;
+ regulator-max-microvolt = <1160000>;
+ regulator-ramp-delay = <2500>;
regulator-name = "vdd-cpu";
};
reg_dcdcc: dcdcc {
+ regulator-enable-ramp-delay = <32000>;
regulator-min-microvolt = <810000>;
regulator-max-microvolt = <1080000>;
+ regulator-ramp-delay = <2500>;
regulator-name = "vdd-gpu";
};
@@ -232,6 +273,11 @@
};
};
+&r_ir {
+ linux,rc-map-name = "rc-beelink-gs1";
+ status = "okay";
+};
+
&r_pio {
/*
* PL0 and PL1 are used for PMIC I2C
@@ -243,6 +289,14 @@
vcc-pm-supply = <&reg_aldo1>;
};
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&spdif {
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_ph_pins>;
@@ -258,3 +312,7 @@
usb0_vbus-supply = <&reg_vcc5v>;
status = "okay";
};
+
+&usb3phy {
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-h6-cpu-opp.dtsi b/arch/arm/dts/sun50i-h6-cpu-opp.dtsi
new file mode 100644
index 0000000..1a5eddc
--- /dev/null
+++ b/arch/arm/dts/sun50i-h6-cpu-opp.dtsi
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Ondrej Jirman <megous@megous.com>
+// Copyright (C) 2020 Clément Péron <peron.clem@gmail.com>
+
+/ {
+ cpu_opp_table: cpu-opp-table {
+ compatible = "allwinner,sun50i-h6-operating-points";
+ nvmem-cells = <&cpu_speed_grade>;
+ opp-shared;
+
+ opp@480000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <480000000>;
+
+ opp-microvolt-speed0 = <880000 880000 1200000>;
+ opp-microvolt-speed1 = <820000 820000 1200000>;
+ opp-microvolt-speed2 = <820000 820000 1200000>;
+ };
+
+ opp@720000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <720000000>;
+
+ opp-microvolt-speed0 = <880000 880000 1200000>;
+ opp-microvolt-speed1 = <820000 820000 1200000>;
+ opp-microvolt-speed2 = <820000 820000 1200000>;
+ };
+
+ opp@816000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <816000000>;
+
+ opp-microvolt-speed0 = <880000 880000 1200000>;
+ opp-microvolt-speed1 = <820000 820000 1200000>;
+ opp-microvolt-speed2 = <820000 820000 1200000>;
+ };
+
+ opp@888000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <888000000>;
+
+ opp-microvolt-speed0 = <880000 880000 1200000>;
+ opp-microvolt-speed1 = <820000 820000 1200000>;
+ opp-microvolt-speed2 = <820000 820000 1200000>;
+ };
+
+ opp@1080000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1080000000>;
+
+ opp-microvolt-speed0 = <940000 940000 1200000>;
+ opp-microvolt-speed1 = <880000 880000 1200000>;
+ opp-microvolt-speed2 = <880000 880000 1200000>;
+ };
+
+ opp@1320000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1320000000>;
+
+ opp-microvolt-speed0 = <1000000 1000000 1200000>;
+ opp-microvolt-speed1 = <940000 940000 1200000>;
+ opp-microvolt-speed2 = <940000 940000 1200000>;
+ };
+
+ opp@1488000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1488000000>;
+
+ opp-microvolt-speed0 = <1060000 1060000 1200000>;
+ opp-microvolt-speed1 = <1000000 1000000 1200000>;
+ opp-microvolt-speed2 = <1000000 1000000 1200000>;
+ };
+
+ opp@1608000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1608000000>;
+
+ opp-microvolt-speed0 = <1090000 1090000 1200000>;
+ opp-microvolt-speed1 = <1030000 1030000 1200000>;
+ opp-microvolt-speed2 = <1030000 1030000 1200000>;
+ };
+
+ opp@1704000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1704000000>;
+
+ opp-microvolt-speed0 = <1120000 1120000 1200000>;
+ opp-microvolt-speed1 = <1060000 1060000 1200000>;
+ opp-microvolt-speed2 = <1060000 1060000 1200000>;
+ };
+
+ opp@1800000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1800000000>;
+
+ opp-microvolt-speed0 = <1160000 1160000 1200000>;
+ opp-microvolt-speed1 = <1100000 1100000 1200000>;
+ opp-microvolt-speed2 = <1100000 1100000 1200000>;
+ };
+ };
+};
+
+&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-h6-orangepi-3.dts b/arch/arm/dts/sun50i-h6-orangepi-3.dts
new file mode 100644
index 0000000..15c9dd8
--- /dev/null
+++ b/arch/arm/dts/sun50i-h6-orangepi-3.dts
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2019 Ondřej Jirman <megous@megous.com>
+
+/dts-v1/;
+
+#include "sun50i-h6.dtsi"
+#include "sun50i-h6-cpu-opp.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "OrangePi 3";
+ compatible = "xunlong,orangepi-3", "allwinner,sun50i-h6";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power {
+ label = "orangepi:red:power";
+ gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+ default-state = "on";
+ };
+
+ status {
+ label = "orangepi:green:status";
+ gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+ };
+ };
+
+ reg_vcc5v: vcc5v {
+ /* board wide 5V supply directly from the DC jack */
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ reg_vcc33_wifi: vcc33-wifi {
+ /* Always on 3.3V regulator for WiFi and BT */
+ compatible = "regulator-fixed";
+ regulator-name = "vcc33-wifi";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ vin-supply = <&reg_vcc5v>;
+ };
+
+ reg_vcc_wifi_io: vcc-wifi-io {
+ /* Always on 1.8V/300mA regulator for WiFi and BT IO */
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-wifi-io";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ vin-supply = <&reg_vcc33_wifi>;
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rtc 1>;
+ clock-names = "ext_clock";
+ reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
+ post-power-on-delay-ms = <200>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdca>;
+};
+
+&de {
+ status = "okay";
+};
+
+&dwc3 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&gpu {
+ mali-supply = <&reg_dcdcc>;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&mmc0 {
+ vmmc-supply = <&reg_cldo1>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ bus-width = <4>;
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <&reg_vcc33_wifi>;
+ vqmmc-supply = <&reg_vcc_wifi_io>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcm: sdio-wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <1 0 IRQ_TYPE_LEVEL_LOW>; /* PM0 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&mmc2 {
+ vmmc-supply = <&reg_cldo1>;
+ vqmmc-supply = <&reg_bldo2>;
+ cap-mmc-hw-reset;
+ non-removable;
+ bus-width = <8>;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&pio {
+ vcc-pc-supply = <&reg_bldo2>;
+ vcc-pd-supply = <&reg_cldo1>;
+ vcc-pg-supply = <&reg_vcc_wifi_io>;
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp805: pmic@36 {
+ compatible = "x-powers,axp805", "x-powers,axp806";
+ reg = <0x36>;
+ interrupt-parent = <&r_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ x-powers,self-working-mode;
+ vina-supply = <&reg_vcc5v>;
+ vinb-supply = <&reg_vcc5v>;
+ vinc-supply = <&reg_vcc5v>;
+ vind-supply = <&reg_vcc5v>;
+ vine-supply = <&reg_vcc5v>;
+ aldoin-supply = <&reg_vcc5v>;
+ bldoin-supply = <&reg_vcc5v>;
+ cldoin-supply = <&reg_vcc5v>;
+
+ regulators {
+ reg_aldo1: aldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pl-led-ir";
+ };
+
+ reg_aldo2: aldo2 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc33-audio-tv-ephy-mac";
+ };
+
+ /* ALDO3 is shorted to CLDO1 */
+ reg_aldo3: aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-1";
+ };
+
+ reg_bldo1: bldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc18-dram-bias-pll";
+ };
+
+ reg_bldo2: bldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-efuse-pcie-hdmi-pc";
+ };
+
+ bldo3 {
+ /* unused */
+ };
+
+ bldo4 {
+ /* unused */
+ };
+
+ reg_cldo1: cldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-2";
+ };
+
+ cldo2 {
+ /* unused */
+ };
+
+ cldo3 {
+ /* unused */
+ };
+
+ reg_dcdca: dcdca {
+ regulator-always-on;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1160000>;
+ regulator-ramp-delay = <2500>;
+ regulator-name = "vdd-cpu";
+ };
+
+ reg_dcdcc: dcdcc {
+ regulator-enable-ramp-delay = <32000>;
+ regulator-min-microvolt = <810000>;
+ regulator-max-microvolt = <1080000>;
+ regulator-ramp-delay = <2500>;
+ regulator-name = "vdd-gpu";
+ };
+
+ reg_dcdcd: dcdcd {
+ regulator-always-on;
+ regulator-min-microvolt = <960000>;
+ regulator-max-microvolt = <960000>;
+ regulator-name = "vdd-sys";
+ };
+
+ reg_dcdce: dcdce {
+ regulator-always-on;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-name = "vcc-dram";
+ };
+
+ sw {
+ /* unused */
+ };
+ };
+ };
+};
+
+&r_ir {
+ status = "okay";
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_ph_pins>;
+ status = "okay";
+};
+
+/* There's the BT part of the AP6256 connected to that UART */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4345c5";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
+ host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
+ shutdown-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
+ max-speed = <1500000>;
+ };
+};
+
+&usb2otg {
+ /*
+ * This board doesn't have a controllable VBUS even though it
+ * does have an ID pin. Using it as anything but a USB host is
+ * unsafe.
+ */
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb2phy {
+ usb0_id_det-gpios = <&pio 2 15 GPIO_ACTIVE_HIGH>; /* PC15 */
+ usb0_vbus-supply = <&reg_vcc5v>;
+ usb3_vbus-supply = <&reg_vcc5v>;
+ status = "okay";
+};
+
+&usb3phy {
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-h6-orangepi-lite2.dts b/arch/arm/dts/sun50i-h6-orangepi-lite2.dts
index e098a24..e877085 100644
--- a/arch/arm/dts/sun50i-h6-orangepi-lite2.dts
+++ b/arch/arm/dts/sun50i-h6-orangepi-lite2.dts
@@ -1,11 +1,74 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (C) 2018 Jagan Teki <jagan@openedev.com>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2018 Jagan Teki <jagan@openedev.com>
#include "sun50i-h6-orangepi.dtsi"
/ {
model = "OrangePi Lite2";
compatible = "xunlong,orangepi-lite2", "allwinner,sun50i-h6";
+
+ aliases {
+ serial1 = &uart1; /* BT-UART */
+ };
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rtc 1>;
+ clock-names = "ext_clock";
+ reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
+ post-power-on-delay-ms = <200>;
+ };
+};
+
+&mmc1 {
+ vmmc-supply = <&reg_cldo2>;
+ vqmmc-supply = <&reg_bldo3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcm: sdio-wifi@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <1 0 IRQ_TYPE_LEVEL_LOW>; /* PM0 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&reg_cldo2 {
+ /*
+ * This regulator is connected with CLDO3.
+ * Before the kernel can support synchronized
+ * enable of coupled regulators, keep them
+ * both always on as a ugly hack.
+ */
+ regulator-always-on;
+};
+
+&reg_cldo3 {
+ /*
+ * This regulator is connected with CLDO2.
+ * See the comments for CLDO2.
+ */
+ regulator-always-on;
+};
+
+/* There's the BT part of the AP6255 connected to that UART */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "brcm,bcm4345c5";
+ clocks = <&rtc 1>;
+ clock-names = "lpo";
+ device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
+ host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
+ shutdown-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
+ max-speed = <1500000>;
+ };
};
diff --git a/arch/arm/dts/sun50i-h6-orangepi-one-plus.dts b/arch/arm/dts/sun50i-h6-orangepi-one-plus.dts
index 12e1756..29a081e 100644
--- a/arch/arm/dts/sun50i-h6-orangepi-one-plus.dts
+++ b/arch/arm/dts/sun50i-h6-orangepi-one-plus.dts
@@ -1,12 +1,43 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (C) 2018 Amarula Solutions
- * Author: Jagan Teki <jagan@amarulasolutions.com>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2018 Amarula Solutions
+// Author: Jagan Teki <jagan@amarulasolutions.com>
#include "sun50i-h6-orangepi.dtsi"
/ {
model = "OrangePi One Plus";
compatible = "xunlong,orangepi-one-plus", "allwinner,sun50i-h6";
+
+ aliases {
+ ethernet0 = &emac;
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-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 */
+ vin-supply = <&reg_aldo2>;
+ };
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rgmii_pins>;
+ phy-mode = "rgmii-id";
+ phy-handle = <&ext_rgmii_phy>;
+ phy-supply = <&reg_gmac_3v3>;
+ allwinner,rx-delay-ps = <200>;
+ allwinner,tx-delay-ps = <200>;
+ status = "okay";
+};
+
+&mdio {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
};
diff --git a/arch/arm/dts/sun50i-h6-orangepi.dtsi b/arch/arm/dts/sun50i-h6-orangepi.dtsi
index 62e2794..ebc120a 100644
--- a/arch/arm/dts/sun50i-h6-orangepi.dtsi
+++ b/arch/arm/dts/sun50i-h6-orangepi.dtsi
@@ -1,8 +1,6 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (C) 2018 Amarula Solutions
- * Author: Jagan Teki <jagan@amarulasolutions.com>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2018 Amarula Solutions
+// Author: Jagan Teki <jagan@amarulasolutions.com>
/dts-v1/;
@@ -22,6 +20,25 @@
stdout-path = "serial0:115200n8";
};
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
leds {
compatible = "gpio-leds";
@@ -47,6 +64,10 @@
};
};
+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -55,6 +76,21 @@
status = "okay";
};
+&gpu {
+ mali-supply = <&reg_dcdcc>;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_cldo1>;
cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
@@ -70,6 +106,12 @@
status = "okay";
};
+&pio {
+ vcc-pc-supply = <&reg_bldo2>;
+ vcc-pd-supply = <&reg_cldo1>;
+ vcc-pg-supply = <&reg_aldo1>;
+};
+
&r_i2c {
status = "okay";
@@ -163,6 +205,7 @@
};
reg_dcdcc: dcdcc {
+ regulator-enable-ramp-delay = <32000>;
regulator-min-microvolt = <810000>;
regulator-max-microvolt = <1080000>;
regulator-name = "vdd-gpu";
@@ -189,6 +232,18 @@
};
};
+&r_ir {
+ status = "okay";
+};
+
+&r_pio {
+ vcc-pm-supply = <&reg_bldo3>;
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_ph_pins>;
@@ -196,7 +251,12 @@
};
&usb2otg {
- dr_mode = "otg";
+ /*
+ * OrangePi Lite 2 and One Plus, where this DT is used, don't
+ * have a controllable VBUS even though they do have an ID pin.
+ * Using it as anything but a USB host is unsafe.
+ */
+ dr_mode = "host";
status = "okay";
};
diff --git a/arch/arm/dts/sun50i-h6-pine-h64.dts b/arch/arm/dts/sun50i-h6-pine-h64.dts
index 1898345..961732c 100644
--- a/arch/arm/dts/sun50i-h6-pine-h64.dts
+++ b/arch/arm/dts/sun50i-h6-pine-h64.dts
@@ -1,30 +1,38 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
/dts-v1/;
#include "sun50i-h6.dtsi"
+#include "sun50i-h6-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
/ {
- model = "Pine H64";
+ model = "Pine H64 model A";
compatible = "pine64,pine-h64", "allwinner,sun50i-h6";
aliases {
ethernet0 = &emac;
serial0 = &uart0;
+ spi0 = &spi0;
};
chosen {
stdout-path = "serial0:115200n8";
};
- connector {
+ ext_osc32k: ext_osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "ext_osc32k";
+ };
+
+ hdmi_connector: connector {
compatible = "hdmi-connector";
type = "a";
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
port {
hdmi_con_in: endpoint {
@@ -52,6 +60,16 @@
};
};
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ gpio = <&pio 2 16 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
reg_usb_vbus: vbus {
compatible = "regulator-fixed";
regulator-name = "usb-vbus";
@@ -63,25 +81,35 @@
};
};
+&cpu0 {
+ cpu-supply = <&reg_dcdca>;
+};
+
+&de {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
&emac {
pinctrl-names = "default";
pinctrl-0 = <&ext_rgmii_pins>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-handle = <&ext_rgmii_phy>;
- phy-supply = <&reg_aldo2>;
+ phy-supply = <&reg_gmac_3v3>;
allwinner,rx-delay-ps = <200>;
allwinner,tx-delay-ps = <200>;
status = "okay";
};
-&mdio {
- ext_rgmii_phy: ethernet-phy@1 {
- compatible = "ethernet-phy-ieee802.3-c22";
- reg = <1>;
- };
-};
-
-&de {
+&gpu {
+ mali-supply = <&reg_dcdcc>;
status = "okay";
};
@@ -95,12 +123,11 @@
};
};
-&ehci0 {
- status = "okay";
-};
-
-&ehci3 {
- status = "okay";
+&mdio {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
};
&mmc0 {
@@ -216,13 +243,16 @@
reg_dcdca: dcdca {
regulator-always-on;
regulator-min-microvolt = <810000>;
- regulator-max-microvolt = <1080000>;
+ regulator-max-microvolt = <1160000>;
+ regulator-ramp-delay = <2500>;
regulator-name = "vdd-cpu";
};
reg_dcdcc: dcdcc {
+ regulator-enable-ramp-delay = <32000>;
regulator-min-microvolt = <810000>;
regulator-max-microvolt = <1080000>;
+ regulator-ramp-delay = <2500>;
regulator-name = "vdd-gpu";
};
@@ -255,10 +285,36 @@
};
};
+&r_ir {
+ status = "okay";
+};
+
&r_pio {
vcc-pm-supply = <&reg_aldo1>;
};
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+/*
+ * The CS pin is shared with the MMC2 CMD pin, so we cannot have the SPI
+ * flash and eMMC at the same time, as one of them would fail probing.
+ * Disable SPI0 in here, to prefer the more useful eMMC. U-Boot can
+ * fix this up in no eMMC is connected.
+ */
+&spi0 {
+ pinctrl-0 = <&spi0_pins>, <&spi0_cs_pin>;
+ pinctrl-names = "default";
+ status = "disabled";
+
+ flash@0 {
+ compatible = "winbond,w25q128", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <4000000>;
+ };
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_ph_pins>;
diff --git a/arch/arm/dts/sun50i-h6-tanix-tx6.dts b/arch/arm/dts/sun50i-h6-tanix-tx6.dts
new file mode 100644
index 0000000..be81330
--- /dev/null
+++ b/arch/arm/dts/sun50i-h6-tanix-tx6.dts
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+
+/dts-v1/;
+
+#include "sun50i-h6.dtsi"
+#include "sun50i-h6-cpu-opp.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Tanix TX6";
+ compatible = "oranth,tanix-tx6", "allwinner,sun50i-h6";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ connector {
+ compatible = "hdmi-connector";
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
+ reg_vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_vdd_cpu_gpu: vdd-cpu-gpu {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd-cpu-gpu";
+ regulator-min-microvolt = <1135000>;
+ regulator-max-microvolt = <1135000>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_vdd_cpu_gpu>;
+};
+
+&de {
+ status = "okay";
+};
+
+&dwc3 {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci3 {
+ status = "okay";
+};
+
+&gpu {
+ mali-supply = <&reg_vdd_cpu_gpu>;
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ vmmc-supply = <&reg_vcc3v3>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci3 {
+ status = "okay";
+};
+
+&r_ir {
+ linux,rc-map-name = "rc-tanix-tx5max";
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_ph_pins>;
+ status = "okay";
+};
+
+&usb2otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb2phy {
+ status = "okay";
+};
+
+&usb3phy {
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-h6.dtsi b/arch/arm/dts/sun50i-h6.dtsi
index a117f47..8a62a9f 100644
--- a/arch/arm/dts/sun50i-h6.dtsi
+++ b/arch/arm/dts/sun50i-h6.dtsi
@@ -1,7 +1,5 @@
-// SPDX-License-Identifier: (GPL-2.0+ or MIT)
-/*
- * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
- */
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/sun50i-h6-ccu.h>
@@ -11,6 +9,7 @@
#include <dt-bindings/reset/sun50i-h6-ccu.h>
#include <dt-bindings/reset/sun50i-h6-r-ccu.h>
#include <dt-bindings/reset/sun8i-de2.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&gic>;
@@ -26,6 +25,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 {
@@ -33,6 +35,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 {
@@ -40,6 +45,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 {
@@ -47,6 +55,9 @@
device_type = "cpu";
reg = <3>;
enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ #cooling-cells = <2>;
};
};
@@ -56,14 +67,6 @@
status = "disabled";
};
- iosc: internal-osc-clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <16000000>;
- clock-accuracy = <300000000>;
- clock-output-names = "iosc";
- };
-
osc24M: osc24M_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
@@ -71,11 +74,13 @@
clock-output-names = "osc24M";
};
- osc32k: osc32k_clk {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
- clock-output-names = "osc32k";
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
};
psci {
@@ -85,6 +90,7 @@
timer {
compatible = "arm,armv8-timer";
+ arm,no-tick-in-suspend;
interrupts = <GIC_PPI 13
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_PPI 14
@@ -130,6 +136,7 @@
clock-names = "bus",
"mod";
resets = <&display_clocks RST_MIXER0>;
+ iommus = <&iommu 0>;
ports {
#address-cells = <1>;
@@ -155,6 +162,30 @@
resets = <&ccu RST_BUS_VE>;
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
allwinner,sram = <&ve_sram 1>;
+ iommus = <&iommu 3>;
+ };
+
+ gpu: gpu@1800000 {
+ compatible = "allwinner,sun50i-h6-mali",
+ "arm,mali-t720";
+ reg = <0x01800000 0x4000>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "job", "mmu", "gpu";
+ clocks = <&ccu CLK_GPU>, <&ccu CLK_BUS_GPU>;
+ clock-names = "core", "bus";
+ resets = <&ccu RST_BUS_GPU>;
+ status = "disabled";
+ };
+
+ crypto: crypto@1904000 {
+ compatible = "allwinner,sun50i-h6-crypto";
+ reg = <0x01904000 0x1000>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>, <&ccu CLK_MBUS_CE>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_CE>;
};
syscon: syscon@3000000 {
@@ -197,7 +228,7 @@
ccu: clock@3001000 {
compatible = "allwinner,sun50i-h6-ccu";
reg = <0x03001000 0x1000>;
- clocks = <&osc24M>, <&osc32k>, <&iosc>;
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>;
clock-names = "hosc", "losc", "iosc";
#clock-cells = <1>;
#reset-cells = <1>;
@@ -215,9 +246,29 @@
#dma-cells = <1>;
};
- sid: sid@3006000 {
+ msgbox: mailbox@3003000 {
+ compatible = "allwinner,sun50i-h6-msgbox",
+ "allwinner,sun6i-a31-msgbox";
+ reg = <0x03003000 0x1000>;
+ clocks = <&ccu CLK_BUS_MSGBOX>;
+ resets = <&ccu RST_BUS_MSGBOX>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
+ };
+
+ sid: efuse@3006000 {
compatible = "allwinner,sun50i-h6-sid";
reg = <0x03006000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ths_calibration: thermal-sensor-calibration@14 {
+ reg = <0x14 0x8>;
+ };
+
+ cpu_speed_grade: cpu-speed-grade@1c {
+ reg = <0x1c 0x4>;
+ };
};
watchdog: watchdog@30090a0 {
@@ -225,10 +276,21 @@
"allwinner,sun6i-a31-wdt";
reg = <0x030090a0 0x20>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
/* Broken on some H6 boards */
status = "disabled";
};
+ pwm: pwm@300a000 {
+ compatible = "allwinner,sun50i-h6-pwm";
+ reg = <0x0300a000 0x400>;
+ clocks = <&osc24M>, <&ccu CLK_BUS_PWM>;
+ clock-names = "mod", "bus";
+ resets = <&ccu RST_BUS_PWM>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
pio: pinctrl@300b000 {
compatible = "allwinner,sun50i-h6-pinctrl";
reg = <0x0300b000 0x400>;
@@ -236,7 +298,7 @@
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ccu CLK_APB1>, <&osc24M>, <&osc32k>;
+ clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
#gpio-cells = <3>;
@@ -256,6 +318,21 @@
function = "hdmi";
};
+ i2c0_pins: i2c0-pins {
+ pins = "PD25", "PD26";
+ function = "i2c0";
+ };
+
+ i2c1_pins: i2c1-pins {
+ pins = "PH5", "PH6";
+ function = "i2c1";
+ };
+
+ i2c2_pins: i2c2-pins {
+ pins = "PD23", "PD24";
+ function = "i2c2";
+ };
+
mmc0_pins: mmc0-pins {
pins = "PF0", "PF1", "PF2", "PF3",
"PF4", "PF5";
@@ -264,10 +341,7 @@
bias-pull-up;
};
- /*
- * /omit-if-no-ref/ isn't supported by U-boot
- * keep this comment to avoid bad sync with Linux
- */
+ /omit-if-no-ref/
mmc1_pins: mmc1-pins {
pins = "PG0", "PG1", "PG2", "PG3",
"PG4", "PG5";
@@ -285,10 +359,50 @@
bias-pull-up;
};
+ /omit-if-no-ref/
+ spi0_pins: spi0-pins {
+ pins = "PC0", "PC2", "PC3";
+ function = "spi0";
+ };
+
+ /* pin shared with MMC2-CMD (eMMC) */
+ /omit-if-no-ref/
+ spi0_cs_pin: spi0-cs-pin {
+ pins = "PC5";
+ function = "spi0";
+ };
+
+ /omit-if-no-ref/
+ spi1_pins: spi1-pins {
+ pins = "PH4", "PH5", "PH6";
+ function = "spi1";
+ };
+
+ /omit-if-no-ref/
+ spi1_cs_pin: spi1-cs-pin {
+ pins = "PH3";
+ function = "spi1";
+ };
+
+ spdif_tx_pin: spdif-tx-pin {
+ pins = "PH7";
+ function = "spdif";
+ };
+
uart0_ph_pins: uart0-ph-pins {
pins = "PH0", "PH1";
function = "uart0";
};
+
+ uart1_pins: uart1-pins {
+ pins = "PG6", "PG7";
+ function = "uart1";
+ };
+
+ uart1_rts_cts_pins: uart1-rts-cts-pins {
+ pins = "PG8", "PG9";
+ function = "uart1";
+ };
};
gic: interrupt-controller@3021000 {
@@ -302,6 +416,15 @@
#interrupt-cells = <3>;
};
+ iommu: iommu@30f0000 {
+ compatible = "allwinner,sun50i-h6-iommu";
+ reg = <0x030f0000 0x10000>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_IOMMU>;
+ resets = <&ccu RST_BUS_IOMMU>;
+ #iommu-cells = <1>;
+ };
+
mmc0: mmc@4020000 {
compatible = "allwinner,sun50i-h6-mmc",
"allwinner,sun50i-a64-mmc";
@@ -394,6 +517,78 @@
status = "disabled";
};
+ i2c0: i2c@5002000 {
+ compatible = "allwinner,sun50i-h6-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002000 0x400>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@5002400 {
+ compatible = "allwinner,sun50i-h6-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002400 0x400>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@5002800 {
+ compatible = "allwinner,sun50i-h6-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002800 0x400>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi0: spi@5010000 {
+ compatible = "allwinner,sun50i-h6-spi",
+ "allwinner,sun8i-h3-spi";
+ reg = <0x05010000 0x1000>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma 22>, <&dma 22>;
+ dma-names = "rx", "tx";
+ resets = <&ccu RST_BUS_SPI0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi1: spi@5011000 {
+ compatible = "allwinner,sun50i-h6-spi",
+ "allwinner,sun8i-h3-spi";
+ reg = <0x05011000 0x1000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+ clock-names = "ahb", "mod";
+ dmas = <&dma 23>, <&dma 23>;
+ dma-names = "rx", "tx";
+ resets = <&ccu RST_BUS_SPI1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
emac: ethernet@5020000 {
compatible = "allwinner,sun50i-h6-emac",
"allwinner,sun50i-a64-emac";
@@ -414,6 +609,34 @@
};
};
+ i2s1: i2s@5091000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-h6-i2s";
+ reg = <0x05091000 0x1000>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 4>, <&dma 4>;
+ resets = <&ccu RST_BUS_I2S1>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ spdif: spdif@5093000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-h6-spdif";
+ reg = <0x05093000 0x400>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>;
+ clock-names = "apb", "spdif";
+ resets = <&ccu RST_BUS_SPDIF>;
+ dmas = <&dma 2>;
+ dma-names = "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_tx_pin>;
+ status = "disabled";
+ };
+
usb2otg: usb@5100000 {
compatible = "allwinner,sun50i-h6-musb",
"allwinner,sun8i-a33-musb";
@@ -470,6 +693,38 @@
status = "disabled";
};
+ dwc3: usb@5200000 {
+ compatible = "snps,dwc3";
+ reg = <0x05200000 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_XHCI>,
+ <&ccu CLK_BUS_XHCI>,
+ <&rtc 0>;
+ clock-names = "ref", "bus_early", "suspend";
+ resets = <&ccu RST_BUS_XHCI>;
+ /*
+ * The datasheet of the chip doesn't declare the
+ * peripheral function, and there's no boards known
+ * to have a USB Type-B port routed to the port.
+ * In addition, no one has tested the peripheral
+ * function yet.
+ * So set the dr_mode to "host" in the DTSI file.
+ */
+ dr_mode = "host";
+ phys = <&usb3phy>;
+ phy-names = "usb3-phy";
+ status = "disabled";
+ };
+
+ usb3phy: phy@5210000 {
+ compatible = "allwinner,sun50i-h6-usb3-phy";
+ reg = <0x5210000 0x10000>;
+ clocks = <&ccu CLK_USB_PHY1>;
+ resets = <&ccu RST_USB_PHY1>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
ehci3: usb@5311000 {
compatible = "allwinner,sun50i-h6-ehci", "generic-ehci";
reg = <0x05311000 0x100>;
@@ -480,6 +735,7 @@
resets = <&ccu RST_BUS_OHCI3>,
<&ccu RST_BUS_EHCI3>;
phys = <&usb2phy 3>;
+ phy-names = "usb";
status = "disabled";
};
@@ -491,6 +747,7 @@
<&ccu CLK_USB_OHCI3>;
resets = <&ccu RST_BUS_OHCI3>;
phys = <&usb2phy 3>;
+ phy-names = "usb";
status = "disabled";
};
@@ -507,7 +764,7 @@
resets = <&ccu RST_BUS_HDMI_SUB>, <&ccu RST_BUS_HDCP>;
reset-names = "ctrl", "hdcp";
phys = <&hdmi_phy>;
- phy-names = "hdmi-phy";
+ phy-names = "phy";
pinctrl-names = "default";
pinctrl-0 = <&hdmi_pins>;
status = "disabled";
@@ -549,7 +806,6 @@
"tcon-tv0";
clock-output-names = "tcon-top-tv0";
resets = <&ccu RST_BUS_TCON_TOP>;
- reset-names = "rst";
#clock-cells = <1>;
ports {
@@ -636,10 +892,19 @@
};
};
+ rtc: rtc@7000000 {
+ compatible = "allwinner,sun50i-h6-rtc";
+ reg = <0x07000000 0x400>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clock-output-names = "osc32k", "osc32k-out", "iosc";
+ #clock-cells = <1>;
+ };
+
r_ccu: clock@7010000 {
compatible = "allwinner,sun50i-h6-r-ccu";
reg = <0x07010000 0x400>;
- clocks = <&osc24M>, <&osc32k>, <&iosc>,
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
<&ccu CLK_PLL_PERIPH0>;
clock-names = "hosc", "losc", "iosc", "pll-periph";
#clock-cells = <1>;
@@ -651,6 +916,7 @@
"allwinner,sun6i-a31-wdt";
reg = <0x07020400 0x20>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
};
r_intc: interrupt-controller@7021000 {
@@ -667,7 +933,7 @@
reg = <0x07022000 0x400>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&osc32k>;
+ clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
#gpio-cells = <3>;
@@ -678,10 +944,30 @@
pins = "PL0", "PL1";
function = "s_i2c";
};
+
+ r_ir_rx_pin: r-ir-rx-pin {
+ pins = "PL9";
+ function = "s_cir_rx";
+ };
+ };
+
+ r_ir: ir@7040000 {
+ compatible = "allwinner,sun50i-h6-ir",
+ "allwinner,sun6i-a31-ir";
+ reg = <0x07040000 0x400>;
+ interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu CLK_R_APB1_IR>,
+ <&r_ccu CLK_IR>;
+ clock-names = "apb", "ir";
+ resets = <&r_ccu RST_R_APB1_IR>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_ir_rx_pin>;
+ status = "disabled";
};
r_i2c: i2c@7081400 {
- compatible = "allwinner,sun6i-a31-i2c";
+ compatible = "allwinner,sun50i-h6-i2c",
+ "allwinner,sun6i-a31-i2c";
reg = <0x07081400 0x400>;
interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&r_ccu CLK_R_APB2_I2C>;
@@ -692,5 +978,55 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ ths: thermal-sensor@5070400 {
+ compatible = "allwinner,sun50i-h6-ths";
+ reg = <0x05070400 0x100>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_THS>;
+ clock-names = "bus";
+ resets = <&ccu RST_BUS_THS>;
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
+ thermal-zones {
+ cpu-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 0>;
+
+ trips {
+ cpu_alert: cpu-alert {
+ temperature = <85000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu-crit {
+ temperature = <100000>;
+ hysteresis = <0>;
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert>;
+ 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 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths 1>;
+ };
};
};
diff --git a/arch/arm/dts/sun50i-h616-orangepi-zero2.dts b/arch/arm/dts/sun50i-h616-orangepi-zero2.dts
new file mode 100644
index 0000000..e6de49f
--- /dev/null
+++ b/arch/arm/dts/sun50i-h616-orangepi-zero2.dts
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+/*
+ * Copyright (C) 2020 Arm Ltd.
+ */
+
+/dts-v1/;
+
+#include "sun50i-h616.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+ model = "OrangePi Zero2";
+ compatible = "xunlong,orangepi-zero2", "allwinner,sun50i-h616";
+
+ aliases {
+ ethernet0 = &emac0;
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-0 {
+ function = LED_FUNCTION_POWER;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&pio 2 12 GPIO_ACTIVE_HIGH>; /* PC12 */
+ default-state = "on";
+ };
+
+ led-1 {
+ function = LED_FUNCTION_STATUS;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&pio 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */
+ };
+ };
+
+ reg_vcc5v: vcc5v {
+ /* board wide 5V supply directly from the USB-C socket */
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb1-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&reg_vcc5v>;
+ enable-active-high;
+ gpio = <&pio 2 16 GPIO_ACTIVE_HIGH>; /* PC16 */
+ status = "okay";
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+/* USB 2 & 3 are on headers only. */
+
+&emac0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rgmii_pins>;
+ phy-mode = "rgmii";
+ phy-handle = <&ext_rgmii_phy>;
+ phy-supply = <&reg_dcdce>;
+ allwinner,rx-delay-ps = <3100>;
+ allwinner,tx-delay-ps = <700>;
+ status = "okay";
+};
+
+&mdio0 {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+};
+
+&mmc0 {
+ vmmc-supply = <&reg_dcdce>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ bus-width = <4>;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&r_rsb {
+ status = "okay";
+
+ axp305: pmic@745 {
+ compatible = "x-powers,axp305", "x-powers,axp805",
+ "x-powers,axp806";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x745>;
+
+ x-powers,self-working-mode;
+ vina-supply = <&reg_vcc5v>;
+ vinb-supply = <&reg_vcc5v>;
+ vinc-supply = <&reg_vcc5v>;
+ vind-supply = <&reg_vcc5v>;
+ vine-supply = <&reg_vcc5v>;
+ aldoin-supply = <&reg_vcc5v>;
+ bldoin-supply = <&reg_vcc5v>;
+ cldoin-supply = <&reg_vcc5v>;
+
+ regulators {
+ reg_aldo1: aldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-sys";
+ };
+
+ reg_aldo2: aldo2 { /* 3.3V on headers */
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc3v3-ext";
+ };
+
+ reg_aldo3: aldo3 { /* 3.3V on headers */
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc3v3-ext2";
+ };
+
+ reg_bldo1: bldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc1v8";
+ };
+
+ bldo2 {
+ /* unused */
+ };
+
+ bldo3 {
+ /* unused */
+ };
+
+ bldo4 {
+ /* unused */
+ };
+
+ cldo1 {
+ /* reserved */
+ };
+
+ cldo2 {
+ /* unused */
+ };
+
+ cldo3 {
+ /* unused */
+ };
+
+ reg_dcdca: dcdca {
+ regulator-always-on;
+ regulator-min-microvolt = <810000>;
+ regulator-max-microvolt = <1080000>;
+ regulator-name = "vdd-cpu";
+ };
+
+ reg_dcdcc: dcdcc {
+ regulator-always-on;
+ regulator-min-microvolt = <810000>;
+ regulator-max-microvolt = <1080000>;
+ regulator-name = "vdd-gpu-sys";
+ };
+
+ reg_dcdcd: dcdcd {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vdd-dram";
+ };
+
+ reg_dcdce: dcdce {
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-eth-mmc";
+ };
+
+ sw {
+ /* unused */
+ };
+ };
+ };
+};
+
+&spi0 {
+ status = "okay";
+
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <40000000>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_ph_pins>;
+ status = "okay";
+};
+
+&usbotg {
+ dr_mode = "peripheral";
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun50i-h616.dtsi b/arch/arm/dts/sun50i-h616.dtsi
new file mode 100644
index 0000000..953e8fa
--- /dev/null
+++ b/arch/arm/dts/sun50i-h616.dtsi
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2020 Arm Ltd.
+// based on the H6 dtsi, which is:
+// Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun50i-h616-ccu.h>
+#include <dt-bindings/clock/sun50i-h6-r-ccu.h>
+#include <dt-bindings/reset/sun50i-h616-ccu.h>
+#include <dt-bindings/reset/sun50i-h6-r-ccu.h>
+
+/ {
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <0>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <1>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <2>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53";
+ device_type = "cpu";
+ reg = <3>;
+ enable-method = "psci";
+ clocks = <&ccu CLK_CPUX>;
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* 512KiB reserved for ARM Trusted Firmware (BL31) */
+ secmon_reserved: secmon@40000000 {
+ reg = <0x0 0x40000000 0x0 0x80000>;
+ no-map;
+ };
+ };
+
+ osc24M: osc24M_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ arm,no-tick-in-suspend;
+ interrupts = <GIC_PPI 13
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 14
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 11
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+ <GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x0 0x40000000>;
+
+ syscon: syscon@3000000 {
+ compatible = "allwinner,sun50i-h616-system-control";
+ reg = <0x03000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_c: sram@28000 {
+ compatible = "mmio-sram";
+ reg = <0x00028000 0x30000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00028000 0x30000>;
+ };
+ };
+
+ ccu: clock@3001000 {
+ compatible = "allwinner,sun50i-h616-ccu";
+ reg = <0x03001000 0x1000>;
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>;
+ clock-names = "hosc", "losc", "iosc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ watchdog: watchdog@30090a0 {
+ compatible = "allwinner,sun50i-h616-wdt",
+ "allwinner,sun6i-a31-wdt";
+ reg = <0x030090a0 0x20>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ status = "disabled";
+ };
+
+ pio: pinctrl@300b000 {
+ compatible = "allwinner,sun50i-h616-pinctrl";
+ reg = <0x0300b000 0x400>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_APB1>, <&osc24M>, <&rtc 0>;
+ clock-names = "apb", "hosc", "losc";
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ ext_rgmii_pins: rgmii-pins {
+ pins = "PI0", "PI1", "PI2", "PI3", "PI4",
+ "PI5", "PI7", "PI8", "PI9", "PI10",
+ "PI11", "PI12", "PI13", "PI14", "PI15",
+ "PI16";
+ function = "emac0";
+ drive-strength = <40>;
+ };
+
+ i2c0_pins: i2c0-pins {
+ pins = "PI6", "PI7";
+ function = "i2c0";
+ };
+
+ i2c3_ph_pins: i2c3-ph-pins {
+ pins = "PH4", "PH5";
+ function = "i2c3";
+ };
+
+ ir_rx_pin: ir_rx_pin {
+ pins = "PH10";
+ function = "ir_rx";
+ };
+
+ mmc0_pins: mmc0-pins {
+ pins = "PF0", "PF1", "PF2", "PF3",
+ "PF4", "PF5";
+ function = "mmc0";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ mmc1_pins: mmc1-pins {
+ pins = "PG0", "PG1", "PG2", "PG3",
+ "PG4", "PG5";
+ function = "mmc1";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ mmc2_pins: mmc2-pins {
+ pins = "PC0", "PC1", "PC5", "PC6",
+ "PC8", "PC9", "PC10", "PC11",
+ "PC13", "PC14", "PC15", "PC16";
+ function = "mmc2";
+ drive-strength = <30>;
+ bias-pull-up;
+ };
+
+ spi0_pins: spi0-pins {
+ pins = "PC0", "PC2", "PC3", "PC4";
+ function = "spi0";
+ };
+
+ spi1_pins: spi1-pins {
+ pins = "PH6", "PH7", "PH8";
+ function = "spi1";
+ };
+
+ spi1_cs_pin: spi1-cs-pin {
+ pins = "PH5";
+ function = "spi1";
+ };
+
+ uart0_ph_pins: uart0-ph-pins {
+ pins = "PH0", "PH1";
+ function = "uart0";
+ };
+
+ uart1_pins: uart1-pins {
+ pins = "PG6", "PG7";
+ function = "uart1";
+ };
+
+ uart1_rts_cts_pins: uart1-rts-cts-pins {
+ pins = "PG8", "PG9";
+ function = "uart1";
+ };
+ };
+
+ gic: interrupt-controller@3021000 {
+ compatible = "arm,gic-400";
+ reg = <0x03021000 0x1000>,
+ <0x03022000 0x2000>,
+ <0x03024000 0x2000>,
+ <0x03026000 0x2000>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ mmc0: mmc@4020000 {
+ compatible = "allwinner,sun50i-h616-mmc",
+ "allwinner,sun50i-a100-mmc";
+ reg = <0x04020000 0x1000>;
+ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
+ clock-names = "ahb", "mmc";
+ resets = <&ccu RST_BUS_MMC0>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ status = "disabled";
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ mmc-ddr-3_3v;
+ mmc-ddr-1_8v;
+ cap-sdio-irq;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc1: mmc@4021000 {
+ compatible = "allwinner,sun50i-h616-mmc",
+ "allwinner,sun50i-a100-mmc";
+ reg = <0x04021000 0x1000>;
+ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
+ clock-names = "ahb", "mmc";
+ resets = <&ccu RST_BUS_MMC1>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ status = "disabled";
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ mmc-ddr-3_3v;
+ mmc-ddr-1_8v;
+ cap-sdio-irq;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mmc2: mmc@4022000 {
+ compatible = "allwinner,sun50i-h616-emmc",
+ "allwinner,sun50i-a100-emmc";
+ reg = <0x04022000 0x1000>;
+ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
+ clock-names = "ahb", "mmc";
+ resets = <&ccu RST_BUS_MMC2>;
+ reset-names = "ahb";
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+ status = "disabled";
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ mmc-ddr-3_3v;
+ mmc-ddr-1_8v;
+ cap-sdio-irq;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ uart0: serial@5000000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05000000 0x400>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART0>;
+ resets = <&ccu RST_BUS_UART0>;
+ status = "disabled";
+ };
+
+ uart1: serial@5000400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05000400 0x400>;
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART1>;
+ resets = <&ccu RST_BUS_UART1>;
+ status = "disabled";
+ };
+
+ uart2: serial@5000800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05000800 0x400>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART2>;
+ resets = <&ccu RST_BUS_UART2>;
+ status = "disabled";
+ };
+
+ uart3: serial@5000c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05000c00 0x400>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART3>;
+ resets = <&ccu RST_BUS_UART3>;
+ status = "disabled";
+ };
+
+ uart4: serial@5001000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05001000 0x400>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART4>;
+ resets = <&ccu RST_BUS_UART4>;
+ status = "disabled";
+ };
+
+ uart5: serial@5001400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x05001400 0x400>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&ccu CLK_BUS_UART5>;
+ resets = <&ccu RST_BUS_UART5>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@5002000 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002000 0x400>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C0>;
+ resets = <&ccu RST_BUS_I2C0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@5002400 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002400 0x400>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C1>;
+ resets = <&ccu RST_BUS_I2C1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@5002800 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002800 0x400>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C2>;
+ resets = <&ccu RST_BUS_I2C2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c3: i2c@5002c00 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05002c00 0x400>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C3>;
+ resets = <&ccu RST_BUS_I2C3>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c4: i2c@5003000 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x05003000 0x400>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2C4>;
+ resets = <&ccu RST_BUS_I2C4>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi0: spi@5010000 {
+ compatible = "allwinner,sun50i-h616-spi",
+ "allwinner,sun8i-h3-spi";
+ reg = <0x05010000 0x1000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+ clock-names = "ahb", "mod";
+ resets = <&ccu RST_BUS_SPI0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi1: spi@5011000 {
+ compatible = "allwinner,sun50i-h616-spi",
+ "allwinner,sun8i-h3-spi";
+ reg = <0x05011000 0x1000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+ clock-names = "ahb", "mod";
+ resets = <&ccu RST_BUS_SPI1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ emac0: ethernet@5020000 {
+ compatible = "allwinner,sun50i-h616-emac",
+ "allwinner,sun50i-a64-emac";
+ syscon = <&syscon>;
+ reg = <0x05020000 0x10000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ resets = <&ccu RST_BUS_EMAC0>;
+ reset-names = "stmmaceth";
+ clocks = <&ccu CLK_BUS_EMAC0>;
+ clock-names = "stmmaceth";
+ status = "disabled";
+
+ mdio0: mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ emac1: ethernet@5030000 {
+ compatible = "allwinner,sun50i-h616-emac";
+ syscon = <&syscon 1>;
+ reg = <0x05030000 0x10000>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ resets = <&ccu RST_BUS_EMAC1>;
+ reset-names = "stmmaceth";
+ clocks = <&ccu CLK_BUS_EMAC1>;
+ clock-names = "stmmaceth";
+ status = "disabled";
+
+ mdio1: mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ usbotg: usb@5100000 {
+ compatible = "allwinner,sun50i-h616-musb",
+ "allwinner,sun8i-h3-musb";
+ reg = <0x05100000 0x0400>;
+ clocks = <&ccu CLK_BUS_OTG>;
+ resets = <&ccu RST_BUS_OTG>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ status = "disabled";
+ };
+
+ usbphy: phy@5100400 {
+ compatible = "allwinner,sun50i-h616-usb-phy";
+ reg = <0x05100400 0x24>,
+ <0x05101800 0x14>,
+ <0x05200800 0x14>,
+ <0x05310800 0x14>,
+ <0x05311800 0x14>;
+ reg-names = "phy_ctrl",
+ "pmu0",
+ "pmu1",
+ "pmu2",
+ "pmu3";
+ clocks = <&ccu CLK_USB_PHY0>,
+ <&ccu CLK_USB_PHY1>,
+ <&ccu CLK_USB_PHY2>,
+ <&ccu CLK_USB_PHY3>;
+ clock-names = "usb0_phy",
+ "usb1_phy",
+ "usb2_phy",
+ "usb3_phy";
+ resets = <&ccu RST_USB_PHY0>,
+ <&ccu RST_USB_PHY1>,
+ <&ccu RST_USB_PHY2>,
+ <&ccu RST_USB_PHY3>;
+ reset-names = "usb0_reset",
+ "usb1_reset",
+ "usb2_reset",
+ "usb3_reset";
+ status = "disabled";
+ #phy-cells = <1>;
+ };
+
+ ehci0: usb@5101000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05101000 0x100>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_BUS_EHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_OHCI0>,
+ <&ccu RST_BUS_EHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci0: usb@5101400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05101400 0x100>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI0>,
+ <&ccu CLK_USB_OHCI0>;
+ resets = <&ccu RST_BUS_OHCI0>;
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci1: usb@5200000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05200000 0x100>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI1>,
+ <&ccu CLK_BUS_EHCI1>,
+ <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_BUS_OHCI1>,
+ <&ccu RST_BUS_EHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci1: usb@5200400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05200400 0x100>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI1>,
+ <&ccu CLK_USB_OHCI1>;
+ resets = <&ccu RST_BUS_OHCI1>;
+ phys = <&usbphy 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci2: usb@5310000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05310000 0x100>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI2>,
+ <&ccu CLK_BUS_EHCI2>,
+ <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_BUS_OHCI2>,
+ <&ccu RST_BUS_EHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci2: usb@5310400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05310400 0x100>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI2>,
+ <&ccu CLK_USB_OHCI2>;
+ resets = <&ccu RST_BUS_OHCI2>;
+ phys = <&usbphy 2>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ehci3: usb@5311000 {
+ compatible = "allwinner,sun50i-h616-ehci",
+ "generic-ehci";
+ reg = <0x05311000 0x100>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI3>,
+ <&ccu CLK_BUS_EHCI3>,
+ <&ccu CLK_USB_OHCI3>;
+ resets = <&ccu RST_BUS_OHCI3>,
+ <&ccu RST_BUS_EHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ ohci3: usb@5311400 {
+ compatible = "allwinner,sun50i-h616-ohci",
+ "generic-ohci";
+ reg = <0x05311400 0x100>;
+ interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_OHCI3>,
+ <&ccu CLK_USB_OHCI3>;
+ resets = <&ccu RST_BUS_OHCI3>;
+ phys = <&usbphy 3>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ rtc: rtc@7000000 {
+ compatible = "allwinner,sun50i-h616-rtc",
+ "allwinner,sun50i-h6-rtc";
+ reg = <0x07000000 0x400>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clock-output-names = "osc32k", "osc32k-out", "iosc";
+ #clock-cells = <1>;
+ };
+
+ r_ccu: clock@7010000 {
+ compatible = "allwinner,sun50i-h616-r-ccu";
+ reg = <0x07010000 0x400>;
+ clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
+ <&ccu CLK_PLL_PERIPH0>;
+ clock-names = "hosc", "losc", "iosc", "pll-periph";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ r_pio: pinctrl@7022000 {
+ compatible = "allwinner,sun50i-h616-r-pinctrl";
+ reg = <0x07022000 0x400>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
+ clock-names = "apb", "hosc", "losc";
+ gpio-controller;
+ #gpio-cells = <3>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ r_i2c_pins: r-i2c-pins {
+ pins = "PL0", "PL1";
+ function = "s_i2c";
+ };
+
+ r_rsb_pins: r-rsb-pins {
+ pins = "PL0", "PL1";
+ function = "s_rsb";
+ };
+ };
+
+ ir: ir@7040000 {
+ compatible = "allwinner,sun50i-h616-ir",
+ "allwinner,sun6i-a31-ir";
+ reg = <0x07040000 0x400>;
+ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu CLK_R_APB1_IR>,
+ <&r_ccu CLK_IR>;
+ clock-names = "apb", "ir";
+ resets = <&r_ccu RST_R_APB1_IR>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_rx_pin>;
+ status = "disabled";
+ };
+
+ r_i2c: i2c@7081400 {
+ compatible = "allwinner,sun50i-h616-i2c",
+ "allwinner,sun6i-a31-i2c";
+ reg = <0x07081400 0x400>;
+ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu CLK_R_APB2_I2C>;
+ resets = <&r_ccu RST_R_APB2_I2C>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ r_rsb: rsb@7083000 {
+ compatible = "allwinner,sun50i-h616-rsb",
+ "allwinner,sun8i-a23-rsb";
+ reg = <0x07083000 0x400>;
+ interrupts = <GIC_SPI 109 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>;
+ };
+ };
+};
diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi
index c77cf7c..abe629c 100644
--- a/arch/arm/dts/sunxi-u-boot.dtsi
+++ b/arch/arm/dts/sunxi-u-boot.dtsi
@@ -3,6 +3,8 @@
#ifdef CONFIG_MACH_SUN50I_H6
#define BL31_ADDR 0x104000
#define SCP_ADDR 0x114000
+#elif defined(CONFIG_MACH_SUN50I_H616)
+#define BL31_ADDR 0x40004000
#else
#define BL31_ADDR 0x44000
#define SCP_ADDR 0x50000
@@ -61,6 +63,7 @@
};
};
+#ifndef CONFIG_MACH_SUN50I_H616
scp {
description = "SCP firmware";
type = "firmware";
@@ -73,6 +76,7 @@
missing-msg = "scp-sunxi";
};
};
+#endif
@fdt-SEQ {
description = "NAME";
@@ -87,7 +91,11 @@
@config-SEQ {
description = "NAME";
firmware = "atf";
+#ifdef CONFIG_MACH_SUN50I_H616
+ loadables = "uboot";
+#else
loadables = "scp", "uboot";
+#endif
fdt = "fdt-SEQ";
};
};
diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
index 46d0f06..e8e8e38 100644
--- a/arch/arm/include/asm/arch-sunxi/boot0.h
+++ b/arch/arm/include/asm/arch-sunxi/boot0.h
@@ -39,7 +39,7 @@
.word 0xf57ff06f // isb sy
.word 0xe320f003 // wfi
.word 0xeafffffd // b @wfi
-#ifndef CONFIG_MACH_SUN50I_H6
+#ifndef CONFIG_SUN50I_GEN_H6
.word 0x017000a0 // writeable RVBAR mapping address
#else
.word 0x09010040 // writeable RVBAR mapping address
diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
index 5994130..cbbe5c7 100644
--- a/arch/arm/include/asm/arch-sunxi/clock.h
+++ b/arch/arm/include/asm/arch-sunxi/clock.h
@@ -16,7 +16,7 @@
/* clock control module regs definition */
#if defined(CONFIG_MACH_SUN8I_A83T)
#include <asm/arch/clock_sun8i_a83t.h>
-#elif defined(CONFIG_MACH_SUN50I_H6)
+#elif defined(CONFIG_SUN50I_GEN_H6)
#include <asm/arch/clock_sun50i_h6.h>
#elif defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \
defined(CONFIG_MACH_SUN50I)
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 426069f..62abfc4 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
@@ -230,6 +230,7 @@ struct sunxi_ccm_reg {
#define CCM_PLL1_CTRL_EN BIT(31)
#define CCM_PLL1_LOCK_EN BIT(29)
#define CCM_PLL1_LOCK BIT(28)
+#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)
@@ -238,6 +239,7 @@ struct sunxi_ccm_reg {
#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_DIV1(div1) ((div1) << 0)
#define CCM_PLL5_CTRL_DIV2(div0) ((div0) << 1)
@@ -252,7 +254,6 @@ struct sunxi_ccm_reg {
#define CCM_PLL6_CTRL_DIV1_MASK (0x1 << CCM_PLL6_CTRL_DIV1_SHIFT)
#define CCM_PLL6_CTRL_DIV2_SHIFT 1
#define CCM_PLL6_CTRL_DIV2_MASK (0x1 << CCM_PLL6_CTRL_DIV2_SHIFT)
-#define CCM_PLL6_DEFAULT 0xa0006300
/* cpu_axi bit field*/
#define CCM_CPU_AXI_MUX_MASK (0x3 << 24)
@@ -262,6 +263,9 @@ struct sunxi_ccm_reg {
#define CCM_CPU_AXI_AXI_MASK 0x3
#define CCM_CPU_AXI_DEFAULT_FACTORS 0x301
+#ifdef CONFIG_MACH_SUN50I_H6
+#define CCM_PLL6_DEFAULT 0xa0006300
+
/* psi_ahb1_ahb2 bit field */
#define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000102
@@ -270,6 +274,18 @@ struct sunxi_ccm_reg {
/* apb1 bit field */
#define CCM_APB1_DEFAULT 0x03000102
+#elif CONFIG_MACH_SUN50I_H616
+#define CCM_PLL6_DEFAULT 0xa8003100
+
+/* psi_ahb1_ahb2 bit field */
+#define CCM_PSI_AHB1_AHB2_DEFAULT 0x03000002
+
+/* ahb3 bit field */
+#define CCM_AHB3_DEFAULT 0x03000002
+
+/* apb1 bit field */
+#define CCM_APB1_DEFAULT 0x03000102
+#endif
/* apb2 bit field */
#define APB2_CLK_SRC_OSC24M (0x0 << 24)
@@ -297,6 +313,7 @@ struct sunxi_ccm_reg {
/* Module gate/reset shift*/
#define RESET_SHIFT (16)
+#define GATE_SHIFT (0)
/* DRAM clock bit field */
#define DRAM_MOD_RESET BIT(30)
diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
index 8b57d24..b08f202 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu.h
@@ -8,7 +8,7 @@
#if defined(CONFIG_MACH_SUN9I)
#include <asm/arch/cpu_sun9i.h>
-#elif defined(CONFIG_MACH_SUN50I_H6)
+#elif defined(CONFIG_SUN50I_GEN_H6)
#include <asm/arch/cpu_sun50i_h6.h>
#else
#include <asm/arch/cpu_sun4i.h>
diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
index 6392cb0..d9cf8ae 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
@@ -28,13 +28,20 @@
#define SUNXI_GIC400_BASE 0x03020000
#define SUNXI_IOMMU_BASE 0x030F0000
+#ifdef CONFIG_MACH_SUN50I_H6
#define SUNXI_DRAM_COM_BASE 0x04002000
#define SUNXI_DRAM_CTL0_BASE 0x04003000
#define SUNXI_DRAM_PHY0_BASE 0x04005000
+#endif
#define SUNXI_NFC_BASE 0x04011000
#define SUNXI_MMC0_BASE 0x04020000
#define SUNXI_MMC1_BASE 0x04021000
#define SUNXI_MMC2_BASE 0x04022000
+#ifdef CONFIG_MACH_SUN50I_H616
+#define SUNXI_DRAM_COM_BASE 0x047FA000
+#define SUNXI_DRAM_CTL0_BASE 0x047FB000
+#define SUNXI_DRAM_PHY0_BASE 0x04800000
+#endif
#define SUNXI_UART0_BASE 0x05000000
#define SUNXI_UART1_BASE 0x05000400
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index 8002b7e..c3b3e1f 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -29,6 +29,8 @@
#include <asm/arch/dram_sun9i.h>
#elif defined(CONFIG_MACH_SUN50I_H6)
#include <asm/arch/dram_sun50i_h6.h>
+#elif defined(CONFIG_MACH_SUN50I_H616)
+#include <asm/arch/dram_sun50i_h616.h>
#else
#include <asm/arch/dram_sun4i.h>
#endif
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
new file mode 100644
index 0000000..134679d
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
@@ -0,0 +1,159 @@
+/*
+ * H616 dram controller register and constant defines
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on H6 one, which is:
+ * (C) Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _SUNXI_DRAM_SUN50I_H616_H
+#define _SUNXI_DRAM_SUN50I_H616_H
+
+#include <stdbool.h>
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+enum sunxi_dram_type {
+ SUNXI_DRAM_TYPE_DDR3 = 3,
+ SUNXI_DRAM_TYPE_DDR4,
+ SUNXI_DRAM_TYPE_LPDDR3 = 7,
+ SUNXI_DRAM_TYPE_LPDDR4
+};
+
+/* MBUS part is largely the same as in H6, except for one special register */
+struct sunxi_mctl_com_reg {
+ u32 cr; /* 0x000 control register */
+ u8 reserved_0x004[4]; /* 0x004 */
+ u32 unk_0x008; /* 0x008 */
+ u32 tmr; /* 0x00c timer register */
+ u8 reserved_0x010[4]; /* 0x010 */
+ u32 unk_0x014; /* 0x014 */
+ u8 reserved_0x018[8]; /* 0x018 */
+ u32 maer0; /* 0x020 master enable register 0 */
+ u32 maer1; /* 0x024 master enable register 1 */
+ u32 maer2; /* 0x028 master enable register 2 */
+ u8 reserved_0x02c[468]; /* 0x02c */
+ u32 bwcr; /* 0x200 bandwidth control register */
+ u8 reserved_0x204[12]; /* 0x204 */
+ /*
+ * The last master configured by BSP libdram is at 0x49x, so the
+ * size of this struct array is set to 41 (0x29) now.
+ */
+ struct {
+ u32 cfg0; /* 0x0 */
+ u32 cfg1; /* 0x4 */
+ u8 reserved_0x8[8]; /* 0x8 */
+ } master[41]; /* 0x210 + index * 0x10 */
+ u8 reserved_0x4a0[96]; /* 0x4a0 */
+ u32 unk_0x500; /* 0x500 */
+};
+check_member(sunxi_mctl_com_reg, unk_0x500, 0x500);
+
+/*
+ * Controller registers seems to be the same or at least very similar
+ * to those in H6.
+ */
+struct sunxi_mctl_ctl_reg {
+ u32 mstr; /* 0x000 */
+ u32 statr; /* 0x004 unused */
+ u32 mstr1; /* 0x008 unused */
+ u32 clken; /* 0x00c */
+ u32 mrctrl0; /* 0x010 unused */
+ u32 mrctrl1; /* 0x014 unused */
+ u32 mrstatr; /* 0x018 unused */
+ u32 mrctrl2; /* 0x01c unused */
+ u32 derateen; /* 0x020 unused */
+ u32 derateint; /* 0x024 unused */
+ u8 reserved_0x028[8]; /* 0x028 */
+ u32 pwrctl; /* 0x030 unused */
+ u32 pwrtmg; /* 0x034 unused */
+ u32 hwlpctl; /* 0x038 unused */
+ u8 reserved_0x03c[20]; /* 0x03c */
+ u32 rfshctl0; /* 0x050 unused */
+ u32 rfshctl1; /* 0x054 unused */
+ u8 reserved_0x058[8]; /* 0x05c */
+ u32 rfshctl3; /* 0x060 */
+ u32 rfshtmg; /* 0x064 */
+ u8 reserved_0x068[104]; /* 0x068 */
+ u32 init[8]; /* 0x0d0 */
+ u32 dimmctl; /* 0x0f0 unused */
+ u32 rankctl; /* 0x0f4 */
+ u8 reserved_0x0f8[8]; /* 0x0f8 */
+ u32 dramtmg[17]; /* 0x100 */
+ u8 reserved_0x144[60]; /* 0x144 */
+ u32 zqctl[3]; /* 0x180 */
+ u32 zqstat; /* 0x18c unused */
+ u32 dfitmg0; /* 0x190 */
+ u32 dfitmg1; /* 0x194 */
+ u32 dfilpcfg[2]; /* 0x198 unused */
+ u32 dfiupd[3]; /* 0x1a0 */
+ u32 reserved_0x1ac; /* 0x1ac */
+ u32 dfimisc; /* 0x1b0 */
+ u32 dfitmg2; /* 0x1b4 unused */
+ u32 dfitmg3; /* 0x1b8 unused */
+ u32 dfistat; /* 0x1bc */
+ u32 dbictl; /* 0x1c0 */
+ u8 reserved_0x1c4[60]; /* 0x1c4 */
+ u32 addrmap[12]; /* 0x200 */
+ u8 reserved_0x230[16]; /* 0x230 */
+ u32 odtcfg; /* 0x240 */
+ u32 odtmap; /* 0x244 */
+ u8 reserved_0x248[8]; /* 0x248 */
+ u32 sched[2]; /* 0x250 */
+ u8 reserved_0x258[180]; /* 0x258 */
+ u32 dbgcmd; /* 0x30c unused */
+ u32 dbgstat; /* 0x310 unused */
+ u8 reserved_0x314[12]; /* 0x314 */
+ u32 swctl; /* 0x320 */
+ u32 swstat; /* 0x324 */
+ u8 reserved_0x328[7768];/* 0x328 */
+ u32 unk_0x2180; /* 0x2180 */
+ u8 reserved_0x2184[188];/* 0x2184 */
+ u32 unk_0x2240; /* 0x2240 */
+ u8 reserved_0x2244[3900];/* 0x2244 */
+ u32 unk_0x3180; /* 0x3180 */
+ u8 reserved_0x3184[188];/* 0x3184 */
+ u32 unk_0x3240; /* 0x3240 */
+ u8 reserved_0x3244[3900];/* 0x3244 */
+ u32 unk_0x4180; /* 0x4180 */
+ u8 reserved_0x4184[188];/* 0x4184 */
+ u32 unk_0x4240; /* 0x4240 */
+};
+check_member(sunxi_mctl_ctl_reg, swstat, 0x324);
+check_member(sunxi_mctl_ctl_reg, unk_0x4240, 0x4240);
+
+#define MSTR_DEVICETYPE_DDR3 BIT(0)
+#define MSTR_DEVICETYPE_LPDDR2 BIT(2)
+#define MSTR_DEVICETYPE_LPDDR3 BIT(3)
+#define MSTR_DEVICETYPE_DDR4 BIT(4)
+#define MSTR_DEVICETYPE_MASK GENMASK(5, 0)
+#define MSTR_2TMODE BIT(10)
+#define MSTR_BUSWIDTH_FULL (0 << 12)
+#define MSTR_BUSWIDTH_HALF (1 << 12)
+#define MSTR_ACTIVE_RANKS(x) (((x == 2) ? 3 : 1) << 24)
+#define MSTR_BURST_LENGTH(x) (((x) >> 1) << 16)
+
+struct dram_para {
+ u32 clk;
+ enum sunxi_dram_type type;
+ u8 cols;
+ u8 rows;
+ u8 ranks;
+ u8 bus_full_width;
+};
+
+
+static inline int ns_to_t(int nanoseconds)
+{
+ const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
+
+ return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
+}
+
+void mctl_set_timing_params(struct dram_para *para);
+
+#endif /* _SUNXI_DRAM_SUN50I_H616_H */
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index f817d32..de77bf6 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -206,6 +206,7 @@ enum sunxi_gpio_number {
#define SUN6I_GPH_UART0 2
#define SUN9I_GPH_UART0 2
#define SUN50I_H6_GPH_UART0 2
+#define SUN50I_H616_GPH_UART0 2
#define SUNXI_GPI_SDC3 2
#define SUN7I_GPI_TWI3 3
@@ -219,6 +220,7 @@ enum sunxi_gpio_number {
#define SUN8I_A23_GPL_R_TWI 3
#define SUN8I_GPL_R_UART 2
#define SUN50I_GPL_R_TWI 2
+#define SUN50I_H616_GPL_R_TWI 3
#define SUN9I_GPN_R_RSB 3
diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
index f2deafd..340e25b 100644
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -45,7 +45,7 @@ struct sunxi_mmc {
u32 chda; /* 0x90 */
u32 cbda; /* 0x94 */
u32 res2[26];
-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
u32 res3[17];
u32 samp_dl;
u32 res4[46];
diff --git a/arch/arm/include/asm/arch-sunxi/prcm.h b/arch/arm/include/asm/arch-sunxi/prcm.h
index 767d1ff..5106076 100644
--- a/arch/arm/include/asm/arch-sunxi/prcm.h
+++ b/arch/arm/include/asm/arch-sunxi/prcm.h
@@ -1,247 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Sunxi A31 Power Management Unit register definition.
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
*
- * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://linux-sunxi.org
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * Berg Xing <bergxing@allwinnertech.com>
- * Tom Cubie <tangliang@allwinnertech.com>
+ * Sunxi platform prcm register definition.
*/
#ifndef _SUNXI_PRCM_H
#define _SUNXI_PRCM_H
-#define __PRCM_CPUS_CFG_PRE(n) (((n) & 0x3) << 4)
-#define PRCM_CPUS_CFG_PRE_MASK __PRCM_CPUS_CFG_PRE(0x3)
-#define __PRCM_CPUS_CFG_PRE_DIV(n) (((n) >> 1) - 1)
-#define PRCM_CPUS_CFG_PRE_DIV(n) \
- __PRCM_CPUS_CFG_PRE(__PRCM_CPUS_CFG_CLK_PRE(n))
-#define __PRCM_CPUS_CFG_POST(n) (((n) & 0x1f) << 8)
-#define PRCM_CPUS_CFG_POST_MASK __PRCM_CPUS_CFG_POST(0x1f)
-#define __PRCM_CPUS_CFG_POST_DIV(n) ((n) - 1)
-#define PRCM_CPUS_CFG_POST_DIV(n) \
- __PRCM_CPUS_CFG_POST_DIV(__PRCM_CPUS_CFG_POST_DIV(n))
-#define __PRCM_CPUS_CFG_CLK_SRC(n) (((n) & 0x3) << 16)
-#define PRCM_CPUS_CFG_CLK_SRC_MASK __PRCM_CPUS_CFG_CLK_SRC(0x3)
-#define __PRCM_CPUS_CFG_CLK_SRC_LOSC 0x0
-#define __PRCM_CPUS_CFG_CLK_SRC_HOSC 0x1
-#define __PRCM_CPUS_CFG_CLK_SRC_PLL6 0x2
-#define __PRCM_CPUS_CFG_CLK_SRC_PDIV 0x3
-#define PRCM_CPUS_CFG_CLK_SRC_LOSC \
- __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_LOSC)
-#define PRCM_CPUS_CFG_CLK_SRC_HOSC \
- __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_HOSC)
-#define PRCM_CPUS_CFG_CLK_SRC_PLL6 \
- __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PLL6)
-#define PRCM_CPUS_CFG_CLK_SRC_PDIV \
- __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PDIV)
+/* prcm regs definition */
+#if defined(CONFIG_SUN50I_GEN_H6)
+#include <asm/arch/prcm_sun50i.h>
+#else
+#include <asm/arch/prcm_sun6i.h>
+#endif
-#define __PRCM_APB0_RATIO(n) (((n) & 0x3) << 0)
-#define PRCM_APB0_RATIO_DIV_MASK __PRCM_APB0_RATIO_DIV(0x3)
-#define __PRCM_APB0_RATIO_DIV(n) (((n) >> 1) - 1)
-#define PRCM_APB0_RATIO_DIV(n) \
- __PRCM_APB0_RATIO(__PRCM_APB0_RATIO_DIV(n))
-
-#define PRCM_CPU_CFG_NEON_CLK_EN (0x1 << 0)
-#define PRCM_CPU_CFG_CPU_CLK_EN (0x1 << 1)
-
-#define PRCM_APB0_GATE_PIO (0x1 << 0)
-#define PRCM_APB0_GATE_IR (0x1 << 1)
-#define PRCM_APB0_GATE_TIMER01 (0x1 << 2)
-#define PRCM_APB0_GATE_P2WI (0x1 << 3) /* sun6i */
-#define PRCM_APB0_GATE_RSB (0x1 << 3) /* sun8i */
-#define PRCM_APB0_GATE_UART (0x1 << 4)
-#define PRCM_APB0_GATE_1WIRE (0x1 << 5)
-#define PRCM_APB0_GATE_I2C (0x1 << 6)
-
-#define PRCM_APB0_RESET_PIO (0x1 << 0)
-#define PRCM_APB0_RESET_IR (0x1 << 1)
-#define PRCM_APB0_RESET_TIMER01 (0x1 << 2)
-#define PRCM_APB0_RESET_P2WI (0x1 << 3)
-#define PRCM_APB0_RESET_UART (0x1 << 4)
-#define PRCM_APB0_RESET_1WIRE (0x1 << 5)
-#define PRCM_APB0_RESET_I2C (0x1 << 6)
-
-#define PRCM_PLL_CTRL_PLL_BIAS (0x1 << 0)
-#define PRCM_PLL_CTRL_HOSC_GAIN_ENH (0x1 << 1)
-#define __PRCM_PLL_CTRL_USB_CLK_SRC(n) (((n) & 0x3) << 4)
-#define PRCM_PLL_CTRL_USB_CLK_SRC_MASK \
- __PRCM_PLL_CTRL_USB_CLK_SRC(0x3)
-#define __PRCM_PLL_CTRL_USB_CLK_0 0x0
-#define __PRCM_PLL_CTRL_USB_CLK_1 0x1
-#define __PRCM_PLL_CTRL_USB_CLK_2 0x2
-#define __PRCM_PLL_CTRL_USB_CLK_3 0x3
-#define PRCM_PLL_CTRL_USB_CLK_0 \
- __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_0)
-#define PRCM_PLL_CTRL_USB_CLK_1 \
- __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_1)
-#define PRCM_PLL_CTRL_USB_CLK_2 \
- __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_2)
-#define PRCM_PLL_CTRL_USB_CLK_3 \
- __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_3)
-#define __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) (((n) & 0x3) << 12)
-#define PRCM_PLL_CTRL_INT_PLL_IN_SEL_MASK \
- __PRCM_PLL_CTRL_INT_PLL_IN_SEL(0x3)
-#define PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) \
- __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n)
-#define __PRCM_PLL_CTRL_HOSC_CLK_SEL(n) (((n) & 0x3) << 20)
-#define PRCM_PLL_CTRL_HOSC_CLK_SEL_MASK \
- __PRCM_PLL_CTRL_HOSC_CLK_SEL(0x3)
-#define __PRCM_PLL_CTRL_HOSC_CLK_0 0x0
-#define __PRCM_PLL_CTRL_HOSC_CLK_1 0x1
-#define __PRCM_PLL_CTRL_HOSC_CLK_2 0x2
-#define __PRCM_PLL_CTRL_HOSC_CLK_3 0x3
-#define PRCM_PLL_CTRL_HOSC_CLK_0 \
- __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_0)
-#define PRCM_PLL_CTRL_HOSC_CLK_1 \
- __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_1)
-#define PRCM_PLL_CTRL_HOSC_CLK_2 \
- __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_2)
-#define PRCM_PLL_CTRL_HOSC_CLK_3 \
- __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_3)
-#define PRCM_PLL_CTRL_PLL_TST_SRC_EXT (0x1 << 24)
-#define PRCM_PLL_CTRL_LDO_DIGITAL_EN (0x1 << 0)
-#define PRCM_PLL_CTRL_LDO_ANALOG_EN (0x1 << 1)
-#define PRCM_PLL_CTRL_EXT_OSC_EN (0x1 << 2)
-#define PRCM_PLL_CTRL_CLK_TST_EN (0x1 << 3)
-#define PRCM_PLL_CTRL_IN_PWR_HIGH (0x1 << 15) /* 3.3 for hi 2.5 for lo */
-#define __PRCM_PLL_CTRL_VDD_LDO_OUT(n) (((n) & 0x7) << 16)
-#define PRCM_PLL_CTRL_LDO_OUT_MASK \
- __PRCM_PLL_CTRL_LDO_OUT(0x7)
-/* When using the low voltage 20 mV steps, and high voltage 30 mV steps */
-#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
- __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
-#define PRCM_PLL_CTRL_LDO_OUT_H(n) \
- __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1160) / 30) & 0x7)
-#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
- __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
-#define PRCM_PLL_CTRL_LDO_OUT_HV(n) \
- __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 30) + 1160)
-#define PRCM_PLL_CTRL_LDO_KEY (0xa7 << 24)
-#define PRCM_PLL_CTRL_LDO_KEY_MASK (0xff << 24)
-
-#define PRCM_CLK_1WIRE_GATE (0x1 << 31)
-
-#define __PRCM_CLK_MOD0_M(n) (((n) & 0xf) << 0)
-#define PRCM_CLK_MOD0_M_MASK __PRCM_CLK_MOD0_M(0xf)
-#define __PRCM_CLK_MOD0_M_X(n) (n - 1)
-#define PRCM_CLK_MOD0_M(n) __PRCM_CLK_MOD0_M(__PRCM_CLK_MOD0_M_X(n))
-#define PRCM_CLK_MOD0_OUT_PHASE(n) (((n) & 0x7) << 8)
-#define PRCM_CLK_MOD0_OUT_PHASE_MASK(n) PRCM_CLK_MOD0_OUT_PHASE(0x7)
-#define _PRCM_CLK_MOD0_N(n) (((n) & 0x3) << 16)
-#define PRCM_CLK_MOD0_N_MASK __PRCM_CLK_MOD_N(0x3)
-#define __PRCM_CLK_MOD0_N_X(n) (((n) >> 1) - 1)
-#define PRCM_CLK_MOD0_N(n) __PRCM_CLK_MOD0_N(__PRCM_CLK_MOD0_N_X(n))
-#define PRCM_CLK_MOD0_SMPL_PHASE(n) (((n) & 0x7) << 20)
-#define PRCM_CLK_MOD0_SMPL_PHASE_MASK PRCM_CLK_MOD0_SMPL_PHASE(0x7)
-#define PRCM_CLK_MOD0_SRC_SEL(n) (((n) & 0x7) << 24)
-#define PRCM_CLK_MOD0_SRC_SEL_MASK PRCM_CLK_MOD0_SRC_SEL(0x7)
-#define PRCM_CLK_MOD0_GATE_EN (0x1 << 31)
-
-#define PRCM_APB0_RESET_PIO (0x1 << 0)
-#define PRCM_APB0_RESET_IR (0x1 << 1)
-#define PRCM_APB0_RESET_TIMER01 (0x1 << 2)
-#define PRCM_APB0_RESET_P2WI (0x1 << 3)
-#define PRCM_APB0_RESET_UART (0x1 << 4)
-#define PRCM_APB0_RESET_1WIRE (0x1 << 5)
-#define PRCM_APB0_RESET_I2C (0x1 << 6)
-
-#define __PRCM_CLK_OUTD_M(n) (((n) & 0x7) << 8)
-#define PRCM_CLK_OUTD_M_MASK __PRCM_CLK_OUTD_M(0x7)
-#define __PRCM_CLK_OUTD_M_X() ((n) - 1)
-#define PRCM_CLK_OUTD_M(n) __PRCM_CLK_OUTD_M(__PRCM_CLK_OUTD_M_X(n))
-#define __PRCM_CLK_OUTD_N(n) (((n) & 0x7) << 20)
-#define PRCM_CLK_OUTD_N_MASK __PRCM_CLK_OUTD_N(0x7)
-#define __PRCM_CLK_OUTD_N_X(n) (((n) >> 1) - 1)
-#define PRCM_CLK_OUTD_N(n) __PRCM_CLK_OUTD_N(__PRCM_CLK_OUTD_N_X(n)
-#define __PRCM_CLK_OUTD_SRC_SEL(n) (((n) & 0x3) << 24)
-#define PRCM_CLK_OUTD_SRC_SEL_MASK __PRCM_CLK_OUTD_SRC_SEL(0x3)
-#define __PRCM_CLK_OUTD_SRC_LOSC2 0x0
-#define __PRCM_CLK_OUTD_SRC_LOSC 0x1
-#define __PRCM_CLK_OUTD_SRC_HOSC 0x2
-#define __PRCM_CLK_OUTD_SRC_ERR 0x3
-#define PRCM_CLK_OUTD_SRC_LOSC2 \
-#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_LOSC2)
-#define PRCM_CLK_OUTD_SRC_LOSC \
-#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_LOSC)
-#define PRCM_CLK_OUTD_SRC_HOSC \
-#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_HOSC)
-#define PRCM_CLK_OUTD_SRC_ERR \
-#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_ERR)
-#define PRCM_CLK_OUTD_EN (0x1 << 31)
-
-#define PRCM_CPU0_PWROFF (0x1 << 0)
-#define PRCM_CPU1_PWROFF (0x1 << 1)
-#define PRCM_CPU2_PWROFF (0x1 << 2)
-#define PRCM_CPU3_PWROFF (0x1 << 3)
-#define PRCM_CPU_ALL_PWROFF (0xf << 0)
-
-#define PRCM_VDD_SYS_DRAM_CH0_PAD_HOLD_PWROFF (0x1 << 0)
-#define PRCM_VDD_SYS_DRAM_CH1_PAD_HOLD_PWROFF (0x1 << 1)
-#define PRCM_VDD_SYS_AVCC_A_PWROFF (0x1 << 2)
-#define PRCM_VDD_SYS_CPU0_VDD_PWROFF (0x1 << 3)
-
-#define PRCM_VDD_GPU_PWROFF (0x1 << 0)
-
-#define PRCM_VDD_SYS_RESET (0x1 << 0)
-
-#define PRCM_CPU1_PWR_CLAMP(n) (((n) & 0xff) << 0)
-#define PRCM_CPU1_PWR_CLAMP_MASK PRCM_CPU1_PWR_CLAMP(0xff)
-
-#define PRCM_CPU2_PWR_CLAMP(n) (((n) & 0xff) << 0)
-#define PRCM_CPU2_PWR_CLAMP_MASK PRCM_CPU2_PWR_CLAMP(0xff)
-
-#define PRCM_CPU3_PWR_CLAMP(n) (((n) & 0xff) << 0)
-#define PRCM_CPU3_PWR_CLAMP_MASK PRCM_CPU3_PWR_CLAMP(0xff)
-
-#define PRCM_SEC_SWITCH_APB0_CLK_NONSEC (0x1 << 0)
-#define PRCM_SEC_SWITCH_PLL_CFG_NONSEC (0x1 << 1)
-#define PRCM_SEC_SWITCH_PWR_GATE_NONSEC (0x1 << 2)
-
-#ifndef __ASSEMBLY__
-#include <linux/compiler.h>
-
-struct sunxi_prcm_reg {
- u32 cpus_cfg; /* 0x000 */
- u8 res0[0x8]; /* 0x004 */
- u32 apb0_ratio; /* 0x00c */
- u32 cpu0_cfg; /* 0x010 */
- u32 cpu1_cfg; /* 0x014 */
- u32 cpu2_cfg; /* 0x018 */
- u32 cpu3_cfg; /* 0x01c */
- u8 res1[0x8]; /* 0x020 */
- u32 apb0_gate; /* 0x028 */
- u8 res2[0x14]; /* 0x02c */
- u32 pll_ctrl0; /* 0x040 */
- u32 pll_ctrl1; /* 0x044 */
- u8 res3[0x8]; /* 0x048 */
- u32 clk_1wire; /* 0x050 */
- u32 clk_ir; /* 0x054 */
- u8 res4[0x58]; /* 0x058 */
- u32 apb0_reset; /* 0x0b0 */
- u8 res5[0x3c]; /* 0x0b4 */
- u32 clk_outd; /* 0x0f0 */
- u8 res6[0xc]; /* 0x0f4 */
- u32 cpu_pwroff; /* 0x100 */
- u8 res7[0xc]; /* 0x104 */
- u32 vdd_sys_pwroff; /* 0x110 */
- u8 res8[0x4]; /* 0x114 */
- u32 gpu_pwroff; /* 0x118 */
- u8 res9[0x4]; /* 0x11c */
- u32 vdd_pwr_reset; /* 0x120 */
- u8 res10[0x1c]; /* 0x124 */
- u32 cpu_pwr_clamp[4]; /* 0x140 but first one is actually unused */
- u8 res11[0x30]; /* 0x150 */
- u32 dram_pwr; /* 0x180 */
- u8 res12[0xc]; /* 0x184 */
- u32 dram_tst; /* 0x190 */
- u8 res13[0x3c]; /* 0x194 */
- u32 prcm_sec_switch; /* 0x1d0 */
-};
-
-void prcm_apb0_enable(u32 flags);
-void prcm_apb0_disable(u32 flags);
-
-#endif /* __ASSEMBLY__ */
-#endif /* _PRCM_H */
+#endif /* _SUNXI_PRCM_H */
diff --git a/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h
new file mode 100644
index 0000000..5f636e8
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/prcm_sun50i.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Sunxi H6 Power Management Unit register definition.
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN50I_PRCM_H
+#define _SUN50I_PRCM_H
+
+#ifndef __ASSEMBLY__
+#include <linux/compiler.h>
+
+struct sunxi_prcm_reg {
+ u32 cpus_cfg; /* 0x000 */
+ u8 res0[0x8]; /* 0x004 */
+ u32 apbs1_cfg; /* 0x00c */
+ u32 apbs2_cfg; /* 0x010 */
+ u8 res1[0x108]; /* 0x014 */
+ u32 tmr_gate_reset; /* 0x11c */
+ u8 res2[0xc]; /* 0x120 */
+ u32 twd_gate_reset; /* 0x12c */
+ u8 res3[0xc]; /* 0x130 */
+ u32 pwm_gate_reset; /* 0x13c */
+ u8 res4[0x4c]; /* 0x140 */
+ u32 uart_gate_reset; /* 0x18c */
+ u8 res5[0xc]; /* 0x190 */
+ u32 twi_gate_reset; /* 0x19c */
+ u8 res6[0x1c]; /* 0x1a0 */
+ u32 rsb_gate_reset; /* 0x1bc */
+ u32 cir_cfg; /* 0x1c0 */
+ u8 res7[0x8]; /* 0x1c4 */
+ u32 cir_gate_reset; /* 0x1cc */
+ u8 res8[0x10]; /* 0x1d0 */
+ u32 w1_cfg; /* 0x1e0 */
+ u8 res9[0x8]; /* 0x1e4 */
+ u32 w1_gate_reset; /* 0x1ec */
+ u8 res10[0x1c]; /* 0x1f0 */
+ u32 rtc_gate_reset; /* 0x20c */
+};
+check_member(sunxi_prcm_reg, rtc_gate_reset, 0x20c);
+
+#define PRCM_TWI_GATE (1 << 0)
+#define PRCM_TWI_RESET (1 << 16)
+
+#endif /* __ASSEMBLY__ */
+#endif /* _PRCM_H */
diff --git a/arch/arm/include/asm/arch-sunxi/prcm_sun6i.h b/arch/arm/include/asm/arch-sunxi/prcm_sun6i.h
new file mode 100644
index 0000000..ab664e8
--- /dev/null
+++ b/arch/arm/include/asm/arch-sunxi/prcm_sun6i.h
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Sunxi A31 Power Management Unit register definition.
+ *
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * http://linux-sunxi.org
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * Berg Xing <bergxing@allwinnertech.com>
+ * Tom Cubie <tangliang@allwinnertech.com>
+ */
+
+#ifndef _SUN6I_PRCM_H
+#define _SUN6I_PRCM_H
+
+#define __PRCM_CPUS_CFG_PRE(n) (((n) & 0x3) << 4)
+#define PRCM_CPUS_CFG_PRE_MASK __PRCM_CPUS_CFG_PRE(0x3)
+#define __PRCM_CPUS_CFG_PRE_DIV(n) (((n) >> 1) - 1)
+#define PRCM_CPUS_CFG_PRE_DIV(n) \
+ __PRCM_CPUS_CFG_PRE(__PRCM_CPUS_CFG_CLK_PRE(n))
+#define __PRCM_CPUS_CFG_POST(n) (((n) & 0x1f) << 8)
+#define PRCM_CPUS_CFG_POST_MASK __PRCM_CPUS_CFG_POST(0x1f)
+#define __PRCM_CPUS_CFG_POST_DIV(n) ((n) - 1)
+#define PRCM_CPUS_CFG_POST_DIV(n) \
+ __PRCM_CPUS_CFG_POST_DIV(__PRCM_CPUS_CFG_POST_DIV(n))
+#define __PRCM_CPUS_CFG_CLK_SRC(n) (((n) & 0x3) << 16)
+#define PRCM_CPUS_CFG_CLK_SRC_MASK __PRCM_CPUS_CFG_CLK_SRC(0x3)
+#define __PRCM_CPUS_CFG_CLK_SRC_LOSC 0x0
+#define __PRCM_CPUS_CFG_CLK_SRC_HOSC 0x1
+#define __PRCM_CPUS_CFG_CLK_SRC_PLL6 0x2
+#define __PRCM_CPUS_CFG_CLK_SRC_PDIV 0x3
+#define PRCM_CPUS_CFG_CLK_SRC_LOSC \
+ __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_LOSC)
+#define PRCM_CPUS_CFG_CLK_SRC_HOSC \
+ __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_HOSC)
+#define PRCM_CPUS_CFG_CLK_SRC_PLL6 \
+ __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PLL6)
+#define PRCM_CPUS_CFG_CLK_SRC_PDIV \
+ __PRCM_CPUS_CFG_CLK_SRC(__PRCM_CPUS_CFG_CLK_SRC_PDIV)
+
+#define __PRCM_APB0_RATIO(n) (((n) & 0x3) << 0)
+#define PRCM_APB0_RATIO_DIV_MASK __PRCM_APB0_RATIO_DIV(0x3)
+#define __PRCM_APB0_RATIO_DIV(n) (((n) >> 1) - 1)
+#define PRCM_APB0_RATIO_DIV(n) \
+ __PRCM_APB0_RATIO(__PRCM_APB0_RATIO_DIV(n))
+
+#define PRCM_CPU_CFG_NEON_CLK_EN (0x1 << 0)
+#define PRCM_CPU_CFG_CPU_CLK_EN (0x1 << 1)
+
+#define PRCM_APB0_GATE_PIO (0x1 << 0)
+#define PRCM_APB0_GATE_IR (0x1 << 1)
+#define PRCM_APB0_GATE_TIMER01 (0x1 << 2)
+#define PRCM_APB0_GATE_P2WI (0x1 << 3) /* sun6i */
+#define PRCM_APB0_GATE_RSB (0x1 << 3) /* sun8i */
+#define PRCM_APB0_GATE_UART (0x1 << 4)
+#define PRCM_APB0_GATE_1WIRE (0x1 << 5)
+#define PRCM_APB0_GATE_I2C (0x1 << 6)
+
+#define PRCM_APB0_RESET_PIO (0x1 << 0)
+#define PRCM_APB0_RESET_IR (0x1 << 1)
+#define PRCM_APB0_RESET_TIMER01 (0x1 << 2)
+#define PRCM_APB0_RESET_P2WI (0x1 << 3)
+#define PRCM_APB0_RESET_UART (0x1 << 4)
+#define PRCM_APB0_RESET_1WIRE (0x1 << 5)
+#define PRCM_APB0_RESET_I2C (0x1 << 6)
+
+#define PRCM_PLL_CTRL_PLL_BIAS (0x1 << 0)
+#define PRCM_PLL_CTRL_HOSC_GAIN_ENH (0x1 << 1)
+#define __PRCM_PLL_CTRL_USB_CLK_SRC(n) (((n) & 0x3) << 4)
+#define PRCM_PLL_CTRL_USB_CLK_SRC_MASK \
+ __PRCM_PLL_CTRL_USB_CLK_SRC(0x3)
+#define __PRCM_PLL_CTRL_USB_CLK_0 0x0
+#define __PRCM_PLL_CTRL_USB_CLK_1 0x1
+#define __PRCM_PLL_CTRL_USB_CLK_2 0x2
+#define __PRCM_PLL_CTRL_USB_CLK_3 0x3
+#define PRCM_PLL_CTRL_USB_CLK_0 \
+ __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_0)
+#define PRCM_PLL_CTRL_USB_CLK_1 \
+ __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_1)
+#define PRCM_PLL_CTRL_USB_CLK_2 \
+ __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_2)
+#define PRCM_PLL_CTRL_USB_CLK_3 \
+ __PRCM_PLL_CTRL_USB_CLK_SRC(__PRCM_PLL_CTRL_USB_CLK_3)
+#define __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) (((n) & 0x3) << 12)
+#define PRCM_PLL_CTRL_INT_PLL_IN_SEL_MASK \
+ __PRCM_PLL_CTRL_INT_PLL_IN_SEL(0x3)
+#define PRCM_PLL_CTRL_INT_PLL_IN_SEL(n) \
+ __PRCM_PLL_CTRL_INT_PLL_IN_SEL(n)
+#define __PRCM_PLL_CTRL_HOSC_CLK_SEL(n) (((n) & 0x3) << 20)
+#define PRCM_PLL_CTRL_HOSC_CLK_SEL_MASK \
+ __PRCM_PLL_CTRL_HOSC_CLK_SEL(0x3)
+#define __PRCM_PLL_CTRL_HOSC_CLK_0 0x0
+#define __PRCM_PLL_CTRL_HOSC_CLK_1 0x1
+#define __PRCM_PLL_CTRL_HOSC_CLK_2 0x2
+#define __PRCM_PLL_CTRL_HOSC_CLK_3 0x3
+#define PRCM_PLL_CTRL_HOSC_CLK_0 \
+ __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_0)
+#define PRCM_PLL_CTRL_HOSC_CLK_1 \
+ __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_1)
+#define PRCM_PLL_CTRL_HOSC_CLK_2 \
+ __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_2)
+#define PRCM_PLL_CTRL_HOSC_CLK_3 \
+ __PRCM_PLL_CTRL_HOSC_CLK_SEL(__PRCM_PLL_CTRL_HOSC_CLK_3)
+#define PRCM_PLL_CTRL_PLL_TST_SRC_EXT (0x1 << 24)
+#define PRCM_PLL_CTRL_LDO_DIGITAL_EN (0x1 << 0)
+#define PRCM_PLL_CTRL_LDO_ANALOG_EN (0x1 << 1)
+#define PRCM_PLL_CTRL_EXT_OSC_EN (0x1 << 2)
+#define PRCM_PLL_CTRL_CLK_TST_EN (0x1 << 3)
+#define PRCM_PLL_CTRL_IN_PWR_HIGH (0x1 << 15) /* 3.3 for hi 2.5 for lo */
+#define __PRCM_PLL_CTRL_VDD_LDO_OUT(n) (((n) & 0x7) << 16)
+#define PRCM_PLL_CTRL_LDO_OUT_MASK \
+ __PRCM_PLL_CTRL_LDO_OUT(0x7)
+/* When using the low voltage 20 mV steps, and high voltage 30 mV steps */
+#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
+ __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
+#define PRCM_PLL_CTRL_LDO_OUT_H(n) \
+ __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1160) / 30) & 0x7)
+#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
+ __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
+#define PRCM_PLL_CTRL_LDO_OUT_HV(n) \
+ __PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 30) + 1160)
+#define PRCM_PLL_CTRL_LDO_KEY (0xa7 << 24)
+#define PRCM_PLL_CTRL_LDO_KEY_MASK (0xff << 24)
+
+#define PRCM_CLK_1WIRE_GATE (0x1 << 31)
+
+#define __PRCM_CLK_MOD0_M(n) (((n) & 0xf) << 0)
+#define PRCM_CLK_MOD0_M_MASK __PRCM_CLK_MOD0_M(0xf)
+#define __PRCM_CLK_MOD0_M_X(n) (n - 1)
+#define PRCM_CLK_MOD0_M(n) __PRCM_CLK_MOD0_M(__PRCM_CLK_MOD0_M_X(n))
+#define PRCM_CLK_MOD0_OUT_PHASE(n) (((n) & 0x7) << 8)
+#define PRCM_CLK_MOD0_OUT_PHASE_MASK(n) PRCM_CLK_MOD0_OUT_PHASE(0x7)
+#define _PRCM_CLK_MOD0_N(n) (((n) & 0x3) << 16)
+#define PRCM_CLK_MOD0_N_MASK __PRCM_CLK_MOD_N(0x3)
+#define __PRCM_CLK_MOD0_N_X(n) (((n) >> 1) - 1)
+#define PRCM_CLK_MOD0_N(n) __PRCM_CLK_MOD0_N(__PRCM_CLK_MOD0_N_X(n))
+#define PRCM_CLK_MOD0_SMPL_PHASE(n) (((n) & 0x7) << 20)
+#define PRCM_CLK_MOD0_SMPL_PHASE_MASK PRCM_CLK_MOD0_SMPL_PHASE(0x7)
+#define PRCM_CLK_MOD0_SRC_SEL(n) (((n) & 0x7) << 24)
+#define PRCM_CLK_MOD0_SRC_SEL_MASK PRCM_CLK_MOD0_SRC_SEL(0x7)
+#define PRCM_CLK_MOD0_GATE_EN (0x1 << 31)
+
+#define PRCM_APB0_RESET_PIO (0x1 << 0)
+#define PRCM_APB0_RESET_IR (0x1 << 1)
+#define PRCM_APB0_RESET_TIMER01 (0x1 << 2)
+#define PRCM_APB0_RESET_P2WI (0x1 << 3)
+#define PRCM_APB0_RESET_UART (0x1 << 4)
+#define PRCM_APB0_RESET_1WIRE (0x1 << 5)
+#define PRCM_APB0_RESET_I2C (0x1 << 6)
+
+#define __PRCM_CLK_OUTD_M(n) (((n) & 0x7) << 8)
+#define PRCM_CLK_OUTD_M_MASK __PRCM_CLK_OUTD_M(0x7)
+#define __PRCM_CLK_OUTD_M_X() ((n) - 1)
+#define PRCM_CLK_OUTD_M(n) __PRCM_CLK_OUTD_M(__PRCM_CLK_OUTD_M_X(n))
+#define __PRCM_CLK_OUTD_N(n) (((n) & 0x7) << 20)
+#define PRCM_CLK_OUTD_N_MASK __PRCM_CLK_OUTD_N(0x7)
+#define __PRCM_CLK_OUTD_N_X(n) (((n) >> 1) - 1)
+#define PRCM_CLK_OUTD_N(n) __PRCM_CLK_OUTD_N(__PRCM_CLK_OUTD_N_X(n)
+#define __PRCM_CLK_OUTD_SRC_SEL(n) (((n) & 0x3) << 24)
+#define PRCM_CLK_OUTD_SRC_SEL_MASK __PRCM_CLK_OUTD_SRC_SEL(0x3)
+#define __PRCM_CLK_OUTD_SRC_LOSC2 0x0
+#define __PRCM_CLK_OUTD_SRC_LOSC 0x1
+#define __PRCM_CLK_OUTD_SRC_HOSC 0x2
+#define __PRCM_CLK_OUTD_SRC_ERR 0x3
+#define PRCM_CLK_OUTD_SRC_LOSC2 \
+#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_LOSC2)
+#define PRCM_CLK_OUTD_SRC_LOSC \
+#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_LOSC)
+#define PRCM_CLK_OUTD_SRC_HOSC \
+#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_HOSC)
+#define PRCM_CLK_OUTD_SRC_ERR \
+#deifne __PRCM_CLK_OUTD_SRC_SEL(__PRCM_CLK_OUTD_SRC_ERR)
+#define PRCM_CLK_OUTD_EN (0x1 << 31)
+
+#define PRCM_CPU0_PWROFF (0x1 << 0)
+#define PRCM_CPU1_PWROFF (0x1 << 1)
+#define PRCM_CPU2_PWROFF (0x1 << 2)
+#define PRCM_CPU3_PWROFF (0x1 << 3)
+#define PRCM_CPU_ALL_PWROFF (0xf << 0)
+
+#define PRCM_VDD_SYS_DRAM_CH0_PAD_HOLD_PWROFF (0x1 << 0)
+#define PRCM_VDD_SYS_DRAM_CH1_PAD_HOLD_PWROFF (0x1 << 1)
+#define PRCM_VDD_SYS_AVCC_A_PWROFF (0x1 << 2)
+#define PRCM_VDD_SYS_CPU0_VDD_PWROFF (0x1 << 3)
+
+#define PRCM_VDD_GPU_PWROFF (0x1 << 0)
+
+#define PRCM_VDD_SYS_RESET (0x1 << 0)
+
+#define PRCM_CPU1_PWR_CLAMP(n) (((n) & 0xff) << 0)
+#define PRCM_CPU1_PWR_CLAMP_MASK PRCM_CPU1_PWR_CLAMP(0xff)
+
+#define PRCM_CPU2_PWR_CLAMP(n) (((n) & 0xff) << 0)
+#define PRCM_CPU2_PWR_CLAMP_MASK PRCM_CPU2_PWR_CLAMP(0xff)
+
+#define PRCM_CPU3_PWR_CLAMP(n) (((n) & 0xff) << 0)
+#define PRCM_CPU3_PWR_CLAMP_MASK PRCM_CPU3_PWR_CLAMP(0xff)
+
+#define PRCM_SEC_SWITCH_APB0_CLK_NONSEC (0x1 << 0)
+#define PRCM_SEC_SWITCH_PLL_CFG_NONSEC (0x1 << 1)
+#define PRCM_SEC_SWITCH_PWR_GATE_NONSEC (0x1 << 2)
+
+#ifndef __ASSEMBLY__
+#include <linux/compiler.h>
+
+struct sunxi_prcm_reg {
+ u32 cpus_cfg; /* 0x000 */
+ u8 res0[0x8]; /* 0x004 */
+ u32 apb0_ratio; /* 0x00c */
+ u32 cpu0_cfg; /* 0x010 */
+ u32 cpu1_cfg; /* 0x014 */
+ u32 cpu2_cfg; /* 0x018 */
+ u32 cpu3_cfg; /* 0x01c */
+ u8 res1[0x8]; /* 0x020 */
+ u32 apb0_gate; /* 0x028 */
+ u8 res2[0x14]; /* 0x02c */
+ u32 pll_ctrl0; /* 0x040 */
+ u32 pll_ctrl1; /* 0x044 */
+ u8 res3[0x8]; /* 0x048 */
+ u32 clk_1wire; /* 0x050 */
+ u32 clk_ir; /* 0x054 */
+ u8 res4[0x58]; /* 0x058 */
+ u32 apb0_reset; /* 0x0b0 */
+ u8 res5[0x3c]; /* 0x0b4 */
+ u32 clk_outd; /* 0x0f0 */
+ u8 res6[0xc]; /* 0x0f4 */
+ u32 cpu_pwroff; /* 0x100 */
+ u8 res7[0xc]; /* 0x104 */
+ u32 vdd_sys_pwroff; /* 0x110 */
+ u8 res8[0x4]; /* 0x114 */
+ u32 gpu_pwroff; /* 0x118 */
+ u8 res9[0x4]; /* 0x11c */
+ u32 vdd_pwr_reset; /* 0x120 */
+ u8 res10[0x1c]; /* 0x124 */
+ u32 cpu_pwr_clamp[4]; /* 0x140 but first one is actually unused */
+ u8 res11[0x30]; /* 0x150 */
+ u32 dram_pwr; /* 0x180 */
+ u8 res12[0xc]; /* 0x184 */
+ u32 dram_tst; /* 0x190 */
+ u8 res13[0x3c]; /* 0x194 */
+ u32 prcm_sec_switch; /* 0x1d0 */
+};
+
+void prcm_apb0_enable(u32 flags);
+void prcm_apb0_disable(u32 flags);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _PRCM_H */
diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h
index 6f138d0..bb5626d 100644
--- a/arch/arm/include/asm/arch-sunxi/timer.h
+++ b/arch/arm/include/asm/arch-sunxi/timer.h
@@ -76,7 +76,7 @@ struct sunxi_timer_reg {
struct sunxi_tgp tgp[4];
u8 res5[8];
u32 cpu_cfg;
-#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
+#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
u8 res3[16];
struct sunxi_wdog wdog[5]; /* We have 5 watchdogs */
#endif
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 11e6445..0135575 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -48,6 +48,46 @@ config DRAM_SUN50I_H6
Select this dram controller driver for some sun50i platforms,
like H6.
+config DRAM_SUN50I_H616
+ bool
+ help
+ Select this dram controller driver for some sun50i platforms,
+ like H616.
+
+if DRAM_SUN50I_H616
+config DRAM_SUN50I_H616_WRITE_LEVELING
+ bool "H616 DRAM write leveling"
+ ---help---
+ Select this when DRAM on your H616 board needs write leveling.
+
+config DRAM_SUN50I_H616_READ_CALIBRATION
+ bool "H616 DRAM read calibration"
+ ---help---
+ Select this when DRAM on your H616 board needs read calibration.
+
+config DRAM_SUN50I_H616_READ_TRAINING
+ bool "H616 DRAM read training"
+ ---help---
+ Select this when DRAM on your H616 board needs read training.
+
+config DRAM_SUN50I_H616_WRITE_TRAINING
+ bool "H616 DRAM write training"
+ ---help---
+ Select this when DRAM on your H616 board needs write training.
+
+config DRAM_SUN50I_H616_BIT_DELAY_COMPENSATION
+ bool "H616 DRAM bit delay compensation"
+ ---help---
+ Select this when DRAM on your H616 board needs bit delay
+ compensation.
+
+config DRAM_SUN50I_H616_UNKNOWN_FEATURE
+ bool "H616 DRAM unknown feature"
+ ---help---
+ Select this when DRAM on your H616 board needs this unknown
+ feature.
+endif
+
config SUN6I_P2WI
bool "Allwinner sun6i internal P2WI controller"
help
@@ -82,7 +122,7 @@ config SUN8I_RSB
config SUNXI_SRAM_ADDRESS
hex
default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
- default 0x20000 if MACH_SUN50I_H6
+ default 0x20000 if SUN50I_GEN_H6
default 0x0
---help---
Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
@@ -108,6 +148,15 @@ config SUNXI_GEN_SUN6I
separate ahb reset control registers, custom pmic bus, new style
watchdog, etc.
+config SUN50I_GEN_H6
+ bool
+ select FIT
+ select SPL_LOAD_FIT
+ select SUPPORT_SPL
+ ---help---
+ Select this for sunxi SoCs which have H6 like peripherals, clocks
+ and memory map.
+
config SUNXI_DRAM_DW
bool
---help---
@@ -141,9 +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
+ default 0xC0000000 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6 || MACH_SUN50I_H616
default 0x80000000
choice
@@ -302,11 +352,15 @@ config MACH_SUN50I_H5
config MACH_SUN50I_H6
bool "sun50i (Allwinner H6)"
select ARM64
- select SUPPORT_SPL
- select FIT
select PHY_SUN4I_USB
- select SPL_LOAD_FIT
select DRAM_SUN50I_H6
+ select SUN50I_GEN_H6
+
+config MACH_SUN50I_H616
+ bool "sun50i (Allwinner H616)"
+ select ARM64
+ select DRAM_SUN50I_H616
+ select SUN50I_GEN_H6
endchoice
@@ -417,6 +471,7 @@ config DRAM_CLK
MACH_SUN8I_V3S
default 672 if MACH_SUN50I
default 744 if MACH_SUN50I_H6
+ default 720 if MACH_SUN50I_H616
---help---
Set the dram clock speed, valid range 240 - 480 (prior to sun9i),
must be a multiple of 24. For the sun9i (A80), the tested values
@@ -433,6 +488,7 @@ endif
config DRAM_ZQ
int "sunxi dram zq value"
+ depends on !MACH_SUN50I_H616
default 123 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || \
MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_A83T
default 127 if MACH_SUN7I
@@ -450,6 +506,7 @@ config DRAM_ODT_EN
default y if MACH_SUN8I_R40
default y if MACH_SUN50I
default y if MACH_SUN50I_H6
+ default y if MACH_SUN50I_H616
---help---
Select this to enable dram odt (on die termination).
@@ -541,6 +598,7 @@ config SYS_CLK_FREQ
default 1008000000 if MACH_SUN8I
default 1008000000 if MACH_SUN9I
default 888000000 if MACH_SUN50I_H6
+ default 1008000000 if MACH_SUN50I_H616
config SYS_CONFIG_NAME
default "sun4i" if MACH_SUN4I
@@ -551,6 +609,7 @@ config SYS_CONFIG_NAME
default "sun9i" if MACH_SUN9I
default "sun50i" if MACH_SUN50I
default "sun50i" if MACH_SUN50I_H6
+ default "sun50i" if MACH_SUN50I_H616
config SYS_BOARD
default "sunxi"
@@ -723,7 +782,7 @@ config I2C3_ENABLE
See I2C0_ENABLE help text.
endif
-if SUNXI_GEN_SUN6I
+if SUNXI_GEN_SUN6I || SUN50I_GEN_H6
config R_I2C_ENABLE
bool "Enable the PRCM I2C/TWI controller"
# This is used for the pmic on H3
@@ -756,7 +815,7 @@ config VIDEO_SUNXI
depends on !MACH_SUN8I_V3S
depends on !MACH_SUN9I
depends on !MACH_SUN50I
- depends on !MACH_SUN50I_H6
+ depends on !SUN50I_GEN_H6
select VIDEO
imply VIDEO_DT_SIMPLEFB
default y
@@ -989,7 +1048,7 @@ config SPL_STACK_R_ADDR
default 0x4fe00000 if MACH_SUN8I
default 0x2fe00000 if MACH_SUN9I
default 0x4fe00000 if MACH_SUN50I
- default 0x4fe00000 if MACH_SUN50I_H6
+ default 0x4fe00000 if SUN50I_GEN_H6
config SPL_SPI_SUNXI
bool "Support for SPI Flash on Allwinner SoCs in SPL"
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index d129f33..3f081d9 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -26,7 +26,7 @@ else
obj-$(CONFIG_MACH_SUN8I) += clock_sun6i.o
endif
obj-$(CONFIG_MACH_SUN9I) += clock_sun9i.o gtbus_sun9i.o
-obj-$(CONFIG_MACH_SUN50I_H6) += clock_sun50i_h6.o
+obj-$(CONFIG_SUN50I_GEN_H6) += clock_sun50i_h6.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_DRAM_SUN4I) += dram_sun4i.o
@@ -40,4 +40,6 @@ obj-$(CONFIG_SUNXI_DRAM_DW) += dram_sunxi_dw.o
obj-$(CONFIG_SUNXI_DRAM_DW) += dram_timings/
obj-$(CONFIG_DRAM_SUN50I_H6) += dram_sun50i_h6.o
obj-$(CONFIG_DRAM_SUN50I_H6) += dram_timings/
+obj-$(CONFIG_DRAM_SUN50I_H616) += dram_sun50i_h616.o
+obj-$(CONFIG_DRAM_SUN50I_H616) += dram_timings/
endif
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index f40fccd..ae6bc65 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -116,6 +116,10 @@ static int gpio_init(void)
sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H6_GPH_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H6_GPH_UART0);
sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP);
+#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN50I_H616)
+ sunxi_gpio_set_cfgpin(SUNXI_GPH(0), SUN50I_H616_GPH_UART0);
+ sunxi_gpio_set_cfgpin(SUNXI_GPH(1), SUN50I_H616_GPH_UART0);
+ sunxi_gpio_set_pull(SUNXI_GPH(1), SUNXI_GPIO_PULL_UP);
#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_A83T)
sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_A83T_GPB_UART0);
sunxi_gpio_set_cfgpin(SUNXI_GPB(10), SUN8I_A83T_GPB_UART0);
@@ -144,7 +148,7 @@ static int gpio_init(void)
#error Unsupported console port number. Please fix pin mux settings in board.c
#endif
-#ifdef CONFIG_MACH_SUN50I_H6
+#ifdef CONFIG_SUN50I_GEN_H6
/* Update PIO power bias configuration by copy hardware detected value */
val = readl(SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
writel(val, SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
@@ -277,15 +281,29 @@ uint32_t sunxi_get_boot_device(void)
}
#ifdef CONFIG_SPL_BUILD
+static u32 sunxi_get_spl_size(void)
+{
+ if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
+ return 0;
+
+ return readl(SPL_ADDR + 0x10);
+}
+
/*
* The eGON SPL image can be located at 8KB or at 128KB into an SD card or
* an eMMC device. The boot source has bit 4 set in the latter case.
* By adding 120KB to the normal offset when booting from a "high" location
* we can support both cases.
+ * Also U-Boot proper is located at least 32KB after the SPL, but will
+ * immediately follow the SPL if that is bigger than that.
*/
-unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc)
+unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
+ unsigned long raw_sect)
{
- unsigned long sector = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR;
+ unsigned long spl_size = sunxi_get_spl_size();
+ unsigned long sector;
+
+ sector = max(raw_sect, spl_size / 512);
switch (sunxi_get_boot_source()) {
case SUNXI_BOOTED_FROM_MMC0_HIGH:
@@ -329,7 +347,7 @@ void reset_cpu(ulong addr)
/* sun5i sometimes gets stuck without this */
writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
}
-#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN50I_H6)
+#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
#if defined(CONFIG_MACH_SUN50I_H6)
/* WDOG is broken for some H6 rev. use the R_WDOG instead */
static const struct sunxi_wdog *wdog =
diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
index ba8a26e..06d84eb 100644
--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
@@ -2,6 +2,7 @@
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clock.h>
+#include <asm/arch/prcm.h>
#ifdef CONFIG_SPL_BUILD
void clock_init_safe(void)
@@ -67,6 +68,9 @@ void clock_set_pll1(unsigned int clk)
/* clk = 24*n/p, p is ignored if clock is >288MHz */
writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 |
+#ifdef CONFIG_MACH_SUN50I_H616
+ CCM_PLL1_OUT_EN |
+#endif
CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
@@ -82,6 +86,7 @@ unsigned int clock_get_pll6(void)
{
struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ 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);
@@ -89,6 +94,34 @@ unsigned int clock_get_pll6(void)
CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >>
CCM_PLL6_CTRL_DIV2_SHIFT) + 1;
- /* The register defines PLL6-4X, not plain PLL6 */
- return 24000000 / 4 * n / div1 / div2;
+ /* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */
+ return 24000000 / m * n / div1 / div2;
+}
+
+int clock_twi_onoff(int port, int state)
+{
+ struct sunxi_ccm_reg *const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_prcm_reg *const prcm =
+ (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+ u32 value, *ptr;
+ int shift;
+
+ value = BIT(GATE_SHIFT) | BIT (RESET_SHIFT);
+
+ if (port == 5) {
+ shift = 0;
+ ptr = &prcm->twi_gate_reset;
+ } else {
+ shift = port;
+ ptr = &ccm->twi_gate_reset;
+ }
+
+ /* set the apb clock gate and reset for twi */
+ if (state)
+ setbits_le32(ptr, value << shift);
+ else
+ clrbits_le32(ptr, value << shift);
+
+ return 0;
}
diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c
index 875e5a1..ba33ef2 100644
--- a/arch/arm/mach-sunxi/cpu_info.c
+++ b/arch/arm/mach-sunxi/cpu_info.c
@@ -99,6 +99,8 @@ int print_cpuinfo(void)
puts("CPU: Allwinner H5 (SUN50I)\n");
#elif defined CONFIG_MACH_SUN50I_H6
puts("CPU: Allwinner H6 (SUN50I)\n");
+#elif defined CONFIG_MACH_SUN50I_H616
+ puts("CPU: Allwinner H616 (SUN50I)\n");
#else
#warning Please update cpu_info.c with correct CPU information
puts("CPU: SUNXI Family\n");
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c
new file mode 100644
index 0000000..ef58769
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c
@@ -0,0 +1,1023 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * sun50i H616 platform dram controller driver
+ *
+ * While controller is very similar to that in H6, PHY is completely
+ * unknown. That's why this driver has plenty of magic numbers. Some
+ * meaning was nevertheless deduced from strings found in boot0 and
+ * known meaning of some dram parameters.
+ * This driver only supports DDR3 memory and omits logic for all
+ * other supported types supported by hardware.
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ */
+#include <common.h>
+#include <init.h>
+#include <log.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kconfig.h>
+
+enum {
+ MBUS_QOS_LOWEST = 0,
+ MBUS_QOS_LOW,
+ MBUS_QOS_HIGH,
+ MBUS_QOS_HIGHEST
+};
+
+inline void mbus_configure_port(u8 port,
+ bool bwlimit,
+ bool priority,
+ u8 qos,
+ u8 waittime,
+ u8 acs,
+ u16 bwl0,
+ u16 bwl1,
+ u16 bwl2)
+{
+ struct sunxi_mctl_com_reg * const mctl_com =
+ (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+ const u32 cfg0 = ( (bwlimit ? (1 << 0) : 0)
+ | (priority ? (1 << 1) : 0)
+ | ((qos & 0x3) << 2)
+ | ((waittime & 0xf) << 4)
+ | ((acs & 0xff) << 8)
+ | (bwl0 << 16) );
+ const u32 cfg1 = ((u32)bwl2 << 16) | (bwl1 & 0xffff);
+
+ debug("MBUS port %d cfg0 %08x cfg1 %08x\n", port, cfg0, cfg1);
+ writel_relaxed(cfg0, &mctl_com->master[port].cfg0);
+ writel_relaxed(cfg1, &mctl_com->master[port].cfg1);
+}
+
+#define MBUS_CONF(port, bwlimit, qos, acs, bwl0, bwl1, bwl2) \
+ mbus_configure_port(port, bwlimit, false, \
+ MBUS_QOS_ ## qos, 0, acs, bwl0, bwl1, bwl2)
+
+static void mctl_set_master_priority(void)
+{
+ struct sunxi_mctl_com_reg * const mctl_com =
+ (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+
+ /* enable bandwidth limit windows and set windows size 1us */
+ writel(399, &mctl_com->tmr);
+ writel(BIT(16), &mctl_com->bwcr);
+
+ MBUS_CONF( 0, true, HIGHEST, 0, 256, 128, 100);
+ MBUS_CONF( 1, true, HIGH, 0, 1536, 1400, 256);
+ MBUS_CONF( 2, true, HIGHEST, 0, 512, 256, 96);
+ MBUS_CONF( 3, true, HIGH, 0, 256, 100, 80);
+ MBUS_CONF( 4, true, HIGH, 2, 8192, 5500, 5000);
+ MBUS_CONF( 5, true, HIGH, 2, 100, 64, 32);
+ MBUS_CONF( 6, true, HIGH, 2, 100, 64, 32);
+ MBUS_CONF( 8, true, HIGH, 0, 256, 128, 64);
+ MBUS_CONF(11, true, HIGH, 0, 256, 128, 100);
+ MBUS_CONF(14, true, HIGH, 0, 1024, 256, 64);
+ MBUS_CONF(16, true, HIGHEST, 6, 8192, 2800, 2400);
+ MBUS_CONF(21, true, HIGHEST, 6, 2048, 768, 512);
+ MBUS_CONF(25, true, HIGHEST, 0, 100, 64, 32);
+ MBUS_CONF(26, true, HIGH, 2, 8192, 5500, 5000);
+ MBUS_CONF(37, true, HIGH, 0, 256, 128, 64);
+ MBUS_CONF(38, true, HIGH, 2, 100, 64, 32);
+ MBUS_CONF(39, true, HIGH, 2, 8192, 5500, 5000);
+ MBUS_CONF(40, true, HIGH, 2, 100, 64, 32);
+
+ dmb();
+}
+
+static void mctl_sys_init(struct dram_para *para)
+{
+ struct sunxi_ccm_reg * const ccm =
+ (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_mctl_com_reg * const mctl_com =
+ (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+ /* Put all DRAM-related blocks to reset state */
+ clrbits_le32(&ccm->mbus_cfg, MBUS_ENABLE);
+ clrbits_le32(&ccm->mbus_cfg, MBUS_RESET);
+ clrbits_le32(&ccm->dram_gate_reset, BIT(GATE_SHIFT));
+ udelay(5);
+ clrbits_le32(&ccm->dram_gate_reset, BIT(RESET_SHIFT));
+ clrbits_le32(&ccm->pll5_cfg, CCM_PLL5_CTRL_EN);
+ clrbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET);
+
+ udelay(5);
+
+ /* 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);
+ mctl_await_completion(&ccm->pll5_cfg, CCM_PLL5_LOCK, CCM_PLL5_LOCK);
+
+ /* Configure DRAM mod clock */
+ writel(DRAM_CLK_SRC_PLL5, &ccm->dram_clk_cfg);
+ writel(BIT(RESET_SHIFT), &ccm->dram_gate_reset);
+ udelay(5);
+ setbits_le32(&ccm->dram_gate_reset, BIT(GATE_SHIFT));
+
+ /* Disable all channels */
+ writel(0, &mctl_com->maer0);
+ writel(0, &mctl_com->maer1);
+ writel(0, &mctl_com->maer2);
+
+ /* Configure MBUS and enable DRAM mod reset */
+ setbits_le32(&ccm->mbus_cfg, MBUS_RESET);
+ setbits_le32(&ccm->mbus_cfg, MBUS_ENABLE);
+
+ clrbits_le32(&mctl_com->unk_0x500, BIT(25));
+
+ setbits_le32(&ccm->dram_clk_cfg, DRAM_MOD_RESET);
+ udelay(5);
+
+ /* Unknown hack, which enables access of mctl_ctl regs */
+ writel(0x8000, &mctl_ctl->clken);
+}
+
+static void mctl_set_addrmap(struct dram_para *para)
+{
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+ u8 cols = para->cols;
+ u8 rows = para->rows;
+ u8 ranks = para->ranks;
+
+ if (!para->bus_full_width)
+ cols -= 1;
+
+ /* Ranks */
+ if (ranks == 2)
+ mctl_ctl->addrmap[0] = rows + cols - 3;
+ else
+ mctl_ctl->addrmap[0] = 0x1F;
+
+ /* Banks, hardcoded to 8 banks now */
+ mctl_ctl->addrmap[1] = (cols - 2) | (cols - 2) << 8 | (cols - 2) << 16;
+
+ /* Columns */
+ mctl_ctl->addrmap[2] = 0;
+ switch (cols) {
+ case 7:
+ mctl_ctl->addrmap[3] = 0x1F1F1F00;
+ mctl_ctl->addrmap[4] = 0x1F1F;
+ break;
+ case 8:
+ mctl_ctl->addrmap[3] = 0x1F1F0000;
+ mctl_ctl->addrmap[4] = 0x1F1F;
+ break;
+ case 9:
+ mctl_ctl->addrmap[3] = 0x1F000000;
+ mctl_ctl->addrmap[4] = 0x1F1F;
+ break;
+ case 10:
+ mctl_ctl->addrmap[3] = 0;
+ mctl_ctl->addrmap[4] = 0x1F1F;
+ break;
+ case 11:
+ mctl_ctl->addrmap[3] = 0;
+ mctl_ctl->addrmap[4] = 0x1F00;
+ break;
+ case 12:
+ mctl_ctl->addrmap[3] = 0;
+ mctl_ctl->addrmap[4] = 0;
+ break;
+ default:
+ panic("Unsupported DRAM configuration: column number invalid\n");
+ }
+
+ /* Rows */
+ mctl_ctl->addrmap[5] = (cols - 3) | ((cols - 3) << 8) | ((cols - 3) << 16) | ((cols - 3) << 24);
+ switch (rows) {
+ case 13:
+ mctl_ctl->addrmap[6] = (cols - 3) | 0x0F0F0F00;
+ mctl_ctl->addrmap[7] = 0x0F0F;
+ break;
+ case 14:
+ mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | 0x0F0F0000;
+ mctl_ctl->addrmap[7] = 0x0F0F;
+ break;
+ case 15:
+ mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | ((cols - 3) << 16) | 0x0F000000;
+ mctl_ctl->addrmap[7] = 0x0F0F;
+ break;
+ case 16:
+ mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | ((cols - 3) << 16) | ((cols - 3) << 24);
+ mctl_ctl->addrmap[7] = 0x0F0F;
+ break;
+ case 17:
+ mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | ((cols - 3) << 16) | ((cols - 3) << 24);
+ mctl_ctl->addrmap[7] = (cols - 3) | 0x0F00;
+ break;
+ case 18:
+ mctl_ctl->addrmap[6] = (cols - 3) | ((cols - 3) << 8) | ((cols - 3) << 16) | ((cols - 3) << 24);
+ mctl_ctl->addrmap[7] = (cols - 3) | ((cols - 3) << 8);
+ break;
+ default:
+ panic("Unsupported DRAM configuration: row number invalid\n");
+ }
+
+ /* Bank groups, DDR4 only */
+ mctl_ctl->addrmap[8] = 0x3F3F;
+}
+
+static const u8 phy_init[] = {
+ 0x07, 0x0b, 0x02, 0x16, 0x0d, 0x0e, 0x14, 0x19,
+ 0x0a, 0x15, 0x03, 0x13, 0x04, 0x0c, 0x10, 0x06,
+ 0x0f, 0x11, 0x1a, 0x01, 0x12, 0x17, 0x00, 0x08,
+ 0x09, 0x05, 0x18
+};
+
+static void mctl_phy_configure_odt(void)
+{
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x388);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x38c);
+
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3c8);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x3cc);
+
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x408);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x40c);
+
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x448);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x44c);
+
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x340);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x344);
+
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x348);
+ writel_relaxed(0xe, SUNXI_DRAM_PHY0_BASE + 0x34c);
+
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x380);
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x384);
+
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c0);
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x3c4);
+
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x400);
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x404);
+
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x440);
+ writel_relaxed(0x8, SUNXI_DRAM_PHY0_BASE + 0x444);
+
+ dmb();
+}
+
+static bool mctl_phy_write_leveling(struct dram_para *para)
+{
+ bool result = true;
+ u32 val;
+
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0, 0x80);
+ writel(4, SUNXI_DRAM_PHY0_BASE + 0xc);
+ writel(0x40, SUNXI_DRAM_PHY0_BASE + 0x10);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4);
+
+ if (para->bus_full_width)
+ val = 0xf;
+ else
+ val = 3;
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val);
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4);
+
+ val = readl(SUNXI_DRAM_PHY0_BASE + 0x258);
+ if (val == 0 || val == 0x3f)
+ result = false;
+ val = readl(SUNXI_DRAM_PHY0_BASE + 0x25c);
+ if (val == 0 || val == 0x3f)
+ result = false;
+ val = readl(SUNXI_DRAM_PHY0_BASE + 0x318);
+ if (val == 0 || val == 0x3f)
+ result = false;
+ val = readl(SUNXI_DRAM_PHY0_BASE + 0x31c);
+ if (val == 0 || val == 0x3f)
+ result = false;
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0);
+
+ if (para->ranks == 2) {
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0, 0x40);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4);
+
+ if (para->bus_full_width)
+ val = 0xf;
+ else
+ val = 3;
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x188), val, val);
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 4);
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0xc0);
+
+ return result;
+}
+
+static bool mctl_phy_read_calibration(struct dram_para *para)
+{
+ bool result = true;
+ u32 val, tmp;
+
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30, 0x20);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1);
+
+ if (para->bus_full_width)
+ val = 0xf;
+ else
+ val = 3;
+
+ while ((readl(SUNXI_DRAM_PHY0_BASE + 0x184) & val) != val) {
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x184) & 0x20) {
+ result = false;
+ break;
+ }
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1);
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30);
+
+ if (para->ranks == 2) {
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30, 0x10);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1);
+
+ while ((readl(SUNXI_DRAM_PHY0_BASE + 0x184) & val) != val) {
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x184) & 0x20) {
+ result = false;
+ break;
+ }
+ }
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 1);
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 0x30);
+
+ val = readl(SUNXI_DRAM_PHY0_BASE + 0x274) & 7;
+ tmp = readl(SUNXI_DRAM_PHY0_BASE + 0x26c) & 7;
+ if (val < tmp)
+ val = tmp;
+ tmp = readl(SUNXI_DRAM_PHY0_BASE + 0x32c) & 7;
+ if (val < tmp)
+ val = tmp;
+ tmp = readl(SUNXI_DRAM_PHY0_BASE + 0x334) & 7;
+ if (val < tmp)
+ val = tmp;
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x38, 0x7, (val + 2) & 7);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 0x20);
+
+ return result;
+}
+
+static bool mctl_phy_read_training(struct dram_para *para)
+{
+ u32 val1, val2, *ptr1, *ptr2;
+ bool result = true;
+ int i;
+
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2);
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x804, 0x3f, 0xf);
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x808, 0x3f, 0xf);
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa04, 0x3f, 0xf);
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0xa08, 0x3f, 0xf);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6);
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1);
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3)
+ result = false;
+
+ if (para->bus_full_width) {
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3)
+ result = false;
+ }
+
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x898);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x850);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x8bc);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x874);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+
+ if (para->bus_full_width) {
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa98);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa50);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xabc);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xa74);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3);
+
+ if (para->ranks == 2) {
+ /* maybe last parameter should be 1? */
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3, 2);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 6);
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 1);
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x840), 0xc, 0xc);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x840) & 3)
+ result = false;
+
+ if (para->bus_full_width) {
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xa40), 0xc, 0xc);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0xa40) & 3)
+ result = false;
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 3);
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 3);
+
+ return result;
+}
+
+static bool mctl_phy_write_training(struct dram_para *para)
+{
+ u32 val1, val2, *ptr1, *ptr2;
+ bool result = true;
+ int i;
+
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x134);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x138);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x19c);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x1a0);
+
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 8);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20);
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc)
+ result = false;
+
+ if (para->bus_full_width) {
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc)
+ result = false;
+ }
+
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x938);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x8f0);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x95c);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x914);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+
+ if (para->bus_full_width) {
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xb38);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xaf0);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+ ptr1 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xb5c);
+ ptr2 = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xb14);
+ for (i = 0; i < 9; i++) {
+ val1 = readl(&ptr1[i]);
+ val2 = readl(&ptr2[i]);
+ if (val1 - val2 <= 6)
+ result = false;
+ }
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60);
+
+ if (para->ranks == 2) {
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc, 4);
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x20);
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x8e0), 3, 3);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0x8e0) & 0xc)
+ result = false;
+
+ if (para->bus_full_width) {
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0xae0), 3, 3);
+ if (readl(SUNXI_DRAM_PHY0_BASE + 0xae0) & 0xc)
+ result = false;
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x60);
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x198, 0xc);
+
+ return result;
+}
+
+static bool mctl_phy_bit_delay_compensation(struct dram_para *para)
+{
+ u32 *ptr;
+ int i;
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1);
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 8, 8);
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 0x10);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x484);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x16, ptr);
+ writel_relaxed(0x16, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4d0);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x590);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x4cc);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x58c);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x4d8);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x1a, ptr);
+ writel_relaxed(0x1a, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x524);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x5e4);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x520);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x5e0);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x604);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x1a, ptr);
+ writel_relaxed(0x1a, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x650);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x710);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x64c);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x70c);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x658);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x1a, ptr);
+ writel_relaxed(0x1a, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x6a4);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x764);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x6a0);
+ writel_relaxed(0x1e, SUNXI_DRAM_PHY0_BASE + 0x760);
+
+ dmb();
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1);
+
+ /* second part */
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, 0x80);
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, 4);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x480);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x10, ptr);
+ writel_relaxed(0x10, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x18, SUNXI_DRAM_PHY0_BASE + 0x528);
+ writel_relaxed(0x18, SUNXI_DRAM_PHY0_BASE + 0x5e8);
+ writel_relaxed(0x18, SUNXI_DRAM_PHY0_BASE + 0x4c8);
+ writel_relaxed(0x18, SUNXI_DRAM_PHY0_BASE + 0x588);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x4d4);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x12, ptr);
+ writel_relaxed(0x12, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x52c);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x5ec);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x51c);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x5dc);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x600);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x12, ptr);
+ writel_relaxed(0x12, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x6a8);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x768);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x648);
+ writel_relaxed(0x1a, SUNXI_DRAM_PHY0_BASE + 0x708);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x654);
+ for (i = 0; i < 9; i++) {
+ writel_relaxed(0x14, ptr);
+ writel_relaxed(0x14, ptr + 0x30);
+ ptr += 2;
+ }
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x6ac);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x76c);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x69c);
+ writel_relaxed(0x1c, SUNXI_DRAM_PHY0_BASE + 0x75c);
+
+ dmb();
+
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, 0x80);
+
+ return true;
+}
+
+static bool mctl_phy_init(struct dram_para *para)
+{
+ struct sunxi_mctl_com_reg * const mctl_com =
+ (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+ u32 val, *ptr;
+ int i;
+
+ if (para->bus_full_width)
+ val = 0xf;
+ else
+ val = 3;
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x3c, 0xf, val);
+
+ writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x14);
+ writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x35c);
+ writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x368);
+ writel(0xd, SUNXI_DRAM_PHY0_BASE + 0x374);
+
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x18);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x360);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x36c);
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x378);
+
+ writel(9, SUNXI_DRAM_PHY0_BASE + 0x1c);
+ writel(9, SUNXI_DRAM_PHY0_BASE + 0x364);
+ writel(9, SUNXI_DRAM_PHY0_BASE + 0x370);
+ writel(9, SUNXI_DRAM_PHY0_BASE + 0x37c);
+
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0xc0);
+ for (i = 0; i < ARRAY_SIZE(phy_init); i++)
+ writel(phy_init[i], &ptr[i]);
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_UNKNOWN_FEATURE)) {
+ ptr = (u32*)(SUNXI_DRAM_PHY0_BASE + 0x780);
+ for (i = 0; i < 32; i++)
+ writel(0x16, &ptr[i]);
+ writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x78c);
+ writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7a4);
+ writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7b8);
+ writel(0x8, SUNXI_DRAM_PHY0_BASE + 0x7d4);
+ writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7dc);
+ writel(0xe, SUNXI_DRAM_PHY0_BASE + 0x7e0);
+ }
+
+ writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x3dc);
+ writel(0x80, SUNXI_DRAM_PHY0_BASE + 0x45c);
+
+ if (IS_ENABLED(DRAM_ODT_EN))
+ mctl_phy_configure_odt();
+
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 4, 7, 0xa);
+
+ if (para->clk <= 672)
+ writel(0xf, SUNXI_DRAM_PHY0_BASE + 0x20);
+ if (para->clk > 500) {
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x144, BIT(7));
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x14c, 0xe0);
+ } else {
+ setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x144, BIT(7));
+ clrsetbits_le32(SUNXI_DRAM_PHY0_BASE + 0x14c, 0xe0, 0x20);
+ }
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x14c, 8);
+
+ mctl_await_completion((u32*)(SUNXI_DRAM_PHY0_BASE + 0x180), 4, 4);
+
+ writel(0x37, SUNXI_DRAM_PHY0_BASE + 0x58);
+ clrbits_le32(&mctl_com->unk_0x500, 0x200);
+
+ writel(0, &mctl_ctl->swctl);
+ setbits_le32(&mctl_ctl->dfimisc, 1);
+
+ /* start DFI init */
+ setbits_le32(&mctl_ctl->dfimisc, 0x20);
+ writel(1, &mctl_ctl->swctl);
+ mctl_await_completion(&mctl_ctl->swstat, 1, 1);
+ /* poll DFI init complete */
+ mctl_await_completion(&mctl_ctl->dfistat, 1, 1);
+ writel(0, &mctl_ctl->swctl);
+ clrbits_le32(&mctl_ctl->dfimisc, 0x20);
+
+ clrbits_le32(&mctl_ctl->pwrctl, 0x20);
+ writel(1, &mctl_ctl->swctl);
+ mctl_await_completion(&mctl_ctl->swstat, 1, 1);
+ mctl_await_completion(&mctl_ctl->statr, 3, 1);
+
+ writel(0, &mctl_ctl->swctl);
+ clrbits_le32(&mctl_ctl->dfimisc, 1);
+
+ writel(1, &mctl_ctl->swctl);
+ mctl_await_completion(&mctl_ctl->swstat, 1, 1);
+
+ writel(0x1f14, &mctl_ctl->mrctrl1);
+ writel(0x80000030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(4, &mctl_ctl->mrctrl1);
+ writel(0x80001030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0x20, &mctl_ctl->mrctrl1);
+ writel(0x80002030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0, &mctl_ctl->mrctrl1);
+ writel(0x80003030, &mctl_ctl->mrctrl0);
+ mctl_await_completion(&mctl_ctl->mrctrl0, BIT(31), 0);
+
+ writel(0, SUNXI_DRAM_PHY0_BASE + 0x54);
+
+ writel(0, &mctl_ctl->swctl);
+ clrbits_le32(&mctl_ctl->rfshctl3, 1);
+ writel(1, &mctl_ctl->swctl);
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_WRITE_LEVELING)) {
+ for (i = 0; i < 5; i++)
+ if (mctl_phy_write_leveling(para))
+ break;
+ if (i == 5) {
+ debug("write leveling failed!\n");
+ return false;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_READ_CALIBRATION)) {
+ for (i = 0; i < 5; i++)
+ if (mctl_phy_read_calibration(para))
+ break;
+ if (i == 5) {
+ debug("read calibration failed!\n");
+ return false;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_READ_TRAINING)) {
+ for (i = 0; i < 5; i++)
+ if (mctl_phy_read_training(para))
+ break;
+ if (i == 5) {
+ debug("read training failed!\n");
+ return false;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_WRITE_TRAINING)) {
+ for (i = 0; i < 5; i++)
+ if (mctl_phy_write_training(para))
+ break;
+ if (i == 5) {
+ debug("write training failed!\n");
+ return false;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_BIT_DELAY_COMPENSATION))
+ mctl_phy_bit_delay_compensation(para);
+
+ clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 4);
+
+ return true;
+}
+
+static bool mctl_ctrl_init(struct dram_para *para)
+{
+ struct sunxi_mctl_com_reg * const mctl_com =
+ (struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+ u32 reg_val;
+
+ clrsetbits_le32(&mctl_com->unk_0x500, BIT(24), 0x200);
+ writel(0x8000, &mctl_ctl->clken);
+
+ setbits_le32(&mctl_com->unk_0x008, 0xff00);
+
+ clrsetbits_le32(&mctl_ctl->sched[0], 0xff00, 0x3000);
+
+ writel(0, &mctl_ctl->hwlpctl);
+
+ setbits_le32(&mctl_com->unk_0x008, 0xff00);
+
+ reg_val = MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks);
+ reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE;
+ if (para->bus_full_width)
+ reg_val |= MSTR_BUSWIDTH_FULL;
+ else
+ reg_val |= MSTR_BUSWIDTH_HALF;
+ writel(BIT(31) | BIT(30) | reg_val, &mctl_ctl->mstr);
+
+ if (para->ranks == 2)
+ writel(0x0303, &mctl_ctl->odtmap);
+ else
+ writel(0x0201, &mctl_ctl->odtmap);
+
+ writel(0x06000400, &mctl_ctl->odtcfg);
+ writel(0x06000400, &mctl_ctl->unk_0x2240);
+ writel(0x06000400, &mctl_ctl->unk_0x3240);
+ writel(0x06000400, &mctl_ctl->unk_0x4240);
+
+ setbits_le32(&mctl_com->cr, BIT(31));
+
+ mctl_set_addrmap(para);
+
+ mctl_set_timing_params(para);
+
+ writel(0, &mctl_ctl->pwrctl);
+
+ setbits_le32(&mctl_ctl->dfiupd[0], BIT(31) | BIT(30));
+ setbits_le32(&mctl_ctl->zqctl[0], BIT(31) | BIT(30));
+ setbits_le32(&mctl_ctl->unk_0x2180, BIT(31) | BIT(30));
+ setbits_le32(&mctl_ctl->unk_0x3180, BIT(31) | BIT(30));
+ setbits_le32(&mctl_ctl->unk_0x4180, BIT(31) | BIT(30));
+
+ setbits_le32(&mctl_ctl->rfshctl3, BIT(0));
+ clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
+
+ writel(0, &mctl_com->maer0);
+ writel(0, &mctl_com->maer1);
+ writel(0, &mctl_com->maer2);
+
+ writel(0x20, &mctl_ctl->pwrctl);
+ setbits_le32(&mctl_ctl->clken, BIT(8));
+
+ clrsetbits_le32(&mctl_com->unk_0x500, BIT(24), 0x300);
+ /* this write seems to enable PHY MMIO region */
+ setbits_le32(&mctl_com->unk_0x500, BIT(24));
+
+ if (!mctl_phy_init(para))
+ return false;
+
+ writel(0, &mctl_ctl->swctl);
+ clrbits_le32(&mctl_ctl->rfshctl3, BIT(0));
+
+ setbits_le32(&mctl_com->unk_0x014, BIT(31));
+ writel(0xffffffff, &mctl_com->maer0);
+ writel(0x7ff, &mctl_com->maer1);
+ writel(0xffff, &mctl_com->maer2);
+
+ writel(1, &mctl_ctl->swctl);
+ mctl_await_completion(&mctl_ctl->swstat, 1, 1);
+
+ return true;
+}
+
+static bool mctl_core_init(struct dram_para *para)
+{
+ mctl_sys_init(para);
+
+ return mctl_ctrl_init(para);
+}
+
+static void mctl_auto_detect_rank_width(struct dram_para *para)
+{
+ /* this is minimum size that it's supported */
+ para->cols = 8;
+ para->rows = 13;
+
+ /*
+ * Strategy here is to test most demanding combination first and least
+ * demanding last, otherwise HW might not be fully utilized. For
+ * example, half bus width and rank = 1 combination would also work
+ * on HW with full bus width and rank = 2, but only 1/4 RAM would be
+ * visible.
+ */
+
+ debug("testing 32-bit width, rank = 2\n");
+ para->bus_full_width = 1;
+ para->ranks = 2;
+ if (mctl_core_init(para))
+ return;
+
+ debug("testing 32-bit width, rank = 1\n");
+ para->bus_full_width = 1;
+ para->ranks = 1;
+ if (mctl_core_init(para))
+ return;
+
+ debug("testing 16-bit width, rank = 2\n");
+ para->bus_full_width = 0;
+ para->ranks = 2;
+ if (mctl_core_init(para))
+ return;
+
+ debug("testing 16-bit width, rank = 1\n");
+ para->bus_full_width = 0;
+ para->ranks = 1;
+ if (mctl_core_init(para))
+ return;
+
+ panic("This DRAM setup is currently not supported.\n");
+}
+
+static void mctl_auto_detect_dram_size(struct dram_para *para)
+{
+ /* detect row address bits */
+ para->cols = 8;
+ para->rows = 18;
+ mctl_core_init(para);
+
+ for (para->rows = 13; para->rows < 18; para->rows++) {
+ /* 8 banks, 8 bit per byte and 16/32 bit width */
+ if (mctl_mem_matches((1 << (para->rows + para->cols +
+ 4 + para->bus_full_width))))
+ break;
+ }
+
+ /* detect column address bits */
+ para->cols = 11;
+ mctl_core_init(para);
+
+ for (para->cols = 8; para->cols < 11; para->cols++) {
+ /* 8 bits per byte and 16/32 bit width */
+ if (mctl_mem_matches(1 << (para->cols + 1 +
+ para->bus_full_width)))
+ break;
+ }
+}
+
+static unsigned long mctl_calc_size(struct dram_para *para)
+{
+ u8 width = para->bus_full_width ? 4 : 2;
+
+ /* 8 banks */
+ return (1ULL << (para->cols + para->rows + 3)) * width * para->ranks;
+}
+
+unsigned long sunxi_dram_init(void)
+{
+ struct dram_para para = {
+ .clk = CONFIG_DRAM_CLK,
+ .type = SUNXI_DRAM_TYPE_DDR3,
+ };
+ unsigned long size;
+
+ setbits_le32(0x7010310, BIT(8));
+ clrbits_le32(0x7010318, 0x3f);
+
+ mctl_auto_detect_rank_width(&para);
+ mctl_auto_detect_dram_size(&para);
+
+ mctl_core_init(&para);
+
+ size = mctl_calc_size(&para);
+
+ mctl_set_master_priority();
+
+ return size;
+};
diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile
index 0deb991..39a8756 100644
--- a/arch/arm/mach-sunxi/dram_timings/Makefile
+++ b/arch/arm/mach-sunxi/dram_timings/Makefile
@@ -3,3 +3,5 @@ obj-$(CONFIG_SUNXI_DRAM_LPDDR3_STOCK) += lpddr3_stock.o
obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S) += ddr2_v3s.o
obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3) += h6_lpddr3.o
obj-$(CONFIG_SUNXI_DRAM_H6_DDR3_1333) += h6_ddr3_1333.o
+# currently only DDR3 is supported on H616
+obj-$(CONFIG_MACH_SUN50I_H616) += h616_ddr3_1333.o
diff --git a/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c
new file mode 100644
index 0000000..8f50834
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c
@@ -0,0 +1,94 @@
+/*
+ * sun50i H616 DDR3-1333 timings, as programmed by Allwinner's boot0
+ *
+ * The chips are probably able to be driven by a faster clock, but boot0
+ * uses a more conservative timing (as usual).
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ * Based on H6 DDR3 timings:
+ * (C) Copyright 2018,2019 Arm Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+
+void mctl_set_timing_params(struct dram_para *para)
+{
+ struct sunxi_mctl_ctl_reg * const mctl_ctl =
+ (struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+
+ u8 tccd = 2; /* JEDEC: 4nCK */
+ u8 tfaw = ns_to_t(50); /* JEDEC: 30 ns w/ 1K pages */
+ u8 trrd = max(ns_to_t(6), 4); /* JEDEC: max(6 ns, 4nCK) */
+ u8 trcd = ns_to_t(15); /* JEDEC: 13.5 ns */
+ u8 trc = ns_to_t(53); /* JEDEC: 49.5 ns */
+ u8 txp = max(ns_to_t(6), 3); /* JEDEC: max(6 ns, 3nCK) */
+ u8 trtp = max(ns_to_t(8), 2); /* JEDEC: max(7.5 ns, 4nCK) */
+ u8 trp = ns_to_t(15); /* JEDEC: >= 13.75 ns */
+ u8 tras = ns_to_t(38); /* JEDEC >= 36 ns, <= 9*trefi */
+ u16 trefi = ns_to_t(7800) / 32; /* JEDEC: 7.8us@Tcase <= 85C */
+ u16 trfc = ns_to_t(350); /* JEDEC: 160 ns for 2Gb */
+ u16 txsr = 4; /* ? */
+
+ u8 tmrw = 0; /* ? */
+ u8 tmrd = 4; /* JEDEC: 4nCK */
+ u8 tmod = max(ns_to_t(15), 12); /* JEDEC: max(15 ns, 12nCK) */
+ u8 tcke = max(ns_to_t(6), 3); /* JEDEC: max(5.625 ns, 3nCK) */
+ u8 tcksrx = max(ns_to_t(10), 4); /* JEDEC: max(10 ns, 5nCK) */
+ u8 tcksre = max(ns_to_t(10), 4); /* JEDEC: max(10 ns, 5nCK) */
+ u8 tckesr = tcke + 1; /* JEDEC: tCKE(min) + 1nCK */
+ u8 trasmax = (para->clk / 2) / 15; /* JEDEC: tREFI * 9 */
+ u8 txs = ns_to_t(360) / 32; /* JEDEC: max(5nCK,tRFC+10ns) */
+ u8 txsdll = 16; /* JEDEC: 512 nCK */
+ u8 txsabort = 4; /* ? */
+ u8 txsfast = 4; /* ? */
+ u8 tcl = 7; /* JEDEC: CL / 2 => 6 */
+ u8 tcwl = 5; /* JEDEC: 8 */
+ u8 t_rdata_en = 9; /* ? */
+
+ u8 twtp = 14; /* (WL + BL / 2 + tWR) / 2 */
+ u8 twr2rd = trtp + 7; /* (WL + BL / 2 + tWTR) / 2 */
+ u8 trd2wr = 5; /* (RL + BL / 2 + 2 - WL) / 2 */
+
+ /* set DRAM timing */
+ writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras,
+ &mctl_ctl->dramtmg[0]);
+ writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]);
+ writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd,
+ &mctl_ctl->dramtmg[2]);
+ writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]);
+ writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp,
+ &mctl_ctl->dramtmg[4]);
+ writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke,
+ &mctl_ctl->dramtmg[5]);
+ /* Value suggested by ZynqMP manual and used by libdram */
+ writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]);
+ writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs,
+ &mctl_ctl->dramtmg[8]);
+ writel(0x00020208, &mctl_ctl->dramtmg[9]);
+ writel(0xE0C05, &mctl_ctl->dramtmg[10]);
+ writel(0x440C021C, &mctl_ctl->dramtmg[11]);
+ writel(8, &mctl_ctl->dramtmg[12]);
+ writel(0xA100002, &mctl_ctl->dramtmg[13]);
+ writel(txsr, &mctl_ctl->dramtmg[14]);
+
+ clrbits_le32(&mctl_ctl->init[0], 3 << 30);
+ writel(0x420000, &mctl_ctl->init[1]);
+ writel(5, &mctl_ctl->init[2]);
+ writel(0x1f140004, &mctl_ctl->init[3]);
+ writel(0x00200000, &mctl_ctl->init[4]);
+
+ writel(0, &mctl_ctl->dfimisc);
+ clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
+
+ /* Configure DFI timing */
+ writel((tcl - 2) | 0x2000000 | (t_rdata_en << 16) | 0x808000,
+ &mctl_ctl->dfitmg0);
+ writel(0x100202, &mctl_ctl->dfitmg1);
+
+ /* set refresh timing */
+ writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
+}
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index dea42de..0394ce8 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -18,6 +18,8 @@
#define AXP209_I2C_ADDR 0x34
+#define AXP305_I2C_ADDR 0x36
+
#define AXP221_CHIP_ADDR 0x68
#define AXP221_CTRL_ADDR 0x3e
#define AXP221_INIT_DATA 0x3e
@@ -64,6 +66,8 @@ int pmic_bus_read(u8 reg, u8 *data)
return i2c_read(AXP152_I2C_ADDR, reg, 1, data, 1);
#elif defined CONFIG_AXP209_POWER
return i2c_read(AXP209_I2C_ADDR, reg, 1, data, 1);
+#elif defined CONFIG_AXP305_POWER
+ return i2c_read(AXP305_I2C_ADDR, reg, 1, data, 1);
#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
# ifdef CONFIG_MACH_SUN6I
return p2wi_read(reg, data);
@@ -81,6 +85,8 @@ int pmic_bus_write(u8 reg, u8 data)
return i2c_write(AXP152_I2C_ADDR, reg, 1, &data, 1);
#elif defined CONFIG_AXP209_POWER
return i2c_write(AXP209_I2C_ADDR, reg, 1, &data, 1);
+#elif defined CONFIG_AXP305_POWER
+ return i2c_write(AXP305_I2C_ADDR, reg, 1, &data, 1);
#elif defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
# ifdef CONFIG_MACH_SUN6I
return p2wi_write(reg, data);
diff --git a/arch/arm/mach-sunxi/rmr_switch.S b/arch/arm/mach-sunxi/rmr_switch.S
index fafd306..33e55d4 100644
--- a/arch/arm/mach-sunxi/rmr_switch.S
+++ b/arch/arm/mach-sunxi/rmr_switch.S
@@ -30,7 +30,7 @@
.text
-#ifndef CONFIG_MACH_SUN50I_H6
+#ifndef CONFIG_SUN50I_GEN_H6
ldr r1, =0x017000a0 @ MMIO mapped RVBAR[0] register
#else
ldr r1, =0x09010040 @ MMIO mapped RVBAR[0] register
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 735801a..76eba2a 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -385,6 +385,11 @@ M: Icenowy Zheng <icenowy@aosc.io>
S: Maintained
F: configs/teres_i_defconfig
+ORANGEPI 3 BOARD
+M: Andre Heider <a.heider@gmail.com>
+S: Maintained
+F: configs/orangepi_3_defconfig
+
ORANGEPI LITE2 BOARD
M: Jagan Teki <jagan@amarulasolutions.com>
S: Maintained
@@ -420,6 +425,11 @@ M: Diego Rondini <diego.rondini@kynetics.com>
S: Maintained
F: configs/orangepi_zero_plus2_h3_defconfig
+ORANGEPI ZERO 2 BOARD
+M: Jernej Skrabec <jernej.skrabec@siol.net>
+S: Maintained
+F: configs/orangepi_zero2_defconfig
+
ORANGEPI PC 2 BOARD
M: Andre Przywara <andre.przywara@arm.com>
S: Maintained
@@ -494,6 +504,12 @@ S: Maintained
F: configs/Sunchip_CX-A99_defconfig
W: https://linux-sunxi.org/Sunchip_CX-A99
+TANIX TX6 BOARD
+M: Jernej Skrabec <jernej.skrabec@siol.net>
+S: Maintained
+F: configs/tanix_tx6_defconfig
+W: https://linux-sunxi.org/Tanix_TX6
+
TBS A711 BOARD
M: Maxime Ripard <mripard@kernel.org>
S: Maintained
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 4f05895..e42b61e 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -197,6 +197,10 @@ void i2c_init_board(void)
clock_twi_onoff(5, 1);
sunxi_gpio_set_cfgpin(SUNXI_GPL(8), SUN50I_GPL_R_TWI);
sunxi_gpio_set_cfgpin(SUNXI_GPL(9), SUN50I_GPL_R_TWI);
+#elif CONFIG_MACH_SUN50I_H616
+ clock_twi_onoff(5, 1);
+ sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN50I_H616_GPL_R_TWI);
+ sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN50I_H616_GPL_R_TWI);
#else
clock_twi_onoff(5, 1);
sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_H3_GPL_R_TWI);
@@ -265,18 +269,28 @@ int board_init(void)
if (ret)
return ret;
-#ifdef CONFIG_SATAPWR
- satapwr_pin = sunxi_name_to_gpio(CONFIG_SATAPWR);
- gpio_request(satapwr_pin, "satapwr");
- gpio_direction_output(satapwr_pin, 1);
- /* Give attached sata device time to power-up to avoid link timeouts */
- mdelay(500);
-#endif
-#ifdef CONFIG_MACPWR
- macpwr_pin = sunxi_name_to_gpio(CONFIG_MACPWR);
- gpio_request(macpwr_pin, "macpwr");
- gpio_direction_output(macpwr_pin, 1);
-#endif
+ /* strcmp() would look better, but doesn't get optimised away. */
+ if (CONFIG_SATAPWR[0]) {
+ satapwr_pin = sunxi_name_to_gpio(CONFIG_SATAPWR);
+ if (satapwr_pin >= 0) {
+ gpio_request(satapwr_pin, "satapwr");
+ gpio_direction_output(satapwr_pin, 1);
+
+ /*
+ * Give the attached SATA device time to power-up
+ * to avoid link timeouts
+ */
+ mdelay(500);
+ }
+ }
+
+ if (CONFIG_MACPWR[0]) {
+ macpwr_pin = sunxi_name_to_gpio(CONFIG_MACPWR);
+ if (macpwr_pin >= 0) {
+ gpio_request(macpwr_pin, "macpwr");
+ gpio_direction_output(macpwr_pin, 1);
+ }
+ }
#ifdef CONFIG_DM_I2C
/*
@@ -635,16 +649,18 @@ void sunxi_board_init(void)
#endif
#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
- defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
- defined CONFIG_AXP818_POWER
+ defined CONFIG_AXP221_POWER || defined CONFIG_AXP305_POWER || \
+ defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
power_failed = axp_init();
#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
defined CONFIG_AXP818_POWER
power_failed |= axp_set_dcdc1(CONFIG_AXP_DCDC1_VOLT);
#endif
+#if !defined(CONFIG_AXP305_POWER)
power_failed |= axp_set_dcdc2(CONFIG_AXP_DCDC2_VOLT);
power_failed |= axp_set_dcdc3(CONFIG_AXP_DCDC3_VOLT);
+#endif
#if !defined(CONFIG_AXP209_POWER) && !defined(CONFIG_AXP818_POWER)
power_failed |= axp_set_dcdc4(CONFIG_AXP_DCDC4_VOLT);
#endif
@@ -657,8 +673,10 @@ void sunxi_board_init(void)
defined CONFIG_AXP818_POWER
power_failed |= axp_set_aldo1(CONFIG_AXP_ALDO1_VOLT);
#endif
+#if !defined(CONFIG_AXP305_POWER)
power_failed |= axp_set_aldo2(CONFIG_AXP_ALDO2_VOLT);
-#if !defined(CONFIG_AXP152_POWER)
+#endif
+#if !defined(CONFIG_AXP152_POWER) && !defined(CONFIG_AXP305_POWER)
power_failed |= axp_set_aldo3(CONFIG_AXP_ALDO3_VOLT);
#endif
#ifdef CONFIG_AXP209_POWER
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 7561335..bdc229f 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -159,7 +159,7 @@ config SPL_TEXT_BASE
hex "SPL Text Base"
default ISW_ENTRY_ADDR if AM43XX || AM33XX || OMAP54XX || ARCH_KEYSTONE
default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I
- default 0x20060 if MACH_SUN50I_H6
+ default 0x20060 if SUN50I_GEN_H6
default 0x00060 if ARCH_SUNXI
default 0xfffc0000 if ARCH_ZYNQMP
default 0x0
@@ -325,7 +325,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
hex "Address on the MMC to load U-Boot from"
depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
- default 0x50 if ARCH_SUNXI
+ default 0x40 if ARCH_SUNXI
default 0x75 if ARCH_DAVINCI
default 0x8a if ARCH_MX6 || ARCH_MX7
default 0x100 if ARCH_UNIPHIER
@@ -342,6 +342,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
config SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET
hex "U-Boot main hardware partition image offset"
depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ default 0x10 if ARCH_SUNXI
default 0x0
help
On some platforms SPL location depends on hardware partition. The ROM
@@ -468,7 +469,7 @@ config SPL_SHA512_SUPPORT
config SPL_FIT_IMAGE_TINY
bool "Remove functionality from SPL FIT loading to reduce size"
depends on SPL_FIT
- default y if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN50I_H6
+ default y if MACH_SUN50I || MACH_SUN50I_H5 || SUN50I_GEN_H6
default y if ARCH_IMX8M
help
Enable this to reduce the size of the FIT image loading code
diff --git a/configs/orangepi_3_defconfig b/configs/orangepi_3_defconfig
new file mode 100644
index 0000000..82b9815
--- /dev/null
+++ b/configs/orangepi_3_defconfig
@@ -0,0 +1,12 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_SPL=y
+CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_LPDDR3=y
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+CONFIG_BLUETOOTH_DT_DEVICE_FIXUP="brcm,bcm4345c5"
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-orangepi-3"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
diff --git a/configs/orangepi_zero2_defconfig b/configs/orangepi_zero2_defconfig
new file mode 100644
index 0000000..0c20b5f
--- /dev/null
+++ b/configs/orangepi_zero2_defconfig
@@ -0,0 +1,13 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_SPL=y
+CONFIG_DRAM_SUN50I_H616_WRITE_LEVELING=y
+CONFIG_DRAM_SUN50I_H616_READ_CALIBRATION=y
+CONFIG_DRAM_SUN50I_H616_READ_TRAINING=y
+CONFIG_DRAM_SUN50I_H616_WRITE_TRAINING=y
+CONFIG_MACH_SUN50I_H616=y
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_R_I2C_ENABLE=y
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-h616-orangepi-zero2"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SPL_I2C_SUPPORT=y
diff --git a/configs/tanix_tx6_defconfig b/configs/tanix_tx6_defconfig
new file mode 100644
index 0000000..9ce812e
--- /dev/null
+++ b/configs/tanix_tx6_defconfig
@@ -0,0 +1,10 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_SPL=y
+CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_DDR3_1333=y
+CONFIG_DRAM_CLK=648
+CONFIG_MMC0_CD_PIN="PF6"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-tanix-tx6"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index 5ff101b..bf084fa 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -79,6 +79,13 @@ config CLK_SUN50I_H6
This enables common clock driver support for platforms based
on Allwinner H6 SoC.
+config CLK_SUN50I_H616
+ bool "Clock driver for Allwinner H616"
+ default MACH_SUN50I_H616
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner H616 SoC.
+
config CLK_SUN50I_A64
bool "Clock driver for Allwinner A64"
default MACH_SUN50I
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 36fb2ae..0dfc059 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o
obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o
obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o
obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o
+obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o
obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o
diff --git a/drivers/clk/sunxi/clk_h616.c b/drivers/clk/sunxi/clk_h616.c
new file mode 100644
index 0000000..553d7c6
--- /dev/null
+++ b/drivers/clk/sunxi/clk_h616.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <dt-bindings/clock/sun50i-h616-ccu.h>
+#include <dt-bindings/reset/sun50i-h616-ccu.h>
+#include <linux/bitops.h>
+
+static struct ccu_clk_gate h616_gates[] = {
+ [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
+ [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
+ [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)),
+
+ [CLK_BUS_UART0] = GATE(0x90c, BIT(0)),
+ [CLK_BUS_UART1] = GATE(0x90c, BIT(1)),
+ [CLK_BUS_UART2] = GATE(0x90c, BIT(2)),
+ [CLK_BUS_UART3] = GATE(0x90c, BIT(3)),
+ [CLK_BUS_UART4] = GATE(0x90c, BIT(4)),
+ [CLK_BUS_UART5] = GATE(0x90c, BIT(5)),
+
+ [CLK_SPI0] = GATE(0x940, BIT(31)),
+ [CLK_SPI1] = GATE(0x944, BIT(31)),
+
+ [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)),
+ [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)),
+
+ [CLK_BUS_EMAC0] = GATE(0x97c, BIT(0)),
+ [CLK_BUS_EMAC1] = GATE(0x97c, BIT(1)),
+
+ [CLK_USB_PHY0] = GATE(0xa70, BIT(29)),
+ [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)),
+
+ [CLK_USB_PHY1] = GATE(0xa74, BIT(29)),
+ [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)),
+
+ [CLK_USB_PHY2] = GATE(0xa78, BIT(29)),
+ [CLK_USB_OHCI2] = GATE(0xa78, BIT(31)),
+
+ [CLK_USB_PHY3] = GATE(0xa7c, BIT(29)),
+ [CLK_USB_OHCI3] = GATE(0xa7c, BIT(31)),
+
+ [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
+ [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
+ [CLK_BUS_OHCI2] = GATE(0xa8c, BIT(2)),
+ [CLK_BUS_OHCI3] = GATE(0xa8c, BIT(3)),
+ [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
+ [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)),
+ [CLK_BUS_EHCI2] = GATE(0xa8c, BIT(6)),
+ [CLK_BUS_EHCI3] = GATE(0xa8c, BIT(7)),
+ [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
+};
+
+static struct ccu_reset h616_resets[] = {
+ [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
+ [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
+ [RST_BUS_MMC2] = RESET(0x84c, BIT(18)),
+
+ [RST_BUS_UART0] = RESET(0x90c, BIT(16)),
+ [RST_BUS_UART1] = RESET(0x90c, BIT(17)),
+ [RST_BUS_UART2] = RESET(0x90c, BIT(18)),
+ [RST_BUS_UART3] = RESET(0x90c, BIT(19)),
+ [RST_BUS_UART4] = RESET(0x90c, BIT(20)),
+ [RST_BUS_UART5] = RESET(0x90c, BIT(21)),
+
+ [RST_BUS_SPI0] = RESET(0x96c, BIT(16)),
+ [RST_BUS_SPI1] = RESET(0x96c, BIT(17)),
+
+ [RST_BUS_EMAC0] = RESET(0x97c, BIT(16)),
+ [RST_BUS_EMAC1] = RESET(0x97c, BIT(17)),
+
+ [RST_USB_PHY0] = RESET(0xa70, BIT(30)),
+
+ [RST_USB_PHY1] = RESET(0xa74, BIT(30)),
+
+ [RST_USB_PHY2] = RESET(0xa78, BIT(30)),
+
+ [RST_USB_PHY3] = RESET(0xa7c, BIT(30)),
+
+ [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
+ [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
+ [RST_BUS_OHCI2] = RESET(0xa8c, BIT(18)),
+ [RST_BUS_OHCI3] = RESET(0xa8c, BIT(19)),
+ [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
+ [RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)),
+ [RST_BUS_EHCI2] = RESET(0xa8c, BIT(22)),
+ [RST_BUS_EHCI3] = RESET(0xa8c, BIT(23)),
+ [RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
+};
+
+static const struct ccu_desc h616_ccu_desc = {
+ .gates = h616_gates,
+ .resets = h616_resets,
+};
+
+static int h616_clk_bind(struct udevice *dev)
+{
+ return sunxi_reset_bind(dev, ARRAY_SIZE(h616_resets));
+}
+
+static const struct udevice_id h616_ccu_ids[] = {
+ { .compatible = "allwinner,sun50i-h616-ccu",
+ .data = (ulong)&h616_ccu_desc },
+ { }
+};
+
+U_BOOT_DRIVER(clk_sun50i_h616) = {
+ .name = "sun50i_h616_ccu",
+ .id = UCLASS_CLK,
+ .of_match = h616_ccu_ids,
+ .priv_auto = sizeof(struct ccu_priv),
+ .ops = &sunxi_clk_ops,
+ .probe = sunxi_clk_probe,
+ .bind = h616_clk_bind,
+};
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 7633422..24cb604 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -355,6 +355,7 @@ static const struct udevice_id sunxi_gpio_ids[] = {
ID("allwinner,sun9i-a80-pinctrl", a_all),
ID("allwinner,sun50i-a64-pinctrl", a_all),
ID("allwinner,sun50i-h6-pinctrl", a_all),
+ ID("allwinner,sun50i-h616-pinctrl", a_all),
ID("allwinner,sun6i-a31-r-pinctrl", l_2),
ID("allwinner,sun8i-a23-r-pinctrl", l_1),
ID("allwinner,sun8i-a83t-r-pinctrl", l_1),
@@ -362,6 +363,7 @@ static const struct udevice_id sunxi_gpio_ids[] = {
ID("allwinner,sun9i-a80-r-pinctrl", l_3),
ID("allwinner,sun50i-a64-r-pinctrl", l_1),
ID("allwinner,sun50i-h6-r-pinctrl", l_2),
+ ID("allwinner,sun50i-h616-r-pinctrl", l_1),
{ }
};
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index a4d59b6..37b1a06 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -121,7 +121,7 @@ enum mvtwsi_ctrl_register_fields {
* on other platforms, it is a normal r/w bit, which is cleared by writing 0.
*/
-#ifdef CONFIG_SUNXI_GEN_SUN6I
+#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
#else
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index b33f80b..3503ccd 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -23,12 +23,6 @@
#include <asm-generic/gpio.h>
#include <linux/delay.h>
-#ifdef CONFIG_DM_MMC
-struct sunxi_mmc_variant {
- u16 mclk_offset;
-};
-#endif
-
struct sunxi_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -42,9 +36,6 @@ struct sunxi_mmc_priv {
int cd_inverted; /* Inverted Card Detect */
struct sunxi_mmc *reg;
struct mmc_config cfg;
-#ifdef CONFIG_DM_MMC
- const struct sunxi_mmc_variant *variant;
-#endif
};
#if !CONFIG_IS_ENABLED(DM_MMC)
@@ -122,7 +113,7 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2)
new_mode = false;
-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
+#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_SUN50I_GEN_H6)
calibrate = true;
#endif
@@ -133,7 +124,7 @@ 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_MACH_SUN50I_H6)
+#elif defined(CONFIG_SUN50I_GEN_H6)
pll = CCM_MMC_CTRL_PLL6X2;
pll_hz = clock_get_pll6() * 2;
#else
@@ -249,7 +240,7 @@ 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_MACH_SUN50I_H6)
+#if defined(CONFIG_MACH_SUN50I) || 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
@@ -530,7 +521,7 @@ 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_MACH_SUN50I_H6)
+#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_SUN50I_GEN_H6)
if (sdc_no == 2)
cfg->host_caps = MMC_MODE_8BIT;
#endif
@@ -545,7 +536,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
/* config ahb clock */
debug("init mmc %d clock and io\n", sdc_no);
-#if !defined(CONFIG_MACH_SUN50I_H6)
+#if !defined(CONFIG_SUN50I_GEN_H6)
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
#ifdef CONFIG_SUNXI_GEN_SUN6I
@@ -557,7 +548,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
#endif
-#else /* CONFIG_MACH_SUN50I_H6 */
+#else /* CONFIG_SUN50I_GEN_H6 */
setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
/* unassert reset */
setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
@@ -605,6 +596,17 @@ static const struct dm_mmc_ops sunxi_mmc_ops = {
.get_cd = sunxi_mmc_getcd,
};
+static unsigned get_mclk_offset(void)
+{
+ if (IS_ENABLED(CONFIG_MACH_SUN9I_A80))
+ return 0x410;
+
+ if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
+ return 0x830;
+
+ return 0x88;
+};
+
static int sunxi_mmc_probe(struct udevice *dev)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
@@ -633,8 +635,6 @@ static int sunxi_mmc_probe(struct udevice *dev)
cfg->f_max = 52000000;
priv->reg = (void *)dev_read_addr(dev);
- priv->variant =
- (const struct sunxi_mmc_variant *)dev_get_driver_data(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,
@@ -644,8 +644,7 @@ static int sunxi_mmc_probe(struct udevice *dev)
ccu_reg = (u32 *)ofnode_get_addr(args.node);
priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
- priv->mclkreg = (void *)ccu_reg +
- (priv->variant->mclk_offset + (priv->mmc_no * 4));
+ priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4;
ret = clk_get_by_name(dev, "ahb", &gate_clk);
if (!ret)
@@ -687,55 +686,18 @@ static int sunxi_mmc_bind(struct udevice *dev)
return mmc_bind(dev, &plat->mmc, &plat->cfg);
}
-static const struct sunxi_mmc_variant sun4i_a10_variant = {
- .mclk_offset = 0x88,
-};
-
-static const struct sunxi_mmc_variant sun9i_a80_variant = {
- .mclk_offset = 0x410,
-};
-
-static const struct sunxi_mmc_variant sun50i_h6_variant = {
- .mclk_offset = 0x830,
-};
-
static const struct udevice_id sunxi_mmc_ids[] = {
- {
- .compatible = "allwinner,sun4i-a10-mmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun5i-a13-mmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun7i-a20-mmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun8i-a83t-emmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun9i-a80-mmc",
- .data = (ulong)&sun9i_a80_variant,
- },
- {
- .compatible = "allwinner,sun50i-a64-mmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun50i-a64-emmc",
- .data = (ulong)&sun4i_a10_variant,
- },
- {
- .compatible = "allwinner,sun50i-h6-mmc",
- .data = (ulong)&sun50i_h6_variant,
- },
- {
- .compatible = "allwinner,sun50i-h6-emmc",
- .data = (ulong)&sun50i_h6_variant,
- },
+ { .compatible = "allwinner,sun4i-a10-mmc" },
+ { .compatible = "allwinner,sun5i-a13-mmc" },
+ { .compatible = "allwinner,sun7i-a20-mmc" },
+ { .compatible = "allwinner,sun8i-a83t-emmc" },
+ { .compatible = "allwinner,sun9i-a80-mmc" },
+ { .compatible = "allwinner,sun50i-a64-mmc" },
+ { .compatible = "allwinner,sun50i-a64-emmc" },
+ { .compatible = "allwinner,sun50i-h6-mmc" },
+ { .compatible = "allwinner,sun50i-h6-emmc" },
+ { .compatible = "allwinner,sun50i-a100-mmc" },
+ { .compatible = "allwinner,sun50i-a100-emmc" },
{ /* sentinel */ }
};
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index cf15e9f..9f91a20 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -353,6 +353,9 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
/* default */
break;
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
reg |= SC_EPIT | SC_ETCS_INT_GMII;
break;
case PHY_INTERFACE_MODE_RMII:
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 02050f6..c5fbf1f 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -13,6 +13,7 @@ choice
depends on ARCH_SUNXI
default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40
+ default AXP305_POWER if MACH_SUN50I_H616
default AXP818_POWER if MACH_SUN8I_A83T
default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_V3S
@@ -48,6 +49,15 @@ config AXP221_POWER
Select this to enable support for the axp221/axp223 pmic found on most
A23 and A31 boards.
+config AXP305_POWER
+ bool "axp305 pmic support"
+ depends on MACH_SUN50I_H616
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the axp305 pmic found on most
+ H616 boards.
+
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
@@ -127,11 +137,12 @@ config AXP_DCDC3_VOLT
config AXP_DCDC4_VOLT
int "axp pmic dcdc4 voltage"
- depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP305_POWER
default 1250 if AXP152_POWER
default 1200 if MACH_SUN6I
default 0 if MACH_SUN8I
default 900 if MACH_SUN9I
+ default 1500 if AXP305_POWER
---help---
Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to
disable dcdc4.
@@ -140,6 +151,7 @@ config AXP_DCDC4_VOLT
On A23 / A33 boards dcdc4 is unused and should be disabled.
On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V.
On A83T boards dcdc4 is used for VDD-GPU.
+ On H616 boards dcdcd is used for VCC-DRAM.
config AXP_DCDC5_VOLT
int "axp pmic dcdc5 voltage"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 2dcc7bb..0bef069 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_AXP152_POWER) += axp152.o
obj-$(CONFIG_AXP209_POWER) += axp209.o
obj-$(CONFIG_AXP221_POWER) += axp221.o
+obj-$(CONFIG_AXP305_POWER) += axp305.o
obj-$(CONFIG_AXP809_POWER) += axp809.o
obj-$(CONFIG_AXP818_POWER) += axp818.o
obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o
diff --git a/drivers/power/axp305.c b/drivers/power/axp305.c
new file mode 100644
index 0000000..0191e4d
--- /dev/null
+++ b/drivers/power/axp305.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP305 driver
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+#define AXP305_DCDC4_1600MV_OFFSET 46
+
+static u8 axp305_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+ if (mvolt < min)
+ mvolt = min;
+ else if (mvolt > max)
+ mvolt = max;
+
+ return (mvolt - min) / div;
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+ int ret;
+ u8 cfg;
+
+ if (mvolt >= 1600)
+ cfg = AXP305_DCDC4_1600MV_OFFSET +
+ axp305_mvolt_to_cfg(mvolt, 1600, 3300, 100);
+ else
+ cfg = axp305_mvolt_to_cfg(mvolt, 600, 1500, 20);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP305_OUTPUT_CTRL1,
+ AXP305_OUTPUT_CTRL1_DCDCD_EN);
+
+ ret = pmic_bus_write(AXP305_DCDCD_VOLTAGE, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP305_OUTPUT_CTRL1,
+ AXP305_OUTPUT_CTRL1_DCDCD_EN);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP305_CHIP_VERSION, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ if ((axp_chip_id & AXP305_CHIP_VERSION_MASK) != 0x40)
+ return -ENODEV;
+
+ return ret;
+}
+
+#ifndef CONFIG_PSCI_RESET
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP305_SHUTDOWN, AXP305_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
+#endif
diff --git a/include/axp305.h b/include/axp305.h
new file mode 100644
index 0000000..225c504
--- /dev/null
+++ b/include/axp305.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+enum axp305_reg {
+ AXP305_CHIP_VERSION = 0x3,
+ AXP305_OUTPUT_CTRL1 = 0x10,
+ AXP305_DCDCD_VOLTAGE = 0x15,
+ AXP305_SHUTDOWN = 0x32,
+};
+
+#define AXP305_CHIP_VERSION_MASK 0xcf
+
+#define AXP305_OUTPUT_CTRL1_DCDCD_EN (1 << 3)
+
+#define AXP305_POWEROFF (1 << 7)
diff --git a/include/axp_pmic.h b/include/axp_pmic.h
index 10091d0..405044c 100644
--- a/include/axp_pmic.h
+++ b/include/axp_pmic.h
@@ -15,6 +15,9 @@
#ifdef CONFIG_AXP221_POWER
#include <axp221.h>
#endif
+#ifdef CONFIG_AXP305_POWER
+#include <axp305.h>
+#endif
#ifdef CONFIG_AXP809_POWER
#include <axp809.h>
#endif
diff --git a/include/configs/sun50i.h b/include/configs/sun50i.h
index e050a52..bc2e3a3 100644
--- a/include/configs/sun50i.h
+++ b/include/configs/sun50i.h
@@ -10,7 +10,7 @@
* A64 specific configuration
*/
-#ifndef CONFIG_MACH_SUN50I_H6
+#ifndef CONFIG_SUN50I_GEN_H6
#define GICD_BASE 0x1c81000
#define GICC_BASE 0x1c82000
#else
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 203cb10..000f386 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -178,9 +178,14 @@
#define LOW_LEVEL_SRAM_STACK 0x00018000
#endif /* !CONFIG_ARM64 */
#elif CONFIG_SUNXI_SRAM_ADDRESS == 0x20000
+#ifdef CONFIG_MACH_SUN50I_H616
+#define CONFIG_SPL_MAX_SIZE 0xbfa0 /* 48 KiB */
+#define LOW_LEVEL_SRAM_STACK 0x58000
+#else
#define CONFIG_SPL_MAX_SIZE 0x7fa0 /* 32 KiB */
/* end of SRAM A2 on H6 for now */
#define LOW_LEVEL_SRAM_STACK 0x00118000
+#endif
#else
#define CONFIG_SPL_MAX_SIZE 0x5fa0 /* 24KB on sun4i/sun7i */
#define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */
@@ -188,7 +193,9 @@
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK
+#ifndef CONFIG_MACH_SUN50I_H616
#define CONFIG_SPL_PAD_TO 32768 /* decimal for 'dd' */
+#endif
/* I2C */
diff --git a/include/dt-bindings/clock/sun50i-h6-r-ccu.h b/include/dt-bindings/clock/sun50i-h6-r-ccu.h
index 7613613..890368d 100644
--- a/include/dt-bindings/clock/sun50i-h6-r-ccu.h
+++ b/include/dt-bindings/clock/sun50i-h6-r-ccu.h
@@ -21,4 +21,6 @@
#define CLK_IR 11
#define CLK_W1 12
+#define CLK_R_APB2_RSB 13
+
#endif /* _DT_BINDINGS_CLK_SUN50I_H6_R_CCU_H_ */
diff --git a/include/dt-bindings/clock/sun50i-h616-ccu.h b/include/dt-bindings/clock/sun50i-h616-ccu.h
new file mode 100644
index 0000000..4fc08b0
--- /dev/null
+++ b/include/dt-bindings/clock/sun50i-h616-ccu.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2020 Arm Ltd.
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN50I_H616_H_
+#define _DT_BINDINGS_CLK_SUN50I_H616_H_
+
+#define CLK_PLL_PERIPH0 4
+
+#define CLK_CPUX 21
+
+#define CLK_APB1 26
+
+#define CLK_DE 29
+#define CLK_BUS_DE 30
+#define CLK_DEINTERLACE 31
+#define CLK_BUS_DEINTERLACE 32
+#define CLK_G2D 33
+#define CLK_BUS_G2D 34
+#define CLK_GPU0 35
+#define CLK_BUS_GPU 36
+#define CLK_GPU1 37
+#define CLK_CE 38
+#define CLK_BUS_CE 39
+#define CLK_VE 40
+#define CLK_BUS_VE 41
+#define CLK_BUS_DMA 42
+#define CLK_BUS_HSTIMER 43
+#define CLK_AVS 44
+#define CLK_BUS_DBG 45
+#define CLK_BUS_PSI 46
+#define CLK_BUS_PWM 47
+#define CLK_BUS_IOMMU 48
+
+#define CLK_MBUS_DMA 50
+#define CLK_MBUS_VE 51
+#define CLK_MBUS_CE 52
+#define CLK_MBUS_TS 53
+#define CLK_MBUS_NAND 54
+#define CLK_MBUS_G2D 55
+
+#define CLK_NAND0 57
+#define CLK_NAND1 58
+#define CLK_BUS_NAND 59
+#define CLK_MMC0 60
+#define CLK_MMC1 61
+#define CLK_MMC2 62
+#define CLK_BUS_MMC0 63
+#define CLK_BUS_MMC1 64
+#define CLK_BUS_MMC2 65
+#define CLK_BUS_UART0 66
+#define CLK_BUS_UART1 67
+#define CLK_BUS_UART2 68
+#define CLK_BUS_UART3 69
+#define CLK_BUS_UART4 70
+#define CLK_BUS_UART5 71
+#define CLK_BUS_I2C0 72
+#define CLK_BUS_I2C1 73
+#define CLK_BUS_I2C2 74
+#define CLK_BUS_I2C3 75
+#define CLK_BUS_I2C4 76
+#define CLK_SPI0 77
+#define CLK_SPI1 78
+#define CLK_BUS_SPI0 79
+#define CLK_BUS_SPI1 80
+#define CLK_EMAC_25M 81
+#define CLK_BUS_EMAC0 82
+#define CLK_BUS_EMAC1 83
+#define CLK_TS 84
+#define CLK_BUS_TS 85
+#define CLK_BUS_THS 86
+#define CLK_SPDIF 87
+#define CLK_BUS_SPDIF 88
+#define CLK_DMIC 89
+#define CLK_BUS_DMIC 90
+#define CLK_AUDIO_CODEC_1X 91
+#define CLK_AUDIO_CODEC_4X 92
+#define CLK_BUS_AUDIO_CODEC 93
+#define CLK_AUDIO_HUB 94
+#define CLK_BUS_AUDIO_HUB 95
+#define CLK_USB_OHCI0 96
+#define CLK_USB_PHY0 97
+#define CLK_USB_OHCI1 98
+#define CLK_USB_PHY1 99
+#define CLK_USB_OHCI2 100
+#define CLK_USB_PHY2 101
+#define CLK_USB_OHCI3 102
+#define CLK_USB_PHY3 103
+#define CLK_BUS_OHCI0 104
+#define CLK_BUS_OHCI1 105
+#define CLK_BUS_OHCI2 106
+#define CLK_BUS_OHCI3 107
+#define CLK_BUS_EHCI0 108
+#define CLK_BUS_EHCI1 109
+#define CLK_BUS_EHCI2 110
+#define CLK_BUS_EHCI3 111
+#define CLK_BUS_OTG 112
+#define CLK_BUS_KEYADC 113
+#define CLK_HDMI 114
+#define CLK_HDMI_SLOW 115
+#define CLK_HDMI_CEC 116
+#define CLK_BUS_HDMI 117
+#define CLK_BUS_TCON_TOP 118
+#define CLK_TCON_TV0 119
+#define CLK_TCON_TV1 120
+#define CLK_BUS_TCON_TV0 121
+#define CLK_BUS_TCON_TV1 122
+#define CLK_TVE0 123
+#define CLK_BUS_TVE_TOP 124
+#define CLK_BUS_TVE0 125
+#define CLK_HDCP 126
+#define CLK_BUS_HDCP 127
+
+#endif /* _DT_BINDINGS_CLK_SUN50I_H616_H_ */
diff --git a/include/dt-bindings/reset/sun50i-h6-r-ccu.h b/include/dt-bindings/reset/sun50i-h6-r-ccu.h
index 01c84db..7950e79 100644
--- a/include/dt-bindings/reset/sun50i-h6-r-ccu.h
+++ b/include/dt-bindings/reset/sun50i-h6-r-ccu.h
@@ -13,5 +13,6 @@
#define RST_R_APB2_I2C 4
#define RST_R_APB1_IR 5
#define RST_R_APB1_W1 6
+#define RST_R_APB2_RSB 7
#endif /* _DT_BINDINGS_RST_SUN50I_H6_R_CCU_H_ */
diff --git a/include/dt-bindings/reset/sun50i-h616-ccu.h b/include/dt-bindings/reset/sun50i-h616-ccu.h
new file mode 100644
index 0000000..cb6285a
--- /dev/null
+++ b/include/dt-bindings/reset/sun50i-h616-ccu.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2020 Arm Ltd.
+ */
+
+#ifndef _DT_BINDINGS_RESET_SUN50I_H616_H_
+#define _DT_BINDINGS_RESET_SUN50I_H616_H_
+
+#define RST_MBUS 0
+#define RST_BUS_DE 1
+#define RST_BUS_DEINTERLACE 2
+#define RST_BUS_GPU 3
+#define RST_BUS_CE 4
+#define RST_BUS_VE 5
+#define RST_BUS_DMA 6
+#define RST_BUS_HSTIMER 7
+#define RST_BUS_DBG 8
+#define RST_BUS_PSI 9
+#define RST_BUS_PWM 10
+#define RST_BUS_IOMMU 11
+#define RST_BUS_DRAM 12
+#define RST_BUS_NAND 13
+#define RST_BUS_MMC0 14
+#define RST_BUS_MMC1 15
+#define RST_BUS_MMC2 16
+#define RST_BUS_UART0 17
+#define RST_BUS_UART1 18
+#define RST_BUS_UART2 19
+#define RST_BUS_UART3 20
+#define RST_BUS_UART4 21
+#define RST_BUS_UART5 22
+#define RST_BUS_I2C0 23
+#define RST_BUS_I2C1 24
+#define RST_BUS_I2C2 25
+#define RST_BUS_I2C3 26
+#define RST_BUS_I2C4 27
+#define RST_BUS_SPI0 28
+#define RST_BUS_SPI1 29
+#define RST_BUS_EMAC0 30
+#define RST_BUS_EMAC1 31
+#define RST_BUS_TS 32
+#define RST_BUS_THS 33
+#define RST_BUS_SPDIF 34
+#define RST_BUS_DMIC 35
+#define RST_BUS_AUDIO_CODEC 36
+#define RST_BUS_AUDIO_HUB 37
+#define RST_USB_PHY0 38
+#define RST_USB_PHY1 39
+#define RST_USB_PHY2 40
+#define RST_USB_PHY3 41
+#define RST_BUS_OHCI0 42
+#define RST_BUS_OHCI1 43
+#define RST_BUS_OHCI2 44
+#define RST_BUS_OHCI3 45
+#define RST_BUS_EHCI0 46
+#define RST_BUS_EHCI1 47
+#define RST_BUS_EHCI2 48
+#define RST_BUS_EHCI3 49
+#define RST_BUS_OTG 50
+#define RST_BUS_HDMI 51
+#define RST_BUS_HDMI_SUB 52
+#define RST_BUS_TCON_TOP 53
+#define RST_BUS_TCON_TV0 54
+#define RST_BUS_TCON_TV1 55
+#define RST_BUS_TVE_TOP 56
+#define RST_BUS_TVE0 57
+#define RST_BUS_HDCP 58
+#define RST_BUS_KEYADC 59
+
+#endif /* _DT_BINDINGS_RESET_SUN50I_H616_H_ */