--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2023 OpenWrt.org
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2023.01
+PKG_RELEASE:=1
+
+#PKG_HASH:=352ad311dcf9431fc112122b0afe710e3104c0e670fc943273e8ed3b65c17335
+PKG_HASH:=69423bad380f89a0916636e89e6dcbd2e4512d584308d922d1039d1e4331950f
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+ BUILD_TARGET:=d1
+ UBOOT_IMAGE:=u-boot-sunxi-with-spl.bin
+ UENV:=default
+ DTS_DIR:=arch/riscv/dts
+endef
+
+define U-Boot/dongshan_nezha_stu
+ NAME:=Dongshan Nezha STU
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=sun20i-d1-dongshan-nezha-stu.dtb
+ BUILD_DEVICES:=dongshan_nezha_stu
+endef
+
+define U-Boot/lichee_rv_dock
+ NAME:=LicheePi RV (dock)
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=sun20i-d1-lichee-rv-dock.dtb
+ BUILD_DEVICES:=lichee_rv_dock
+endef
+
+define U-Boot/mangopi_mq_pro
+ NAME:=MangoPi MQ Pro
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=sun20i-d1-mangopi-mq-pro.dtb
+ BUILD_DEVICES:=mangopi_mq_pro
+endef
+
+define U-Boot/nezha
+ NAME:=Nezha D1
+ OPENSBI:=generic
+ DEPENDS:=+opensbi_generic
+ UBOOT_DTS:=sun20i-d1-nezha.dtb
+ BUILD_DEVICES:=nezha
+endef
+
+UBOOT_TARGETS := \
+ dongshan_nezha_stu \
+ lichee_rv_dock \
+ mangopi_mq_pro \
+ nezha \
+
+UBOOT_MAKE_FLAGS += \
+ OPENSBI=$(STAGING_DIR_IMAGE)/fw_dynamic-${OPENSBI}.bin
+
+define Build/Configure
+ $(call Build/Configure/U-Boot)
+ sed -i 's/CONFIG_TOOLS_LIBCRYPTO=y/# CONFIG_TOOLS_LIBCRYPTO is not set/' $(PKG_BUILD_DIR)/.config
+endef
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(DTS_DIR)/$(UBOOT_DTS) $(STAGING_DIR_IMAGE)/$(UBOOT_DTS)
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)
+ mkimage -C none -A riscv -T script -d uEnv-$(UENV).txt \
+ $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-boot.scr
+endef
+
+define Package/u-boot/install/default
+endef
+
+$(eval $(call BuildPackage/U-Boot))
--- /dev/null
+From d45e64aad18e5e324425b9efbe6a0ec9e1a343da Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 20 Nov 2021 13:19:13 -0600
+Subject: [PATCH 01/90] ARM: dts: sun8i: A33: Add iNet U70B REV01
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/Makefile | 1 +
+ arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts | 172 ++++++++++++++++++++++
+ 2 files changed, 173 insertions(+)
+ create mode 100644 arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts
+
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -644,6 +644,7 @@ dtb-$(CONFIG_MACH_SUN8I_A33) += \
+ sun8i-a33-et-q8-v1.6.dtb \
+ sun8i-a33-ga10h-v1.1.dtb \
+ sun8i-a33-inet-d978-rev2.dtb \
++ sun8i-a33-inet-u70b-rev1.dtb \
+ sun8i-a33-ippo-q8h-v1.2.dtb \
+ sun8i-a33-olinuxino.dtb \
+ sun8i-a33-q8-tablet.dtb \
+--- /dev/null
++++ b/arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts
+@@ -0,0 +1,172 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++
++/dts-v1/;
++
++#include "sun8i-a33.dtsi"
++#include "sun8i-reference-design-tablet.dtsi"
++
++/ {
++ model = "iNet U70B REV01";
++ compatible = "inet-tek,inet-u70b-rev01", "allwinner,sun8i-a33";
++
++ aliases {
++ ethernet0 = &rtl8723cs;
++ };
++
++ panel: panel {
++ compatible = "panel-dpi";
++ backlight = <&backlight>;
++ enable-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
++ power-supply = <®_dc1sw>;
++
++ panel-timing {
++ clock-frequency = <51000000>;
++ hactive = <1024>;
++ vactive = <600>;
++ hfront-porch = <162>;
++ hback-porch = <158>;
++ hsync-len = <20>;
++ vback-porch = <25>;
++ vfront-porch = <10>;
++ vsync-len = <3>;
++ hsync-active = <1>;
++ vsync-active = <1>;
++ };
++
++ port {
++ panel_in_tcon0: endpoint {
++ remote-endpoint = <&tcon0_out_panel>;
++ };
++ };
++ };
++
++ speaker_amp: audio-amplifier {
++ compatible = "simple-audio-amplifier";
++ enable-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
++ sound-name-prefix = "Speaker Amp";
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */
++ post-power-on-delay-ms = <200>;
++ };
++};
++
++&codec {
++ status = "okay";
++};
++
++&dai {
++ status = "okay";
++};
++
++&de {
++ status = "okay";
++};
++
++&i2c1 {
++ clock-frequency = <400000>;
++
++ accelerometer@18 {
++ compatible = "bosch,bma250";
++ reg = <0x18>;
++ interrupt-parent = <&pio>;
++ interrupts = <7 10 IRQ_TYPE_EDGE_RISING>; /* PH10 / EINT10 */
++ };
++};
++
++&mmc1 {
++ pinctrl-0 = <&mmc1_pg_pins>;
++ pinctrl-names = "default";
++ bus-width = <4>;
++ non-removable;
++ vmmc-supply = <®_dldo1>;
++ vqmmc-supply = <®_dldo2>;
++ status = "okay";
++
++ rtl8723cs: wifi@1 {
++ reg = <1>;
++ interrupt-parent = <&r_pio>;
++ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */
++ };
++};
++
++&nfc {
++ status = "okay";
++
++ nand@0 {
++ reg = <0>;
++ allwinner,rb = <0>;
++ nand-ecc-maximize;
++ };
++};
++
++&r_uart {
++ status = "disabled";
++};
++
++®_dldo2 {
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-name = "vcc-wifi-io";
++};
++
++&simplefb_lcd {
++ status = "okay";
++};
++
++&sound {
++ simple-audio-card,aux-devs = <&codec_analog>, <&speaker_amp>;
++ simple-audio-card,widgets = "Headphone", "Headphone Jack",
++ "Microphone", "Internal Microphone",
++ "Speaker", "Internal Speaker";
++ simple-audio-card,routing = "Headphone Jack", "HP",
++ "Internal Speaker", "Speaker Amp OUTL",
++ "Internal Speaker", "Speaker Amp OUTR",
++ "Speaker Amp INL", "HP", /* PHONEOUT ??? */
++ "Speaker Amp INR", "HP", /* PHONEOUT ??? */
++ "Left DAC", "DACL",
++ "Right DAC", "DACR",
++ "ADCL", "Left ADC",
++ "ADCR", "Right ADC",
++ "MIC1", "Internal Microphone",
++ "MIC2", "Headset Microphone",
++ "Headset Microphone", "HBIAS",
++ "Internal Microphone", "MBIAS";
++ status = "okay";
++};
++
++&tcon0 {
++ pinctrl-0 = <&lcd_rgb666_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&tcon0_out {
++ tcon0_out_panel: endpoint {
++ remote-endpoint = <&panel_in_tcon0>;
++ };
++};
++
++&touchscreen {
++ reg = <0x40>;
++ compatible = "silead,gsl1680";
++ avdd-supply = <®_ldo_io1>;
++ touchscreen-size-x = <1024>;
++ touchscreen-size-y = <600>;
++ status = "okay";
++};
++
++&uart1 {
++ pinctrl-0 = <&uart1_pg_pins>, <&uart1_cts_rts_pg_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ bluetooth {
++ compatible = "realtek,rtl8723cs-bt";
++ device-wake-gpios = <&r_pio 0 10 GPIO_ACTIVE_LOW>; /* PL10 */
++ enable-gpios = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
++ host-wake-gpios = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */
++ };
++};
--- /dev/null
+From ddb1f06d1c7758c538e286c0c7a9c8545d2af6b1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 20 Nov 2021 13:26:36 -0600
+Subject: [PATCH 02/90] sunxi: Add iNet_U70B_rev1_defconfig
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ configs/iNet_U70B_rev1_defconfig | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+ create mode 100644 configs/iNet_U70B_rev1_defconfig
+
+--- /dev/null
++++ b/configs/iNet_U70B_rev1_defconfig
+@@ -0,0 +1,32 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-a33-inet-u70b-rev1"
++# CONFIG_SPL_SERIAL is not set
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_A33=y
++CONFIG_DRAM_CLK=480
++CONFIG_DRAM_ZQ=31675
++CONFIG_DRAM_ODT_EN=y
++CONFIG_MMC0_CD_PIN="PB4"
++CONFIG_VIDEO_LCD_MODE="x:1024,y:600,depth:18,pclk_khz:51000,le:158,ri:162,up:25,lo:10,hs:20,vs:3,sync:3,vmode:0"
++CONFIG_VIDEO_LCD_DCLK_PHASE=0
++CONFIG_VIDEO_LCD_POWER="PH7"
++CONFIG_VIDEO_LCD_BL_EN="PH6"
++CONFIG_VIDEO_LCD_BL_PWM="PH0"
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_CMD_BIND=y
++CONFIG_CMD_CLK=y
++CONFIG_CMD_PWM=y
++CONFIG_CMD_I2C=y
++CONFIG_CMD_WDT=y
++CONFIG_CMD_PMIC=y
++CONFIG_CMD_REGULATOR=y
++# CONFIG_NET is not set
++CONFIG_AXP_GPIO=y
++CONFIG_REGULATOR_AXP=y
++CONFIG_REGULATOR_AXP_USB_POWER=y
++CONFIG_AXP_DLDO1_VOLT=3300
++CONFIG_DM_PWM=y
++CONFIG_PWM_SUNXI=y
++# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
++CONFIG_USB_MUSB_HOST=y
--- /dev/null
+From ef808412055d1ef6fe77ff130d3f5a9432fef2d7 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Tue, 3 May 2022 22:35:12 -0500
+Subject: [PATCH 03/90] Adapt iNet U70B REV01 for development (FEL + serial)
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts | 11 +++++++++++
+ configs/iNet_U70B_rev1_defconfig | 14 +++++---------
+ 2 files changed, 16 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts
++++ b/arch/arm/dts/sun8i-a33-inet-u70b-rev1.dts
+@@ -11,6 +11,7 @@
+
+ aliases {
+ ethernet0 = &rtl8723cs;
++ serial0 = &uart0;
+ };
+
+ panel: panel {
+@@ -76,6 +77,10 @@
+ };
+ };
+
++&mmc0 {
++ status = "disabled";
++};
++
+ &mmc1 {
+ pinctrl-0 = <&mmc1_pg_pins>;
+ pinctrl-names = "default";
+@@ -158,6 +163,12 @@
+ status = "okay";
+ };
+
++&uart0 {
++ pinctrl-0 = <&uart0_pf_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &uart1 {
+ pinctrl-0 = <&uart1_pg_pins>, <&uart1_cts_rts_pg_pins>;
+ pinctrl-names = "default";
+--- a/configs/iNet_U70B_rev1_defconfig
++++ b/configs/iNet_U70B_rev1_defconfig
+@@ -1,12 +1,12 @@
+ CONFIG_ARM=y
+ CONFIG_ARCH_SUNXI=y
+ CONFIG_DEFAULT_DEVICE_TREE="sun8i-a33-inet-u70b-rev1"
+-# CONFIG_SPL_SERIAL is not set
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_A33=y
+ CONFIG_DRAM_CLK=480
+ CONFIG_DRAM_ZQ=31675
+ CONFIG_DRAM_ODT_EN=y
++CONFIG_UART0_PORT_F=y
+ CONFIG_MMC0_CD_PIN="PB4"
+ CONFIG_VIDEO_LCD_MODE="x:1024,y:600,depth:18,pclk_khz:51000,le:158,ri:162,up:25,lo:10,hs:20,vs:3,sync:3,vmode:0"
+ CONFIG_VIDEO_LCD_DCLK_PHASE=0
+@@ -14,19 +14,15 @@ CONFIG_VIDEO_LCD_POWER="PH7"
+ CONFIG_VIDEO_LCD_BL_EN="PH6"
+ CONFIG_VIDEO_LCD_BL_PWM="PH0"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+-CONFIG_CMD_BIND=y
+-CONFIG_CMD_CLK=y
+-CONFIG_CMD_PWM=y
+-CONFIG_CMD_I2C=y
+-CONFIG_CMD_WDT=y
++CONFIG_PREBOOT="fastboot usb 0"
+ CONFIG_CMD_PMIC=y
+ CONFIG_CMD_REGULATOR=y
+-# CONFIG_NET is not set
+ CONFIG_AXP_GPIO=y
+ CONFIG_REGULATOR_AXP=y
+ CONFIG_REGULATOR_AXP_USB_POWER=y
+ CONFIG_AXP_DLDO1_VOLT=3300
+ CONFIG_DM_PWM=y
+ CONFIG_PWM_SUNXI=y
+-# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+-CONFIG_USB_MUSB_HOST=y
++CONFIG_REMOTEPROC_SUN6I_AR100=y
++CONFIG_USB_MUSB_GADGET=y
++CONFIG_WATCHDOG_AUTOSTART=y
--- /dev/null
+From 40a0ec0fdb6a110d69151de5480148772877f267 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 20:39:33 -0500
+Subject: [PATCH 04/90] ARM: dts: sun6i: mixtile-loftq: Add USB1 VBUS regulator
+
+This board is configured with CONFIG_USB1_VBUS_PIN="PH24", but no
+regulator exists in its device tree. Add the regulator, so USB will
+continue to work when the PHY driver switches to using the regulator
+uclass instead of a GPIO.
+
+Update the device tree here because it does not exist in Linux.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/sun6i-a31-mixtile-loftq.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/arch/arm/dts/sun6i-a31-mixtile-loftq.dts
++++ b/arch/arm/dts/sun6i-a31-mixtile-loftq.dts
+@@ -6,6 +6,9 @@
+ */
+
+ /dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++
+ #include "sun6i-a31.dtsi"
+
+ / {
+@@ -19,6 +22,15 @@
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ compatible = "regulator-fixed";
++ regulator-name = "usb1-vbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ enable-active-high;
++ gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
++ };
+ };
+
+ &ehci0 {
+@@ -56,3 +68,8 @@
+ pinctrl-0 = <&uart0_ph_pins>;
+ status = "okay";
+ };
++
++&usbphy {
++ usb1_vbus-supply = <®_usb1_vbus>;
++ status = "okay";
++};
--- /dev/null
+From e07c1d516c1a7842510d22a7cf88666d500a9a9a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Aug 2021 21:35:45 -0500
+Subject: [PATCH 05/90] power: regulator: Add a driver for the AXP USB power
+ supply
+
+This driver reports the presence/absence of voltage on the PMIC's USB
+VBUS pin. This information is used by the USB PHY driver. The
+corresponding Linux driver uses the power supply class, which does not
+exist in U-Boot. UCLASS_REGULATOR seems to be the closest match.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/power/regulator/Kconfig | 7 ++++
+ drivers/power/regulator/Makefile | 1 +
+ drivers/power/regulator/axp_usb_power.c | 49 +++++++++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+ create mode 100644 drivers/power/regulator/axp_usb_power.c
+
+--- a/drivers/power/regulator/Kconfig
++++ b/drivers/power/regulator/Kconfig
+@@ -43,6 +43,13 @@ config REGULATOR_AS3722
+ but does not yet support change voltages. Currently this must be
+ done using direct register writes to the PMIC.
+
++config REGULATOR_AXP_USB_POWER
++ bool "Enable driver for X-Powers AXP PMIC USB power supply"
++ depends on DM_REGULATOR && PMIC_AXP
++ help
++ Enable support for reading the USB power supply status from
++ X-Powers AXP2xx and AXP8xx PMICs.
++
+ config DM_REGULATOR_BD71837
+ bool "Enable Driver Model for ROHM BD71837/BD71847 regulators"
+ depends on DM_REGULATOR && DM_PMIC_BD71837
+--- a/drivers/power/regulator/Makefile
++++ b/drivers/power/regulator/Makefile
+@@ -7,6 +7,7 @@
+ obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o
+ obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
+ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
++obj-$(CONFIG_$(SPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
+ obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o
+ obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
+ obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
+--- /dev/null
++++ b/drivers/power/regulator/axp_usb_power.c
+@@ -0,0 +1,49 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <dm/device.h>
++#include <errno.h>
++#include <power/pmic.h>
++#include <power/regulator.h>
++
++#define AXP_POWER_STATUS 0x00
++#define AXP_POWER_STATUS_VBUS_PRESENT BIT(5)
++
++static int axp_usb_power_get_enable(struct udevice *dev)
++{
++ int ret;
++
++ ret = pmic_reg_read(dev->parent, AXP_POWER_STATUS);
++ if (ret < 0)
++ return ret;
++
++ return !!(ret & AXP_POWER_STATUS_VBUS_PRESENT);
++}
++
++static const struct dm_regulator_ops axp_usb_power_ops = {
++ .get_enable = axp_usb_power_get_enable,
++};
++
++static int axp_usb_power_probe(struct udevice *dev)
++{
++ struct dm_regulator_uclass_plat *uc_plat = dev_get_uclass_plat(dev);
++
++ uc_plat->type = REGULATOR_TYPE_FIXED;
++
++ return 0;
++}
++
++static const struct udevice_id axp_usb_power_ids[] = {
++ { .compatible = "x-powers,axp202-usb-power-supply" },
++ { .compatible = "x-powers,axp221-usb-power-supply" },
++ { .compatible = "x-powers,axp223-usb-power-supply" },
++ { .compatible = "x-powers,axp813-usb-power-supply" },
++ { }
++};
++
++U_BOOT_DRIVER(axp_usb_power) = {
++ .name = "axp_usb_power",
++ .id = UCLASS_REGULATOR,
++ .of_match = axp_usb_power_ids,
++ .probe = axp_usb_power_probe,
++ .ops = &axp_usb_power_ops,
++};
--- /dev/null
+From c750151e1107a8d46ca0f9bd30c1da276b142ec1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 18:02:54 -0500
+Subject: [PATCH 06/90] gpio: axp/sunxi: Remove virtual VBUS detection GPIO
+
+Now that this functionality is modeled using the device tree and
+regulator uclass, the named GPIO is not referenced anywhere. Remove it.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h | 1 -
+ drivers/gpio/axp_gpio.c | 21 ++++-----------------
+ drivers/gpio/sunxi_gpio.c | 6 +-----
+ include/axp209.h | 1 -
+ include/axp221.h | 1 -
+ include/axp809.h | 1 -
+ include/axp818.h | 1 -
+ 7 files changed, 5 insertions(+), 27 deletions(-)
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -209,7 +209,6 @@ enum sunxi_gpio_number {
+
+ /* Virtual AXP0 GPIOs */
+ #define SUNXI_GPIO_AXP0_PREFIX "AXP0-"
+-#define SUNXI_GPIO_AXP0_VBUS_DETECT 4
+ #define SUNXI_GPIO_AXP0_VBUS_ENABLE 5
+ #define SUNXI_GPIO_AXP0_GPIO_COUNT 6
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -36,18 +36,11 @@ static int axp_gpio_direction_input(stru
+ {
+ u8 reg;
+
+- switch (pin) {
+-#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
+- case SUNXI_GPIO_AXP0_VBUS_DETECT:
+- return 0;
+-#endif
+- default:
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
++ reg = axp_get_gpio_ctrl_reg(pin);
++ if (reg == 0)
++ return -EINVAL;
+
+- return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT);
+- }
++ return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT);
+ }
+
+ static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
+@@ -83,12 +76,6 @@ static int axp_gpio_get_value(struct ude
+ int ret;
+
+ switch (pin) {
+-#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
+- case SUNXI_GPIO_AXP0_VBUS_DETECT:
+- ret = pmic_bus_read(AXP_POWER_STATUS, &val);
+- mask = AXP_POWER_STATUS_VBUS_PRESENT;
+- break;
+-#endif
+ #ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+ /* Only available on later PMICs */
+ case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+--- a/drivers/gpio/sunxi_gpio.c
++++ b/drivers/gpio/sunxi_gpio.c
+@@ -117,11 +117,7 @@ int sunxi_name_to_gpio(const char *name)
+ #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
+ char lookup[8];
+
+- if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
+- sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
+- SUNXI_GPIO_AXP0_VBUS_DETECT);
+- name = lookup;
+- } else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
++ if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
+ sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
+ SUNXI_GPIO_AXP0_VBUS_ENABLE);
+ name = lookup;
+--- a/include/axp209.h
++++ b/include/axp209.h
+@@ -77,7 +77,6 @@ enum axp209_reg {
+ #ifdef CONFIG_AXP209_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_POWER_STATUS_VBUS_PRESENT BIT(5)
+ #define AXP_GPIO0_CTRL 0x90
+ #define AXP_GPIO1_CTRL 0x92
+ #define AXP_GPIO2_CTRL 0x93
+--- a/include/axp221.h
++++ b/include/axp221.h
+@@ -53,7 +53,6 @@
+ #ifdef CONFIG_AXP221_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_POWER_STATUS_VBUS_PRESENT BIT(5)
+ #define AXP_VBUS_IPSOUT 0x30
+ #define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+ #define AXP_MISC_CTRL 0x8f
+--- a/include/axp809.h
++++ b/include/axp809.h
+@@ -47,7 +47,6 @@
+ #ifdef CONFIG_AXP809_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_POWER_STATUS_VBUS_PRESENT BIT(5)
+ #define AXP_VBUS_IPSOUT 0x30
+ #define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+ #define AXP_MISC_CTRL 0x8f
+--- a/include/axp818.h
++++ b/include/axp818.h
+@@ -61,7 +61,6 @@
+ #ifdef CONFIG_AXP818_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_POWER_STATUS_VBUS_PRESENT BIT(5)
+ #define AXP_VBUS_IPSOUT 0x30
+ #define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+ #define AXP_MISC_CTRL 0x8f
--- /dev/null
+From 25434a394705d2de92c50981e31347db4074204a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 21:32:15 -0500
+Subject: [PATCH 07/90] power: regulator: Add a driver for the AXP PMIC
+ drivevbus
+
+The first AXP regulator converted to use the regulator uclass is the
+drivevbus switch, since it is used by the USB PHY driver.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/power/regulator/Kconfig | 14 ++++++
+ drivers/power/regulator/Makefile | 1 +
+ drivers/power/regulator/axp_regulator.c | 58 +++++++++++++++++++++++++
+ 3 files changed, 73 insertions(+)
+ create mode 100644 drivers/power/regulator/axp_regulator.c
+
+--- a/drivers/power/regulator/Kconfig
++++ b/drivers/power/regulator/Kconfig
+@@ -43,6 +43,20 @@ config REGULATOR_AS3722
+ but does not yet support change voltages. Currently this must be
+ done using direct register writes to the PMIC.
+
++config REGULATOR_AXP
++ bool "Enable driver for X-Powers AXP PMIC regulators"
++ depends on DM_REGULATOR && PMIC_AXP
++ help
++ Enable support for the regulators (DCDCs, LDOs) in the
++ X-Powers AXP152, AXP2xx, and AXP8xx PMICs.
++
++config SPL_REGULATOR_AXP
++ bool "Enable driver for X-Powers AXP PMIC regulators in SPL"
++ depends on SPL_DM_REGULATOR && SPL_PMIC_AXP
++ help
++ Enable support in SPL for the regulators (DCDCs, LDOs) in the
++ X-Powers AXP152, AXP2xx, and AXP8xx PMICs.
++
+ config REGULATOR_AXP_USB_POWER
+ bool "Enable driver for X-Powers AXP PMIC USB power supply"
+ depends on DM_REGULATOR && PMIC_AXP
+--- a/drivers/power/regulator/Makefile
++++ b/drivers/power/regulator/Makefile
+@@ -7,6 +7,7 @@
+ obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o
+ obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
+ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o
++obj-$(CONFIG_$(SPL_)REGULATOR_AXP) += axp_regulator.o
+ obj-$(CONFIG_$(SPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o
+ obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o
+ obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
+--- /dev/null
++++ b/drivers/power/regulator/axp_regulator.c
+@@ -0,0 +1,58 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <dm.h>
++#include <errno.h>
++#include <power/pmic.h>
++#include <power/regulator.h>
++
++#define AXP_VBUS_IPSOUT 0x30
++#define AXP_VBUS_IPSOUT_DRIVEBUS BIT(2)
++#define AXP_MISC_CTRL 0x8f
++#define AXP_MISC_CTRL_N_VBUSEN_FUNC BIT(4)
++
++static int axp_drivevbus_get_enable(struct udevice *dev)
++{
++ int ret;
++
++ ret = pmic_reg_read(dev->parent, AXP_VBUS_IPSOUT);
++ if (ret < 0)
++ return ret;
++
++ return !!(ret & AXP_VBUS_IPSOUT_DRIVEBUS);
++}
++
++static int axp_drivevbus_set_enable(struct udevice *dev, bool enable)
++{
++ return pmic_clrsetbits(dev->parent, AXP_VBUS_IPSOUT,
++ AXP_VBUS_IPSOUT_DRIVEBUS,
++ enable ? AXP_VBUS_IPSOUT_DRIVEBUS : 0);
++}
++
++static const struct dm_regulator_ops axp_drivevbus_ops = {
++ .get_enable = axp_drivevbus_get_enable,
++ .set_enable = axp_drivevbus_set_enable,
++};
++
++static int axp_drivevbus_probe(struct udevice *dev)
++{
++ struct dm_regulator_uclass_plat *uc_plat = dev_get_uclass_plat(dev);
++ int ret;
++
++ uc_plat->type = REGULATOR_TYPE_FIXED;
++
++ if (dev_read_bool(dev->parent, "x-powers,drive-vbus-en")) {
++ ret = pmic_clrsetbits(dev->parent, AXP_MISC_CTRL,
++ AXP_MISC_CTRL_N_VBUSEN_FUNC, 0);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++U_BOOT_DRIVER(axp_drivevbus) = {
++ .name = "axp_drivevbus",
++ .id = UCLASS_REGULATOR,
++ .probe = axp_drivevbus_probe,
++ .ops = &axp_drivevbus_ops,
++};
--- /dev/null
+From a588c97f146b67bae47099bc419cf10c02eca169 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 21:34:33 -0500
+Subject: [PATCH 08/90] power: pmic: axp: Probe the drivevbus regulator from
+ the DT
+
+Now that some regulator driver exists for this PMIC, add support for
+probing regulator drivers from the device tree subnodes.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/power/pmic/axp.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/power/pmic/axp.c
++++ b/drivers/power/pmic/axp.c
+@@ -45,14 +45,24 @@ static struct dm_pmic_ops axp_pmic_ops =
+ .write = dm_i2c_write,
+ };
+
++static const struct pmic_child_info axp_pmic_child_info[] = {
++ { "drivevbus", "axp_drivevbus" },
++ { }
++};
++
+ static int axp_pmic_bind(struct udevice *dev)
+ {
++ ofnode regulators_node;
+ int ret;
+
+ ret = dm_scan_fdt_dev(dev);
+ if (ret)
+ return ret;
+
++ regulators_node = dev_read_subnode(dev, "regulators");
++ if (ofnode_valid(regulators_node))
++ pmic_bind_children(dev, regulators_node, axp_pmic_child_info);
++
+ if (CONFIG_IS_ENABLED(SYSRESET)) {
+ ret = device_bind_driver_to_node(dev, "axp_sysreset", "axp_sysreset",
+ dev_ofnode(dev), NULL);
--- /dev/null
+From e8fb34342dfb79cd2059431dd1a0f03202a244ca Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 22:11:37 -0500
+Subject: [PATCH 09/90] phy: sun4i-usb: Control USB supplies via regulator
+ uclass
+
+The device tree binding for the PHY provides VBUS supplies as regulator
+references. Now that all boards have the appropriate regulator uclass
+drivers enabled, the PHY driver can switch to using them. This replaces
+direct GPIO usage, which in some cases needed a special DM-incompatible
+"virtual" GPIO from the PMIC.
+
+The following boards provided a value for CONFIG_USB0_VBUS_PIN, but are
+missing the "usb0_vbus-supply" property in their device tree. None of
+them have the MUSB controller enabled in host or OTG mode, so they
+should see no impact:
+ - Ainol_AW1_defconfig / sun7i-a20-ainol-aw1
+ - Ampe_A76_defconfig / sun5i-a13-ampe-a76
+ - CHIP_pro_defconfig / sun5i-gr8-chip-pro
+ - Cubieboard4_defconfig / sun9i-a80-cubieboard4
+ - Merrii_A80_Optimus_defconfig / sun9i-a80-optimus
+ - Sunchip_CX-A99_defconfig / sun9i-a80-cx-a99
+ - Yones_Toptech_BD1078_defconfig / sun7i-a20-yones-toptech-bd1078
+ - Yones_Toptech_BS1078_V2_defconfig /
+ sun6i-a31s-yones-toptech-bs1078-v2
+ - iNet_3F_defconfig / sun4i-a10-inet-3f
+ - iNet_3W_defconfig / sun4i-a10-inet-3w
+ - iNet_86VS_defconfig / sun5i-a13-inet-86vs
+ - iNet_D978_rev2_defconfig / sun8i-a33-inet-d978-rev2
+ - icnova-a20-swac_defconfig / sun7i-a20-icnova-swac
+ - sun8i_a23_evb_defconfig / sun8i-a23-evb
+
+Similarly, the following boards set CONFIG_USB1_VBUS_PIN, but do not
+have "usb1_vbus-supply" in their device tree. Neither of them have USB
+enabled at all, so again there should be no impact:
+ - Cubieboard4_defconfig / sun9i-a80-cubieboard4 (also for USB3)
+ - sun8i_a23_evb_defconfig / sun8i-a23-evb
+
+The following boards use a different pin for USB1 VBUS between their
+defconfig and their device tree. Depending on which is correct, they
+may be broken:
+ - Linksprite_pcDuino3_Nano_defconfig (PH11) /
+ sun7i-a20-pcduino3-nano (PD2)
+ - icnova-a20-swac_defconfig (PG10) / sun7i-a20-icnova-swac (PH6)
+
+Finally, this board has conflicting pins given for its USB2 VBUS:
+ - Lamobo_R1_defconfig (PH3) / sun7i-a20-lamobo-r1 (PH12)
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/phy/allwinner/phy-sun4i-usb.c | 41 +++++++++++++--------------
+ 1 file changed, 19 insertions(+), 22 deletions(-)
+
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -97,27 +97,22 @@ struct sun4i_usb_phy_cfg {
+ };
+
+ struct sun4i_usb_phy_info {
+- const char *gpio_vbus;
+ const char *gpio_vbus_det;
+ const char *gpio_id_det;
+ } phy_info[] = {
+ {
+- .gpio_vbus = CONFIG_USB0_VBUS_PIN,
+ .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
+ .gpio_id_det = CONFIG_USB0_ID_DET,
+ },
+ {
+- .gpio_vbus = CONFIG_USB1_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+ {
+- .gpio_vbus = CONFIG_USB2_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+ {
+- .gpio_vbus = CONFIG_USB3_VBUS_PIN,
+ .gpio_vbus_det = NULL,
+ .gpio_id_det = NULL,
+ },
+@@ -125,11 +120,11 @@ struct sun4i_usb_phy_info {
+
+ struct sun4i_usb_phy_plat {
+ void __iomem *pmu;
+- struct gpio_desc gpio_vbus;
+ struct gpio_desc gpio_vbus_det;
+ struct gpio_desc gpio_id_det;
+ struct clk clocks;
+ struct reset_ctl resets;
++ struct udevice *vbus;
+ int id;
+ };
+
+@@ -218,14 +213,18 @@ static int sun4i_usb_phy_power_on(struct
+ {
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
++ int ret;
+
+ if (initial_usb_scan_delay) {
+ mdelay(initial_usb_scan_delay);
+ initial_usb_scan_delay = 0;
+ }
+
+- if (dm_gpio_is_valid(&usb_phy->gpio_vbus))
+- dm_gpio_set_value(&usb_phy->gpio_vbus, 1);
++ if (usb_phy->vbus) {
++ ret = regulator_set_enable(usb_phy->vbus, true);
++ if (ret && ret != -ENOSYS)
++ return ret;
++ }
+
+ return 0;
+ }
+@@ -234,9 +233,13 @@ static int sun4i_usb_phy_power_off(struc
+ {
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+ struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
++ int ret;
+
+- if (dm_gpio_is_valid(&usb_phy->gpio_vbus))
+- dm_gpio_set_value(&usb_phy->gpio_vbus, 0);
++ if (usb_phy->vbus) {
++ ret = regulator_set_enable(usb_phy->vbus, false);
++ if (ret && ret != -ENOSYS)
++ return ret;
++ }
+
+ return 0;
+ }
+@@ -450,22 +453,16 @@ static int sun4i_usb_phy_probe(struct ud
+ for (i = 0; i < data->cfg->num_phys; i++) {
+ struct sun4i_usb_phy_plat *phy = &plat[i];
+ struct sun4i_usb_phy_info *info = &phy_info[i];
+- char name[16];
++ char name[20];
+
+ if (data->cfg->missing_phys & BIT(i))
+ continue;
+
+- ret = dm_gpio_lookup_name(info->gpio_vbus, &phy->gpio_vbus);
+- if (ret == 0) {
+- ret = dm_gpio_request(&phy->gpio_vbus, "usb_vbus");
+- if (ret)
+- return ret;
+- ret = dm_gpio_set_dir_flags(&phy->gpio_vbus,
+- GPIOD_IS_OUT);
+- if (ret)
+- return ret;
+- ret = dm_gpio_set_value(&phy->gpio_vbus, 0);
+- if (ret)
++ snprintf(name, sizeof(name), "usb%d_vbus-supply", i);
++ ret = device_get_supply_regulator(dev, name, &phy->vbus);
++ if (phy->vbus) {
++ ret = regulator_set_enable(phy->vbus, false);
++ if (ret && ret != -ENOSYS)
+ return ret;
+ }
+
--- /dev/null
+From 649bb7845e30805c66f62fc5725c4dbf350f21cb Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 22:26:40 -0500
+Subject: [PATCH 10/90] sunxi: Remove obsolete USBx_VBUS_PIN Kconfig symbols
+
+Now that the USB PHY driver uses the device tree to get VBUS supply
+regulators, these Kconfig symbols are unused. Remove them.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/mach-sunxi/Kconfig | 29 -----------------------------
+ 1 file changed, 29 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -693,13 +693,6 @@ config MMC_SUNXI_SLOT_EXTRA
+ slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable
+ support for this.
+
+-config USB0_VBUS_PIN
+- string "Vbus enable pin for usb0 (otg)"
+- default ""
+- ---help---
+- Set the Vbus enable pin for usb0 (otg). This takes a string in the
+- format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+-
+ config USB0_VBUS_DET
+ string "Vbus detect pin for usb0 (otg)"
+ default ""
+@@ -714,28 +707,6 @@ config USB0_ID_DET
+ Set the ID detect pin for usb0 (otg). This takes a string in the
+ format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+
+-config USB1_VBUS_PIN
+- string "Vbus enable pin for usb1 (ehci0)"
+- default "PH6" if MACH_SUN4I || MACH_SUN7I
+- default "PH27" if MACH_SUN6I
+- ---help---
+- Set the Vbus enable pin for usb1 (ehci0, usb0 is the otg). This takes
+- a string in the format understood by sunxi_name_to_gpio, e.g.
+- PH1 for pin 1 of port H.
+-
+-config USB2_VBUS_PIN
+- string "Vbus enable pin for usb2 (ehci1)"
+- default "PH3" if MACH_SUN4I || MACH_SUN7I
+- default "PH24" if MACH_SUN6I
+- ---help---
+- See USB1_VBUS_PIN help text.
+-
+-config USB3_VBUS_PIN
+- string "Vbus enable pin for usb3 (ehci2)"
+- default ""
+- ---help---
+- See USB1_VBUS_PIN help text.
+-
+ config I2C0_ENABLE
+ bool "Enable I2C/TWI controller 0"
+ default y if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_R40
--- /dev/null
+From 73d6c82e34e89cfde880d1948b3e0dc714adead8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 30 Apr 2022 22:34:19 -0500
+Subject: [PATCH 11/90] clk: sunxi: Add support for the D1 CCU
+
+Since the D1 CCU binding is defined, we can add support for its
+gates/resets, following the pattern of the existing drivers.
+
+Series-to: sunxi
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi/Kconfig | 6 +
+ drivers/clk/sunxi/Makefile | 1 +
+ drivers/clk/sunxi/clk_d1.c | 82 ++++++++++++
+ drivers/clk/sunxi/clk_sunxi.c | 5 +
+ include/dt-bindings/clock/sun20i-d1-ccu.h | 156 ++++++++++++++++++++++
+ include/dt-bindings/reset/sun20i-d1-ccu.h | 77 +++++++++++
+ 6 files changed, 327 insertions(+)
+ create mode 100644 drivers/clk/sunxi/clk_d1.c
+ create mode 100644 include/dt-bindings/clock/sun20i-d1-ccu.h
+ create mode 100644 include/dt-bindings/reset/sun20i-d1-ccu.h
+
+--- a/drivers/clk/sunxi/Kconfig
++++ b/drivers/clk/sunxi/Kconfig
+@@ -87,6 +87,12 @@ config CLK_SUN8I_H3
+ This enables common clock driver support for platforms based
+ on Allwinner H3/H5 SoC.
+
++config CLK_SUN20I_D1
++ bool "Clock driver for Allwinner D1"
++ help
++ This enables common clock driver support for platforms based
++ on Allwinner D1 SoC.
++
+ config CLK_SUN50I_H6
+ bool "Clock driver for Allwinner H6"
+ default MACH_SUN50I_H6
+--- a/drivers/clk/sunxi/Makefile
++++ b/drivers/clk/sunxi/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
+ 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_SUN20I_D1) += clk_d1.o
+ obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o
+ obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o
+ obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o
+--- /dev/null
++++ b/drivers/clk/sunxi/clk_d1.c
+@@ -0,0 +1,82 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <common.h>
++#include <clk-uclass.h>
++#include <dm.h>
++#include <errno.h>
++#include <clk/sunxi.h>
++#include <dt-bindings/clock/sun20i-d1-ccu.h>
++#include <dt-bindings/reset/sun20i-d1-ccu.h>
++#include <linux/bitops.h>
++
++static struct ccu_clk_gate d1_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_BUS_I2C0] = GATE(0x91c, BIT(0)),
++ [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)),
++ [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)),
++ [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)),
++ [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_EMAC] = GATE(0x97c, BIT(0)),
++
++ [CLK_USB_OHCI0] = GATE(0xa70, BIT(31)),
++ [CLK_USB_OHCI1] = GATE(0xa74, BIT(31)),
++ [CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
++ [CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
++ [CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
++ [CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)),
++ [CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
++ [CLK_BUS_LRADC] = GATE(0xa9c, BIT(0)),
++
++ [CLK_RISCV] = GATE(0xd04, BIT(31)),
++};
++
++static struct ccu_reset d1_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_I2C0] = RESET(0x91c, BIT(16)),
++ [RST_BUS_I2C1] = RESET(0x91c, BIT(17)),
++ [RST_BUS_I2C2] = RESET(0x91c, BIT(18)),
++ [RST_BUS_I2C3] = RESET(0x91c, BIT(19)),
++ [RST_BUS_SPI0] = RESET(0x96c, BIT(16)),
++ [RST_BUS_SPI1] = RESET(0x96c, BIT(17)),
++
++ [RST_BUS_EMAC] = RESET(0x97c, BIT(16)),
++
++ [RST_USB_PHY0] = RESET(0xa70, BIT(30)),
++ [RST_USB_PHY1] = RESET(0xa74, BIT(30)),
++ [RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
++ [RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
++ [RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
++ [RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)),
++ [RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
++ [RST_BUS_LRADC] = RESET(0xa9c, BIT(16)),
++};
++
++const struct ccu_desc d1_ccu_desc = {
++ .gates = d1_gates,
++ .resets = d1_resets,
++ .num_gates = ARRAY_SIZE(d1_gates),
++ .num_resets = ARRAY_SIZE(d1_resets),
++};
+--- a/drivers/clk/sunxi/clk_sunxi.c
++++ b/drivers/clk/sunxi/clk_sunxi.c
+@@ -118,6 +118,7 @@ extern const struct ccu_desc a64_ccu_des
+ extern const struct ccu_desc a80_ccu_desc;
+ extern const struct ccu_desc a80_mmc_clk_desc;
+ extern const struct ccu_desc a83t_ccu_desc;
++extern const struct ccu_desc d1_ccu_desc;
+ extern const struct ccu_desc f1c100s_ccu_desc;
+ extern const struct ccu_desc h3_ccu_desc;
+ extern const struct ccu_desc h6_ccu_desc;
+@@ -183,6 +184,10 @@ static const struct udevice_id sunxi_clk
+ { .compatible = "allwinner,sun9i-a80-mmc-config-clk",
+ .data = (ulong)&a80_mmc_clk_desc },
+ #endif
++#ifdef CONFIG_CLK_SUN20I_D1
++ { .compatible = "allwinner,sun20i-d1-ccu",
++ .data = (ulong)&d1_ccu_desc },
++#endif
+ #ifdef CONFIG_CLK_SUN50I_A64
+ { .compatible = "allwinner,sun50i-a64-ccu",
+ .data = (ulong)&a64_ccu_desc },
+--- /dev/null
++++ b/include/dt-bindings/clock/sun20i-d1-ccu.h
+@@ -0,0 +1,156 @@
++/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
++/*
++ * Copyright (C) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
++#define _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
++
++#define CLK_PLL_CPUX 0
++#define CLK_PLL_DDR0 1
++#define CLK_PLL_PERIPH0_4X 2
++#define CLK_PLL_PERIPH0_2X 3
++#define CLK_PLL_PERIPH0_800M 4
++#define CLK_PLL_PERIPH0 5
++#define CLK_PLL_PERIPH0_DIV3 6
++#define CLK_PLL_VIDEO0_4X 7
++#define CLK_PLL_VIDEO0_2X 8
++#define CLK_PLL_VIDEO0 9
++#define CLK_PLL_VIDEO1_4X 10
++#define CLK_PLL_VIDEO1_2X 11
++#define CLK_PLL_VIDEO1 12
++#define CLK_PLL_VE 13
++#define CLK_PLL_AUDIO0_4X 14
++#define CLK_PLL_AUDIO0_2X 15
++#define CLK_PLL_AUDIO0 16
++#define CLK_PLL_AUDIO1 17
++#define CLK_PLL_AUDIO1_DIV2 18
++#define CLK_PLL_AUDIO1_DIV5 19
++#define CLK_CPUX 20
++#define CLK_CPUX_AXI 21
++#define CLK_CPUX_APB 22
++#define CLK_PSI_AHB 23
++#define CLK_APB0 24
++#define CLK_APB1 25
++#define CLK_MBUS 26
++#define CLK_DE 27
++#define CLK_BUS_DE 28
++#define CLK_DI 29
++#define CLK_BUS_DI 30
++#define CLK_G2D 31
++#define CLK_BUS_G2D 32
++#define CLK_CE 33
++#define CLK_BUS_CE 34
++#define CLK_VE 35
++#define CLK_BUS_VE 36
++#define CLK_BUS_DMA 37
++#define CLK_BUS_MSGBOX0 38
++#define CLK_BUS_MSGBOX1 39
++#define CLK_BUS_MSGBOX2 40
++#define CLK_BUS_SPINLOCK 41
++#define CLK_BUS_HSTIMER 42
++#define CLK_AVS 43
++#define CLK_BUS_DBG 44
++#define CLK_BUS_PWM 45
++#define CLK_BUS_IOMMU 46
++#define CLK_DRAM 47
++#define CLK_MBUS_DMA 48
++#define CLK_MBUS_VE 49
++#define CLK_MBUS_CE 50
++#define CLK_MBUS_TVIN 51
++#define CLK_MBUS_CSI 52
++#define CLK_MBUS_G2D 53
++#define CLK_MBUS_RISCV 54
++#define CLK_BUS_DRAM 55
++#define CLK_MMC0 56
++#define CLK_MMC1 57
++#define CLK_MMC2 58
++#define CLK_BUS_MMC0 59
++#define CLK_BUS_MMC1 60
++#define CLK_BUS_MMC2 61
++#define CLK_BUS_UART0 62
++#define CLK_BUS_UART1 63
++#define CLK_BUS_UART2 64
++#define CLK_BUS_UART3 65
++#define CLK_BUS_UART4 66
++#define CLK_BUS_UART5 67
++#define CLK_BUS_I2C0 68
++#define CLK_BUS_I2C1 69
++#define CLK_BUS_I2C2 70
++#define CLK_BUS_I2C3 71
++#define CLK_SPI0 72
++#define CLK_SPI1 73
++#define CLK_BUS_SPI0 74
++#define CLK_BUS_SPI1 75
++#define CLK_EMAC_25M 76
++#define CLK_BUS_EMAC 77
++#define CLK_IR_TX 78
++#define CLK_BUS_IR_TX 79
++#define CLK_BUS_GPADC 80
++#define CLK_BUS_THS 81
++#define CLK_I2S0 82
++#define CLK_I2S1 83
++#define CLK_I2S2 84
++#define CLK_I2S2_ASRC 85
++#define CLK_BUS_I2S0 86
++#define CLK_BUS_I2S1 87
++#define CLK_BUS_I2S2 88
++#define CLK_SPDIF_TX 89
++#define CLK_SPDIF_RX 90
++#define CLK_BUS_SPDIF 91
++#define CLK_DMIC 92
++#define CLK_BUS_DMIC 93
++#define CLK_AUDIO_DAC 94
++#define CLK_AUDIO_ADC 95
++#define CLK_BUS_AUDIO 96
++#define CLK_USB_OHCI0 97
++#define CLK_USB_OHCI1 98
++#define CLK_BUS_OHCI0 99
++#define CLK_BUS_OHCI1 100
++#define CLK_BUS_EHCI0 101
++#define CLK_BUS_EHCI1 102
++#define CLK_BUS_OTG 103
++#define CLK_BUS_LRADC 104
++#define CLK_BUS_DPSS_TOP 105
++#define CLK_HDMI_24M 106
++#define CLK_HDMI_CEC_32K 107
++#define CLK_HDMI_CEC 108
++#define CLK_BUS_HDMI 109
++#define CLK_MIPI_DSI 110
++#define CLK_BUS_MIPI_DSI 111
++#define CLK_TCON_LCD0 112
++#define CLK_BUS_TCON_LCD0 113
++#define CLK_TCON_TV 114
++#define CLK_BUS_TCON_TV 115
++#define CLK_TVE 116
++#define CLK_BUS_TVE_TOP 117
++#define CLK_BUS_TVE 118
++#define CLK_TVD 119
++#define CLK_BUS_TVD_TOP 120
++#define CLK_BUS_TVD 121
++#define CLK_LEDC 122
++#define CLK_BUS_LEDC 123
++#define CLK_CSI_TOP 124
++#define CLK_CSI_MCLK 125
++#define CLK_BUS_CSI 126
++#define CLK_TPADC 127
++#define CLK_BUS_TPADC 128
++#define CLK_BUS_TZMA 129
++#define CLK_DSP 130
++#define CLK_BUS_DSP_CFG 131
++#define CLK_RISCV 132
++#define CLK_RISCV_AXI 133
++#define CLK_BUS_RISCV_CFG 134
++#define CLK_FANOUT_24M 135
++#define CLK_FANOUT_12M 136
++#define CLK_FANOUT_16M 137
++#define CLK_FANOUT_25M 138
++#define CLK_FANOUT_32K 139
++#define CLK_FANOUT_27M 140
++#define CLK_FANOUT_PCLK 141
++#define CLK_FANOUT0 142
++#define CLK_FANOUT1 143
++#define CLK_FANOUT2 144
++
++#endif /* _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_ */
+--- /dev/null
++++ b/include/dt-bindings/reset/sun20i-d1-ccu.h
+@@ -0,0 +1,77 @@
++/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
++/*
++ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
++#define _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
++
++#define RST_MBUS 0
++#define RST_BUS_DE 1
++#define RST_BUS_DI 2
++#define RST_BUS_G2D 3
++#define RST_BUS_CE 4
++#define RST_BUS_VE 5
++#define RST_BUS_DMA 6
++#define RST_BUS_MSGBOX0 7
++#define RST_BUS_MSGBOX1 8
++#define RST_BUS_MSGBOX2 9
++#define RST_BUS_SPINLOCK 10
++#define RST_BUS_HSTIMER 11
++#define RST_BUS_DBG 12
++#define RST_BUS_PWM 13
++#define RST_BUS_DRAM 14
++#define RST_BUS_MMC0 15
++#define RST_BUS_MMC1 16
++#define RST_BUS_MMC2 17
++#define RST_BUS_UART0 18
++#define RST_BUS_UART1 19
++#define RST_BUS_UART2 20
++#define RST_BUS_UART3 21
++#define RST_BUS_UART4 22
++#define RST_BUS_UART5 23
++#define RST_BUS_I2C0 24
++#define RST_BUS_I2C1 25
++#define RST_BUS_I2C2 26
++#define RST_BUS_I2C3 27
++#define RST_BUS_SPI0 28
++#define RST_BUS_SPI1 29
++#define RST_BUS_EMAC 30
++#define RST_BUS_IR_TX 31
++#define RST_BUS_GPADC 32
++#define RST_BUS_THS 33
++#define RST_BUS_I2S0 34
++#define RST_BUS_I2S1 35
++#define RST_BUS_I2S2 36
++#define RST_BUS_SPDIF 37
++#define RST_BUS_DMIC 38
++#define RST_BUS_AUDIO 39
++#define RST_USB_PHY0 40
++#define RST_USB_PHY1 41
++#define RST_BUS_OHCI0 42
++#define RST_BUS_OHCI1 43
++#define RST_BUS_EHCI0 44
++#define RST_BUS_EHCI1 45
++#define RST_BUS_OTG 46
++#define RST_BUS_LRADC 47
++#define RST_BUS_DPSS_TOP 48
++#define RST_BUS_HDMI_SUB 49
++#define RST_BUS_HDMI_MAIN 50
++#define RST_BUS_MIPI_DSI 51
++#define RST_BUS_TCON_LCD0 52
++#define RST_BUS_TCON_TV 53
++#define RST_BUS_LVDS0 54
++#define RST_BUS_TVE 55
++#define RST_BUS_TVE_TOP 56
++#define RST_BUS_TVD 57
++#define RST_BUS_TVD_TOP 58
++#define RST_BUS_LEDC 59
++#define RST_BUS_CSI 60
++#define RST_BUS_TPADC 61
++#define RST_DSP 62
++#define RST_BUS_DSP_CFG 63
++#define RST_BUS_DSP_DBG 64
++#define RST_BUS_RISCV_CFG 65
++
++#endif /* _DT_BINDINGS_RST_SUN20I_D1_CCU_H_ */
--- /dev/null
+From cbb281e0ec847b9de41970e470348b3534bb9a9f Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 26 Aug 2021 18:02:54 -0500
+Subject: [PATCH 12/90] gpio: axp: Remove virtual VBUS enable GPIO
+
+Now that this functionality is modeled using the device tree and
+regulator uclass, the named GPIO is not referenced anywhere. Remove
+it, along with the rest of the support for AXP virtual GPIOs.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h | 8 ---
+ drivers/gpio/axp_gpio.c | 75 ++++++++------------------
+ drivers/gpio/sunxi_gpio.c | 8 ---
+ include/axp221.h | 4 --
+ include/axp809.h | 4 --
+ include/axp818.h | 4 --
+ 6 files changed, 21 insertions(+), 82 deletions(-)
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -111,7 +111,6 @@ enum sunxi_gpio_number {
+ SUNXI_GPIO_L_START = 352,
+ SUNXI_GPIO_M_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_L),
+ SUNXI_GPIO_N_START = SUNXI_GPIO_NEXT(SUNXI_GPIO_M),
+- SUNXI_GPIO_AXP0_START = 1024,
+ };
+
+ /* SUNXI GPIO number definitions */
+@@ -128,8 +127,6 @@ enum sunxi_gpio_number {
+ #define SUNXI_GPM(_nr) (SUNXI_GPIO_M_START + (_nr))
+ #define SUNXI_GPN(_nr) (SUNXI_GPIO_N_START + (_nr))
+
+-#define SUNXI_GPAXP0(_nr) (SUNXI_GPIO_AXP0_START + (_nr))
+-
+ /* GPIO pin function config */
+ #define SUNXI_GPIO_INPUT 0
+ #define SUNXI_GPIO_OUTPUT 1
+@@ -207,11 +204,6 @@ enum sunxi_gpio_number {
+ #define SUNXI_GPIO_PULL_UP 1
+ #define SUNXI_GPIO_PULL_DOWN 2
+
+-/* Virtual AXP0 GPIOs */
+-#define SUNXI_GPIO_AXP0_PREFIX "AXP0-"
+-#define SUNXI_GPIO_AXP0_VBUS_ENABLE 5
+-#define SUNXI_GPIO_AXP0_GPIO_COUNT 6
+-
+ struct sunxi_gpio_plat {
+ struct sunxi_gpio *regs;
+ char bank_name[3];
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -15,6 +15,9 @@
+ #include <dm/root.h>
+ #include <errno.h>
+
++#define AXP_GPIO_PREFIX "AXP0-"
++#define AXP_GPIO_COUNT 4
++
+ static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
+
+ static u8 axp_get_gpio_ctrl_reg(unsigned pin)
+@@ -46,28 +49,14 @@ static int axp_gpio_direction_input(stru
+ static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
+ int val)
+ {
+- __maybe_unused int ret;
+ u8 reg;
+
+- switch (pin) {
+-#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+- /* Only available on later PMICs */
+- case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+- ret = pmic_bus_clrbits(AXP_MISC_CTRL,
+- AXP_MISC_CTRL_N_VBUSEN_FUNC);
+- if (ret)
+- return ret;
+-
+- return axp_gpio_set_value(dev, pin, val);
+-#endif
+- default:
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
++ reg = axp_get_gpio_ctrl_reg(pin);
++ if (reg == 0)
++ return -EINVAL;
+
+- return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
+- }
++ return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
++ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+
+ static int axp_gpio_get_value(struct udevice *dev, unsigned pin)
+@@ -75,25 +64,16 @@ static int axp_gpio_get_value(struct ude
+ u8 reg, val, mask;
+ int ret;
+
+- switch (pin) {
+-#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+- /* Only available on later PMICs */
+- case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+- ret = pmic_bus_read(AXP_VBUS_IPSOUT, &val);
+- mask = AXP_VBUS_IPSOUT_DRIVEBUS;
+- break;
+-#endif
+- default:
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
++ reg = axp_get_gpio_ctrl_reg(pin);
++ if (reg == 0)
++ return -EINVAL;
+
+- ret = pmic_bus_read(AXP_GPIO_STATE, &val);
+- mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
+- }
++ ret = pmic_bus_read(AXP_GPIO_STATE, &val);
+ if (ret)
+ return ret;
+
++ mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
++
+ return (val & mask) ? 1 : 0;
+ }
+
+@@ -101,25 +81,12 @@ static int axp_gpio_set_value(struct ude
+ {
+ u8 reg;
+
+- switch (pin) {
+-#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
+- /* Only available on later PMICs */
+- case SUNXI_GPIO_AXP0_VBUS_ENABLE:
+- if (val)
+- return pmic_bus_setbits(AXP_VBUS_IPSOUT,
+- AXP_VBUS_IPSOUT_DRIVEBUS);
+- else
+- return pmic_bus_clrbits(AXP_VBUS_IPSOUT,
+- AXP_VBUS_IPSOUT_DRIVEBUS);
+-#endif
+- default:
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
++ reg = axp_get_gpio_ctrl_reg(pin);
++ if (reg == 0)
++ return -EINVAL;
+
+- return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
+- }
++ return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
++ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+
+ static const struct dm_gpio_ops gpio_axp_ops = {
+@@ -134,8 +101,8 @@ static int gpio_axp_probe(struct udevice
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ /* Tell the uclass how many GPIOs we have */
+- uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX);
+- uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT;
++ uc_priv->bank_name = AXP_GPIO_PREFIX;
++ uc_priv->gpio_count = AXP_GPIO_COUNT;
+
+ return 0;
+ }
+--- a/drivers/gpio/sunxi_gpio.c
++++ b/drivers/gpio/sunxi_gpio.c
+@@ -114,15 +114,7 @@ int sunxi_name_to_gpio(const char *name)
+ {
+ unsigned int gpio;
+ int ret;
+-#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
+- char lookup[8];
+
+- if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
+- sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
+- SUNXI_GPIO_AXP0_VBUS_ENABLE);
+- name = lookup;
+- }
+-#endif
+ ret = gpio_lookup_name(name, NULL, NULL, &gpio);
+
+ return ret ? ret : gpio;
+--- a/include/axp221.h
++++ b/include/axp221.h
+@@ -53,10 +53,6 @@
+ #ifdef CONFIG_AXP221_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_VBUS_IPSOUT 0x30
+-#define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+-#define AXP_MISC_CTRL 0x8f
+-#define AXP_MISC_CTRL_N_VBUSEN_FUNC (1 << 4)
+ #define AXP_GPIO0_CTRL 0x90
+ #define AXP_GPIO1_CTRL 0x92
+ #define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+--- a/include/axp809.h
++++ b/include/axp809.h
+@@ -47,10 +47,6 @@
+ #ifdef CONFIG_AXP809_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_VBUS_IPSOUT 0x30
+-#define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+-#define AXP_MISC_CTRL 0x8f
+-#define AXP_MISC_CTRL_N_VBUSEN_FUNC (1 << 4)
+ #define AXP_GPIO0_CTRL 0x90
+ #define AXP_GPIO1_CTRL 0x92
+ #define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+--- a/include/axp818.h
++++ b/include/axp818.h
+@@ -61,10 +61,6 @@
+ #ifdef CONFIG_AXP818_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_VBUS_IPSOUT 0x30
+-#define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2)
+-#define AXP_MISC_CTRL 0x8f
+-#define AXP_MISC_CTRL_N_VBUSEN_FUNC (1 << 4)
+ #define AXP_GPIO0_CTRL 0x90
+ #define AXP_GPIO1_CTRL 0x92
+ #define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
--- /dev/null
+From 5a909f4d4d10f3a7a59b3b75eee502937e166891 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 2 May 2022 22:00:05 -0500
+Subject: [PATCH 13/90] clk: sunxi: Add a driver for the legacy A31/A23/A33
+ PRCM
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi/Kconfig | 13 ++++-
+ drivers/clk/sunxi/Makefile | 1 +
+ drivers/clk/sunxi/clk_a31_apb0.c | 97 ++++++++++++++++++++++++++++++++
+ include/clk/sunxi.h | 1 +
+ 4 files changed, 110 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/clk/sunxi/clk_a31_apb0.c
+
+--- a/drivers/clk/sunxi/Kconfig
++++ b/drivers/clk/sunxi/Kconfig
+@@ -38,12 +38,21 @@ config CLK_SUN6I_A31
+ This enables common clock driver support for platforms based
+ on Allwinner A31/A31s SoC.
+
++config CLK_SUN6I_A31_APB0
++ bool "Clock driver for Allwinner A31 generation PRCM (legacy)"
++ default MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
++ help
++ This enables common clock driver support for the PRCM
++ in Allwinner A31/A31s/A23/A33 SoCs using the legacy PRCM
++ MFD binding.
++
+ config CLK_SUN6I_A31_R
+- bool "Clock driver for Allwinner A31 generation PRCM"
++ bool "Clock driver for Allwinner A31 generation PRCM (CCU)"
+ default SUNXI_GEN_SUN6I
+ help
+ This enables common clock driver support for the PRCM
+- in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs.
++ in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs using
++ the new CCU binding.
+
+ config CLK_SUN8I_A23
+ bool "Clock driver for Allwinner A23/A33"
+--- a/drivers/clk/sunxi/Makefile
++++ b/drivers/clk/sunxi/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_CLK_SUNIV_F1C100S) += clk_f
+ obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
+ obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
+ obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
++obj-$(CONFIG_CLK_SUN6I_A31_APB0) += clk_a31_apb0.o
+ obj-$(CONFIG_CLK_SUN6I_A31_R) += clk_a31_r.o
+ obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o
+ obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o
+--- /dev/null
++++ b/drivers/clk/sunxi/clk_a31_apb0.c
+@@ -0,0 +1,97 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (C) Samuel Holland <samuel@sholland.org>
++ */
++
++#include <clk-uclass.h>
++#include <dm.h>
++#include <clk/sunxi.h>
++#include <linux/bitops.h>
++
++static struct ccu_clk_gate sun6i_apb0_gates[] = {
++ [0] = GATE(0x028, BIT(0)),
++ [1] = GATE(0x028, BIT(1)),
++ [2] = GATE(0x028, BIT(2)),
++ [3] = GATE(0x028, BIT(3)),
++ [4] = GATE(0x028, BIT(4)),
++ [5] = GATE(0x028, BIT(5)),
++ [6] = GATE(0x028, BIT(6)),
++ [7] = GATE(0x028, BIT(7)),
++};
++
++static struct ccu_reset sun6i_apb0_resets[] = {
++ [0] = RESET(0x0b0, BIT(0)),
++ [1] = RESET(0x0b0, BIT(1)),
++ [2] = RESET(0x0b0, BIT(2)),
++ [3] = RESET(0x0b0, BIT(3)),
++ [4] = RESET(0x0b0, BIT(4)),
++ [5] = RESET(0x0b0, BIT(5)),
++ [6] = RESET(0x0b0, BIT(6)),
++ [7] = RESET(0x0b0, BIT(7)),
++};
++
++const struct ccu_desc sun6i_apb0_clk_desc = {
++ .gates = sun6i_apb0_gates,
++ .resets = sun6i_apb0_resets,
++ .num_gates = ARRAY_SIZE(sun6i_apb0_gates),
++ .num_resets = ARRAY_SIZE(sun6i_apb0_resets),
++};
++
++static int sun6i_apb0_of_to_plat(struct udevice *dev)
++{
++ struct ccu_plat *plat = dev_get_plat(dev);
++
++ plat->base = dev_read_addr_ptr(dev->parent);
++ if (!plat->base)
++ return -ENOMEM;
++
++ plat->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
++ if (!plat->desc)
++ return -EINVAL;
++
++ return 0;
++}
++
++static const struct udevice_id sun6i_apb0_clk_ids[] = {
++ { .compatible = "allwinner,sun6i-a31-apb0-gates-clk",
++ .data = (ulong)&sun6i_apb0_clk_desc },
++ { .compatible = "allwinner,sun8i-a23-apb0-gates-clk",
++ .data = (ulong)&sun6i_apb0_clk_desc },
++ { }
++};
++
++U_BOOT_DRIVER(sun6i_apb0_clk) = {
++ .name = "sun6i_apb0_clk",
++ .id = UCLASS_CLK,
++ .of_match = sun6i_apb0_clk_ids,
++ .of_to_plat = sun6i_apb0_of_to_plat,
++ .plat_auto = sizeof(struct ccu_plat),
++ .ops = &sunxi_clk_ops,
++};
++
++static const struct udevice_id sun6i_apb0_reset_ids[] = {
++ { .compatible = "allwinner,sun6i-a31-clock-reset",
++ .data = (ulong)&sun6i_apb0_clk_desc },
++ { }
++};
++
++U_BOOT_DRIVER(sun6i_apb0_reset) = {
++ .name = "sun6i_apb0_reset",
++ .id = UCLASS_RESET,
++ .of_match = sun6i_apb0_reset_ids,
++ .of_to_plat = sun6i_apb0_of_to_plat,
++ .plat_auto = sizeof(struct ccu_plat),
++ .ops = &sunxi_reset_ops,
++};
++
++static const struct udevice_id sun6i_prcm_mfd_ids[] = {
++ { .compatible = "allwinner,sun6i-a31-prcm" },
++ { .compatible = "allwinner,sun8i-a23-prcm" },
++ { }
++};
++
++U_BOOT_DRIVER(sun6i_prcm_mfd) = {
++ .name = "sun6i_prcm_mfd",
++ .id = UCLASS_SIMPLE_BUS,
++ .of_match = sun6i_prcm_mfd_ids,
++};
+--- a/include/clk/sunxi.h
++++ b/include/clk/sunxi.h
+@@ -86,5 +86,6 @@ struct ccu_plat {
+ };
+
+ extern struct clk_ops sunxi_clk_ops;
++extern struct reset_ops sunxi_reset_ops;
+
+ #endif /* _CLK_SUNXI_H */
--- /dev/null
+From 3d97f99cb173422ee8a15b7ec1df83ff61e68204 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 30 Oct 2022 14:28:23 -0500
+Subject: [PATCH 14/90] clk: sunxi: Use the right symbol in the Makefile
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -25,7 +25,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+ obj-$(CONFIG_ARCH_SOCFPGA) += altera/
+ obj-$(CONFIG_ARCH_STM32) += stm32/
+ obj-$(CONFIG_ARCH_STM32MP) += stm32/
+-obj-$(CONFIG_ARCH_SUNXI) += sunxi/
++obj-$(CONFIG_CLK_SUNXI) += sunxi/
+ obj-$(CONFIG_CLK_AT91) += at91/
+ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
+ obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
--- /dev/null
+From 9766169812418aee10dbc8d40aca27c1c576f521 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 14 Jul 2022 23:39:46 -0500
+Subject: [PATCH 15/90] net: sun8i-emac: Use common syscon setup for R40
+
+While R40 puts the EMAC syscon register at a different address from
+other variants, the relevant portion of the register's layout is the
+same. Factor out the register offset so the same code can be shared
+by all variants. This matches what the Linux driver does.
+
+This change provides two benefits beyond the simplification:
+ - R40 boards now respect the RX delays from the devicetree
+ - This resolves a warning on architectures where readl/writel
+ expect the address to have a pointer type, not phys_addr_t.
+
+Series-to: sunxi
+
+Cover-letter:
+net: sun8i-emac: Allwinner D1 Support
+D1 is a RISC-V SoC containing an EMAC compatible with the A64 EMAC.
+However, there are a couple of issues with the driver preventing it
+being built for RISC-V. These are resolved by patches 2-3. Patch 1 is
+a general cleanup.
+END
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/net/sun8i_emac.c | 29 ++++++++++++-----------------
+ 1 file changed, 12 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -162,7 +162,7 @@ struct emac_eth_dev {
+
+ enum emac_variant variant;
+ void *mac_reg;
+- phys_addr_t sysctl_reg;
++ void *sysctl_reg;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+ struct clk tx_clk;
+@@ -317,18 +317,7 @@ static int sun8i_emac_set_syscon(struct
+ {
+ u32 reg;
+
+- if (priv->variant == R40_GMAC) {
+- /* Select RGMII for R40 */
+- reg = readl(priv->sysctl_reg + 0x164);
+- reg |= SC_ETCS_INT_GMII |
+- SC_EPIT |
+- (CONFIG_GMAC_TX_DELAY << SC_ETXDC_OFFSET);
+-
+- writel(reg, priv->sysctl_reg + 0x164);
+- return 0;
+- }
+-
+- reg = readl(priv->sysctl_reg + 0x30);
++ reg = readl(priv->sysctl_reg);
+
+ reg = sun8i_emac_set_syscon_ephy(priv, reg);
+
+@@ -369,7 +358,7 @@ static int sun8i_emac_set_syscon(struct
+ reg |= ((pdata->rx_delay_ps / 100) << SC_ERXDC_OFFSET)
+ & SC_ERXDC_MASK;
+
+- writel(reg, priv->sysctl_reg + 0x30);
++ writel(reg, priv->sysctl_reg);
+
+ return 0;
+ }
+@@ -792,6 +781,7 @@ static int sun8i_emac_eth_of_to_plat(str
+ struct sun8i_eth_pdata *sun8i_pdata = dev_get_plat(dev);
+ struct eth_pdata *pdata = &sun8i_pdata->eth_pdata;
+ struct emac_eth_dev *priv = dev_get_priv(dev);
++ phys_addr_t syscon_base;
+ const fdt32_t *reg;
+ int node = dev_of_offset(dev);
+ int offset = 0;
+@@ -837,13 +827,18 @@ static int sun8i_emac_eth_of_to_plat(str
+ __func__);
+ return -EINVAL;
+ }
+- priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob,
+- offset, reg);
+- if (priv->sysctl_reg == FDT_ADDR_T_NONE) {
++
++ syscon_base = fdt_translate_address((void *)gd->fdt_blob, offset, reg);
++ if (syscon_base == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot find syscon base address\n", __func__);
+ return -EINVAL;
+ }
+
++ if (priv->variant == R40_GMAC)
++ priv->sysctl_reg = (void *)syscon_base + 0x164;
++ else
++ priv->sysctl_reg = (void *)syscon_base + 0x30;
++
+ pdata->phy_interface = -1;
+ priv->phyaddr = -1;
+ priv->use_internal_phy = false;
--- /dev/null
+From 2cde6c8a7c41c13137298c19b4e104e4f5d6851c Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Wed, 13 Jul 2022 17:21:43 +0100
+Subject: [PATCH 16/90] sunxi: mmc: ignore card detect in SPL
+
+The sunxi MMC code does not use the DM in the SPL, as we don't have a
+device tree available that early, also no space for it.
+This also means we cannot access the card-detect GPIO information from
+there, so we have Kconfig symbols called CONFIG_MMCx_CD_PIN, which each
+board has to define. This is a burden, also requires extra GPIO code in
+the SPL.
+As the SPL is the natural successor of the BootROM (from which we are
+loaded), we can actually ignore the CD pin completely, as this is what
+the BootROM does as well: CD GPIOs are board specific, but the BootROM
+is not, so accesses the MMC devices anyway.
+
+Remove the card detect code from the non-DM implementation of the sunxi
+MMC driver, to get rid of this unneeded code.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/mmc/sunxi_mmc.c | 37 ++-----------------------------------
+ 1 file changed, 2 insertions(+), 35 deletions(-)
+
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -44,22 +44,10 @@ struct sunxi_mmc_priv {
+ /* support 4 mmc hosts */
+ struct sunxi_mmc_priv mmc_host[4];
+
+-static int sunxi_mmc_getcd_gpio(int sdc_no)
+-{
+- switch (sdc_no) {
+- case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
+- case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
+- case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
+- case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
+- }
+- return -EINVAL;
+-}
+-
+ static int mmc_resource_init(int sdc_no)
+ {
+ struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+- int cd_pin, ret = 0;
+
+ debug("init mmc %d resource\n", sdc_no);
+
+@@ -90,16 +78,7 @@ static int mmc_resource_init(int sdc_no)
+ }
+ priv->mmc_no = sdc_no;
+
+- cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
+- if (cd_pin >= 0) {
+- ret = gpio_request(cd_pin, "mmc_cd");
+- if (!ret) {
+- sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
+- ret = gpio_direction_input(cd_pin);
+- }
+- }
+-
+- return ret;
++ return 0;
+ }
+ #endif
+
+@@ -523,23 +502,11 @@ static int sunxi_mmc_send_cmd_legacy(str
+ return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
+ }
+
+-static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
+-{
+- struct sunxi_mmc_priv *priv = mmc->priv;
+- int cd_pin;
+-
+- cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
+- if (cd_pin < 0)
+- return 1;
+-
+- return !gpio_get_value(cd_pin);
+-}
+-
++/* .get_cd is not needed by the SPL */
+ static const struct mmc_ops sunxi_mmc_ops = {
+ .send_cmd = sunxi_mmc_send_cmd_legacy,
+ .set_ios = sunxi_mmc_set_ios_legacy,
+ .init = sunxi_mmc_core_init,
+- .getcd = sunxi_mmc_getcd_legacy,
+ };
+
+ struct mmc *sunxi_mmc_init(int sdc_no)
--- /dev/null
+From 74afc3a4e0ff780eddd859a25de7142e4baeeed5 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Wed, 13 Jul 2022 17:21:44 +0100
+Subject: [PATCH 17/90] sunxi: mmc: group non-DM specific functions
+
+As the SPL code for sunxi boards does not use the driver model, we have
+two mmc_ops structures, one for DM, one for non-DM. The actual hardware
+access code is shared, with the respective callback functions using that
+common code.
+
+To make this more obvious and easier to read, reorder the functions to
+group them: we first have the common code, then the non-DM bits, and
+the proper DM implementation at the end.
+Also document this structure in the comment at the beginning of the file.
+
+No functional change intended.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/mmc/sunxi_mmc.c | 117 +++++++++++++++++++++-------------------
+ 1 file changed, 61 insertions(+), 56 deletions(-)
+
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -5,6 +5,12 @@
+ * Aaron <leafy.myeh@allwinnertech.com>
+ *
+ * MMC driver for allwinner sunxi platform.
++ *
++ * This driver is used by the (ARM) SPL with the legacy MMC interface, and
++ * by U-Boot proper using the full DM interface. The actual hardware access
++ * code is common, and comes first in this file.
++ * The legacy MMC interface implementation comes next, followed by the
++ * proper DM_MMC implementation at the end.
+ */
+
+ #include <common.h>
+@@ -40,48 +46,6 @@ struct sunxi_mmc_priv {
+ struct mmc_config cfg;
+ };
+
+-#if !CONFIG_IS_ENABLED(DM_MMC)
+-/* support 4 mmc hosts */
+-struct sunxi_mmc_priv mmc_host[4];
+-
+-static int mmc_resource_init(int sdc_no)
+-{
+- struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
+- struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+-
+- debug("init mmc %d resource\n", sdc_no);
+-
+- switch (sdc_no) {
+- case 0:
+- priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
+- priv->mclkreg = &ccm->sd0_clk_cfg;
+- break;
+- case 1:
+- priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
+- priv->mclkreg = &ccm->sd1_clk_cfg;
+- break;
+-#ifdef SUNXI_MMC2_BASE
+- case 2:
+- priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
+- priv->mclkreg = &ccm->sd2_clk_cfg;
+- break;
+-#endif
+-#ifdef SUNXI_MMC3_BASE
+- case 3:
+- priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
+- priv->mclkreg = &ccm->sd3_clk_cfg;
+- break;
+-#endif
+- default:
+- printf("Wrong mmc number %d\n", sdc_no);
+- return -1;
+- }
+- priv->mmc_no = sdc_no;
+-
+- return 0;
+-}
+-#endif
+-
+ /*
+ * All A64 and later MMC controllers feature auto-calibration. This would
+ * normally be detected via the compatible string, but we need something
+@@ -269,19 +233,6 @@ static int sunxi_mmc_set_ios_common(stru
+ return 0;
+ }
+
+-#if !CONFIG_IS_ENABLED(DM_MMC)
+-static int sunxi_mmc_core_init(struct mmc *mmc)
+-{
+- struct sunxi_mmc_priv *priv = mmc->priv;
+-
+- /* Reset controller */
+- writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
+- udelay(1000);
+-
+- return 0;
+-}
+-#endif
+-
+ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
+ struct mmc_data *data)
+ {
+@@ -486,7 +437,60 @@ out:
+ return error;
+ }
+
++/* non-DM code here is used by the (ARM) SPL only */
++
+ #if !CONFIG_IS_ENABLED(DM_MMC)
++/* support 4 mmc hosts */
++struct sunxi_mmc_priv mmc_host[4];
++
++static int mmc_resource_init(int sdc_no)
++{
++ struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
++ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
++
++ debug("init mmc %d resource\n", sdc_no);
++
++ switch (sdc_no) {
++ case 0:
++ priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
++ priv->mclkreg = &ccm->sd0_clk_cfg;
++ break;
++ case 1:
++ priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
++ priv->mclkreg = &ccm->sd1_clk_cfg;
++ break;
++#ifdef SUNXI_MMC2_BASE
++ case 2:
++ priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
++ priv->mclkreg = &ccm->sd2_clk_cfg;
++ break;
++#endif
++#ifdef SUNXI_MMC3_BASE
++ case 3:
++ priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
++ priv->mclkreg = &ccm->sd3_clk_cfg;
++ break;
++#endif
++ default:
++ printf("Wrong mmc number %d\n", sdc_no);
++ return -1;
++ }
++ priv->mmc_no = sdc_no;
++
++ return 0;
++}
++
++static int sunxi_mmc_core_init(struct mmc *mmc)
++{
++ struct sunxi_mmc_priv *priv = mmc->priv;
++
++ /* Reset controller */
++ writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
++ udelay(1000);
++
++ return 0;
++}
++
+ static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
+ {
+ struct sunxi_mmc_priv *priv = mmc->priv;
+@@ -562,7 +566,8 @@ struct mmc *sunxi_mmc_init(int sdc_no)
+
+ return mmc_create(cfg, priv);
+ }
+-#else
++
++#else /* CONFIG_DM_MMC code below, as used by U-Boot proper */
+
+ static int sunxi_mmc_set_ios(struct udevice *dev)
+ {
--- /dev/null
+From bcc2e01668041c146d964ed5f77b819dcc35b3e2 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 15:07:47 +0000
+Subject: [PATCH 18/90] sunxi: remove CONFIG_MMC?_CD_PIN
+
+For legacy reasons we were defining the card detect GPIO for all sunxi
+boards in each board's defconfig.
+There is actually no need for a card-detect check in the SPL code (which
+consequently has been removed already), and also in U-Boot proper we
+have DM code to query the CD GPIO name from the device tree.
+
+That means we don't have any user of that information left, so can
+remove the definitions from the defconfigs.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/mach-sunxi/Kconfig | 27 --------------------
+ configs/A10-OLinuXino-Lime_defconfig | 1 -
+ configs/A10s-OLinuXino-M_defconfig | 2 --
+ configs/A13-OLinuXino_defconfig | 1 -
+ configs/A20-OLinuXino-Lime2-eMMC_defconfig | 1 -
+ configs/A20-OLinuXino-Lime_defconfig | 1 -
+ configs/A20-OLinuXino_MICRO-eMMC_defconfig | 1 -
+ configs/A20-OLinuXino_MICRO_defconfig | 2 --
+ configs/A20-Olimex-SOM-EVB_defconfig | 2 --
+ configs/A20-Olimex-SOM204-EVB-eMMC_defconfig | 1 -
+ configs/Bananapi_M2_Ultra_defconfig | 1 -
+ configs/Bananapi_m2m_defconfig | 1 -
+ configs/Cubieboard2_defconfig | 1 -
+ configs/Cubieboard4_defconfig | 1 -
+ configs/Cubieboard_defconfig | 1 -
+ configs/Itead_Ibox_A20_defconfig | 1 -
+ configs/Lamobo_R1_defconfig | 1 -
+ configs/Mele_M3_defconfig | 1 -
+ configs/Mele_M5_defconfig | 1 -
+ configs/Merrii_A80_Optimus_defconfig | 1 -
+ configs/Orangepi_mini_defconfig | 2 --
+ configs/Sinlinx_SinA31s_defconfig | 1 -
+ configs/Sinlinx_SinA33_defconfig | 1 -
+ configs/Sunchip_CX-A99_defconfig | 1 -
+ configs/UTOO_P66_defconfig | 1 -
+ configs/Yones_Toptech_BD1078_defconfig | 2 --
+ configs/bananapi_m2_zero_defconfig | 1 -
+ configs/bananapi_m64_defconfig | 1 -
+ configs/beelink_gs1_defconfig | 1 -
+ configs/nanopi_m1_plus_defconfig | 1 -
+ configs/oceanic_5205_5inmfd_defconfig | 1 -
+ configs/orangepi_3_defconfig | 1 -
+ configs/orangepi_lite2_defconfig | 1 -
+ configs/orangepi_one_plus_defconfig | 1 -
+ configs/orangepi_zero2_defconfig | 1 -
+ configs/orangepi_zero_plus2_defconfig | 1 -
+ configs/orangepi_zero_plus2_h3_defconfig | 1 -
+ configs/parrot_r16_defconfig | 1 -
+ configs/pine64-lts_defconfig | 1 -
+ configs/pine_h64_defconfig | 1 -
+ configs/sopine_baseboard_defconfig | 1 -
+ configs/tanix_tx6_defconfig | 1 -
+ 42 files changed, 73 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -652,33 +652,6 @@ config MACPWR
+ Set the pin used to power the MAC. This takes a string in the format
+ understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+
+-config MMC0_CD_PIN
+- string "Card detect pin for mmc0"
+- default "PF6" if MACH_SUN8I_A83T || MACH_SUNXI_H3_H5 || MACH_SUN50I
+- default ""
+- ---help---
+- Set the card detect pin for mmc0, leave empty to not use cd. This
+- takes a string in the format understood by sunxi_name_to_gpio, e.g.
+- PH1 for pin 1 of port H.
+-
+-config MMC1_CD_PIN
+- string "Card detect pin for mmc1"
+- default ""
+- ---help---
+- See MMC0_CD_PIN help text.
+-
+-config MMC2_CD_PIN
+- string "Card detect pin for mmc2"
+- default ""
+- ---help---
+- See MMC0_CD_PIN help text.
+-
+-config MMC3_CD_PIN
+- string "Card detect pin for mmc3"
+- default ""
+- ---help---
+- See MMC0_CD_PIN help text.
+-
+ config MMC1_PINS_PH
+ bool "Pins for mmc1 are on Port H"
+ depends on MACH_SUN4I || MACH_SUN7I || MACH_SUN8I_R40
+--- a/configs/A10-OLinuXino-Lime_defconfig
++++ b/configs/A10-OLinuXino-Lime_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN4I=y
+ CONFIG_DRAM_CLK=480
+ CONFIG_DRAM_EMR1=4
+ CONFIG_SYS_CLK_FREQ=912000000
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+--- a/configs/A10s-OLinuXino-M_defconfig
++++ b/configs/A10s-OLinuXino-M_defconfig
+@@ -4,8 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun5i-a10s-o
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN5I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MMC0_CD_PIN="PG1"
+-CONFIG_MMC1_CD_PIN="PG13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=1
+ CONFIG_USB1_VBUS_PIN="PB10"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/A13-OLinuXino_defconfig
++++ b/configs/A13-OLinuXino_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN5I=y
+ CONFIG_DRAM_CLK=408
+ CONFIG_DRAM_EMR1=0
+-CONFIG_MMC0_CD_PIN="PG0"
+ CONFIG_USB0_VBUS_DET="PG1"
+ CONFIG_USB1_VBUS_PIN="PG11"
+ CONFIG_AXP_GPIO=y
+--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
++++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+--- a/configs/A20-OLinuXino-Lime_defconfig
++++ b/configs/A20-OLinuXino-Lime_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+--- a/configs/A20-OLinuXino_MICRO-eMMC_defconfig
++++ b/configs/A20-OLinuXino_MICRO-eMMC_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_VIDEO_VGA=y
+--- a/configs/A20-OLinuXino_MICRO_defconfig
++++ b/configs/A20-OLinuXino_MICRO_defconfig
+@@ -4,8 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+-CONFIG_MMC3_CD_PIN="PH11"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_VIDEO_VGA=y
+--- a/configs/A20-Olimex-SOM-EVB_defconfig
++++ b/configs/A20-Olimex-SOM-EVB_defconfig
+@@ -4,8 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+-CONFIG_MMC3_CD_PIN="PH0"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_USB0_VBUS_PIN="PB9"
+ CONFIG_USB0_VBUS_DET="PH5"
+--- a/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig
++++ b/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-ol
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+--- a/configs/Bananapi_M2_Ultra_defconfig
++++ b/configs/Bananapi_M2_Ultra_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_R40=y
+ CONFIG_DRAM_CLK=576
+ CONFIG_MACPWR="PA17"
+-CONFIG_MMC0_CD_PIN="PH13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB1_VBUS_PIN="PH23"
+ CONFIG_USB2_VBUS_PIN="PH23"
+--- a/configs/Bananapi_m2m_defconfig
++++ b/configs/Bananapi_m2m_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN8I_A33=y
+ CONFIG_DRAM_CLK=600
+ CONFIG_DRAM_ZQ=15291
+ CONFIG_DRAM_ODT_EN=y
+-CONFIG_MMC0_CD_PIN="PB4"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_ID_DET="PH8"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/Cubieboard2_defconfig
++++ b/configs/Cubieboard2_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-cu
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/Cubieboard4_defconfig
++++ b/configs/Cubieboard4_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun9i-a80-cu
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN9I=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MMC0_CD_PIN="PH18"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="AXP0-VBUS-ENABLE"
+ CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT"
+--- a/configs/Cubieboard_defconfig
++++ b/configs/Cubieboard_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun4i-a10-cu
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN4I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/Itead_Ibox_A20_defconfig
++++ b/configs/Itead_Ibox_A20_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-it
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/Lamobo_R1_defconfig
++++ b/configs/Lamobo_R1_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+ CONFIG_MACPWR="PH23"
+-CONFIG_MMC0_CD_PIN="PH10"
+ CONFIG_SATAPWR="PB3"
+ CONFIG_GMAC_TX_DELAY=4
+ CONFIG_AHCI=y
+--- a/configs/Mele_M3_defconfig
++++ b/configs/Mele_M3_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-m3
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_VIDEO_VGA=y
+ CONFIG_VIDEO_COMPOSITE=y
+--- a/configs/Mele_M5_defconfig
++++ b/configs/Mele_M5_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+ CONFIG_DRAM_ZQ=122
+-CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_VIDEO_COMPOSITE=y
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/Merrii_A80_Optimus_defconfig
++++ b/configs/Merrii_A80_Optimus_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun9i-a80-op
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN9I=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MMC0_CD_PIN="PH18"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="AXP0-VBUS-ENABLE"
+ CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT"
+--- a/configs/Orangepi_mini_defconfig
++++ b/configs/Orangepi_mini_defconfig
+@@ -5,8 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+ CONFIG_MACPWR="PH23"
+-CONFIG_MMC0_CD_PIN="PH10"
+-CONFIG_MMC3_CD_PIN="PH11"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_USB1_VBUS_PIN="PH26"
+ CONFIG_USB2_VBUS_PIN="PH22"
+--- a/configs/Sinlinx_SinA31s_defconfig
++++ b/configs/Sinlinx_SinA31s_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN6I=y
+ CONFIG_DRAM_CLK=432
+ CONFIG_DRAM_ZQ=251
+-CONFIG_MMC0_CD_PIN="PA4"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_USB1_VBUS_PIN=""
+ CONFIG_USB2_VBUS_PIN=""
+--- a/configs/Sinlinx_SinA33_defconfig
++++ b/configs/Sinlinx_SinA33_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_A33=y
+ CONFIG_DRAM_CLK=552
+ CONFIG_DRAM_ZQ=15291
+-CONFIG_MMC0_CD_PIN="PB4"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_ID_DET="PH8"
+ CONFIG_VIDEO_LCD_MODE="x:1024,y:600,depth:18,pclk_khz:66000,le:90,ri:160,up:3,lo:127,hs:70,vs:20,sync:3,vmode:0"
+--- a/configs/Sunchip_CX-A99_defconfig
++++ b/configs/Sunchip_CX-A99_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN9I=y
+ CONFIG_DRAM_CLK=600
+ CONFIG_DRAM_ZQ=3881915
+ CONFIG_DRAM_ODT_EN=y
+-CONFIG_MMC0_CD_PIN="PH17"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PH15"
+ CONFIG_USB1_VBUS_PIN="PL7"
+--- a/configs/UTOO_P66_defconfig
++++ b/configs/UTOO_P66_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN5I=y
+ CONFIG_DRAM_CLK=432
+ CONFIG_DRAM_EMR1=0
+-CONFIG_MMC0_CD_PIN="PG0"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PB04"
+ CONFIG_USB0_VBUS_DET="PG01"
+--- a/configs/Yones_Toptech_BD1078_defconfig
++++ b/configs/Yones_Toptech_BD1078_defconfig
+@@ -4,8 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-yo
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=408
+-CONFIG_MMC0_CD_PIN="PH1"
+-CONFIG_MMC1_CD_PIN="PH2"
+ CONFIG_MMC1_PINS_PH=y
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=1
+ CONFIG_USB0_VBUS_PIN="PB9"
+--- a/configs/bananapi_m2_zero_defconfig
++++ b/configs/bananapi_m2_zero_defconfig
+@@ -4,5 +4,4 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h2-plu
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=408
+-CONFIG_MMC0_CD_PIN=""
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/bananapi_m64_defconfig
++++ b/configs/bananapi_m64_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-b
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I=y
+ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+-CONFIG_MMC0_CD_PIN="PH13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUPPORT_EMMC_BOOT=y
+--- a/configs/beelink_gs1_defconfig
++++ b/configs/beelink_gs1_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-be
+ 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_PSCI_RESET is not set
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/nanopi_m1_plus_defconfig
++++ b/configs/nanopi_m1_plus_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=408
+ CONFIG_MACPWR="PD6"
+-CONFIG_MMC0_CD_PIN="PH13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+--- a/configs/oceanic_5205_5inmfd_defconfig
++++ b/configs/oceanic_5205_5inmfd_defconfig
+@@ -7,7 +7,6 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+ CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
+ CONFIG_DRAM_CLK=552
+ CONFIG_DRAM_ZQ=3881949
+-CONFIG_MMC0_CD_PIN=""
+ CONFIG_SPL_SPI_SUNXI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+--- a/configs/orangepi_3_defconfig
++++ b/configs/orangepi_3_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-or
+ 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_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/orangepi_lite2_defconfig
++++ b/configs/orangepi_lite2_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-or
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H6=y
+ CONFIG_SUNXI_DRAM_H6_LPDDR3=y
+-CONFIG_MMC0_CD_PIN="PF6"
+ # CONFIG_PSCI_RESET is not set
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_USB_EHCI_HCD=y
+--- a/configs/orangepi_one_plus_defconfig
++++ b/configs/orangepi_one_plus_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-or
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H6=y
+ CONFIG_SUNXI_DRAM_H6_LPDDR3=y
+-CONFIG_MMC0_CD_PIN="PF6"
+ # CONFIG_PSCI_RESET is not set
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_USB_EHCI_HCD=y
+--- a/configs/orangepi_zero2_defconfig
++++ b/configs/orangepi_zero2_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_SUN50I_H616_READ_CALIBRATION
+ 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_SPL_SPI_SUNXI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/orangepi_zero_plus2_defconfig
++++ b/configs/orangepi_zero_plus2_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN50I_H5=y
+ CONFIG_DRAM_CLK=672
+ CONFIG_DRAM_ZQ=3881977
+ # CONFIG_DRAM_ODT_EN is not set
+-CONFIG_MMC0_CD_PIN="PH13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+--- a/configs/orangepi_zero_plus2_h3_defconfig
++++ b/configs/orangepi_zero_plus2_h3_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=672
+ # CONFIG_DRAM_ODT_EN is not set
+-CONFIG_MMC0_CD_PIN="PH13"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+--- a/configs/parrot_r16_defconfig
++++ b/configs/parrot_r16_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_A33=y
+ CONFIG_DRAM_CLK=600
+ CONFIG_DRAM_ZQ=15291
+-CONFIG_MMC0_CD_PIN="PD14"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_ID_DET="PD10"
+ CONFIG_USB1_VBUS_PIN="PD12"
+--- a/configs/pine64-lts_defconfig
++++ b/configs/pine64-lts_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN50I=y
+ CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
+ CONFIG_DRAM_CLK=552
+ CONFIG_DRAM_ZQ=3881949
+-CONFIG_MMC0_CD_PIN=""
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_SPL_SPI_SUNXI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/pine_h64_defconfig
++++ b/configs/pine_h64_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H6=y
+ CONFIG_SUNXI_DRAM_H6_LPDDR3=y
+ CONFIG_MACPWR="PC16"
+-CONFIG_MMC0_CD_PIN="PF6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB3_VBUS_PIN="PL5"
+ CONFIG_SPL_SPI_SUNXI=y
+--- a/configs/sopine_baseboard_defconfig
++++ b/configs/sopine_baseboard_defconfig
+@@ -7,7 +7,6 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
+ CONFIG_SUNXI_DRAM_LPDDR3_STOCK=y
+ CONFIG_DRAM_CLK=552
+ CONFIG_DRAM_ZQ=3881949
+-CONFIG_MMC0_CD_PIN=""
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_SPL_SPI_SUNXI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/configs/tanix_tx6_defconfig
++++ b/configs/tanix_tx6_defconfig
+@@ -5,6 +5,5 @@ 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_SYS_MALLOC_CLEAR_ON_INIT is not set
--- /dev/null
+From 4c0c00e7131baf410702555342337c178dd0de98 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 30 Oct 2022 16:04:47 -0500
+Subject: [PATCH 19/90] sunxi: mmc: Move header to the driver directory
+
+The MMC controller driver is (and ought to be) the only user of these
+register definitions. Put them in a header next to the driver to remove
+the dependency on a specific ARM platform's headers.
+
+Due to the sunxi_mmc_init() prototype, the file was not renamed. None of
+the register definitions were changed.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/include/asm/arch-sunxi/mmc.h | 139 +-------------------------
+ drivers/mmc/sunxi_mmc.c | 4 +
+ drivers/mmc/sunxi_mmc.h | 138 +++++++++++++++++++++++++
+ 3 files changed, 146 insertions(+), 135 deletions(-)
+ create mode 100644 drivers/mmc/sunxi_mmc.h
+
+--- a/arch/arm/include/asm/arch-sunxi/mmc.h
++++ b/arch/arm/include/asm/arch-sunxi/mmc.h
+@@ -1,139 +1,8 @@
+ /* SPDX-License-Identifier: GPL-2.0+ */
+-/*
+- * (C) Copyright 2007-2011
+- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+- * Aaron <leafy.myeh@allwinnertech.com>
+- *
+- * MMC register definition for allwinner sunxi platform.
+- */
+
+-#ifndef _SUNXI_MMC_H
+-#define _SUNXI_MMC_H
+-
+-#include <linux/types.h>
+-
+-struct sunxi_mmc {
+- u32 gctrl; /* 0x00 global control */
+- u32 clkcr; /* 0x04 clock control */
+- u32 timeout; /* 0x08 time out */
+- u32 width; /* 0x0c bus width */
+- u32 blksz; /* 0x10 block size */
+- u32 bytecnt; /* 0x14 byte count */
+- u32 cmd; /* 0x18 command */
+- u32 arg; /* 0x1c argument */
+- u32 resp0; /* 0x20 response 0 */
+- u32 resp1; /* 0x24 response 1 */
+- u32 resp2; /* 0x28 response 2 */
+- u32 resp3; /* 0x2c response 3 */
+- u32 imask; /* 0x30 interrupt mask */
+- u32 mint; /* 0x34 masked interrupt status */
+- u32 rint; /* 0x38 raw interrupt status */
+- u32 status; /* 0x3c status */
+- u32 ftrglevel; /* 0x40 FIFO threshold watermark*/
+- u32 funcsel; /* 0x44 function select */
+- u32 cbcr; /* 0x48 CIU byte count */
+- u32 bbcr; /* 0x4c BIU byte count */
+- u32 dbgc; /* 0x50 debug enable */
+- u32 res0; /* 0x54 reserved */
+- u32 a12a; /* 0x58 Auto command 12 argument */
+- u32 ntsr; /* 0x5c New timing set register */
+- u32 res1[8];
+- u32 dmac; /* 0x80 internal DMA control */
+- u32 dlba; /* 0x84 internal DMA descr list base address */
+- u32 idst; /* 0x88 internal DMA status */
+- u32 idie; /* 0x8c internal DMA interrupt enable */
+- u32 chda; /* 0x90 */
+- u32 cbda; /* 0x94 */
+- u32 res2[26];
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
+- u32 res3[17];
+- u32 samp_dl;
+- u32 res4[46];
+-#endif
+- u32 fifo; /* 0x100 / 0x200 FIFO access address */
+-};
+-
+-#define SUNXI_MMC_CLK_POWERSAVE (0x1 << 17)
+-#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
+-#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
+-
+-#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
+-#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
+-#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
+-#define SUNXI_MMC_GCTRL_RESET (SUNXI_MMC_GCTRL_SOFT_RESET|\
+- SUNXI_MMC_GCTRL_FIFO_RESET|\
+- SUNXI_MMC_GCTRL_DMA_RESET)
+-#define SUNXI_MMC_GCTRL_DMA_ENABLE (0x1 << 5)
+-#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB (0x1 << 31)
+-
+-#define SUNXI_MMC_CMD_RESP_EXPIRE (0x1 << 6)
+-#define SUNXI_MMC_CMD_LONG_RESPONSE (0x1 << 7)
+-#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC (0x1 << 8)
+-#define SUNXI_MMC_CMD_DATA_EXPIRE (0x1 << 9)
+-#define SUNXI_MMC_CMD_WRITE (0x1 << 10)
+-#define SUNXI_MMC_CMD_AUTO_STOP (0x1 << 12)
+-#define SUNXI_MMC_CMD_WAIT_PRE_OVER (0x1 << 13)
+-#define SUNXI_MMC_CMD_SEND_INIT_SEQ (0x1 << 15)
+-#define SUNXI_MMC_CMD_UPCLK_ONLY (0x1 << 21)
+-#define SUNXI_MMC_CMD_START (0x1 << 31)
+-
+-#define SUNXI_MMC_RINT_RESP_ERROR (0x1 << 1)
+-#define SUNXI_MMC_RINT_COMMAND_DONE (0x1 << 2)
+-#define SUNXI_MMC_RINT_DATA_OVER (0x1 << 3)
+-#define SUNXI_MMC_RINT_TX_DATA_REQUEST (0x1 << 4)
+-#define SUNXI_MMC_RINT_RX_DATA_REQUEST (0x1 << 5)
+-#define SUNXI_MMC_RINT_RESP_CRC_ERROR (0x1 << 6)
+-#define SUNXI_MMC_RINT_DATA_CRC_ERROR (0x1 << 7)
+-#define SUNXI_MMC_RINT_RESP_TIMEOUT (0x1 << 8)
+-#define SUNXI_MMC_RINT_DATA_TIMEOUT (0x1 << 9)
+-#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10)
+-#define SUNXI_MMC_RINT_FIFO_RUN_ERROR (0x1 << 11)
+-#define SUNXI_MMC_RINT_HARD_WARE_LOCKED (0x1 << 12)
+-#define SUNXI_MMC_RINT_START_BIT_ERROR (0x1 << 13)
+-#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE (0x1 << 14)
+-#define SUNXI_MMC_RINT_END_BIT_ERROR (0x1 << 15)
+-#define SUNXI_MMC_RINT_SDIO_INTERRUPT (0x1 << 16)
+-#define SUNXI_MMC_RINT_CARD_INSERT (0x1 << 30)
+-#define SUNXI_MMC_RINT_CARD_REMOVE (0x1 << 31)
+-#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT \
+- (SUNXI_MMC_RINT_RESP_ERROR | \
+- SUNXI_MMC_RINT_RESP_CRC_ERROR | \
+- SUNXI_MMC_RINT_DATA_CRC_ERROR | \
+- SUNXI_MMC_RINT_RESP_TIMEOUT | \
+- SUNXI_MMC_RINT_DATA_TIMEOUT | \
+- SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE | \
+- SUNXI_MMC_RINT_FIFO_RUN_ERROR | \
+- SUNXI_MMC_RINT_HARD_WARE_LOCKED | \
+- SUNXI_MMC_RINT_START_BIT_ERROR | \
+- SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */
+-#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT \
+- (SUNXI_MMC_RINT_AUTO_COMMAND_DONE | \
+- SUNXI_MMC_RINT_DATA_OVER | \
+- SUNXI_MMC_RINT_COMMAND_DONE | \
+- SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
+-
+-#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0)
+-#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1)
+-#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2)
+-#define SUNXI_MMC_STATUS_FIFO_FULL (0x1 << 3)
+-#define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8)
+-#define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9)
+-#define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10)
+-#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg) (((reg) >> 17) & 0x3fff)
+-
+-#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
+-
+-#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
+-#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
+-#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
+-
+-#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0)
+-#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1)
+-
+-#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
+-#define SUNXI_MMC_COMMON_RESET (1 << 18)
+-
+-#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
++#ifndef _ASM_ARCH_MMC_H_
++#define _ASM_ARCH_MMC_H_
+
+ struct mmc *sunxi_mmc_init(int sdc_no);
+-#endif /* _SUNXI_MMC_H */
++
++#endif /* _ASM_ARCH_MMC_H_ */
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -25,9 +25,13 @@
+ #include <asm/io.h>
+ #include <asm/arch/clock.h>
+ #include <asm/arch/cpu.h>
++#if !CONFIG_IS_ENABLED(DM_MMC)
+ #include <asm/arch/mmc.h>
++#endif
+ #include <linux/delay.h>
+
++#include "sunxi_mmc.h"
++
+ #ifndef CCM_MMC_CTRL_MODE_SEL_NEW
+ #define CCM_MMC_CTRL_MODE_SEL_NEW 0
+ #endif
+--- /dev/null
++++ b/drivers/mmc/sunxi_mmc.h
+@@ -0,0 +1,138 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2007-2011
++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
++ * Aaron <leafy.myeh@allwinnertech.com>
++ *
++ * MMC register definition for allwinner sunxi platform.
++ */
++
++#ifndef _SUNXI_MMC_H
++#define _SUNXI_MMC_H
++
++#include <linux/types.h>
++
++struct sunxi_mmc {
++ u32 gctrl; /* 0x00 global control */
++ u32 clkcr; /* 0x04 clock control */
++ u32 timeout; /* 0x08 time out */
++ u32 width; /* 0x0c bus width */
++ u32 blksz; /* 0x10 block size */
++ u32 bytecnt; /* 0x14 byte count */
++ u32 cmd; /* 0x18 command */
++ u32 arg; /* 0x1c argument */
++ u32 resp0; /* 0x20 response 0 */
++ u32 resp1; /* 0x24 response 1 */
++ u32 resp2; /* 0x28 response 2 */
++ u32 resp3; /* 0x2c response 3 */
++ u32 imask; /* 0x30 interrupt mask */
++ u32 mint; /* 0x34 masked interrupt status */
++ u32 rint; /* 0x38 raw interrupt status */
++ u32 status; /* 0x3c status */
++ u32 ftrglevel; /* 0x40 FIFO threshold watermark*/
++ u32 funcsel; /* 0x44 function select */
++ u32 cbcr; /* 0x48 CIU byte count */
++ u32 bbcr; /* 0x4c BIU byte count */
++ u32 dbgc; /* 0x50 debug enable */
++ u32 res0; /* 0x54 reserved */
++ u32 a12a; /* 0x58 Auto command 12 argument */
++ u32 ntsr; /* 0x5c New timing set register */
++ u32 res1[8];
++ u32 dmac; /* 0x80 internal DMA control */
++ u32 dlba; /* 0x84 internal DMA descr list base address */
++ u32 idst; /* 0x88 internal DMA status */
++ u32 idie; /* 0x8c internal DMA interrupt enable */
++ u32 chda; /* 0x90 */
++ u32 cbda; /* 0x94 */
++ u32 res2[26];
++#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++ u32 res3[17];
++ u32 samp_dl;
++ u32 res4[46];
++#endif
++ u32 fifo; /* 0x100 / 0x200 FIFO access address */
++};
++
++#define SUNXI_MMC_CLK_POWERSAVE (0x1 << 17)
++#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
++#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
++
++#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
++#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
++#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
++#define SUNXI_MMC_GCTRL_RESET (SUNXI_MMC_GCTRL_SOFT_RESET|\
++ SUNXI_MMC_GCTRL_FIFO_RESET|\
++ SUNXI_MMC_GCTRL_DMA_RESET)
++#define SUNXI_MMC_GCTRL_DMA_ENABLE (0x1 << 5)
++#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB (0x1 << 31)
++
++#define SUNXI_MMC_CMD_RESP_EXPIRE (0x1 << 6)
++#define SUNXI_MMC_CMD_LONG_RESPONSE (0x1 << 7)
++#define SUNXI_MMC_CMD_CHK_RESPONSE_CRC (0x1 << 8)
++#define SUNXI_MMC_CMD_DATA_EXPIRE (0x1 << 9)
++#define SUNXI_MMC_CMD_WRITE (0x1 << 10)
++#define SUNXI_MMC_CMD_AUTO_STOP (0x1 << 12)
++#define SUNXI_MMC_CMD_WAIT_PRE_OVER (0x1 << 13)
++#define SUNXI_MMC_CMD_SEND_INIT_SEQ (0x1 << 15)
++#define SUNXI_MMC_CMD_UPCLK_ONLY (0x1 << 21)
++#define SUNXI_MMC_CMD_START (0x1 << 31)
++
++#define SUNXI_MMC_RINT_RESP_ERROR (0x1 << 1)
++#define SUNXI_MMC_RINT_COMMAND_DONE (0x1 << 2)
++#define SUNXI_MMC_RINT_DATA_OVER (0x1 << 3)
++#define SUNXI_MMC_RINT_TX_DATA_REQUEST (0x1 << 4)
++#define SUNXI_MMC_RINT_RX_DATA_REQUEST (0x1 << 5)
++#define SUNXI_MMC_RINT_RESP_CRC_ERROR (0x1 << 6)
++#define SUNXI_MMC_RINT_DATA_CRC_ERROR (0x1 << 7)
++#define SUNXI_MMC_RINT_RESP_TIMEOUT (0x1 << 8)
++#define SUNXI_MMC_RINT_DATA_TIMEOUT (0x1 << 9)
++#define SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10)
++#define SUNXI_MMC_RINT_FIFO_RUN_ERROR (0x1 << 11)
++#define SUNXI_MMC_RINT_HARD_WARE_LOCKED (0x1 << 12)
++#define SUNXI_MMC_RINT_START_BIT_ERROR (0x1 << 13)
++#define SUNXI_MMC_RINT_AUTO_COMMAND_DONE (0x1 << 14)
++#define SUNXI_MMC_RINT_END_BIT_ERROR (0x1 << 15)
++#define SUNXI_MMC_RINT_SDIO_INTERRUPT (0x1 << 16)
++#define SUNXI_MMC_RINT_CARD_INSERT (0x1 << 30)
++#define SUNXI_MMC_RINT_CARD_REMOVE (0x1 << 31)
++#define SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT \
++ (SUNXI_MMC_RINT_RESP_ERROR | \
++ SUNXI_MMC_RINT_RESP_CRC_ERROR | \
++ SUNXI_MMC_RINT_DATA_CRC_ERROR | \
++ SUNXI_MMC_RINT_RESP_TIMEOUT | \
++ SUNXI_MMC_RINT_DATA_TIMEOUT | \
++ SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE | \
++ SUNXI_MMC_RINT_FIFO_RUN_ERROR | \
++ SUNXI_MMC_RINT_HARD_WARE_LOCKED | \
++ SUNXI_MMC_RINT_START_BIT_ERROR | \
++ SUNXI_MMC_RINT_END_BIT_ERROR) /* 0xbfc2 */
++#define SUNXI_MMC_RINT_INTERRUPT_DONE_BIT \
++ (SUNXI_MMC_RINT_AUTO_COMMAND_DONE | \
++ SUNXI_MMC_RINT_DATA_OVER | \
++ SUNXI_MMC_RINT_COMMAND_DONE | \
++ SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE)
++
++#define SUNXI_MMC_STATUS_RXWL_FLAG (0x1 << 0)
++#define SUNXI_MMC_STATUS_TXWL_FLAG (0x1 << 1)
++#define SUNXI_MMC_STATUS_FIFO_EMPTY (0x1 << 2)
++#define SUNXI_MMC_STATUS_FIFO_FULL (0x1 << 3)
++#define SUNXI_MMC_STATUS_CARD_PRESENT (0x1 << 8)
++#define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9)
++#define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10)
++#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg) (((reg) >> 17) & 0x3fff)
++
++#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
++
++#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
++#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
++#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
++
++#define SUNXI_MMC_IDIE_TXIRQ (0x1 << 0)
++#define SUNXI_MMC_IDIE_RXIRQ (0x1 << 1)
++
++#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
++#define SUNXI_MMC_COMMON_RESET (1 << 18)
++
++#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
++
++#endif /* _SUNXI_MMC_H */
--- /dev/null
+From fdf871a6089ee2f56439880b69d33a7d0d707d15 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 28 Aug 2021 22:24:28 -0500
+Subject: [PATCH 20/90] pinctrl: sunxi: Add support for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/Kconfig | 5 +++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 31 +++++++++++++++++++++++++++
+ 2 files changed, 36 insertions(+)
+
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -89,6 +89,11 @@ config PINCTRL_SUN9I_A80_R
+ default MACH_SUN9I
+ select PINCTRL_SUNXI
+
++config PINCTRL_SUN20I_D1
++ bool "Support for the Allwinner D1 PIO"
++ default TARGET_SUN20I_D1
++ select PINCTRL_SUNXI
++
+ config PINCTRL_SUN50I_A64
+ bool "Support for the Allwinner A64 PIO"
+ default MACH_SUN50I
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -588,6 +588,31 @@ static const struct sunxi_pinctrl_desc _
+ .num_banks = 3,
+ };
+
++static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
++ { "emac", 8 }, /* PE0-PE15 */
++ { "gpio_in", 0 },
++ { "gpio_out", 1 },
++ { "i2c0", 4 }, /* PB10-PB11 */
++ { "mmc0", 2 }, /* PF0-PF5 */
++ { "mmc1", 2 }, /* PG0-PG5 */
++ { "mmc2", 3 }, /* PC2-PC7 */
++ { "spi0", 2 }, /* PC2-PC7 */
++#if IS_ENABLED(CONFIG_UART0_PORT_F)
++ { "uart0", 3 }, /* PF2-PF4 */
++#else
++ { "uart0", 6 }, /* PB8-PB9 */
++#endif
++ { "uart1", 2 }, /* PG6-PG7 */
++ { "uart2", 7 }, /* PB0-PB1 */
++};
++
++static const struct sunxi_pinctrl_desc __maybe_unused sun20i_d1_pinctrl_desc = {
++ .functions = sun20i_d1_pinctrl_functions,
++ .num_functions = ARRAY_SIZE(sun20i_d1_pinctrl_functions),
++ .first_bank = SUNXI_GPIO_A,
++ .num_banks = 7,
++};
++
+ static const struct sunxi_pinctrl_function sun50i_a64_pinctrl_functions[] = {
+ { "emac", 4 }, /* PD8-PD23 */
+ { "gpio_in", 0 },
+@@ -849,6 +874,12 @@ static const struct udevice_id sunxi_pin
+ .data = (ulong)&sun9i_a80_r_pinctrl_desc,
+ },
+ #endif
++#ifdef CONFIG_PINCTRL_SUN20I_D1
++ {
++ .compatible = "allwinner,sun20i-d1-pinctrl",
++ .data = (ulong)&sun20i_d1_pinctrl_desc,
++ },
++#endif
+ #ifdef CONFIG_PINCTRL_SUN50I_A64
+ {
+ .compatible = "allwinner,sun50i-a64-pinctrl",
--- /dev/null
+From 8fde85b609273f8389178d4c0d066390a0e0773d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 30 Oct 2022 14:56:10 -0500
+Subject: [PATCH 21/90] serial: ns16550: Enable clocks during probe
+
+If the UART bus or baud clock has a gate, it must be enabled before the
+UART can be used.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/serial/ns16550.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/serial/ns16550.c
++++ b/drivers/serial/ns16550.c
+@@ -506,6 +506,7 @@ int ns16550_serial_probe(struct udevice
+ struct ns16550_plat *plat = dev_get_plat(dev);
+ struct ns16550 *const com_port = dev_get_priv(dev);
+ struct reset_ctl_bulk reset_bulk;
++ struct clk_bulk clk_bulk;
+ fdt_addr_t addr;
+ int ret;
+
+@@ -524,6 +525,10 @@ int ns16550_serial_probe(struct udevice
+ if (!ret)
+ reset_deassert_bulk(&reset_bulk);
+
++ ret = clk_get_bulk(dev, &clk_bulk);
++ if (!ret)
++ clk_enable_bulk(&clk_bulk);
++
+ com_port->plat = dev_get_plat(dev);
+ ns16550_init(com_port, -1);
+
--- /dev/null
+From 0e4edc3a01f179337bb0bd0d31855dbce338a23e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 30 Oct 2022 14:53:45 -0500
+Subject: [PATCH 22/90] fdt: Fix bounds check in devfdt_get_addr_index
+
+reg must contain enough cells for the entire next address/size pair
+after skipping `index` pairs. The previous code allows an out-of-bounds
+read when na + ns > 1.
+
+Series-to: Simon Glass <sjg@chromium.org>
+
+Fixes: 69b41388ba45 ("dm: core: Add a new api to get indexed device address")
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/core/fdtaddr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/core/fdtaddr.c
++++ b/drivers/core/fdtaddr.c
+@@ -43,7 +43,7 @@ fdt_addr_t devfdt_get_addr_index(const s
+ }
+
+ reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
+- if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) {
++ if (!reg || (len < ((index + 1) * sizeof(fdt32_t) * (na + ns)))) {
+ debug("Req index out of range\n");
+ return FDT_ADDR_T_NONE;
+ }
--- /dev/null
+From 2d85df851c590b454749ac989a778bb226637bfc Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 15:08:39 +0000
+Subject: [PATCH 23/90] Kconfig: Remove an impossible condition
+
+ARCH_SUNXI selects BINMAN, so the condition "!BINMAN && ARCH_SUNXI"
+is impossible to satisfy.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/Kconfig
++++ b/Kconfig
+@@ -459,7 +459,7 @@ config BUILD_TARGET
+ default "u-boot-with-spl.kwb" if ARCH_MVEBU && SPL
+ default "u-boot-elf.srec" if RCAR_GEN3
+ default "u-boot.itb" if !BINMAN && SPL_LOAD_FIT && (ARCH_ROCKCHIP || \
+- ARCH_SUNXI || RISCV || ARCH_ZYNQMP)
++ RISCV || ARCH_ZYNQMP)
+ default "u-boot.kwb" if ARCH_KIRKWOOD
+ default "u-boot-with-spl.bin" if ARCH_AT91 && SPL_NAND_SUPPORT
+ default "u-boot-with-spl.imx" if ARCH_MX6 && SPL
--- /dev/null
+From b7150f7dd885012868c94b29ac4fe6152c065a95 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 10:43:56 -0500
+Subject: [PATCH 24/90] binman: Prevent entries in a section from overlapping
+
+Currently, if the "offset" property is given for an entry, the section's
+running offset is completely ignored. This causes entries to overlap if
+the provided offset is less than the size of the entries earlier in the
+section. Avoid the overlap by only using the provided offset when it is
+greater than the running offset.
+
+The motivation for this change is the rule used by SPL to find U-Boot on
+sunxi boards: U-Boot starts 32 KiB after the start of SPL, unless SPL is
+larger than 32 KiB, in which case U-Boot immediately follows SPL.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ tools/binman/entry.py | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/tools/binman/entry.py
++++ b/tools/binman/entry.py
+@@ -483,7 +483,9 @@ class Entry(object):
+ if self.offset_unset:
+ self.Raise('No offset set with offset-unset: should another '
+ 'entry provide this correct offset?')
+- self.offset = tools.align(offset, self.align)
++ elif self.offset > offset:
++ offset = self.offset
++ self.offset = tools.align(offset, self.align)
+ needed = self.pad_before + self.contents_size + self.pad_after
+ needed = tools.align(needed, self.align_size)
+ size = self.size
--- /dev/null
+From b641ca5f4d272b83ef77ebcf5c75678cf139c69a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 17 Apr 2021 13:33:54 -0500
+Subject: [PATCH 25/90] sunxi: binman: Enable SPL FIT loading for 32-bit SoCs
+
+Now that Crust (SCP firmware) has support for H3, we need a FIT image to
+load it. H3 also needs to load a SoC-specific eGon blob to support CPU 0
+hotplug. Let's first enable FIT support before adding extra firmware.
+
+Update the binman description to work on either 32-bit or 64-bit SoCs:
+ - Make BL31 optional, since it is not used on 32-bit SoCs (though BL32
+ may be used in the future).
+ - Explicitly set the minimum offset of the FIT to 32 KiB, since SPL on
+ some boards is still only 24 KiB large even with FIT support enabled.
+ CONFIG_SPL_PAD_TO cannot be used because it is not defined for H616.
+
+FIT unlocks more features (signatures, multiple DTBs, etc.), so enable
+it by default. A10 (sun4i) only has 24 KiB of SRAM A1, so it needs
+SPL_FIT_IMAGE_TINY. For simplicity, enable that option everywhere.
+
+Cover-letter:
+sunxi: SPL FIT support for 32-bit sunxi SoCs
+This series makes the necessary changes so 32-bit sunxi SoCs can load
+additional device trees or firmware from SPL along with U-Boot proper.
+
+There was no existing binman entry property that put the FIT at the
+right offset. The minimum offset is 32k, but this matches neither the
+SPL size (which is no more than 24k on some SoCs) nor the FIT alignment
+(which is 512 bytes in practice due to SPL size constraints). So instead
+of adding a new property, I fixed what is arguably a bug in the offset
+property -- though this strategy will not work if someone is
+intentionally creating overlapping entries.
+END
+Series-to: sunxi
+Series-to: sjg
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/Kconfig | 1 +
+ arch/arm/dts/sunxi-u-boot.dtsi | 46 ++++++++++++++++++++++------------
+ common/spl/Kconfig | 9 +++----
+ 3 files changed, 35 insertions(+), 21 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1135,6 +1135,7 @@ config ARCH_SUNXI
+ imply SPL_GPIO
+ imply SPL_LIBCOMMON_SUPPORT
+ imply SPL_LIBGENERIC_SUPPORT
++ imply SPL_LOAD_FIT
+ imply SPL_MMC if MMC
+ imply SPL_POWER
+ imply SPL_SERIAL
+--- a/arch/arm/dts/sunxi-u-boot.dtsi
++++ b/arch/arm/dts/sunxi-u-boot.dtsi
+@@ -1,13 +1,19 @@
+ #include <config.h>
+
+-#ifdef CONFIG_MACH_SUN50I_H6
+-#define BL31_ADDR 0x104000
+-#define SCP_ADDR 0x114000
+-#elif defined(CONFIG_MACH_SUN50I_H616)
+-#define BL31_ADDR 0x40000000
++#ifdef CONFIG_ARM64
++#define ARCH "arm64"
+ #else
+-#define BL31_ADDR 0x44000
+-#define SCP_ADDR 0x50000
++#define ARCH "arm"
++#endif
++
++#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
++#define BL31_ADDR 0x00044000
++#define SCP_ADDR 0x00050000
++#elif defined(CONFIG_MACH_SUN50I_H6)
++#define BL31_ADDR 0x00104000
++#define SCP_ADDR 0x00114000
++#elif defined(CONFIG_MACH_SUN50I_H616)
++#define BL31_ADDR 0x40000000
+ #endif
+
+ / {
+@@ -34,30 +40,33 @@
+ filename = "spl/sunxi-spl.bin";
+ };
+
+-#ifdef CONFIG_ARM64
++#ifdef CONFIG_SPL_LOAD_FIT
+ fit {
+- description = "Configuration to load ATF before U-Boot";
++ description = "Configuration to load U-Boot and firmware";
++ offset = <32768>;
+ #address-cells = <1>;
+ fit,fdt-list = "of-list";
+
+ images {
+ uboot {
+- description = "U-Boot (64-bit)";
++ description = "U-Boot";
+ type = "standalone";
+ os = "u-boot";
+- arch = "arm64";
++ arch = ARCH;
+ compression = "none";
+ load = <CONFIG_TEXT_BASE>;
++ entry = <CONFIG_TEXT_BASE>;
+
+ u-boot-nodtb {
+ };
+ };
+
++#ifdef BL31_ADDR
+ atf {
+ description = "ARM Trusted Firmware";
+ type = "firmware";
+ os = "arm-trusted-firmware";
+- arch = "arm64";
++ arch = ARCH;
+ compression = "none";
+ load = <BL31_ADDR>;
+ entry = <BL31_ADDR>;
+@@ -67,6 +76,7 @@
+ missing-msg = "atf-bl31-sunxi";
+ };
+ };
++#endif
+
+ #ifdef SCP_ADDR
+ scp {
+@@ -95,19 +105,23 @@
+
+ @config-SEQ {
+ description = "NAME";
++#ifdef BL31_ADDR
+ firmware = "atf";
+-#ifndef SCP_ADDR
+- loadables = "uboot";
+ #else
+- loadables = "scp", "uboot";
++ firmware = "uboot";
++#endif
++ loadables =
++#ifdef SCP_ADDR
++ "scp",
+ #endif
++ "uboot";
+ fdt = "fdt-SEQ";
+ };
+ };
+ };
+ #else
+ u-boot-img {
+- offset = <CONFIG_SPL_PAD_TO>;
++ offset = <32768>;
+ };
+ #endif
+ };
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -76,12 +76,12 @@ config SPL_SIZE_LIMIT_PROVIDE_STACK
+
+ config SPL_MAX_SIZE
+ hex "Maximum size of the SPL image, excluding BSS"
++ default 0x37fa0 if MACH_SUN50I_H616
+ default 0x30000 if ARCH_MX6 && MX6_OCRAM_256KB
++ default 0x25fa0 if MACH_SUN50I_H6
+ default 0x1b000 if AM33XX && !TI_SECURE_DEVICE
+ default 0x10000 if ARCH_MX6 && !MX6_OCRAM_256KB
+ default 0x7fa0 if SUNXI_SRAM_ADDRESS = 0x10000
+- default 0x7fa0 if SUNXI_SRAM_ADDRESS = 0x20000 && !MACH_SUN50I_H616
+- default 0xbfa0 if MACH_SUN50I_H616
+ default 0x7000 if RCAR_GEN3
+ default 0x5fa0 if SUNXI_SRAM_ADDRESS = 0x0
+ default 0x10000 if ASPEED_AST2600
+@@ -97,7 +97,7 @@ config SPL_PAD_TO
+ default 0x31000 if ARCH_MX6 && MX6_OCRAM_256KB
+ default 0x11000 if ARCH_MX7 || (ARCH_MX6 && !MX6_OCRAM_256KB)
+ default 0x10000 if ARCH_KEYSTONE
+- default 0x8000 if ARCH_SUNXI && !MACH_SUN50I_H616
++ default 0x0 if ARCH_SUNXI
+ default 0x0 if ARCH_MTMIPS
+ default TPL_MAX_SIZE if TPL_MAX_SIZE > SPL_MAX_SIZE
+ default SPL_MAX_SIZE
+@@ -575,8 +575,7 @@ config SPL_MD5
+ 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 || SUN50I_GEN_H6
+- default y if ARCH_IMX8M || ARCH_IMX9
++ default y if ARCH_IMX8M || ARCH_IMX9 || ARCH_SUNXI
+ help
+ Enable this to reduce the size of the FIT image loading code
+ in SPL, if space for the SPL binary is very tight.
--- /dev/null
+From ca1e6f4491981432c3e88441131c8e25067da95e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 22:00:22 -0500
+Subject: [PATCH 26/90] sunxi: psci: Avoid hanging when CPU 0 is hot-unplugged
+
+Do not try to send an SGI from CPU 0 to itself. Since FIQs are masked
+when entering monitor mode, this will hang. Plus, CPU 0 cannot fully
+power itself off anyway. Instead, have it turn FIQs back on and continue
+servicing SGIs from other cores.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/cpu/armv7/sunxi/psci.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -38,6 +38,15 @@
+ #define SUN8I_R40_PWR_CLAMP(cpu) (0x120 + (cpu) * 0x4)
+ #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
+
++static inline u32 __secure cp15_read_mpidr(void)
++{
++ u32 val;
++
++ asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (val));
++
++ return val;
++}
++
+ static void __secure cp15_write_cntp_tval(u32 tval)
+ {
+ asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
+@@ -281,9 +290,14 @@ s32 __secure psci_cpu_off(void)
+ {
+ psci_cpu_off_common();
+
+- /* Ask CPU0 via SGI15 to pull the rug... */
+- writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
+- dsb();
++ if (cp15_read_mpidr() & 3) {
++ /* Ask CPU0 via SGI15 to pull the rug... */
++ writel(BIT(16) | 15, GICD_BASE + GICD_SGIR);
++ dsb();
++ } else {
++ /* Unmask FIQs to service SGI15. */
++ asm volatile ("cpsie f");
++ }
+
+ /* Wait to be turned off */
+ while (1)
--- /dev/null
+From 2f48dfc23d612f6f1798ff761854fd3141d0671f Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 15 May 2022 21:29:22 -0500
+Subject: [PATCH 27/90] clk: sunxi: Add NAND clocks and resets
+
+Currently NAND clock setup is done in board code, both in SPL and in
+U-Boot proper. Add the NAND clocks/resets here so they can be used by
+the "full" NAND driver once it is converted to the driver model.
+
+The bit locations are copied from the Linux CCU drivers.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/clk/sunxi/clk_a10.c | 2 ++
+ drivers/clk/sunxi/clk_a10s.c | 2 ++
+ drivers/clk/sunxi/clk_a23.c | 3 +++
+ drivers/clk/sunxi/clk_a31.c | 6 ++++++
+ drivers/clk/sunxi/clk_a64.c | 3 +++
+ drivers/clk/sunxi/clk_a80.c | 8 ++++++++
+ drivers/clk/sunxi/clk_a83t.c | 3 +++
+ drivers/clk/sunxi/clk_h3.c | 3 +++
+ drivers/clk/sunxi/clk_h6.c | 6 ++++++
+ drivers/clk/sunxi/clk_h616.c | 6 ++++++
+ drivers/clk/sunxi/clk_r40.c | 3 +++
+ 11 files changed, 45 insertions(+)
+
+--- a/drivers/clk/sunxi/clk_a10.c
++++ b/drivers/clk/sunxi/clk_a10.c
+@@ -23,6 +23,7 @@ static struct ccu_clk_gate a10_gates[] =
+ [CLK_AHB_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_AHB_MMC2] = GATE(0x060, BIT(10)),
+ [CLK_AHB_MMC3] = GATE(0x060, BIT(11)),
++ [CLK_AHB_NAND] = GATE(0x060, BIT(13)),
+ [CLK_AHB_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_AHB_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_AHB_SPI1] = GATE(0x060, BIT(21)),
+@@ -47,6 +48,7 @@ static struct ccu_clk_gate a10_gates[] =
+ [CLK_APB1_UART6] = GATE(0x06c, BIT(22)),
+ [CLK_APB1_UART7] = GATE(0x06c, BIT(23)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+ [CLK_SPI2] = GATE(0x0a8, BIT(31)),
+--- a/drivers/clk/sunxi/clk_a10s.c
++++ b/drivers/clk/sunxi/clk_a10s.c
+@@ -20,6 +20,7 @@ static struct ccu_clk_gate a10s_gates[]
+ [CLK_AHB_MMC0] = GATE(0x060, BIT(8)),
+ [CLK_AHB_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_AHB_MMC2] = GATE(0x060, BIT(10)),
++ [CLK_AHB_NAND] = GATE(0x060, BIT(13)),
+ [CLK_AHB_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_AHB_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_AHB_SPI1] = GATE(0x060, BIT(21)),
+@@ -35,6 +36,7 @@ static struct ccu_clk_gate a10s_gates[]
+ [CLK_APB1_UART2] = GATE(0x06c, BIT(18)),
+ [CLK_APB1_UART3] = GATE(0x06c, BIT(19)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+ [CLK_SPI2] = GATE(0x0a8, BIT(31)),
+--- a/drivers/clk/sunxi/clk_a23.c
++++ b/drivers/clk/sunxi/clk_a23.c
+@@ -17,6 +17,7 @@ static struct ccu_clk_gate a23_gates[] =
+ [CLK_BUS_MMC0] = GATE(0x060, BIT(8)),
+ [CLK_BUS_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_BUS_MMC2] = GATE(0x060, BIT(10)),
++ [CLK_BUS_NAND] = GATE(0x060, BIT(13)),
+ [CLK_BUS_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x060, BIT(21)),
+ [CLK_BUS_OTG] = GATE(0x060, BIT(24)),
+@@ -34,6 +35,7 @@ static struct ccu_clk_gate a23_gates[] =
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+
+@@ -52,6 +54,7 @@ static struct ccu_reset a23_resets[] = {
+ [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)),
+ [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)),
++ [RST_BUS_NAND] = RESET(0x2c0, BIT(13)),
+ [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)),
+ [RST_BUS_OTG] = RESET(0x2c0, BIT(24)),
+--- a/drivers/clk/sunxi/clk_a31.c
++++ b/drivers/clk/sunxi/clk_a31.c
+@@ -18,6 +18,8 @@ static struct ccu_clk_gate a31_gates[] =
+ [CLK_AHB1_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_AHB1_MMC2] = GATE(0x060, BIT(10)),
+ [CLK_AHB1_MMC3] = GATE(0x060, BIT(11)),
++ [CLK_AHB1_NAND1] = GATE(0x060, BIT(12)),
++ [CLK_AHB1_NAND0] = GATE(0x060, BIT(13)),
+ [CLK_AHB1_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_AHB1_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_AHB1_SPI1] = GATE(0x060, BIT(21)),
+@@ -43,6 +45,8 @@ static struct ccu_clk_gate a31_gates[] =
+ [CLK_APB2_UART4] = GATE(0x06c, BIT(20)),
+ [CLK_APB2_UART5] = GATE(0x06c, BIT(21)),
+
++ [CLK_NAND0] = GATE(0x080, BIT(31)),
++ [CLK_NAND1] = GATE(0x084, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+ [CLK_SPI2] = GATE(0x0a8, BIT(31)),
+@@ -65,6 +69,8 @@ static struct ccu_reset a31_resets[] = {
+ [RST_AHB1_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_AHB1_MMC2] = RESET(0x2c0, BIT(10)),
+ [RST_AHB1_MMC3] = RESET(0x2c0, BIT(11)),
++ [RST_AHB1_NAND1] = RESET(0x2c0, BIT(12)),
++ [RST_AHB1_NAND0] = RESET(0x2c0, BIT(13)),
+ [RST_AHB1_EMAC] = RESET(0x2c0, BIT(17)),
+ [RST_AHB1_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_AHB1_SPI1] = RESET(0x2c0, BIT(21)),
+--- a/drivers/clk/sunxi/clk_a64.c
++++ b/drivers/clk/sunxi/clk_a64.c
+@@ -19,6 +19,7 @@ static const struct ccu_clk_gate a64_gat
+ [CLK_BUS_MMC0] = GATE(0x060, BIT(8)),
+ [CLK_BUS_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_BUS_MMC2] = GATE(0x060, BIT(10)),
++ [CLK_BUS_NAND] = GATE(0x060, BIT(13)),
+ [CLK_BUS_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_BUS_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x060, BIT(21)),
+@@ -39,6 +40,7 @@ static const struct ccu_clk_gate a64_gat
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+
+@@ -58,6 +60,7 @@ static const struct ccu_reset a64_resets
+ [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)),
+ [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)),
++ [RST_BUS_NAND] = RESET(0x2c0, BIT(13)),
+ [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)),
+ [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)),
+--- a/drivers/clk/sunxi/clk_a80.c
++++ b/drivers/clk/sunxi/clk_a80.c
+@@ -14,12 +14,18 @@
+ #include <linux/bitops.h>
+
+ static const struct ccu_clk_gate a80_gates[] = {
++ [CLK_NAND0_0] = GATE(0x400, BIT(31)),
++ [CLK_NAND0_1] = GATE(0x404, BIT(31)),
++ [CLK_NAND1_0] = GATE(0x408, BIT(31)),
++ [CLK_NAND1_1] = GATE(0x40c, BIT(31)),
+ [CLK_SPI0] = GATE(0x430, BIT(31)),
+ [CLK_SPI1] = GATE(0x434, BIT(31)),
+ [CLK_SPI2] = GATE(0x438, BIT(31)),
+ [CLK_SPI3] = GATE(0x43c, BIT(31)),
+
+ [CLK_BUS_MMC] = GATE(0x580, BIT(8)),
++ [CLK_BUS_NAND0] = GATE(0x580, BIT(12)),
++ [CLK_BUS_NAND1] = GATE(0x580, BIT(13)),
+ [CLK_BUS_SPI0] = GATE(0x580, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x580, BIT(21)),
+ [CLK_BUS_SPI2] = GATE(0x580, BIT(22)),
+@@ -42,6 +48,8 @@ static const struct ccu_clk_gate a80_gat
+
+ static const struct ccu_reset a80_resets[] = {
+ [RST_BUS_MMC] = RESET(0x5a0, BIT(8)),
++ [RST_BUS_NAND0] = RESET(0x5a0, BIT(12)),
++ [RST_BUS_NAND1] = RESET(0x5a0, BIT(13)),
+ [RST_BUS_SPI0] = RESET(0x5a0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x5a0, BIT(21)),
+ [RST_BUS_SPI2] = RESET(0x5a0, BIT(22)),
+--- a/drivers/clk/sunxi/clk_a83t.c
++++ b/drivers/clk/sunxi/clk_a83t.c
+@@ -17,6 +17,7 @@ static struct ccu_clk_gate a83t_gates[]
+ [CLK_BUS_MMC0] = GATE(0x060, BIT(8)),
+ [CLK_BUS_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_BUS_MMC2] = GATE(0x060, BIT(10)),
++ [CLK_BUS_NAND] = GATE(0x060, BIT(13)),
+ [CLK_BUS_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_BUS_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x060, BIT(21)),
+@@ -36,6 +37,7 @@ static struct ccu_clk_gate a83t_gates[]
+ [CLK_BUS_UART3] = GATE(0x06c, BIT(19)),
+ [CLK_BUS_UART4] = GATE(0x06c, BIT(20)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+
+@@ -54,6 +56,7 @@ static struct ccu_reset a83t_resets[] =
+ [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)),
+ [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)),
++ [RST_BUS_NAND] = RESET(0x2c0, BIT(13)),
+ [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)),
+ [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)),
+--- a/drivers/clk/sunxi/clk_h3.c
++++ b/drivers/clk/sunxi/clk_h3.c
+@@ -19,6 +19,7 @@ static struct ccu_clk_gate h3_gates[] =
+ [CLK_BUS_MMC0] = GATE(0x060, BIT(8)),
+ [CLK_BUS_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_BUS_MMC2] = GATE(0x060, BIT(10)),
++ [CLK_BUS_NAND] = GATE(0x060, BIT(13)),
+ [CLK_BUS_EMAC] = GATE(0x060, BIT(17)),
+ [CLK_BUS_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x060, BIT(21)),
+@@ -44,6 +45,7 @@ static struct ccu_clk_gate h3_gates[] =
+
+ [CLK_BUS_EPHY] = GATE(0x070, BIT(0)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+
+@@ -66,6 +68,7 @@ static struct ccu_reset h3_resets[] = {
+ [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)),
+ [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)),
++ [RST_BUS_NAND] = RESET(0x2c0, BIT(13)),
+ [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)),
+ [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)),
+--- a/drivers/clk/sunxi/clk_h6.c
++++ b/drivers/clk/sunxi/clk_h6.c
+@@ -18,6 +18,10 @@ static struct ccu_clk_gate h6_gates[] =
+
+ [CLK_APB1] = GATE_DUMMY,
+
++ [CLK_NAND0] = GATE(0x810, BIT(31)),
++ [CLK_NAND1] = GATE(0x814, BIT(31)),
++ [CLK_BUS_NAND] = GATE(0x82c, BIT(0)),
++
+ [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
+ [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
+ [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)),
+@@ -58,6 +62,8 @@ static struct ccu_clk_gate h6_gates[] =
+ };
+
+ static struct ccu_reset h6_resets[] = {
++ [RST_BUS_NAND] = RESET(0x82c, BIT(16)),
++
+ [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
+ [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
+ [RST_BUS_MMC2] = RESET(0x84c, BIT(18)),
+--- a/drivers/clk/sunxi/clk_h616.c
++++ b/drivers/clk/sunxi/clk_h616.c
+@@ -17,6 +17,10 @@ static struct ccu_clk_gate h616_gates[]
+
+ [CLK_APB1] = GATE_DUMMY,
+
++ [CLK_NAND0] = GATE(0x810, BIT(31)),
++ [CLK_NAND1] = GATE(0x814, BIT(31)),
++ [CLK_BUS_NAND] = GATE(0x82c, BIT(0)),
++
+ [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)),
+ [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)),
+ [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)),
+@@ -67,6 +71,8 @@ static struct ccu_clk_gate h616_gates[]
+ };
+
+ static struct ccu_reset h616_resets[] = {
++ [RST_BUS_NAND] = RESET(0x82c, BIT(16)),
++
+ [RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
+ [RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
+ [RST_BUS_MMC2] = RESET(0x84c, BIT(18)),
+--- a/drivers/clk/sunxi/clk_r40.c
++++ b/drivers/clk/sunxi/clk_r40.c
+@@ -18,6 +18,7 @@ static struct ccu_clk_gate r40_gates[] =
+ [CLK_BUS_MMC1] = GATE(0x060, BIT(9)),
+ [CLK_BUS_MMC2] = GATE(0x060, BIT(10)),
+ [CLK_BUS_MMC3] = GATE(0x060, BIT(11)),
++ [CLK_BUS_NAND] = GATE(0x060, BIT(13)),
+ [CLK_BUS_SPI0] = GATE(0x060, BIT(20)),
+ [CLK_BUS_SPI1] = GATE(0x060, BIT(21)),
+ [CLK_BUS_SPI2] = GATE(0x060, BIT(22)),
+@@ -48,6 +49,7 @@ static struct ccu_clk_gate r40_gates[] =
+ [CLK_BUS_UART6] = GATE(0x06c, BIT(22)),
+ [CLK_BUS_UART7] = GATE(0x06c, BIT(23)),
+
++ [CLK_NAND] = GATE(0x080, BIT(31)),
+ [CLK_SPI0] = GATE(0x0a0, BIT(31)),
+ [CLK_SPI1] = GATE(0x0a4, BIT(31)),
+ [CLK_SPI2] = GATE(0x0a8, BIT(31)),
+@@ -70,6 +72,7 @@ static struct ccu_reset r40_resets[] = {
+ [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)),
+ [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)),
+ [RST_BUS_MMC3] = RESET(0x2c0, BIT(11)),
++ [RST_BUS_NAND] = RESET(0x2c0, BIT(13)),
+ [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)),
+ [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)),
+ [RST_BUS_SPI2] = RESET(0x2c0, BIT(22)),
--- /dev/null
+From 7be2405244565973cff0a40196bbed08df90f6a3 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 16 May 2022 00:31:36 -0500
+Subject: [PATCH 28/90] pinctrl: sunxi: Add NAND pinmuxes
+
+NAND is always at function 2 on port C.
+
+Pin lists and mux values were taken from the Linux drivers.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -269,6 +269,7 @@ static const struct sunxi_pinctrl_functi
+ #endif
+ { "mmc2", 3 }, /* PC6-PC15 */
+ { "mmc3", 2 }, /* PI4-PI9 */
++ { "nand0", 2 }, /* PC0-PC24 */
+ { "spi0", 3 }, /* PC0-PC2, PC23 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 4 }, /* PF2-PF4 */
+@@ -293,6 +294,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG3-PG8 */
+ { "mmc2", 3 }, /* PC6-PC15 */
++ { "nand0", 2 }, /* PC0-PC19 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 4 }, /* PF2-PF4 */
+@@ -319,6 +321,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC6-PC15, PC24 */
+ { "mmc3", 4 }, /* PC6-PC15, PC24 */
++ { "nand0", 2 }, /* PC0-PC26 */
+ { "spi0", 3 }, /* PC0-PC2, PC27 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -363,6 +366,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc1", 4 }, /* PG0-PG5 */
+ #endif
+ { "mmc2", 3 }, /* PC5-PC15, PC24 */
++ { "nand0", 2 }, /* PC0-PC24 */
+ { "spi0", 3 }, /* PC0-PC2, PC23 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 4 }, /* PF2-PF4 */
+@@ -386,6 +390,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC5-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -424,6 +429,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC5-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -450,6 +456,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC5-PC16 */
++ { "nand0", 2 }, /* PC0-PC18 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -491,6 +498,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC5-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -557,6 +565,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC6-PC16 */
++ { "nand0", 2 }, /* PC0-PC18 */
+ { "spi0", 3 }, /* PC0-PC2, PC19 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 4 }, /* PF2-PF4 */
+@@ -622,6 +631,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC1-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "pwm", 2 }, /* PD22 */
+ { "spi0", 4 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+@@ -664,6 +674,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC1-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 3 }, /* PC0-PC3 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -690,6 +701,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC1-PC14 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 4 }, /* PC0-PC7 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
+@@ -728,6 +740,7 @@ static const struct sunxi_pinctrl_functi
+ { "mmc0", 2 }, /* PF0-PF5 */
+ { "mmc1", 2 }, /* PG0-PG5 */
+ { "mmc2", 3 }, /* PC0-PC16 */
++ { "nand0", 2 }, /* PC0-PC16 */
+ { "spi0", 4 }, /* PC0-PC7, PC15-PC16 */
+ #if IS_ENABLED(CONFIG_UART0_PORT_F)
+ { "uart0", 3 }, /* PF2-PF4 */
--- /dev/null
+From 8e793af8598a8429c9dc0f096c72a92adb360a57 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 15 May 2022 21:51:47 -0500
+Subject: [PATCH 29/90] mtd: nand: sunxi: Remove an unnecessary check
+
+Each chip is required to have a unique CS number ("reg" property) in the
+range 0-7, so there is no need to separately count the number of chips.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mtd/nand/raw/sunxi_nand.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+--- a/drivers/mtd/nand/raw/sunxi_nand.c
++++ b/drivers/mtd/nand/raw/sunxi_nand.c
+@@ -1767,16 +1767,6 @@ static int sunxi_nand_chips_init(int nod
+ int ret, i = 0;
+
+ for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
+- nand_node = fdt_next_subnode(blob, nand_node))
+- i++;
+-
+- if (i > 8) {
+- dev_err(nfc->dev, "too many NAND chips: %d (max = 8)\n", i);
+- return -EINVAL;
+- }
+-
+- i = 0;
+- for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
+ nand_node = fdt_next_subnode(blob, nand_node)) {
+ ret = sunxi_nand_chip_init(nand_node, nfc, i++);
+ if (ret)
--- /dev/null
+From 61b63cbb3526e19a0e299f95a3435a237c7c4b4b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 15 May 2022 21:54:25 -0500
+Subject: [PATCH 30/90] mtd: nand: sunxi: Convert from fdtdec to ofnode
+
+As a first step toward converting this driver to the driver model, use
+the ofnode abstraction to replace direct references to the FDT blob.
+
+Using ofnode_read_u32_index removes an extra pair of loops and makes the
+allwinner,rb property optional, matching the devicetree binding.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mtd/nand/raw/sunxi_nand.c | 73 +++++++++++--------------------
+ include/fdtdec.h | 1 -
+ lib/fdtdec.c | 1 -
+ 3 files changed, 26 insertions(+), 49 deletions(-)
+
+--- a/drivers/mtd/nand/raw/sunxi_nand.c
++++ b/drivers/mtd/nand/raw/sunxi_nand.c
+@@ -25,11 +25,10 @@
+ */
+
+ #include <common.h>
+-#include <fdtdec.h>
++#include <dm.h>
+ #include <malloc.h>
+ #include <memalign.h>
+ #include <nand.h>
+-#include <asm/global_data.h>
+ #include <dm/device_compat.h>
+ #include <dm/devres.h>
+ #include <linux/bitops.h>
+@@ -45,8 +44,6 @@
+ #include <asm/gpio.h>
+ #include <asm/arch/clock.h>
+
+-DECLARE_GLOBAL_DATA_PTR;
+-
+ #define NFC_REG_CTL 0x0000
+ #define NFC_REG_ST 0x0004
+ #define NFC_REG_INT 0x0008
+@@ -1605,19 +1602,18 @@ static int sunxi_nand_ecc_init(struct mt
+ return 0;
+ }
+
+-static int sunxi_nand_chip_init(int node, struct sunxi_nfc *nfc, int devnum)
++static int sunxi_nand_chip_init(ofnode np, struct sunxi_nfc *nfc, int devnum)
+ {
+ const struct nand_sdr_timings *timings;
+- const void *blob = gd->fdt_blob;
+ struct sunxi_nand_chip *chip;
+ struct mtd_info *mtd;
+ struct nand_chip *nand;
+ int nsels;
+ int ret;
+ int i;
+- u32 cs[8], rb[8];
++ u32 tmp;
+
+- if (!fdt_getprop(blob, node, "reg", &nsels))
++ if (!ofnode_get_property(np, "reg", &nsels))
+ return -EINVAL;
+
+ nsels /= sizeof(u32);
+@@ -1638,25 +1634,12 @@ static int sunxi_nand_chip_init(int node
+ chip->selected = -1;
+
+ for (i = 0; i < nsels; i++) {
+- cs[i] = -1;
+- rb[i] = -1;
+- }
+-
+- ret = fdtdec_get_int_array(gd->fdt_blob, node, "reg", cs, nsels);
+- if (ret) {
+- dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
+- return ret;
+- }
+-
+- ret = fdtdec_get_int_array(gd->fdt_blob, node, "allwinner,rb", rb,
+- nsels);
+- if (ret) {
+- dev_err(nfc->dev, "could not retrieve reg property: %d\n", ret);
+- return ret;
+- }
+-
+- for (i = 0; i < nsels; i++) {
+- int tmp = cs[i];
++ ret = ofnode_read_u32_index(np, "reg", i, &tmp);
++ if (ret) {
++ dev_err(nfc->dev, "could not retrieve reg property: %d\n",
++ ret);
++ return ret;
++ }
+
+ if (tmp > NFC_MAX_CS) {
+ dev_err(nfc->dev,
+@@ -1671,15 +1654,14 @@ static int sunxi_nand_chip_init(int node
+
+ chip->sels[i].cs = tmp;
+
+- tmp = rb[i];
+- if (tmp >= 0 && tmp < 2) {
++ if (!ofnode_read_u32_index(np, "allwinner,rb", i, &tmp) &&
++ tmp < 2) {
+ chip->sels[i].rb.type = RB_NATIVE;
+ chip->sels[i].rb.info.nativeid = tmp;
+ } else {
+- ret = gpio_request_by_name_nodev(offset_to_ofnode(node),
+- "rb-gpios", i,
+- &chip->sels[i].rb.info.gpio,
+- GPIOD_IS_IN);
++ ret = gpio_request_by_name_nodev(np, "rb-gpios", i,
++ &chip->sels[i].rb.info.gpio,
++ GPIOD_IS_IN);
+ if (ret)
+ chip->sels[i].rb.type = RB_GPIO;
+ else
+@@ -1711,7 +1693,7 @@ static int sunxi_nand_chip_init(int node
+ * in the DT.
+ */
+ nand->ecc.mode = NAND_ECC_HW;
+- nand->flash_node = offset_to_ofnode(node);
++ nand->flash_node = np;
+ nand->select_chip = sunxi_nfc_select_chip;
+ nand->cmd_ctrl = sunxi_nfc_cmd_ctrl;
+ nand->read_buf = sunxi_nfc_read_buf;
+@@ -1760,15 +1742,13 @@ static int sunxi_nand_chip_init(int node
+ return 0;
+ }
+
+-static int sunxi_nand_chips_init(int node, struct sunxi_nfc *nfc)
++static int sunxi_nand_chips_init(ofnode node, struct sunxi_nfc *nfc)
+ {
+- const void *blob = gd->fdt_blob;
+- int nand_node;
++ ofnode nand_np;
+ int ret, i = 0;
+
+- for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
+- nand_node = fdt_next_subnode(blob, nand_node)) {
+- ret = sunxi_nand_chip_init(nand_node, nfc, i++);
++ ofnode_for_each_subnode(nand_np, node) {
++ ret = sunxi_nand_chip_init(nand_np, nfc, i++);
+ if (ret)
+ return ret;
+ }
+@@ -1794,10 +1774,9 @@ static void sunxi_nand_chips_cleanup(str
+
+ void sunxi_nand_init(void)
+ {
+- const void *blob = gd->fdt_blob;
+ struct sunxi_nfc *nfc;
+- fdt_addr_t regs;
+- int node;
++ phys_addr_t regs;
++ ofnode node;
+ int ret;
+
+ nfc = kzalloc(sizeof(*nfc), GFP_KERNEL);
+@@ -1808,18 +1787,18 @@ void sunxi_nand_init(void)
+ init_waitqueue_head(&nfc->controller.wq);
+ INIT_LIST_HEAD(&nfc->chips);
+
+- node = fdtdec_next_compatible(blob, 0, COMPAT_SUNXI_NAND);
+- if (node < 0) {
++ node = ofnode_by_compatible(ofnode_null(), "allwinner,sun4i-a10-nand");
++ if (!ofnode_valid(node)) {
+ pr_err("unable to find nfc node in device tree\n");
+ goto err;
+ }
+
+- if (!fdtdec_get_is_enabled(blob, node)) {
++ if (!ofnode_is_enabled(node)) {
+ pr_err("nfc disabled in device tree\n");
+ goto err;
+ }
+
+- regs = fdtdec_get_addr(blob, node, "reg");
++ regs = ofnode_get_addr(node);
+ if (regs == FDT_ADDR_T_NONE) {
+ pr_err("unable to find nfc address in device tree\n");
+ goto err;
+--- a/include/fdtdec.h
++++ b/include/fdtdec.h
+@@ -187,7 +187,6 @@ enum fdt_compat_id {
+ COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */
+ COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */
+ COMPAT_INTEL_IVYBRIDGE_FSP, /* Intel Ivy Bridge FSP */
+- COMPAT_SUNXI_NAND, /* SUNXI NAND controller */
+ COMPAT_ALTERA_SOCFPGA_CLK, /* SoCFPGA Clock initialization */
+ COMPAT_ALTERA_SOCFPGA_PINCTRL_SINGLE, /* SoCFPGA pinctrl-single */
+ COMPAT_ALTERA_SOCFPGA_H2F_BRG, /* SoCFPGA hps2fpga bridge */
+--- a/lib/fdtdec.c
++++ b/lib/fdtdec.c
+@@ -64,7 +64,6 @@ static const char * const compat_names[C
+ COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
+ COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
+ COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
+- COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
+ COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"),
+ COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"),
+ COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"),
--- /dev/null
+From 3411a9a1be9a8d8fef236a81edbce2a1a8218a32 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 16 May 2022 00:16:48 -0500
+Subject: [PATCH 31/90] mtd: nand: sunxi: Convert to the driver model
+
+Clocks, resets, and pinmuxes are now handled by the driver model, so the
+only thing the "board" code needs to do is load the driver. This matches
+the pattern used by other DM raw NAND drivers (there is no NAND uclass).
+
+The actual board code is now only needed in SPL.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/board.c | 5 +-
+ drivers/mtd/nand/raw/sunxi_nand.c | 81 ++++++++++++++++++-------------
+ 2 files changed, 49 insertions(+), 37 deletions(-)
+
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -311,7 +311,7 @@ int dram_init(void)
+ return 0;
+ }
+
+-#if defined(CONFIG_NAND_SUNXI)
++#if defined(CONFIG_NAND_SUNXI) && defined(CONFIG_SPL_BUILD)
+ static void nand_pinmux_setup(void)
+ {
+ unsigned int pin;
+@@ -347,9 +347,6 @@ void board_nand_init(void)
+ {
+ nand_pinmux_setup();
+ nand_clock_setup();
+-#ifndef CONFIG_SPL_BUILD
+- sunxi_nand_init();
+-#endif
+ }
+ #endif /* CONFIG_NAND_SUNXI */
+
+--- a/drivers/mtd/nand/raw/sunxi_nand.c
++++ b/drivers/mtd/nand/raw/sunxi_nand.c
+@@ -24,11 +24,13 @@
+ * GNU General Public License for more details.
+ */
+
++#include <clk.h>
+ #include <common.h>
+ #include <dm.h>
+ #include <malloc.h>
+ #include <memalign.h>
+ #include <nand.h>
++#include <reset.h>
+ #include <dm/device_compat.h>
+ #include <dm/devres.h>
+ #include <linux/bitops.h>
+@@ -260,7 +262,7 @@ static inline struct sunxi_nand_chip *to
+ * NAND Controller structure: stores sunxi NAND controller information
+ *
+ * @controller: base controller structure
+- * @dev: parent device (used to print error messages)
++ * @dev: DM device (used to print error messages)
+ * @regs: NAND controller registers
+ * @ahb_clk: NAND Controller AHB clock
+ * @mod_clk: NAND Controller mod clock
+@@ -273,7 +275,7 @@ static inline struct sunxi_nand_chip *to
+ */
+ struct sunxi_nfc {
+ struct nand_hw_control controller;
+- struct device *dev;
++ struct udevice *dev;
+ void __iomem *regs;
+ struct clk *ahb_clk;
+ struct clk *mod_clk;
+@@ -1772,54 +1774,67 @@ static void sunxi_nand_chips_cleanup(str
+ }
+ #endif /* __UBOOT__ */
+
+-void sunxi_nand_init(void)
++static int sunxi_nand_probe(struct udevice *dev)
+ {
+- struct sunxi_nfc *nfc;
+- phys_addr_t regs;
+- ofnode node;
++ struct sunxi_nfc *nfc = dev_get_priv(dev);
++ struct reset_ctl_bulk rst_bulk;
++ struct clk_bulk clk_bulk;
+ int ret;
+
+- nfc = kzalloc(sizeof(*nfc), GFP_KERNEL);
+- if (!nfc)
+- return;
+-
++ nfc->dev = dev;
+ spin_lock_init(&nfc->controller.lock);
+ init_waitqueue_head(&nfc->controller.wq);
+ INIT_LIST_HEAD(&nfc->chips);
+
+- node = ofnode_by_compatible(ofnode_null(), "allwinner,sun4i-a10-nand");
+- if (!ofnode_valid(node)) {
+- pr_err("unable to find nfc node in device tree\n");
+- goto err;
+- }
+-
+- if (!ofnode_is_enabled(node)) {
+- pr_err("nfc disabled in device tree\n");
+- goto err;
+- }
+-
+- regs = ofnode_get_addr(node);
+- if (regs == FDT_ADDR_T_NONE) {
+- pr_err("unable to find nfc address in device tree\n");
+- goto err;
+- }
++ nfc->regs = dev_read_addr_ptr(dev);
++ if (!nfc->regs)
++ return -EINVAL;
+
+- nfc->regs = (void *)regs;
++ ret = reset_get_bulk(dev, &rst_bulk);
++ if (!ret)
++ reset_deassert_bulk(&rst_bulk);
++
++ ret = clk_get_bulk(dev, &clk_bulk);
++ if (!ret)
++ clk_enable_bulk(&clk_bulk);
+
+ ret = sunxi_nfc_rst(nfc);
+ if (ret)
+- goto err;
++ return ret;
+
+- ret = sunxi_nand_chips_init(node, nfc);
++ ret = sunxi_nand_chips_init(dev_ofnode(dev), nfc);
+ if (ret) {
+- dev_err(nfc->dev, "failed to init nand chips\n");
+- goto err;
++ dev_err(dev, "failed to init nand chips\n");
++ return ret;
+ }
+
+- return;
++ return 0;
++}
+
+-err:
+- kfree(nfc);
++static const struct udevice_id sunxi_nand_ids[] = {
++ {
++ .compatible = "allwinner,sun4i-a10-nand",
++ },
++ { }
++};
++
++U_BOOT_DRIVER(sunxi_nand) = {
++ .name = "sunxi_nand",
++ .id = UCLASS_MTD,
++ .of_match = sunxi_nand_ids,
++ .probe = sunxi_nand_probe,
++ .priv_auto = sizeof(struct sunxi_nfc),
++};
++
++void board_nand_init(void)
++{
++ struct udevice *dev;
++ int ret;
++
++ ret = uclass_get_device_by_driver(UCLASS_MTD,
++ DM_DRIVER_GET(sunxi_nand), &dev);
++ if (ret && ret != -ENODEV)
++ pr_err("Failed to initialize sunxi NAND controller: %d\n", ret);
+ }
+
+ MODULE_LICENSE("GPL v2");
--- /dev/null
+From 6fdd7e8d2758f69f5c8e3cb2a0f06da47c1f2cb4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 17 Apr 2021 14:21:45 -0500
+Subject: [PATCH 32/90] sunxi: DT: H6: Add USB3 to Pine H64 DTS
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/sun50i-h6-pine-h64.dts | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/arm/dts/sun50i-h6-pine-h64.dts
++++ b/arch/arm/dts/sun50i-h6-pine-h64.dts
+@@ -89,6 +89,10 @@
+ status = "okay";
+ };
+
++&dwc3 {
++ status = "okay";
++};
++
+ &ehci0 {
+ status = "okay";
+ };
+@@ -332,3 +336,7 @@
+ usb3_vbus-supply = <®_usb_vbus>;
+ status = "okay";
+ };
++
++&usb3phy {
++ status = "okay";
++};
--- /dev/null
+From ff0e952a3a380ba191375d5f68609cdbe026d535 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 7 Aug 2021 19:55:20 -0500
+Subject: [PATCH 33/90] tools: mkimage: Add Allwinner TOC1 support
+
+TOC1 is an container format used by Allwinner's boot0 that can hold
+multiple images. It supports encryption and signatures, but that
+functionality is not implemented, only the basic "non-secure" subset.
+
+A config file is used to provide the list of data files to include. Its
+path is passed as the argument to "-d". It contains sections of the
+following form:
+
+ [name]
+ file = /path/to/file
+ addr = 0x12345678
+
+Specific well-known names, such as "dtb", "opensbi", and "u-boot", are
+used by the bootloader to distinguish the items inside the image.
+
+Cover-letter:
+tools: mkimage: Add Allwinner TOC1 support
+
+The SPL port for the Allwinner D1 RISC-V SoC will probably take a while
+longer than porting U-Boot proper, as none of the relevant drivers are
+set up for DM in SPL. In the meantime, we are using[1][2] a fork[3] of
+Allwinner's boot0 loader, which they also call "spl" in their BSP. boot0
+uses this TOC1 image format.
+
+The vendor tools for generating TOC1 images require a binary config file
+generated by their FEX compiler. Instead of trying to support that, I
+made up a simple human-readable config file format. I didn't see any
+existing platform-agnostic parser for multi-image containers in mkimage.
+
+I am sending this as RFC because it is only of temporary/limited use.
+It only works with one specific fork of boot0 which was modified to
+"behave" (the the original vendor version monkey-patches a custom header
+inside the U-Boot image during boot). So it will be obsolete once U-Boot
+SPL is ported. And it is Yet Another Image Format. On the other hand, it
+does work, and it is currently being used.
+
+[1]: https://linux-sunxi.org/Allwinner_Nezha#U-Boot
+[2]: https://fedoraproject.org/wiki/Architectures/RISC-V/Allwinner
+[3]: https://github.com/smaeul/sun20i_d1_spl
+END
+Series-prefix: RFC
+Series-to: sunxi
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ boot/image.c | 1 +
+ include/image.h | 1 +
+ include/sunxi_image.h | 26 ++++
+ tools/Makefile | 1 +
+ tools/sunxi_toc1.c | 318 ++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 347 insertions(+)
+ create mode 100644 tools/sunxi_toc1.c
+
+--- a/boot/image.c
++++ b/boot/image.c
+@@ -180,6 +180,7 @@ static const table_entry_t uimage_type[]
+ { IH_TYPE_COPRO, "copro", "Coprocessor Image"},
+ { IH_TYPE_SUNXI_EGON, "sunxi_egon", "Allwinner eGON Boot Image" },
+ { IH_TYPE_SUNXI_TOC0, "sunxi_toc0", "Allwinner TOC0 Boot Image" },
++ { IH_TYPE_SUNXI_TOC1, "sunxi_toc1", "Allwinner TOC1 Boot Image" },
+ { -1, "", "", },
+ };
+
+--- a/include/image.h
++++ b/include/image.h
+@@ -229,6 +229,7 @@ enum image_type_t {
+ IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/
+ IH_TYPE_SUNXI_EGON, /* Allwinner eGON Boot Image */
+ IH_TYPE_SUNXI_TOC0, /* Allwinner TOC0 Boot Image */
++ IH_TYPE_SUNXI_TOC1, /* Allwinner TOC1 Boot Image */
+
+ IH_TYPE_COUNT, /* Number of image types */
+ };
+--- a/include/sunxi_image.h
++++ b/include/sunxi_image.h
+@@ -116,4 +116,30 @@ struct __packed toc0_item_info {
+ #define TOC0_ITEM_INFO_NAME_KEY 0x00010303
+ #define TOC0_ITEM_INFO_END "IIE;"
+
++struct __packed toc1_main_info {
++ uint8_t name[16];
++ __le32 magic;
++ __le32 checksum;
++ __le32 serial;
++ __le32 status;
++ __le32 num_items;
++ __le32 length;
++ __le32 major_version;
++ __le32 minor_version;
++ __le32 reserved[3];
++ uint8_t end[4];
++};
++
++struct __packed toc1_item_info {
++ uint8_t name[64];
++ __le32 offset;
++ __le32 length;
++ __le32 encryption;
++ __le32 type;
++ __le32 load_addr;
++ __le32 index;
++ __le32 reserved[69];
++ uint8_t end[4];
++};
++
+ #endif
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -132,6 +132,7 @@ dumpimage-mkimage-objs := aisimage.o \
+ $(ROCKCHIP_OBS) \
+ socfpgaimage.o \
+ sunxi_egon.o \
++ sunxi_toc1.o \
+ lib/crc16-ccitt.o \
+ lib/hash-checksum.o \
+ lib/sha1.o \
+--- /dev/null
++++ b/tools/sunxi_toc1.c
+@@ -0,0 +1,318 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2018 Arm Ltd.
++ * (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <assert.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <image.h>
++#include <sunxi_image.h>
++
++#include "imagetool.h"
++#include "mkimage.h"
++
++#define SECTOR_SIZE 512
++
++struct item_desc {
++ const char *name;
++ const char *file;
++ unsigned long addr;
++ long length;
++};
++
++static uint32_t toc1_header_length(uint32_t num_items)
++{
++ return ALIGN(sizeof(struct toc1_main_info) +
++ sizeof(struct toc1_item_info) * num_items, SECTOR_SIZE);
++}
++
++static int toc1_parse_cfg(const char *file, struct item_desc **desc,
++ uint32_t *main_length, uint32_t *num_items)
++{
++ struct item_desc *descs = NULL;
++ int ret = EXIT_FAILURE;
++ FILE *cfg, *fp = NULL;
++ uint32_t ndescs = 0;
++ char *line = NULL;
++ size_t len = 0;
++
++ *desc = NULL;
++ *main_length = 0;
++ *num_items = 0;
++
++ cfg = fopen(file, "r");
++ if (!cfg)
++ return ret;
++
++ while (getline(&line, &len, cfg) > 0) {
++ char *end, *s;
++
++ if (line[0] == '[') {
++ s = line + 1;
++ end = strchr(s, ']');
++ if (!end || end[1] != '\n')
++ goto err;
++ end[0] = '\0';
++
++ ndescs++;
++ descs = reallocarray(descs, ndescs, sizeof(*descs));
++ if (!descs)
++ goto err;
++
++ descs[ndescs - 1].name = strdup(s);
++ } else if (line[0] != '#' && line[0] != '\n') {
++ s = strchr(line, '=');
++ if (!s)
++ goto err;
++ while ((++s)[0] == ' ')
++ ;
++ end = strchr(s, '\n');
++ if (!end)
++ goto err;
++ end[0] = '\0';
++
++ if (!strncmp(line, "file", strlen("file"))) {
++ fp = fopen(s, "rb");
++ if (!fp)
++ goto err;
++ if (fseek(fp, 0, SEEK_END) < 0)
++ goto err;
++ descs[ndescs - 1].file = strdup(s);
++ descs[ndescs - 1].length = ftell(fp);
++ *main_length += ALIGN(descs[ndescs - 1].length,
++ SECTOR_SIZE);
++ fclose(fp);
++ fp = NULL;
++ } else if (!strncmp(line, "addr", strlen("addr"))) {
++ descs[ndescs - 1].addr = strtoul(s, NULL, 0);
++ } else {
++ goto err;
++ }
++ }
++ }
++
++ *desc = descs;
++ *main_length += toc1_header_length(ndescs);
++ *num_items = ndescs;
++
++ ret = EXIT_SUCCESS;
++
++err:
++ if (fp)
++ fclose(fp);
++ if (ret)
++ free(descs);
++ free(line);
++ fclose(cfg);
++
++ return ret;
++}
++
++static int toc1_create(uint8_t *buf, uint32_t len,
++ const struct item_desc *desc, uint32_t num_items)
++{
++ struct toc1_main_info *main = (void *)buf;
++ struct toc1_item_info *item = (void *)(main + 1);
++ uint32_t item_offset, item_length;
++ uint32_t *buf32 = (void *)buf;
++ int ret = EXIT_FAILURE;
++ uint32_t checksum = 0;
++ FILE *fp = NULL;
++ int i;
++
++ /* Create the main TOC1 header. */
++ main->magic = cpu_to_le32(TOC0_MAIN_INFO_MAGIC);
++ main->checksum = cpu_to_le32(BROM_STAMP_VALUE);
++ main->num_items = cpu_to_le32(num_items);
++ memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end));
++
++ item_offset = 0;
++ item_length = toc1_header_length(num_items);
++
++ for (i = 0; i < num_items; ++i, ++item, ++desc) {
++ item_offset = item_offset + item_length;
++ item_length = desc->length;
++
++ /* Create the item header. */
++ memcpy(item->name, desc->name,
++ strnlen(desc->name, sizeof(item->name)));
++ item->offset = cpu_to_le32(item_offset);
++ item->length = cpu_to_le32(item_length);
++ item->load_addr = cpu_to_le32(desc->addr);
++ memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
++
++ /* Read in the data. */
++ fp = fopen(desc->file, "rb");
++ if (!fp)
++ goto err;
++ if (!fread(buf + item_offset, item_length, 1, fp))
++ goto err;
++ fclose(fp);
++ fp = NULL;
++
++ /* Pad the sectors with 0xff to be flash-friendly. */
++ item_offset = item_offset + item_length;
++ item_length = ALIGN(item_offset, SECTOR_SIZE) - item_offset;
++ memset(buf + item_offset, 0xff, item_length);
++ }
++
++ /* Fill in the total padded file length. */
++ item_offset = item_offset + item_length;
++ main->length = cpu_to_le32(item_offset);
++
++ /* Verify enough space was provided when creating the image. */
++ assert(len >= item_offset);
++
++ /* Calculate the checksum. Yes, it's that simple. */
++ for (i = 0; i < item_offset / 4; ++i)
++ checksum += le32_to_cpu(buf32[i]);
++ main->checksum = cpu_to_le32(checksum);
++
++ ret = EXIT_SUCCESS;
++
++err:
++ if (fp)
++ fclose(fp);
++
++ return ret;
++}
++
++static int toc1_verify(const uint8_t *buf, uint32_t len)
++{
++ const struct toc1_main_info *main = (void *)buf;
++ const struct toc1_item_info *item = (void *)(main + 1);
++ uint32_t checksum = BROM_STAMP_VALUE;
++ uint32_t main_length, num_items;
++ uint32_t *buf32 = (void *)buf;
++ int ret = EXIT_FAILURE;
++ int i;
++
++ num_items = le32_to_cpu(main->num_items);
++ main_length = le32_to_cpu(main->length);
++
++ if (len < main_length || main_length < toc1_header_length(num_items))
++ goto err;
++
++ /* Verify the main header. */
++ if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC)
++ goto err;
++ /* Verify the checksum without modifying the buffer. */
++ for (i = 0; i < main_length / 4; ++i)
++ checksum += le32_to_cpu(buf32[i]);
++ if (checksum != 2 * le32_to_cpu(main->checksum))
++ goto err;
++ /* The length must be at least 512 byte aligned. */
++ if (main_length % SECTOR_SIZE)
++ goto err;
++ if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)))
++ goto err;
++
++ /* Verify each item header. */
++ for (i = 0; i < num_items; ++i, ++item)
++ if (memcmp(item->end, TOC0_ITEM_INFO_END, sizeof(item->end)))
++ goto err;
++
++ ret = EXIT_SUCCESS;
++
++err:
++ return ret;
++}
++
++static int toc1_check_params(struct image_tool_params *params)
++{
++ if (!params->dflag)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int toc1_verify_header(unsigned char *buf, int image_size,
++ struct image_tool_params *params)
++{
++ return toc1_verify(buf, image_size);
++}
++
++static void toc1_print_header(const void *buf)
++{
++ const struct toc1_main_info *main = buf;
++ const struct toc1_item_info *item = (void *)(main + 1);
++ uint32_t head_length, main_length, num_items;
++ uint32_t item_offset, item_length, item_addr;
++ int i;
++
++ num_items = le32_to_cpu(main->num_items);
++ head_length = sizeof(*main) + num_items * sizeof(*item);
++ main_length = le32_to_cpu(main->length);
++
++ printf("Allwinner TOC1 Image\n"
++ "Size: %d bytes\n"
++ "Contents: %d items\n"
++ " 00000000:%08x Headers\n",
++ main_length, num_items, head_length);
++
++ for (i = 0; i < num_items; ++i, ++item) {
++ item_offset = le32_to_cpu(item->offset);
++ item_length = le32_to_cpu(item->length);
++ item_addr = le32_to_cpu(item->load_addr);
++
++ printf(" %08x:%08x => %08x %s\n",
++ item_offset, item_length, item_addr, item->name);
++ }
++}
++
++static void toc1_set_header(void *buf, struct stat *sbuf, int ifd,
++ struct image_tool_params *params)
++{
++ /* Image is already written below. */
++}
++
++static int toc1_check_image_type(uint8_t type)
++{
++ return type == IH_TYPE_SUNXI_TOC1 ? 0 : 1;
++}
++
++static int toc1_vrec_header(struct image_tool_params *params,
++ struct image_type_params *tparams)
++{
++ uint32_t main_length, num_items;
++ struct item_desc *desc;
++ int ret;
++
++ /* This "header" contains the entire image. */
++ params->skipcpy = 1;
++
++ ret = toc1_parse_cfg(params->datafile, &desc, &main_length, &num_items);
++ if (ret)
++ exit(ret);
++
++ tparams->header_size = main_length;
++ tparams->hdr = calloc(tparams->header_size, 1);
++ if (!tparams->hdr)
++ exit(ret);
++
++ ret = toc1_create(tparams->hdr, tparams->header_size, desc, num_items);
++ if (ret)
++ exit(ret);
++
++ return 0;
++}
++
++U_BOOT_IMAGE_TYPE(
++ sunxi_toc1,
++ "Allwinner TOC1 Boot Image support",
++ 0,
++ NULL,
++ toc1_check_params,
++ toc1_verify_header,
++ toc1_print_header,
++ toc1_set_header,
++ NULL,
++ toc1_check_image_type,
++ NULL,
++ toc1_vrec_header
++);
--- /dev/null
+From 79f7d883d980beea9989d06f9fba4fcc0430176a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 14 Jul 2022 22:14:38 -0500
+Subject: [PATCH 34/90] phy: sun4i-usb: Do not drive VBUS with external VBUS
+ present
+
+It is possible to use host-side USB with externally-provided VBUS. For
+example, some USB OTG cables have an extra power input which powers
+both the board and the USB peripheral.
+
+To support this setup, skip enabling the VBUS switch/regulator if VBUS
+voltage is already present. This behavior matches the Linux PHY driver.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/phy/allwinner/phy-sun4i-usb.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -220,6 +220,12 @@ static int sun4i_usb_phy_power_on(struct
+ initial_usb_scan_delay = 0;
+ }
+
++ /* For phy0 only turn on Vbus if we don't have an ext. Vbus */
++ if (phy->id == 0 && sun4i_usb_phy_vbus_detect(phy)) {
++ dev_warn(phy->dev, "External vbus detected, not enabling our own vbus\n");
++ return 0;
++ }
++
+ if (usb_phy->vbus) {
+ ret = regulator_set_enable(usb_phy->vbus, true);
+ if (ret && ret != -ENOSYS)
--- /dev/null
+From 4bc5cec5361dd6a2ae3bd044c79a4b5227bb9627 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 16 May 2022 00:47:32 -0500
+Subject: [PATCH 35/90] mtd: nand: sunxi: Pass the device to the init function
+
+This more closely matches the U-Boot driver to the Linux version.
+
+Series-to: sunxi
+
+Cover-letter:
+mtd: nand: sunxi: Convert to devicetree and the driver model
+This series converts the sunxi NAND driver to get its resources (clocks,
+resets, pins) from the devicetree, and probe using the driver model.
+
+In addition to the immediate cleanup, this allows backporting more
+patches (bugfixes, newer SoC support) from the Linux driver.
+END
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/mtd/nand/raw/sunxi_nand.c | 39 ++++++++++++++++---------------
+ 1 file changed, 20 insertions(+), 19 deletions(-)
+
+--- a/drivers/mtd/nand/raw/sunxi_nand.c
++++ b/drivers/mtd/nand/raw/sunxi_nand.c
+@@ -1604,7 +1604,8 @@ static int sunxi_nand_ecc_init(struct mt
+ return 0;
+ }
+
+-static int sunxi_nand_chip_init(ofnode np, struct sunxi_nfc *nfc, int devnum)
++static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc,
++ ofnode np, int devnum)
+ {
+ const struct nand_sdr_timings *timings;
+ struct sunxi_nand_chip *chip;
+@@ -1620,7 +1621,7 @@ static int sunxi_nand_chip_init(ofnode n
+
+ nsels /= sizeof(u32);
+ if (!nsels || nsels > 8) {
+- dev_err(nfc->dev, "invalid reg property size\n");
++ dev_err(dev, "invalid reg property size\n");
+ return -EINVAL;
+ }
+
+@@ -1628,7 +1629,7 @@ static int sunxi_nand_chip_init(ofnode n
+ (nsels * sizeof(struct sunxi_nand_chip_sel)),
+ GFP_KERNEL);
+ if (!chip) {
+- dev_err(nfc->dev, "could not allocate chip\n");
++ dev_err(dev, "could not allocate chip\n");
+ return -ENOMEM;
+ }
+
+@@ -1638,19 +1639,19 @@ static int sunxi_nand_chip_init(ofnode n
+ for (i = 0; i < nsels; i++) {
+ ret = ofnode_read_u32_index(np, "reg", i, &tmp);
+ if (ret) {
+- dev_err(nfc->dev, "could not retrieve reg property: %d\n",
++ dev_err(dev, "could not retrieve reg property: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (tmp > NFC_MAX_CS) {
+- dev_err(nfc->dev,
++ dev_err(dev,
+ "invalid reg value: %u (max CS = 7)\n", tmp);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
+- dev_err(nfc->dev, "CS %d already assigned\n", tmp);
++ dev_err(dev, "CS %d already assigned\n", tmp);
+ return -EINVAL;
+ }
+
+@@ -1661,9 +1662,9 @@ static int sunxi_nand_chip_init(ofnode n
+ chip->sels[i].rb.type = RB_NATIVE;
+ chip->sels[i].rb.info.nativeid = tmp;
+ } else {
+- ret = gpio_request_by_name_nodev(np, "rb-gpios", i,
+- &chip->sels[i].rb.info.gpio,
+- GPIOD_IS_IN);
++ ret = gpio_request_by_name(dev, "rb-gpios", i,
++ &chip->sels[i].rb.info.gpio,
++ GPIOD_IS_IN);
+ if (ret)
+ chip->sels[i].rb.type = RB_GPIO;
+ else
+@@ -1674,7 +1675,7 @@ static int sunxi_nand_chip_init(ofnode n
+ timings = onfi_async_timing_mode_to_sdr_timings(0);
+ if (IS_ERR(timings)) {
+ ret = PTR_ERR(timings);
+- dev_err(nfc->dev,
++ dev_err(dev,
+ "could not retrieve timings for ONFI mode 0: %d\n",
+ ret);
+ return ret;
+@@ -1682,7 +1683,7 @@ static int sunxi_nand_chip_init(ofnode n
+
+ ret = sunxi_nand_chip_set_timings(nfc, chip, timings);
+ if (ret) {
+- dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
++ dev_err(dev, "could not configure chip timings: %d\n", ret);
+ return ret;
+ }
+
+@@ -1717,25 +1718,25 @@ static int sunxi_nand_chip_init(ofnode n
+
+ ret = sunxi_nand_chip_init_timings(nfc, chip);
+ if (ret) {
+- dev_err(nfc->dev, "could not configure chip timings: %d\n", ret);
++ dev_err(dev, "could not configure chip timings: %d\n", ret);
+ return ret;
+ }
+
+ ret = sunxi_nand_ecc_init(mtd, &nand->ecc);
+ if (ret) {
+- dev_err(nfc->dev, "ECC init failed: %d\n", ret);
++ dev_err(dev, "ECC init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+- dev_err(nfc->dev, "nand_scan_tail failed: %d\n", ret);
++ dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = nand_register(devnum, mtd);
+ if (ret) {
+- dev_err(nfc->dev, "failed to register mtd device: %d\n", ret);
++ dev_err(dev, "failed to register mtd device: %d\n", ret);
+ return ret;
+ }
+
+@@ -1744,13 +1745,13 @@ static int sunxi_nand_chip_init(ofnode n
+ return 0;
+ }
+
+-static int sunxi_nand_chips_init(ofnode node, struct sunxi_nfc *nfc)
++static int sunxi_nand_chips_init(struct udevice *dev, struct sunxi_nfc *nfc)
+ {
+ ofnode nand_np;
+ int ret, i = 0;
+
+- ofnode_for_each_subnode(nand_np, node) {
+- ret = sunxi_nand_chip_init(nand_np, nfc, i++);
++ dev_for_each_subnode(nand_np, dev) {
++ ret = sunxi_nand_chip_init(dev, nfc, nand_np, i++);
+ if (ret)
+ return ret;
+ }
+@@ -1802,7 +1803,7 @@ static int sunxi_nand_probe(struct udevi
+ if (ret)
+ return ret;
+
+- ret = sunxi_nand_chips_init(dev_ofnode(dev), nfc);
++ ret = sunxi_nand_chips_init(dev, nfc);
+ if (ret) {
+ dev_err(dev, "failed to init nand chips\n");
+ return ret;
--- /dev/null
+From b13140a914199dcdd80331fef6f33d47f008f1b4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:40:22 -0500
+Subject: [PATCH 36/90] sunxi: Enable PHY_SUN4I_USB by default for new SoCs
+
+With one exception (sun9i), all sunxi SoCs released to date use variants
+of the same USB PHY. Instead of requiring each new SoC to duplicate the
+PHY driver selection, enable it by default.
+
+Series-to: Andre Przywara <andre.przywara@arm.com>
+Series-to: Jagan Teki <jagan@amarulasolutions.com>
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/mach-sunxi/Kconfig | 11 -----------
+ drivers/phy/allwinner/Kconfig | 3 ++-
+ 2 files changed, 2 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -162,7 +162,6 @@ endif
+
+ config MACH_SUNXI_H3_H5
+ bool
+- select PHY_SUN4I_USB
+ select SUNXI_DE2
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_32BIT
+@@ -191,7 +190,6 @@ config MACH_SUNIV
+ config MACH_SUN4I
+ bool "sun4i (Allwinner A10)"
+ select CPU_V7A
+- select PHY_SUN4I_USB
+ select DRAM_SUN4I
+ select SUNXI_GEN_SUN4I
+ select SUPPORT_SPL
+@@ -202,7 +200,6 @@ config MACH_SUN5I
+ bool "sun5i (Allwinner A13)"
+ select CPU_V7A
+ select DRAM_SUN4I
+- select PHY_SUN4I_USB
+ select SUNXI_GEN_SUN4I
+ select SUPPORT_SPL
+ imply SPL_SYS_I2C_LEGACY
+@@ -216,7 +213,6 @@ config MACH_SUN6I
+ select ARCH_SUPPORT_PSCI
+ select SPL_ARMV7_SET_CORTEX_SMPEN
+ select DRAM_SUN6I
+- select PHY_SUN4I_USB
+ select SPL_I2C
+ select SUN6I_PRCM
+ select SUNXI_GEN_SUN6I
+@@ -232,7 +228,6 @@ config MACH_SUN7I
+ select ARCH_SUPPORT_PSCI
+ select SPL_ARMV7_SET_CORTEX_SMPEN
+ select DRAM_SUN4I
+- select PHY_SUN4I_USB
+ select SUNXI_GEN_SUN4I
+ select SUPPORT_SPL
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+@@ -246,7 +241,6 @@ config MACH_SUN8I_A23
+ select CPU_V7_HAS_VIRT
+ select ARCH_SUPPORT_PSCI
+ select DRAM_SUN8I_A23
+- select PHY_SUN4I_USB
+ select SPL_I2C
+ select SUNXI_GEN_SUN6I
+ select SUPPORT_SPL
+@@ -260,7 +254,6 @@ config MACH_SUN8I_A33
+ select CPU_V7_HAS_VIRT
+ select ARCH_SUPPORT_PSCI
+ select DRAM_SUN8I_A33
+- select PHY_SUN4I_USB
+ select SPL_I2C
+ select SUNXI_GEN_SUN6I
+ select SUPPORT_SPL
+@@ -271,7 +264,6 @@ config MACH_SUN8I_A83T
+ bool "sun8i (Allwinner A83T)"
+ select CPU_V7A
+ select DRAM_SUN8I_A83T
+- select PHY_SUN4I_USB
+ select SPL_I2C
+ select SUNXI_GEN_SUN6I
+ select MMC_SUNXI_HAS_NEW_MODE
+@@ -299,7 +291,6 @@ config MACH_SUN8I_R40
+ select SUPPORT_SPL
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_32BIT
+- select PHY_SUN4I_USB
+ imply SPL_SYS_I2C_LEGACY
+
+ config MACH_SUN8I_V3S
+@@ -327,7 +318,6 @@ config MACH_SUN9I
+ config MACH_SUN50I
+ bool "sun50i (Allwinner A64)"
+ select ARM64
+- select PHY_SUN4I_USB
+ select SUN6I_PRCM
+ select SUNXI_DE2
+ select SUNXI_GEN_SUN6I
+@@ -350,7 +340,6 @@ config MACH_SUN50I_H5
+ config MACH_SUN50I_H6
+ bool "sun50i (Allwinner H6)"
+ select ARM64
+- select PHY_SUN4I_USB
+ select DRAM_SUN50I_H6
+ select SUN50I_GEN_H6
+
+--- a/drivers/phy/allwinner/Kconfig
++++ b/drivers/phy/allwinner/Kconfig
+@@ -3,7 +3,8 @@
+ #
+ config PHY_SUN4I_USB
+ bool "Allwinner Sun4I USB PHY driver"
+- depends on ARCH_SUNXI
++ depends on ARCH_SUNXI && !MACH_SUN9I
++ default y
+ select DM_REGULATOR
+ select PHY
+ help
--- /dev/null
+From d11c5971f60d482c05f807c24f3ccd37cf7d0f70 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 17:12:57 -0500
+Subject: [PATCH 37/90] sunxi: psci: Add support for H3 CPU 0 hotplug
+
+Due to a bug in the H3 SoC, where the CPU 0 hotplug flag cannot be
+written, resuming CPU 0 requires using the "Super Standby" code path in
+the BROM instead of the hotplug path. This path requires jumping to an
+eGON image in SRAM.
+
+Add support to the build system to generate this eGON image and include
+it in the FIT, and add code to direct the BROM to its location in SRAM.
+
+Since the Super Standby code path in the BROM initializes the CPU and
+AHB1 clocks to 24 MHz, those registers need to be restored after control
+passes back to U-Boot. Furthermore, because the BROM lowers the AHB1
+clock divider to /1 before switching to the lower-frequency parent,
+PLL_PERIPH0 must be bypassed to prevent AHB1 from temporarily running at
+600 MHz. Otherwise, this locks up the SoC.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ Makefile | 17 +++++++++++++++++
+ arch/arm/cpu/armv7/sunxi/psci.c | 31 +++++++++++++++++++++++++++++++
+ arch/arm/dts/sunxi-u-boot.dtsi | 23 ++++++++++++++++++++++-
+ include/configs/sun8i.h | 4 ++++
+ 4 files changed, 74 insertions(+), 1 deletion(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -1013,6 +1013,23 @@ INPUTS-y += u-boot.img
+ endif
+ endif
+
++ifeq ($(CONFIG_MACH_SUN8I_H3)$(CONFIG_ARMV7_PSCI),yy)
++INPUTS-$(CONFIG_ARMV7_PSCI) += u-boot-resume.img
++
++MKIMAGEFLAGS_u-boot-resume.img := -B 0x400 -T sunxi_egon
++
++u-boot-resume.img: u-boot-resume.bin
++ $(call if_changed,mkimage)
++
++OBJCOPYFLAGS_u-boot-resume.bin := -O binary
++
++u-boot-resume.bin: u-boot-resume.o
++ $(call if_changed,objcopy)
++
++u-boot-resume.S: u-boot
++ @sed -En 's/(0x[[:xdigit:]]+) +psci_cpu_entry/ldr pc, =\1/p' $<.map > $@
++endif
++
+ INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
+ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
+ $(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin)
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -10,6 +10,7 @@
+ #include <common.h>
+ #include <asm/cache.h>
+
++#include <asm/arch/clock.h>
+ #include <asm/arch/cpu.h>
+ #include <asm/arch/cpucfg.h>
+ #include <asm/arch/prcm.h>
+@@ -141,6 +142,13 @@ static void __secure sunxi_set_entry_add
+ (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+
+ writel((u32)entry, &cpucfg->priv0);
++
++#ifdef CONFIG_MACH_SUN8I_H3
++ /* Redirect CPU 0 to the secure monitor via the resume shim. */
++ writel(0x16aaefe8, &cpucfg->super_standy_flag);
++ writel(0xaa16efe8, &cpucfg->super_standy_flag);
++ writel(SUNXI_RESUME_BASE, &cpucfg->priv1);
++#endif
+ }
+ #endif
+
+@@ -255,9 +263,12 @@ out:
+ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
+ u32 context_id)
+ {
++ struct sunxi_ccm_reg *ccu = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ struct sunxi_cpucfg_reg *cpucfg =
+ (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+ u32 cpu = (mpidr & 0x3);
++ u32 cpu_clk;
++ u32 bus_clk;
+
+ /* store target PC and context id */
+ psci_save(cpu, pc, context_id);
+@@ -274,12 +285,32 @@ int __secure psci_cpu_on(u32 __always_un
+ /* Lock CPU (Disable external debug access) */
+ clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
+
++ if (IS_ENABLED(CONFIG_MACH_SUN8I_H3) && cpu == 0) {
++ /* Save registers that will be clobbered by the BROM. */
++ cpu_clk = readl(&ccu->cpu_axi_cfg);
++ bus_clk = readl(&ccu->ahb1_apb1_div);
++
++ /* Bypass PLL_PERIPH0 so AHB1 frequency does not spike. */
++ setbits_le32(&ccu->pll6_cfg, BIT(25));
++ }
++
+ /* Power up target CPU */
+ sunxi_cpu_set_power(cpu, true);
+
+ /* De-assert reset on target CPU */
+ writel(BIT(1) | BIT(0), &cpucfg->cpu[cpu].rst);
+
++ if (IS_ENABLED(CONFIG_MACH_SUN8I_H3) && cpu == 0) {
++ /* Spin until the BROM has clobbered the clock registers. */
++ while (readl(&ccu->ahb1_apb1_div) != 0x00001100);
++
++ /* Restore the registers and turn off PLL_PERIPH0 bypass. */
++ writel(cpu_clk, &ccu->cpu_axi_cfg);
++ writel(bus_clk, &ccu->ahb1_apb1_div);
++
++ clrbits_le32(&ccu->pll6_cfg, BIT(25));
++ }
++
+ /* Unlock CPU (Disable external debug access) */
+ setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
+
+--- a/arch/arm/dts/sunxi-u-boot.dtsi
++++ b/arch/arm/dts/sunxi-u-boot.dtsi
+@@ -6,7 +6,11 @@
+ #define ARCH "arm"
+ #endif
+
+-#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
++#if defined(CONFIG_MACH_SUN8I_H3)
++#ifdef CONFIG_ARMV7_PSCI
++#define RESUME_ADDR SUNXI_RESUME_BASE
++#endif
++#elif defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
+ #define BL31_ADDR 0x00044000
+ #define SCP_ADDR 0x00050000
+ #elif defined(CONFIG_MACH_SUN50I_H6)
+@@ -78,6 +82,20 @@
+ };
+ #endif
+
++#ifdef RESUME_ADDR
++ resume {
++ description = "Super Standby resume image";
++ type = "standalone";
++ arch = ARCH;
++ compression = "none";
++ load = <RESUME_ADDR>;
++
++ blob-ext {
++ filename = "u-boot-resume.img";
++ };
++ };
++#endif
++
+ #ifdef SCP_ADDR
+ scp {
+ description = "SCP firmware";
+@@ -111,6 +129,9 @@
+ firmware = "uboot";
+ #endif
+ loadables =
++#ifdef RESUME_ADDR
++ "resume",
++#endif
+ #ifdef SCP_ADDR
+ "scp",
+ #endif
+--- a/include/configs/sun8i.h
++++ b/include/configs/sun8i.h
+@@ -8,6 +8,10 @@
+ #ifndef __CONFIG_H
+ #define __CONFIG_H
+
++#define SUNXI_RESUME_BASE (CONFIG_ARMV7_SECURE_BASE + \
++ CONFIG_ARMV7_SECURE_MAX_SIZE)
++#define SUNXI_RESUME_SIZE 1024
++
+ #include <configs/sunxi-common.h>
+
+ #endif /* __CONFIG_H */
--- /dev/null
+From 7585a12ffec6e42c62222d8ee4085413b3a197f7 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 14:58:27 -0500
+Subject: [PATCH 38/90] remoteproc: Add a driver for the Allwinner AR100
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/remoteproc/Kconfig | 9 ++
+ drivers/remoteproc/Makefile | 1 +
+ drivers/remoteproc/sun6i_ar100_rproc.c | 111 +++++++++++++++++++++++++
+ 3 files changed, 121 insertions(+)
+ create mode 100644 drivers/remoteproc/sun6i_ar100_rproc.c
+
+--- a/drivers/remoteproc/Kconfig
++++ b/drivers/remoteproc/Kconfig
+@@ -41,6 +41,15 @@ config REMOTEPROC_STM32_COPRO
+ Say 'y' here to add support for STM32 Cortex-M4 coprocessors via the
+ remoteproc framework.
+
++config REMOTEPROC_SUN6I_AR100
++ bool "Support for Allwinner AR100 SCP"
++ select REMOTEPROC
++ depends on ARCH_SUNXI
++ help
++ Say 'y' here to support Allwinner's AR100 System Control Processor
++ (SCP), found in various sun6i/sun8i/sun50i family SoCs, through the
++ remoteproc framework.
++
+ config REMOTEPROC_TI_K3_ARM64
+ bool "Support for TI's K3 based ARM64 remoteproc driver"
+ select REMOTEPROC
+--- a/drivers/remoteproc/Makefile
++++ b/drivers/remoteproc/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc
+ obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o
+ obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o
+ obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
++obj-$(CONFIG_REMOTEPROC_SUN6I_AR100) += sun6i_ar100_rproc.o
+ obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
+ obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o
+ obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o
+--- /dev/null
++++ b/drivers/remoteproc/sun6i_ar100_rproc.c
+@@ -0,0 +1,111 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <dm.h>
++#include <errno.h>
++#include <remoteproc.h>
++#include <asm/io.h>
++
++#define SUNXI_SCP_MAGIC 0xb4400012
++
++#define OR1K_VEC_FIRST 0x01
++#define OR1K_VEC_LAST 0x0e
++#define OR1K_VEC_ADDR(n) (0x100 * (n))
++
++struct sun6i_ar100_rproc_priv {
++ void *cfg_base;
++ ulong sram_base;
++};
++
++static int sun6i_ar100_rproc_load(struct udevice *dev, ulong addr, ulong size)
++{
++ struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
++
++ /* Check for a valid SCP firmware. */
++ if (readl_relaxed(addr) != SUNXI_SCP_MAGIC)
++ return -ENOENT;
++
++ /* Program exception vectors to the firmware entry point. */
++ for (u32 i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
++ ulong vector = priv->sram_base + OR1K_VEC_ADDR(i);
++ ulong offset = addr - vector;
++
++ writel_relaxed(offset >> 2, vector);
++ }
++
++ return 0;
++}
++
++static int sun6i_ar100_rproc_start(struct udevice *dev)
++{
++ struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
++
++ setbits_le32(priv->cfg_base, BIT(0));
++
++ return 0;
++}
++
++static int sun6i_ar100_rproc_stop(struct udevice *dev)
++{
++ struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
++
++ clrbits_le32(priv->cfg_base, BIT(0));
++
++ return 0;
++}
++
++static int sun6i_ar100_rproc_reset(struct udevice *dev)
++{
++ int ret;
++
++ ret = sun6i_ar100_rproc_stop(dev);
++ if (ret)
++ return ret;
++
++ return sun6i_ar100_rproc_start(dev);
++}
++
++static int sun6i_ar100_rproc_is_running(struct udevice *dev)
++{
++ struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
++
++ return !(readl_relaxed(priv->cfg_base) & BIT(0));
++}
++
++static const struct dm_rproc_ops sun6i_ar100_rproc_ops = {
++ .load = sun6i_ar100_rproc_load,
++ .start = sun6i_ar100_rproc_start,
++ .stop = sun6i_ar100_rproc_stop,
++ .reset = sun6i_ar100_rproc_reset,
++ .is_running = sun6i_ar100_rproc_is_running,
++};
++
++static int sun6i_ar100_rproc_probe(struct udevice *dev)
++{
++ struct sun6i_ar100_rproc_priv *priv = dev_get_priv(dev);
++ struct ofnode_phandle_args sram_handle;
++ int ret;
++
++ priv->cfg_base = dev_read_addr_ptr(dev);
++
++ ret = dev_read_phandle_with_args(dev, "sram", NULL, 0, 0, &sram_handle);
++ if (ret)
++ return ret;
++
++ priv->sram_base = ofnode_get_addr(sram_handle.node);
++
++ return 0;
++}
++
++static const struct udevice_id sun6i_ar100_rproc_ids[] = {
++ { .compatible = "allwinner,sun6i-a31-ar100" },
++ { }
++};
++
++U_BOOT_DRIVER(sun6i_ar100_rproc) = {
++ .name = "sun6i_ar100_rproc",
++ .id = UCLASS_REMOTEPROC,
++ .of_match = sun6i_ar100_rproc_ids,
++ .probe = sun6i_ar100_rproc_probe,
++ .priv_auto = sizeof(struct sun6i_ar100_rproc_priv),
++ .ops = &sun6i_ar100_rproc_ops,
++};
--- /dev/null
+From 2fdd94449c2668b4ff69326ff8d5daabdf2c9f00 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 15:04:16 -0500
+Subject: [PATCH 39/90] arm: dts: sunxi: h3: Add nodes for AR100 remoteproc
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/sun8i-h3.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/arch/arm/dts/sun8i-h3.dtsi
++++ b/arch/arm/dts/sun8i-h3.dtsi
+@@ -170,6 +170,14 @@
+ #size-cells = <1>;
+ ranges;
+
++ sram_a2: sram@40000 {
++ compatible = "mmio-sram";
++ reg = <0x00040000 0xc000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0x00040000 0xc000>;
++ };
++
+ sram_c: sram@1d00000 {
+ compatible = "mmio-sram";
+ reg = <0x01d00000 0x80000>;
+@@ -239,6 +247,12 @@
+ nvmem-cell-names = "calibration";
+ #thermal-sensor-cells = <0>;
+ };
++
++ remoteproc@1f01c00 {
++ compatible = "allwinner,sun6i-a31-ar100";
++ reg = <0x01f01c00 0x400>;
++ sram = <&sram_a2>;
++ };
+ };
+
+ thermal-zones {
--- /dev/null
+From aefe751d6f23c9d526bca447c6c28da97e45e528 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 17 Apr 2021 13:33:54 -0500
+Subject: [PATCH 40/90] sunxi: Enable support for SCP firmware on H3
+
+Now that issues with the BROM have been sorted out, we can implement
+PSCI system suspend on H3 by delegating to SCP firmware. Let's start by
+including the firmware in the FIT image and starting the coprocessor if
+valid firmware is loaded.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/sunxi-u-boot.dtsi | 1 +
+ board/sunxi/board.c | 8 ++++++++
+ include/configs/sun8i.h | 3 +++
+ 3 files changed, 12 insertions(+)
+
+--- a/arch/arm/dts/sunxi-u-boot.dtsi
++++ b/arch/arm/dts/sunxi-u-boot.dtsi
+@@ -9,6 +9,7 @@
+ #if defined(CONFIG_MACH_SUN8I_H3)
+ #ifdef CONFIG_ARMV7_PSCI
+ #define RESUME_ADDR SUNXI_RESUME_BASE
++#define SCP_ADDR SUNXI_SCP_BASE
+ #endif
+ #elif defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
+ #define BL31_ADDR 0x00044000
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -19,6 +19,7 @@
+ #include <init.h>
+ #include <log.h>
+ #include <mmc.h>
++#include <remoteproc.h>
+ #include <axp_pmic.h>
+ #include <generic-phy.h>
+ #include <phy-sun4i-usb.h>
+@@ -867,6 +868,13 @@ int board_late_init(void)
+ usb_ether_init();
+ #endif
+
++#ifdef CONFIG_REMOTEPROC_SUN6I_AR100
++ if (!rproc_load(0, SUNXI_SCP_BASE, SUNXI_SCP_MAX_SIZE)) {
++ puts("Starting SCP...\n");
++ rproc_start(0);
++ }
++#endif
++
+ return 0;
+ }
+
+--- a/include/configs/sun8i.h
++++ b/include/configs/sun8i.h
+@@ -12,6 +12,9 @@
+ CONFIG_ARMV7_SECURE_MAX_SIZE)
+ #define SUNXI_RESUME_SIZE 1024
+
++#define SUNXI_SCP_BASE (SUNXI_RESUME_BASE + SUNXI_RESUME_SIZE)
++#define SUNXI_SCP_MAX_SIZE (16 * 1024)
++
+ #include <configs/sunxi-common.h>
+
+ #endif /* __CONFIG_H */
--- /dev/null
+From f73116f62647c74eb0f06f0d8c29e5993d961d82 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 22:43:26 -0500
+Subject: [PATCH 41/90] arm: psci: Add definitions for PSCI v1.1
+
+Add the new option, function IDs, and prototypes for PSCI v1.1
+implementations. In the process, fix some issues with the existing
+definitions:
+ - Fix the incorrectly-named ARM_PSCI_0_2_FN64_SYSTEM_RESET2.
+ - Replace the deprecated "affinity_level" naming with "power_level".
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/cpu/armv7/Kconfig | 3 +++
+ arch/arm/cpu/armv8/fwcall.c | 2 +-
+ arch/arm/include/asm/psci.h | 9 +++++++--
+ arch/arm/include/asm/system.h | 14 +++++++++-----
+ arch/arm/lib/psci-dt.c | 2 ++
+ 5 files changed, 22 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/cpu/armv7/Kconfig
++++ b/arch/arm/cpu/armv7/Kconfig
+@@ -80,6 +80,9 @@ choice
+ help
+ Select the supported PSCI version.
+
++config ARMV7_PSCI_1_1
++ bool "PSCI V1.1"
++
+ config ARMV7_PSCI_1_0
+ bool "PSCI V1.0"
+
+--- a/arch/arm/cpu/armv8/fwcall.c
++++ b/arch/arm/cpu/armv8/fwcall.c
+@@ -103,7 +103,7 @@ void __noreturn psci_system_reset2(u32 r
+ {
+ struct pt_regs regs;
+
+- regs.regs[0] = ARM_PSCI_0_2_FN64_SYSTEM_RESET2;
++ regs.regs[0] = ARM_PSCI_1_1_FN64_SYSTEM_RESET2;
+ regs.regs[1] = PSCI_RESET2_TYPE_VENDOR | reset_level;
+ regs.regs[2] = cookie;
+ if (use_smc_for_psci)
+--- a/arch/arm/include/asm/psci.h
++++ b/arch/arm/include/asm/psci.h
+@@ -22,8 +22,9 @@
+ #include <linux/bitops.h>
+ #endif
+
+-#define ARM_PSCI_VER_1_0 (0x00010000)
+ #define ARM_PSCI_VER_0_2 (0x00000002)
++#define ARM_PSCI_VER_1_0 (0x00010000)
++#define ARM_PSCI_VER_1_1 (0x00010001)
+
+ /* PSCI 0.1 interface */
+ #define ARM_PSCI_FN_BASE 0x95c1ba5e
+@@ -68,7 +69,6 @@
+ #define ARM_PSCI_0_2_FN64_AFFINITY_INFO ARM_PSCI_0_2_FN64(4)
+ #define ARM_PSCI_0_2_FN64_MIGRATE ARM_PSCI_0_2_FN64(5)
+ #define ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ARM_PSCI_0_2_FN64(7)
+-#define ARM_PSCI_0_2_FN64_SYSTEM_RESET2 ARM_PSCI_0_2_FN64(18)
+
+ /* PSCI 1.0 interface */
+ #define ARM_PSCI_1_0_FN_PSCI_FEATURES ARM_PSCI_0_2_FN(10)
+@@ -86,6 +86,11 @@
+ #define ARM_PSCI_1_0_FN64_STAT_RESIDENCY ARM_PSCI_0_2_FN64(16)
+ #define ARM_PSCI_1_0_FN64_STAT_COUNT ARM_PSCI_0_2_FN64(17)
+
++/* PSCI 1.1 interface */
++#define ARM_PSCI_1_1_FN_SYSTEM_RESET2 ARM_PSCI_0_2_FN(18)
++
++#define ARM_PSCI_1_1_FN64_SYSTEM_RESET2 ARM_PSCI_0_2_FN64(18)
++
+ /* 1KB stack per core */
+ #define ARM_PSCI_STACK_SHIFT 10
+ #define ARM_PSCI_STACK_SIZE (1 << ARM_PSCI_STACK_SHIFT)
+--- a/arch/arm/include/asm/system.h
++++ b/arch/arm/include/asm/system.h
+@@ -557,16 +557,20 @@ void mmu_page_table_flush(unsigned long
+ #ifdef CONFIG_ARMV7_PSCI
+ void psci_arch_cpu_entry(void);
+ void psci_arch_init(void);
++
+ u32 psci_version(void);
+-s32 psci_features(u32 function_id, u32 psci_fid);
++s32 psci_cpu_suspend(u32 function_id, u32 power_state, u32 pc, u32 context_id);
+ s32 psci_cpu_off(void);
+-s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
+- u32 context_id);
+-s32 psci_affinity_info(u32 function_id, u32 target_affinity,
+- u32 lowest_affinity_level);
++s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, u32 context_id);
++s32 psci_affinity_info(u32 function_id, u32 target_affinity, u32 power_level);
+ u32 psci_migrate_info_type(void);
+ void psci_system_off(void);
+ void psci_system_reset(void);
++s32 psci_features(u32 function_id, u32 psci_fid);
++s32 psci_cpu_default_suspend(u32 function_id, u32 pc, u32 context_id);
++s32 psci_node_hw_state(u32 function_id, u32 target_cpu, u32 power_level);
++s32 psci_system_suspend(u32 function_id, u32 pc, u32 context_id);
++s32 psci_system_reset2(u32 function_id, u32 reset_type, u32 cookie);
+ #endif
+
+ #endif /* __ASSEMBLY__ */
+--- a/arch/arm/lib/psci-dt.c
++++ b/arch/arm/lib/psci-dt.c
+@@ -66,6 +66,8 @@ int fdt_psci(void *fdt)
+ init_psci_node:
+ #if CONFIG_IS_ENABLED(ARMV8_SEC_FIRMWARE_SUPPORT)
+ psci_ver = sec_firmware_support_psci_version();
++#elif defined(CONFIG_ARMV7_PSCI_1_1)
++ psci_ver = ARM_PSCI_VER_1_1;
+ #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
+ psci_ver = ARM_PSCI_VER_1_0;
+ #elif defined(CONFIG_ARMV7_PSCI_0_2)
--- /dev/null
+From 6dc0da83dba9570740365d0f1b32f91ae8ba0998 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 11 Oct 2021 03:20:28 -0500
+Subject: [PATCH 42/90] sunxi: Enable remoteproc on some H3 boards
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ configs/orangepi_one_defconfig | 1 +
+ configs/orangepi_plus2e_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/configs/orangepi_one_defconfig
++++ b/configs/orangepi_one_defconfig
+@@ -6,5 +6,6 @@ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=672
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
++CONFIG_REMOTEPROC_SUN6I_AR100=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_OHCI_HCD=y
+--- a/configs/orangepi_plus2e_defconfig
++++ b/configs/orangepi_plus2e_defconfig
+@@ -12,5 +12,6 @@ CONFIG_SPL_SYS_I2C_LEGACY=y
+ CONFIG_SYS_I2C_MVTWSI=y
+ CONFIG_SUN8I_EMAC=y
+ CONFIG_SY8106A_POWER=y
++CONFIG_REMOTEPROC_SUN6I_AR100=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_OHCI_HCD=y
--- /dev/null
+From 650fab5c589a883b139b4164527101f9c849f1a5 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 9 Oct 2021 23:01:05 -0500
+Subject: [PATCH 43/90] sunxi: psci: Delegate PSCI to SCPI
+
+This adds a new PSCI implementation which communicates with SCP firmware
+running on the AR100 using the SCPI protocol. This allows it to support
+the full set of PSCI v1.1 features, including CPU idle states, system
+suspend, and multiple reset methods.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/cpu/armv7/Kconfig | 1 +
+ arch/arm/cpu/armv7/sunxi/Makefile | 4 +
+ arch/arm/cpu/armv7/sunxi/psci-scpi.c | 451 +++++++++++++++++++++++++++
+ 3 files changed, 456 insertions(+)
+ create mode 100644 arch/arm/cpu/armv7/sunxi/psci-scpi.c
+
+--- a/arch/arm/cpu/armv7/Kconfig
++++ b/arch/arm/cpu/armv7/Kconfig
+@@ -75,6 +75,7 @@ config ARMV7_PSCI
+ choice
+ prompt "Supported PSCI version"
+ depends on ARMV7_PSCI
++ default ARMV7_PSCI_1_1 if MACH_SUN8I_H3
+ default ARMV7_PSCI_0_1 if ARCH_SUNXI
+ default ARMV7_PSCI_1_0
+ help
+--- a/arch/arm/cpu/armv7/sunxi/Makefile
++++ b/arch/arm/cpu/armv7/sunxi/Makefile
+@@ -13,8 +13,12 @@ obj-$(CONFIG_MACH_SUN6I) += sram.o
+ obj-$(CONFIG_MACH_SUN8I) += sram.o
+
+ ifndef CONFIG_SPL_BUILD
++ifdef CONFIG_MACH_SUN8I_H3
++obj-$(CONFIG_ARMV7_PSCI) += psci-scpi.o
++else
+ obj-$(CONFIG_ARMV7_PSCI) += psci.o
+ endif
++endif
+
+ ifdef CONFIG_SPL_BUILD
+ obj-y += fel_utils.o
+--- /dev/null
++++ b/arch/arm/cpu/armv7/sunxi/psci-scpi.c
+@@ -0,0 +1,451 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
++ * Copyright (C) 2018-2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#include <common.h>
++#include <asm/arch/cpu.h>
++#include <asm/arch/cpucfg.h>
++#include <asm/armv7.h>
++#include <asm/gic.h>
++#include <asm/io.h>
++#include <asm/psci.h>
++#include <asm/secure.h>
++#include <asm/system.h>
++
++#define GICD_BASE (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
++#define GICC_BASE (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
++
++#define HW_ON 0
++#define HW_OFF 1
++#define HW_STANDBY 2
++
++#define MPIDR_AFFLVL0(mpidr) (mpidr & 0xf)
++#define MPIDR_AFFLVL1(mpidr) (mpidr >> 8 & 0xf)
++
++#define SCPI_SHMEM_BASE 0x0004be00
++#define SCPI_SHMEM ((struct scpi_shmem *)SCPI_SHMEM_BASE)
++
++#define SCPI_RX_CHANNEL 1
++#define SCPI_TX_CHANNEL 0
++#define SCPI_VIRTUAL_CHANNEL BIT(0)
++
++#define SCPI_MESSAGE_SIZE 0x100
++#define SCPI_PAYLOAD_SIZE (SCPI_MESSAGE_SIZE - sizeof(struct scpi_header))
++
++#define SUNXI_MSGBOX_BASE 0x01c17000
++#define REMOTE_IRQ_STAT_REG (SUNXI_MSGBOX_BASE + 0x0050)
++#define LOCAL_IRQ_STAT_REG (SUNXI_MSGBOX_BASE + 0x0070)
++#define MSG_STAT_REG(n) (SUNXI_MSGBOX_BASE + 0x0140 + 0x4 * (n))
++#define MSG_DATA_REG(n) (SUNXI_MSGBOX_BASE + 0x0180 + 0x4 * (n))
++
++#define RX_IRQ(n) BIT(0 + 2 * (n))
++#define TX_IRQ(n) BIT(1 + 2 * (n))
++
++enum {
++ CORE_POWER_LEVEL = 0,
++ CLUSTER_POWER_LEVEL = 1,
++ CSS_POWER_LEVEL = 2,
++};
++
++enum {
++ SCPI_CMD_SCP_READY = 0x01,
++ SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
++ SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
++ SCPI_CMD_SET_SYS_POWER_STATE = 0x05,
++};
++
++enum {
++ SCPI_E_OK = 0,
++ SCPI_E_PARAM = 1,
++ SCPI_E_ALIGN = 2,
++ SCPI_E_SIZE = 3,
++ SCPI_E_HANDLER = 4,
++ SCPI_E_ACCESS = 5,
++ SCPI_E_RANGE = 6,
++ SCPI_E_TIMEOUT = 7,
++ SCPI_E_NOMEM = 8,
++ SCPI_E_PWRSTATE = 9,
++ SCPI_E_SUPPORT = 10,
++ SCPI_E_DEVICE = 11,
++ SCPI_E_BUSY = 12,
++ SCPI_E_OS = 13,
++ SCPI_E_DATA = 14,
++ SCPI_E_STATE = 15,
++};
++
++enum {
++ SCPI_POWER_ON = 0x00,
++ SCPI_POWER_RETENTION = 0x01,
++ SCPI_POWER_OFF = 0x03,
++};
++
++enum {
++ SCPI_SYSTEM_SHUTDOWN = 0x00,
++ SCPI_SYSTEM_REBOOT = 0x01,
++ SCPI_SYSTEM_RESET = 0x02,
++};
++
++struct scpi_header {
++ u8 command;
++ u8 sender;
++ u16 size;
++ u32 status;
++};
++
++struct scpi_message {
++ struct scpi_header header;
++ u8 payload[SCPI_PAYLOAD_SIZE];
++};
++
++struct scpi_shmem {
++ struct scpi_message rx;
++ struct scpi_message tx;
++};
++
++static bool __secure_data gic_dist_init;
++
++static u32 __secure_data lock;
++
++static inline u32 __secure read_mpidr(void)
++{
++ u32 val;
++
++ asm volatile ("mrc p15, 0, %0, c0, c0, 5" : "=r" (val));
++
++ return val;
++}
++
++static void __secure scpi_begin_command(void)
++{
++ u32 mpidr = read_mpidr();
++
++ do {
++ while (readl(&lock));
++ writel(mpidr, &lock);
++ dsb();
++ } while (readl(&lock) != mpidr);
++ while (readl(REMOTE_IRQ_STAT_REG) & RX_IRQ(SCPI_TX_CHANNEL));
++}
++
++static void __secure scpi_send_command(void)
++{
++ writel(SCPI_VIRTUAL_CHANNEL, MSG_DATA_REG(SCPI_TX_CHANNEL));
++}
++
++static void __secure scpi_wait_response(void)
++{
++ while (!readl(MSG_STAT_REG(SCPI_RX_CHANNEL)));
++}
++
++static void __secure scpi_end_command(void)
++{
++ while (readl(MSG_STAT_REG(SCPI_RX_CHANNEL)))
++ readl(MSG_DATA_REG(SCPI_RX_CHANNEL));
++ writel(RX_IRQ(SCPI_RX_CHANNEL), LOCAL_IRQ_STAT_REG);
++ writel(0, &lock);
++}
++
++static void __secure scpi_set_css_power_state(u32 target_cpu, u32 core_state,
++ u32 cluster_state, u32 css_state)
++{
++ struct scpi_shmem *shmem = SCPI_SHMEM;
++
++ scpi_begin_command();
++
++ shmem->tx.header.command = SCPI_CMD_SET_CSS_POWER_STATE;
++ shmem->tx.header.size = 4;
++
++ shmem->tx.payload[0] = target_cpu >> 4 | target_cpu;
++ shmem->tx.payload[1] = cluster_state << 4 | core_state;
++ shmem->tx.payload[2] = css_state;
++ shmem->tx.payload[3] = 0;
++
++ scpi_send_command();
++ scpi_end_command();
++}
++
++static s32 __secure scpi_get_css_power_state(u32 target_cpu, u8 *core_states,
++ u8 *cluster_state)
++{
++ struct scpi_shmem *shmem = SCPI_SHMEM;
++ u32 cluster = MPIDR_AFFLVL1(target_cpu);
++ u32 offset;
++ s32 ret;
++
++ scpi_begin_command();
++
++ shmem->tx.header.command = SCPI_CMD_GET_CSS_POWER_STATE;
++ shmem->tx.header.size = 0;
++
++ scpi_send_command();
++ scpi_wait_response();
++
++ for (offset = 0; offset < shmem->rx.header.size; offset += 2) {
++ if ((shmem->rx.payload[offset] & 0xf) == cluster) {
++ *cluster_state = shmem->rx.payload[offset+0] >> 4;
++ *core_states = shmem->rx.payload[offset+1];
++
++ break;
++ }
++ }
++
++ ret = shmem->rx.header.status;
++
++ scpi_end_command();
++
++ return ret;
++}
++
++static s32 __secure scpi_set_sys_power_state(u32 sys_state)
++{
++ struct scpi_shmem *shmem = SCPI_SHMEM;
++ s32 ret;
++
++ scpi_begin_command();
++
++ shmem->tx.header.command = SCPI_CMD_SET_SYS_POWER_STATE;
++ shmem->tx.header.size = 1;
++
++ shmem->tx.payload[0] = sys_state;
++
++ scpi_send_command();
++ scpi_wait_response();
++
++ ret = shmem->rx.header.status;
++
++ scpi_end_command();
++
++ return ret;
++}
++
++void psci_enable_smp(void);
++
++static s32 __secure psci_suspend_common(u32 pc, u32 context_id, u32 core_state,
++ u32 cluster_state, u32 css_state)
++
++{
++ u32 target_cpu = read_mpidr();
++
++ if (core_state == SCPI_POWER_OFF)
++ psci_save(MPIDR_AFFLVL0(target_cpu), pc, context_id);
++ if (css_state == SCPI_POWER_OFF)
++ gic_dist_init = true;
++
++ scpi_set_css_power_state(target_cpu, core_state,
++ cluster_state, css_state);
++
++ psci_cpu_off_common();
++
++ wfi();
++
++ psci_enable_smp();
++
++ return ARM_PSCI_RET_SUCCESS;
++}
++
++u32 __secure psci_version(void)
++{
++ return ARM_PSCI_VER_1_1;
++}
++
++s32 __secure psci_cpu_suspend(u32 __always_unused function_id,
++ u32 power_state, u32 pc, u32 context_id)
++{
++ return psci_suspend_common(pc, context_id,
++ power_state >> 0 & 0xf,
++ power_state >> 4 & 0xf,
++ power_state >> 8 & 0xf);
++}
++
++s32 __secure psci_cpu_off(void)
++{
++ u32 pc = 0, context_id = 0;
++
++ return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
++ SCPI_POWER_OFF, SCPI_POWER_ON);
++}
++
++s32 __secure psci_cpu_on(u32 __always_unused function_id,
++ u32 target_cpu, u32 pc, u32 context_id)
++{
++ psci_save(MPIDR_AFFLVL0(target_cpu), pc, context_id);
++
++ scpi_set_css_power_state(target_cpu, SCPI_POWER_ON,
++ SCPI_POWER_ON, SCPI_POWER_ON);
++
++ return ARM_PSCI_RET_SUCCESS;
++}
++
++s32 __secure psci_affinity_info(u32 function_id,
++ u32 target_cpu, u32 power_level)
++{
++ if (power_level != CORE_POWER_LEVEL)
++ return ARM_PSCI_RET_INVAL;
++
++ /* This happens to have the same HW_ON/HW_OFF encoding. */
++ return psci_node_hw_state(function_id, target_cpu, power_level);
++}
++
++void __secure psci_system_off(void)
++{
++ scpi_set_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
++
++ /* Wait to be turned off. */
++ for (;;) wfi();
++}
++
++void __secure psci_system_reset(void)
++{
++ scpi_set_sys_power_state(SCPI_SYSTEM_REBOOT);
++
++ /* Wait to be turned off. */
++ for (;;) wfi();
++}
++
++s32 __secure psci_features(u32 __always_unused function_id,
++ u32 psci_fid)
++{
++ switch (psci_fid) {
++ case ARM_PSCI_0_2_FN_PSCI_VERSION:
++ case ARM_PSCI_0_2_FN_CPU_SUSPEND:
++ case ARM_PSCI_0_2_FN_CPU_OFF:
++ case ARM_PSCI_0_2_FN_CPU_ON:
++ case ARM_PSCI_0_2_FN_AFFINITY_INFO:
++ case ARM_PSCI_0_2_FN_SYSTEM_OFF:
++ case ARM_PSCI_0_2_FN_SYSTEM_RESET:
++ case ARM_PSCI_1_0_FN_PSCI_FEATURES:
++ case ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND:
++ case ARM_PSCI_1_0_FN_NODE_HW_STATE:
++ case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND:
++ case ARM_PSCI_1_1_FN_SYSTEM_RESET2:
++ return ARM_PSCI_RET_SUCCESS;
++ default:
++ return ARM_PSCI_RET_NI;
++ }
++}
++
++s32 __secure psci_cpu_default_suspend(u32 __always_unused function_id,
++ u32 pc, u32 context_id)
++{
++ return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
++ SCPI_POWER_OFF, SCPI_POWER_RETENTION);
++}
++
++s32 __secure psci_node_hw_state(u32 __always_unused function_id,
++ u32 target_cpu, u32 power_level)
++{
++ u32 core = MPIDR_AFFLVL0(target_cpu);
++ u8 core_states, cluster_state;
++
++ if (power_level >= CSS_POWER_LEVEL)
++ return HW_ON;
++ if (scpi_get_css_power_state(target_cpu, &core_states, &cluster_state))
++ return ARM_PSCI_RET_NI;
++ if (power_level == CLUSTER_POWER_LEVEL) {
++ if (cluster_state == SCPI_POWER_ON)
++ return HW_ON;
++ if (cluster_state < SCPI_POWER_OFF)
++ return HW_STANDBY;
++ return HW_OFF;
++ }
++
++ return (core_states & BIT(core)) ? HW_ON : HW_OFF;
++}
++
++s32 __secure psci_system_suspend(u32 __always_unused function_id,
++ u32 pc, u32 context_id)
++{
++ return psci_suspend_common(pc, context_id, SCPI_POWER_OFF,
++ SCPI_POWER_OFF, SCPI_POWER_OFF);
++}
++
++s32 __secure psci_system_reset2(u32 __always_unused function_id,
++ u32 reset_type, u32 cookie)
++{
++ s32 ret;
++
++ if (reset_type)
++ return ARM_PSCI_RET_INVAL;
++
++ ret = scpi_set_sys_power_state(SCPI_SYSTEM_RESET);
++ if (ret)
++ return ARM_PSCI_RET_INVAL;
++
++ /* Wait to be turned off. */
++ for (;;) wfi();
++}
++
++/*
++ * R40 is different from other single cluster SoCs. The secondary core
++ * entry address register is in the SRAM controller address range.
++ */
++#define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0 (0xbc)
++
++#ifdef CONFIG_MACH_SUN8I_R40
++/* secondary core entry address is programmed differently on R40 */
++static void __secure sunxi_set_entry_address(void *entry)
++{
++ writel((u32)entry,
++ SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
++}
++#else
++static void __secure sunxi_set_entry_address(void *entry)
++{
++ struct sunxi_cpucfg_reg *cpucfg =
++ (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++
++ writel((u32)entry, &cpucfg->priv0);
++
++#ifdef CONFIG_MACH_SUN8I_H3
++ /* Redirect CPU 0 to the secure monitor via the resume shim. */
++ writel(0x16aaefe8, &cpucfg->super_standy_flag);
++ writel(0xaa16efe8, &cpucfg->super_standy_flag);
++ writel(SUNXI_RESUME_BASE, &cpucfg->priv1);
++#endif
++}
++#endif
++
++void __secure psci_arch_init(void)
++{
++ static bool __secure_data one_time_init = true;
++
++ if (one_time_init) {
++ /* Set secondary core power-on PC. */
++ sunxi_set_entry_address(psci_cpu_entry);
++
++ /* Wait for the SCP firmware to boot. */
++ scpi_begin_command();
++ scpi_wait_response();
++ scpi_end_command();
++
++ one_time_init = false;
++ }
++
++ /*
++ * Copied from arch/arm/cpu/armv7/virt-v7.c
++ * See also gic_resume() in arch/arm/mach-imx/mx7/psci-mx7.c
++ */
++ if (gic_dist_init) {
++ u32 i, itlinesnr;
++
++ /* enable the GIC distributor */
++ writel(readl(GICD_BASE + GICD_CTLR) | 0x03, GICD_BASE + GICD_CTLR);
++
++ /* TYPER[4:0] contains an encoded number of available interrupts */
++ itlinesnr = readl(GICD_BASE + GICD_TYPER) & 0x1f;
++
++ /* set all bits in the GIC group registers to one to allow access
++ * from non-secure state. The first 32 interrupts are private per
++ * CPU and will be set later when enabling the GIC for each core
++ */
++ for (i = 1; i <= itlinesnr; i++)
++ writel((unsigned)-1, GICD_BASE + GICD_IGROUPRn + 4 * i);
++
++ gic_dist_init = false;
++ }
++
++ /* Be cool with non-secure. */
++ writel(0xff, GICC_BASE + GICC_PMR);
++}
--- /dev/null
+From 5a7a91bf9a78a3a73e26d6de975261e62f9fb127 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 8 Jun 2022 07:55:54 -0500
+Subject: [PATCH 44/90] sunxi: Enable SCP/SCPI on A33 as well
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/cpu/armv7/Kconfig | 2 +-
+ arch/arm/cpu/armv7/sunxi/Makefile | 2 +-
+ arch/arm/cpu/armv7/sunxi/psci-scpi.c | 4 ++++
+ arch/arm/dts/sun8i-a23-a33.dtsi | 14 ++++++++++++++
+ arch/arm/dts/sunxi-u-boot.dtsi | 4 ++--
+ 5 files changed, 22 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/cpu/armv7/Kconfig
++++ b/arch/arm/cpu/armv7/Kconfig
+@@ -75,7 +75,7 @@ config ARMV7_PSCI
+ choice
+ prompt "Supported PSCI version"
+ depends on ARMV7_PSCI
+- default ARMV7_PSCI_1_1 if MACH_SUN8I_H3
++ default ARMV7_PSCI_1_1 if MACH_SUN8I_A33 || MACH_SUN8I_H3
+ default ARMV7_PSCI_0_1 if ARCH_SUNXI
+ default ARMV7_PSCI_1_0
+ help
+--- a/arch/arm/cpu/armv7/sunxi/Makefile
++++ b/arch/arm/cpu/armv7/sunxi/Makefile
+@@ -13,7 +13,7 @@ obj-$(CONFIG_MACH_SUN6I) += sram.o
+ obj-$(CONFIG_MACH_SUN8I) += sram.o
+
+ ifndef CONFIG_SPL_BUILD
+-ifdef CONFIG_MACH_SUN8I_H3
++ifneq ($(CONFIG_MACH_SUN8I_A33)$(CONFIG_MACH_SUN8I_H3),)
+ obj-$(CONFIG_ARMV7_PSCI) += psci-scpi.o
+ else
+ obj-$(CONFIG_ARMV7_PSCI) += psci.o
+--- a/arch/arm/cpu/armv7/sunxi/psci-scpi.c
++++ b/arch/arm/cpu/armv7/sunxi/psci-scpi.c
+@@ -24,7 +24,11 @@
+ #define MPIDR_AFFLVL0(mpidr) (mpidr & 0xf)
+ #define MPIDR_AFFLVL1(mpidr) (mpidr >> 8 & 0xf)
+
++#if defined(CONFIG_MACH_SUN8I_H3)
+ #define SCPI_SHMEM_BASE 0x0004be00
++#else
++#define SCPI_SHMEM_BASE 0x00053e00
++#endif
+ #define SCPI_SHMEM ((struct scpi_shmem *)SCPI_SHMEM_BASE)
+
+ #define SCPI_RX_CHANNEL 1
+--- a/arch/arm/dts/sun8i-a23-a33.dtsi
++++ b/arch/arm/dts/sun8i-a23-a33.dtsi
+@@ -138,6 +138,14 @@
+ #size-cells = <1>;
+ ranges;
+
++ sram_a2: sram@40000 {
++ compatible = "mmio-sram";
++ reg = <0x00040000 0x14000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0x00040000 0x14000>;
++ };
++
+ sram_c: sram@1d00000 {
+ compatible = "mmio-sram";
+ reg = <0x01d00000 0x80000>;
+@@ -847,5 +855,11 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ remoteproc@1f01c00 {
++ compatible = "allwinner,sun6i-a31-ar100";
++ reg = <0x01f01c00 0x400>;
++ sram = <&sram_a2>;
++ };
+ };
+ };
+--- a/arch/arm/dts/sunxi-u-boot.dtsi
++++ b/arch/arm/dts/sunxi-u-boot.dtsi
+@@ -6,11 +6,11 @@
+ #define ARCH "arm"
+ #endif
+
++#if defined(CONFIG_ARMV7_PSCI) && (defined(CONFIG_MACH_SUN8I_A33) || defined(CONFIG_MACH_SUN8I_H3))
+ #if defined(CONFIG_MACH_SUN8I_H3)
+-#ifdef CONFIG_ARMV7_PSCI
+ #define RESUME_ADDR SUNXI_RESUME_BASE
+-#define SCP_ADDR SUNXI_SCP_BASE
+ #endif
++#define SCP_ADDR SUNXI_SCP_BASE
+ #elif defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H5)
+ #define BL31_ADDR 0x00044000
+ #define SCP_ADDR 0x00050000
--- /dev/null
+From afa281decfbb174f57341897e0ad50ee9ad3564f Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 17:59:24 +0000
+Subject: [PATCH 45/90] phy: sun4i-usb: Use DM_GPIO for id/vbus_det GPIOs
+
+Now that the sunxi_gpio driver handles pull-up/down via the driver
+model, we can switch to DM_GPIO for these pins with no loss in
+functionality. Since the driver now gets its pin configuration from
+the device tree, we can remove the Kconfig symbols.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/sun5i-a13-ampe-a76.dts | 6 ++
+ .../sun6i-a31s-yones-toptech-bs1078-v2.dts | 1 +
+ arch/arm/dts/sun8i-a33-sinlinx-sina33.dts | 1 +
+ arch/arm/mach-sunxi/Kconfig | 14 ----
+ drivers/phy/allwinner/phy-sun4i-usb.c | 71 ++++---------------
+ 5 files changed, 22 insertions(+), 71 deletions(-)
+
+--- a/arch/arm/dts/sun5i-a13-ampe-a76.dts
++++ b/arch/arm/dts/sun5i-a13-ampe-a76.dts
+@@ -8,6 +8,8 @@
+ /dts-v1/;
+ #include "sun5i-a13.dtsi"
+
++#include <dt-bindings/gpio/gpio.h>
++
+ / {
+ model = "Ampe A76";
+ compatible = "ampe,a76", "allwinner,sun5i-a13";
+@@ -26,3 +28,7 @@
+ pinctrl-0 = <&uart1_pg_pins>;
+ status = "okay";
+ };
++
++&usbphy {
++ usb0_id_det-gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
++};
+--- a/arch/arm/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
++++ b/arch/arm/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+@@ -176,6 +176,7 @@
+ };
+
+ &usbphy {
++ usb0_id_det-gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; /* PA15 */
+ usb1_vbus-supply = <®_dldo1>;
+ usb2_vbus-supply = <®_dc1sw>;
+ status = "okay";
+--- a/arch/arm/dts/sun8i-a33-sinlinx-sina33.dts
++++ b/arch/arm/dts/sun8i-a33-sinlinx-sina33.dts
+@@ -271,5 +271,6 @@
+
+ &usbphy {
+ status = "okay";
++ usb0_id_det-gpios = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */
+ usb1_vbus-supply = <®_vcc5v0>; /* USB1 VBUS is always on */
+ };
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -655,20 +655,6 @@ config MMC_SUNXI_SLOT_EXTRA
+ slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable
+ support for this.
+
+-config USB0_VBUS_DET
+- string "Vbus detect pin for usb0 (otg)"
+- default ""
+- ---help---
+- Set the Vbus detect pin for usb0 (otg). This takes a string in the
+- format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+-
+-config USB0_ID_DET
+- string "ID detect pin for usb0 (otg)"
+- default ""
+- ---help---
+- Set the ID detect pin for usb0 (otg). This takes a string in the
+- format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+-
+ config I2C0_ENABLE
+ bool "Enable I2C/TWI controller 0"
+ default y if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_R40
+--- a/drivers/phy/allwinner/phy-sun4i-usb.c
++++ b/drivers/phy/allwinner/phy-sun4i-usb.c
+@@ -96,32 +96,8 @@ struct sun4i_usb_phy_cfg {
+ int missing_phys;
+ };
+
+-struct sun4i_usb_phy_info {
+- const char *gpio_vbus_det;
+- const char *gpio_id_det;
+-} phy_info[] = {
+- {
+- .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
+- .gpio_id_det = CONFIG_USB0_ID_DET,
+- },
+- {
+- .gpio_vbus_det = NULL,
+- .gpio_id_det = NULL,
+- },
+- {
+- .gpio_vbus_det = NULL,
+- .gpio_id_det = NULL,
+- },
+- {
+- .gpio_vbus_det = NULL,
+- .gpio_id_det = NULL,
+- },
+-};
+-
+ struct sun4i_usb_phy_plat {
+ void __iomem *pmu;
+- struct gpio_desc gpio_vbus_det;
+- struct gpio_desc gpio_id_det;
+ struct clk clocks;
+ struct reset_ctl resets;
+ struct udevice *vbus;
+@@ -132,6 +108,8 @@ struct sun4i_usb_phy_data {
+ void __iomem *base;
+ const struct sun4i_usb_phy_cfg *cfg;
+ struct sun4i_usb_phy_plat *usb_phy;
++ struct gpio_desc id_det_gpio;
++ struct gpio_desc vbus_det_gpio;
+ struct udevice *vbus_power_supply;
+ };
+
+@@ -393,11 +371,10 @@ static int sun4i_usb_phy_xlate(struct ph
+ int sun4i_usb_phy_vbus_detect(struct phy *phy)
+ {
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+- struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+ int err = 1, retries = 3;
+
+- if (dm_gpio_is_valid(&usb_phy->gpio_vbus_det)) {
+- err = dm_gpio_get_value(&usb_phy->gpio_vbus_det);
++ if (dm_gpio_is_valid(&data->vbus_det_gpio)) {
++ err = dm_gpio_get_value(&data->vbus_det_gpio);
+ /*
+ * Vbus may have been provided by the board and just turned off
+ * some milliseconds ago on reset. What we're measuring then is
+@@ -405,7 +382,7 @@ int sun4i_usb_phy_vbus_detect(struct phy
+ */
+ while (err > 0 && retries--) {
+ mdelay(100);
+- err = dm_gpio_get_value(&usb_phy->gpio_vbus_det);
++ err = dm_gpio_get_value(&data->vbus_det_gpio);
+ }
+ } else if (data->vbus_power_supply) {
+ err = regulator_get_enable(data->vbus_power_supply);
+@@ -417,12 +394,11 @@ int sun4i_usb_phy_vbus_detect(struct phy
+ int sun4i_usb_phy_id_detect(struct phy *phy)
+ {
+ struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
+- struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
+
+- if (!dm_gpio_is_valid(&usb_phy->gpio_id_det))
+- return -1;
++ if (!dm_gpio_is_valid(&data->id_det_gpio))
++ return -EOPNOTSUPP;
+
+- return dm_gpio_get_value(&usb_phy->gpio_id_det);
++ return dm_gpio_get_value(&data->id_det_gpio);
+ }
+
+ void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled)
+@@ -452,13 +428,18 @@ static int sun4i_usb_phy_probe(struct ud
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
++ gpio_request_by_name(dev, "usb0_id_det-gpios", 0, &data->id_det_gpio,
++ GPIOD_IS_IN | GPIOD_PULL_UP);
++
++ gpio_request_by_name(dev, "usb0_vbus_det-gpios", 0, &data->vbus_det_gpio,
++ GPIOD_IS_IN);
++
+ device_get_supply_regulator(dev, "usb0_vbus_power-supply",
+ &data->vbus_power_supply);
+
+ data->usb_phy = plat;
+ for (i = 0; i < data->cfg->num_phys; i++) {
+ struct sun4i_usb_phy_plat *phy = &plat[i];
+- struct sun4i_usb_phy_info *info = &phy_info[i];
+ char name[20];
+
+ if (data->cfg->missing_phys & BIT(i))
+@@ -472,30 +453,6 @@ static int sun4i_usb_phy_probe(struct ud
+ return ret;
+ }
+
+- ret = dm_gpio_lookup_name(info->gpio_vbus_det,
+- &phy->gpio_vbus_det);
+- if (ret == 0) {
+- ret = dm_gpio_request(&phy->gpio_vbus_det,
+- "usb_vbus_det");
+- if (ret)
+- return ret;
+- ret = dm_gpio_set_dir_flags(&phy->gpio_vbus_det,
+- GPIOD_IS_IN);
+- if (ret)
+- return ret;
+- }
+-
+- ret = dm_gpio_lookup_name(info->gpio_id_det, &phy->gpio_id_det);
+- if (ret == 0) {
+- ret = dm_gpio_request(&phy->gpio_id_det, "usb_id_det");
+- if (ret)
+- return ret;
+- ret = dm_gpio_set_dir_flags(&phy->gpio_id_det,
+- GPIOD_IS_IN | GPIOD_PULL_UP);
+- if (ret)
+- return ret;
+- }
+-
+ if (data->cfg->dedicated_clocks)
+ snprintf(name, sizeof(name), "usb%d_phy", i);
+ else
--- /dev/null
+From 9e34036e651528df9575c2ffb38d78ae1f613481 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 21 Aug 2021 17:11:54 -0500
+Subject: [PATCH 46/90] ARM: dts: sunxi: Add AXP221 and AXP809 GPIO nodes
+
+These PMICs each have two GPIO pins, and are supported by the axp_gpio
+driver. In order to convert the axp_gpio driver to probe using the
+device tree, the corresponding device tree nodes must be present. Add
+them, following the same binding as the AXP209 and AXP813.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/dts/axp22x.dtsi | 6 ++++++
+ arch/arm/dts/axp809.dtsi | 7 +++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/arch/arm/dts/axp22x.dtsi
++++ b/arch/arm/dts/axp22x.dtsi
+@@ -67,6 +67,12 @@
+ status = "disabled";
+ };
+
++ axp_gpio: gpio {
++ compatible = "x-powers,axp221-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ };
++
+ regulators {
+ /* Default work frequency for buck regulators */
+ x-powers,dcdc-freq = <3000>;
+--- a/arch/arm/dts/axp809.dtsi
++++ b/arch/arm/dts/axp809.dtsi
+@@ -50,4 +50,11 @@
+ compatible = "x-powers,axp809";
+ interrupt-controller;
+ #interrupt-cells = <1>;
++
++ axp_gpio: gpio {
++ compatible = "x-powers,axp809-gpio",
++ "x-powers,axp221-gpio";
++ gpio-controller;
++ #gpio-cells = <2>;
++ };
+ };
--- /dev/null
+From 7e85c2d6516e47b537b27132d1946d1eab3b8923 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 27 Aug 2021 17:39:36 -0500
+Subject: [PATCH 47/90] gpio: axp: Consistently use the "axp_gpio" order
+
+This is less confusing than half of the driver using "axp_gpio" and the
+other half using "gpio_axp".
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/axp_gpio.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -89,14 +89,14 @@ static int axp_gpio_set_value(struct ude
+ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+
+-static const struct dm_gpio_ops gpio_axp_ops = {
++static const struct dm_gpio_ops axp_gpio_ops = {
+ .direction_input = axp_gpio_direction_input,
+ .direction_output = axp_gpio_direction_output,
+ .get_value = axp_gpio_get_value,
+ .set_value = axp_gpio_set_value,
+ };
+
+-static int gpio_axp_probe(struct udevice *dev)
++static int axp_gpio_probe(struct udevice *dev)
+ {
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+@@ -107,11 +107,11 @@ static int gpio_axp_probe(struct udevice
+ return 0;
+ }
+
+-U_BOOT_DRIVER(gpio_axp) = {
+- .name = "gpio_axp",
+- .id = UCLASS_GPIO,
+- .ops = &gpio_axp_ops,
+- .probe = gpio_axp_probe,
++U_BOOT_DRIVER(axp_gpio) = {
++ .name = "axp_gpio",
++ .id = UCLASS_GPIO,
++ .probe = axp_gpio_probe,
++ .ops = &axp_gpio_ops,
+ };
+
+ int axp_gpio_init(void)
+@@ -124,7 +124,7 @@ int axp_gpio_init(void)
+ return ret;
+
+ /* There is no devicetree support for the axp yet, so bind directly */
+- ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev);
++ ret = device_bind_driver(dm_root(), "axp_gpio", "AXP-gpio", &dev);
+ if (ret)
+ return ret;
+
--- /dev/null
+From a39b1bd1ad0babb355a5cb6f6a3bd8e378433b54 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 27 Aug 2021 21:43:19 -0500
+Subject: [PATCH 48/90] gpio: axp: Bind via device tree
+
+Now that the PMIC has a DM driver and binds device tree subnodes, the
+GPIO device can be bound that way, instead of from inside board code.
+
+Since the driver still uses the single set of register definitions from
+axpXXX.h (as selected by AXPxxx_POWER), it does not differentiate among
+the supported compatibles.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h | 6 -----
+ arch/arm/mach-sunxi/Kconfig | 6 -----
+ board/sunxi/board.c | 4 ---
+ drivers/gpio/Kconfig | 8 ++++++
+ drivers/gpio/axp_gpio.c | 34 +++++++++++---------------
+ 5 files changed, 22 insertions(+), 36 deletions(-)
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -219,10 +219,4 @@ void sunxi_gpio_set_pull(u32 pin, u32 va
+ void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val);
+ int sunxi_name_to_gpio(const char *name);
+
+-#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
+-int axp_gpio_init(void);
+-#else
+-static inline int axp_gpio_init(void) { return 0; }
+-#endif
+-
+ #endif /* _SUNXI_GPIO_H */
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -682,12 +682,6 @@ config R_I2C_ENABLE
+ Set this to y to enable the I2C controller which is part of the PRCM.
+ endif
+
+-config AXP_GPIO
+- bool "Enable support for gpio-s on axp PMICs"
+- depends on AXP_PMIC_BUS
+- ---help---
+- Say Y here to enable support for the gpio pins of the axp PMIC ICs.
+-
+ config AXP_DISABLE_BOOT_ON_POWERON
+ bool "Disable device boot on power plug-in"
+ depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -221,10 +221,6 @@ int board_init(void)
+ }
+ #endif /* !CONFIG_ARM64 && !CONFIG_MACH_SUNIV */
+
+- ret = axp_gpio_init();
+- if (ret)
+- return ret;
+-
+ /* strcmp() would look better, but doesn't get optimised away. */
+ if (CONFIG_SATAPWR[0]) {
+ satapwr_pin = sunxi_name_to_gpio(CONFIG_SATAPWR);
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -104,6 +104,14 @@ config ALTERA_PIO
+ Select this to enable PIO for Altera devices. Please find
+ details on the "Embedded Peripherals IP User Guide" of Altera.
+
++config AXP_GPIO
++ bool "X-Powers AXP PMICs GPIO driver"
++ depends on DM_GPIO && PMIC_AXP
++ depends on AXP_PMIC_BUS
++ help
++ This driver supports the GPIO pins on
++ X-Powers AXP152, AXP2xx, and AXP8xx PMICs.
++
+ config BCM2835_GPIO
+ bool "BCM2835 GPIO driver"
+ depends on DM_GPIO
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -10,9 +10,6 @@
+ #include <asm/gpio.h>
+ #include <axp_pmic.h>
+ #include <dm.h>
+-#include <dm/device-internal.h>
+-#include <dm/lists.h>
+-#include <dm/root.h>
+ #include <errno.h>
+
+ #define AXP_GPIO_PREFIX "AXP0-"
+@@ -99,6 +96,11 @@ static const struct dm_gpio_ops axp_gpio
+ static int axp_gpio_probe(struct udevice *dev)
+ {
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
++ int ret;
++
++ ret = pmic_bus_init();
++ if (ret)
++ return ret;
+
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->bank_name = AXP_GPIO_PREFIX;
+@@ -107,26 +109,18 @@ static int axp_gpio_probe(struct udevice
+ return 0;
+ }
+
++static const struct udevice_id axp_gpio_ids[] = {
++ { .compatible = "x-powers,axp152-gpio" },
++ { .compatible = "x-powers,axp209-gpio" },
++ { .compatible = "x-powers,axp221-gpio" },
++ { .compatible = "x-powers,axp813-gpio" },
++ { }
++};
++
+ U_BOOT_DRIVER(axp_gpio) = {
+ .name = "axp_gpio",
+ .id = UCLASS_GPIO,
++ .of_match = axp_gpio_ids,
+ .probe = axp_gpio_probe,
+ .ops = &axp_gpio_ops,
+ };
+-
+-int axp_gpio_init(void)
+-{
+- struct udevice *dev;
+- int ret;
+-
+- ret = pmic_bus_init();
+- if (ret)
+- return ret;
+-
+- /* There is no devicetree support for the axp yet, so bind directly */
+- ret = device_bind_driver(dm_root(), "axp_gpio", "AXP-gpio", &dev);
+- if (ret)
+- return ret;
+-
+- return 0;
+-}
--- /dev/null
+From 532b81ac600b6a70a1421f86503cb6d8543edf1b Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Tue, 17 Aug 2021 20:01:55 -0500
+Subject: [PATCH 49/90] gpio: axp: Use DM_PMIC functions for register access
+
+Now that the PMIC driver implements the DM_PMIC uclass, those functions
+can be used instead of the platform-specific "pmic_bus" functions.
+
+Since the driver still uses the single set of register definitions from
+axpXXX.h (as selected by AXPxxx_POWER), it still depends on one of those
+choices, and therefore also AXP_PMIC_BUS.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/axp_gpio.c | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -6,11 +6,11 @@
+ */
+
+ #include <common.h>
+-#include <asm/arch/pmic_bus.h>
+ #include <asm/gpio.h>
+ #include <axp_pmic.h>
+ #include <dm.h>
+ #include <errno.h>
++#include <power/pmic.h>
+
+ #define AXP_GPIO_PREFIX "AXP0-"
+ #define AXP_GPIO_COUNT 4
+@@ -40,7 +40,7 @@ static int axp_gpio_direction_input(stru
+ if (reg == 0)
+ return -EINVAL;
+
+- return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT);
++ return pmic_reg_write(dev->parent, reg, AXP_GPIO_CTRL_INPUT);
+ }
+
+ static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
+@@ -52,26 +52,27 @@ static int axp_gpio_direction_output(str
+ if (reg == 0)
+ return -EINVAL;
+
+- return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
++ return pmic_reg_write(dev->parent, reg,
++ val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
++ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+
+ static int axp_gpio_get_value(struct udevice *dev, unsigned pin)
+ {
+- u8 reg, val, mask;
++ u8 reg, mask;
+ int ret;
+
+ reg = axp_get_gpio_ctrl_reg(pin);
+ if (reg == 0)
+ return -EINVAL;
+
+- ret = pmic_bus_read(AXP_GPIO_STATE, &val);
+- if (ret)
++ ret = pmic_reg_read(dev->parent, AXP_GPIO_STATE);
++ if (ret < 0)
+ return ret;
+
+ mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
+
+- return (val & mask) ? 1 : 0;
++ return (ret & mask) ? 1 : 0;
+ }
+
+ static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val)
+@@ -82,8 +83,9 @@ static int axp_gpio_set_value(struct ude
+ if (reg == 0)
+ return -EINVAL;
+
+- return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
++ return pmic_reg_write(dev->parent, reg,
++ val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
++ AXP_GPIO_CTRL_OUTPUT_LOW);
+ }
+
+ static const struct dm_gpio_ops axp_gpio_ops = {
+@@ -96,11 +98,6 @@ static const struct dm_gpio_ops axp_gpio
+ static int axp_gpio_probe(struct udevice *dev)
+ {
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+- int ret;
+-
+- ret = pmic_bus_init();
+- if (ret)
+- return ret;
+
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->bank_name = AXP_GPIO_PREFIX;
--- /dev/null
+From 697eb56ed8c9b3814ddbd87ae0c6e749ccafc9e3 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 28 Aug 2021 00:27:19 -0500
+Subject: [PATCH 50/90] gpio: axp: Select variant from compatible at runtime
+
+There are three major variants of the AXP PMIC GPIO functionality (plus
+PMICs with no GPIOs at all). Except for GPIO3 on the AXP209, which uses
+a different register layout, it is straightforward to support all three
+variants with a single driver. Do this, and in the process remove the
+GPIO-related definitions from the PMIC-specific headers, and therefore
+the dependency on AXP_PMIC_BUS.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/Kconfig | 1 -
+ drivers/gpio/axp_gpio.c | 137 +++++++++++++++++++++-------------------
+ drivers/power/axp209.c | 6 +-
+ drivers/power/axp221.c | 4 +-
+ include/axp152.h | 10 ---
+ include/axp209.h | 16 ++---
+ include/axp221.h | 13 ++--
+ include/axp809.h | 8 ---
+ include/axp818.h | 8 ---
+ 9 files changed, 89 insertions(+), 114 deletions(-)
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -107,7 +107,6 @@ config ALTERA_PIO
+ config AXP_GPIO
+ bool "X-Powers AXP PMICs GPIO driver"
+ depends on DM_GPIO && PMIC_AXP
+- depends on AXP_PMIC_BUS
+ help
+ This driver supports the GPIO pins on
+ X-Powers AXP152, AXP2xx, and AXP8xx PMICs.
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -7,110 +7,117 @@
+
+ #include <common.h>
+ #include <asm/gpio.h>
+-#include <axp_pmic.h>
+ #include <dm.h>
++#include <dm/device-internal.h>
+ #include <errno.h>
+ #include <power/pmic.h>
+
+ #define AXP_GPIO_PREFIX "AXP0-"
+ #define AXP_GPIO_COUNT 4
+
+-static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
+-
+-static u8 axp_get_gpio_ctrl_reg(unsigned pin)
+-{
+- switch (pin) {
+- case 0: return AXP_GPIO0_CTRL;
+- case 1: return AXP_GPIO1_CTRL;
+-#ifdef AXP_GPIO2_CTRL
+- case 2: return AXP_GPIO2_CTRL;
+-#endif
+-#ifdef AXP_GPIO3_CTRL
+- case 3: return AXP_GPIO3_CTRL;
+-#endif
+- }
+- return 0;
+-}
+-
+-static int axp_gpio_direction_input(struct udevice *dev, unsigned pin)
+-{
+- u8 reg;
+-
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
+-
+- return pmic_reg_write(dev->parent, reg, AXP_GPIO_CTRL_INPUT);
+-}
+-
+-static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
+- int val)
+-{
+- u8 reg;
+-
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
+-
+- return pmic_reg_write(dev->parent, reg,
+- val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
+-}
++#define AXP_GPIO_CTRL_MASK 0x7
++#define AXP_GPIO_CTRL_OUTPUT_LOW 0
++#define AXP_GPIO_CTRL_OUTPUT_HIGH 1
++
++struct axp_gpio_desc {
++ const u8 *pins;
++ u8 npins;
++ u8 status_reg;
++ u8 status_offset;
++ u8 input_mux;
++};
+
+ static int axp_gpio_get_value(struct udevice *dev, unsigned pin)
+ {
+- u8 reg, mask;
++ const struct axp_gpio_desc *desc = dev_get_priv(dev);
+ int ret;
+
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
+- return -EINVAL;
+-
+- ret = pmic_reg_read(dev->parent, AXP_GPIO_STATE);
++ ret = pmic_reg_read(dev->parent, desc->status_reg);
+ if (ret < 0)
+ return ret;
+
+- mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
+-
+- return (ret & mask) ? 1 : 0;
++ return !!(ret & BIT(desc->status_offset + pin));
+ }
+
+-static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val)
++static int axp_gpio_set_flags(struct udevice *dev, unsigned pin, ulong flags)
+ {
+- u8 reg;
++ const struct axp_gpio_desc *desc = dev_get_priv(dev);
++ u8 mux;
+
+- reg = axp_get_gpio_ctrl_reg(pin);
+- if (reg == 0)
++ if (flags & (GPIOD_MASK_DSTYPE | GPIOD_MASK_PULL))
+ return -EINVAL;
+
+- return pmic_reg_write(dev->parent, reg,
+- val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
+- AXP_GPIO_CTRL_OUTPUT_LOW);
++ if (flags & GPIOD_IS_IN)
++ mux = desc->input_mux;
++ else if (flags & GPIOD_IS_OUT_ACTIVE)
++ mux = AXP_GPIO_CTRL_OUTPUT_HIGH;
++ else
++ mux = AXP_GPIO_CTRL_OUTPUT_LOW;
++
++ return pmic_clrsetbits(dev->parent, desc->pins[pin],
++ AXP_GPIO_CTRL_MASK, mux);
+ }
+
+ static const struct dm_gpio_ops axp_gpio_ops = {
+- .direction_input = axp_gpio_direction_input,
+- .direction_output = axp_gpio_direction_output,
+ .get_value = axp_gpio_get_value,
+- .set_value = axp_gpio_set_value,
++ .xlate = gpio_xlate_offs_flags,
++ .set_flags = axp_gpio_set_flags,
+ };
+
+ static int axp_gpio_probe(struct udevice *dev)
+ {
++ struct axp_gpio_desc *desc = (void *)dev_get_driver_data(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
++ dev_set_priv(dev, desc);
++
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->bank_name = AXP_GPIO_PREFIX;
+- uc_priv->gpio_count = AXP_GPIO_COUNT;
++ uc_priv->gpio_count = desc->npins;
+
+ return 0;
+ }
+
++static const u8 axp152_gpio_pins[] = {
++ 0x90, 0x91, 0x92, 0x93,
++};
++
++static const struct axp_gpio_desc axp152_gpio_desc = {
++ .pins = axp152_gpio_pins,
++ .npins = ARRAY_SIZE(axp152_gpio_pins),
++ .status_reg = 0x97,
++ .status_offset = 4,
++ .input_mux = 3,
++};
++
++static const u8 axp209_gpio_pins[] = {
++ 0x90, 0x92, 0x93,
++};
++
++static const struct axp_gpio_desc axp209_gpio_desc = {
++ .pins = axp209_gpio_pins,
++ .npins = ARRAY_SIZE(axp209_gpio_pins),
++ .status_reg = 0x94,
++ .status_offset = 4,
++ .input_mux = 2,
++};
++
++static const u8 axp221_gpio_pins[] = {
++ 0x90, 0x92,
++};
++
++static const struct axp_gpio_desc axp221_gpio_desc = {
++ .pins = axp221_gpio_pins,
++ .npins = ARRAY_SIZE(axp221_gpio_pins),
++ .status_reg = 0x94,
++ .input_mux = 2,
++};
++
+ static const struct udevice_id axp_gpio_ids[] = {
+- { .compatible = "x-powers,axp152-gpio" },
+- { .compatible = "x-powers,axp209-gpio" },
+- { .compatible = "x-powers,axp221-gpio" },
+- { .compatible = "x-powers,axp813-gpio" },
++ { .compatible = "x-powers,axp152-gpio", .data = (ulong)&axp152_gpio_desc },
++ { .compatible = "x-powers,axp209-gpio", .data = (ulong)&axp209_gpio_desc },
++ { .compatible = "x-powers,axp221-gpio", .data = (ulong)&axp221_gpio_desc },
++ { .compatible = "x-powers,axp813-gpio", .data = (ulong)&axp221_gpio_desc },
+ { }
+ };
+
+--- a/drivers/power/axp209.c
++++ b/drivers/power/axp209.c
+@@ -215,15 +215,15 @@ int axp_init(void)
+ * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
+ * from android these are sometimes on.
+ */
+- rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
++ rc = pmic_bus_write(AXP209_GPIO0_CTRL, AXP209_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+- rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
++ rc = pmic_bus_write(AXP209_GPIO1_CTRL, AXP209_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+- rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
++ rc = pmic_bus_write(AXP209_GPIO2_CTRL, AXP209_GPIO_CTRL_INPUT);
+ if (rc)
+ return rc;
+
+--- a/drivers/power/axp221.c
++++ b/drivers/power/axp221.c
+@@ -226,11 +226,11 @@ int axp_init(void)
+ * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
+ * from android these are sometimes on.
+ */
+- ret = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
++ ret = pmic_bus_write(AXP221_GPIO0_CTRL, AXP221_GPIO_CTRL_INPUT);
+ if (ret)
+ return ret;
+
+- ret = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
++ ret = pmic_bus_write(AXP221_GPIO1_CTRL, AXP221_GPIO_CTRL_INPUT);
+ if (ret)
+ return ret;
+
+--- a/include/axp152.h
++++ b/include/axp152.h
+@@ -14,17 +14,7 @@ enum axp152_reg {
+
+ #define AXP152_POWEROFF (1 << 7)
+
+-/* For axp_gpio.c */
+ #ifdef CONFIG_AXP152_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_GPIO0_CTRL 0x90
+-#define AXP_GPIO1_CTRL 0x91
+-#define AXP_GPIO2_CTRL 0x92
+-#define AXP_GPIO3_CTRL 0x93
+-#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+-#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+-#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+-#define AXP_GPIO_STATE 0x97
+-#define AXP_GPIO_STATE_OFFSET 0
+ #endif
+--- a/include/axp209.h
++++ b/include/axp209.h
+@@ -21,6 +21,9 @@ enum axp209_reg {
+ AXP209_IRQ_ENABLE5 = 0x44,
+ AXP209_IRQ_STATUS5 = 0x4c,
+ AXP209_SHUTDOWN = 0x32,
++ AXP209_GPIO0_CTRL = 0x90,
++ AXP209_GPIO1_CTRL = 0x92,
++ AXP209_GPIO2_CTRL = 0x93,
+ };
+
+ #define AXP209_POWER_STATUS_ON_BY_DC BIT(0)
+@@ -73,16 +76,11 @@ enum axp209_reg {
+
+ #define AXP209_POWEROFF BIT(7)
+
+-/* For axp_gpio.c */
++#define AXP209_GPIO_CTRL_OUTPUT_LOW 0x00
++#define AXP209_GPIO_CTRL_OUTPUT_HIGH 0x01
++#define AXP209_GPIO_CTRL_INPUT 0x02
++
+ #ifdef CONFIG_AXP209_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_GPIO0_CTRL 0x90
+-#define AXP_GPIO1_CTRL 0x92
+-#define AXP_GPIO2_CTRL 0x93
+-#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+-#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+-#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+-#define AXP_GPIO_STATE 0x94
+-#define AXP_GPIO_STATE_OFFSET 4
+ #endif
+--- a/include/axp221.h
++++ b/include/axp221.h
+@@ -44,20 +44,17 @@
+ #define AXP221_ALDO3_CTRL 0x2a
+ #define AXP221_SHUTDOWN 0x32
+ #define AXP221_SHUTDOWN_POWEROFF (1 << 7)
++#define AXP221_GPIO0_CTRL 0x90
++#define AXP221_GPIO1_CTRL 0x92
++#define AXP221_GPIO_CTRL_OUTPUT_LOW 0x00
++#define AXP221_GPIO_CTRL_OUTPUT_HIGH 0x01
++#define AXP221_GPIO_CTRL_INPUT 0x02
+ #define AXP221_PAGE 0xff
+
+ /* Page 1 addresses */
+ #define AXP221_SID 0x20
+
+-/* For axp_gpio.c */
+ #ifdef CONFIG_AXP221_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_GPIO0_CTRL 0x90
+-#define AXP_GPIO1_CTRL 0x92
+-#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+-#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+-#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+-#define AXP_GPIO_STATE 0x94
+-#define AXP_GPIO_STATE_OFFSET 0
+ #endif
+--- a/include/axp809.h
++++ b/include/axp809.h
+@@ -43,15 +43,7 @@
+ #define AXP809_SHUTDOWN 0x32
+ #define AXP809_SHUTDOWN_POWEROFF (1 << 7)
+
+-/* For axp_gpio.c */
+ #ifdef CONFIG_AXP809_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_GPIO0_CTRL 0x90
+-#define AXP_GPIO1_CTRL 0x92
+-#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+-#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+-#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+-#define AXP_GPIO_STATE 0x94
+-#define AXP_GPIO_STATE_OFFSET 0
+ #endif
+--- a/include/axp818.h
++++ b/include/axp818.h
+@@ -57,15 +57,7 @@
+ #define AXP818_SHUTDOWN 0x32
+ #define AXP818_SHUTDOWN_POWEROFF (1 << 7)
+
+-/* For axp_gpio.c */
+ #ifdef CONFIG_AXP818_POWER
+ #define AXP_POWER_STATUS 0x00
+ #define AXP_POWER_STATUS_ALDO_IN BIT(0)
+-#define AXP_GPIO0_CTRL 0x90
+-#define AXP_GPIO1_CTRL 0x92
+-#define AXP_GPIO_CTRL_OUTPUT_LOW 0x00 /* Drive pin low */
+-#define AXP_GPIO_CTRL_OUTPUT_HIGH 0x01 /* Drive pin high */
+-#define AXP_GPIO_CTRL_INPUT 0x02 /* Input */
+-#define AXP_GPIO_STATE 0x94
+-#define AXP_GPIO_STATE_OFFSET 0
+ #endif
--- /dev/null
+From 37e19d9b8a23c88413dd845dbb3dd58dd3636a6d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 28 Aug 2021 00:36:33 -0500
+Subject: [PATCH 51/90] gpio: axp: Add support for getting the pin function
+
+Implement the .get_function operation, so the gpio command can report
+the current function. Since the GPIOF_FUNC (versus GPIOF_UNUSED) mux
+values vary among the PMICs, report all non-GPIO mux values as UNKNOWN.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/axp_gpio.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -39,6 +39,24 @@ static int axp_gpio_get_value(struct ude
+ return !!(ret & BIT(desc->status_offset + pin));
+ }
+
++static int axp_gpio_get_function(struct udevice *dev, unsigned pin)
++{
++ const struct axp_gpio_desc *desc = dev_get_priv(dev);
++ int ret;
++
++ ret = pmic_reg_read(dev->parent, desc->pins[pin]);
++ if (ret < 0)
++ return ret;
++
++ ret &= AXP_GPIO_CTRL_MASK;
++ if (ret == desc->input_mux)
++ return GPIOF_INPUT;
++ if (ret == AXP_GPIO_CTRL_OUTPUT_HIGH || ret == AXP_GPIO_CTRL_OUTPUT_LOW)
++ return GPIOF_OUTPUT;
++
++ return GPIOF_UNKNOWN;
++}
++
+ static int axp_gpio_set_flags(struct udevice *dev, unsigned pin, ulong flags)
+ {
+ const struct axp_gpio_desc *desc = dev_get_priv(dev);
+@@ -60,6 +78,7 @@ static int axp_gpio_set_flags(struct ude
+
+ static const struct dm_gpio_ops axp_gpio_ops = {
+ .get_value = axp_gpio_get_value,
++ .get_function = axp_gpio_get_function,
+ .xlate = gpio_xlate_offs_flags,
+ .set_flags = axp_gpio_set_flags,
+ };
--- /dev/null
+From 4be9f9082b0a2ac2626ae20b7e07006139827442 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 28 Aug 2021 00:34:54 -0500
+Subject: [PATCH 52/90] gpio: axp: Add pull-down support for AXP22x/AXP8xx
+ variant
+
+The AXP221 and newer PMICs support a pull-down function on their GPIOs.
+Add support for it.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/axp_gpio.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -24,6 +24,7 @@ struct axp_gpio_desc {
+ u8 npins;
+ u8 status_reg;
+ u8 status_offset;
++ u8 pull_reg;
+ u8 input_mux;
+ };
+
+@@ -60,11 +61,22 @@ static int axp_gpio_get_function(struct
+ static int axp_gpio_set_flags(struct udevice *dev, unsigned pin, ulong flags)
+ {
+ const struct axp_gpio_desc *desc = dev_get_priv(dev);
++ bool pull_down = flags & GPIOD_PULL_DOWN;
++ int ret;
+ u8 mux;
+
+- if (flags & (GPIOD_MASK_DSTYPE | GPIOD_MASK_PULL))
++ if (flags & (GPIOD_MASK_DSTYPE | GPIOD_PULL_UP))
++ return -EINVAL;
++ if (pull_down && !desc->pull_reg)
+ return -EINVAL;
+
++ if (desc->pull_reg) {
++ ret = pmic_clrsetbits(dev->parent, desc->pull_reg,
++ BIT(pin), pull_down ? BIT(pin) : 0);
++ if (ret)
++ return ret;
++ }
++
+ if (flags & GPIOD_IS_IN)
+ mux = desc->input_mux;
+ else if (flags & GPIOD_IS_OUT_ACTIVE)
+@@ -129,6 +141,7 @@ static const struct axp_gpio_desc axp221
+ .pins = axp221_gpio_pins,
+ .npins = ARRAY_SIZE(axp221_gpio_pins),
+ .status_reg = 0x94,
++ .pull_reg = 0x97,
+ .input_mux = 2,
+ };
+
--- /dev/null
+From 52c172782d659750b447572281cd11835d1edf58 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 31 Jul 2022 18:19:39 -0500
+Subject: [PATCH 53/90] gpio: axp: Report the correct value for outputs
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/gpio/axp_gpio.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -33,6 +33,15 @@ static int axp_gpio_get_value(struct ude
+ const struct axp_gpio_desc *desc = dev_get_priv(dev);
+ int ret;
+
++ ret = pmic_reg_read(dev->parent, desc->pins[pin]);
++ if (ret < 0)
++ return ret;
++
++ if (ret == AXP_GPIO_CTRL_OUTPUT_LOW)
++ return 0;
++ if (ret == AXP_GPIO_CTRL_OUTPUT_HIGH)
++ return 1;
++
+ ret = pmic_reg_read(dev->parent, desc->status_reg);
+ if (ret < 0)
+ return ret;
--- /dev/null
+From 64de4fd71d35c6154a0f7b4c7c02cb24e978a4ce Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:45:19 -0500
+Subject: [PATCH 54/90] sunxi: Fix default-enablement of USB host drivers
+
+We tried to enable USB_EHCI_GENERIC and USB_OHCI_GENERIC by default.
+This did not work because those symbols depend on USB_EHCI_HCD and
+USB_OHCI_HCD, which were not enabled. Fix this by implying all four.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/Kconfig | 4 ++++
+ drivers/usb/host/Kconfig | 2 --
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1142,7 +1142,11 @@ config ARCH_SUNXI
+ imply SYSRESET
+ imply SYSRESET_WATCHDOG
+ imply SYSRESET_WATCHDOG_AUTO
++ imply USB_EHCI_GENERIC
++ imply USB_EHCI_HCD
+ imply USB_GADGET
++ imply USB_OHCI_GENERIC
++ imply USB_OHCI_HCD
+ imply WDT
+
+ config ARCH_U8500
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -281,7 +281,6 @@ config USB_EHCI_ZYNQ
+ config USB_EHCI_GENERIC
+ bool "Support for generic EHCI USB controller"
+ depends on DM_USB
+- default ARCH_SUNXI
+ ---help---
+ Enables support for generic EHCI controller.
+
+@@ -343,7 +342,6 @@ config USB_OHCI_PCI
+
+ config USB_OHCI_GENERIC
+ bool "Support for generic OHCI USB controller"
+- default ARCH_SUNXI
+ ---help---
+ Enables support for generic OHCI controller.
+
--- /dev/null
+From 891fef47500dbf4aecb16e08c1d8ade3fbc8caec Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 4 Aug 2022 23:22:05 -0500
+Subject: [PATCH 55/90] sunxi: Remove unnecessary Kconfig selections
+
+Two of these selections are redundant and have no effect:
+ - DM_KEYBOARD is selected by USB_KEYBOARD
+ - DM_MMC is selected by MMC
+
+This selection has no effect by default and is unnecessarily strong:
+ - USB_STORAGE is implied by DISTRO_DEFAULTS
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/Kconfig | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1100,8 +1100,6 @@ config ARCH_SUNXI
+ select DM_I2C if I2C
+ select DM_SPI if SPI
+ select DM_SPI_FLASH if SPI
+- select DM_KEYBOARD
+- select DM_MMC if MMC
+ select DM_SCSI if SCSI
+ select DM_SERIAL
+ select GPIO_EXTRA_HEADER
+@@ -1119,7 +1117,6 @@ config ARCH_SUNXI
+ select SYS_THUMB_BUILD if !ARM64
+ select USB if DISTRO_DEFAULTS
+ select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
+- select USB_STORAGE if DISTRO_DEFAULTS && USB_HOST
+ select SPL_USE_TINY_PRINTF
+ select USE_PREBOOT
+ select SYS_RELOC_GD_ENV_ADDR
--- /dev/null
+From 9e12a7fd80276092da3a43b7dbaf572bad294419 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 4 Aug 2022 23:29:13 -0500
+Subject: [PATCH 56/90] sunxi: Add missing dependencies to Kconfig selections
+
+Some of the selected symbols have a user-visible dependency. Make the
+selections conditional on that dependency to avoid creating invalid
+configurations.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/Kconfig | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1090,30 +1090,30 @@ config ARCH_SOCFPGA
+ config ARCH_SUNXI
+ bool "Support sunxi (Allwinner) SoCs"
+ select BINMAN
+- select CMD_GPIO
++ select CMD_GPIO if GPIO
+ select CMD_MMC if MMC
+ select CMD_USB if DISTRO_DEFAULTS && USB_HOST
+ select CLK
+ select DM
+- select DM_ETH
+- select DM_GPIO
++ select DM_ETH if NET
++ select DM_GPIO if GPIO
+ select DM_I2C if I2C
++ select DM_SCSI if BLK && SCSI
++ select DM_SERIAL if SERIAL
+ select DM_SPI if SPI
+ select DM_SPI_FLASH if SPI
+- select DM_SCSI if SCSI
+- select DM_SERIAL
+ select GPIO_EXTRA_HEADER
+ select OF_BOARD_SETUP
+ select OF_CONTROL
+ select OF_SEPARATE
+ select PINCTRL
+- select SPECIFY_CONSOLE_INDEX
++ select SPECIFY_CONSOLE_INDEX if SERIAL
+ select SPL_SEPARATE_BSS if SPL
+ select SPL_STACK_R if SPL
+ select SPL_SYS_MALLOC_SIMPLE if SPL
+ select SPL_SYS_THUMB_BUILD if !ARM64
+- select SUNXI_GPIO
+- select SYS_NS16550
++ select SUNXI_GPIO if GPIO
++ select SYS_NS16550 if SERIAL
+ select SYS_THUMB_BUILD if !ARM64
+ select USB if DISTRO_DEFAULTS
+ select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
--- /dev/null
+From 2ba626d36e622f29528ce953618dde9a01bdacd6 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 21:56:43 -0500
+Subject: [PATCH 57/90] sunxi: Hide image type selection if SPL is disabled
+
+This choice is meaningless when SPL is disabled. Hide it to avoid any
+possible confusion.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -1,5 +1,6 @@
+ choice
+ prompt "SPL Image Type"
++ depends on SPL
+ default SPL_IMAGE_TYPE_SUNXI_EGON
+
+ config SPL_IMAGE_TYPE_SUNXI_EGON
--- /dev/null
+From 5d197433cd54085306e369ac260e09fe6077bfbb Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 4 Aug 2022 21:30:57 -0500
+Subject: [PATCH 58/90] sunxi: Share the board Kconfig across architectures
+
+With the introduction of the Allwinner D1, the sunxi board family now
+spans multiple architectures (ARM and RISC-V). Since ARCH_SUNXI depends
+on ARM, it cannot be used to gate architecture-independent options.
+Specifically, this means the board Kconfig file cannot be sourced from
+inside the "if ARCH_SUNXI" block.
+
+Introduce a new BOARD_SUNXI symbol that can be selected by both
+ARCH_SUNXI now and the new RISC-V SoC symbols when they are added, and
+use it to gate the architecture-independent board options.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/Kconfig | 1 +
+ arch/arm/Kconfig | 1 +
+ arch/arm/mach-sunxi/Kconfig | 2 --
+ board/sunxi/Kconfig | 11 +++++++++++
+ 4 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/arch/Kconfig
++++ b/arch/Kconfig
+@@ -482,6 +482,7 @@ source "arch/Kconfig.nxp"
+ endif
+
+ source "board/keymile/Kconfig"
++source "board/sunxi/Kconfig"
+
+ if MIPS || MICROBLAZE
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1090,6 +1090,7 @@ config ARCH_SOCFPGA
+ config ARCH_SUNXI
+ bool "Support sunxi (Allwinner) SoCs"
+ select BINMAN
++ select BOARD_SUNXI
+ select CMD_GPIO if GPIO
+ select CMD_MMC if MMC
+ select CMD_USB if DISTRO_DEFAULTS && USB_HOST
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -959,8 +959,6 @@ config BLUETOOTH_DT_DEVICE_FIXUP
+ The used address is "bdaddr" if set, and "ethaddr" with the LSB
+ flipped elsewise.
+
+-source "board/sunxi/Kconfig"
+-
+ endif
+
+ config CHIP_DIP_SCAN
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -1,3 +1,10 @@
++config BOARD_SUNXI
++ bool
++
++if BOARD_SUNXI
++
++menu "sunxi board options"
++
+ choice
+ prompt "SPL Image Type"
+ depends on SPL
+@@ -23,3 +30,7 @@ config SPL_IMAGE_TYPE
+ string
+ default "sunxi_egon" if SPL_IMAGE_TYPE_SUNXI_EGON
+ default "sunxi_toc0" if SPL_IMAGE_TYPE_SUNXI_TOC0
++
++endmenu
++
++endif
--- /dev/null
+From 963331be1cc924ad7c928f88b3ee46bc20a41bcd Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 18:06:20 +0000
+Subject: [PATCH 59/90] sunxi: Move most Kconfig selections to the board
+ Kconfig
+
+To maintain consistent behavior across architectures, most of the
+options selected by ARCH_SUNXI should be selected for the D1 SoC as
+well. To accomplish this, select them from BOARD_SUNXI instead.
+
+No functional change here. Lines are only moved and alphabetized.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/Kconfig | 47 ---------------------------------------------
+ board/sunxi/Kconfig | 46 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 46 insertions(+), 47 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1089,63 +1089,16 @@ config ARCH_SOCFPGA
+
+ config ARCH_SUNXI
+ bool "Support sunxi (Allwinner) SoCs"
+- select BINMAN
+ select BOARD_SUNXI
+- select CMD_GPIO if GPIO
+- select CMD_MMC if MMC
+- select CMD_USB if DISTRO_DEFAULTS && USB_HOST
+- select CLK
+- select DM
+- select DM_ETH if NET
+- select DM_GPIO if GPIO
+- select DM_I2C if I2C
+- select DM_SCSI if BLK && SCSI
+- select DM_SERIAL if SERIAL
+- select DM_SPI if SPI
+- select DM_SPI_FLASH if SPI
+ select GPIO_EXTRA_HEADER
+- select OF_BOARD_SETUP
+ select OF_CONTROL
+ select OF_SEPARATE
+- select PINCTRL
+ select SPECIFY_CONSOLE_INDEX if SERIAL
+- select SPL_SEPARATE_BSS if SPL
+ select SPL_STACK_R if SPL
+ select SPL_SYS_MALLOC_SIMPLE if SPL
+ select SPL_SYS_THUMB_BUILD if !ARM64
+- select SUNXI_GPIO if GPIO
+- select SYS_NS16550 if SERIAL
+ select SYS_THUMB_BUILD if !ARM64
+- select USB if DISTRO_DEFAULTS
+- select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
+ select SPL_USE_TINY_PRINTF
+- select USE_PREBOOT
+- select SYS_RELOC_GD_ENV_ADDR
+- imply BOARD_LATE_INIT
+- imply CMD_DM
+- imply CMD_GPT
+- imply CMD_UBI if MTD_RAW_NAND
+- imply DISTRO_DEFAULTS
+- imply FAT_WRITE
+- imply FIT
+- imply OF_LIBFDT_OVERLAY
+- imply PRE_CONSOLE_BUFFER
+- imply SPL_GPIO
+- imply SPL_LIBCOMMON_SUPPORT
+- imply SPL_LIBGENERIC_SUPPORT
+- imply SPL_LOAD_FIT
+- imply SPL_MMC if MMC
+- imply SPL_POWER
+- imply SPL_SERIAL
+- imply SYSRESET
+- imply SYSRESET_WATCHDOG
+- imply SYSRESET_WATCHDOG_AUTO
+- imply USB_EHCI_GENERIC
+- imply USB_EHCI_HCD
+- imply USB_GADGET
+- imply USB_OHCI_GENERIC
+- imply USB_OHCI_HCD
+- imply WDT
+
+ config ARCH_U8500
+ bool "ST-Ericsson U8500 Series"
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -1,5 +1,51 @@
+ config BOARD_SUNXI
+ bool
++ select BINMAN
++ select CLK
++ select CMD_GPIO if GPIO
++ select CMD_MMC if MMC
++ select CMD_USB if DISTRO_DEFAULTS && USB_HOST
++ select DM
++ select DM_ETH if NET
++ select DM_GPIO if GPIO
++ select DM_I2C if I2C
++ select DM_SCSI if BLK && SCSI
++ select DM_SERIAL if SERIAL
++ select DM_SPI if SPI
++ select DM_SPI_FLASH if SPI
++ select OF_BOARD_SETUP
++ select PINCTRL
++ select SPL_SEPARATE_BSS if SPL
++ select SUNXI_GPIO if GPIO
++ select SYS_NS16550 if SERIAL
++ select SYS_RELOC_GD_ENV_ADDR
++ select USB if DISTRO_DEFAULTS
++ select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
++ select USE_PREBOOT
++ imply BOARD_LATE_INIT
++ imply CMD_DM
++ imply CMD_GPT
++ imply CMD_UBI if MTD_RAW_NAND
++ imply DISTRO_DEFAULTS
++ imply FAT_WRITE
++ imply FIT
++ imply OF_LIBFDT_OVERLAY
++ imply PRE_CONSOLE_BUFFER
++ imply SPL_GPIO
++ imply SPL_LIBCOMMON_SUPPORT
++ imply SPL_LIBGENERIC_SUPPORT
++ imply SPL_MMC if MMC
++ imply SPL_POWER
++ imply SPL_SERIAL
++ imply SYSRESET
++ imply SYSRESET_WATCHDOG
++ imply SYSRESET_WATCHDOG_AUTO
++ imply USB_EHCI_GENERIC
++ imply USB_EHCI_HCD
++ imply USB_GADGET
++ imply USB_OHCI_GENERIC
++ imply USB_OHCI_HCD
++ imply WDT
+
+ if BOARD_SUNXI
+
--- /dev/null
+From 5838fd3a53e613312d46ab4cb6015a502c4c45d0 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 18:07:24 +0000
+Subject: [PATCH 60/90] sunxi: Globally enable SUPPORT_SPL
+
+This was already supported by every machine type. It is unlikely that
+any new SoC support will be added without SPL support.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/mach-sunxi/Kconfig | 14 --------------
+ board/sunxi/Kconfig | 2 ++
+ 2 files changed, 2 insertions(+), 14 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -133,7 +133,6 @@ config SUN50I_GEN_H6
+ select FIT
+ select SPL_LOAD_FIT
+ select MMC_SUNXI_HAS_NEW_MODE
+- select SUPPORT_SPL
+ ---help---
+ Select this for sunxi SoCs which have H6 like peripherals, clocks
+ and memory map.
+@@ -166,7 +165,6 @@ config MACH_SUNXI_H3_H5
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_32BIT
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+
+ # TODO: try out A80's 8GiB DRAM space
+ config SUNXI_DRAM_MAX_SIZE
+@@ -183,7 +181,6 @@ config MACH_SUNIV
+ bool "suniv (Allwinner F1C100s/F1C200s/F1C600/R6)"
+ select CPU_ARM926EJS
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+ select SKIP_LOWLEVEL_INIT_ONLY
+ select SPL_SKIP_LOWLEVEL_INIT_ONLY
+
+@@ -192,7 +189,6 @@ config MACH_SUN4I
+ select CPU_V7A
+ select DRAM_SUN4I
+ select SUNXI_GEN_SUN4I
+- select SUPPORT_SPL
+ imply SPL_SYS_I2C_LEGACY
+ imply SYS_I2C_LEGACY
+
+@@ -201,7 +197,6 @@ config MACH_SUN5I
+ select CPU_V7A
+ select DRAM_SUN4I
+ select SUNXI_GEN_SUN4I
+- select SUPPORT_SPL
+ imply SPL_SYS_I2C_LEGACY
+ imply SYS_I2C_LEGACY
+
+@@ -216,7 +211,6 @@ config MACH_SUN6I
+ select SPL_I2C
+ select SUN6I_PRCM
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+ select SYS_I2C_SUN6I_P2WI
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+
+@@ -229,7 +223,6 @@ config MACH_SUN7I
+ select SPL_ARMV7_SET_CORTEX_SMPEN
+ select DRAM_SUN4I
+ select SUNXI_GEN_SUN4I
+- select SUPPORT_SPL
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+ imply SPL_SYS_I2C_LEGACY
+ imply SYS_I2C_LEGACY
+@@ -243,7 +236,6 @@ config MACH_SUN8I_A23
+ select DRAM_SUN8I_A23
+ select SPL_I2C
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+
+@@ -256,7 +248,6 @@ config MACH_SUN8I_A33
+ select DRAM_SUN8I_A33
+ select SPL_I2C
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+
+@@ -268,7 +259,6 @@ config MACH_SUN8I_A83T
+ select SUNXI_GEN_SUN6I
+ select MMC_SUNXI_HAS_NEW_MODE
+ select MMC_SUNXI_HAS_MODE_SWITCH
+- select SUPPORT_SPL
+ select SYS_I2C_SUN8I_RSB
+
+ config MACH_SUN8I_H3
+@@ -288,7 +278,6 @@ config MACH_SUN8I_R40
+ select ARCH_SUPPORT_PSCI
+ select SUNXI_GEN_SUN6I
+ select MMC_SUNXI_HAS_NEW_MODE
+- select SUPPORT_SPL
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_32BIT
+ imply SPL_SYS_I2C_LEGACY
+@@ -302,7 +291,6 @@ config MACH_SUN8I_V3S
+ select SUNXI_GEN_SUN6I
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_16BIT
+- select SUPPORT_SPL
+ select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
+
+ config MACH_SUN9I
+@@ -313,7 +301,6 @@ config MACH_SUN9I
+ select SPL_I2C
+ select SUN6I_PRCM
+ select SUNXI_GEN_SUN6I
+- select SUPPORT_SPL
+
+ config MACH_SUN50I
+ bool "sun50i (Allwinner A64)"
+@@ -322,7 +309,6 @@ config MACH_SUN50I
+ select SUNXI_DE2
+ select SUNXI_GEN_SUN6I
+ select MMC_SUNXI_HAS_NEW_MODE
+- select SUPPORT_SPL
+ select SUNXI_DRAM_DW
+ select SUNXI_DRAM_DW_32BIT
+ select FIT
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -18,6 +18,7 @@ config BOARD_SUNXI
+ select SPL_SEPARATE_BSS if SPL
+ select SUNXI_GPIO if GPIO
+ select SYS_NS16550 if SERIAL
++ select SUPPORT_SPL
+ select SYS_RELOC_GD_ENV_ADDR
+ select USB if DISTRO_DEFAULTS
+ select USB_KEYBOARD if DISTRO_DEFAULTS && USB_HOST
+@@ -31,6 +32,7 @@ config BOARD_SUNXI
+ imply FIT
+ imply OF_LIBFDT_OVERLAY
+ imply PRE_CONSOLE_BUFFER
++ imply SPL
+ imply SPL_GPIO
+ imply SPL_LIBCOMMON_SUPPORT
+ imply SPL_LIBGENERIC_SUPPORT
--- /dev/null
+From 6c8707fcd3372015829a1e8b8d5e8030c5806382 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:10:46 -0500
+Subject: [PATCH 61/90] sunxi: Downgrade driver selections to implications
+
+While not especially likely, it is plausible that someone wants to build
+U-Boot without GPIO or UART support. Don't force building these drivers.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -16,8 +16,6 @@ config BOARD_SUNXI
+ select OF_BOARD_SETUP
+ select PINCTRL
+ select SPL_SEPARATE_BSS if SPL
+- select SUNXI_GPIO if GPIO
+- select SYS_NS16550 if SERIAL
+ select SUPPORT_SPL
+ select SYS_RELOC_GD_ENV_ADDR
+ select USB if DISTRO_DEFAULTS
+@@ -39,6 +37,8 @@ config BOARD_SUNXI
+ imply SPL_MMC if MMC
+ imply SPL_POWER
+ imply SPL_SERIAL
++ imply SUNXI_GPIO
++ imply SYS_NS16550
+ imply SYSRESET
+ imply SYSRESET_WATCHDOG
+ imply SYSRESET_WATCHDOG_AUTO
--- /dev/null
+From ad619478827b825d7b88dce22eb9b5e1c6ea7eb0 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:11:54 -0500
+Subject: [PATCH 62/90] sunxi: Enable the I2C driver by default
+
+This is used by quite a large number of boards, for PMIC/regulator or
+LCD panel control.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -38,6 +38,7 @@ config BOARD_SUNXI
+ imply SPL_POWER
+ imply SPL_SERIAL
+ imply SUNXI_GPIO
++ imply SYS_I2C_MVTWSI
+ imply SYS_NS16550
+ imply SYSRESET
+ imply SYSRESET_WATCHDOG
--- /dev/null
+From fde804c2ece090eb7802a218781e38c7c6d6f00d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:10:11 -0500
+Subject: [PATCH 63/90] sunxi: Move default values to the board Kconfig
+
+This keeps all of the defaults for sunxi platforms in one place. Most of
+these only depend on architecture-independent features of the SoC (clock
+tree or SRAM layout) anyway.
+
+No functional change; just some minor help text cleanup.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/mach-sunxi/Kconfig | 67 ------------------------------------
+ board/sunxi/Kconfig | 68 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 68 insertions(+), 67 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -1,8 +1,5 @@
+ if ARCH_SUNXI
+
+-config IDENT_STRING
+- default " Allwinner Technology"
+-
+ config DRAM_SUN4I
+ bool
+ help
+@@ -99,17 +96,6 @@ config AXP_PMIC_BUS
+ Select this PMIC bus access helpers for Sunxi platform PRCM or other
+ AXP family PMIC devices.
+
+-config SUNXI_SRAM_ADDRESS
+- hex
+- default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
+- default 0x20000 if SUN50I_GEN_H6
+- default 0x0
+- ---help---
+- Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
+- with the first SRAM region being located at address 0.
+- Some newer SoCs map the boot ROM at address 0 instead and move the
+- SRAM to a different address.
+-
+ config SUNXI_A64_TIMER_ERRATUM
+ bool
+
+@@ -562,48 +548,6 @@ config DRAM_ODT_CORRECTION
+ then the correction is negative. Usually the value for this is 0.
+ endif
+
+-config SYS_CLK_FREQ
+- default 408000000 if MACH_SUNIV
+- default 1008000000 if MACH_SUN4I
+- default 1008000000 if MACH_SUN5I
+- default 1008000000 if MACH_SUN6I
+- default 912000000 if MACH_SUN7I
+- default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
+- 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 "suniv" if MACH_SUNIV
+- default "sun4i" if MACH_SUN4I
+- default "sun5i" if MACH_SUN5I
+- default "sun6i" if MACH_SUN6I
+- default "sun7i" if MACH_SUN7I
+- default "sun8i" if MACH_SUN8I
+- 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"
+-
+-config SYS_SOC
+- default "sunxi"
+-
+-config SUNXI_MINIMUM_DRAM_MB
+- int "minimum DRAM size"
+- default 32 if MACH_SUNIV
+- default 64 if MACH_SUN8I_V3S
+- default 256
+- ---help---
+- Minimum DRAM size expected on the board. Traditionally we assumed
+- 256 MB, so that U-Boot would load at 160MB. With co-packaged DRAM
+- we have smaller sizes, though, so that U-Boot's own load address and
+- the default payload addresses must be shifted down.
+- This is expected to be fixed by the SoC selection.
+-
+ config UART0_PORT_F
+ bool "UART0 on MicroSD breakout board"
+ ---help---
+@@ -898,17 +842,6 @@ config GMAC_TX_DELAY
+ ---help---
+ Set the GMAC Transmit Clock Delay Chain value.
+
+-config SPL_STACK_R_ADDR
+- default 0x81e00000 if MACH_SUNIV
+- default 0x4fe00000 if MACH_SUN4I
+- default 0x4fe00000 if MACH_SUN5I
+- default 0x4fe00000 if MACH_SUN6I
+- default 0x4fe00000 if MACH_SUN7I
+- default 0x4fe00000 if MACH_SUN8I
+- default 0x2fe00000 if MACH_SUN9I
+- default 0x4fe00000 if MACH_SUN50I
+- default 0x4fe00000 if SUN50I_GEN_H6
+-
+ config SPL_SPI_SUNXI
+ bool "Support for SPI Flash on Allwinner SoCs in SPL"
+ depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || SUN50I_GEN_H6 || MACH_SUNIV
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -52,6 +52,74 @@ config BOARD_SUNXI
+
+ if BOARD_SUNXI
+
++config IDENT_STRING
++ default " Allwinner Technology"
++
++config SPL_STACK_R_ADDR
++ default 0x81e00000 if MACH_SUNIV
++ default 0x4fe00000 if MACH_SUN4I
++ default 0x4fe00000 if MACH_SUN5I
++ default 0x4fe00000 if MACH_SUN6I
++ default 0x4fe00000 if MACH_SUN7I
++ default 0x4fe00000 if MACH_SUN8I
++ default 0x2fe00000 if MACH_SUN9I
++ default 0x4fe00000 if MACH_SUN50I
++ default 0x4fe00000 if SUN50I_GEN_H6
++
++config SUNXI_MINIMUM_DRAM_MB
++ int "minimum DRAM size"
++ default 32 if MACH_SUNIV
++ default 64 if MACH_SUN8I_V3S
++ default 256
++ help
++ Minimum DRAM size expected on the board. Traditionally we
++ assumed 256 MB, so that U-Boot would load at 160MB. With
++ co-packaged DRAM we have smaller sizes, though, so U-Boot's
++ own load address and the default payload addresses must be
++ shifted down. This is expected to be fixed by the SoC
++ selection.
++
++config SUNXI_SRAM_ADDRESS
++ hex
++ default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
++ default 0x20000 if SUN50I_GEN_H6
++ default 0x0
++ help
++ Older Allwinner SoCs have their boot mask ROM mapped just
++ below 4GB, with the first SRAM region located at address 0.
++ Newer SoCs map the boot ROM at address 0 instead and move the
++ SRAM to a different address.
++
++config SYS_BOARD
++ default "sunxi"
++
++config SYS_CLK_FREQ
++ default 408000000 if MACH_SUNIV
++ default 1008000000 if MACH_SUN4I
++ default 1008000000 if MACH_SUN5I
++ default 1008000000 if MACH_SUN6I
++ default 912000000 if MACH_SUN7I
++ default 1008000000 if MACH_SUN8I
++ default 1008000000 if MACH_SUN9I
++ default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
++ default 888000000 if MACH_SUN50I_H6
++ default 1008000000 if MACH_SUN50I_H616
++
++config SYS_CONFIG_NAME
++ default "suniv" if MACH_SUNIV
++ default "sun4i" if MACH_SUN4I
++ default "sun5i" if MACH_SUN5I
++ default "sun6i" if MACH_SUN6I
++ default "sun7i" if MACH_SUN7I
++ default "sun8i" if MACH_SUN8I
++ default "sun9i" if MACH_SUN9I
++ default "sun50i" if MACH_SUN50I
++ default "sun50i" if MACH_SUN50I_H6
++ default "sun50i" if MACH_SUN50I_H616
++
++config SYS_SOC
++ default "sunxi"
++
+ menu "sunxi board options"
+
+ choice
--- /dev/null
+From 8377aa2162d0a7fda76597eae59725a298dda5e6 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 Oct 2022 22:14:36 -0500
+Subject: [PATCH 64/90] sunxi: Hide the SUNXI_MINIMUM_DRAM_MB symbol
+
+This option affects the ABI between SPL/U-Boot and U-Boot/scripts, so it
+should not normally be changed by the user.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -67,7 +67,7 @@ config SPL_STACK_R_ADDR
+ default 0x4fe00000 if SUN50I_GEN_H6
+
+ config SUNXI_MINIMUM_DRAM_MB
+- int "minimum DRAM size"
++ int
+ default 32 if MACH_SUNIV
+ default 64 if MACH_SUN8I_V3S
+ default 256
--- /dev/null
+From 41e5a94533e9744b8eac718dd2c359eca57573f8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:25:26 -0500
+Subject: [PATCH 65/90] sunxi: Clean up the SPL_STACK_R_ADDR defaults
+
+Update this option to be based on SUNXI_MINIMUM_DRAM_MB. This corrects
+the value used on V3s, which previously was the MACH_SUN8I default, and
+so relied on addresses wrapping modulo the DRAM size.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -57,14 +57,9 @@ config IDENT_STRING
+
+ config SPL_STACK_R_ADDR
+ default 0x81e00000 if MACH_SUNIV
+- default 0x4fe00000 if MACH_SUN4I
+- default 0x4fe00000 if MACH_SUN5I
+- default 0x4fe00000 if MACH_SUN6I
+- default 0x4fe00000 if MACH_SUN7I
+- default 0x4fe00000 if MACH_SUN8I
+ default 0x2fe00000 if MACH_SUN9I
+- default 0x4fe00000 if MACH_SUN50I
+- default 0x4fe00000 if SUN50I_GEN_H6
++ default 0x4fe00000 if SUNXI_MINIMUM_DRAM_MB >= 256
++ default 0x43e00000 if SUNXI_MINIMUM_DRAM_MB >= 64
+
+ config SUNXI_MINIMUM_DRAM_MB
+ int
--- /dev/null
+From e947c7377b90897e4c638dad6e64201361dc8a9e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:45:10 -0500
+Subject: [PATCH 66/90] sunxi: Move PRE_CON_BUF_ADDR to the board Kconfig
+
+This provides a default value for RISC-V when that is added, and it
+makes sense to put this option next to the other DRAM layout options.
+
+While at it, provide sensible values for platforms with less DRAM.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 6 ++++++
+ common/Kconfig | 2 --
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -55,6 +55,12 @@ if BOARD_SUNXI
+ config IDENT_STRING
+ default " Allwinner Technology"
+
++config PRE_CON_BUF_ADDR
++ default 0x81000000 if MACH_SUNIV
++ default 0x2f000000 if MACH_SUN9I
++ default 0x4f000000 if SUNXI_MINIMUM_DRAM_MB >= 256
++ default 0x43000000 if SUNXI_MINIMUM_DRAM_MB >= 64
++
+ config SPL_STACK_R_ADDR
+ default 0x81e00000 if MACH_SUNIV
+ default 0x2fe00000 if MACH_SUN9I
+--- a/common/Kconfig
++++ b/common/Kconfig
+@@ -195,8 +195,6 @@ config PRE_CON_BUF_SZ
+ config PRE_CON_BUF_ADDR
+ hex "Address of the pre-console buffer"
+ depends on PRE_CONSOLE_BUFFER
+- default 0x2f000000 if ARCH_SUNXI && MACH_SUN9I
+- default 0x4f000000 if ARCH_SUNXI && !MACH_SUN9I
+ default 0x0f000000 if ROCKCHIP_RK3288
+ default 0x0f200000 if ROCKCHIP_RK3399
+ help
--- /dev/null
+From 71796f9d47a6b7e0dd6bb276436950463039c1b8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 Oct 2022 00:08:26 -0500
+Subject: [PATCH 67/90] sunxi: Move SPL_BSS_START_ADDR to the board Kconfig
+
+This provides a default value for RISC-V when that is added, and it
+makes sense to put this option next to the other DRAM layout options.
+
+While at it, provide sensible values for platforms with less DRAM.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 6 ++++++
+ common/spl/Kconfig | 3 ---
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -61,6 +61,12 @@ config PRE_CON_BUF_ADDR
+ default 0x4f000000 if SUNXI_MINIMUM_DRAM_MB >= 256
+ default 0x43000000 if SUNXI_MINIMUM_DRAM_MB >= 64
+
++config SPL_BSS_START_ADDR
++ default 0x81f80000 if MACH_SUNIV
++ default 0x2ff80000 if MACH_SUN9I
++ default 0x4ff80000 if SUNXI_MINIMUM_DRAM_MB >= 256
++ default 0x43f80000 if SUNXI_MINIMUM_DRAM_MB >= 64
++
+ config SPL_STACK_R_ADDR
+ default 0x81e00000 if MACH_SUNIV
+ default 0x2fe00000 if MACH_SUN9I
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -119,9 +119,6 @@ config SPL_BSS_START_ADDR
+ default 0x88200000 if (ARCH_MX6 && (MX6SX || MX6SL || MX6UL || MX6ULL)) || ARCH_MX7
+ default 0x18200000 if ARCH_MX6 && !(MX6SX || MX6SL || MX6UL || MX6ULL)
+ default 0x80a00000 if ARCH_OMAP2PLUS
+- default 0x81f80000 if ARCH_SUNXI && MACH_SUNIV
+- default 0x4ff80000 if ARCH_SUNXI && !(MACH_SUN9I || MACH_SUNIV)
+- default 0x2ff80000 if ARCH_SUNXI && MACH_SUN9I
+ default 0x1000 if ARCH_ZYNQMP
+
+ choice
--- /dev/null
+From 5d60490d0f0ca0a5d414ba9a4e41ceea8a98b4d2 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:07:47 -0500
+Subject: [PATCH 68/90] sunxi: Move SPL_TEXT_BASE to the board Kconfig
+
+It makes sense to put this near the definition of SUNXI_SRAM_ADDRESS.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 5 +++++
+ common/spl/Kconfig | 3 ---
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -73,6 +73,11 @@ config SPL_STACK_R_ADDR
+ default 0x4fe00000 if SUNXI_MINIMUM_DRAM_MB >= 256
+ default 0x43e00000 if SUNXI_MINIMUM_DRAM_MB >= 64
+
++config SPL_TEXT_BASE
++ default 0x10060 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
++ default 0x20060 if SUN50I_GEN_H6
++ default 0x00060
++
+ config SUNXI_MINIMUM_DRAM_MB
+ int
+ default 32 if MACH_SUNIV
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -261,9 +261,6 @@ config SPL_TEXT_BASE
+ default 0x402F4000 if AM43XX
+ default 0x402F0400 if AM33XX
+ default 0x40301350 if OMAP54XX
+- default 0x10060 if MACH_SUN50I || MACH_SUN50I_H5 || MACH_SUN9I
+- default 0x20060 if SUN50I_GEN_H6
+- default 0x00060 if ARCH_SUNXI
+ default 0xfffc0000 if ARCH_ZYNQMP
+ default 0x0
+ help
--- /dev/null
+From 03f3ba82e9dfb67f1ae0812f72aea6559aa61bb4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:23:34 -0500
+Subject: [PATCH 69/90] sunxi: Move SYS_LOAD_ADDR to the board Kconfig
+
+This will provide a default value for RISC-V when that is added, and it
+makes sense to put this option next to the other DRAM layout options.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ Kconfig | 3 ---
+ board/sunxi/Kconfig | 5 +++++
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+--- a/Kconfig
++++ b/Kconfig
+@@ -508,9 +508,6 @@ config SYS_LOAD_ADDR
+ hex "Address in memory to use by default"
+ default 0x01000000 if ARCH_SOCFPGA
+ default 0x02000000 if PPC || X86
+- default 0x81000000 if MACH_SUNIV
+- default 0x22000000 if MACH_SUN9I
+- default 0x42000000 if ARCH_SUNXI
+ default 0x82000000 if ARCH_KEYSTONE || ARCH_OMAP2PLUS || ARCH_K3
+ default 0x82000000 if ARCH_MX6 && (MX6SL || MX6SLL || MX6SX || MX6UL || MX6ULL)
+ default 0x12000000 if ARCH_MX6 && !(MX6SL || MX6SLL || MX6SX || MX6UL || MX6ULL)
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -129,6 +129,11 @@ config SYS_CONFIG_NAME
+ default "sun50i" if MACH_SUN50I_H6
+ default "sun50i" if MACH_SUN50I_H616
+
++config SYS_LOAD_ADDR
++ default 0x81000000 if MACH_SUNIV
++ default 0x22000000 if MACH_SUN9I
++ default 0x42000000
++
+ config SYS_SOC
+ default "sunxi"
+
--- /dev/null
+From 08b45a89c7b25eb7828589360cf4ca2d9910cc59 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 21:48:53 -0500
+Subject: [PATCH 70/90] sunxi: Move TEXT_BASE to the board Kconfig
+
+This is how the vast majority of platforms provided TEXT_BASE.
+sunxi was the exception here.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Kconfig | 6 ++++++
+ boot/Kconfig | 4 ----
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -137,6 +137,12 @@ config SYS_LOAD_ADDR
+ config SYS_SOC
+ default "sunxi"
+
++config TEXT_BASE
++ default 0x81700000 if MACH_SUNIV
++ default 0x2a000000 if MACH_SUN9I
++ default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256
++ default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64
++
+ menu "sunxi board options"
+
+ choice
+--- a/boot/Kconfig
++++ b/boot/Kconfig
+@@ -633,10 +633,6 @@ config TEXT_BASE
+ depends on HAVE_TEXT_BASE
+ default 0x0 if POSITION_INDEPENDENT
+ default 0x80800000 if ARCH_OMAP2PLUS || ARCH_K3
+- default 0x81700000 if MACH_SUNIV
+- default 0x2a000000 if MACH_SUN9I
+- default 0x4a000000 if SUNXI_MINIMUM_DRAM_MB >= 256
+- default 0x42e00000 if SUNXI_MINIMUM_DRAM_MB >= 64
+ hex "Text Base"
+ help
+ The address in memory that U-Boot will be running from, initially.
--- /dev/null
+From 6a1b660a83b262237b6bebed26e44db923a86a6b Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 18:09:19 +0000
+Subject: [PATCH 71/90] sunxi: Move most board options to the board Kconfig
+
+This excludes options that are inherently ARM-specific or are specific
+to legacy non-DM drivers.
+
+Some help text is cleaned up along the way.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/mach-sunxi/Kconfig | 71 ------------------------------------
+ board/sunxi/Kconfig | 72 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 72 insertions(+), 71 deletions(-)
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -548,16 +548,6 @@ config DRAM_ODT_CORRECTION
+ then the correction is negative. Usually the value for this is 0.
+ endif
+
+-config UART0_PORT_F
+- bool "UART0 on MicroSD breakout board"
+- ---help---
+- Repurpose the SD card slot for getting access to the UART0 serial
+- console. Primarily useful only for low level u-boot debugging on
+- tablets, where normal UART0 is difficult to access and requires
+- device disassembly and/or soldering. As the SD card can't be used
+- at the same time, the system can be only booted in the FEL mode.
+- Only enable this if you really know what you are doing.
+-
+ config OLD_SUNXI_KERNEL_COMPAT
+ bool "Enable workarounds for booting old kernels"
+ ---help---
+@@ -571,20 +561,6 @@ config MACPWR
+ Set the pin used to power the MAC. This takes a string in the format
+ understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+
+-config MMC1_PINS_PH
+- bool "Pins for mmc1 are on Port H"
+- depends on MACH_SUN4I || MACH_SUN7I || MACH_SUN8I_R40
+- ---help---
+- Select this option for boards where mmc1 uses the Port H pinmux.
+-
+-config MMC_SUNXI_SLOT_EXTRA
+- int "mmc extra slot number"
+- default -1
+- ---help---
+- sunxi builds always enable mmc0, some boards also have a second sdcard
+- slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable
+- support for this.
+-
+ config I2C0_ENABLE
+ bool "Enable I2C/TWI controller 0"
+ default y if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_R40
+@@ -612,16 +588,6 @@ config R_I2C_ENABLE
+ Set this to y to enable the I2C controller which is part of the PRCM.
+ endif
+
+-config AXP_DISABLE_BOOT_ON_POWERON
+- bool "Disable device boot on power plug-in"
+- depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+- default n
+- ---help---
+- Say Y here to prevent the device from booting up because of a plug-in
+- event. When set, the device will boot into the SPL briefly to
+- determine why it was powered on, and if it was determined because of
+- a plug-in event instead of a button press event it will shut back off.
+-
+ config VIDEO_SUNXI
+ bool "Enable graphical uboot console on HDMI, LCD or VGA"
+ depends on !MACH_SUN8I_A83T
+@@ -850,41 +816,4 @@ config SPL_SPI_SUNXI
+ sunxi SPI Flash. It uses the same method as the boot ROM, so does
+ not need any extra configuration.
+
+-config PINE64_DT_SELECTION
+- bool "Enable Pine64 device tree selection code"
+- depends on MACH_SUN50I
+- help
+- The original Pine A64 and Pine A64+ are similar but different
+- boards and can be differed by the DRAM size. Pine A64 has
+- 512MiB DRAM, and Pine A64+ has 1GiB or 2GiB. By selecting this
+- option, the device tree selection code specific to Pine64 which
+- utilizes the DRAM size will be enabled.
+-
+-config PINEPHONE_DT_SELECTION
+- bool "Enable PinePhone device tree selection code"
+- depends on MACH_SUN50I
+- help
+- Enable this option to automatically select the device tree for the
+- correct PinePhone hardware revision during boot.
+-
+-config BLUETOOTH_DT_DEVICE_FIXUP
+- string "Fixup the Bluetooth controller address"
+- default ""
+- help
+- This option specifies the DT compatible name of the Bluetooth
+- controller for which to set the "local-bd-address" property.
+- Set this option if your device ships with the Bluetooth controller
+- default address.
+- The used address is "bdaddr" if set, and "ethaddr" with the LSB
+- flipped elsewise.
+-
+ endif
+-
+-config CHIP_DIP_SCAN
+- bool "Enable DIPs detection for CHIP board"
+- select SUPPORT_EXTENSION_SCAN
+- select W1
+- select W1_GPIO
+- select W1_EEPROM
+- select W1_EEPROM_DS24XXX
+- select CMD_EXTENSION
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -171,6 +171,78 @@ config SPL_IMAGE_TYPE
+ default "sunxi_egon" if SPL_IMAGE_TYPE_SUNXI_EGON
+ default "sunxi_toc0" if SPL_IMAGE_TYPE_SUNXI_TOC0
+
++config MMC_SUNXI_SLOT_EXTRA
++ int "MMC extra slot number"
++ default -1
++ help
++ sunxi builds always enable mmc0. Some boards also have a
++ second SD card slot or eMMC on mmc1 - mmc3. Setting this to 1,
++ 2 or 3 will enable support for this.
++
++config MMC1_PINS_PH
++ bool "MMC1 pins are on Port H"
++ depends on MACH_SUN4I || MACH_SUN7I || MACH_SUN8I_R40
++ help
++ Select this option on boards where mmc1 uses the Port H pinmux.
++
++config UART0_PORT_F
++ bool "UART0 pins are on Port F (MicroSD breakout board)"
++ help
++ Repurpose the SD card slot for getting access to the UART0
++ serial console. Primarily useful only for low level u-boot
++ debugging on tablets, where normal UART0 is difficult to
++ access and requires device disassembly and/or soldering. As
++ the SD card can't be used at the same time, the system can be
++ only booted in FEL mode. Only enable this if you really know
++ what you are doing.
++
++config AXP_DISABLE_BOOT_ON_POWERON
++ bool "Disable device boot on power plug-in"
++ depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
++ help
++ Say Y here to prevent the device from booting up because of a
++ plug-in event. When set, the device will boot into the SPL
++ briefly to determine why it was powered on, and if the board
++ was powered on because of a plug-in event instead of a button
++ press event, it will shut back off.
++
++config CHIP_DIP_SCAN
++ bool "Enable DIPs detection for CHIP board"
++ select SUPPORT_EXTENSION_SCAN
++ select W1
++ select W1_GPIO
++ select W1_EEPROM
++ select W1_EEPROM_DS24XXX
++ select CMD_EXTENSION
++
++config PINE64_DT_SELECTION
++ bool "Enable Pine64 device tree selection code"
++ depends on MACH_SUN50I
++ help
++ The original Pine A64 and Pine A64+ are similar but different
++ boards and can be differed by the DRAM size. Pine A64 has
++ 512MiB DRAM, and Pine A64+ has 1GiB or 2GiB. By selecting this
++ option, the device tree selection code specific to Pine64 which
++ utilizes the DRAM size will be enabled.
++
++config PINEPHONE_DT_SELECTION
++ bool "Enable PinePhone device tree selection code"
++ depends on MACH_SUN50I
++ help
++ Enable this option to automatically select the device tree for the
++ correct PinePhone hardware revision during boot.
++
++config BLUETOOTH_DT_DEVICE_FIXUP
++ string "Fixup the Bluetooth controller address"
++ default ""
++ help
++ This option specifies the DT compatible name of the Bluetooth
++ controller for which to set the "local-bd-address" property.
++ Set this option if your device ships with the Bluetooth controller
++ default address.
++ The used address is "bdaddr" if set, and "ethaddr" with the LSB
++ flipped elsewise.
++
+ endmenu
+
+ endif
--- /dev/null
+From 27834df51087a005b0330f094492b984cc225f6a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 5 Aug 2022 23:28:54 -0500
+Subject: [PATCH 72/90] env: sunxi: Replace ARCH_SUNXI with BOARD_SUNXI
+
+This ensures the same environment layout will be used across all sunxi
+boards, regardless of CPU architecture.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ env/Kconfig | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/env/Kconfig
++++ b/env/Kconfig
+@@ -92,7 +92,7 @@ config ENV_IS_IN_FAT
+ bool "Environment is in a FAT filesystem"
+ depends on !CHAIN_OF_TRUST
+ default y if ARCH_BCM283X
+- default y if ARCH_SUNXI && MMC
++ default y if BOARD_SUNXI && MMC
+ default y if MMC_OMAP_HS && TI_COMMON_CMD_OPTIONS
+ select FS_FAT
+ select FAT_WRITE
+@@ -338,7 +338,7 @@ config ENV_IS_IN_SPI_FLASH
+ default y if NORTHBRIDGE_INTEL_IVYBRIDGE
+ default y if INTEL_QUARK
+ default y if INTEL_QUEENSBAY
+- default y if ARCH_SUNXI
++ default y if BOARD_SUNXI
+ help
+ Define this if you have a SPI Flash memory device which you
+ want to use for the environment.
+@@ -461,7 +461,7 @@ config ENV_FAT_DEVICE_AND_PART
+ depends on ENV_IS_IN_FAT
+ default "0:1" if TI_COMMON_CMD_OPTIONS
+ default "0:auto" if ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
+- default ":auto" if ARCH_SUNXI
++ default ":auto" if BOARD_SUNXI
+ default "0" if ARCH_AT91
+ help
+ Define this to a string to specify the partition of the device. It can
+@@ -555,7 +555,7 @@ config ENV_OFFSET
+ ENV_IS_IN_SPI_FLASH
+ default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
+ default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
+- default 0xF0000 if ARCH_SUNXI
++ default 0xF0000 if BOARD_SUNXI
+ default 0xE0000 if ARCH_ZYNQ
+ default 0x1E00000 if ARCH_ZYNQMP
+ default 0x7F40000 if ARCH_VERSAL || ARCH_VERSAL_NET
+@@ -580,7 +580,7 @@ config ENV_SIZE
+ hex "Environment Size"
+ default 0x40000 if ENV_IS_IN_SPI_FLASH && ARCH_ZYNQMP
+ default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
+- default 0x10000 if ARCH_SUNXI
++ default 0x10000 if BOARD_SUNXI
+ default 0x8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
+ default 0x2000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
+ default 0x8000 if ARCH_ZYNQMP || ARCH_VERSAL || ARCH_VERSAL_NET
+@@ -596,7 +596,7 @@ config ENV_SECT_SIZE
+ default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL || ARCH_VERSAL_NET
+ default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
+ default 0x20000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH
+- default 0x10000 if ARCH_SUNXI && ENV_IS_IN_SPI_FLASH
++ default 0x10000 if BOARD_SUNXI && ENV_IS_IN_SPI_FLASH
+ help
+ Size of the sector containing the environment.
+
--- /dev/null
+From 666d3c2bc058268a976397ec3e258f532edcfeb2 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 18:12:11 +0000
+Subject: [PATCH 73/90] drivers: sunxi: Replace ARCH_SUNXI with BOARD_SUNXI
+
+This provides a unified configuration across all sunxi boards,
+regardless of CPU architecture.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ drivers/clk/sunxi/Kconfig | 2 +-
+ drivers/fastboot/Kconfig | 13 ++++++-------
+ drivers/gpio/Kconfig | 2 +-
+ drivers/mmc/Kconfig | 2 +-
+ drivers/net/phy/Kconfig | 4 ++--
+ drivers/phy/allwinner/Kconfig | 2 +-
+ drivers/pinctrl/sunxi/Kconfig | 2 +-
+ drivers/reset/Kconfig | 2 +-
+ drivers/spi/Kconfig | 2 +-
+ drivers/usb/Kconfig | 2 +-
+ drivers/usb/gadget/Kconfig | 8 ++++----
+ drivers/usb/musb-new/Kconfig | 2 +-
+ drivers/video/Kconfig | 2 +-
+ drivers/watchdog/Kconfig | 4 ++--
+ 14 files changed, 24 insertions(+), 25 deletions(-)
+
+--- a/drivers/clk/sunxi/Kconfig
++++ b/drivers/clk/sunxi/Kconfig
+@@ -1,6 +1,6 @@
+ config CLK_SUNXI
+ bool "Clock support for Allwinner SoCs"
+- depends on CLK && ARCH_SUNXI
++ depends on CLK && BOARD_SUNXI
+ select DM_RESET
+ select SPL_DM_RESET if SPL_CLK
+ default y
+--- a/drivers/fastboot/Kconfig
++++ b/drivers/fastboot/Kconfig
+@@ -8,7 +8,7 @@ config FASTBOOT
+ config USB_FUNCTION_FASTBOOT
+ bool "Enable USB fastboot gadget"
+ depends on USB_GADGET
+- default y if ARCH_SUNXI && USB_MUSB_GADGET
++ default y if BOARD_SUNXI && USB_MUSB_GADGET
+ select FASTBOOT
+ select USB_GADGET_DOWNLOAD
+ help
+@@ -32,10 +32,9 @@ if FASTBOOT
+
+ config FASTBOOT_BUF_ADDR
+ hex "Define FASTBOOT buffer address"
++ default SYS_LOAD_ADDR if BOARD_SUNXI
+ default 0x82000000 if MX6SX || MX6SL || MX6UL || MX6SLL
+ default 0x81000000 if ARCH_OMAP2PLUS
+- default 0x42000000 if ARCH_SUNXI && !MACH_SUN9I
+- default 0x22000000 if ARCH_SUNXI && MACH_SUN9I
+ default 0x60800800 if ROCKCHIP_RK3036 || ROCKCHIP_RK3188 || \
+ ROCKCHIP_RK322X
+ default 0x800800 if ROCKCHIP_RK3288 || ROCKCHIP_RK3329 || \
+@@ -52,7 +51,7 @@ config FASTBOOT_BUF_SIZE
+ hex "Define FASTBOOT buffer size"
+ default 0x8000000 if ARCH_ROCKCHIP
+ default 0x6000000 if ARCH_ZYNQMP
+- default 0x2000000 if ARCH_SUNXI
++ default 0x2000000 if BOARD_SUNXI
+ default 0x8192 if SANDBOX
+ default 0x7000000
+ help
+@@ -71,7 +70,7 @@ config FASTBOOT_USB_DEV
+
+ config FASTBOOT_FLASH
+ bool "Enable FASTBOOT FLASH command"
+- default y if ARCH_SUNXI || ARCH_ROCKCHIP
++ default y if BOARD_SUNXI || ARCH_ROCKCHIP
+ depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS)
+ select IMAGE_SPARSE
+ help
+@@ -105,8 +104,8 @@ config FASTBOOT_FLASH_MMC_DEV
+ int "Define FASTBOOT MMC FLASH default device"
+ depends on FASTBOOT_FLASH_MMC
+ default 0 if ARCH_ROCKCHIP
+- default 0 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1
+- default 1 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1
++ default 0 if BOARD_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1
++ default 1 if BOARD_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1
+ help
+ The fastboot "flash" command requires additional information
+ regarding the non-volatile storage device. Define this to
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -370,7 +370,7 @@ config SANDBOX_GPIO_COUNT
+
+ config SUNXI_GPIO
+ bool "Allwinner GPIO driver"
+- depends on ARCH_SUNXI
++ depends on BOARD_SUNXI
+ select SPL_STRTO if SPL
+ help
+ Support the GPIO device in Allwinner SoCs.
+--- a/drivers/mmc/Kconfig
++++ b/drivers/mmc/Kconfig
+@@ -756,7 +756,7 @@ config ZYNQ_HISPD_BROKEN
+
+ config MMC_SUNXI
+ bool "Allwinner sunxi SD/MMC Host Controller support"
+- depends on ARCH_SUNXI
++ depends on BOARD_SUNXI
+ default y
+ help
+ This selects support for the SD/MMC Host Controller on
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -19,14 +19,14 @@ if PHYLIB
+
+ config PHY_ADDR_ENABLE
+ bool "Limit phy address"
+- default y if ARCH_SUNXI
++ default y if BOARD_SUNXI
+ help
+ Select this if you want to control which phy address is used
+
+ if PHY_ADDR_ENABLE
+ config PHY_ADDR
+ int "PHY address"
+- default 1 if ARCH_SUNXI
++ default 1 if BOARD_SUNXI
+ default 0
+ help
+ The address of PHY on MII bus. Usually in range of 0 to 31.
+--- a/drivers/phy/allwinner/Kconfig
++++ b/drivers/phy/allwinner/Kconfig
+@@ -3,7 +3,7 @@
+ #
+ config PHY_SUN4I_USB
+ bool "Allwinner Sun4I USB PHY driver"
+- depends on ARCH_SUNXI && !MACH_SUN9I
++ depends on depends on BOARD_SUNXI
+ default y
+ select DM_REGULATOR
+ select PHY
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+
+-if ARCH_SUNXI
++if BOARD_SUNXI
+
+ config PINCTRL_SUNXI
+ select PINCTRL_FULL
+--- a/drivers/reset/Kconfig
++++ b/drivers/reset/Kconfig
+@@ -137,7 +137,7 @@ config RESET_MTMIPS
+
+ config RESET_SUNXI
+ bool "RESET support for Allwinner SoCs"
+- depends on DM_RESET && ARCH_SUNXI
++ depends on DM_RESET && BOARD_SUNXI
+ default y
+ help
+ This enables support for common reset driver for
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -453,7 +453,7 @@ config SOFT_SPI
+
+ config SPI_SUNXI
+ bool "Allwinner SoC SPI controllers"
+- default ARCH_SUNXI
++ default BOARD_SUNXI
+ help
+ Enable the Allwinner SoC SPi controller driver.
+
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -116,7 +116,7 @@ config USB_KEYBOARD_FN_KEYS
+
+ choice
+ prompt "USB keyboard polling"
+- default SYS_USB_EVENT_POLL_VIA_INT_QUEUE if ARCH_SUNXI
++ default SYS_USB_EVENT_POLL_VIA_INT_QUEUE if BOARD_SUNXI
+ default SYS_USB_EVENT_POLL
+ ---help---
+ Enable a polling mechanism for USB keyboard.
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -40,7 +40,7 @@ if USB_GADGET
+
+ config USB_GADGET_MANUFACTURER
+ string "Vendor name of the USB device"
+- default "Allwinner Technology" if ARCH_SUNXI
++ default "Allwinner Technology" if BOARD_SUNXI
+ default "Rockchip" if ARCH_ROCKCHIP
+ default "U-Boot"
+ help
+@@ -49,7 +49,7 @@ config USB_GADGET_MANUFACTURER
+
+ config USB_GADGET_VENDOR_NUM
+ hex "Vendor ID of the USB device"
+- default 0x1f3a if ARCH_SUNXI
++ default 0x1f3a if BOARD_SUNXI
+ default 0x2207 if ARCH_ROCKCHIP
+ default 0x0
+ help
+@@ -59,7 +59,7 @@ config USB_GADGET_VENDOR_NUM
+
+ config USB_GADGET_PRODUCT_NUM
+ hex "Product ID of the USB device"
+- default 0x1010 if ARCH_SUNXI
++ default 0x1010 if BOARD_SUNXI
+ default 0x310a if ROCKCHIP_RK3036
+ default 0x300a if ROCKCHIP_RK3066
+ default 0x310c if ROCKCHIP_RK3128
+@@ -202,7 +202,7 @@ endif # USB_GADGET_DOWNLOAD
+ config USB_ETHER
+ bool "USB Ethernet Gadget"
+ depends on NET
+- default y if ARCH_SUNXI && USB_MUSB_GADGET
++ default y if BOARD_SUNXI && USB_MUSB_GADGET
+ help
+ Creates an Ethernet network device through a USB peripheral
+ controller. This will create a network interface on both the device
+--- a/drivers/usb/musb-new/Kconfig
++++ b/drivers/usb/musb-new/Kconfig
+@@ -67,7 +67,7 @@ config USB_MUSB_PIC32
+
+ config USB_MUSB_SUNXI
+ bool "Enable sunxi OTG / DRC USB controller"
+- depends on ARCH_SUNXI
++ depends on BOARD_SUNXI
+ select USB_MUSB_PIO_ONLY
+ default y
+ ---help---
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -183,7 +183,7 @@ config CONSOLE_TRUETYPE_MAX_METRICS
+
+ config SYS_WHITE_ON_BLACK
+ bool "Display console as white on a black background"
+- default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI
++ default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || BOARD_SUNXI
+ help
+ Normally the display is black on a white background, Enable this
+ option to invert this, i.e. white on a black background. This can be
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -29,7 +29,7 @@ config WATCHDOG_TIMEOUT_MSECS
+ default 128000 if ARCH_MX31 || ARCH_MX5 || ARCH_MX6
+ default 128000 if ARCH_MX7 || ARCH_VF610
+ default 30000 if ARCH_SOCFPGA
+- default 16000 if ARCH_SUNXI
++ default 16000 if BOARD_SUNXI
+ default 60000
+ help
+ Watchdog timeout in msec
+@@ -321,7 +321,7 @@ config WDT_STM32MP
+
+ config WDT_SUNXI
+ bool "Allwinner sunxi watchdog timer support"
+- depends on WDT && ARCH_SUNXI
++ depends on WDT && BOARD_SUNXI
+ default y
+ help
+ Enable support for the watchdog timer in Allwinner sunxi SoCs.
--- /dev/null
+From 98fb93ceb936b375d7f8f2908f0703a93e27fbc4 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:05:52 -0500
+Subject: [PATCH 74/90] disk: sunxi: Replace ARCH_SUNXI with BOARD_SUNXI
+
+This provides a unified configuration across all sunxi boards,
+regardless of CPU architecture.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ disk/Kconfig | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/disk/Kconfig
++++ b/disk/Kconfig
+@@ -61,7 +61,7 @@ config SPL_DOS_PARTITION
+ bool "Enable MS Dos partition table for SPL"
+ depends on SPL
+ default n if ARCH_MVEBU
+- default n if ARCH_SUNXI
++ default n if BOARD_SUNXI
+ default y if DOS_PARTITION
+ select SPL_PARTITIONS
+
+@@ -104,7 +104,7 @@ config EFI_PARTITION
+ config EFI_PARTITION_ENTRIES_NUMBERS
+ int "Number of the EFI partition entries"
+ depends on EFI_PARTITION
+- default 56 if ARCH_SUNXI
++ default 56 if BOARD_SUNXI
+ default 128
+ help
+ Specify the number of partition entries in the GPT. This is
+@@ -132,7 +132,7 @@ config SPL_EFI_PARTITION
+ bool "Enable EFI GPT partition table for SPL"
+ depends on SPL
+ default n if ARCH_MVEBU
+- default n if ARCH_SUNXI
++ default n if BOARD_SUNXI
+ default y if EFI_PARTITION
+ select SPL_PARTITIONS
+
--- /dev/null
+From 7f06dca4df9302a22a8d27af887da50a67b7dd1d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:09:38 -0500
+Subject: [PATCH 75/90] spl: sunxi: Replace ARCH_SUNXI with BOARD_SUNXI
+
+This provides a unified configuration across all sunxi boards,
+regardless of CPU architecture.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ common/spl/Kconfig | 12 ++++++------
+ scripts/Makefile.spl | 2 +-
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -111,7 +111,7 @@ config SPL_PAD_TO
+ config SPL_HAS_BSS_LINKER_SECTION
+ depends on SPL_FRAMEWORK
+ bool "Use a specific address for the BSS via the linker script"
+- default y if ARCH_SUNXI || ARCH_MX6 || ARCH_OMAP2PLUS || MIPS || RISCV || ARCH_ZYNQMP
++ default y if ARCH_MX6 || ARCH_OMAP2PLUS || ARCH_ZYNQMP || BOARD_SUNXI || MIPS || RISCV
+
+ config SPL_BSS_START_ADDR
+ hex "Link address for the BSS within the SPL binary"
+@@ -335,7 +335,7 @@ config SPL_SYS_MALLOC_SIMPLE
+ config SPL_SHARES_INIT_SP_ADDR
+ bool "SPL and U-Boot use the same initial stack pointer location"
+ depends on (ARM || ARCH_JZ47XX || MICROBLAZE || RISCV) && SPL_FRAMEWORK
+- default n if ARCH_SUNXI || ARCH_MX6 || ARCH_MX7
++ default n if BOARD_SUNXI || ARCH_MX6 || ARCH_MX7
+ default y
+ help
+ In many cases, we can use the same initial stack pointer address for
+@@ -453,7 +453,7 @@ config SPL_DISPLAY_PRINT
+
+ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+ bool "MMC raw mode: by sector"
+- default y if ARCH_SUNXI || ARCH_DAVINCI || ARCH_UNIPHIER || \
++ default y if BOARD_SUNXI || ARCH_DAVINCI || ARCH_UNIPHIER || \
+ ARCH_MX6 || ARCH_MX7 || \
+ ARCH_ROCKCHIP || ARCH_MVEBU || ARCH_SOCFPGA || \
+ ARCH_AT91 || ARCH_ZYNQ || ARCH_KEYSTONE || OMAP34XX || \
+@@ -466,7 +466,7 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SEC
+ 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 0x40 if ARCH_SUNXI
++ default 0x40 if BOARD_SUNXI
+ default 0x75 if ARCH_DAVINCI
+ default 0x8a if ARCH_MX6 || ARCH_MX7
+ default 0x100 if ARCH_UNIPHIER
+@@ -483,7 +483,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 0x10 if BOARD_SUNXI
+ default 0x0
+ help
+ On some platforms SPL location depends on hardware partition. The ROM
+@@ -1308,7 +1308,7 @@ endif # SPL_SPI_FLASH_SUPPORT
+
+ config SYS_SPI_U_BOOT_OFFS
+ hex "address of u-boot payload in SPI flash"
+- default 0x8000 if ARCH_SUNXI
++ default 0x8000 if BOARD_SUNXI
+ default 0x0
+ depends on SPL_SPI_LOAD || SPL_SPI_SUNXI
+ help
+--- a/scripts/Makefile.spl
++++ b/scripts/Makefile.spl
+@@ -264,7 +264,7 @@ endif
+
+ INPUTS-$(CONFIG_TARGET_SOCFPGA_SOC64) += $(obj)/u-boot-spl-dtb.hex
+
+-ifdef CONFIG_ARCH_SUNXI
++ifdef CONFIG_BOARD_SUNXI
+ INPUTS-y += $(obj)/sunxi-spl.bin
+
+ ifdef CONFIG_NAND_SUNXI
--- /dev/null
+From b6da98cd39612bb5660afbcad06e3a6bac43563e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 11 Sep 2021 23:27:42 -0500
+Subject: [PATCH 76/90] riscv: cpu: Add cache operations for T-HEAD CPUs
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/cpu/Makefile | 1 +
+ arch/riscv/cpu/thead/cache.c | 119 +++++++++++++++++++++++++++++++++++
+ arch/riscv/lib/cache.c | 2 +-
+ 3 files changed, 121 insertions(+), 1 deletion(-)
+ create mode 100644 arch/riscv/cpu/thead/cache.c
+
+--- a/arch/riscv/cpu/Makefile
++++ b/arch/riscv/cpu/Makefile
+@@ -5,3 +5,4 @@
+ extra-y = start.o
+
+ obj-y += cpu.o mtrap.o
++obj-y += thead/cache.o
+--- /dev/null
++++ b/arch/riscv/cpu/thead/cache.c
+@@ -0,0 +1,119 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <asm/cache.h>
++#include <asm/csr.h>
++
++#define CSR_MHCR 0x7c1
++#define CSR_MCOR 0x7c2
++#define CSR_MHINT 0x7c5
++
++#define MHCR_IE BIT(0) /* icache enable */
++#define MHCR_DE BIT(1) /* dcache enable */
++#define MHCR_WA BIT(2) /* dcache write allocate */
++#define MHCR_WB BIT(3) /* dcache write back */
++#define MHCR_RS BIT(4) /* return stack enable */
++#define MHCR_BPE BIT(5) /* branch prediction enable */
++#define MHCR_BTB BIT(6) /* branch target prediction enable */
++#define MHCR_WBR BIT(8) /* write burst enable */
++#define MHCR_L0BTB BIT(12)
++
++#define MCOR_CACHE_SEL_ICACHE (0x1 << 0)
++#define MCOR_CACHE_SEL_DCACHE (0x2 << 0)
++#define MCOR_CACHE_SEL_BOTH (0x3 << 0)
++#define MCOR_INV BIT(4)
++#define MCOR_CLR BIT(5)
++#define MCOR_BHT_INV BIT(16)
++#define MCOR_BTB_INV BIT(17)
++
++#define MHINT_DPLD BIT(2) /* dcache prefetch enable */
++#define MHINT_AMR_PAGE (0x0 << 3)
++#define MHINT_AMR_LIMIT_3 (0x1 << 3)
++#define MHINT_AMR_LIMIT_64 (0x2 << 3)
++#define MHINT_AMR_LIMIT_128 (0x3 << 3)
++#define MHINT_IPLD BIT(8) /* icache prefetch enable */
++#define MHINT_IWPE BIT(9) /* icache prediction enable */
++#define MHINT_DIS_PREFETCH_2 (0x0 << 13)
++#define MHINT_DIS_PREFETCH_4 (0x1 << 13)
++#define MHINT_DIS_PREFETCH_8 (0x2 << 13)
++#define MHINT_DIS_PREFETCH_16 (0x3 << 13)
++
++#define sync_i() asm volatile (".long 0x01a0000b" ::: "memory")
++
++void flush_dcache_all(void)
++{
++ asm volatile (".long 0x0030000b" ::: "memory"); /* dcache.ciall */
++ sync_i();
++}
++
++void flush_dcache_range(unsigned long start, unsigned long end)
++{
++ register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
++
++ for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
++ asm volatile (".long 0x02b5000b" ::: "memory"); /* dcache.cipa a0 */
++ sync_i();
++}
++
++void invalidate_icache_range(unsigned long start, unsigned long end)
++{
++ register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
++
++ for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
++ asm volatile (".long 0x0385000b" ::: "memory"); /* icache.ipa a0 */
++ sync_i();
++}
++
++void invalidate_dcache_range(unsigned long start, unsigned long end)
++{
++ register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;
++
++ for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
++ asm volatile (".long 0x02a5000b" ::: "memory"); /* dcache.ipa a0 */
++ sync_i();
++}
++
++#if 0
++void icache_enable(void)
++{
++ asm volatile (".long 0x0100000b" ::: "memory"); /* icache.iall */
++ sync_i();
++ csr_set(CSR_MHCR, MHCR_IE | MHCR_RS | MHCR_BPE | MHCR_BTB | MHCR_L0BTB);
++ csr_set(CSR_MHINT, MHINT_IPLD | MHINT_IWPE);
++}
++
++void icache_disable(void)
++{
++ csr_clear(CSR_MHCR, MHCR_IE);
++}
++
++int icache_status(void)
++{
++ return csr_read(CSR_MHCR) & MHCR_IE;
++}
++
++void dcache_enable(void)
++{
++ asm volatile (".long 0x0020000b" ::: "memory"); /* dcache.iall */
++ sync_i();
++ csr_set(CSR_MHCR, MHCR_DE | MHCR_WA | MHCR_WB | MHCR_WBR);
++ csr_set(CSR_MHINT, MHINT_DPLD | MHINT_AMR_LIMIT_3);
++}
++
++void dcache_disable(void)
++{
++ asm volatile (".long 0x0010000b" ::: "memory"); /* dcache.call */
++ sync_i();
++ csr_clear(CSR_MHCR, MHCR_DE);
++}
++
++int dcache_status(void)
++{
++ return csr_read(CSR_MHCR) & MHCR_DE;
++}
++
++void enable_caches(void)
++{
++ icache_enable();
++ dcache_enable();
++}
++#endif
+--- a/arch/riscv/lib/cache.c
++++ b/arch/riscv/lib/cache.c
+@@ -20,7 +20,7 @@ __weak void flush_dcache_range(unsigned
+ {
+ }
+
+-void invalidate_icache_range(unsigned long start, unsigned long end)
++__weak void invalidate_icache_range(unsigned long start, unsigned long end)
+ {
+ /*
+ * RISC-V does not have an instruction for invalidating parts of the
--- /dev/null
+From 35da34adec7b5b06ad81455a21c67a9c1152e2c9 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 7 Aug 2021 12:09:35 -0500
+Subject: [PATCH 77/90] riscv: Sort target configs alphabetically
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/Kconfig | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -14,6 +14,9 @@ config TARGET_AX25_AE350
+ config TARGET_MICROCHIP_ICICLE
+ bool "Support Microchip PolarFire-SoC Icicle Board"
+
++config TARGET_OPENPITON_RISCV64
++ bool "Support RISC-V cores on OpenPiton SoC"
++
+ config TARGET_QEMU_VIRT
+ bool "Support QEMU Virt Board"
+
+@@ -28,9 +31,6 @@ config TARGET_SIPEED_MAIX
+ bool "Support Sipeed Maix Board"
+ select SYS_CACHE_SHIFT_6
+
+-config TARGET_OPENPITON_RISCV64
+- bool "Support RISC-V cores on OpenPiton SoC"
+-
+ endchoice
+
+ config SYS_ICACHE_OFF
+@@ -61,9 +61,9 @@ config SPL_SYS_DCACHE_OFF
+ source "board/AndesTech/ax25-ae350/Kconfig"
+ source "board/emulation/qemu-riscv/Kconfig"
+ source "board/microchip/mpfs_icicle/Kconfig"
++source "board/openpiton/riscv64/Kconfig"
+ source "board/sifive/unleashed/Kconfig"
+ source "board/sifive/unmatched/Kconfig"
+-source "board/openpiton/riscv64/Kconfig"
+ source "board/sipeed/maix/Kconfig"
+
+ # platform-specific options below
--- /dev/null
+From ce792f7abd4294ebba76f76d9d7aa90c7970de8e Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 4 Aug 2022 23:35:09 -0500
+Subject: [PATCH 78/90] riscv: Add Allwinner D1 devicetrees
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/dts/Makefile | 9 +
+ .../riscv/dts/sun20i-d1-clockworkpi-v3.14.dts | 242 +++++
+ .../dts/sun20i-d1-common-regulators.dtsi | 51 +
+ arch/riscv/dts/sun20i-d1-devterm-v3.14.dts | 37 +
+ .../dts/sun20i-d1-dongshan-nezha-stu.dts | 114 +++
+ .../dts/sun20i-d1-lichee-rv-86-panel-480p.dts | 29 +
+ .../dts/sun20i-d1-lichee-rv-86-panel-720p.dts | 10 +
+ .../dts/sun20i-d1-lichee-rv-86-panel.dtsi | 92 ++
+ arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts | 74 ++
+ arch/riscv/dts/sun20i-d1-lichee-rv.dts | 84 ++
+ arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts | 128 +++
+ arch/riscv/dts/sun20i-d1-nezha.dts | 171 ++++
+ arch/riscv/dts/sun20i-d1.dtsi | 900 ++++++++++++++++++
+ arch/riscv/dts/sunxi-u-boot.dtsi | 68 ++
+ include/dt-bindings/clock/sun20i-d1-r-ccu.h | 19 +
+ include/dt-bindings/reset/sun20i-d1-r-ccu.h | 16 +
+ 16 files changed, 2044 insertions(+)
+ create mode 100644 arch/riscv/dts/sun20i-d1-clockworkpi-v3.14.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-common-regulators.dtsi
+ create mode 100644 arch/riscv/dts/sun20i-d1-devterm-v3.14.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-dongshan-nezha-stu.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-480p.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-720p.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-lichee-rv-86-panel.dtsi
+ create mode 100644 arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-lichee-rv.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1-nezha.dts
+ create mode 100644 arch/riscv/dts/sun20i-d1.dtsi
+ create mode 100644 arch/riscv/dts/sunxi-u-boot.dtsi
+ create mode 100644 include/dt-bindings/clock/sun20i-d1-r-ccu.h
+ create mode 100644 include/dt-bindings/reset/sun20i-d1-r-ccu.h
+
+--- a/arch/riscv/dts/Makefile
++++ b/arch/riscv/dts/Makefile
+@@ -7,6 +7,15 @@ dtb-$(CONFIG_TARGET_OPENPITON_RISCV64) +
+ dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb
+ dtb-$(CONFIG_TARGET_SIFIVE_UNMATCHED) += hifive-unmatched-a00.dtb
+ dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-clockworkpi-v3.14.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-devterm-v3.14.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-dongshan-nezha-stu.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-lichee-rv-86-panel-480p.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-lichee-rv-86-panel-720p.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-lichee-rv-dock.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-lichee-rv.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-mangopi-mq-pro.dtb
++dtb-$(CONFIG_TARGET_SUN20I_D1) += sun20i-d1-nezha.dtb
+
+ include $(srctree)/scripts/Makefile.dts
+
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-clockworkpi-v3.14.dts
+@@ -0,0 +1,242 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++#include "sun20i-d1.dtsi"
++#include "sun20i-d1-common-regulators.dtsi"
++
++/ {
++ model = "ClockworkPi v3.14 (R-01)";
++ compatible = "clockwork,r-01-clockworkpi-v3.14", "allwinner,sun20i-d1";
++
++ aliases {
++ ethernet0 = &ap6256;
++ mmc0 = &mmc0;
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ /*
++ * This regulator is PWM-controlled, but the PWM controller is not
++ * yet supported, so fix the regulator to its default voltage.
++ */
++ reg_vdd_cpu: vdd-cpu {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-cpu";
++ regulator-min-microvolt = <1100000>;
++ regulator-max-microvolt = <1100000>;
++ vin-supply = <®_vcc>;
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>; /* PG11/GPIO3 */
++ };
++};
++
++&cpu0 {
++ cpu-supply = <®_vdd_cpu>;
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&i2c0 {
++ pinctrl-0 = <&i2c0_pb10_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ axp221: pmic@34 {
++ compatible = "x-powers,axp228", "x-powers,axp221";
++ reg = <0x34>;
++ interrupt-parent = <&pio>;
++ interrupts = <4 9 IRQ_TYPE_LEVEL_LOW>; /* PE9/GPIO2 */
++ interrupt-controller;
++ #interrupt-cells = <1>;
++
++ ac_power_supply: ac-power {
++ compatible = "x-powers,axp221-ac-power-supply";
++ };
++
++ axp_adc: adc {
++ compatible = "x-powers,axp221-adc";
++ #io-channel-cells = <1>;
++ };
++
++ battery_power_supply: battery-power {
++ compatible = "x-powers,axp221-battery-power-supply";
++ };
++
++ regulators {
++ x-powers,dcdc-freq = <3000>;
++
++ reg_dcdc1: dcdc1 {
++ regulator-name = "sys-3v3";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_dcdc3: dcdc3 {
++ regulator-name = "sys-1v8";
++ regulator-always-on;
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ reg_aldo1: aldo1 {
++ regulator-name = "aud-3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_aldo2: aldo2 {
++ regulator-name = "disp-3v3";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_aldo3: aldo3 {
++ regulator-name = "vdd-wifi";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ /* DLDO1 and ELDO1-3 are connected in parallel. */
++ reg_dldo1: dldo1 {
++ regulator-name = "vbat-wifi-a";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ /* DLDO2-DLDO4 are connected in parallel. */
++ reg_dldo2: dldo2 {
++ regulator-name = "vcc-3v3-ext-a";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_dldo3: dldo3 {
++ regulator-name = "vcc-3v3-ext-b";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_dldo4: dldo4 {
++ regulator-name = "vcc-3v3-ext-c";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_eldo1: eldo1 {
++ regulator-name = "vbat-wifi-b";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_eldo2: eldo2 {
++ regulator-name = "vbat-wifi-c";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ reg_eldo3: eldo3 {
++ regulator-name = "vbat-wifi-d";
++ regulator-always-on;
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++ };
++
++ usb_power_supply: usb-power {
++ compatible = "x-powers,axp221-usb-power-supply";
++ status = "disabled";
++ };
++ };
++};
++
++&mmc0 {
++ broken-cd;
++ bus-width = <4>;
++ disable-wp;
++ vmmc-supply = <®_dcdc1>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&mmc1 {
++ bus-width = <4>;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ non-removable;
++ vmmc-supply = <®_dldo1>;
++ vqmmc-supply = <®_aldo3>;
++ pinctrl-0 = <&mmc1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ ap6256: wifi@1 {
++ compatible = "brcm,bcm43456-fmac", "brcm,bcm4329-fmac";
++ reg = <1>;
++ interrupt-parent = <&pio>;
++ interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10/GPIO4 */
++ interrupt-names = "host-wake";
++ };
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&pio {
++ vcc-pg-supply = <®_ldoa>;
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pb8_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&uart1 {
++ uart-has-rtscts;
++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ bluetooth {
++ compatible = "brcm,bcm4345c5";
++ interrupt-parent = <&pio>;
++ interrupts = <6 17 IRQ_TYPE_LEVEL_HIGH>; /* PG17/GPIO6 */
++ device-wakeup-gpios = <&pio 6 16 GPIO_ACTIVE_HIGH>; /* PG16/GPIO7 */
++ shutdown-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18/GPIO5 */
++ max-speed = <1500000>;
++ vbat-supply = <®_dldo1>;
++ vddio-supply = <®_aldo3>;
++ };
++};
++
++&usb_otg {
++ dr_mode = "peripheral";
++ status = "okay";
++};
++
++&usbphy {
++ usb0_vbus_power-supply = <&ac_power_supply>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-common-regulators.dtsi
+@@ -0,0 +1,51 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++/ {
++ reg_vcc: vcc {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ };
++
++ reg_vcc_3v3: vcc-3v3 {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ vin-supply = <®_vcc>;
++ };
++};
++
++&lradc {
++ vref-supply = <®_aldo>;
++};
++
++&pio {
++ vcc-pb-supply = <®_vcc_3v3>;
++ vcc-pc-supply = <®_vcc_3v3>;
++ vcc-pd-supply = <®_vcc_3v3>;
++ vcc-pe-supply = <®_vcc_3v3>;
++ vcc-pf-supply = <®_vcc_3v3>;
++ vcc-pg-supply = <®_vcc_3v3>;
++};
++
++®_aldo {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ vdd33-supply = <®_vcc_3v3>;
++};
++
++®_hpldo {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ hpldoin-supply = <®_vcc_3v3>;
++};
++
++®_ldoa {
++ regulator-always-on;
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ ldo-in-supply = <®_vcc_3v3>;
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-devterm-v3.14.dts
+@@ -0,0 +1,37 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include "sun20i-d1-clockworkpi-v3.14.dts"
++
++/ {
++ model = "Clockwork DevTerm (R-01)";
++ compatible = "clockwork,r-01-devterm-v3.14",
++ "clockwork,r-01-clockworkpi-v3.14",
++ "allwinner,sun20i-d1";
++
++ fan {
++ compatible = "gpio-fan";
++ gpios = <&pio 3 10 GPIO_ACTIVE_HIGH>; /* PD10/GPIO41 */
++ gpio-fan,speed-map = <0 0>,
++ <6000 1>;
++ #cooling-cells = <2>;
++ };
++
++ i2c-gpio-0 {
++ compatible = "i2c-gpio";
++ sda-gpios = <&pio 3 14 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; /* PD14/GPIO44 */
++ scl-gpios = <&pio 3 15 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; /* PD15/GPIO45 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ adc@54 {
++ compatible = "ti,adc101c";
++ reg = <0x54>;
++ interrupt-parent = <&pio>;
++ interrupts = <4 12 IRQ_TYPE_LEVEL_LOW>; /* PE12/GPIO35 */
++ vref-supply = <®_dldo2>;
++ };
++ };
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-dongshan-nezha-stu.dts
+@@ -0,0 +1,114 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/leds/common.h>
++
++#include "sun20i-d1.dtsi"
++#include "sun20i-d1-common-regulators.dtsi"
++
++/ {
++ model = "Dongshan Nezha STU";
++ compatible = "100ask,dongshan-nezha-stu", "allwinner,sun20i-d1";
++
++ aliases {
++ ethernet0 = &emac;
++ mmc0 = &mmc0;
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led-0 {
++ color = <LED_COLOR_ID_GREEN>;
++ function = LED_FUNCTION_STATUS;
++ gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>; /* PC1 */
++ };
++ };
++
++ reg_usbvbus: usbvbus {
++ compatible = "regulator-fixed";
++ regulator-name = "usbvbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ gpio = <&pio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */
++ enable-active-high;
++ vin-supply = <®_vcc>;
++ };
++
++ /*
++ * This regulator is PWM-controlled, but the PWM controller is not
++ * yet supported, so fix the regulator to its default voltage.
++ */
++ reg_vdd_cpu: vdd-cpu {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-cpu";
++ regulator-min-microvolt = <1100000>;
++ regulator-max-microvolt = <1100000>;
++ vin-supply = <®_vcc>;
++ };
++};
++
++&cpu0 {
++ cpu-supply = <®_vdd_cpu>;
++};
++
++&ehci0 {
++ status = "okay";
++};
++
++&emac {
++ pinctrl-0 = <&rgmii_pe_pins>;
++ pinctrl-names = "default";
++ phy-handle = <&ext_rgmii_phy>;
++ phy-mode = "rgmii-id";
++ phy-supply = <®_vcc_3v3>;
++ status = "okay";
++};
++
++&mdio {
++ ext_rgmii_phy: ethernet-phy@1 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <1>;
++ };
++};
++
++&mmc0 {
++ broken-cd;
++ bus-width = <4>;
++ disable-wp;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&ohci0 {
++ status = "okay";
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pb8_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&usb_otg {
++ dr_mode = "otg";
++ status = "okay";
++};
++
++&usbphy {
++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */
++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */
++ usb0_vbus-supply = <®_usbvbus>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-480p.dts
+@@ -0,0 +1,29 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++#include "sun20i-d1-lichee-rv-86-panel.dtsi"
++
++/ {
++ model = "Sipeed Lichee RV 86 Panel (480p)";
++ compatible = "sipeed,lichee-rv-86-panel-480p", "sipeed,lichee-rv",
++ "allwinner,sun20i-d1";
++};
++
++&i2c2 {
++ pinctrl-0 = <&i2c2_pb0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ touchscreen@48 {
++ compatible = "focaltech,ft6236";
++ reg = <0x48>;
++ interrupt-parent = <&pio>;
++ interrupts = <6 14 IRQ_TYPE_LEVEL_LOW>; /* PG14 */
++ iovcc-supply = <®_vcc_3v3>;
++ reset-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */
++ touchscreen-size-x = <480>;
++ touchscreen-size-y = <480>;
++ vcc-supply = <®_vcc_3v3>;
++ wakeup-source;
++ };
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-720p.dts
+@@ -0,0 +1,10 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++#include "sun20i-d1-lichee-rv-86-panel.dtsi"
++
++/ {
++ model = "Sipeed Lichee RV 86 Panel (720p)";
++ compatible = "sipeed,lichee-rv-86-panel-720p", "sipeed,lichee-rv",
++ "allwinner,sun20i-d1";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel.dtsi
+@@ -0,0 +1,92 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++#include "sun20i-d1-lichee-rv.dts"
++
++/ {
++ aliases {
++ ethernet0 = &emac;
++ ethernet1 = &xr829;
++ };
++
++ /* PC1 is repurposed as BT_WAKE_AP */
++ /delete-node/ leds;
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ clocks = <&ccu CLK_FANOUT1>;
++ clock-names = "ext_clock";
++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
++ assigned-clocks = <&ccu CLK_FANOUT1>;
++ assigned-clock-rates = <32768>;
++ pinctrl-0 = <&clk_pg11_pin>;
++ pinctrl-names = "default";
++ };
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&emac {
++ pinctrl-0 = <&rmii_pe_pins>;
++ pinctrl-names = "default";
++ phy-handle = <&ext_rmii_phy>;
++ phy-mode = "rmii";
++ phy-supply = <®_vcc_3v3>;
++ status = "okay";
++};
++
++&mdio {
++ ext_rmii_phy: ethernet-phy@1 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <1>;
++ reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */
++ };
++};
++
++&mmc1 {
++ bus-width = <4>;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ non-removable;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ xr829: wifi@1 {
++ reg = <1>;
++ };
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&pio {
++ clk_pg11_pin: clk-pg11-pin {
++ pins = "PG11";
++ function = "clk";
++ };
++};
++
++&uart1 {
++ uart-has-rtscts;
++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ /* XR829 bluetooth is connected here */
++};
++
++&usb_otg {
++ status = "disabled";
++};
++
++&usbphy {
++ /* PD20 and PD21 are repurposed for the LCD panel */
++ /delete-property/ usb0_id_det-gpios;
++ /delete-property/ usb0_vbus_det-gpios;
++ usb1_vbus-supply = <®_vcc>;
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts
+@@ -0,0 +1,74 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++#include <dt-bindings/input/input.h>
++
++#include "sun20i-d1-lichee-rv.dts"
++
++/ {
++ model = "Sipeed Lichee RV Dock";
++ compatible = "sipeed,lichee-rv-dock", "sipeed,lichee-rv",
++ "allwinner,sun20i-d1";
++
++ aliases {
++ ethernet1 = &rtl8723ds;
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
++ };
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&lradc {
++ status = "okay";
++
++ button-220 {
++ label = "OK";
++ linux,code = <KEY_OK>;
++ channel = <0>;
++ voltage = <220000>;
++ };
++};
++
++&mmc1 {
++ bus-width = <4>;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ non-removable;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ rtl8723ds: wifi@1 {
++ reg = <1>;
++ };
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&uart1 {
++ uart-has-rtscts;
++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ bluetooth {
++ compatible = "realtek,rtl8723ds-bt";
++ device-wake-gpios = <&pio 6 15 GPIO_ACTIVE_HIGH>; /* PG16 */
++ enable-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18 */
++ host-wake-gpios = <&pio 6 17 GPIO_ACTIVE_HIGH>; /* PG17 */
++ };
++};
++
++&usbphy {
++ usb1_vbus-supply = <®_vcc>;
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv.dts
+@@ -0,0 +1,84 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/leds/common.h>
++
++#include "sun20i-d1.dtsi"
++#include "sun20i-d1-common-regulators.dtsi"
++
++/ {
++ model = "Sipeed Lichee RV";
++ compatible = "sipeed,lichee-rv", "allwinner,sun20i-d1";
++
++ aliases {
++ mmc0 = &mmc0;
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led-0 {
++ color = <LED_COLOR_ID_GREEN>;
++ function = LED_FUNCTION_STATUS;
++ gpios = <&pio 2 1 GPIO_ACTIVE_HIGH>; /* PC1 */
++ };
++ };
++
++ reg_vdd_cpu: vdd-cpu {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-cpu";
++ regulator-min-microvolt = <900000>;
++ regulator-max-microvolt = <900000>;
++ vin-supply = <®_vcc>;
++ };
++};
++
++&cpu0 {
++ cpu-supply = <®_vdd_cpu>;
++};
++
++&ehci0 {
++ status = "okay";
++};
++
++&mmc0 {
++ broken-cd;
++ bus-width = <4>;
++ disable-wp;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&ohci0 {
++ status = "okay";
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pb8_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&usb_otg {
++ dr_mode = "otg";
++ status = "okay";
++};
++
++&usbphy {
++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */
++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */
++ usb0_vbus-supply = <®_vcc>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts
+@@ -0,0 +1,128 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++#include "sun20i-d1.dtsi"
++#include "sun20i-d1-common-regulators.dtsi"
++
++/ {
++ model = "MangoPi MQ Pro";
++ compatible = "widora,mangopi-mq-pro", "allwinner,sun20i-d1";
++
++ aliases {
++ ethernet0 = &rtl8723ds;
++ mmc0 = &mmc0;
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ reg_avdd2v8: avdd2v8 {
++ compatible = "regulator-fixed";
++ regulator-name = "avdd2v8";
++ regulator-min-microvolt = <2800000>;
++ regulator-max-microvolt = <2800000>;
++ vin-supply = <®_vcc_3v3>;
++ };
++
++ reg_dvdd: dvdd {
++ compatible = "regulator-fixed";
++ regulator-name = "dvdd";
++ regulator-min-microvolt = <1200000>;
++ regulator-max-microvolt = <1200000>;
++ vin-supply = <®_vcc_3v3>;
++ };
++
++ reg_vdd_cpu: vdd-cpu {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-cpu";
++ regulator-min-microvolt = <1100000>;
++ regulator-max-microvolt = <1100000>;
++ vin-supply = <®_vcc>;
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&pio 6 17 GPIO_ACTIVE_LOW>; /* PG17 */
++ };
++};
++
++&cpu0 {
++ cpu-supply = <®_vdd_cpu>;
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&mmc0 {
++ bus-width = <4>;
++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
++ disable-wp;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&mmc1 {
++ bus-width = <4>;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ non-removable;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ rtl8723ds: wifi@1 {
++ reg = <1>;
++ interrupt-parent = <&pio>;
++ interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 */
++ interrupt-names = "host-wake";
++ };
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&pio {
++ vcc-pe-supply = <®_avdd2v8>;
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pb8_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&uart1 {
++ uart-has-rtscts;
++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ bluetooth {
++ compatible = "realtek,rtl8723ds-bt";
++ device-wake-gpios = <&pio 6 18 GPIO_ACTIVE_HIGH>; /* PG18 */
++ enable-gpios = <&pio 6 15 GPIO_ACTIVE_HIGH>; /* PG15 */
++ host-wake-gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */
++ };
++};
++
++&usb_otg {
++ dr_mode = "peripheral";
++ status = "okay";
++};
++
++&usbphy {
++ usb0_vbus-supply = <®_vcc>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1-nezha.dts
+@@ -0,0 +1,171 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++/dts-v1/;
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++
++#include "sun20i-d1.dtsi"
++#include "sun20i-d1-common-regulators.dtsi"
++
++/ {
++ model = "Allwinner D1 Nezha";
++ compatible = "allwinner,d1-nezha", "allwinner,sun20i-d1";
++
++ aliases {
++ ethernet0 = &emac;
++ ethernet1 = &xr829;
++ mmc0 = &mmc0;
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ reg_usbvbus: usbvbus {
++ compatible = "regulator-fixed";
++ regulator-name = "usbvbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ gpio = <&pio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */
++ enable-active-high;
++ vin-supply = <®_vcc>;
++ };
++
++ /*
++ * This regulator is PWM-controlled, but the PWM controller is not
++ * yet supported, so fix the regulator to its default voltage.
++ */
++ reg_vdd_cpu: vdd-cpu {
++ compatible = "regulator-fixed";
++ regulator-name = "vdd-cpu";
++ regulator-min-microvolt = <1100000>;
++ regulator-max-microvolt = <1100000>;
++ vin-supply = <®_vcc>;
++ };
++
++ wifi_pwrseq: wifi-pwrseq {
++ compatible = "mmc-pwrseq-simple";
++ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
++ };
++};
++
++&cpu0 {
++ cpu-supply = <®_vdd_cpu>;
++};
++
++&ehci0 {
++ status = "okay";
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&emac {
++ pinctrl-0 = <&rgmii_pe_pins>;
++ pinctrl-names = "default";
++ phy-handle = <&ext_rgmii_phy>;
++ phy-mode = "rgmii-id";
++ phy-supply = <®_vcc_3v3>;
++ status = "okay";
++};
++
++&i2c2 {
++ pinctrl-0 = <&i2c2_pb0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ pcf8574a: gpio@38 {
++ compatible = "nxp,pcf8574a";
++ reg = <0x38>;
++ interrupt-parent = <&pio>;
++ interrupts = <1 2 IRQ_TYPE_LEVEL_LOW>; /* PB2 */
++ interrupt-controller;
++ gpio-controller;
++ #gpio-cells = <2>;
++ #interrupt-cells = <2>;
++ };
++};
++
++&lradc {
++ status = "okay";
++
++ button-160 {
++ label = "OK";
++ linux,code = <KEY_OK>;
++ channel = <0>;
++ voltage = <160000>;
++ };
++};
++
++&mdio {
++ ext_rgmii_phy: ethernet-phy@1 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <1>;
++ };
++};
++
++&mmc0 {
++ bus-width = <4>;
++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
++ disable-wp;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&mmc1 {
++ bus-width = <4>;
++ mmc-pwrseq = <&wifi_pwrseq>;
++ non-removable;
++ vmmc-supply = <®_vcc_3v3>;
++ vqmmc-supply = <®_vcc_3v3>;
++ pinctrl-0 = <&mmc1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ xr829: wifi@1 {
++ reg = <1>;
++ };
++};
++
++&ohci0 {
++ status = "okay";
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&uart0 {
++ pinctrl-0 = <&uart0_pb8_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&uart1 {
++ uart-has-rtscts;
++ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ /* XR829 bluetooth is connected here */
++};
++
++&usb_otg {
++ dr_mode = "otg";
++ status = "okay";
++};
++
++&usbphy {
++ usb0_id_det-gpios = <&pio 3 21 GPIO_ACTIVE_HIGH>; /* PD21 */
++ usb0_vbus_det-gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */
++ usb0_vbus-supply = <®_usbvbus>;
++ usb1_vbus-supply = <®_vcc>;
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1.dtsi
+@@ -0,0 +1,900 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++#include <dt-bindings/clock/sun6i-rtc.h>
++#include <dt-bindings/clock/sun8i-de2.h>
++#include <dt-bindings/clock/sun8i-tcon-top.h>
++#include <dt-bindings/clock/sun20i-d1-ccu.h>
++#include <dt-bindings/clock/sun20i-d1-r-ccu.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/reset/sun8i-de2.h>
++#include <dt-bindings/reset/sun20i-d1-ccu.h>
++#include <dt-bindings/reset/sun20i-d1-r-ccu.h>
++#include <dt-bindings/thermal/thermal.h>
++
++/ {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ cpus {
++ timebase-frequency = <24000000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ cpu0: cpu@0 {
++ compatible = "thead,c906", "riscv";
++ device_type = "cpu";
++ reg = <0>;
++ clocks = <&ccu CLK_RISCV>;
++ clock-frequency = <24000000>;
++ d-cache-block-size = <64>;
++ d-cache-sets = <256>;
++ d-cache-size = <32768>;
++ i-cache-block-size = <64>;
++ i-cache-sets = <128>;
++ i-cache-size = <32768>;
++ mmu-type = "riscv,sv39";
++ riscv,isa = "rv64imafdc";
++ #cooling-cells = <2>;
++
++ cpu0_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ };
++ };
++ };
++
++ de: display-engine {
++ compatible = "allwinner,sun20i-d1-display-engine";
++ allwinner,pipelines = <&mixer0>, <&mixer1>;
++ status = "disabled";
++ };
++
++ osc24M: osc24M-clk {
++ compatible = "fixed-clock";
++ clock-frequency = <24000000>;
++ clock-output-names = "osc24M";
++ #clock-cells = <0>;
++ };
++
++ soc {
++ compatible = "simple-bus";
++ ranges;
++ interrupt-parent = <&plic>;
++ dma-noncoherent;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ dsp_wdt: watchdog@1700400 {
++ compatible = "allwinner,sun20i-d1-wdt";
++ reg = <0x1700400 0x20>;
++ interrupts = <138 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&osc24M>, <&rtc CLK_OSC32K>;
++ clock-names = "hosc", "losc";
++ status = "reserved";
++ };
++
++ pio: pinctrl@2000000 {
++ compatible = "allwinner,sun20i-d1-pinctrl";
++ reg = <0x2000000 0x800>;
++ interrupts = <85 IRQ_TYPE_LEVEL_HIGH>,
++ <87 IRQ_TYPE_LEVEL_HIGH>,
++ <89 IRQ_TYPE_LEVEL_HIGH>,
++ <91 IRQ_TYPE_LEVEL_HIGH>,
++ <93 IRQ_TYPE_LEVEL_HIGH>,
++ <95 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_APB0>,
++ <&osc24M>,
++ <&rtc CLK_OSC32K>;
++ clock-names = "apb", "hosc", "losc";
++ gpio-controller;
++ interrupt-controller;
++ #gpio-cells = <3>;
++ #interrupt-cells = <3>;
++
++ /omit-if-no-ref/
++ i2c0_pb10_pins: i2c0-pb10-pins {
++ pins = "PB10", "PB11";
++ function = "i2c0";
++ };
++
++ /omit-if-no-ref/
++ i2c2_pb0_pins: i2c2-pb0-pins {
++ pins = "PB0", "PB1";
++ function = "i2c2";
++ };
++
++ /omit-if-no-ref/
++ lcd_rgb666_pins: lcd-rgb666-pins {
++ pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5",
++ "PD6", "PD7", "PD8", "PD9", "PD10", "PD11",
++ "PD12", "PD13", "PD14", "PD15", "PD16", "PD17",
++ "PD18", "PD19", "PD20", "PD21";
++ function = "lcd0";
++ };
++
++ /omit-if-no-ref/
++ mmc0_pins: mmc0-pins {
++ pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
++ function = "mmc0";
++ };
++
++ /omit-if-no-ref/
++ mmc1_pins: mmc1-pins {
++ pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5";
++ function = "mmc1";
++ };
++
++ /omit-if-no-ref/
++ mmc2_pins: mmc2-pins {
++ pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7";
++ function = "mmc2";
++ };
++
++ /omit-if-no-ref/
++ rgmii_pe_pins: rgmii-pe-pins {
++ pins = "PE0", "PE1", "PE2", "PE3", "PE4",
++ "PE5", "PE6", "PE7", "PE8", "PE9",
++ "PE11", "PE12", "PE13", "PE14", "PE15";
++ function = "emac";
++ };
++
++ /omit-if-no-ref/
++ rmii_pe_pins: rmii-pe-pins {
++ pins = "PE0", "PE1", "PE2", "PE3", "PE4",
++ "PE5", "PE6", "PE7", "PE8", "PE9";
++ function = "emac";
++ };
++
++ /omit-if-no-ref/
++ uart0_pb8_pins: uart0-pb8-pins {
++ pins = "PB8", "PB9";
++ function = "uart0";
++ };
++
++ /omit-if-no-ref/
++ uart1_pg6_pins: uart1-pg6-pins {
++ pins = "PG6", "PG7";
++ function = "uart1";
++ };
++
++ /omit-if-no-ref/
++ uart1_pg8_rts_cts_pins: uart1-pg8-rts-cts-pins {
++ pins = "PG8", "PG9";
++ function = "uart1";
++ };
++ };
++
++ ccu: clock-controller@2001000 {
++ compatible = "allwinner,sun20i-d1-ccu";
++ reg = <0x2001000 0x1000>;
++ clocks = <&osc24M>,
++ <&rtc CLK_OSC32K>,
++ <&rtc CLK_IOSC>;
++ clock-names = "hosc", "losc", "iosc";
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++
++ lradc: keys@2009800 {
++ compatible = "allwinner,sun20i-d1-lradc",
++ "allwinner,sun50i-r329-lradc";
++ reg = <0x2009800 0x400>;
++ interrupts = <77 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_LRADC>;
++ resets = <&ccu RST_BUS_LRADC>;
++ status = "disabled";
++ };
++
++ codec: audio-codec@2030000 {
++ compatible = "simple-mfd", "syscon";
++ reg = <0x2030000 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ regulators@2030348 {
++ compatible = "allwinner,sun20i-d1-analog-ldos";
++ reg = <0x2030348 0x4>;
++ nvmem-cells = <&bg_trim>;
++ nvmem-cell-names = "bg_trim";
++
++ reg_aldo: aldo {
++ };
++
++ reg_hpldo: hpldo {
++ };
++ };
++ };
++
++ i2s0: i2s@2032000 {
++ compatible = "allwinner,sun20i-d1-i2s",
++ "allwinner,sun50i-r329-i2s";
++ reg = <0x2032000 0x1000>;
++ interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2S0>,
++ <&ccu CLK_I2S0>;
++ clock-names = "apb", "mod";
++ resets = <&ccu RST_BUS_I2S0>;
++ dmas = <&dma 3>, <&dma 3>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #sound-dai-cells = <0>;
++ };
++
++ i2s1: i2s@2033000 {
++ compatible = "allwinner,sun20i-d1-i2s",
++ "allwinner,sun50i-r329-i2s";
++ reg = <0x2033000 0x1000>;
++ interrupts = <43 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2S1>,
++ <&ccu CLK_I2S1>;
++ clock-names = "apb", "mod";
++ resets = <&ccu RST_BUS_I2S1>;
++ dmas = <&dma 4>, <&dma 4>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #sound-dai-cells = <0>;
++ };
++
++ i2s2: i2s@2034000 {
++ compatible = "allwinner,sun20i-d1-i2s",
++ "allwinner,sun50i-r329-i2s";
++ reg = <0x2034000 0x1000>;
++ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2S2>,
++ <&ccu CLK_I2S2>;
++ clock-names = "apb", "mod";
++ resets = <&ccu RST_BUS_I2S2>;
++ dmas = <&dma 5>, <&dma 5>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #sound-dai-cells = <0>;
++ };
++
++ timer: timer@2050000 {
++ compatible = "allwinner,sun20i-d1-timer",
++ "allwinner,sun8i-a23-timer";
++ reg = <0x2050000 0xa0>;
++ interrupts = <75 IRQ_TYPE_LEVEL_HIGH>,
++ <76 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&osc24M>;
++ };
++
++ wdt: watchdog@20500a0 {
++ compatible = "allwinner,sun20i-d1-wdt-reset",
++ "allwinner,sun20i-d1-wdt";
++ reg = <0x20500a0 0x20>;
++ interrupts = <79 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&osc24M>, <&rtc CLK_OSC32K>;
++ clock-names = "hosc", "losc";
++ status = "reserved";
++ };
++
++ uart0: serial@2500000 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2500000 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART0>;
++ resets = <&ccu RST_BUS_UART0>;
++ dmas = <&dma 14>, <&dma 14>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ uart1: serial@2500400 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2500400 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART1>;
++ resets = <&ccu RST_BUS_UART1>;
++ dmas = <&dma 15>, <&dma 15>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ uart2: serial@2500800 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2500800 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART2>;
++ resets = <&ccu RST_BUS_UART2>;
++ dmas = <&dma 16>, <&dma 16>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ uart3: serial@2500c00 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2500c00 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART3>;
++ resets = <&ccu RST_BUS_UART3>;
++ dmas = <&dma 17>, <&dma 17>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ uart4: serial@2501000 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2501000 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART4>;
++ resets = <&ccu RST_BUS_UART4>;
++ dmas = <&dma 18>, <&dma 18>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ uart5: serial@2501400 {
++ compatible = "snps,dw-apb-uart";
++ reg = <0x2501400 0x400>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_UART5>;
++ resets = <&ccu RST_BUS_UART5>;
++ dmas = <&dma 19>, <&dma 19>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ };
++
++ i2c0: i2c@2502000 {
++ compatible = "allwinner,sun20i-d1-i2c",
++ "allwinner,sun8i-v536-i2c",
++ "allwinner,sun6i-a31-i2c";
++ reg = <0x2502000 0x400>;
++ interrupts = <25 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2C0>;
++ resets = <&ccu RST_BUS_I2C0>;
++ dmas = <&dma 43>, <&dma 43>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ i2c1: i2c@2502400 {
++ compatible = "allwinner,sun20i-d1-i2c",
++ "allwinner,sun8i-v536-i2c",
++ "allwinner,sun6i-a31-i2c";
++ reg = <0x2502400 0x400>;
++ interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2C1>;
++ resets = <&ccu RST_BUS_I2C1>;
++ dmas = <&dma 44>, <&dma 44>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ i2c2: i2c@2502800 {
++ compatible = "allwinner,sun20i-d1-i2c",
++ "allwinner,sun8i-v536-i2c",
++ "allwinner,sun6i-a31-i2c";
++ reg = <0x2502800 0x400>;
++ interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2C2>;
++ resets = <&ccu RST_BUS_I2C2>;
++ dmas = <&dma 45>, <&dma 45>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ i2c3: i2c@2502c00 {
++ compatible = "allwinner,sun20i-d1-i2c",
++ "allwinner,sun8i-v536-i2c",
++ "allwinner,sun6i-a31-i2c";
++ reg = <0x2502c00 0x400>;
++ interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_I2C3>;
++ resets = <&ccu RST_BUS_I2C3>;
++ dmas = <&dma 46>, <&dma 46>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ syscon: syscon@3000000 {
++ compatible = "allwinner,sun20i-d1-system-control";
++ reg = <0x3000000 0x1000>;
++ ranges;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ regulators@3000150 {
++ compatible = "allwinner,sun20i-d1-system-ldos";
++ reg = <0x3000150 0x4>;
++
++ reg_ldoa: ldoa {
++ };
++
++ reg_ldob: ldob {
++ };
++ };
++ };
++
++ dma: dma-controller@3002000 {
++ compatible = "allwinner,sun20i-d1-dma";
++ reg = <0x3002000 0x1000>;
++ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
++ clock-names = "bus", "mbus";
++ resets = <&ccu RST_BUS_DMA>;
++ dma-channels = <16>;
++ dma-requests = <48>;
++ #dma-cells = <1>;
++ };
++
++ sid: efuse@3006000 {
++ compatible = "allwinner,sun20i-d1-sid";
++ reg = <0x3006000 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ ths_calib: ths-calib@14 {
++ reg = <0x14 0x4>;
++ };
++
++ bg_trim: bg-trim@28 {
++ reg = <0x28 0x4>;
++ bits = <16 8>;
++ };
++ };
++
++ mbus: dram-controller@3102000 {
++ compatible = "allwinner,sun20i-d1-mbus";
++ reg = <0x3102000 0x1000>,
++ <0x3103000 0x1000>;
++ reg-names = "mbus", "dram";
++ interrupts = <59 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_MBUS>,
++ <&ccu CLK_DRAM>,
++ <&ccu CLK_BUS_DRAM>;
++ clock-names = "mbus", "dram", "bus";
++ dma-ranges = <0 0x40000000 0x80000000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ #interconnect-cells = <1>;
++ };
++
++ mmc0: mmc@4020000 {
++ compatible = "allwinner,sun20i-d1-mmc";
++ reg = <0x4020000 0x1000>;
++ interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>;
++ clock-names = "ahb", "mmc";
++ resets = <&ccu RST_BUS_MMC0>;
++ reset-names = "ahb";
++ cap-sd-highspeed;
++ max-frequency = <150000000>;
++ no-mmc;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@4021000 {
++ compatible = "allwinner,sun20i-d1-mmc";
++ reg = <0x4021000 0x1000>;
++ interrupts = <57 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>;
++ clock-names = "ahb", "mmc";
++ resets = <&ccu RST_BUS_MMC1>;
++ reset-names = "ahb";
++ cap-sd-highspeed;
++ max-frequency = <150000000>;
++ no-mmc;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc2: mmc@4022000 {
++ compatible = "allwinner,sun20i-d1-emmc",
++ "allwinner,sun50i-a100-emmc";
++ reg = <0x4022000 0x1000>;
++ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>;
++ clock-names = "ahb", "mmc";
++ resets = <&ccu RST_BUS_MMC2>;
++ reset-names = "ahb";
++ cap-mmc-highspeed;
++ max-frequency = <150000000>;
++ mmc-ddr-1_8v;
++ mmc-ddr-3_3v;
++ no-sd;
++ no-sdio;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ usb_otg: usb@4100000 {
++ compatible = "allwinner,sun20i-d1-musb",
++ "allwinner,sun8i-a33-musb";
++ reg = <0x4100000 0x400>;
++ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "mc";
++ clocks = <&ccu CLK_BUS_OTG>;
++ resets = <&ccu RST_BUS_OTG>;
++ extcon = <&usbphy 0>;
++ phys = <&usbphy 0>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ usbphy: phy@4100400 {
++ compatible = "allwinner,sun20i-d1-usb-phy";
++ reg = <0x4100400 0x100>,
++ <0x4101800 0x100>,
++ <0x4200800 0x100>;
++ reg-names = "phy_ctrl",
++ "pmu0",
++ "pmu1";
++ clocks = <&osc24M>,
++ <&osc24M>;
++ clock-names = "usb0_phy",
++ "usb1_phy";
++ resets = <&ccu RST_USB_PHY0>,
++ <&ccu RST_USB_PHY1>;
++ reset-names = "usb0_reset",
++ "usb1_reset";
++ status = "disabled";
++ #phy-cells = <1>;
++ };
++
++ ehci0: usb@4101000 {
++ compatible = "allwinner,sun20i-d1-ehci",
++ "generic-ehci";
++ reg = <0x4101000 0x100>;
++ interrupts = <46 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@4101400 {
++ compatible = "allwinner,sun20i-d1-ohci",
++ "generic-ohci";
++ reg = <0x4101400 0x100>;
++ interrupts = <47 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@4200000 {
++ compatible = "allwinner,sun20i-d1-ehci",
++ "generic-ehci";
++ reg = <0x4200000 0x100>;
++ interrupts = <49 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@4200400 {
++ compatible = "allwinner,sun20i-d1-ohci",
++ "generic-ohci";
++ reg = <0x4200400 0x100>;
++ interrupts = <50 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";
++ };
++
++ emac: ethernet@4500000 {
++ compatible = "allwinner,sun20i-d1-emac",
++ "allwinner,sun50i-a64-emac";
++ reg = <0x4500000 0x10000>;
++ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-names = "macirq";
++ clocks = <&ccu CLK_BUS_EMAC>;
++ clock-names = "stmmaceth";
++ resets = <&ccu RST_BUS_EMAC>;
++ reset-names = "stmmaceth";
++ syscon = <&syscon>;
++ status = "disabled";
++
++ mdio: mdio {
++ compatible = "snps,dwmac-mdio";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++ };
++
++ display_clocks: clock-controller@5000000 {
++ compatible = "allwinner,sun20i-d1-de2-clk",
++ "allwinner,sun50i-h5-de2-clk";
++ reg = <0x5000000 0x10000>;
++ clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_DE>;
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++
++ mixer0: mixer@5100000 {
++ compatible = "allwinner,sun20i-d1-de2-mixer-0";
++ reg = <0x5100000 0x100000>;
++ clocks = <&display_clocks CLK_BUS_MIXER0>,
++ <&display_clocks CLK_MIXER0>;
++ clock-names = "bus", "mod";
++ resets = <&display_clocks RST_MIXER0>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ mixer0_out: port@1 {
++ reg = <1>;
++
++ mixer0_out_tcon_top_mixer0: endpoint {
++ remote-endpoint = <&tcon_top_mixer0_in_mixer0>;
++ };
++ };
++ };
++ };
++
++ mixer1: mixer@5200000 {
++ compatible = "allwinner,sun20i-d1-de2-mixer-1";
++ reg = <0x5200000 0x100000>;
++ clocks = <&display_clocks CLK_BUS_MIXER1>,
++ <&display_clocks CLK_MIXER1>;
++ clock-names = "bus", "mod";
++ resets = <&display_clocks RST_MIXER1>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ mixer1_out: port@1 {
++ reg = <1>;
++
++ mixer1_out_tcon_top_mixer1: endpoint {
++ remote-endpoint = <&tcon_top_mixer1_in_mixer1>;
++ };
++ };
++ };
++ };
++
++ tcon_top: tcon-top@5460000 {
++ compatible = "allwinner,sun20i-d1-tcon-top";
++ reg = <0x5460000 0x1000>;
++ clocks = <&ccu CLK_BUS_DPSS_TOP>,
++ <&ccu CLK_TCON_TV>,
++ <&ccu CLK_TVE>,
++ <&ccu CLK_TCON_LCD0>;
++ clock-names = "bus", "tcon-tv0", "tve0", "dsi";
++ clock-output-names = "tcon-top-tv0", "tcon-top-dsi";
++ resets = <&ccu RST_BUS_DPSS_TOP>;
++ #clock-cells = <1>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_top_mixer0_in: port@0 {
++ reg = <0>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_top_mixer0_in_mixer0: endpoint@0 {
++ reg = <0>;
++ remote-endpoint = <&mixer0_out_tcon_top_mixer0>;
++ };
++ };
++
++ tcon_top_mixer0_out: port@1 {
++ reg = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_top_mixer0_out_tcon_lcd0: endpoint@0 {
++ reg = <0>;
++ remote-endpoint = <&tcon_lcd0_in_tcon_top_mixer0>;
++ };
++
++ tcon_top_mixer0_out_tcon_tv0: endpoint@2 {
++ reg = <2>;
++ remote-endpoint = <&tcon_tv0_in_tcon_top_mixer0>;
++ };
++ };
++
++ tcon_top_mixer1_in: port@2 {
++ reg = <2>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_top_mixer1_in_mixer1: endpoint@1 {
++ reg = <1>;
++ remote-endpoint = <&mixer1_out_tcon_top_mixer1>;
++ };
++ };
++
++ tcon_top_mixer1_out: port@3 {
++ reg = <3>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_top_mixer1_out_tcon_lcd0: endpoint@0 {
++ reg = <0>;
++ remote-endpoint = <&tcon_lcd0_in_tcon_top_mixer1>;
++ };
++
++ tcon_top_mixer1_out_tcon_tv0: endpoint@2 {
++ reg = <2>;
++ remote-endpoint = <&tcon_tv0_in_tcon_top_mixer1>;
++ };
++ };
++
++ tcon_top_hdmi_in: port@4 {
++ reg = <4>;
++
++ tcon_top_hdmi_in_tcon_tv0: endpoint {
++ remote-endpoint = <&tcon_tv0_out_tcon_top_hdmi>;
++ };
++ };
++
++ tcon_top_hdmi_out: port@5 {
++ reg = <5>;
++ };
++ };
++ };
++
++ tcon_lcd0: lcd-controller@5461000 {
++ compatible = "allwinner,sun20i-d1-tcon-lcd";
++ reg = <0x5461000 0x1000>;
++ interrupts = <106 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_TCON_LCD0>,
++ <&ccu CLK_TCON_LCD0>;
++ clock-names = "ahb", "tcon-ch0";
++ clock-output-names = "tcon-pixel-clock";
++ resets = <&ccu RST_BUS_TCON_LCD0>,
++ <&ccu RST_BUS_LVDS0>;
++ reset-names = "lcd", "lvds";
++ #clock-cells = <0>;
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_lcd0_in: port@0 {
++ reg = <0>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_lcd0_in_tcon_top_mixer0: endpoint@0 {
++ reg = <0>;
++ remote-endpoint = <&tcon_top_mixer0_out_tcon_lcd0>;
++ };
++
++ tcon_lcd0_in_tcon_top_mixer1: endpoint@1 {
++ reg = <1>;
++ remote-endpoint = <&tcon_top_mixer1_out_tcon_lcd0>;
++ };
++ };
++
++ tcon_lcd0_out: port@1 {
++ reg = <1>;
++ };
++ };
++ };
++
++ tcon_tv0: lcd-controller@5470000 {
++ compatible = "allwinner,sun20i-d1-tcon-tv";
++ reg = <0x5470000 0x1000>;
++ interrupts = <107 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_TCON_TV>,
++ <&tcon_top CLK_TCON_TOP_TV0>;
++ clock-names = "ahb", "tcon-ch1";
++ resets = <&ccu RST_BUS_TCON_TV>;
++ reset-names = "lcd";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_tv0_in: port@0 {
++ reg = <0>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_tv0_in_tcon_top_mixer0: endpoint@0 {
++ reg = <0>;
++ remote-endpoint = <&tcon_top_mixer0_out_tcon_tv0>;
++ };
++
++ tcon_tv0_in_tcon_top_mixer1: endpoint@1 {
++ reg = <1>;
++ remote-endpoint = <&tcon_top_mixer1_out_tcon_tv0>;
++ };
++ };
++
++ tcon_tv0_out: port@1 {
++ reg = <1>;
++
++ tcon_tv0_out_tcon_top_hdmi: endpoint {
++ remote-endpoint = <&tcon_top_hdmi_in_tcon_tv0>;
++ };
++ };
++ };
++ };
++
++ riscv_wdt: watchdog@6011000 {
++ compatible = "allwinner,sun20i-d1-wdt";
++ reg = <0x6011000 0x20>;
++ interrupts = <147 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&osc24M>, <&rtc CLK_OSC32K>;
++ clock-names = "hosc", "losc";
++ };
++
++ r_ccu: clock-controller@7010000 {
++ compatible = "allwinner,sun20i-d1-r-ccu";
++ reg = <0x7010000 0x400>;
++ clocks = <&osc24M>,
++ <&rtc CLK_OSC32K>,
++ <&rtc CLK_IOSC>,
++ <&ccu CLK_PLL_PERIPH0_DIV3>;
++ clock-names = "hosc", "losc", "iosc", "pll-periph";
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++
++ rtc: rtc@7090000 {
++ compatible = "allwinner,sun20i-d1-rtc",
++ "allwinner,sun50i-r329-rtc";
++ reg = <0x7090000 0x400>;
++ interrupts = <160 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&r_ccu CLK_BUS_R_RTC>,
++ <&osc24M>,
++ <&r_ccu CLK_R_AHB>;
++ clock-names = "bus", "hosc", "ahb";
++ #clock-cells = <1>;
++ };
++
++ plic: interrupt-controller@10000000 {
++ compatible = "allwinner,sun20i-d1-plic",
++ "thead,c900-plic";
++ reg = <0x10000000 0x4000000>;
++ interrupts-extended = <&cpu0_intc 11>,
++ <&cpu0_intc 9>;
++ interrupt-controller;
++ riscv,ndev = <176>;
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ };
++ };
++};
+--- /dev/null
++++ b/arch/riscv/dts/sunxi-u-boot.dtsi
+@@ -0,0 +1,68 @@
++// SPDX-License-Identifier: (GPL-2.0 OR MIT)
++
++#include "binman.dtsi"
++
++/ {
++ cpus {
++ u-boot,dm-spl;
++ };
++
++ soc {
++ u-boot,dm-spl;
++ };
++};
++
++&binman {
++ u-boot-sunxi-with-spl {
++ filename = "u-boot-sunxi-with-spl.bin";
++ pad-byte = <0xff>;
++
++ blob@0 {
++ filename = "spl/sunxi-spl.bin";
++ };
++
++ blob@1 {
++ filename = "u-boot.itb";
++ };
++ };
++};
++
++&ccu {
++ u-boot,dm-spl;
++};
++
++&cpu0 {
++ u-boot,dm-spl;
++};
++
++&mbus {
++ u-boot,dm-spl;
++};
++
++&mmc0 {
++ u-boot,dm-spl;
++};
++
++&mmc0_pins {
++ u-boot,dm-spl;
++};
++
++&osc24M {
++ u-boot,dm-spl;
++};
++
++&pio {
++ u-boot,dm-spl;
++};
++
++&rtc {
++ u-boot,dm-spl;
++};
++
++&uart0 {
++ u-boot,dm-spl;
++};
++
++&uart0_pb8_pins {
++ u-boot,dm-spl;
++};
+--- /dev/null
++++ b/include/dt-bindings/clock/sun20i-d1-r-ccu.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
++/*
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
++#define _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
++
++#define CLK_R_AHB 0
++
++#define CLK_BUS_R_TIMER 2
++#define CLK_BUS_R_TWD 3
++#define CLK_BUS_R_PPU 4
++#define CLK_R_IR_RX 5
++#define CLK_BUS_R_IR_RX 6
++#define CLK_BUS_R_RTC 7
++#define CLK_BUS_R_CPUCFG 8
++
++#endif /* _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_ */
+--- /dev/null
++++ b/include/dt-bindings/reset/sun20i-d1-r-ccu.h
+@@ -0,0 +1,16 @@
++/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
++/*
++ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
++ */
++
++#ifndef _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
++#define _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
++
++#define RST_BUS_R_TIMER 0
++#define RST_BUS_R_TWD 1
++#define RST_BUS_R_PPU 2
++#define RST_BUS_R_IR_RX 3
++#define RST_BUS_R_RTC 4
++#define RST_BUS_R_CPUCFG 5
++
++#endif /* _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_ */
--- /dev/null
+From 6b0c83a5c7b9189fb1c5cf56145ec4882d9e5588 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 18:13:34 +0000
+Subject: [PATCH 79/90] riscv: Add CONFIG_TARGET_SUN20I_D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/riscv/Kconfig | 5 +++++
+ board/sunxi/Kconfig | 30 +++++++++++++++++++++++++++---
+ common/spl/Kconfig | 1 +
+ drivers/clk/sunxi/Kconfig | 1 +
+ include/configs/sun20i.h | 11 +++++++++++
+ 5 files changed, 45 insertions(+), 3 deletions(-)
+ create mode 100644 include/configs/sun20i.h
+
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -31,6 +31,11 @@ config TARGET_SIPEED_MAIX
+ bool "Support Sipeed Maix Board"
+ select SYS_CACHE_SHIFT_6
+
++config TARGET_SUN20I_D1
++ bool "Support Allwinner D1 Boards"
++ select BOARD_SUNXI
++ select SYS_CACHE_SHIFT_6
++
+ endchoice
+
+ config SYS_ICACHE_OFF
+--- a/board/sunxi/Kconfig
++++ b/board/sunxi/Kconfig
+@@ -13,8 +13,18 @@ config BOARD_SUNXI
+ select DM_SERIAL if SERIAL
+ select DM_SPI if SPI
+ select DM_SPI_FLASH if SPI
++ select GENERIC_RISCV if RISCV
+ select OF_BOARD_SETUP
+ select PINCTRL
++ select RAM if SPL_DM
++ select SPL_CLK if SPL_DM
++ select SPL_DM if RISCV && SPL
++ select SPL_DM_SPI if SPL_DM && SPL_SPI
++ select SPL_DM_SPI_FLASH if SPL_DM && SPL_SPI
++ select SPL_OF_CONTROL if SPL_DM
++ select SPL_PINCTRL if SPL_DM
++ select SPL_PINCONF if SPL_DM
++ select SPL_RAM if SPL_DM
+ select SPL_SEPARATE_BSS if SPL
+ select SUPPORT_SPL
+ select SYS_RELOC_GD_ENV_ADDR
+@@ -28,12 +38,14 @@ config BOARD_SUNXI
+ imply DISTRO_DEFAULTS
+ imply FAT_WRITE
+ imply FIT
++ imply MMC
+ imply OF_LIBFDT_OVERLAY
+ imply PRE_CONSOLE_BUFFER
+ imply SPL
+ imply SPL_GPIO
+ imply SPL_LIBCOMMON_SUPPORT
+ imply SPL_LIBGENERIC_SUPPORT
++ imply SPL_LOAD_FIT
+ imply SPL_MMC if MMC
+ imply SPL_POWER
+ imply SPL_SERIAL
+@@ -41,6 +53,7 @@ config BOARD_SUNXI
+ imply SYS_I2C_MVTWSI
+ imply SYS_NS16550
+ imply SYSRESET
++ imply SYSRESET_SBI
+ imply SYSRESET_WATCHDOG
+ imply SYSRESET_WATCHDOG_AUTO
+ imply USB_EHCI_GENERIC
+@@ -67,6 +80,12 @@ config SPL_BSS_START_ADDR
+ default 0x4ff80000 if SUNXI_MINIMUM_DRAM_MB >= 256
+ default 0x43f80000 if SUNXI_MINIMUM_DRAM_MB >= 64
+
++config SPL_OPENSBI_LOAD_ADDR
++ default 0x40000000 if RISCV
++
++config SPL_STACK
++ default 0x48000 if TARGET_SUN20I_D1
++
+ config SPL_STACK_R_ADDR
+ default 0x81e00000 if MACH_SUNIV
+ default 0x2fe00000 if MACH_SUN9I
+@@ -75,13 +94,13 @@ config SPL_STACK_R_ADDR
+
+ config SPL_TEXT_BASE
+ default 0x10060 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
+- default 0x20060 if SUN50I_GEN_H6
++ default 0x20060 if SUN50I_GEN_H6 || TARGET_SUN20I_D1
+ default 0x00060
+
+ config SUNXI_MINIMUM_DRAM_MB
+ int
+ default 32 if MACH_SUNIV
+- default 64 if MACH_SUN8I_V3S
++ default 64 if MACH_SUN8I_V3S || TARGET_SUN20I_D1
+ default 256
+ help
+ Minimum DRAM size expected on the board. Traditionally we
+@@ -94,7 +113,7 @@ config SUNXI_MINIMUM_DRAM_MB
+ config SUNXI_SRAM_ADDRESS
+ hex
+ default 0x10000 if MACH_SUN9I || MACH_SUN50I || MACH_SUN50I_H5
+- default 0x20000 if SUN50I_GEN_H6
++ default 0x20000 if SUN50I_GEN_H6 || TARGET_SUN20I_D1
+ default 0x0
+ help
+ Older Allwinner SoCs have their boot mask ROM mapped just
+@@ -113,6 +132,7 @@ config SYS_CLK_FREQ
+ default 912000000 if MACH_SUN7I
+ default 1008000000 if MACH_SUN8I
+ default 1008000000 if MACH_SUN9I
++ default 1008000000 if TARGET_SUN20I_D1
+ default 816000000 if MACH_SUN50I || MACH_SUN50I_H5
+ default 888000000 if MACH_SUN50I_H6
+ default 1008000000 if MACH_SUN50I_H616
+@@ -125,10 +145,14 @@ config SYS_CONFIG_NAME
+ default "sun7i" if MACH_SUN7I
+ default "sun8i" if MACH_SUN8I
+ default "sun9i" if MACH_SUN9I
++ default "sun20i" if TARGET_SUN20I_D1
+ default "sun50i" if MACH_SUN50I
+ default "sun50i" if MACH_SUN50I_H6
+ default "sun50i" if MACH_SUN50I_H616
+
++config SYS_CPU
++ default "generic" if TARGET_SUN20I_D1
++
+ config SYS_LOAD_ADDR
+ default 0x81000000 if MACH_SUNIV
+ default 0x22000000 if MACH_SUN9I
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -78,6 +78,7 @@ config SPL_MAX_SIZE
+ hex "Maximum size of the SPL image, excluding BSS"
+ default 0x37fa0 if MACH_SUN50I_H616
+ default 0x30000 if ARCH_MX6 && MX6_OCRAM_256KB
++ default 0x27fa0 if TARGET_SUN20I_D1
+ default 0x25fa0 if MACH_SUN50I_H6
+ default 0x1b000 if AM33XX && !TI_SECURE_DEVICE
+ default 0x10000 if ARCH_MX6 && !MX6_OCRAM_256KB
+--- a/drivers/clk/sunxi/Kconfig
++++ b/drivers/clk/sunxi/Kconfig
+@@ -98,6 +98,7 @@ config CLK_SUN8I_H3
+
+ config CLK_SUN20I_D1
+ bool "Clock driver for Allwinner D1"
++ default TARGET_SUN20I_D1
+ help
+ This enables common clock driver support for platforms based
+ on Allwinner D1 SoC.
+--- /dev/null
++++ b/include/configs/sun20i.h
+@@ -0,0 +1,11 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Placeholder wrapper to allow addressing Allwinner D1 (and later) sun20i
++ * CPU based devices separately. Please do not add anything in here.
++ */
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#include <configs/sunxi-common.h>
++
++#endif /* __CONFIG_H */
--- /dev/null
+From 28682ca027b9fa64f3de4cea99373642f36c4e6c Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 8 Aug 2021 19:32:14 -0500
+Subject: [PATCH 80/90] gpio: sunxi: Hack up the driver for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h | 12 ++++++++++--
+ arch/arm/mach-sunxi/pinmux.c | 8 +++++++-
+ drivers/gpio/sunxi_gpio.c | 3 +++
+ 3 files changed, 20 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -9,7 +9,9 @@
+ #define _SUNXI_GPIO_H
+
+ #include <linux/types.h>
++#if 0
+ #include <asm/arch/cpu.h>
++#endif
+
+ /*
+ * sunxi has 9 banks of gpio, they are:
+@@ -55,30 +57,36 @@
+ struct sunxi_gpio {
+ u32 cfg[4];
+ u32 dat;
+- u32 drv[2];
++ u32 drv[4];
+ u32 pull[2];
++ u32 reserved;
+ };
+
+ /* gpio interrupt control */
+ struct sunxi_gpio_int {
+- u32 cfg[3];
++ u32 cfg[4];
+ u32 ctl;
+ u32 sta;
+ u32 deb; /* interrupt debounce */
++ u32 reserved;
+ };
+
++#if 0
+ struct sunxi_gpio_reg {
+ struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
+ u8 res[0xbc];
+ struct sunxi_gpio_int gpio_int;
+ };
++#endif
+
+ #define SUN50I_H6_GPIO_POW_MOD_SEL 0x340
+ #define SUN50I_H6_GPIO_POW_MOD_VAL 0x348
+
++#if 0
+ #define BANK_TO_GPIO(bank) (((bank) < SUNXI_GPIO_L) ? \
+ &((struct sunxi_gpio_reg *)SUNXI_PIO_BASE)->gpio_bank[bank] : \
+ &((struct sunxi_gpio_reg *)SUNXI_R_PIO_BASE)->gpio_bank[(bank) - SUNXI_GPIO_L])
++#endif
+
+ #define GPIO_BANK(pin) ((pin) >> 5)
+ #define GPIO_NUM(pin) ((pin) & 0x1f)
+--- a/arch/arm/mach-sunxi/pinmux.c
++++ b/arch/arm/mach-sunxi/pinmux.c
+@@ -7,7 +7,7 @@
+
+ #include <common.h>
+ #include <asm/io.h>
+-#include <asm/arch/gpio.h>
++//#include <asm/arch/gpio.h>
+
+ void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val)
+ {
+@@ -17,6 +17,7 @@ void sunxi_gpio_set_cfgbank(struct sunxi
+ clrsetbits_le32(&pio->cfg[index], 0xf << offset, val << offset);
+ }
+
++#if !CONFIG_IS_ENABLED(DM_GPIO)
+ void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
+ {
+ u32 bank = GPIO_BANK(pin);
+@@ -24,6 +25,7 @@ void sunxi_gpio_set_cfgpin(u32 pin, u32
+
+ sunxi_gpio_set_cfgbank(pio, pin, val);
+ }
++#endif
+
+ int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
+ {
+@@ -37,6 +39,7 @@ int sunxi_gpio_get_cfgbank(struct sunxi_
+ return cfg & 0xf;
+ }
+
++#if !CONFIG_IS_ENABLED(DM_GPIO)
+ int sunxi_gpio_get_cfgpin(u32 pin)
+ {
+ u32 bank = GPIO_BANK(pin);
+@@ -52,6 +55,7 @@ void sunxi_gpio_set_drv(u32 pin, u32 val
+
+ sunxi_gpio_set_drv_bank(pio, pin, val);
+ }
++#endif
+
+ void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val)
+ {
+@@ -61,6 +65,7 @@ void sunxi_gpio_set_drv_bank(struct sunx
+ clrsetbits_le32(&pio->drv[index], 0x3 << offset, val << offset);
+ }
+
++#if !CONFIG_IS_ENABLED(DM_GPIO)
+ void sunxi_gpio_set_pull(u32 pin, u32 val)
+ {
+ u32 bank = GPIO_BANK(pin);
+@@ -68,6 +73,7 @@ void sunxi_gpio_set_pull(u32 pin, u32 va
+
+ sunxi_gpio_set_pull_bank(pio, pin, val);
+ }
++#endif
+
+ void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
+ {
+--- a/drivers/gpio/sunxi_gpio.c
++++ b/drivers/gpio/sunxi_gpio.c
+@@ -18,6 +18,9 @@
+ #include <asm/gpio.h>
+ #include <dt-bindings/gpio/gpio.h>
+
++#include "../../arch/arm/include/asm/arch-sunxi/gpio.h"
++#include "../../arch/arm/mach-sunxi/pinmux.c"
++
+ #if !CONFIG_IS_ENABLED(DM_GPIO)
+ static int sunxi_gpio_output(u32 pin, u32 val)
+ {
--- /dev/null
+From 4df80766531bc35510981ebc5ea0bb07264beac9 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 8 Aug 2021 19:31:20 -0500
+Subject: [PATCH 81/90] mmc: sunxi: Hack up the driver for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/include/asm/io.h | 1 +
+ drivers/mmc/sunxi_mmc.c | 29 +++++++++++++++++++++++++----
+ drivers/mmc/sunxi_mmc.h | 2 --
+ 3 files changed, 26 insertions(+), 6 deletions(-)
+
+--- a/arch/riscv/include/asm/io.h
++++ b/arch/riscv/include/asm/io.h
+@@ -85,6 +85,7 @@ static inline u16 readw(const volatile v
+ return val;
+ }
+
++#define readl_relaxed readl
+ static inline u32 readl(const volatile void __iomem *addr)
+ {
+ u32 val;
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -23,9 +23,9 @@
+ #include <reset.h>
+ #include <asm/gpio.h>
+ #include <asm/io.h>
++#if !CONFIG_IS_ENABLED(DM_MMC)
+ #include <asm/arch/clock.h>
+ #include <asm/arch/cpu.h>
+-#if !CONFIG_IS_ENABLED(DM_MMC)
+ #include <asm/arch/mmc.h>
+ #endif
+ #include <linux/delay.h>
+@@ -36,6 +36,23 @@
+ #define CCM_MMC_CTRL_MODE_SEL_NEW 0
+ #endif
+
++#include "../../arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h"
++
++unsigned int clock_get_pll6(void)
++{
++ uint32_t rval = readl((void *)0x2001020);
++
++ int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
++ int m = ((rval >> 1) & 0x1) + 1;
++ int p0 = ((rval >> 16) & 0x7) + 1;
++ /* The register defines PLL6-2X, not plain PLL6 */
++ uint32_t freq = 24000000UL * n / m / p0;
++
++ printf("PLL reg = 0x%08x, freq = %d\n", rval, freq);
++
++ return freq;
++}
++
+ struct sunxi_mmc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+@@ -60,7 +77,8 @@ static bool sunxi_mmc_can_calibrate(void
+ return IS_ENABLED(CONFIG_MACH_SUN50I) ||
+ IS_ENABLED(CONFIG_MACH_SUN50I_H5) ||
+ IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
+- IS_ENABLED(CONFIG_MACH_SUN8I_R40);
++ IS_ENABLED(CONFIG_MACH_SUN8I_R40) ||
++ IS_ENABLED(CONFIG_TARGET_SUN20I_D1);
+ }
+
+ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
+@@ -194,7 +212,7 @@ static int mmc_config_clock(struct sunxi
+ rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
+ writel(rval, &priv->reg->clkcr);
+
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_TARGET_SUN20I_D1)
+ /* 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
+@@ -622,7 +640,8 @@ static unsigned get_mclk_offset(void)
+ if (IS_ENABLED(CONFIG_MACH_SUN9I_A80))
+ return 0x410;
+
+- if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++ if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++ IS_ENABLED(CONFIG_TARGET_SUN20I_D1))
+ return 0x830;
+
+ return 0x88;
+@@ -662,6 +681,7 @@ static int sunxi_mmc_probe(struct udevic
+ return ret;
+ ccu_reg = (u32 *)(uintptr_t)ofnode_get_addr(args.node);
+
++#define SUNXI_MMC0_BASE 0x4020000
+ priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
+ priv->mclkreg = (void *)ccu_reg + get_mclk_offset() + priv->mmc_no * 4;
+
+@@ -703,6 +723,7 @@ static const struct udevice_id sunxi_mmc
+ { .compatible = "allwinner,sun7i-a20-mmc" },
+ { .compatible = "allwinner,sun8i-a83t-emmc" },
+ { .compatible = "allwinner,sun9i-a80-mmc" },
++ { .compatible = "allwinner,sun20i-d1-mmc" },
+ { .compatible = "allwinner,sun50i-a64-mmc" },
+ { .compatible = "allwinner,sun50i-a64-emmc" },
+ { .compatible = "allwinner,sun50i-h6-mmc" },
+--- a/drivers/mmc/sunxi_mmc.h
++++ b/drivers/mmc/sunxi_mmc.h
+@@ -45,11 +45,9 @@ struct sunxi_mmc {
+ u32 chda; /* 0x90 */
+ u32 cbda; /* 0x94 */
+ u32 res2[26];
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
+ u32 res3[17];
+ u32 samp_dl;
+ u32 res4[46];
+-#endif
+ u32 fifo; /* 0x100 / 0x200 FIFO access address */
+ };
+
--- /dev/null
+From c33ca5c6a5be74711460756bf86c45b6c6fd0a3f Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Thu, 4 Nov 2021 17:49:15 -0500
+Subject: [PATCH 82/90] pinctrl: sunxi: Hack up the driver for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -9,6 +9,7 @@
+ #include <malloc.h>
+
+ #include <asm/gpio.h>
++#include "../../../arch/arm/include/asm/arch-sunxi/gpio.h"
+
+ extern U_BOOT_DRIVER(gpio_sunxi);
+
+@@ -49,7 +50,7 @@ static const char *sunxi_pinctrl_get_pin
+ uint pin_selector)
+ {
+ const struct sunxi_pinctrl_desc *desc = dev_get_priv(dev);
+- static char pin_name[sizeof("PN31")];
++ static char pin_name[sizeof("PN31")] __section(".data");
+
+ snprintf(pin_name, sizeof(pin_name), "P%c%d",
+ pin_selector / SUNXI_GPIOS_PER_BANK + desc->first_bank + 'A',
--- /dev/null
+From 9f612f3a1fd3d0759abca3720d488a17d159aa17 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 30 Oct 2022 14:54:08 -0500
+Subject: [PATCH 83/90] ram: sunxi: Add Allwinner D1 DRAM driver
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/ram/Kconfig | 1 +
+ drivers/ram/Makefile | 1 +
+ drivers/ram/sunxi/Kconfig | 6 +
+ drivers/ram/sunxi/Makefile | 3 +
+ drivers/ram/sunxi/dram_v2.h | 65 +
+ drivers/ram/sunxi/mctl_hal-sun20iw1p1.c | 1771 +++++++++++++++++++++++
+ drivers/ram/sunxi/sdram.h | 46 +
+ 7 files changed, 1893 insertions(+)
+ create mode 100644 drivers/ram/sunxi/Kconfig
+ create mode 100644 drivers/ram/sunxi/Makefile
+ create mode 100644 drivers/ram/sunxi/dram_v2.h
+ create mode 100644 drivers/ram/sunxi/mctl_hal-sun20iw1p1.c
+ create mode 100644 drivers/ram/sunxi/sdram.h
+
+--- a/drivers/ram/Kconfig
++++ b/drivers/ram/Kconfig
+@@ -101,3 +101,4 @@ source "drivers/ram/rockchip/Kconfig"
+ source "drivers/ram/sifive/Kconfig"
+ source "drivers/ram/stm32mp1/Kconfig"
+ source "drivers/ram/octeon/Kconfig"
++source "drivers/ram/sunxi/Kconfig"
+--- a/drivers/ram/Makefile
++++ b/drivers/ram/Makefile
+@@ -20,5 +20,6 @@ obj-$(CONFIG_K3_DDRSS) += k3-ddrss/
+ obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o
+
+ obj-$(CONFIG_RAM_SIFIVE) += sifive/
++obj-$(CONFIG_RAM_SUNXI) += sunxi/
+
+ obj-$(CONFIG_ARCH_OCTEON) += octeon/
+--- /dev/null
++++ b/drivers/ram/sunxi/Kconfig
+@@ -0,0 +1,6 @@
++config RAM_SUNXI
++ bool "Ram drivers support for sunxi SoCs"
++ depends on RAM && BOARD_SUNXI
++ default y
++ help
++ This enables support for ram drivers of sunxi SoCs.
+--- /dev/null
++++ b/drivers/ram/sunxi/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0+
++
++obj-$(CONFIG_RAM_SUNXI) += mctl_hal-sun20iw1p1.o
+--- /dev/null
++++ b/drivers/ram/sunxi/dram_v2.h
+@@ -0,0 +1,65 @@
++/*
++ * (C) Copyright 2007-2013
++* SPDX-License-Identifier: GPL-2.0+
++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
++ * Jerry Wang <wangflord@allwinnertech.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef __dram_head_h__
++#define __dram_head_h__
++
++struct dram_para_t
++{
++ //normal configuration
++ unsigned int dram_clk;
++ unsigned int dram_type; //dram_type DDR2: 2 DDR3: 3 LPDDR2: 6 LPDDR3: 7 DDR3L: 31
++ //unsigned int lpddr2_type; //LPDDR2 type S4:0 S2:1 NVM:2
++ unsigned int dram_zq; //do not need
++ unsigned int dram_odt_en;
++
++ //control configuration
++ unsigned int dram_para1;
++ unsigned int dram_para2;
++
++ //timing configuration
++ unsigned int dram_mr0;
++ unsigned int dram_mr1;
++ unsigned int dram_mr2;
++ unsigned int dram_mr3;
++ unsigned int dram_tpr0; //DRAMTMG0
++ unsigned int dram_tpr1; //DRAMTMG1
++ unsigned int dram_tpr2; //DRAMTMG2
++ unsigned int dram_tpr3; //DRAMTMG3
++ unsigned int dram_tpr4; //DRAMTMG4
++ unsigned int dram_tpr5; //DRAMTMG5
++ unsigned int dram_tpr6; //DRAMTMG8
++ //reserved for future use
++ unsigned int dram_tpr7;
++ unsigned int dram_tpr8;
++ unsigned int dram_tpr9;
++ unsigned int dram_tpr10;
++ unsigned int dram_tpr11;
++ unsigned int dram_tpr12;
++ unsigned int dram_tpr13;
++
++};
++
++#endif
+--- /dev/null
++++ b/drivers/ram/sunxi/mctl_hal-sun20iw1p1.c
+@@ -0,0 +1,1771 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <common.h>
++#include <dm.h>
++#include <ram.h>
++#include <linux/delay.h>
++
++#include "dram_v2.h"
++#include "sdram.h"
++
++#define readl rv_readl
++#define writel rv_writel
++#include <asm/io.h>
++#undef readl
++#undef writel
++
++#define readl(x) rv_readl((const volatile void __iomem *)(u64)(x))
++#define writel(x, v) rv_writel(v, (volatile void __iomem *)(u64)(x))
++
++#if defined(CONFIG_SPL_BUILD)
++
++char* memcpy_self(char* dst, char* src, int len)
++{
++ int i;
++ for(i=0; i!=len; i++) {
++ dst[i] = src[i];
++ }
++ return dst;
++}
++
++void dram_vol_set(struct dram_para_t *para)
++{
++ int reg, vol = 0;
++
++ switch( para->dram_type ) {
++ case 2: vol = 47; break;
++ case 3: vol = 25; break;
++ default: vol = 0;
++ }
++vol = 25; // XXX
++ reg = readl(0x3000150);
++ reg &= ~(0xff00);
++ reg |= vol << 8;
++ reg &= ~(0x200000);
++ writel(0x3000150, reg);
++
++ udelay(1);
++}
++
++void paraconfig(unsigned int *para, unsigned int mask, unsigned int value)
++{
++ *para &= ~(mask);
++ *para |= value;
++}
++
++
++void dram_enable_all_master(void)
++{
++ writel(0x3102020, -1);
++ writel(0x3102024, 0xff);
++ writel(0x3102028, 0xffff);
++ udelay(10);
++}
++
++
++void dram_disable_all_master(void)
++{
++ writel(0x3102020, 1);
++ writel(0x3102024, 0);
++ writel(0x3102028, 0);
++ udelay(10);
++}
++
++
++void eye_delay_compensation(struct dram_para_t *para) // s1
++{
++ unsigned int val, ptr;
++
++ // DATn0IOCR, n = 0...7
++ for (ptr = 0x3103310; ptr != 0x3103334; ptr += 4) {
++ val = readl(ptr);
++ val |= (para->dram_tpr11 << 9) & 0x1e00;
++ val |= (para->dram_tpr12 << 1) & 0x001e;
++ writel(ptr, val);
++ }
++
++ // DATn1IOCR, n = 0...7
++ for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4) {
++ val = readl(ptr);
++ val |= ((para->dram_tpr11 >> 4) << 9) & 0x1e00;
++ val |= ((para->dram_tpr12 >> 4) << 1) & 0x001e;
++ writel(ptr, val);
++ }
++
++ // PGCR0: assert AC loopback FIFO reset
++ val = readl(0x3103100);
++ val &= 0xfbffffff;
++ writel(0x3103100, val);
++
++ // ??
++ val = readl(0x3103334);
++ val |= ((para->dram_tpr11 >> 16) << 9) & 0x1e00;
++ val |= ((para->dram_tpr12 >> 16) << 1) & 0x001e;
++ writel(0x3103334, val);
++
++ val = readl(0x3103338);
++ val |= ((para->dram_tpr11 >> 16) << 9) & 0x1e00;
++ val |= ((para->dram_tpr12 >> 16) << 1) & 0x001e;
++ writel(0x3103338, val);
++
++ val = readl(0x31033b4);
++ val |= ((para->dram_tpr11 >> 20) << 9) & 0x1e00;
++ val |= ((para->dram_tpr12 >> 20) << 1) & 0x001e;
++ writel(0x31033b4, val);
++
++ val = readl(0x31033b8);
++ val |= ((para->dram_tpr11 >> 20) << 9) & 0x1e00;
++ val |= ((para->dram_tpr12 >> 20) << 1) & 0x001e;
++ writel(0x31033b8, val);
++
++ val = readl(0x310333c);
++ val |= ((para->dram_tpr11 >> 16) << 25) & 0x1e000000;
++ writel(0x310333c, val);
++
++ val = readl(0x31033bc);
++ val |= ((para->dram_tpr11 >> 20) << 25) & 0x1e000000;
++ writel(0x31033bc, val);
++
++ // PGCR0: release AC loopback FIFO reset
++ val = readl(0x3103100);
++ val |= 0x04000000;
++ writel(0x3103100, val);
++
++ udelay(1);
++
++ for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4) {
++ val = readl(ptr);
++ val |= ((para->dram_tpr10 >> 4) << 8) & 0x0f00;
++ writel(ptr, val);
++ }
++
++ for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4) {
++ val = readl(ptr);
++ val |= ((para->dram_tpr10 >> 4) << 8) & 0x0f00;
++ writel(ptr, val);
++ }
++
++ val = readl(0x3103218);
++ val |= (para->dram_tpr10 << 8) & 0x0f00;
++ writel(0x3103218, val);
++
++ val = readl(0x310321c);
++ val |= (para->dram_tpr10 << 8) & 0x0f00;
++ writel(0x310321c, val);
++
++ val = readl(0x3103280);
++ val |= ((para->dram_tpr10 >> 12) << 8) & 0x0f00;
++ writel(0x3103280, val);
++}
++
++
++// Not used ??
++//
++void bit_delay_compensation(void)
++{
++ const unsigned int data0[44] = {
++ 0, 1, 2, 3, 2, 3, 3, 3, 0, 0, 0,
++ 6, 6, 6, 5, 5, 5, 5, 5, 0, 0, 0,
++ 0, 2, 4, 2, 6, 5, 5, 5, 0, 0, 0,
++ 3, 3, 3, 2, 2, 1, 1, 1, 0, 0, 0,
++ };
++ const unsigned int data1[44] = {
++ 0, 1, 3, 3, 3, 3, 3, 4, 3, 3, 3,
++ 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3,
++ 0, 3, 3, 1, 6, 6, 5, 6, 3, 3, 3,
++ 5, 5, 6, 6, 4, 5, 3, 3, 3, 3, 3,
++ };
++
++ unsigned int *start = (unsigned int *)0x3102310; // DATX0IOCR
++ unsigned int *end = (unsigned int *)0x3102510; // DATX0IOCR x + 4 * size
++ unsigned int *datxiocr;
++ unsigned int i, j, k, rval;
++
++ rval = readl(0x3102100) & 0x03ffffff;
++ writel(0x3102100, rval);
++
++ // Fill DATX0IOCR - DATX3IOCR, 11 registers per block, blocks 0x20 words apart
++ for(i = 0, datxiocr = start; datxiocr != end; i += 11, datxiocr += 0x20) {
++ for(j = 0, k = i; j != 11; j++, k++) {
++ rval = readl((unsigned int)datxiocr[j]);
++ rval += data1[k] << 8;
++ rval += data0[k];
++ writel((unsigned int)datxiocr[j], rval);
++ }
++ }
++
++ rval = readl(0x3102100) | 0x04000000;
++ writel(0x3102100, rval);
++}
++
++// Not used ??
++//
++void set_master_priority_pad(struct dram_para_t *para)
++{
++ unsigned int val;
++
++ val = readl(0x310200c) & 0xfffff000;
++ val |= (para->dram_clk >> 1) - 1;
++ writel(0x310200c, val);
++
++ writel(0x3102200, 0x00001000);
++ writel(0x3102210, 0x01000009);
++ writel(0x3102214, 0x00500100);
++ writel(0x3102230, 0x0200000d);
++ writel(0x3102234, 0x00600100);
++ writel(0x3102240, 0x01000009);
++ writel(0x3102244, 0x00500100);
++ writel(0x3102260, 0x00640209);
++ writel(0x3102264, 0x00200040);
++ writel(0x3102290, 0x01000009);
++ writel(0x3102294, 0x00400080);
++ writel(0x3102470, 0);
++ writel(0x3102474, 0);
++
++ writel(0x31031c0, 0x0f802f05);
++ writel(0x31031c8, 0x0f0000ff);
++ writel(0x31031d0, 0x3f00005f);
++}
++
++int auto_cal_timing(unsigned int time, unsigned int freq)
++{
++ unsigned int t = time*freq;
++ return t/1000 + ( ((t%1000) != 0) ? 1 : 0);
++}
++
++// Main purpose of the auto_set_timing routine seems to be to calculate all
++// timing settings for the specific type of sdram used. Read together with
++// an sdram datasheet for context on the various variables.
++//
++void auto_set_timing_para(struct dram_para_t *para) // s5
++{
++ unsigned int freq; // s4
++ unsigned int type; // s8
++ unsigned int tpr13; // 80(sp)
++ unsigned int reg_val;
++
++ unsigned char tccd; // 88(sp)
++ unsigned char trrd; // s7
++ unsigned char trcd; // s3
++ unsigned char trc; // s9
++ unsigned char tfaw; // s10
++ unsigned char tras; // s11
++ unsigned char trp; // 0(sp)
++ unsigned char twtr; // s1
++ unsigned char twr; // s6
++ unsigned char trtp; // 64(sp)
++ unsigned char txp; // a6
++ unsigned short trefi; // s2
++ unsigned short trfc; // a5 / 8(sp)
++
++ freq = para->dram_clk;
++ type = para->dram_type;
++ tpr13 = para->dram_tpr13;
++
++ //printf("type = %d\n", type);
++ //printf("tpr13 = %p\n", tpr13);
++
++ if (para->dram_tpr13 & 0x2)
++ {
++ //dram_tpr0
++ tccd = ( (para->dram_tpr0 >> 21) & 0x7 ); // [23:21]
++ tfaw = ( (para->dram_tpr0 >> 15) & 0x3f ); // [20:15]
++ trrd = ( (para->dram_tpr0 >> 11) & 0xf ); // [14:11]
++ trcd = ( (para->dram_tpr0 >> 6) & 0x1f ); // [10:6 ]
++ trc = ( (para->dram_tpr0 >> 0) & 0x3f ); // [ 5:0 ]
++ //dram_tpr1
++ txp = ( (para->dram_tpr1 >> 23) & 0x1f ); // [27:23]
++ twtr = ( (para->dram_tpr1 >> 20) & 0x7 ); // [22:20]
++ trtp = ( (para->dram_tpr1 >> 15) & 0x1f ); // [19:15]
++ twr = ( (para->dram_tpr1 >> 11) & 0xf ); // [14:11]
++ trp = ( (para->dram_tpr1 >> 6) & 0x1f ); // [10:6 ]
++ tras = ( (para->dram_tpr1 >> 0) & 0x3f ); // [ 5:0 ]
++ //dram_tpr2
++ trfc = ( (para->dram_tpr2 >> 12)& 0x1ff); // [20:12]
++ trefi = ( (para->dram_tpr2 >> 0) & 0xfff); // [11:0 ]
++ }
++ else {
++ unsigned int frq2 = freq >> 1; // s0
++
++ if (type == 3) {
++ // DDR3
++ trfc = auto_cal_timing( 350, frq2);
++ trefi = auto_cal_timing(7800, frq2) / 32 + 1; // XXX
++ twr = auto_cal_timing( 8, frq2);
++ trcd = auto_cal_timing( 15, frq2);
++ twtr = twr + 2; // + 2 ? XXX
++ if (twr < 2) twtr = 2;
++ twr = trcd;
++ if (trcd < 2) twr = 2;
++ if (freq <= 800) {
++ tfaw = auto_cal_timing(50, frq2);
++ trrd = auto_cal_timing(10, frq2);
++ if (trrd < 2) trrd = 2;
++ trc = auto_cal_timing(53, frq2);
++ tras = auto_cal_timing(38, frq2);
++ txp = trrd; // 10
++ trp = trcd; // 15
++ }
++ else {
++ tfaw = auto_cal_timing(35, frq2);
++ trrd = auto_cal_timing(10, frq2);
++ if (trrd < 2) trrd = 2;
++ trcd = auto_cal_timing(14, frq2);
++ trc = auto_cal_timing(48, frq2);
++ tras = auto_cal_timing(34, frq2);
++ txp = trrd; // 10
++ trp = trcd; // 14
++ }
++ }
++ else if (type == 2) {
++ // DDR2
++ tfaw = auto_cal_timing( 50, frq2);
++ trrd = auto_cal_timing( 10, frq2);
++ trcd = auto_cal_timing( 20, frq2);
++ trc = auto_cal_timing( 65, frq2);
++ twtr = auto_cal_timing( 8, frq2);
++ trp = auto_cal_timing( 15, frq2);
++ tras = auto_cal_timing( 45, frq2);
++ trefi = auto_cal_timing(7800, frq2) / 32;
++ trfc = auto_cal_timing( 328, frq2);
++ txp = 2;
++ twr = trp; // 15
++ }
++ else if (type == 6) {
++ // LPDDR2
++ tfaw = auto_cal_timing( 50, frq2);
++ if (tfaw < 4) tfaw = 4;
++ trrd = auto_cal_timing( 10, frq2);
++ if (trrd == 0) trrd = 1;
++ trcd = auto_cal_timing( 24, frq2);
++ if (trcd < 2) trcd = 2;
++ trc = auto_cal_timing( 70, frq2);
++ txp = auto_cal_timing( 8, frq2);
++ if (txp == 0) {
++ txp = 1;
++ twtr = 2;
++ }
++ else {
++ twtr = txp;
++ if (txp < 2) {
++ txp = 2;
++ twtr = 2;
++ }
++ }
++ twr = auto_cal_timing( 15, frq2);
++ if (twr < 2) twr = 2;
++ trp = auto_cal_timing( 17, frq2);
++ tras = auto_cal_timing( 42, frq2);
++ trefi = auto_cal_timing(3900, frq2) / 32;
++ trfc = auto_cal_timing( 210, frq2);
++ }
++ else if (type == 7) {
++ // LPDDR3
++ tfaw = auto_cal_timing( 50, frq2);
++ if (tfaw < 4) tfaw = 4;
++ trrd = auto_cal_timing( 10, frq2);
++ if (trrd == 0) trrd = 1;
++ trcd = auto_cal_timing( 24, frq2);
++ if (trcd < 2) trcd = 2;
++ trc = auto_cal_timing( 70, frq2);
++ twtr = auto_cal_timing( 8, frq2);
++ if (twtr < 2) twtr = 2;
++ twr = auto_cal_timing( 15, frq2);
++ if (twr < 2) twr = 2;
++ trp = auto_cal_timing( 17, frq2);
++ tras = auto_cal_timing( 42, frq2);
++ trefi = auto_cal_timing(3900, frq2) / 32;
++ trfc = auto_cal_timing( 210, frq2);
++ txp = twtr;
++ }
++ else {
++ // default
++ trfc = 128;
++ trp = 6;
++ trefi = 98;
++ txp = 10;
++ twr = 8;
++ twtr = 3;
++ tras = 14;
++ tfaw = 16;
++ trc = 20;
++ trcd = 6;
++ trrd = 3;
++ }
++ //assign the value back to the DRAM structure
++ tccd = 2;
++ trtp = 4; // not in .S ?
++ para->dram_tpr0 = (trc<<0) | (trcd<<6) | (trrd<<11) | (tfaw<<15) | (tccd<<21);
++ para->dram_tpr1 = (tras<<0) | (trp<<6) | (twr<<11) | (trtp<<15) | (twtr<<20) | (txp<<23);
++ para->dram_tpr2 = (trefi<<0) | (trfc<<12);
++ }
++
++ unsigned int tcksrx; // t1
++ unsigned int tckesr; // t4;
++ unsigned int trd2wr; // t6
++ unsigned int trasmax; // t3;
++ unsigned int twtp; // s6 (was twr!)
++ unsigned int tcke; // s8
++ unsigned int tmod; // t0
++ unsigned int tmrd; // t5
++ unsigned int tmrw; // a1
++ unsigned int t_rdata_en;// a4 (was tcwl!)
++ unsigned int tcl; // a0
++ unsigned int wr_latency;// a7
++ unsigned int tcwl; // first a4, then a5
++ unsigned int mr3; // s0
++ unsigned int mr2; // t2
++ unsigned int mr1; // s1
++ unsigned int mr0; // a3
++ unsigned int dmr3; // 72(sp)
++ //unsigned int trtp; // 64(sp)
++ unsigned int dmr1; // 56(sp)
++ unsigned int twr2rd; // 48(sp)
++ unsigned int tdinit3; // 40(sp)
++ unsigned int tdinit2; // 32(sp)
++ unsigned int tdinit1; // 24(sp)
++ unsigned int tdinit0; // 16(sp)
++
++ dmr1 = para->dram_mr1;
++ dmr3 = para->dram_mr3;
++
++ switch (type) {
++
++ case 2: // DDR2
++ {
++ trasmax = freq / 30;
++ if (freq < 409) {
++ tcl = 3;
++ t_rdata_en = 1;
++ mr0 = 0x06a3;
++ }
++ else {
++ t_rdata_en = 2;
++ tcl = 4;
++ mr0 = 0x0e73;
++ }
++ tmrd = 2;
++ twtp = twr + 5;
++ tcksrx = 5;
++ tckesr = 4;
++ trd2wr = 4;
++ tcke = 3;
++ tmod = 12;
++ wr_latency = 1;
++ mr3 = 0;
++ mr2 = 0;
++ tdinit0 = 200*freq + 1;
++ tdinit1 = 100*freq / 1000 + 1;
++ tdinit2 = 200*freq + 1;
++ tdinit3 = 1*freq + 1;
++ tmrw = 0;
++ twr2rd = twtr + 5;
++ tcwl = 0;
++ mr1 = dmr1;
++ break;
++ }
++
++ case 3: // DDR3
++ {
++ trasmax = freq / 30;
++ if (freq <= 800) {
++ mr0 = 0x1c70;
++ tcl = 6;
++ wr_latency = 2;
++ tcwl = 4;
++ mr2 = 24;
++ }
++ else {
++ mr0 = 0x1e14;
++ tcl = 7;
++ wr_latency = 3;
++ tcwl = 5;
++ mr2 = 32;
++ }
++
++ twtp = tcwl + 2 + twtr; // WL+BL/2+tWTR
++ trd2wr = tcwl + 2 + twr; // WL+BL/2+tWR
++ twr2rd = tcwl + twtr; // WL+tWTR
++
++ tdinit0 = 500*freq + 1; // 500 us
++ tdinit1 = 360*freq / 1000 + 1; // 360 ns
++ tdinit2 = 200*freq + 1; // 200 us
++ tdinit3 = 1*freq + 1; // 1 us
++
++ if (((tpr13>>2) & 0x03) == 0x01 || freq < 912) {
++ mr1 = dmr1;
++ t_rdata_en = tcwl; // a5 <- a4
++ tcksrx = 5;
++ tckesr = 4;
++ trd2wr = 5;
++ }
++ else {
++ mr1 = dmr1;
++ t_rdata_en = tcwl; // a5 <- a4
++ tcksrx = 5;
++ tckesr = 4;
++ trd2wr = 6;
++ }
++ tcke = 3; // not in .S ?
++ tmod = 12;
++ tmrd = 4;
++ tmrw = 0;
++ mr3 = 0;
++ break;
++ }
++
++ case 6: // LPDDR2
++ {
++ trasmax = freq / 60;
++ mr3 = dmr3;
++ twtp = twr + 5;
++ mr2 = 6;
++ mr1 = 5;
++ tcksrx = 5;
++ tckesr = 5;
++ trd2wr = 10;
++ tcke = 2;
++ tmod = 5;
++ tmrd = 5;
++ tmrw = 3;
++ tcl = 4;
++ wr_latency = 1;
++ t_rdata_en = 1;
++ tdinit0 = 200*freq + 1;
++ tdinit1 = 100*freq / 1000 + 1;
++ tdinit2 = 11*freq + 1;
++ tdinit3 = 1*freq + 1;
++ twr2rd = twtr + 5;
++ tcwl = 2;
++ mr1 = 195;
++ mr0 = 0;
++ break;
++ }
++
++ case 7: // LPDDR3
++ {
++ trasmax = freq / 60;
++ if (freq < 800) {
++ tcwl = 4;
++ wr_latency = 3;
++ t_rdata_en = 6;
++ mr2 = 12;
++ }
++ else {
++ tcwl = 3;
++ tcke = 6;
++ wr_latency = 2;
++ t_rdata_en = 5;
++ mr2 = 10;
++ }
++ twtp = tcwl + 5;
++ tcl = 7;
++ mr3 = dmr3;
++ tcksrx = 5;
++ tckesr = 5;
++ trd2wr = 13;
++ tcke = 3;
++ tmod = 12;
++ tdinit0 = 400*freq + 1;
++ tdinit1 = 500*freq / 1000 + 1;
++ tdinit2 = 11*freq + 1;
++ tdinit3 = 1*freq + 1;
++ tmrd = 5;
++ tmrw = 5;
++ twr2rd = tcwl + twtr + 5;
++ mr1 = 195;
++ mr0 = 0;
++ break;
++ }
++
++ default:
++ twr2rd = 8; // 48(sp)
++ tcksrx = 4; // t1
++ tckesr = 3; // t4
++ trd2wr = 4; // t6
++ trasmax = 27; // t3
++ twtp = 12; // s6
++ tcke = 2; // s8
++ tmod = 6; // t0
++ tmrd = 2; // t5
++ tmrw = 0; // a1
++ tcwl = 3; // a5
++ tcl = 3; // a0
++ wr_latency = 1; // a7
++ t_rdata_en = 1; // a4
++ mr3 = 0; // s0
++ mr2 = 0; // t2
++ mr1 = 0; // s1
++ mr0 = 0; // a3
++ tdinit3 = 0; // 40(sp)
++ tdinit2 = 0; // 32(sp)
++ tdinit1 = 0; // 24(sp)
++ tdinit0 = 0; // 16(sp)
++ break;
++ }
++ if (trtp < tcl - trp + 2) {
++ trtp = tcl - trp + 2;
++ }
++ trtp = 4;
++
++ // Update mode block when permitted
++ if ((para->dram_mr0 & 0xffff0000) == 0) para->dram_mr0 = mr0;
++ if ((para->dram_mr1 & 0xffff0000) == 0) para->dram_mr1 = mr1;
++ if ((para->dram_mr2 & 0xffff0000) == 0) para->dram_mr2 = mr2;
++ if ((para->dram_mr3 & 0xffff0000) == 0) para->dram_mr3 = mr3;
++
++ // Set mode registers
++ writel(0x3103030, para->dram_mr0);
++ writel(0x3103034, para->dram_mr1);
++ writel(0x3103038, para->dram_mr2);
++ writel(0x310303c, para->dram_mr3);
++ writel(0x310302c, (para->dram_odt_en >> 4) & 0x3); // ??
++
++ // Set dram timing DRAMTMG0 - DRAMTMG5
++ reg_val= (twtp<<24) | (tfaw<<16) | (trasmax<<8) | (tras<<0);
++ writel(0x3103058, reg_val);
++ reg_val= (txp<<16) | (trtp<<8) | (trc<<0);
++ writel(0x310305c, reg_val);
++ reg_val= (tcwl<<24) | (tcl<<16) | (trd2wr<<8) | (twr2rd<<0);
++ writel(0x3103060, reg_val);
++ reg_val= (tmrw<<16) | (tmrd<<12) | (tmod<<0);
++ writel(0x3103064, reg_val);
++ reg_val= (trcd<<24) | (tccd<<16) | (trrd<<8) | (trp<<0);
++ writel(0x3103068, reg_val);
++ reg_val= (tcksrx<<24) | (tcksrx<<16) | (tckesr<<8) | (tcke<<0);
++ writel(0x310306c, reg_val);
++
++ // Set two rank timing
++ reg_val = readl(0x3103078);
++ reg_val &= 0x0fff0000;
++ reg_val |= (para->dram_clk < 800) ? 0xf0006600 : 0xf0007600;
++ reg_val |= 0x10;
++ writel(0x3103078, reg_val);
++
++ // Set phy interface time PITMG0, PTR3, PTR4
++ reg_val = (0x2<<24) | (t_rdata_en<<16) | (0x1<<8) | (wr_latency<<0);
++ writel(0x3103080, reg_val);
++ writel(0x3103050, ((tdinit0<<0)|(tdinit1<<20)));
++ writel(0x3103054, ((tdinit2<<0)|(tdinit3<<20)));
++
++ // Set refresh timing and mode
++ reg_val = (trefi<<16) | (trfc<<0);
++ writel(0x3103090, reg_val);
++ reg_val = 0x0fff0000 & (trefi<<15);
++ writel(0x3103094, reg_val);
++}
++
++// Not used ?
++//
++void ccm_get_sscg(void)
++{
++ // NOTE: function is present in the assembly, but was not translated.
++}
++
++// Not used ?
++//
++void ccm_set_pll_sscg(void)
++{
++ // NOTE: function is present in the assembly, but was not translated.
++}
++
++// Purpose of this routine seems to be to initialize the PLL driving
++// the MBUS and sdram.
++//
++int ccm_set_pll_ddr_clk(int index, struct dram_para_t *para)
++{
++ unsigned int val, clk, n;
++
++ clk = (para->dram_tpr13 & (1 << 6)) ? para->dram_tpr9
++ : para->dram_clk;
++
++ // set VCO clock divider
++ n = (clk * 2) / 24;
++ val = readl(0x2001010);
++ val &= 0xfff800fc; // clear dividers
++ val |= (n - 1) << 8; // set PLL division
++ val |= 0xc0000000; // enable PLL and LDO
++ writel(0x2001010, val);
++
++ // Restart PLL locking
++ val &= 0xdfffffff; // disbable lock
++ val |= 0xc0000000; // enable PLL and LDO
++ writel(0x2001010, val);
++ val |= 0xe0000000; // re-enable lock
++ writel(0x2001010, val);
++
++ // wait for PLL to lock
++ while ((readl(0x2001010) & 0x10000000) == 0) {;}
++
++ udelay(20);
++
++ // enable PLL output
++ val = readl(0x2001000);
++ val |= 0x08000000;
++ writel(0x2001000, val);
++
++ // turn clock gate on
++ val = readl(0x2001800);
++ val &= 0xfcfffcfc; // select DDR clk source, n=1, m=1
++ val |= 0x80000000; // turn clock on
++ writel(0x2001800, val);
++
++ return n * 24;
++}
++
++// Main purpose of sys_init seems to be to initalise the clocks for
++// the sdram controller.
++//
++void mctl_sys_init(struct dram_para_t *para)
++{
++ unsigned int val;
++
++ // s1 = 0x02001000
++
++ // assert MBUS reset
++ val = readl(0x2001540);
++ val &= 0xbfffffff;
++ writel(0x2001540, val);
++
++ // turn off sdram clock gate, assert sdram reset
++ val = readl(0x200180c);
++ val &= 0xfffffffe;
++ writel(0x200180c, val);
++ val &= 0xfffefffe;
++ writel(0x200180c, val);
++
++ // turn of bit 30 [??]
++ val = readl(0x2001800);
++ writel(0x2001800, val & 0xbfffffff);
++ // and toggle dram clock gating off + trigger update
++ val &= 0x7fffffff;
++ writel(0x2001800, val);
++ val |= 0x08000000;
++ writel(0x2001800, val);
++ udelay(10);
++
++ // set ddr pll clock
++ val = ccm_set_pll_ddr_clk(0, para);
++ para->dram_clk = val >> 1;
++ udelay(100);
++ dram_disable_all_master();
++
++ // release sdram reset
++ val = readl(0x200180c);
++ val |= 0x00010000;
++ writel(0x200180c, val);
++
++ // release MBUS reset
++ val = readl(0x2001540);
++ val |= 0x40000000;
++ writel(0x2001540, val);
++
++ // turn bit 30 back on [?]
++ val = readl(0x2001800);
++ val |= 0x40000000;
++ writel(0x2001800, val);
++ udelay(5);
++
++ // turn on sdram clock gate
++ val = readl(0x200180c);
++ val |= 0x0000001; // (1<<0)
++ writel(0x200180c, val);
++
++ // turn dram clock gate on, trigger sdr clock update
++ val = readl(0x2001800);
++ val |= 0x80000000;
++ writel(0x2001800, val);
++ val |= 0x88000000;
++ writel(0x2001800, val);
++ udelay(5);
++
++ // mCTL clock enable
++ writel(0x310300c, 0x00008000);
++ udelay(10);
++}
++
++// The main purpose of this routine seems to be to copy an address configuration
++// from the dram_para1 and dram_para2 fields to the PHY configuration registers
++// (0x3102000, 0x3102004).
++//
++void mctl_com_init(struct dram_para_t *para)
++{
++ unsigned int val, end, ptr;
++ int i;
++
++ // purpose ??
++ val = readl(0x3102008) & 0xffffc0ff;
++ val |= 0x2000;
++ writel(0x3102008, val);
++
++ // Set sdram type and word width
++ val = readl(0x3102000) & 0xff000fff;
++ val |= (para->dram_type &0x7) << 16; // DRAM type
++ val |= (~para->dram_para2 & 0x1) << 12; // DQ width
++ if((para->dram_type) != 6 && (para->dram_type) != 7) {
++ val |= ((para->dram_tpr13 >> 5) & 0x1) << 19; // 2T or 1T
++ val |= 0x400000;
++ }
++ else {
++ val |= 0x480000; // type 6 and 7 must use 1T
++ }
++ writel(0x3102000, val);
++
++ // init rank / bank / row for single/dual or two different ranks
++ val = para->dram_para2;
++ end = ((val & 0x100) && (((val >> 12) & 0xf) != 1)) ? 32 : 16;
++ ptr = 0x3102000;
++
++ for (i = 0 ; i != end; i += 16) {
++
++ val = readl(ptr) & 0xfffff000;
++
++ val |= (para->dram_para2 >> 12) & 0x3; // rank
++ val |= ((para->dram_para1 >> (i + 12)) << 2) & 0x4; // bank - 2
++ val |= (((para->dram_para1 >> (i + 4)) - 1) << 4) & 0xff; // row - 1
++
++ // convert from page size to column addr width - 3
++ switch ((para->dram_para1 >> i) & 0xf) {
++ case 8: val |= 0xa00; break;
++ case 4: val |= 0x900; break;
++ case 2: val |= 0x800; break;
++ case 1: val |= 0x700; break;
++ default: val |= 0x600; break;
++ }
++ writel(ptr, val);
++ ptr += 4;
++ }
++
++ // set ODTMAP based on number of ranks in use
++ val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201;
++ writel(0x3103120, val);
++
++ // set mctl reg 3c4 to zero when using half DQ
++ if (para->dram_para2 & (1 << 0)) {
++ writel(0x31033c4, 0);
++ }
++
++ // purpose ??
++ if (para->dram_tpr4) {
++ val = readl(0x3102000);
++ val |= (para->dram_tpr4 << 25) & 0x06000000;
++ writel(0x3102000, val);
++
++ val = readl(0x3102004);
++ val |= ((para->dram_tpr4 >> 2) << 12) & 0x001ff000;
++ writel(0x3102004, val);
++ }
++}
++
++// This routine seems to have several remapping tables for 22 lines.
++// It is unclear which lines are being remapped. It seems to pick
++// table cfg7 for the Nezha board.
++//
++void mctl_phy_ac_remapping(struct dram_para_t *para)
++{
++ char cfg0[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
++ static char cfg1[] = { 1, 9, 3, 7, 8, 18, 4, 13, 5, 6, 10,
++ 2, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 };
++ static char cfg2[] = { 4, 9, 3, 7, 8, 18, 1, 13, 2, 6, 10,
++ 5, 14, 12, 0, 0, 21, 17, 20, 19, 11, 22 };
++ static char cfg3[] = { 1, 7, 8, 12, 10, 18, 4, 13, 5, 6, 3,
++ 2, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 };
++ static char cfg4[] = { 4, 12, 10, 7, 8, 18, 1, 13, 2, 6, 3,
++ 5, 9, 0, 0, 0, 21, 17, 20, 19, 11, 22 };
++ static char cfg5[] = { 13, 2, 7, 9, 12, 19, 5, 1, 6, 3, 4,
++ 8, 10, 0, 0, 0, 21, 22, 18, 17, 11, 20 };
++ static char cfg6[] = { 3, 10, 7, 13, 9, 11, 1, 2, 4, 6, 8,
++ 5, 12, 0, 0, 0, 20, 1, 0, 21, 22, 17 };
++ static char cfg7[] = { 3, 2, 4, 7, 9, 1, 17, 12, 18, 14, 13,
++ 8, 15, 6, 10, 5, 19, 22, 16, 21, 20, 11 };
++
++ unsigned int fuse, val;
++
++ // read SID info @ 0x228
++ fuse = (readl(0x3002228) >> 8) & 0x4;
++ printf("ddr_efuse_type: 0x%x\n", fuse);
++
++ if ((para->dram_tpr13 >> 18) & 0x3) {
++ memcpy_self(cfg0, cfg7, 22);
++ }
++ else {
++ switch (fuse) {
++ case 8: memcpy_self(cfg0, cfg2, 22); break;
++ case 9: memcpy_self(cfg0, cfg3, 22); break;
++ case 10: memcpy_self(cfg0, cfg5, 22); break;
++ case 11: memcpy_self(cfg0, cfg4, 22); break;
++ default:
++ case 12: memcpy_self(cfg0, cfg1, 22); break;
++ case 13:
++ case 14: break;
++ }
++ }
++ if (para->dram_type == 2) {
++ if (fuse == 15) return;
++ memcpy_self(cfg0, cfg6, 22);
++ }
++ if ( para->dram_type == 2 || para->dram_type == 3) {
++
++ val = (cfg0[ 4] << 25) | (cfg0[ 3] << 20) | (cfg0[ 2] << 15) |
++ (cfg0[ 1] << 10) | (cfg0[ 0] << 5);
++ writel(0x3102500, val);
++
++ val = (cfg0[10] << 25) | (cfg0[ 9] << 20) | (cfg0[ 8] << 15) |
++ (cfg0[ 7] << 10) | (cfg0[ 6] << 5) | cfg0[ 5];
++ writel(0x3102504, val);
++
++ val = (cfg0[15] << 20) | (cfg0[14] << 15) |
++ (cfg0[13] << 10) | (cfg0[12] << 5) | cfg0[11];
++ writel(0x3102508, val);
++
++ val = (cfg0[21] << 25) | (cfg0[20] << 20) | (cfg0[19] << 15) |
++ (cfg0[18] << 10) | (cfg0[17] << 5) | cfg0[16];
++ writel(0x310250c, val);
++
++ val = (cfg0[ 4] << 25) | (cfg0 [3] << 20) | (cfg0[2] << 15) |
++ (cfg0[ 1] << 10) | (cfg0 [0] << 5) | 1;
++ writel(0x3102500, val);
++ }
++}
++
++// Init the controller channel. The key part is placing commands in the main
++// command register (PIR, 0x3103000) and checking command status (PGSR0, 0x3103010).
++//
++unsigned int mctl_channel_init(unsigned int ch_index, struct dram_para_t *para)
++{
++ unsigned int val, dqs_gating_mode;
++
++ dqs_gating_mode = (para->dram_tpr13 >> 2) & 0x3;
++
++ // set DDR clock to half of CPU clock
++ val = readl(0x310200c) & 0xfffff000;
++ val |= (para->dram_clk >> 1 ) - 1;
++ writel(0x310200c, val);
++
++ // MRCTRL0 nibble 3 undocumented
++ val = readl(0x3103108) & 0xfffff0ff;
++ val |= 0x300;
++ writel(0x3103108, val);
++
++ // DX0GCR0
++ val = readl(0x3103344) & 0xffffffcf;
++ val |= ((~para->dram_odt_en) << 5) & 0x20;
++ if (para->dram_clk > 672) {
++ val &= 0xffff09f1;
++ val |= 0x00000400;
++ }
++ else {
++ val &= 0xffff0ff1;
++ }
++ writel(0x3103344, val);
++
++ // DX1GCR0
++ val = readl(0x31033c4) & 0xffffffcf;
++ val |= ((~para->dram_odt_en) << 5) & 0x20;
++ if (para->dram_clk > 672) {
++ val &= 0xffff09f1;
++ val |= 0x00000400;
++ }
++ else {
++ val &= 0xffff0ff1;
++ }
++ writel(0x31033c4, val);
++
++ // 0x3103208 undocumented
++ val = readl(0x3103208);
++ val |= 0x2;
++ writel(0x3103208, val);
++
++ eye_delay_compensation(para);
++
++ //set PLL SSCG ?
++ //
++ val = readl(0x3103108);
++ if (dqs_gating_mode == 1) {
++
++ val &= ~(0xc0);
++ writel(0x3103108, val);
++
++ val = readl(0x31030bc);
++ val &= 0xfffffef8;
++ writel(0x31030bc, val);
++ }
++ else if (dqs_gating_mode == 2) {
++
++ val &= ~(0xc0);
++ val |= 0x80;
++ writel(0x3103108, val);
++
++ val = readl(0x31030bc);
++ val &= 0xfffffef8;
++ val |= ((para->dram_tpr13 >> 16) & 0x1f) - 2;
++ val |= 0x100;
++ writel(0x31030bc, val);
++
++ val = readl(0x310311c) & 0x7fffffff;
++ val |= 0x08000000;
++ writel(0x310311c, val);
++ }
++ else {
++ val &= ~(0x40);
++ writel(0x3103108, val);
++
++ udelay(10);
++
++ val = readl(0x3103108);
++ val |= 0xc0;
++ writel(0x3103108, val);
++ }
++
++ if (para->dram_type == 6 || para->dram_type == 7) {
++ val = readl(0x310311c);
++ if (dqs_gating_mode == 1) {
++ val &= 0xf7ffff3f;
++ val |= 0x80000000;
++ }
++ else {
++ val &= 0x88ffffff;
++ val |= 0x22000000;
++ }
++ writel(0x310311c, val);
++ }
++
++ val = readl(0x31030c0);
++ val &= 0xf0000000;
++ val |= (para->dram_para2 & (1 << 12)) ? 0x03000001 : 0x01000007; // 0x01003087 XXX
++ writel(0x31030c0, val);
++
++ if (readl(0x70005d4) & (1 << 16)) {
++ val = readl(0x7010250);
++ val &= 0xfffffffd;
++ writel(0x7010250, val);
++
++ udelay(10);
++ }
++
++ // Set ZQ config
++ val = readl(0x3103140) & 0xfc000000;
++ val |= para->dram_zq & 0x00ffffff;
++ val |= 0x02000000;
++ writel(0x3103140, val);
++
++ // Initialise DRAM controller
++ if (dqs_gating_mode == 1) {
++ writel(0x3103000, 0x52); // prep PHY reset + PLL init + z-cal
++ writel(0x3103000, 0x53); // Go
++
++ while ((readl(0x3103010) & 0x1) == 0) {;} // wait for IDONE
++ udelay(10);
++
++ // 0x520 = prep DQS gating + DRAM init + d-cal
++ val = (para->dram_type == 3) ? 0x5a0 // + DRAM reset
++ : 0x520;
++ }
++ else {
++ if ((readl(0x70005d4) & (1 << 16)) == 0) {
++ // prep DRAM init + PHY reset + d-cal + PLL init + z-cal
++ val = (para->dram_type == 3) ? 0x1f2 // + DRAM reset
++ : 0x172;
++ }
++ else {
++ // prep PHY reset + d-cal + z-cal
++ val = 0x62;
++ }
++ }
++
++ writel(0x3103000, val); // Prep
++ val |= 1;
++ writel(0x3103000, val); // Go
++
++ udelay(10);
++ while ((readl(0x3103010) & 0x1) == 0) {;} // wait for IDONE
++
++ if (readl(0x70005d4) & (1 << 16)) {
++
++ val = readl(0x310310c);
++ val &= 0xf9ffffff;
++ val |= 0x04000000;
++ writel(0x310310c, val);
++
++ udelay(10);
++
++ val = readl(0x3103004);
++ val |= 0x1;
++ writel(0x3103004, val);
++
++ while ((readl(0x3103018) & 0x7) != 0x3) {;}
++
++ val = readl(0x7010250);
++ val &= 0xfffffffe;
++ writel(0x7010250, val);
++
++ udelay(10);
++
++ val = readl(0x3103004);
++ val &= 0xfffffffe;
++ writel(0x3103004, val);
++
++ while ((readl(0x3103018) & 0x7) != 0x1) {;}
++
++ udelay(15);
++
++ if (dqs_gating_mode == 1) {
++
++ val = readl(0x3103108);
++ val &= 0xffffff3f;
++ writel(0x3103108, val);
++
++ val = readl(0x310310c);
++ val &= 0xf9ffffff;
++ val |= 0x02000000;
++ writel(0x310310c, val);
++
++ udelay(1);
++ writel(0x3103000, 0x401);
++
++ while ((readl(0x3103010) & 0x1) == 0) {;}
++ }
++ }
++
++ // Check for training error
++ val = readl(0x3103010);
++ if (((val >> 20) & 0xff) && (val & 0x100000)) {
++ printf("ZQ calibration error, check external 240 ohm resistor.\n");
++ return 0;
++ }
++
++ // STATR = Zynq STAT? Wait for status 'normal'?
++ while ((readl(0x3103018) & 0x1) == 0) {;}
++
++ val = readl(0x310308c);
++ val |= 0x80000000;
++ writel(0x310308c, val);
++
++ udelay(10);
++
++ val = readl(0x310308c);
++ val &= 0x7fffffff;
++ writel(0x310308c, val);
++
++ udelay(10);
++
++ val = readl(0x3102014);
++ val |= 0x80000000;
++ writel(0x3102014, val);
++
++ udelay(10);
++
++ val = readl(0x310310c);
++ val &= 0xf9ffffff;
++ writel(0x310310c, val);
++
++ if (dqs_gating_mode == 1) {
++ val = readl(0x310311c);
++ val &= 0xffffff3f;
++ val |= 0x00000040;
++ writel(0x310311c, val);
++ }
++ return 1;
++}
++
++// The below routine reads the dram config registers and extracts
++// the number of address bits in each rank available. It then calculates
++// total memory size in MB.
++//
++int DRAMC_get_dram_size(void)
++{
++ unsigned int rval, temp, size0, size1;
++
++ rval = readl(0x3102000); // MC_WORK_MODE0
++
++ temp = (rval>>8) & 0xf; // page size - 3
++ temp += (rval>>4) & 0xf; // row width - 1
++ temp += (rval>>2) & 0x3; // bank count - 2
++ temp -= 14; // 1MB = 20 bits, minus above 6 = 14
++ size0 = 1 << temp;
++
++ temp = rval & 0x3; // rank count = 0? -> done
++ if (temp == 0) {
++ return size0;
++ }
++
++ rval = readl(0x3102004); // MC_WORK_MODE1
++
++ temp = rval & 0x3;
++ if (temp == 0) { // two identical ranks
++ return 2 * size0;
++ }
++
++ temp = (rval>>8) & 0xf; // page size - 3
++ temp += (rval>>4) & 0xf; // row width - 1
++ temp += (rval>>2) & 0x3; // bank number - 2
++ temp -= 14; // 1MB = 20 bits, minus above 6 = 14
++ size1 = 1 << temp;
++
++ return size0 + size1; // add size of each rank
++}
++
++// The below routine reads the command status register to extract
++// DQ width and rank count. This follows the DQS training command in
++// channel_init. If error bit 22 is reset, we have two ranks and full DQ.
++// If there was an error, figure out whether it was half DQ, single rank,
++// or both. Set bit 12 and 0 in dram_para2 with the results.
++//
++int dqs_gate_detect(struct dram_para_t *para)
++{
++ unsigned int rval, dx0, dx1;
++
++ if (readl(0x3103010) & (1 << 22)) {
++
++ dx0 = (readl(0x3103348) >> 24) & 0x3;
++ dx1 = (readl(0x31033c8) >> 24) & 0x3;
++
++ if (dx0 == 2) {
++ rval = para->dram_para2;
++ rval &= 0xffff0ff0;
++ if (dx0 != dx1) {
++ rval |= 0x1;
++ para->dram_para2 = rval;
++ printf("[AUTO DEBUG] single rank and half DQ!\n");
++ return 1;
++ }
++ para->dram_para2 = rval;
++ printf("[AUTO DEBUG] single rank and full DQ!\n");
++ return 1;
++ }
++ else if (dx0 == 0) {
++ rval = para->dram_para2;
++ rval &= 0xfffffff0;
++ rval |= 0x00001001;
++ para->dram_para2 = rval;
++ printf("[AUTO DEBUG] dual rank and half DQ!\n");
++ return 1;
++ }
++ else {
++ if (para->dram_tpr13 & (1 << 29)) {
++ printf("DX0 state:%d\n", dx0);
++ printf("DX1 state:%d\n", dx1);
++ }
++ return 0;
++ }
++ }
++ else {
++ rval = para->dram_para2;
++ rval &= 0xfffffff0;
++ rval |= 0x00001000;
++ para->dram_para2 = rval;
++ printf("[AUTO DEBUG] two rank and full DQ!\n");
++ return 1;
++ }
++}
++
++
++#define SDRAM_BASE ((unsigned int *)0x40000000)
++#define uint unsigned int
++
++int dramc_simple_wr_test(uint mem_mb, int len)
++{
++ unsigned int offs = (mem_mb >> 1) << 18; // half of memory size
++ unsigned int patt1 = 0x01234567;
++ unsigned int patt2 = 0xfedcba98;
++ unsigned int *addr, v1, v2, i;
++
++ addr = SDRAM_BASE;
++ for (i = 0; i != len; i++, addr++) {
++ writel(addr, patt1 + i);
++ writel(addr + offs, patt2 + i);
++ }
++
++ addr = SDRAM_BASE;
++ for (i = 0; i != len; i++) {
++ v1 = readl(addr+i);
++ v2 = patt1 + i;
++ if (v1 != v2) {
++ printf("DRAM simple test FAIL.\n");
++ printf("%x != %x at address %p\n", v1, v2, addr+i);
++ return 1;
++ }
++ v1 = readl(addr+offs+i);
++ v2 = patt2 + i;
++ if (v1 != v2) {
++ printf("DRAM simple test FAIL.\n");
++ printf("%x != %x at address %p\n", v1, v2, addr+offs+i);
++ return 1;
++ }
++ }
++ printf("DRAM simple test OK.\n");
++ return 0;
++}
++
++// Set the Vref mode for the controller
++//
++void mctl_vrefzq_init(struct dram_para_t *para)
++{
++ unsigned int val;
++
++ if ((para->dram_tpr13 & (1 << 17)) == 0) {
++ val = readl(0x3103110) & 0x80808080; // IOCVR0
++ val |= para->dram_tpr5;
++ writel(0x3103110, val);
++
++ if ((para->dram_tpr13 & (1 << 16)) == 0) {
++ val = readl(0x3103114) & 0xffffff80; // IOCVR1
++ val |= para->dram_tpr6 & 0x7f;
++ writel(0x3103114, val);
++ }
++ }
++}
++
++// Perform an init of the controller. This is actually done 3 times. The first
++// time to establish the number of ranks and DQ width. The second time to
++// establish the actual ram size. The third time is final one, with the final
++// settings.
++//
++int mctl_core_init(struct dram_para_t *para)
++{
++ mctl_sys_init(para);
++ mctl_vrefzq_init(para);
++ mctl_com_init(para);
++ mctl_phy_ac_remapping(para);
++ auto_set_timing_para(para);
++ return mctl_channel_init(0, para);
++}
++
++
++#define RAM_BASE (0x40000000)
++
++// Autoscan sizes a dram device by cycling through address lines and figuring
++// out if it is connected to a real address line, or if the address is a mirror.
++// First the column and bank bit allocations are set to low values (2 and 9 address
++// lines. Then a maximum allocation (16 lines) is set for rows and this is tested.
++// Next the BA2 line is checked. This seems to be placed above the column, BA0-1 and
++// row addresses. Finally, the column address is allocated 13 lines and these are
++// tested. The results are placed in dram_para1 and dram_para2.
++//
++int auto_scan_dram_size(struct dram_para_t *para) // s7
++{
++ unsigned int rval, i, j, rank, maxrank, offs, mc_work_mode;
++ unsigned int chk, ptr, shft, banks;
++
++ if (mctl_core_init(para) == 0) {
++ printf("[ERROR DEBUG] DRAM initialisation error : 0!\n");
++ return 0;
++ }
++
++ maxrank = (para->dram_para2 & 0xf000) ? 2 : 1;
++ mc_work_mode = 0x3102000;
++ offs = 0;
++
++ // write test pattern
++ for (i = 0, ptr = RAM_BASE; i < 64; i++, ptr += 4) {
++ writel(ptr, (i & 1) ? ptr : ~ptr);
++ }
++
++ for (rank = 0; rank < maxrank; ) {
++
++ // Set row mode
++ rval = readl(mc_work_mode);
++ rval &= 0xfffff0f3;
++ rval |= 0x000006f0;
++ writel(mc_work_mode, rval);
++ while (readl(mc_work_mode) != rval);
++
++ // Scan per address line, until address wraps (i.e. see shadow)
++ for(i = 11; i < 17; i++) {
++ chk = RAM_BASE + (1 << (i + 11));
++ ptr = RAM_BASE;
++ for (j = 0; j < 64; j++) {
++ if (readl(chk) != ((j & 1) ? ptr : ~ptr))
++ goto out1;
++ ptr += 4;
++ chk += 4;
++ }
++ break;
++ out1: ;
++ }
++ if (i > 16) i = 16;
++ printf("[AUTO DEBUG] rank %d row = %d\n", rank, i);
++
++ // Store rows in para 1
++ shft = 4 + offs;
++ rval = para->dram_para1;
++ rval &= ~(0xff << shft);
++ rval |= i << shft;
++ para->dram_para1 = rval;
++
++ if (rank == 1) {
++ // Set bank mode for rank0
++ rval = readl(0x3102000);
++ rval &= 0xfffff003;
++ rval |= 0x000006a4;
++ writel(0x3102000, rval);
++ }
++
++ // Set bank mode for current rank
++ rval = readl(mc_work_mode);
++ rval &= 0xfffff003;
++ rval |= 0x000006a4;
++ writel(mc_work_mode, rval);
++ while (readl(mc_work_mode) != rval);
++
++ // Test if bit A23 is BA2 or mirror XXX A22?
++ chk = RAM_BASE + (1 << 22);
++ ptr = RAM_BASE;
++ for (i = 0, j = 0; i < 64; i++) {
++ if (readl(chk) != ((i & 1) ? ptr : ~ptr)) {
++ j = 1;
++ break;
++ }
++ ptr += 4;
++ chk += 4;
++ }
++ banks = (j + 1) << 2; // 4 or 8
++ printf("[AUTO DEBUG] rank %d bank = %d\n", rank, banks);
++
++ // Store banks in para 1
++ shft = 12 + offs;
++ rval = para->dram_para1;
++ rval &= ~(0xf << shft);
++ rval |= j << shft;
++ para->dram_para1 = rval;
++
++ if (rank == 1) {
++ // Set page mode for rank0
++ rval = readl(0x3102000);
++ rval &= 0xfffff003;
++ rval |= 0x00000aa0;
++ writel(0x3102000, rval);
++ }
++
++ // Set page mode for current rank
++ rval = readl(mc_work_mode);
++ rval &= 0xfffff003;
++ rval |= 0x00000aa0;
++ writel(mc_work_mode, rval);
++ while (readl(mc_work_mode) != rval);
++
++ // Scan per address line, until address wraps (i.e. see shadow)
++ for(i = 9; i < 14; i++) {
++ chk = RAM_BASE + (1 << i);
++ ptr = RAM_BASE;
++ for (j = 0; j < 64; j++) {
++ if (readl(chk) != ((j & 1) ? ptr : ~ptr))
++ goto out2;
++ ptr += 4;
++ chk += 4;
++ }
++ break;
++ out2:;
++ }
++ if (i > 13) i = 13;
++ int pgsize = (i==9) ? 0 : (1 << (i-10));
++ printf("[AUTO DEBUG] rank %d page size = %d KB\n", rank, pgsize);
++
++ // Store page size
++ shft = offs;
++ rval = para->dram_para1;
++ rval &= ~(0xf << shft);
++ rval |= pgsize << shft;
++ para->dram_para1 = rval;
++
++ // Move to next rank
++ rank++;
++ if (rank != maxrank) {
++ if (rank == 1) {
++ rval = readl(0x3202000); // MC_WORK_MODE
++ rval &= 0xfffff003;
++ rval |= 0x000006f0;
++ writel(0x3202000, rval);
++
++ rval = readl(0x3202004); // MC_WORK_MODE2
++ rval &= 0xfffff003;
++ rval |= 0x000006f0;
++ writel(0x3202004, rval);
++ }
++ offs += 16; // store rank1 config in upper half of para1
++ mc_work_mode += 4; // move to MC_WORK_MODE2
++ }
++ }
++ if (maxrank == 2) {
++ para->dram_para2 &= 0xfffff0ff;
++ // note: rval is equal to para->dram_para1 here
++ if ((rval & 0xffff) == ((rval >> 16) & 0xffff)) {
++ printf("rank1 config same as rank0\n");
++ }
++ else {
++ para->dram_para2 |= 0x00000100;
++ printf("rank1 config different from rank0\n");
++ }
++ }
++ return 1;
++}
++
++// This routine sets up parameters with dqs_gating_mode equal to 1 and two
++// ranks enabled. It then configures the core and tests for 1 or 2 ranks and
++// full or half DQ width. it then resets the parameters to the original values.
++// dram_para2 is updated with the rank & width findings.
++//
++int auto_scan_dram_rank_width(struct dram_para_t *para)
++{
++ unsigned int s1 = para->dram_tpr13;
++ unsigned int s2 = para->dram_para1;
++ unsigned int v;
++
++ para->dram_para1 = 0x00b000b0;
++ v = (para->dram_para2 & 0xfffffff0) | 0x1000;
++ para->dram_para2 = v;
++
++ v = (s1 & 0xfffffff7) | 0x5; // set DQS probe mode
++ para->dram_tpr13 = v;
++
++ mctl_core_init(para);
++ if (readl(0x3103010) & (1 << 20)) {
++ return 0;
++ }
++ if (dqs_gate_detect(para) == 0) {
++ return 0;
++ }
++
++ para->dram_tpr13 = s1;
++ para->dram_para1 = s2;
++ return 1;
++}
++
++// This routine determines the sdram topology. It first establishes the number
++// of ranks and the DQ width. Then it scans the sdram address lines to establish
++// the size of each rank. It then updates dram_tpr13 to reflect that the sizes
++// are now known: a re-init will not repeat the autoscan.
++//
++int auto_scan_dram_config(struct dram_para_t *para)
++{
++ if (((para->dram_tpr13 & (1 << 14)) == 0) &&
++ (auto_scan_dram_rank_width(para) == 0))
++ {
++ printf("[ERROR DEBUG] auto scan dram rank & width failed !\n");
++ return 0;
++ }
++ if (((para->dram_tpr13 & (1 << 0)) == 0) &&
++ (auto_scan_dram_size(para) == 0 ))
++ {
++ printf("[ERROR DEBUG] auto scan dram size failed !\n");
++ return 0;
++ }
++ if ((para->dram_tpr13 & (1 << 15)) == 0) {
++ para->dram_tpr13 |= 0x6003;
++ }
++ return 1;
++}
++
++
++signed int init_DRAM(int type, struct dram_para_t *para) // s0
++{
++ int rc, mem_size;
++
++ // Test ZQ status
++ if (para->dram_tpr13 & (1 << 16)) {
++ printf("DRAM only have internal ZQ!!\n");
++ writel(0x3000160, readl(0x3000160) | 0x100);
++ writel(0x3000168, 0);
++ udelay(10);
++ }
++ else {
++ writel(0x7010254, 0);
++ writel(0x3000160, readl(0x3000160) & ~0x003);
++ udelay(10);
++ writel(0x3000160, readl(0x3000160) & ~0x108);
++ udelay(10);
++ writel(0x3000160, readl(0x3000160) | 0x001);
++ udelay(20);
++ printf("ZQ value = 0x%x***********\n", readl(0x3000172));
++ }
++
++ // Set voltage
++ dram_vol_set(para);
++
++ // Set SDRAM controller auto config
++ if ( (para->dram_tpr13 & 0x1)==0 ) {
++ if ( auto_scan_dram_config(para)==0 ) {
++ return 0;
++ }
++ }
++
++ // Print header message (too late)
++ printf("DRAM BOOT DRIVE INFO: %s\n", "V0.24");
++ printf("DRAM CLK = %d MHz\n", para->dram_clk);
++ printf("DRAM Type = %d (2:DDR2,3:DDR3)\n", para->dram_type);
++ if ( (para->dram_odt_en & 0x1) == 0 ) {
++ printf("DRAMC read ODT off.\n");
++ }
++ else {
++ printf("DRAMC ZQ value: 0x%x\n", para->dram_zq);
++ }
++
++ // report ODT
++ rc = para->dram_mr1;
++ if ( (rc & 0x44)==0 ) {
++ printf("DRAM ODT off.\n");
++ }
++ else {
++ printf("DRAM ODT value: 0x%x.\n", rc);
++ }
++
++ // Init core, final run
++ if ( mctl_core_init(para)==0 ) {
++ printf("DRAM initialisation error : 1 !\n");
++ return 0;
++ }
++
++ // Get sdram size
++ rc = para->dram_para2;
++ if ( rc<0 ) {
++ rc = (rc & 0x7fff0000U) >> 16;
++ }
++ else {
++ rc = DRAMC_get_dram_size();
++ printf("DRAM SIZE =%d M\n", rc);
++ para->dram_para2 = (para->dram_para2 & 0xffffu) | rc << 16;
++ }
++ mem_size = rc;
++
++ // Purpose ??
++ if ( para->dram_tpr13 & (1 << 30) ) {
++ rc = readl(¶->dram_tpr8);
++ if ( rc==0 ) {
++ rc = 0x10000200;
++ }
++ writel(0x31030a0, rc);
++ writel(0x310309c, 0x40a);
++ writel(0x3103004, readl(0x3103004) | 1 );
++ printf("Enable Auto SR");
++ }
++ else {
++ writel(0x31030a0, readl(0x31030a0) & 0xffff0000);
++ writel(0x3103004, readl(0x3103004) & (~0x1) );
++ }
++
++ // Pupose ??
++ rc = readl(0x3103100) & ~(0xf000);
++ if ( (para->dram_tpr13 & 0x200)==0 ) {
++ if ( para->dram_type != 6 ) {
++ writel(0x3103100, rc);
++ }
++ }
++ else {
++ writel(0x3103100, rc | 0x5000);
++ }
++
++ writel(0x3103140, readl(0x3103140) | (1 << 31));
++ if (para->dram_tpr13 & (1 << 8)) {
++ writel(0x31030b8, readl(0x3103140) | 0x300);
++ }
++
++ rc = readl(0x3103108);
++ if (para->dram_tpr13 & (1 << 16)) {
++ rc &= 0xffffdfff;
++ }
++ else {
++ rc |= 0x00002000;
++ }
++ writel(0x3103108, rc);
++
++
++ // Purpose ??
++ if (para->dram_type == 7) {
++ rc = readl(0x310307c) & 0xfff0ffff;
++ rc |= 0x0001000;
++ writel(0x310307c, rc);
++ }
++
++ dram_enable_all_master();
++ //if (dramc_simple_wr_test(mem_size, 64)) return 0;
++ if (para->dram_tpr13 & (1 << 28)) {
++ rc = readl(0x70005d4);
++ if ( (rc & (1 << 16)) || dramc_simple_wr_test(mem_size, 4096) ) {
++ return 0;
++ }
++ }
++
++ return mem_size;
++}
++
++struct sunxi_ram_priv {
++ size_t size;
++};
++
++static struct dram_para_t dram_para = {
++ 0x00000318,
++ 0x00000003,
++ 0x007b7bfb,
++ 0x00000001,
++ 0x000010d2,
++ 0x00000000,
++ 0x00001c70,
++ 0x00000042,
++ 0x00000018,
++ 0x00000000,
++ 0x004a2195,
++ 0x02423190,
++ 0x0008b061,
++ 0xb4787896,
++ 0x00000000,
++ 0x48484848,
++ 0x00000048,
++ 0x1620121e,
++ 0x00000000,
++ 0x00000000,
++ 0x00000000,
++ 0x00870000,
++ 0x00000024,
++ 0x34050100,
++};
++
++static int sunxi_ram_probe(struct udevice *dev)
++{
++ struct sunxi_ram_priv *priv = dev_get_priv(dev);
++ int ret;
++
++ printf("%s: %s: probing\n", __func__, dev->name);
++
++ ret = init_DRAM(0, &dram_para);
++ if (ret <= 0) {
++ printf("DRAM init failed: %d\n", ret);
++ return ret;
++ }
++
++ priv->size = ret * 1024 * 1024;
++
++ return 0;
++}
++
++static int sunxi_ram_get_info(struct udevice *dev, struct ram_info *info)
++{
++ struct sunxi_ram_priv *priv = dev_get_priv(dev);
++
++ printf("%s: %s: getting info\n", __func__, dev->name);
++
++ info->base = CONFIG_SYS_SDRAM_BASE;
++ info->size = priv->size;
++
++ return 0;
++}
++
++static struct ram_ops sunxi_ram_ops = {
++ .get_info = sunxi_ram_get_info,
++};
++
++static const struct udevice_id sunxi_ram_ids[] = {
++ { .compatible = "allwinner,sun20i-d1-mbus" },
++ { }
++};
++
++U_BOOT_DRIVER(sunxi_ram) = {
++ .name = "sunxi_ram",
++ .id = UCLASS_RAM,
++ .of_match = sunxi_ram_ids,
++ .ops = &sunxi_ram_ops,
++ .probe = sunxi_ram_probe,
++ .priv_auto = sizeof(struct sunxi_ram_priv),
++};
++
++#endif
+--- /dev/null
++++ b/drivers/ram/sunxi/sdram.h
+@@ -0,0 +1,46 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++/*
++ * dram_para1 bits:
++ * 16-19 = page size
++ * 20-27 = row count
++ * 28 = banks 4 or 8
++ *
++ * dram_para2 bits:
++ * 0 = DQ width
++ * 4 = CS1 control
++ * 8-11 = rank flags? bit 8 = ranks differ in config
++ * 12-13 = rank
++ */
++
++/* MC_WORK_MODE bits
++ * 0- 1 = ranks code
++ * 2- 3 = banks, log2 - 2 2 3 2
++ * 4- 7 = row width, log2 - 1 16 11 11
++ * 8-11 = page size, log2 - 3 9 9 13
++ * 12-15 = DQ width (or 12-14?)
++ * 16-18 = dram type (2=DDR2, 3=DDR3, 6=LPDDR2, 7=LPDDR3)
++ * 19 = 2T or 1T
++ * 23-24 = ranks code (again?)
++ */
++
++#define DRAM_MR0 ((void*)0x3103030)
++#define DRAM_MR1 ((void*)0x3103034)
++#define DRAM_MR2 ((void*)0x3103038)
++#define DRAM_MR3 ((void*)0x310303c)
++
++#define DRAMTMG0 ((void*)0x3103058)
++#define DRAMTMG1 ((void*)0x310305c)
++#define DRAMTMG2 ((void*)0x3103060)
++#define DRAMTMG3 ((void*)0x3103064)
++#define DRAMTMG4 ((void*)0x3103068)
++#define DRAMTMG5 ((void*)0x310306c)
++#define DRAMTMG6 ((void*)0x3103070)
++#define DRAMTMG7 ((void*)0x3103074)
++#define DRAMTMG8 ((void*)0x3103078)
++
++#define PITMG0 ((void*)0x3103080)
++#define PTR3 ((void*)0x3103050)
++#define PTR4 ((void*)0x3103054)
++#define RFSHTMG ((void*)0x3103090)
++#define RFSHCTL1 ((void*)0x3103094)
--- /dev/null
+From 46f73ce33478734dabd5a93d425f7148b60198e1 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Wed, 8 Sep 2021 21:31:06 -0500
+Subject: [PATCH 84/90] spi: sunxi: Hack up the driver for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/spi/spi-sunxi.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-sunxi.c
++++ b/drivers/spi/spi-sunxi.c
+@@ -30,6 +30,7 @@
+ #include <asm/global_data.h>
+ #include <dm/device_compat.h>
+ #include <linux/bitops.h>
++#include <linux/log2.h>
+
+ #include <asm/bitops.h>
+ #include <asm/io.h>
+@@ -85,7 +86,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ #define SUN4I_SPI_DEFAULT_RATE 1000000
+ #define SUN4I_SPI_TIMEOUT_MS 1000
+
+-#define SPI_REG(priv, reg) ((priv)->base + \
++#define SPI_REG(priv, reg) (void *)((priv)->base + \
+ (priv)->variant->regs[reg])
+ #define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
+ #define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
--- /dev/null
+From 4993c31d314d5c7ebad1d08e3e3f79694dca8738 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 11 Sep 2021 23:12:06 -0500
+Subject: [PATCH 85/90] spi: sunxi: Add support for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ drivers/spi/spi-sunxi.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/spi/spi-sunxi.c
++++ b/drivers/spi/spi-sunxi.c
+@@ -558,6 +558,10 @@ static const struct udevice_id sun4i_spi
+ .compatible = "allwinner,sun8i-h3-spi",
+ .data = (ulong)&sun8i_h3_spi_variant,
+ },
++ {
++ .compatible = "allwinner,sun50i-r329-spi",
++ .data = (ulong)&sun8i_h3_spi_variant,
++ },
+ { /* sentinel */ }
+ };
+
--- /dev/null
+From eb0cf5922cf0656a7e9f96d6b83397469a26825a Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 11 Sep 2021 10:12:24 -0500
+Subject: [PATCH 86/90] usb: musb-new: Hack up the driver for the D1
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/include/asm/bitops.h | 1 +
+ arch/riscv/include/asm/io.h | 2 +-
+ arch/riscv/include/asm/processor.h | 2 ++
+ drivers/usb/musb-new/musb_io.h | 2 +-
+ drivers/usb/musb-new/sunxi.c | 6 ++++--
+ 5 files changed, 9 insertions(+), 4 deletions(-)
+
+--- a/arch/riscv/include/asm/bitops.h
++++ b/arch/riscv/include/asm/bitops.h
+@@ -78,6 +78,7 @@ static inline int __test_and_set_bit(int
+ return retval;
+ }
+
++#define test_and_clear_bit __test_and_clear_bit
+ static inline int __test_and_clear_bit(int nr, void *addr)
+ {
+ int mask, retval;
+--- a/arch/riscv/include/asm/io.h
++++ b/arch/riscv/include/asm/io.h
+@@ -218,6 +218,7 @@ static inline u64 readq(const volatile v
+ #define insb(p, d, l) readsb(__io(p), d, l)
+ #define insw(p, d, l) readsw(__io(p), d, l)
+ #define insl(p, d, l) readsl(__io(p), d, l)
++#endif
+
+ static inline void readsb(unsigned int *addr, void *data, int bytelen)
+ {
+@@ -308,7 +309,6 @@ static inline void writesl(unsigned int
+ longlen--;
+ }
+ }
+-#endif
+
+ #define outb_p(val, port) outb((val), (port))
+ #define outw_p(val, port) outw((val), (port))
+--- a/arch/riscv/include/asm/processor.h
++++ b/arch/riscv/include/asm/processor.h
+@@ -23,4 +23,6 @@
+ * no one uses the macros defined in this head file.
+ **************************************************************/
+
++#define cpu_relax() barrier()
++
+ #endif /* __ASM_RISCV_PROCESSOR_H */
+--- a/drivers/usb/musb-new/musb_io.h
++++ b/drivers/usb/musb-new/musb_io.h
+@@ -23,7 +23,7 @@
+ #if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
+ && !defined(CONFIG_PPC32) \
+ && !defined(CONFIG_PPC64) && !defined(CONFIG_MIPS) \
+- && !defined(CONFIG_M68K)
++ && !defined(CONFIG_M68K) && !defined(CONFIG_RISCV)
+ static inline void readsl(const void __iomem *addr, void *buf, int len)
+ { insl((unsigned long)addr, buf, len); }
+ static inline void readsw(const void __iomem *addr, void *buf, int len)
+--- a/drivers/usb/musb-new/sunxi.c
++++ b/drivers/usb/musb-new/sunxi.c
+@@ -23,8 +23,8 @@
+ #include <malloc.h>
+ #include <phy-sun4i-usb.h>
+ #include <reset.h>
+-#include <asm/arch/cpu.h>
+-#include <asm/arch/clock.h>
++//#include <asm/arch/cpu.h>
++//#include <asm/arch/clock.h>
+ #include <dm/device_compat.h>
+ #include <dm/lists.h>
+ #include <dm/root.h>
+@@ -174,6 +174,7 @@ static void USBC_ForceVbusValidToHigh(__
+
+ static void USBC_ConfigFIFO_Base(void)
+ {
++#if 0
+ u32 reg_value;
+
+ /* config usb fifo, 8kb mode */
+@@ -181,6 +182,7 @@ static void USBC_ConfigFIFO_Base(void)
+ reg_value &= ~(0x03 << 0);
+ reg_value |= BIT(0);
+ writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
++#endif
+ }
+
+ /******************************************************************************
--- /dev/null
+From e3152c690732fb141500379f32fbe2203fa47059 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sat, 6 Aug 2022 00:48:38 -0500
+Subject: [PATCH 87/90] sunxi: Add temporary RISC-V version of board code
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ board/sunxi/Makefile | 3 +-
+ board/sunxi/board-riscv.c | 687 +++++++++++++++++++++++++++++++++
+ include/configs/sunxi-common.h | 1 -
+ 3 files changed, 689 insertions(+), 2 deletions(-)
+ create mode 100644 board/sunxi/board-riscv.c
+
+--- a/board/sunxi/Makefile
++++ b/board/sunxi/Makefile
+@@ -6,7 +6,8 @@
+ #
+ # (C) Copyright 2000-2003
+ # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+-obj-y += board.o
++obj-$(CONFIG_ARM) += board.o
++obj-$(CONFIG_RISCV) += board-riscv.o
+ obj-$(CONFIG_SUN7I_GMAC) += gmac.o
+ obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o
+ obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o
+--- /dev/null
++++ b/board/sunxi/board-riscv.c
+@@ -0,0 +1,687 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
++ * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
++ *
++ * (C) Copyright 2007-2011
++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
++ * Tom Cubie <tangliang@allwinnertech.com>
++ *
++ * Some board init for the Allwinner A10-evb board.
++ */
++
++#include <dm.h>
++#include <cpu.h>
++#include <env.h>
++#include <env_internal.h>
++#include <fdt_support.h>
++#include <generic-phy.h>
++#include <image.h>
++#include <init.h>
++#include <net.h>
++#include <phy-sun4i-usb.h>
++#include <ram.h>
++#include <remoteproc.h>
++#include <spl.h>
++#include <status_led.h>
++#include <sunxi_image.h>
++#include <u-boot/crc.h>
++#include <asm/csr.h>
++#include <asm/global_data.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_RISCV
++int board_init(void)
++{
++ /* https://lore.kernel.org/u-boot/31587574-4cd1-02da-9761-0134ac82b94b@sholland.org/ */
++ return cpu_probe_all();
++}
++
++int sunxi_get_sid(unsigned int *sid)
++{
++ return -ENODEV;
++}
++
++#define SPL_ADDR CONFIG_SUNXI_SRAM_ADDRESS
++
++/* The low 8-bits of the 'boot_media' field in the SPL header */
++#define SUNXI_BOOTED_FROM_MMC0 0
++#define SUNXI_BOOTED_FROM_NAND 1
++#define SUNXI_BOOTED_FROM_MMC2 2
++#define SUNXI_BOOTED_FROM_SPI 3
++#define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10
++#define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
++
++#define SUNXI_INVALID_BOOT_SOURCE -1
++
++static int sunxi_egon_valid(struct boot_file_head *egon_head)
++{
++ return !memcmp(egon_head->magic, BOOT0_MAGIC, 8); /* eGON.BT0 */
++}
++
++static int sunxi_toc0_valid(struct toc0_main_info *toc0_info)
++{
++ return !memcmp(toc0_info->name, TOC0_MAIN_INFO_NAME, 8); /* TOC0.GLH */
++}
++
++static int sunxi_get_boot_source(void)
++{
++ struct boot_file_head *egon_head = (void *)SPL_ADDR;
++ struct toc0_main_info *toc0_info = (void *)SPL_ADDR;
++
++ /*
++ * On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the
++ * exception vectors in U-Boot proper, so we won't find any
++ * information there. Also the FEL stash is only valid in the SPL,
++ * so we can't use that either. So if this is called from U-Boot
++ * proper, just return MMC0 as a placeholder, for now.
++ */
++ if (IS_ENABLED(CONFIG_MACH_SUNIV) &&
++ !IS_ENABLED(CONFIG_SPL_BUILD))
++ return SUNXI_BOOTED_FROM_MMC0;
++
++ if (sunxi_egon_valid(egon_head))
++ return readb(&egon_head->boot_media);
++ if (sunxi_toc0_valid(toc0_info))
++ return readb(&toc0_info->platform[0]);
++
++ /* Not a valid image, so we must have been booted via FEL. */
++ return SUNXI_INVALID_BOOT_SOURCE;
++}
++
++/* The sunxi internal brom will try to loader external bootloader
++ * from mmc0, nand flash, mmc2.
++ */
++uint32_t sunxi_get_boot_device(void)
++{
++ int boot_source = sunxi_get_boot_source();
++
++ /*
++ * When booting from the SD card or NAND memory, the "eGON.BT0"
++ * signature is expected to be found in memory at the address 0x0004
++ * (see the "mksunxiboot" tool, which generates this header).
++ *
++ * When booting in the FEL mode over USB, this signature is patched in
++ * memory and replaced with something else by the 'fel' tool. This other
++ * signature is selected in such a way, that it can't be present in a
++ * valid bootable SD card image (because the BROM would refuse to
++ * execute the SPL in this case).
++ *
++ * This checks for the signature and if it is not found returns to
++ * the FEL code in the BROM to wait and receive the main u-boot
++ * binary over USB. If it is found, it determines where SPL was
++ * read from.
++ */
++ switch (boot_source) {
++ case SUNXI_INVALID_BOOT_SOURCE:
++ return BOOT_DEVICE_BOARD;
++ case SUNXI_BOOTED_FROM_MMC0:
++ case SUNXI_BOOTED_FROM_MMC0_HIGH:
++ return BOOT_DEVICE_MMC1;
++ case SUNXI_BOOTED_FROM_NAND:
++ return BOOT_DEVICE_NAND;
++ case SUNXI_BOOTED_FROM_MMC2:
++ case SUNXI_BOOTED_FROM_MMC2_HIGH:
++ return BOOT_DEVICE_MMC2;
++ case SUNXI_BOOTED_FROM_SPI:
++ return BOOT_DEVICE_SPI;
++ }
++
++ panic("Unknown boot source %d\n", boot_source);
++ return -1; /* Never reached */
++}
++
++uint32_t sunxi_get_spl_size(void)
++{
++ struct boot_file_head *egon_head = (void *)SPL_ADDR;
++ struct toc0_main_info *toc0_info = (void *)SPL_ADDR;
++
++ if (sunxi_egon_valid(egon_head))
++ return readl(&egon_head->length);
++ if (sunxi_toc0_valid(toc0_info))
++ return readl(&toc0_info->length);
++
++ /* Not a valid image, so use the default U-Boot offset. */
++ return 0;
++}
++
++/*
++ * 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 raw_sect)
++{
++ 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:
++ case SUNXI_BOOTED_FROM_MMC2_HIGH:
++ sector += (128 - 8) * 2;
++ break;
++ }
++
++ printf("SPL size = %lu, sector = %lu\n", spl_size, sector);
++
++ return sector;
++}
++
++u32 spl_boot_device(void)
++{
++ return sunxi_get_boot_device();
++}
++
++#define CSR_MXSTATUS 0x7c0
++#define CSR_MHCR 0x7c1
++#define CSR_MCOR 0x7c2
++#define CSR_MHINT 0x7c5
++
++int spl_board_init_f(void)
++{
++ int ret;
++ struct udevice *dev;
++
++ /* DDR init */
++ ret = uclass_get_device(UCLASS_RAM, 0, &dev);
++ if (ret) {
++ debug("DRAM init failed: %d\n", ret);
++ return ret;
++ }
++
++ /* Initialize extension CSRs. */
++ printf("mxstatus=0x%08lx mhcr=0x%08lx mcor=0x%08lx mhint=0x%08lx\n",
++ csr_read(CSR_MXSTATUS),
++ csr_read(CSR_MHCR),
++ csr_read(CSR_MCOR),
++ csr_read(CSR_MHINT));
++
++ csr_set(CSR_MXSTATUS, 0x638000);
++ csr_write(CSR_MCOR, 0x70013);
++ csr_write(CSR_MHCR, 0x11ff);
++ csr_write(CSR_MHINT, 0x16e30c);
++
++ return 0;
++}
++
++#ifdef CONFIG_SPL_BUILD
++void spl_perform_fixups(struct spl_image_info *spl_image)
++{
++ struct ram_info info;
++ struct udevice *dev;
++ int ret;
++
++ ret = uclass_get_device(UCLASS_RAM, 0, &dev);
++ if (ret)
++ panic("No RAM device");
++
++ ret = ram_get_info(dev, &info);
++ if (ret)
++ panic("No RAM info");
++
++ ret = fdt_fixup_memory(spl_image->fdt_addr, info.base, info.size);
++ if (ret)
++ panic("Failed to update DTB");
++}
++#endif
++#endif
++
++DECLARE_GLOBAL_DATA_PTR;
++
++/*
++ * Try to use the environment from the boot source first.
++ * For MMC, this means a FAT partition on the boot device (SD or eMMC).
++ * If the raw MMC environment is also enabled, this is tried next.
++ * When booting from NAND we try UBI first, then NAND directly.
++ * SPI flash falls back to FAT (on SD card).
++ */
++enum env_location env_get_location(enum env_operation op, int prio)
++{
++ if (prio > 1)
++ return ENVL_UNKNOWN;
++
++ /* NOWHERE is exclusive, no other option can be defined. */
++ if (IS_ENABLED(CONFIG_ENV_IS_NOWHERE))
++ return ENVL_NOWHERE;
++
++ switch (sunxi_get_boot_device()) {
++ case BOOT_DEVICE_MMC1:
++ case BOOT_DEVICE_MMC2:
++ if (prio == 0 && IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
++ return ENVL_FAT;
++ if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
++ return ENVL_MMC;
++ break;
++ case BOOT_DEVICE_NAND:
++ if (prio == 0 && IS_ENABLED(CONFIG_ENV_IS_IN_UBI))
++ return ENVL_UBI;
++ if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND))
++ return ENVL_NAND;
++ break;
++ case BOOT_DEVICE_SPI:
++ if (prio == 0 && IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
++ return ENVL_SPI_FLASH;
++ if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
++ return ENVL_FAT;
++ break;
++ case BOOT_DEVICE_BOARD:
++ break;
++ default:
++ break;
++ }
++
++ /*
++ * If we come here for the first time, we *must* return a valid
++ * environment location other than ENVL_UNKNOWN, or the setup sequence
++ * in board_f() will silently hang. This is arguably a bug in
++ * env_init(), but for now pick one environment for which we know for
++ * sure to have a driver for. For all defconfigs this is either FAT
++ * or UBI, or NOWHERE, which is already handled above.
++ */
++ if (prio == 0) {
++ if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
++ return ENVL_FAT;
++ if (IS_ENABLED(CONFIG_ENV_IS_IN_UBI))
++ return ENVL_UBI;
++ }
++
++ return ENVL_UNKNOWN;
++}
++
++/*
++ * On older SoCs the SPL is actually at address zero, so using NULL as
++ * an error value does not work.
++ */
++#define INVALID_SPL_HEADER ((void *)~0UL)
++
++static struct boot_file_head * get_spl_header(uint8_t req_version)
++{
++ struct boot_file_head *spl = (void *)(ulong)SPL_ADDR;
++ uint8_t spl_header_version = spl->spl_signature[3];
++
++ /* Is there really the SPL header (still) there? */
++ if (memcmp(spl->spl_signature, SPL_SIGNATURE, 3) != 0)
++ return INVALID_SPL_HEADER;
++
++ if (spl_header_version < req_version) {
++ printf("sunxi SPL version mismatch: expected %u, got %u\n",
++ req_version, spl_header_version);
++ return INVALID_SPL_HEADER;
++ }
++
++ return spl;
++}
++
++static const char *get_spl_dt_name(void)
++{
++ struct boot_file_head *spl = get_spl_header(SPL_DT_HEADER_VERSION);
++
++ /* Check if there is a DT name stored in the SPL header. */
++ if (spl != INVALID_SPL_HEADER && spl->dt_name_offset)
++ return (char *)spl + spl->dt_name_offset;
++
++ return NULL;
++}
++
++#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
++int mmc_get_env_dev(void)
++{
++ switch (sunxi_get_boot_device()) {
++ case BOOT_DEVICE_MMC1:
++ return 0;
++ case BOOT_DEVICE_MMC2:
++ return 1;
++ default:
++ return CONFIG_SYS_MMC_ENV_DEV;
++ }
++}
++#endif
++
++#ifdef CONFIG_SPL_BUILD
++void sunxi_board_init(void)
++{
++#ifdef CONFIG_LED_STATUS
++ if (IS_ENABLED(CONFIG_SPL_DRIVERS_MISC))
++ status_led_init();
++#endif
++}
++#endif
++
++#ifdef CONFIG_USB_GADGET
++int g_dnl_board_usb_cable_connected(void)
++{
++ struct udevice *dev;
++ struct phy phy;
++ int ret;
++
++ ret = uclass_get_device(UCLASS_USB_GADGET_GENERIC, 0, &dev);
++ if (ret) {
++ pr_err("%s: Cannot find USB device\n", __func__);
++ return ret;
++ }
++
++ ret = generic_phy_get_by_name(dev, "usb", &phy);
++ if (ret) {
++ pr_err("failed to get %s USB PHY\n", dev->name);
++ return ret;
++ }
++
++ ret = generic_phy_init(&phy);
++ if (ret) {
++ pr_debug("failed to init %s USB PHY\n", dev->name);
++ return ret;
++ }
++
++ return sun4i_usb_phy_vbus_detect(&phy);
++}
++#endif
++
++#ifdef CONFIG_SERIAL_TAG
++void get_board_serial(struct tag_serialnr *serialnr)
++{
++ char *serial_string;
++ unsigned long long serial;
++
++ serial_string = env_get("serial#");
++
++ if (serial_string) {
++ serial = simple_strtoull(serial_string, NULL, 16);
++
++ serialnr->high = (unsigned int) (serial >> 32);
++ serialnr->low = (unsigned int) (serial & 0xffffffff);
++ } else {
++ serialnr->high = 0;
++ serialnr->low = 0;
++ }
++}
++#endif
++
++/*
++ * Check the SPL header for the "sunxi" variant. If found: parse values
++ * that might have been passed by the loader ("fel" utility), and update
++ * the environment accordingly.
++ */
++static void parse_spl_header(const uint32_t spl_addr)
++{
++ struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
++
++ if (spl == INVALID_SPL_HEADER)
++ return;
++
++ if (!spl->fel_script_address)
++ return;
++
++ if (spl->fel_uEnv_length != 0) {
++ /*
++ * data is expected in uEnv.txt compatible format, so "env
++ * import -t" the string(s) at fel_script_address right away.
++ */
++ himport_r(&env_htab, (char *)(uintptr_t)spl->fel_script_address,
++ spl->fel_uEnv_length, '\n', H_NOCLEAR, 0, 0, NULL);
++ return;
++ }
++ /* otherwise assume .scr format (mkimage-type script) */
++ env_set_hex("fel_scriptaddr", spl->fel_script_address);
++}
++
++static bool get_unique_sid(unsigned int *sid)
++{
++ if (sunxi_get_sid(sid) != 0)
++ return false;
++
++ if (!sid[0])
++ return false;
++
++ /*
++ * The single words 1 - 3 of the SID have quite a few bits
++ * which are the same on many models, so we take a crc32
++ * of all 3 words, to get a more unique value.
++ *
++ * Note we only do this on newer SoCs as we cannot change
++ * the algorithm on older SoCs since those have been using
++ * fixed mac-addresses based on only using word 3 for a
++ * long time and changing a fixed mac-address with an
++ * u-boot update is not good.
++ */
++#if !defined(CONFIG_MACH_SUN4I) && !defined(CONFIG_MACH_SUN5I) && \
++ !defined(CONFIG_MACH_SUN6I) && !defined(CONFIG_MACH_SUN7I) && \
++ !defined(CONFIG_MACH_SUN8I_A23) && !defined(CONFIG_MACH_SUN8I_A33)
++ sid[3] = crc32(0, (unsigned char *)&sid[1], 12);
++#endif
++
++ /* Ensure the NIC specific bytes of the mac are not all 0 */
++ if ((sid[3] & 0xffffff) == 0)
++ sid[3] |= 0x800000;
++
++ return true;
++}
++
++/*
++ * Note this function gets called multiple times.
++ * It must not make any changes to env variables which already exist.
++ */
++static void setup_environment(const void *fdt)
++{
++ char serial_string[17] = { 0 };
++ unsigned int sid[4];
++ uint8_t mac_addr[6];
++ char ethaddr[16];
++ int i;
++
++ if (!get_unique_sid(sid))
++ return;
++
++ for (i = 0; i < 4; i++) {
++ sprintf(ethaddr, "ethernet%d", i);
++ if (!fdt_get_alias(fdt, ethaddr))
++ continue;
++
++ if (i == 0)
++ strcpy(ethaddr, "ethaddr");
++ else
++ sprintf(ethaddr, "eth%daddr", i);
++
++ if (env_get(ethaddr))
++ continue;
++
++ /* Non OUI / registered MAC address */
++ mac_addr[0] = (i << 4) | 0x02;
++ mac_addr[1] = (sid[0] >> 0) & 0xff;
++ mac_addr[2] = (sid[3] >> 24) & 0xff;
++ mac_addr[3] = (sid[3] >> 16) & 0xff;
++ mac_addr[4] = (sid[3] >> 8) & 0xff;
++ mac_addr[5] = (sid[3] >> 0) & 0xff;
++
++ eth_env_set_enetaddr(ethaddr, mac_addr);
++ }
++
++ if (!env_get("serial#")) {
++ snprintf(serial_string, sizeof(serial_string),
++ "%08x%08x", sid[0], sid[3]);
++
++ env_set("serial#", serial_string);
++ }
++}
++
++int misc_init_r(void)
++{
++ const char *spl_dt_name;
++ uint boot;
++
++ env_set("fel_booted", NULL);
++ env_set("fel_scriptaddr", NULL);
++ env_set("mmc_bootdev", NULL);
++
++ boot = sunxi_get_boot_device();
++ /* determine if we are running in FEL mode */
++ if (boot == BOOT_DEVICE_BOARD) {
++ env_set("fel_booted", "1");
++ parse_spl_header(SPL_ADDR);
++ /* or if we booted from MMC, and which one */
++ } else if (boot == BOOT_DEVICE_MMC1) {
++ env_set("mmc_bootdev", "0");
++ } else if (boot == BOOT_DEVICE_MMC2) {
++ env_set("mmc_bootdev", "1");
++ }
++
++ /* Set fdtfile to match the FIT configuration chosen in SPL. */
++ spl_dt_name = get_spl_dt_name();
++ if (spl_dt_name) {
++ char *prefix = IS_ENABLED(CONFIG_ARM64) ? "allwinner/" : "";
++ char str[64];
++
++ snprintf(str, sizeof(str), "%s%s.dtb", prefix, spl_dt_name);
++ env_set("fdtfile", str);
++ }
++
++ setup_environment(gd->fdt_blob);
++
++ return 0;
++}
++
++int board_late_init(void)
++{
++#ifdef CONFIG_USB_ETHER
++ usb_ether_init();
++#endif
++
++#ifdef SUNXI_SCP_BASE
++ if (!rproc_load(0, SUNXI_SCP_BASE, SUNXI_SCP_MAX_SIZE)) {
++ puts("Starting SCP...\n");
++ rproc_start(0);
++ }
++#endif
++
++ return 0;
++}
++
++static void bluetooth_dt_fixup(void *blob)
++{
++ /* Some devices ship with a Bluetooth controller default address.
++ * Set a valid address through the device tree.
++ */
++ uchar tmp[ETH_ALEN], bdaddr[ETH_ALEN];
++ unsigned int sid[4];
++ int i;
++
++ if (!CONFIG_BLUETOOTH_DT_DEVICE_FIXUP[0])
++ return;
++
++ if (eth_env_get_enetaddr("bdaddr", tmp)) {
++ /* Convert between the binary formats of the corresponding stacks */
++ for (i = 0; i < ETH_ALEN; ++i)
++ bdaddr[i] = tmp[ETH_ALEN - i - 1];
++ } else {
++ if (!get_unique_sid(sid))
++ return;
++
++ bdaddr[0] = ((sid[3] >> 0) & 0xff) ^ 1;
++ bdaddr[1] = (sid[3] >> 8) & 0xff;
++ bdaddr[2] = (sid[3] >> 16) & 0xff;
++ bdaddr[3] = (sid[3] >> 24) & 0xff;
++ bdaddr[4] = (sid[0] >> 0) & 0xff;
++ bdaddr[5] = 0x02;
++ }
++
++ do_fixup_by_compat(blob, CONFIG_BLUETOOTH_DT_DEVICE_FIXUP,
++ "local-bd-address", bdaddr, ETH_ALEN, 1);
++}
++
++int ft_board_setup(void *blob, struct bd_info *bd)
++{
++ int __maybe_unused r;
++
++ /*
++ * Call setup_environment and fdt_fixup_ethernet again
++ * in case the boot fdt has ethernet aliases the u-boot
++ * copy does not have.
++ */
++ setup_environment(blob);
++ fdt_fixup_ethernet(blob);
++
++ bluetooth_dt_fixup(blob);
++
++#ifdef CONFIG_VIDEO_DT_SIMPLEFB
++ r = sunxi_simplefb_setup(blob);
++ if (r)
++ return r;
++#endif
++ return 0;
++}
++
++#ifdef CONFIG_SPL_LOAD_FIT
++
++static void set_spl_dt_name(const char *name)
++{
++ struct boot_file_head *spl = get_spl_header(SPL_ENV_HEADER_VERSION);
++
++ if (spl == INVALID_SPL_HEADER)
++ return;
++
++ /* Promote the header version for U-Boot proper, if needed. */
++ if (spl->spl_signature[3] < SPL_DT_HEADER_VERSION)
++ spl->spl_signature[3] = SPL_DT_HEADER_VERSION;
++
++ strcpy((char *)&spl->string_pool, name);
++ spl->dt_name_offset = offsetof(struct boot_file_head, string_pool);
++}
++
++int board_fit_config_name_match(const char *name)
++{
++ const char *best_dt_name = get_spl_dt_name();
++ int ret;
++
++#ifdef CONFIG_DEFAULT_DEVICE_TREE
++ if (best_dt_name == NULL)
++ best_dt_name = CONFIG_DEFAULT_DEVICE_TREE;
++#endif
++
++ if (best_dt_name == NULL) {
++ /* No DT name was provided, so accept the first config. */
++ return 0;
++ }
++#ifdef CONFIG_PINE64_DT_SELECTION
++ if (strstr(best_dt_name, "-pine64-plus")) {
++ /* Differentiate the Pine A64 boards by their DRAM size. */
++ if ((gd->ram_size == 512 * 1024 * 1024))
++ best_dt_name = "sun50i-a64-pine64";
++ }
++#endif
++#ifdef CONFIG_PINEPHONE_DT_SELECTION
++ if (strstr(best_dt_name, "-pinephone")) {
++ /* Differentiate the PinePhone revisions by GPIO inputs. */
++ prcm_apb0_enable(PRCM_APB0_GATE_PIO);
++ sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_UP);
++ sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_INPUT);
++ udelay(100);
++
++ /* PL6 is pulled low by the modem on v1.2. */
++ if (gpio_get_value(SUNXI_GPL(6)) == 0)
++ best_dt_name = "sun50i-a64-pinephone-1.2";
++ else
++ best_dt_name = "sun50i-a64-pinephone-1.1";
++
++ sunxi_gpio_set_cfgpin(SUNXI_GPL(6), SUNXI_GPIO_DISABLE);
++ sunxi_gpio_set_pull(SUNXI_GPL(6), SUNXI_GPIO_PULL_DISABLE);
++ prcm_apb0_disable(PRCM_APB0_GATE_PIO);
++ }
++#endif
++
++ ret = strcmp(name, best_dt_name);
++
++ /*
++ * If one of the FIT configurations matches the most accurate DT name,
++ * update the SPL header to provide that DT name to U-Boot proper.
++ */
++ if (ret == 0)
++ set_spl_dt_name(best_dt_name);
++
++ return ret;
++}
++#endif
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -12,7 +12,6 @@
+ #ifndef _SUNXI_COMMON_CONFIG_H
+ #define _SUNXI_COMMON_CONFIG_H
+
+-#include <asm/arch/cpu.h>
+ #include <linux/stringify.h>
+
+ /* Serial & console */
--- /dev/null
+From 197d4096c697bcde8f9833b1d04b17eb2b232b85 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 Oct 2022 22:59:00 -0500
+Subject: [PATCH 88/90] sunxi: riscv: Copy in WIP version of devicetrees
+
+While the bindings still are not stable, this should help things work
+out of the box.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ .../riscv/dts/sun20i-d1-clockworkpi-v3.14.dts | 134 +++++++-
+ .../dts/sun20i-d1-common-regulators.dtsi | 13 +
+ arch/riscv/dts/sun20i-d1-devterm-v3.14.dts | 16 +
+ .../dts/sun20i-d1-dongshan-nezha-stu.dts | 48 ++-
+ .../dts/sun20i-d1-lichee-rv-86-panel-480p.dts | 51 +++
+ .../dts/sun20i-d1-lichee-rv-86-panel.dtsi | 64 ++++
+ arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts | 98 ++++++
+ arch/riscv/dts/sun20i-d1-lichee-rv.dts | 6 +
+ arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts | 41 +++
+ arch/riscv/dts/sun20i-d1-nezha.dts | 117 ++++++-
+ arch/riscv/dts/sun20i-d1.dtsi | 314 +++++++++++++++++-
+ 11 files changed, 881 insertions(+), 21 deletions(-)
+
+--- a/arch/riscv/dts/sun20i-d1-clockworkpi-v3.14.dts
++++ b/arch/riscv/dts/sun20i-d1-clockworkpi-v3.14.dts
+@@ -22,16 +22,78 @@
+ stdout-path = "serial0:115200n8";
+ };
+
++ audio_amplifier: audio-amplifier {
++ compatible = "simple-audio-amplifier";
++ enable-gpios = <&pio 4 1 GPIO_ACTIVE_HIGH>; /* PE1/GPIO11 */
++ sound-name-prefix = "Amplifier";
++ VCC-supply = <®_vcc>;
++ };
++
++ /*
++ * FIXME: This is not really an amplifier, but the amplifier binding
++ * has the needed properties and behavior.
++ */
++ audio_switch: audio-switch {
++ compatible = "simple-audio-amplifier";
++ enable-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2/AUD_SWITCH */
++ sound-name-prefix = "Switch";
++ VCC-supply = <®_aldo1>;
++ };
++
++ backlight: backlight {
++ compatible = "pwm-backlight";
++ power-supply = <®_vcc>;
++ pwms = <&pwm 4 50000 0>; /* PD20/GPIO9 */
++ };
++
++ bt_sco_codec: bt-sco-codec {
++ #sound-dai-cells = <0>;
++ compatible = "linux,bt-sco";
++ };
++
++ bt-sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "Bluetooth";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ simple-audio-card,dai-link@0 {
++ format = "dsp_a";
++ frame-master = <&bt_sound_cpu>;
++ bitclock-master = <&bt_sound_cpu>;
++
++ bt_sound_cpu: cpu {
++ sound-dai = <&i2s1>;
++ };
++
++ codec {
++ sound-dai = <&bt_sco_codec>;
++ };
++ };
++ };
++
++ hdmi_connector: connector {
++ compatible = "hdmi-connector";
++ type = "d";
++
++ port {
++ hdmi_connector_in: endpoint {
++ remote-endpoint = <&hdmi_out_connector>;
++ };
++ };
++ };
++
+ /*
+ * This regulator is PWM-controlled, but the PWM controller is not
+ * yet supported, so fix the regulator to its default voltage.
+ */
+ reg_vdd_cpu: vdd-cpu {
+- compatible = "regulator-fixed";
++ compatible = "pwm-regulator";
++ pwms = <&pwm 0 50000 0>;
++ pwm-supply = <®_vcc>;
+ regulator-name = "vdd-cpu";
+- regulator-min-microvolt = <1100000>;
+- regulator-max-microvolt = <1100000>;
+- vin-supply = <®_vcc>;
++ regulator-min-microvolt = <810000>;
++ regulator-max-microvolt = <1160000>;
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+@@ -40,14 +102,51 @@
+ };
+ };
+
++&codec {
++ aux-devs = <&audio_amplifier>, <&audio_switch>;
++ hp-det-gpio = <&pio 1 12 GPIO_ACTIVE_HIGH>; /* PB12/GPIO10 */
++ pin-switches = "Internal Speakers";
++ routing = "Internal Speakers", "Amplifier OUTL",
++ "Internal Speakers", "Amplifier OUTR",
++ "Amplifier INL", "Switch OUTL",
++ "Amplifier INR", "Switch OUTR",
++ "Headphone Jack", "Switch OUTL",
++ "Headphone Jack", "Switch OUTR",
++ "Switch INL", "HPOUTL",
++ "Switch INR", "HPOUTR",
++ "MICIN3", "Headset Microphone",
++ "Headset Microphone", "HBIAS";
++ widgets = "Microphone", "Headset Microphone",
++ "Headphone", "Headphone Jack",
++ "Speaker", "Internal Speakers";
++};
++
+ &cpu0 {
+ cpu-supply = <®_vdd_cpu>;
+ };
+
++&de {
++ status = "okay";
++};
++
+ &ehci1 {
+ status = "okay";
+ };
+
++&hdmi {
++ status = "okay";
++};
++
++&hdmi_out {
++ hdmi_out_connector: endpoint {
++ remote-endpoint = <&hdmi_connector_in>;
++ };
++};
++
++&hdmi_phy {
++ status = "okay";
++};
++
+ &i2c0 {
+ pinctrl-0 = <&i2c0_pb10_pins>;
+ pinctrl-names = "default";
+@@ -169,6 +268,12 @@
+ };
+ };
+
++&i2s1 {
++ pinctrl-0 = <&i2s1_clk_pins>, <&i2s1_din_pin>, <&i2s1_dout_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &mmc0 {
+ broken-cd;
+ bus-width = <4>;
+@@ -205,6 +310,27 @@
+
+ &pio {
+ vcc-pg-supply = <®_ldoa>;
++
++ i2s1_clk_pins: i2s1-clk-pins {
++ pins = "PG12", "PG13";
++ function = "i2s1";
++ };
++
++ i2s1_din_pin: i2s1-din-pin {
++ pins = "PG14";
++ function = "i2s1_din";
++ };
++
++ i2s1_dout_pin: i2s1-dout-pin {
++ pins = "PG15";
++ function = "i2s1_dout";
++ };
++};
++
++&pwm {
++ pinctrl-0 = <&pwm0_pd16_pin>, <&pwm4_pd20_pin>;
++ pinctrl-names = "default";
++ status = "okay";
+ };
+
+ &uart0 {
+--- a/arch/riscv/dts/sun20i-d1-common-regulators.dtsi
++++ b/arch/riscv/dts/sun20i-d1-common-regulators.dtsi
+@@ -18,6 +18,15 @@
+ };
+ };
+
++&codec {
++ avcc-supply = <®_aldo>;
++ hpvcc-supply = <®_hpldo>;
++};
++
++&hdmi {
++ hvcc-supply = <®_ldoa>;
++};
++
+ &lradc {
+ vref-supply = <®_aldo>;
+ };
+@@ -49,3 +58,7 @@
+ regulator-max-microvolt = <1800000>;
+ ldo-in-supply = <®_vcc_3v3>;
+ };
++
++&ths {
++ vref-supply = <®_aldo>;
++};
+--- a/arch/riscv/dts/sun20i-d1-devterm-v3.14.dts
++++ b/arch/riscv/dts/sun20i-d1-devterm-v3.14.dts
+@@ -35,3 +35,19 @@
+ };
+ };
+ };
++
++&dsi {
++ pinctrl-0 = <&dsi_4lane_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ panel@0 {
++ compatible = "clockwork,cwd686";
++ reg = <0>;
++ backlight = <&backlight>;
++ reset-gpios = <&pio 3 19 GPIO_ACTIVE_LOW>; /* PD19/GPIO8 */
++ rotation = <90>;
++ iovcc-supply = <®_dcdc3>;
++ vci-supply = <®_aldo2>;
++ };
++};
+--- a/arch/riscv/dts/sun20i-d1-dongshan-nezha-stu.dts
++++ b/arch/riscv/dts/sun20i-d1-dongshan-nezha-stu.dts
+@@ -23,6 +23,17 @@
+ stdout-path = "serial0:115200n8";
+ };
+
++ hdmi_connector: connector {
++ compatible = "hdmi-connector";
++ type = "a";
++
++ port {
++ hdmi_connector_in: endpoint {
++ remote-endpoint = <&hdmi_out_connector>;
++ };
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+@@ -43,16 +54,13 @@
+ vin-supply = <®_vcc>;
+ };
+
+- /*
+- * This regulator is PWM-controlled, but the PWM controller is not
+- * yet supported, so fix the regulator to its default voltage.
+- */
+ reg_vdd_cpu: vdd-cpu {
+- compatible = "regulator-fixed";
++ compatible = "pwm-regulator";
++ pwms = <&pwm 0 50000 0>;
++ pwm-supply = <®_vcc>;
+ regulator-name = "vdd-cpu";
+- regulator-min-microvolt = <1100000>;
+- regulator-max-microvolt = <1100000>;
+- vin-supply = <®_vcc>;
++ regulator-min-microvolt = <810000>;
++ regulator-max-microvolt = <1160000>;
+ };
+ };
+
+@@ -60,6 +68,10 @@
+ cpu-supply = <®_vdd_cpu>;
+ };
+
++&de {
++ status = "okay";
++};
++
+ &ehci0 {
+ status = "okay";
+ };
+@@ -73,6 +85,20 @@
+ status = "okay";
+ };
+
++&hdmi {
++ status = "okay";
++};
++
++&hdmi_out {
++ hdmi_out_connector: endpoint {
++ remote-endpoint = <&hdmi_connector_in>;
++ };
++};
++
++&hdmi_phy {
++ status = "okay";
++};
++
+ &mdio {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+@@ -95,6 +121,12 @@
+ status = "okay";
+ };
+
++&pwm {
++ pinctrl-0 = <&pwm0_pd16_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-0 = <&uart0_pb8_pins>;
+ pinctrl-names = "default";
+--- a/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-480p.dts
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel-480p.dts
+@@ -7,6 +7,40 @@
+ model = "Sipeed Lichee RV 86 Panel (480p)";
+ compatible = "sipeed,lichee-rv-86-panel-480p", "sipeed,lichee-rv",
+ "allwinner,sun20i-d1";
++
++ backlight: backlight {
++ compatible = "pwm-backlight";
++ power-supply = <®_vcc>;
++ pwms = <&pwm 7 50000 0>;
++ };
++
++ spi {
++ compatible = "spi-gpio";
++ cs-gpios = <&pio 4 14 GPIO_ACTIVE_LOW>; /* PE14 */
++ mosi-gpios = <&pio 4 12 GPIO_ACTIVE_HIGH>; /* PE12 */
++ sck-gpios = <&pio 4 15 GPIO_ACTIVE_HIGH>; /* PE15 */
++ num-chipselects = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ panel@0 {
++ compatible = "sitronix,st7701s";
++ reg = <0>;
++ backlight = <&backlight>;
++ reset-gpios = <&pio 6 13 GPIO_ACTIVE_LOW>; /* PG13 */
++ spi-3wire;
++
++ port {
++ panel_in_tcon_lcd0: endpoint {
++ remote-endpoint = <&tcon_lcd0_out_panel>;
++ };
++ };
++ };
++ };
++};
++
++&de {
++ status = "okay";
+ };
+
+ &i2c2 {
+@@ -27,3 +61,20 @@
+ wakeup-source;
+ };
+ };
++
++&pwm {
++ pinctrl-0 = <&pwm7_pd22_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&tcon_lcd0 {
++ pinctrl-0 = <&lcd_rgb666_pins>;
++ pinctrl-names = "default";
++};
++
++&tcon_lcd0_out {
++ tcon_lcd0_out_panel: endpoint {
++ remote-endpoint = <&panel_in_tcon_lcd0>;
++ };
++};
+--- a/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel.dtsi
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-86-panel.dtsi
+@@ -9,6 +9,39 @@
+ ethernet1 = &xr829;
+ };
+
++ audio_amplifier: audio-amplifier {
++ compatible = "simple-audio-amplifier";
++ enable-gpios = <&pio 1 10 GPIO_ACTIVE_HIGH>; /* PB10 */
++ sound-name-prefix = "Amplifier";
++ };
++
++ dmic_codec: dmic-codec {
++ compatible = "dmic-codec";
++ num-channels = <2>;
++ #sound-dai-cells = <0>;
++ };
++
++ dmic-sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "DMIC";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ simple-audio-card,dai-link@0 {
++ format = "pdm";
++ frame-master = <&link0_cpu>;
++ bitclock-master = <&link0_cpu>;
++
++ link0_cpu: cpu {
++ sound-dai = <&dmic>;
++ };
++
++ link0_codec: codec {
++ sound-dai = <&dmic_codec>;
++ };
++ };
++ };
++
+ /* PC1 is repurposed as BT_WAKE_AP */
+ /delete-node/ leds;
+
+@@ -24,6 +57,27 @@
+ };
+ };
+
++&codec {
++ aux-devs = <&audio_amplifier>;
++ routing = "Internal Speaker", "Amplifier OUTL",
++ "Internal Speaker", "Amplifier OUTR",
++ "Amplifier INL", "HPOUTL",
++ "Amplifier INR", "HPOUTR",
++ "LINEINL", "HPOUTL",
++ "LINEINR", "HPOUTR",
++ "MICIN3", "Internal Microphone",
++ "Internal Microphone", "HBIAS";
++ widgets = "Microphone", "Internal Microphone",
++ "Speaker", "Internal Speaker";
++ status = "okay";
++};
++
++&dmic {
++ pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &ehci1 {
+ status = "okay";
+ };
+@@ -69,6 +123,16 @@
+ pins = "PG11";
+ function = "clk";
+ };
++
++ dmic_pb11_d0_pin: dmic-pb11-d0-pin {
++ pins = "PB11";
++ function = "dmic";
++ };
++
++ dmic_pe17_clk_pin: dmic-pe17-clk-pin {
++ pins = "PE17";
++ function = "dmic";
++ };
+ };
+
+ &uart1 {
+--- a/arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv-dock.dts
+@@ -15,16 +15,102 @@
+ ethernet1 = &rtl8723ds;
+ };
+
++ dmic_codec: dmic-codec {
++ compatible = "dmic-codec";
++ num-channels = <2>;
++ #sound-dai-cells = <0>;
++ };
++
++ dmic-sound {
++ compatible = "simple-audio-card";
++ simple-audio-card,name = "DMIC";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ simple-audio-card,dai-link@0 {
++ format = "pdm";
++ frame-master = <&link0_cpu>;
++ bitclock-master = <&link0_cpu>;
++
++ link0_cpu: cpu {
++ sound-dai = <&dmic>;
++ };
++
++ link0_codec: codec {
++ sound-dai = <&dmic_codec>;
++ };
++ };
++ };
++
++ hdmi_connector: connector {
++ compatible = "hdmi-connector";
++ type = "a";
++
++ port {
++ hdmi_connector_in: endpoint {
++ remote-endpoint = <&hdmi_out_connector>;
++ };
++ };
++ };
++
+ wifi_pwrseq: wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
+ };
+ };
+
++&codec {
++ routing = "Internal Speaker", "HPOUTL",
++ "Internal Speaker", "HPOUTR",
++ "LINEINL", "HPOUTL",
++ "LINEINR", "HPOUTR",
++ "MICIN3", "Internal Microphone",
++ "Internal Microphone", "HBIAS";
++ widgets = "Microphone", "Internal Microphone",
++ "Speaker", "Internal Speaker";
++ status = "okay";
++};
++
++&de {
++ status = "okay";
++};
++
++&dmic {
++ pinctrl-0 = <&dmic_pb11_d0_pin>, <&dmic_pe17_clk_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &ehci1 {
+ status = "okay";
+ };
+
++&hdmi {
++ status = "okay";
++};
++
++&hdmi_out {
++ hdmi_out_connector: endpoint {
++ remote-endpoint = <&hdmi_connector_in>;
++ };
++};
++
++&hdmi_phy {
++ status = "okay";
++};
++
++&ledc {
++ pinctrl-0 = <&ledc_pc0_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ multi-led@0 {
++ reg = <0x0>;
++ color = <LED_COLOR_ID_RGB>;
++ function = LED_FUNCTION_STATUS;
++ };
++};
++
+ &lradc {
+ status = "okay";
+
+@@ -55,6 +141,18 @@
+ status = "okay";
+ };
+
++&pio {
++ dmic_pb11_d0_pin: dmic-pb11-d0-pin {
++ pins = "PB11";
++ function = "dmic";
++ };
++
++ dmic_pe17_clk_pin: dmic-pe17-clk-pin {
++ pins = "PE17";
++ function = "dmic";
++ };
++};
++
+ &uart1 {
+ uart-has-rtscts;
+ pinctrl-0 = <&uart1_pg6_pins>, <&uart1_pg8_rts_cts_pins>;
+--- a/arch/riscv/dts/sun20i-d1-lichee-rv.dts
++++ b/arch/riscv/dts/sun20i-d1-lichee-rv.dts
+@@ -65,6 +65,12 @@
+ status = "okay";
+ };
+
++&spi0 {
++ pinctrl-0 = <&spi0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-0 = <&uart0_pb8_pins>;
+ pinctrl-names = "default";
+--- a/arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts
++++ b/arch/riscv/dts/sun20i-d1-mangopi-mq-pro.dts
+@@ -4,6 +4,7 @@
+ /dts-v1/;
+
+ #include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/leds/common.h>
+
+ #include "sun20i-d1.dtsi"
+ #include "sun20i-d1-common-regulators.dtsi"
+@@ -22,6 +23,28 @@
+ stdout-path = "serial0:115200n8";
+ };
+
++ hdmi_connector: connector {
++ compatible = "hdmi-connector";
++ type = "c";
++
++ port {
++ hdmi_connector_in: endpoint {
++ remote-endpoint = <&hdmi_out_connector>;
++ };
++ };
++ };
++
++ leds {
++ compatible = "pwm-leds";
++
++ led {
++ color = <LED_COLOR_ID_BLUE>;
++ function = LED_FUNCTION_STATUS;
++ max-brightness = <255>;
++ pwms = <&pwm 2 50000 0>;
++ };
++ };
++
+ reg_avdd2v8: avdd2v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "avdd2v8";
+@@ -56,10 +79,28 @@
+ cpu-supply = <®_vdd_cpu>;
+ };
+
++&de {
++ status = "okay";
++};
++
+ &ehci1 {
+ status = "okay";
+ };
+
++&hdmi {
++ status = "okay";
++};
++
++&hdmi_out {
++ hdmi_out_connector: endpoint {
++ remote-endpoint = <&hdmi_connector_in>;
++ };
++};
++
++&hdmi_phy {
++ status = "okay";
++};
++
+ &mmc0 {
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+--- a/arch/riscv/dts/sun20i-d1-nezha.dts
++++ b/arch/riscv/dts/sun20i-d1-nezha.dts
+@@ -5,6 +5,7 @@
+
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
++#include <dt-bindings/leds/common.h>
+
+ #include "sun20i-d1.dtsi"
+ #include "sun20i-d1-common-regulators.dtsi"
+@@ -18,12 +19,24 @@
+ ethernet1 = &xr829;
+ mmc0 = &mmc0;
+ serial0 = &uart0;
++ spi0 = &spi0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
++ hdmi_connector: connector {
++ compatible = "hdmi-connector";
++ type = "a";
++
++ port {
++ hdmi_connector_in: endpoint {
++ remote-endpoint = <&hdmi_out_connector>;
++ };
++ };
++ };
++
+ reg_usbvbus: usbvbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usbvbus";
+@@ -34,16 +47,13 @@
+ vin-supply = <®_vcc>;
+ };
+
+- /*
+- * This regulator is PWM-controlled, but the PWM controller is not
+- * yet supported, so fix the regulator to its default voltage.
+- */
+ reg_vdd_cpu: vdd-cpu {
+- compatible = "regulator-fixed";
++ compatible = "pwm-regulator";
++ pwms = <&pwm 0 50000 0>;
++ pwm-supply = <®_vcc>;
+ regulator-name = "vdd-cpu";
+- regulator-min-microvolt = <1100000>;
+- regulator-max-microvolt = <1100000>;
+- vin-supply = <®_vcc>;
++ regulator-min-microvolt = <810000>;
++ regulator-max-microvolt = <1160000>;
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+@@ -52,10 +62,26 @@
+ };
+ };
+
++&codec {
++ routing = "Headphone Jack", "HPOUTL",
++ "Headphone Jack", "HPOUTR",
++ "LINEINL", "HPOUTL",
++ "LINEINR", "HPOUTR",
++ "MICIN3", "Headset Microphone",
++ "Headset Microphone", "HBIAS";
++ widgets = "Microphone", "Headset Microphone",
++ "Headphone", "Headphone Jack";
++ status = "okay";
++};
++
+ &cpu0 {
+ cpu-supply = <®_vdd_cpu>;
+ };
+
++&de {
++ status = "okay";
++};
++
+ &ehci0 {
+ status = "okay";
+ };
+@@ -73,6 +99,20 @@
+ status = "okay";
+ };
+
++&hdmi {
++ status = "okay";
++};
++
++&hdmi_out {
++ hdmi_out_connector: endpoint {
++ remote-endpoint = <&hdmi_connector_in>;
++ };
++};
++
++&hdmi_phy {
++ status = "okay";
++};
++
+ &i2c2 {
+ pinctrl-0 = <&i2c2_pb0_pins>;
+ pinctrl-names = "default";
+@@ -90,6 +130,18 @@
+ };
+ };
+
++&ledc {
++ pinctrl-0 = <&ledc_pc0_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ multi-led@0 {
++ reg = <0x0>;
++ color = <LED_COLOR_ID_RGB>;
++ function = LED_FUNCTION_STATUS;
++ };
++};
++
+ &lradc {
+ status = "okay";
+
+@@ -142,6 +194,55 @@
+ status = "okay";
+ };
+
++&pwm {
++ pinctrl-0 = <&pwm0_pd16_pin>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&spi0 {
++ pinctrl-0 = <&spi0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ flash@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@0 {
++ label = "boot0";
++ reg = <0x00000000 0x00100000>;
++ };
++
++ partition@100000 {
++ label = "uboot";
++ reg = <0x00100000 0x00300000>;
++ };
++
++ partition@400000 {
++ label = "secure_storage";
++ reg = <0x00400000 0x00100000>;
++ };
++
++ partition@500000 {
++ label = "sys";
++ reg = <0x00500000 0x0fb00000>;
++ };
++ };
++ };
++};
++
++&spi1 {
++ pinctrl-0 = <&spi1_pd_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
+ &uart0 {
+ pinctrl-0 = <&uart0_pb8_pins>;
+ pinctrl-names = "default";
+--- a/arch/riscv/dts/sun20i-d1.dtsi
++++ b/arch/riscv/dts/sun20i-d1.dtsi
+@@ -59,6 +59,35 @@
+ #clock-cells = <0>;
+ };
+
++ thermal-zones {
++ cpu-thermal {
++ polling-delay = <0>;
++ polling-delay-passive = <0>;
++ thermal-sensors = <&ths>;
++
++ trips {
++ cpu_target: cpu-target {
++ hysteresis = <3000>;
++ temperature = <85000>;
++ type = "passive";
++ };
++
++ cpu-crit {
++ hysteresis = <0>;
++ temperature = <110000>;
++ type = "critical";
++ };
++ };
++
++ cooling-maps {
++ map0 {
++ trip = <&cpu_target>;
++ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
++ };
++ };
++ };
++ };
++
+ soc {
+ compatible = "simple-bus";
+ ranges;
+@@ -95,6 +124,14 @@
+ #interrupt-cells = <3>;
+
+ /omit-if-no-ref/
++ dsi_4lane_pins: dsi-4lane-pins {
++ pins = "PD0", "PD1", "PD2", "PD3", "PD4", "PD5",
++ "PD6", "PD7", "PD8", "PD9";
++ drive-strength = <30>;
++ function = "dsi";
++ };
++
++ /omit-if-no-ref/
+ i2c0_pb10_pins: i2c0-pb10-pins {
+ pins = "PB10", "PB11";
+ function = "i2c0";
+@@ -116,6 +153,12 @@
+ };
+
+ /omit-if-no-ref/
++ ledc_pc0_pin: ledc-pc0-pin {
++ pins = "PC0";
++ function = "ledc";
++ };
++
++ /omit-if-no-ref/
+ mmc0_pins: mmc0-pins {
+ pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
+ function = "mmc0";
+@@ -149,6 +192,48 @@
+ };
+
+ /omit-if-no-ref/
++ pwm0_pd16_pin: pwm0-pd16-pin {
++ pins = "PD16";
++ function = "pwm0";
++ };
++
++ /omit-if-no-ref/
++ pwm2_pd18_pin: pwm2-pd18-pin {
++ pins = "PD18";
++ function = "pwm2";
++ };
++
++ /omit-if-no-ref/
++ pwm4_pd20_pin: pwm4-pd20-pin {
++ pins = "PD20";
++ function = "pwm4";
++ };
++
++ /omit-if-no-ref/
++ pwm7_pd22_pin: pwm7-pd22-pin {
++ pins = "PD22";
++ function = "pwm7";
++ };
++
++ /omit-if-no-ref/
++ spi0_pins: spi0-pins {
++ pins = "PC2", "PC3", "PC4", "PC5", "PC6", "PC7";
++ function = "spi0";
++ };
++
++ /omit-if-no-ref/
++ spi1_pb_pins: spi1-pb-pins {
++ pins = "PB0", "PB8", "PB9", "PB10", "PB11", "PB12";
++ function = "spi1";
++ };
++
++ /omit-if-no-ref/
++ spi1_pd_pins: spi1-pd-pins {
++ pins = "PD10", "PD11", "PD12", "PD13", "PD14", "PD15";
++ function = "spi1";
++ };
++
++ /omit-if-no-ref/
+ uart0_pb8_pins: uart0-pb8-pins {
+ pins = "PB8", "PB9";
+ function = "uart0";
+@@ -167,6 +252,17 @@
+ };
+ };
+
++ pwm: pwm@2000c00 {
++ compatible = "allwinner,sun20i-d1-pwm";
++ reg = <0x2000c00 0x400>;
++ interrupts = <34 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_PWM>, <&osc24M>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_PWM>;
++ status = "disabled";
++ #pwm-cells = <3>;
++ };
++
+ ccu: clock-controller@2001000 {
+ compatible = "allwinner,sun20i-d1-ccu";
+ reg = <0x2001000 0x1000>;
+@@ -178,6 +274,33 @@
+ #reset-cells = <1>;
+ };
+
++ ledc: led-controller@2008000 {
++ compatible = "allwinner,sun20i-d1-ledc",
++ "allwinner,sun50i-a100-ledc";
++ reg = <0x2008000 0x400>;
++ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_LEDC>, <&ccu CLK_LEDC>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_LEDC>;
++ dmas = <&dma 42>;
++ dma-names = "tx";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ ths: temperature-sensor@2009400 {
++ compatible = "allwinner,sun20i-d1-ths";
++ reg = <0x2009400 0x400>;
++ interrupts = <74 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_THS>, <&osc24M>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_THS>;
++ nvmem-cells = <&ths_calib>;
++ nvmem-cell-names = "calibration";
++ #thermal-sensor-cells = <0>;
++ };
++
+ lradc: keys@2009800 {
+ compatible = "allwinner,sun20i-d1-lradc",
+ "allwinner,sun50i-r329-lradc";
+@@ -188,11 +311,30 @@
+ status = "disabled";
+ };
+
++ iommu: iommu@2010000 {
++ compatible = "allwinner,sun20i-d1-iommu";
++ reg = <0x2010000 0x10000>;
++ interrupts = <80 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_IOMMU>;
++ #iommu-cells = <1>;
++ };
++
+ codec: audio-codec@2030000 {
+- compatible = "simple-mfd", "syscon";
++ compatible = "allwinner,sun20i-d1-codec", "simple-mfd", "syscon";
+ reg = <0x2030000 0x1000>;
++ interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_AUDIO>,
++ <&ccu CLK_AUDIO_ADC>,
++ <&ccu CLK_AUDIO_DAC>,
++ <&osc24M>,
++ <&rtc CLK_OSC32K>;
++ clock-names = "bus", "adc", "dac", "hosc", "losc";
++ resets = <&ccu RST_BUS_AUDIO>;
++ dmas = <&dma 7>, <&dma 7>;
++ dma-names = "rx", "tx";
+ #address-cells = <1>;
+ #size-cells = <1>;
++ #sound-dai-cells = <0>;
+
+ regulators@2030348 {
+ compatible = "allwinner,sun20i-d1-analog-ldos";
+@@ -208,6 +350,21 @@
+ };
+ };
+
++ dmic: dmic@2031000 {
++ compatible = "allwinner,sun20i-d1-dmic",
++ "allwinner,sun50i-h6-dmic";
++ reg = <0x2031000 0x400>;
++ interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_DMIC>,
++ <&ccu CLK_DMIC>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_DMIC>;
++ dmas = <&dma 8>;
++ dma-names = "rx";
++ status = "disabled";
++ #sound-dai-cells = <0>;
++ };
++
+ i2s0: i2s@2032000 {
+ compatible = "allwinner,sun20i-d1-i2s",
+ "allwinner,sun50i-r329-i2s";
+@@ -238,6 +395,7 @@
+ #sound-dai-cells = <0>;
+ };
+
++ // TODO: how to integrate ASRC? same or separate node?
+ i2s2: i2s@2034000 {
+ compatible = "allwinner,sun20i-d1-i2s",
+ "allwinner,sun50i-r329-i2s";
+@@ -253,6 +411,22 @@
+ #sound-dai-cells = <0>;
+ };
+
++ // TODO: add receive functionality
++ spdif: spdif@2036000 {
++ compatible = "allwinner,sun20i-d1-spdif";
++ reg = <0x2036000 0x400>;
++ interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_SPDIF>,
++ <&ccu CLK_SPDIF_RX>,
++ <&ccu CLK_SPDIF_TX>;
++ clock-names = "apb", "rx", "tx";
++ resets = <&ccu RST_BUS_SPDIF>;
++ dmas = <&dma 2>, <&dma 2>;
++ dma-names = "rx", "tx";
++ status = "disabled";
++ #sound-dai-cells = <0>;
++ };
++
+ timer: timer@2050000 {
+ compatible = "allwinner,sun20i-d1-timer",
+ "allwinner,sun8i-a23-timer";
+@@ -457,6 +631,18 @@
+ };
+ };
+
++ crypto: crypto@3040000 {
++ compatible = "allwinner,sun20i-d1-crypto";
++ reg = <0x3040000 0x800>;
++ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_CE>,
++ <&ccu CLK_CE>,
++ <&ccu CLK_MBUS_CE>,
++ <&rtc CLK_IOSC>;
++ clock-names = "bus", "mod", "ram", "trng";
++ resets = <&ccu RST_BUS_CE>;
++ };
++
+ mbus: dram-controller@3102000 {
+ compatible = "allwinner,sun20i-d1-mbus";
+ reg = <0x3102000 0x1000>,
+@@ -525,6 +711,39 @@
+ #size-cells = <0>;
+ };
+
++ spi0: spi@4025000 {
++ compatible = "allwinner,sun20i-d1-spi",
++ "allwinner,sun50i-r329-spi";
++ reg = <0x4025000 0x1000>;
++ interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
++ clock-names = "ahb", "mod";
++ resets = <&ccu RST_BUS_SPI0>;
++ dmas = <&dma 22>, <&dma 22>;
++ dma-names = "rx", "tx";
++ num-cs = <1>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi1: spi@4026000 {
++ compatible = "allwinner,sun20i-d1-spi-dbi",
++ "allwinner,sun50i-r329-spi-dbi",
++ "allwinner,sun50i-r329-spi";
++ reg = <0x4026000 0x1000>;
++ interrupts = <32 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
++ clock-names = "ahb", "mod";
++ resets = <&ccu RST_BUS_SPI1>;
++ dmas = <&dma 23>, <&dma 23>;
++ dma-names = "rx", "tx";
++ num-cs = <1>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ usb_otg: usb@4100000 {
+ compatible = "allwinner,sun20i-d1-musb",
+ "allwinner,sun8i-a33-musb";
+@@ -653,6 +872,7 @@
+ <&display_clocks CLK_MIXER0>;
+ clock-names = "bus", "mod";
+ resets = <&display_clocks RST_MIXER0>;
++ iommus = <&iommu 2>;
+
+ ports {
+ #address-cells = <1>;
+@@ -675,6 +895,7 @@
+ <&display_clocks CLK_MIXER1>;
+ clock-names = "bus", "mod";
+ resets = <&display_clocks RST_MIXER1>;
++ iommus = <&iommu 2>;
+
+ ports {
+ #address-cells = <1>;
+@@ -690,6 +911,40 @@
+ };
+ };
+
++ dsi: dsi@5450000 {
++ compatible = "allwinner,sun20i-d1-mipi-dsi",
++ "allwinner,sun50i-a100-mipi-dsi";
++ reg = <0x5450000 0x1000>;
++ interrupts = <108 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_MIPI_DSI>,
++ <&tcon_top CLK_TCON_TOP_DSI>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_MIPI_DSI>;
++ phys = <&dphy>;
++ phy-names = "dphy";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port {
++ dsi_in_tcon_lcd0: endpoint {
++ remote-endpoint = <&tcon_lcd0_out_dsi>;
++ };
++ };
++ };
++
++ dphy: phy@5451000 {
++ compatible = "allwinner,sun20i-d1-mipi-dphy",
++ "allwinner,sun50i-a100-mipi-dphy";
++ reg = <0x5451000 0x1000>;
++ interrupts = <108 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_MIPI_DSI>,
++ <&ccu CLK_MIPI_DSI>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_MIPI_DSI>;
++ #phy-cells = <0>;
++ };
++
+ tcon_top: tcon-top@5460000 {
+ compatible = "allwinner,sun20i-d1-tcon-top";
+ reg = <0x5460000 0x1000>;
+@@ -770,6 +1025,10 @@
+
+ tcon_top_hdmi_out: port@5 {
+ reg = <5>;
++
++ tcon_top_hdmi_out_hdmi: endpoint {
++ remote-endpoint = <&hdmi_in_tcon_top>;
++ };
+ };
+ };
+ };
+@@ -785,6 +1044,8 @@
+ resets = <&ccu RST_BUS_TCON_LCD0>,
+ <&ccu RST_BUS_LVDS0>;
+ reset-names = "lcd", "lvds";
++ phys = <&dphy>;
++ phy-names = "lvds0";
+ #clock-cells = <0>;
+
+ ports {
+@@ -809,6 +1070,13 @@
+
+ tcon_lcd0_out: port@1 {
+ reg = <1>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ tcon_lcd0_out_dsi: endpoint@1 {
++ reg = <1>;
++ remote-endpoint = <&dsi_in_tcon_lcd0>;
++ };
+ };
+ };
+ };
+@@ -853,6 +1121,50 @@
+ };
+ };
+
++ hdmi: hdmi@5500000 {
++ compatible = "allwinner,sun20i-d1-dw-hdmi";
++ reg = <0x5500000 0x10000>;
++ reg-io-width = <1>;
++ interrupts = <109 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&ccu CLK_BUS_HDMI>,
++ <&ccu CLK_HDMI_24M>,
++ <&ccu CLK_HDMI_CEC>;
++ clock-names = "iahb", "isfr", "cec";
++ resets = <&ccu RST_BUS_HDMI_SUB>;
++ reset-names = "ctrl";
++ phys = <&hdmi_phy>;
++ phy-names = "phy";
++ status = "disabled";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++
++ hdmi_in_tcon_top: endpoint {
++ remote-endpoint = <&tcon_top_hdmi_out_hdmi>;
++ };
++ };
++
++ hdmi_out: port@1 {
++ reg = <1>;
++ };
++ };
++ };
++
++ hdmi_phy: phy@5510000 {
++ compatible = "allwinner,sun20i-d1-hdmi-phy";
++ reg = <0x5510000 0x10000>;
++ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_24M>;
++ clock-names = "bus", "mod";
++ resets = <&ccu RST_BUS_HDMI_MAIN>;
++ reset-names = "phy";
++ status = "disabled";
++ #phy-cells = <0>;
++ };
++
+ riscv_wdt: watchdog@6011000 {
+ compatible = "allwinner,sun20i-d1-wdt";
+ reg = <0x6011000 0x20>;
--- /dev/null
+From 0a4e7a1a19dd505bc5b6ff887b2ce39983aaa92d Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Mon, 31 Oct 2022 23:27:08 -0500
+Subject: [PATCH 89/90] sunxi: riscv: Add defconfigs for several boards
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ configs/devterm_r_01_defconfig | 10 ++++++++++
+ configs/dongshan_nezha_stu_defconfig | 13 +++++++++++++
+ configs/lichee_rv_86_panel_defconfig | 13 +++++++++++++
+ configs/lichee_rv_dock_defconfig | 10 ++++++++++
+ configs/mangopi_mq_pro_defconfig | 10 ++++++++++
+ configs/nezha_defconfig | 13 +++++++++++++
+ 6 files changed, 69 insertions(+)
+ create mode 100644 configs/devterm_r_01_defconfig
+ create mode 100644 configs/dongshan_nezha_stu_defconfig
+ create mode 100644 configs/lichee_rv_86_panel_defconfig
+ create mode 100644 configs/lichee_rv_dock_defconfig
+ create mode 100644 configs/mangopi_mq_pro_defconfig
+ create mode 100644 configs/nezha_defconfig
+
+--- /dev/null
++++ b/configs/devterm_r_01_defconfig
+@@ -0,0 +1,10 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-devterm-v3.14"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_DM_REGULATOR_FIXED=y
+--- /dev/null
++++ b/configs/dongshan_nezha_stu_defconfig
+@@ -0,0 +1,13 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-dongshan-nezha-stu"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_PHY_REALTEK=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_DM_REGULATOR_FIXED=y
+--- /dev/null
++++ b/configs/lichee_rv_86_panel_defconfig
+@@ -0,0 +1,13 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-lichee-rv-86-panel-480p"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_PHY_REALTEK=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_DM_REGULATOR_FIXED=y
+--- /dev/null
++++ b/configs/lichee_rv_dock_defconfig
+@@ -0,0 +1,10 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-lichee-rv-dock"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_DM_REGULATOR_FIXED=y
+--- /dev/null
++++ b/configs/mangopi_mq_pro_defconfig
+@@ -0,0 +1,10 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-mangopi-mq-pro"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_DM_REGULATOR_FIXED=y
+--- /dev/null
++++ b/configs/nezha_defconfig
+@@ -0,0 +1,13 @@
++CONFIG_RISCV=y
++CONFIG_DEFAULT_DEVICE_TREE="sun20i-d1-nezha"
++CONFIG_TARGET_SUN20I_D1=y
++CONFIG_ARCH_RV64I=y
++CONFIG_RISCV_SMODE=y
++# CONFIG_SPL_SMP is not set
++CONFIG_SYS_SPL_MALLOC=y
++CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_SYS_I2C_MVTWSI is not set
++CONFIG_PHY_REALTEK=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_DM_REGULATOR_FIXED=y
--- /dev/null
+From 62419798c137c9eec2d2c1011e417d1520aecffb Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 6 Jun 2023 19:46:30 +0000
+Subject: [PATCH 90/90] drivers: phy: fix typo
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ drivers/phy/allwinner/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/phy/allwinner/Kconfig
++++ b/drivers/phy/allwinner/Kconfig
+@@ -3,7 +3,7 @@
+ #
+ config PHY_SUN4I_USB
+ bool "Allwinner Sun4I USB PHY driver"
+- depends on depends on BOARD_SUNXI
++ depends on BOARD_SUNXI
+ default y
+ select DM_REGULATOR
+ select PHY
--- /dev/null
+From 637800493945ffed2f454756300437a4ec86e3b1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 19 Jul 2017 22:23:15 +0200
+Subject: mkimage: check environment for dtc binary location
+
+Currently mkimage assumes the dtc binary is in the path and fails
+otherwise. This patch makes it check the DTC environment variable first
+for the dtc binary and then fall back to the default path. This makes
+it possible to call the u-boot build with make DTC=... and build a fit
+image with the dtc binary not being the the default path.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Cc: Simon Glass <sjg@chromium.org>
+---
+ tools/fit_image.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/tools/fit_image.c
++++ b/tools/fit_image.c
+@@ -729,9 +729,14 @@ static int fit_handle_file(struct image_
+ }
+ *cmd = '\0';
+ } else if (params->datafile) {
++ const char* dtc = getenv("DTC");
++
++ if (!dtc)
++ dtc = MKIMAGE_DTC;
++
+ /* dtc -I dts -O dtb -p 500 -o tmpfile datafile */
+ snprintf(cmd, sizeof(cmd), "%s %s -o \"%s\" \"%s\"",
+- MKIMAGE_DTC, params->dtc, tmpfile, params->datafile);
++ dtc, params->dtc, tmpfile, params->datafile);
+ debug("Trying to execute \"%s\"\n", cmd);
+ } else {
+ snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
--- /dev/null
+--- a/tools/image-host.c
++++ b/tools/image-host.c
+@@ -1125,6 +1125,7 @@ static int fit_config_add_verification_d
+ * 2) get public key (X509_get_pubkey)
+ * 3) provide der format (d2i_RSAPublicKey)
+ */
++#ifdef CONFIG_TOOLS_LIBCRYPTO
+ static int read_pub_key(const char *keydir, const void *name,
+ unsigned char **pubkey, int *pubkey_len)
+ {
+@@ -1178,6 +1179,13 @@ err_cert:
+ fclose(f);
+ return ret;
+ }
++#else
++static int read_pub_key(const char *keydir, const void *name,
++ unsigned char **pubkey, int *pubkey_len)
++{
++ return -ENOSYS;
++}
++#endif
+
+ int fit_pre_load_data(const char *keydir, void *keydest, void *fit)
+ {
--- /dev/null
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -119,7 +119,6 @@ dumpimage-mkimage-objs := aisimage.o \
+ imximage.o \
+ imx8image.o \
+ imx8mimage.o \
+- kwbimage.o \
+ lib/md5.o \
+ lpc32xximage.o \
+ mxsimage.o \
--- /dev/null
+--- a/Makefile
++++ b/Makefile
+@@ -2045,26 +2045,7 @@ endif
+ # Check dtc and pylibfdt, if DTC is provided, else build them
+ PHONY += scripts_dtc
+ scripts_dtc: scripts_basic
+- $(Q)if test "$(DTC)" = "$(DTC_INTREE)"; then \
+- $(MAKE) $(build)=scripts/dtc; \
+- else \
+- if ! $(DTC) -v >/dev/null; then \
+- echo '*** Failed to check dtc version: $(DTC)'; \
+- false; \
+- else \
+- if test "$(call dtc-version)" -lt $(DTC_MIN_VERSION); then \
+- echo '*** Your dtc is too old, please upgrade to dtc $(DTC_MIN_VERSION) or newer'; \
+- false; \
+- else \
+- if [ -n "$(CONFIG_PYLIBFDT)" ]; then \
+- if ! echo "import libfdt" | $(PYTHON3) 2>/dev/null; then \
+- echo '*** pylibfdt does not seem to be available with $(PYTHON3)'; \
+- false; \
+- fi; \
+- fi; \
+- fi; \
+- fi; \
+- fi
++ $(MAKE) $(build)=scripts/dtc
+
+ # ---------------------------------------------------------------------------
+ quiet_cmd_cpp_lds = LDS $@
--- /dev/null
+setenv loadkernel fatload mmc 0:1 \$kernel_addr_r Image
+setenv bootargs console=ttyS0,115200 earlycon=sbi root=/dev/mmcblk0p2 rootwait
+setenv uenvcmd run loadkernel \&\& booti \$kernel_addr_r - \$fdtcontroladdr
+run uenvcmd