Browse Source

Merge https://gitlab.denx.de/u-boot/custodians/u-boot-sunxi

- New Allwinner H616 SoC support (sans Ethernet & USB)
- H6 DT update
- Tanix TX6 TV box support
- OrangePi 3 support
- OrangePi Zero2 (H616) support
Tom Rini 3 years ago
parent
commit
e262b2973e
61 changed files with 4587 additions and 423 deletions
  1. 4 1
      arch/arm/cpu/armv8/fel_utils.S
  2. 5 1
      arch/arm/dts/Makefile
  3. 64 6
      arch/arm/dts/sun50i-h6-beelink-gs1.dts
  4. 117 0
      arch/arm/dts/sun50i-h6-cpu-opp.dtsi
  5. 345 0
      arch/arm/dts/sun50i-h6-orangepi-3.dts
  6. 67 4
      arch/arm/dts/sun50i-h6-orangepi-lite2.dts
  7. 36 5
      arch/arm/dts/sun50i-h6-orangepi-one-plus.dts
  8. 66 6
      arch/arm/dts/sun50i-h6-orangepi.dtsi
  9. 79 23
      arch/arm/dts/sun50i-h6-pine-h64.dts
  10. 124 0
      arch/arm/dts/sun50i-h6-tanix-tx6.dts
  11. 365 29
      arch/arm/dts/sun50i-h6.dtsi
  12. 242 0
      arch/arm/dts/sun50i-h616-orangepi-zero2.dts
  13. 750 0
      arch/arm/dts/sun50i-h616.dtsi
  14. 8 0
      arch/arm/dts/sunxi-u-boot.dtsi
  15. 1 1
      arch/arm/include/asm/arch-sunxi/boot0.h
  16. 1 1
      arch/arm/include/asm/arch-sunxi/clock.h
  17. 18 1
      arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
  18. 1 1
      arch/arm/include/asm/arch-sunxi/cpu.h
  19. 7 0
      arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
  20. 2 0
      arch/arm/include/asm/arch-sunxi/dram.h
  21. 159 0
      arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
  22. 2 0
      arch/arm/include/asm/arch-sunxi/gpio.h
  23. 1 1
      arch/arm/include/asm/arch-sunxi/mmc.h
  24. 9 238
      arch/arm/include/asm/arch-sunxi/prcm.h
  25. 47 0
      arch/arm/include/asm/arch-sunxi/prcm_sun50i.h
  26. 247 0
      arch/arm/include/asm/arch-sunxi/prcm_sun6i.h
  27. 1 1
      arch/arm/include/asm/arch-sunxi/timer.h
  28. 67 8
      arch/arm/mach-sunxi/Kconfig
  29. 3 1
      arch/arm/mach-sunxi/Makefile
  30. 22 4
      arch/arm/mach-sunxi/board.c
  31. 35 2
      arch/arm/mach-sunxi/clock_sun50i_h6.c
  32. 2 0
      arch/arm/mach-sunxi/cpu_info.c
  33. 1023 0
      arch/arm/mach-sunxi/dram_sun50i_h616.c
  34. 2 0
      arch/arm/mach-sunxi/dram_timings/Makefile
  35. 94 0
      arch/arm/mach-sunxi/dram_timings/h616_ddr3_1333.c
  36. 6 0
      arch/arm/mach-sunxi/pmic_bus.c
  37. 1 1
      arch/arm/mach-sunxi/rmr_switch.S
  38. 16 0
      board/sunxi/MAINTAINERS
  39. 33 15
      board/sunxi/board.c
  40. 4 3
      common/spl/Kconfig
  41. 12 0
      configs/orangepi_3_defconfig
  42. 13 0
      configs/orangepi_zero2_defconfig
  43. 10 0
      configs/tanix_tx6_defconfig
  44. 7 0
      drivers/clk/sunxi/Kconfig
  45. 1 0
      drivers/clk/sunxi/Makefile
  46. 120 0
      drivers/clk/sunxi/clk_h616.c
  47. 2 0
      drivers/gpio/sunxi_gpio.c
  48. 1 1
      drivers/i2c/mvtwsi.c
  49. 29 67
      drivers/mmc/sunxi_mmc.c
  50. 3 0
      drivers/net/sun8i_emac.c
  51. 13 1
      drivers/power/Kconfig
  52. 1 0
      drivers/power/Makefile
  53. 83 0
      drivers/power/axp305.c
  54. 17 0
      include/axp305.h
  55. 3 0
      include/axp_pmic.h
  56. 1 1
      include/configs/sun50i.h
  57. 7 0
      include/configs/sunxi-common.h
  58. 2 0
      include/dt-bindings/clock/sun50i-h6-r-ccu.h
  59. 115 0
      include/dt-bindings/clock/sun50i-h616-ccu.h
  60. 1 0
      include/dt-bindings/reset/sun50i-h6-r-ccu.h
  61. 70 0
      include/dt-bindings/reset/sun50i-h616-ccu.h

+ 4 - 1
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

+ 5 - 1
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 \

+ 64 - 6
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";
+};

+ 117 - 0
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>;
+};

+ 345 - 0
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";
+};

+ 67 - 4
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>;
+	};
 };

+ 36 - 5
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>;
+	};
 };

+ 66 - 6
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";
 };
 

+ 79 - 23
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>;

+ 124 - 0
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";
+};

+ 365 - 29
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>;
+		};
 	};
 };

+ 242 - 0
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";
+};

+ 750 - 0
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>;
+		};
+	};
+};

+ 8 - 0
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";
 				};
 			};

+ 1 - 1
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

+ 1 - 1
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)

+ 18 - 1
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)

+ 1 - 1
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>

+ 7 - 0
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

+ 2 - 0
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

+ 159 - 0
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 */

+ 2 - 0
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
 

+ 1 - 1
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];

+ 9 - 238
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 */

+ 47 - 0
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 */

+ 247 - 0
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 */

+ 1 - 1
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

+ 67 - 8
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"

+ 3 - 1
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

+ 22 - 4
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 =

+ 35 - 2
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;
 }

+ 2 - 0
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");

+ 1023 - 0
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;
+};

+ 2 - 0
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

+ 94 - 0
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);
+}

+ 6 - 0
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);

+ 1 - 1
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

+ 16 - 0
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

+ 33 - 15
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

+ 4 - 3
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

+ 12 - 0
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

+ 13 - 0
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

+ 10 - 0
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

+ 7 - 0
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

+ 1 - 0
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

+ 120 - 0
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,
+};

+ 2 - 0
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),
 	{ }
 };
 

+ 1 - 1
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

+ 29 - 67
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 */ }
 };
 

+ 3 - 0
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:

+ 13 - 1
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"

+ 1 - 0
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

+ 83 - 0
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

+ 17 - 0
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)

+ 3 - 0
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

+ 1 - 1
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

+ 7 - 0
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 */

+ 2 - 0
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_ */

+ 115 - 0
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_ */

+ 1 - 0
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_ */

+ 70 - 0
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_ */