uboot-sunxi: add T113-S3 support
authorZoltan HERPAI <wigyori@uid0.hu>
Wed, 6 Mar 2024 17:59:29 +0000 (18:59 +0100)
committerZoltan HERPAI <wigyori@uid0.hu>
Wed, 6 Mar 2024 22:50:28 +0000 (23:50 +0100)
Add support for the T113 family, along with 4 boards.

Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
56 files changed:
package/boot/uboot-sunxi/Makefile
package/boot/uboot-sunxi/patches/4000-sunxi-remove-CONFIG_SATAPWR.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4001-net-sunxi_emac-Switch-to-new-U-Boot-PHY-API.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4002-net-sunxi_emac-chase-DT-nodes-to-find-PHY-regulator.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4003-net-sun8i-emac-Add-a-structure-for-variant-data.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4004-net-sun8i-emac-Add-a-flag-for-RMII-support.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4005-net-sun8i-emac-Add-a-flag-for-the-internal-PHY-switc.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4006-net-sun8i-emac-Use-common-syscon-setup-for-R40.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4007-net-sun8i-emac-Remove-the-SoC-variant-ID.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4008-sunxi-remove-CONFIG_MACPWR.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4009-pinctrl-sunxi-add-GPIO-in-out-wrappers.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4010-pinctrl-sunxi-remove-struct-sunxi_gpio.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4011-pinctrl-sunxi-move-pinctrl-code-and-remove-GPIO_EXTR.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4012-pinctrl-sunxi-move-PIO_BASE-into-sunxi_gpio.h.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4013-pinctrl-sunxi-add-new-D1-pinctrl-support.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4014-sunxi-introduce-NCAT2-generation-model.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4015-pinctrl-sunxi-add-Allwinner-D1-pinctrl-description.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4016-clk-sunxi-Add-support-for-the-D1-CCU.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4017-sunxi-clock-D1-R528-Enable-PLL-LDO-during-PLL1-setup.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4018-sunxi-clock-support-D1-R528-PLL6-clock.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4019-sunxi-clock-h6-prepare-for-PRCM-less-SoCs.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4020-Kconfig-sunxi-prepare-for-using-drivers-ram-sunxi.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4021-sunxi-add-R528-T113-s3-D1-s-DRAM-initialisation-code.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4022-sunxi-add-Allwinner-R528-T113-SoC-support.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4023-sunxi-refactor-serial-base-addresses-to-avoid-asm-ar.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4024-riscv-dts-allwinner-Add-the-D1-D1s-SoC-devicetree.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4025-ARM-dts-sunxi-add-Allwinner-T113-s-SoC-.dtsi.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4026-sunxi-add-MangoPi-MQ-R-board-support.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4027-net-add-ICPlus-PHY-driver.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4028-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethe.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4029-net-phy-backport-and-update-driver-for-Motorcomm-yt8.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4030-sunxi-SPL-SPI-Add-SPI-boot-support-for-the-Allwinner.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4031-spi-sunxi-Add-support-for-R329-D1-R528-T113-SPI-cont.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4032-riscv-dts-allwinner-d1-Add-SPI-controllers-node.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4033-mtd-spi-nand-backport-from-upstream-kernel.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4034-sunxi-psci-clean-away-preprocessor-macros.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4035-sunxi-psci-refactor-register-access-to-separate-func.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4036-sunxi-psci-stop-modeling-register-layout-with-C-stru.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4037-sunxi-psci-implement-PSCI-on-R528.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4038-HACK-sunxi-psci-be-compatible-with-v1-of-R528-patchs.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4039-sunxi-add-uart0_pins-on-Port-E-PE2-PE3-on-D1s-T133.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4040-sunxi-add-support-for-MangoPI-MQDual-T113-variant.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4041-sunxi-add-support-for-UART5-in-Port-E-group-on-T133.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4042-sunxi-add-MYIR-MYD-YT113X-board.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4043-sunxi-add-support-for-UART3-on-PE-pins.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4044-sunxi-add-support-for-Rongpin-RP-T113-board.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4045-sunxi-add-MYIR-MYD-YT113X-SPI-board.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4046-sunxi-add-support-for-emac-on-PG-pins.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4047-sunxi-add-ethernet-support-on-MYIR-MYD-YT113X-SPI.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4048-sunxi-enable-emac-on-Rongpin-RP-T113.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4049-sunxi-enable-gmac-on-MYIR-MYD-YT113X-with-the-YT8531.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4050-arm-dts-add-partition-table-for-MYIR-MYD-YT113X-SPI.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4051-configs-enable-UBI-support-for-MYIR-MYD-YT113X-SPI.patch [new file with mode: 0644]
package/boot/uboot-sunxi/patches/4052-sunxi-r528-d1-t113-add-SDC2-pinmux-on-PC2-7-pins.patch [new file with mode: 0644]
package/boot/uboot-sunxi/uEnv-t113.ttyS3.txt [new file with mode: 0644]
package/boot/uboot-sunxi/uEnv-t113.ttyS5.txt [new file with mode: 0644]

index 7f50992e6955c6e8d3cb26e6449d324f0f72d349..169dbe6fc9853723cc5389c986831564c97f8cd6 100644 (file)
@@ -358,7 +358,38 @@ define U-Boot/bananapi_p2_zero
 endef
 
 
+define U-Boot/mangopi_mqdual_t113
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=MangoPi MQDual (T113)
+  BUILD_DEVICES:=widora_mangopi-mqdual-t113
+endef
+
+define U-Boot/myir_myd_t113x
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=MYIR MYD-T113X
+  BUILD_DEVICES:=myir_myd-yt113x
+  UENV:=t113.ttyS5
+endef
+
+define U-Boot/myir_myd_t113x-spi
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=MYIR MYD-T113X SPI
+  BUILD_DEVICES:=myir_myd-yt113x-spi
+  UENV:=t113.ttyS5
+endef
+
+define U-Boot/rongpin_rp_t113
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Rongpin RP-T113
+  BUILD_DEVICES:=rongpin_rp-t113
+  UENV:=t113.ttyS3
+endef
+
 UBOOT_TARGETS := \
+       mangopi_mqdual_t113 \
+       myir_myd_t113x \
+       myir_myd_t113x-spi \
+       rongpin_rp_t113 \
        a64-olinuxino \
        a64-olinuxino-emmc \
        A10-OLinuXino-Lime \
@@ -403,8 +434,8 @@ UBOOT_TARGETS := \
        orangepi_pc2 \
        orangepi_zero2 \
        pangolin \
-       pine64_plus \
        Sinovoip_BPI_M3 \
+       pine64_plus \
        sopine_baseboard \
        orangepi_zero_plus \
        libretech_all_h3_cc_h5
diff --git a/package/boot/uboot-sunxi/patches/4000-sunxi-remove-CONFIG_SATAPWR.patch b/package/boot/uboot-sunxi/patches/4000-sunxi-remove-CONFIG_SATAPWR.patch
new file mode 100644 (file)
index 0000000..66d2eca
--- /dev/null
@@ -0,0 +1,370 @@
+From 705db6ba7f566810a339985ac34170d0a84ea868 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 15 Jul 2022 16:52:14 +0100
+Subject: [PATCH 4000/4052] sunxi: remove CONFIG_SATAPWR
+
+The CONFIG_SATAPWR Kconfig symbol was used to point to a GPIO that
+enables the power for a SATA harddisk.
+In the DT this is described with the target-supply property in the AHCI
+DT node, pointing to a (GPIO controlled) regulator. Since we need SATA
+only in U-Boot proper, and use a DM driver for AHCI there, we should use
+the DT instead of hardcoding this.
+
+Add code to the sunxi AHCI driver to check the DT for that regulator and
+enable it, at probe time. Then drop the current code from board.c, which
+was doing that job before.
+This allows us to remove the SATAPWR Kconfig definition and the
+respective values from the defconfigs.
+We also select the generic fixed regulator driver, which handles those
+GPIO controlled regulators.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/Kconfig                             |  2 ++
+ arch/arm/mach-sunxi/Kconfig                  |  8 --------
+ board/sunxi/board.c                          | 16 +---------------
+ configs/A10-OLinuXino-Lime_defconfig         |  1 -
+ configs/A20-OLinuXino-Lime2-eMMC_defconfig   |  1 -
+ configs/A20-OLinuXino-Lime2_defconfig        |  1 -
+ configs/A20-OLinuXino-Lime_defconfig         |  1 -
+ configs/A20-OLinuXino_MICRO-eMMC_defconfig   |  1 -
+ configs/A20-OLinuXino_MICRO_defconfig        |  1 -
+ configs/A20-Olimex-SOM-EVB_defconfig         |  1 -
+ configs/A20-Olimex-SOM204-EVB-eMMC_defconfig |  1 -
+ configs/A20-Olimex-SOM204-EVB_defconfig      |  1 -
+ configs/Cubieboard2_defconfig                |  1 -
+ configs/Cubieboard_defconfig                 |  1 -
+ configs/Cubietruck_defconfig                 |  1 -
+ configs/Itead_Ibox_A20_defconfig             |  1 -
+ configs/Lamobo_R1_defconfig                  |  1 -
+ configs/Linksprite_pcDuino3_Nano_defconfig   |  1 -
+ configs/Linksprite_pcDuino3_defconfig        |  1 -
+ configs/Sinovoip_BPI_M3_defconfig            |  1 -
+ configs/orangepi_plus_defconfig              |  2 +-
+ drivers/ata/ahci_sunxi.c                     |  9 +++++++++
+ 22 files changed, 13 insertions(+), 41 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 8a1e223422..d5a6d293ce 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1130,6 +1130,8 @@ config ARCH_SUNXI
+       imply CMD_GPT
+       imply CMD_UBI if MTD_RAW_NAND
+       imply DISTRO_DEFAULTS
++      imply DM_REGULATOR
++      imply DM_REGULATOR_FIXED
+       imply FAT_WRITE
+       imply FIT
+       imply OF_LIBFDT_OVERLAY
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 6417aee944..c78a553493 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -958,14 +958,6 @@ config VIDEO_LCD_TL059WV5C0
+ endchoice
+-config SATAPWR
+-      string "SATA power pin"
+-      default ""
+-      help
+-        Set the pins used to power the SATA. This takes a string in the
+-        format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of
+-        port H.
+-
+ config GMAC_TX_DELAY
+       int "GMAC Transmit Clock Delay Chain"
+       default 0
+diff --git a/board/sunxi/board.c b/board/sunxi/board.c
+index 827e545032..fe0e7bc2d9 100644
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -187,7 +187,7 @@ enum env_location env_get_location(enum env_operation op, int prio)
+ /* add board specific code here */
+ int board_init(void)
+ {
+-      __maybe_unused int id_pfr1, ret, satapwr_pin, macpwr_pin;
++      __maybe_unused int id_pfr1, ret, macpwr_pin;
+       gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
+@@ -225,20 +225,6 @@ int board_init(void)
+               return ret;
+       /* strcmp() would look better, but doesn't get optimised away. */
+-      if (CONFIG_SATAPWR[0]) {
+-              satapwr_pin = sunxi_name_to_gpio(CONFIG_SATAPWR);
+-              if (satapwr_pin >= 0) {
+-                      gpio_request(satapwr_pin, "satapwr");
+-                      gpio_direction_output(satapwr_pin, 1);
+-
+-                      /*
+-                       * Give the attached SATA device time to power-up
+-                       * to avoid link timeouts
+-                       */
+-                      mdelay(500);
+-              }
+-      }
+-
+       if (CONFIG_MACPWR[0]) {
+               macpwr_pin = sunxi_name_to_gpio(CONFIG_MACPWR);
+               if (macpwr_pin >= 0) {
+diff --git a/configs/A10-OLinuXino-Lime_defconfig b/configs/A10-OLinuXino-Lime_defconfig
+index df4fdfaba4..57e91d0f01 100644
+--- a/configs/A10-OLinuXino-Lime_defconfig
++++ b/configs/A10-OLinuXino-Lime_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=480
+ CONFIG_DRAM_EMR1=4
+ CONFIG_SYS_CLK_FREQ=912000000
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-OLinuXino-Lime2-eMMC_defconfig b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+index be49e9323a..44770ffb04 100644
+--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
++++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+@@ -8,7 +8,6 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_SPL_SPI_SUNXI=y
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/A20-OLinuXino-Lime2_defconfig b/configs/A20-OLinuXino-Lime2_defconfig
+index 43cd28c3dd..e10660c933 100644
+--- a/configs/A20-OLinuXino-Lime2_defconfig
++++ b/configs/A20-OLinuXino-Lime2_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=384
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-OLinuXino-Lime_defconfig b/configs/A20-OLinuXino-Lime_defconfig
+index 7c77f38fba..4ed666a034 100644
+--- a/configs/A20-OLinuXino-Lime_defconfig
++++ b/configs/A20-OLinuXino-Lime_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-OLinuXino_MICRO-eMMC_defconfig b/configs/A20-OLinuXino_MICRO-eMMC_defconfig
+index 02116995a3..ca5869f43d 100644
+--- a/configs/A20-OLinuXino_MICRO-eMMC_defconfig
++++ b/configs/A20-OLinuXino_MICRO-eMMC_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=384
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_VIDEO_VGA=y
+-CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-OLinuXino_MICRO_defconfig b/configs/A20-OLinuXino_MICRO_defconfig
+index 895e8dbcbd..db4270f9b2 100644
+--- a/configs/A20-OLinuXino_MICRO_defconfig
++++ b/configs/A20-OLinuXino_MICRO_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=384
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_I2C1_ENABLE=y
+ CONFIG_VIDEO_VGA=y
+-CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-Olimex-SOM-EVB_defconfig b/configs/A20-Olimex-SOM-EVB_defconfig
+index 5bcc9f9f3c..ac900477d1 100644
+--- a/configs/A20-Olimex-SOM-EVB_defconfig
++++ b/configs/A20-Olimex-SOM-EVB_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=384
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_USB0_VBUS_PIN="PB9"
+ CONFIG_USB0_VBUS_DET="PH5"
+-CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig b/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig
+index e5881090dd..00a98140b3 100644
+--- a/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig
++++ b/configs/A20-Olimex-SOM204-EVB-eMMC_defconfig
+@@ -8,7 +8,6 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_GMAC_TX_DELAY=4
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/A20-Olimex-SOM204-EVB_defconfig b/configs/A20-Olimex-SOM204-EVB_defconfig
+index 592a79a6c7..f4ae3ae6d8 100644
+--- a/configs/A20-Olimex-SOM204-EVB_defconfig
++++ b/configs/A20-Olimex-SOM204-EVB_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=384
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
+-CONFIG_SATAPWR="PC3"
+ CONFIG_GMAC_TX_DELAY=4
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/Cubieboard2_defconfig b/configs/Cubieboard2_defconfig
+index 0c23368741..ef4f11b7c6 100644
+--- a/configs/Cubieboard2_defconfig
++++ b/configs/Cubieboard2_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-cubieboard2"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/Cubieboard_defconfig b/configs/Cubieboard_defconfig
+index 71743f7b8a..ab3f65ad66 100644
+--- a/configs/Cubieboard_defconfig
++++ b/configs/Cubieboard_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun4i-a10-cubieboard"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN4I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/Cubietruck_defconfig b/configs/Cubietruck_defconfig
+index 184f305b19..184143d708 100644
+--- a/configs/Cubietruck_defconfig
++++ b/configs/Cubietruck_defconfig
+@@ -8,7 +8,6 @@ CONFIG_USB0_VBUS_PIN="PH17"
+ CONFIG_USB0_VBUS_DET="PH22"
+ CONFIG_USB0_ID_DET="PH19"
+ CONFIG_VIDEO_VGA=y
+-CONFIG_SATAPWR="PH12"
+ CONFIG_GMAC_TX_DELAY=1
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/Itead_Ibox_A20_defconfig b/configs/Itead_Ibox_A20_defconfig
+index 5d05f33798..d03fa62196 100644
+--- a/configs/Itead_Ibox_A20_defconfig
++++ b/configs/Itead_Ibox_A20_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-itead-ibox"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=480
+-CONFIG_SATAPWR="PB8"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/Lamobo_R1_defconfig b/configs/Lamobo_R1_defconfig
+index 5294608459..9639cb6aad 100644
+--- 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_SATAPWR="PB3"
+ CONFIG_GMAC_TX_DELAY=4
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/Linksprite_pcDuino3_Nano_defconfig b/configs/Linksprite_pcDuino3_Nano_defconfig
+index e3e30a4949..9eb9a918ae 100644
+--- a/configs/Linksprite_pcDuino3_Nano_defconfig
++++ b/configs/Linksprite_pcDuino3_Nano_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=408
+ CONFIG_DRAM_ZQ=122
+ CONFIG_USB1_VBUS_PIN="PH11"
+-CONFIG_SATAPWR="PH2"
+ CONFIG_GMAC_TX_DELAY=3
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/Linksprite_pcDuino3_defconfig b/configs/Linksprite_pcDuino3_defconfig
+index 1fda0db4c9..7db10e685b 100644
+--- a/configs/Linksprite_pcDuino3_defconfig
++++ b/configs/Linksprite_pcDuino3_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=480
+ CONFIG_DRAM_ZQ=122
+-CONFIG_SATAPWR="PH2"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/Sinovoip_BPI_M3_defconfig b/configs/Sinovoip_BPI_M3_defconfig
+index 5116fab52d..5545b3d464 100644
+--- a/configs/Sinovoip_BPI_M3_defconfig
++++ b/configs/Sinovoip_BPI_M3_defconfig
+@@ -13,7 +13,6 @@ CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT"
+ CONFIG_USB0_ID_DET="PH11"
+ CONFIG_USB1_VBUS_PIN="PD24"
+ CONFIG_AXP_GPIO=y
+-CONFIG_SATAPWR="PD25"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_CONSOLE_MUX=y
+ CONFIG_PHY_REALTEK=y
+diff --git a/configs/orangepi_plus_defconfig b/configs/orangepi_plus_defconfig
+index 76de72aa22..ed585881d4 100644
+--- a/configs/orangepi_plus_defconfig
++++ b/configs/orangepi_plus_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_CLK=672
+ CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB1_VBUS_PIN="PG13"
+-CONFIG_SATAPWR="PG11"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+ CONFIG_SPL_SYS_I2C_LEGACY=y
+@@ -16,3 +15,4 @@ CONFIG_SUN8I_EMAC=y
+ CONFIG_SY8106A_POWER=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_OHCI_HCD=y
++CONFIG_USB3_VBUS_PIN="PG11"
+diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
+index 94a3379c53..9064774e66 100644
+--- a/drivers/ata/ahci_sunxi.c
++++ b/drivers/ata/ahci_sunxi.c
+@@ -7,6 +7,7 @@
+ #include <asm/io.h>
+ #include <asm/gpio.h>
+ #include <linux/delay.h>
++#include <power/regulator.h>
+ #define AHCI_PHYCS0R 0x00c0
+ #define AHCI_PHYCS1R 0x00c4
+@@ -74,6 +75,7 @@ static int sunxi_ahci_phy_init(u8 *reg_base)
+ static int sunxi_sata_probe(struct udevice *dev)
+ {
++      struct udevice *reg_dev;
+       ulong base;
+       u8 *reg;
+       int ret;
+@@ -89,6 +91,13 @@ static int sunxi_sata_probe(struct udevice *dev)
+               debug("%s: Failed to init phy (err=%d)\n", __func__, ret);
+               return ret;
+       }
++
++      ret = device_get_supply_regulator(dev, "target-supply", &reg_dev);
++      if (ret == 0) {
++              regulator_set_enable(reg_dev, true);
++              mdelay(500);
++      }
++
+       ret = ahci_probe_scsi(dev, base);
+       if (ret) {
+               debug("%s: Failed to probe (err=%d)\n", __func__, ret);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4001-net-sunxi_emac-Switch-to-new-U-Boot-PHY-API.patch b/package/boot/uboot-sunxi/patches/4001-net-sunxi_emac-Switch-to-new-U-Boot-PHY-API.patch
new file mode 100644 (file)
index 0000000..6865952
--- /dev/null
@@ -0,0 +1,46 @@
+From 02749b4f3d18cb5245b7eed9f60076c41cc308b7 Mon Sep 17 00:00:00 2001
+From: Marek Vasut <marek.vasut+renesas@mailbox.org>
+Date: Wed, 31 May 2023 00:51:24 +0200
+Subject: [PATCH 4001/4052] net: sunxi_emac: Switch to new U-Boot PHY API
+
+Use new U-Boot phy_connect() API which also supports fixed PHYs.
+
+Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sunxi_emac.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
+index ad9e1abd16..4c90d4b498 100644
+--- a/drivers/net/sunxi_emac.c
++++ b/drivers/net/sunxi_emac.c
+@@ -248,10 +248,10 @@ static int emac_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev)
+ {
+-      int ret, mask = 0xffffffff;
++      int ret, mask = -1;
+ #ifdef CONFIG_PHY_ADDR
+-      mask = 1 << CONFIG_PHY_ADDR;
++      mask = CONFIG_PHY_ADDR;
+ #endif
+       priv->bus = mdio_alloc();
+@@ -269,11 +269,10 @@ static int sunxi_emac_init_phy(struct emac_eth_dev *priv, void *dev)
+       if (ret)
+               return ret;
+-      priv->phydev = phy_find_by_mask(priv->bus, mask);
++      priv->phydev = phy_connect(priv->bus, mask, dev, PHY_INTERFACE_MODE_MII);
+       if (!priv->phydev)
+               return -ENODEV;
+-      phy_connect_dev(priv->phydev, dev, PHY_INTERFACE_MODE_MII);
+       phy_config(priv->phydev);
+       return 0;
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4002-net-sunxi_emac-chase-DT-nodes-to-find-PHY-regulator.patch b/package/boot/uboot-sunxi/patches/4002-net-sunxi_emac-chase-DT-nodes-to-find-PHY-regulator.patch
new file mode 100644 (file)
index 0000000..5ea3560
--- /dev/null
@@ -0,0 +1,102 @@
+From fbdfae3efbd295bd4ea4ad02c2af1a8dca649238 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:47 +0100
+Subject: [PATCH 4002/4052] net: sunxi_emac: chase DT nodes to find PHY
+ regulator
+
+At the moment the sun4i EMAC driver relies on hardcoded CONFIG_MACPWR
+Kconfig symbols to enable potential PHY regulators. As we want to get rid
+of those, we need to find the regulator by chasing up the DT.
+
+The sun4i-emac binding puts the PHY regulator into the MDIO node, which
+is the parent of the PHY device. U-Boot does not have (and does not
+need) an MDIO driver, so we need to chase down the regulator through the
+EMAC node: we follow the "phy-handle" property to find the PHY node,
+then go up to its parent, where we find the "phy-supply" link to the
+regulator. Let U-Boot find the associated regulator device, and put that
+into the private device struct, so we can find and enable the regulator
+at probe time, later.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+---
+ drivers/net/sunxi_emac.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
+index 4c90d4b498..f1f0e5bbbb 100644
+--- a/drivers/net/sunxi_emac.c
++++ b/drivers/net/sunxi_emac.c
+@@ -17,6 +17,7 @@
+ #include <net.h>
+ #include <asm/io.h>
+ #include <asm/arch/clock.h>
++#include <power/regulator.h>
+ /* EMAC register  */
+ struct emac_regs {
+@@ -165,6 +166,7 @@ struct emac_eth_dev {
+       struct phy_device *phydev;
+       int link_printed;
+       uchar rx_buf[EMAC_RX_BUFSIZE];
++      struct udevice *phy_reg;
+ };
+ struct emac_rxhdr {
+@@ -572,6 +574,9 @@ static int sunxi_emac_eth_probe(struct udevice *dev)
+       if (ret)
+               return ret;
++      if (priv->phy_reg)
++              regulator_set_enable(priv->phy_reg, true);
++
+       return sunxi_emac_init_phy(priv, dev);
+ }
+@@ -585,9 +590,43 @@ static const struct eth_ops sunxi_emac_eth_ops = {
+ static int sunxi_emac_eth_of_to_plat(struct udevice *dev)
+ {
+       struct eth_pdata *pdata = dev_get_plat(dev);
++      struct emac_eth_dev *priv = dev_get_priv(dev);
++      struct ofnode_phandle_args args;
++      ofnode mdio_node;
++      int ret;
+       pdata->iobase = dev_read_addr(dev);
++      /* The PHY regulator is in the MDIO node, not the EMAC or PHY node. */
++      ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, &args);
++      if (ret) {
++              dev_err(dev, "failed to get PHY node\n");
++              return ret;
++      }
++
++      /*
++       * U-Boot does not have (and does not need) a device driver for the
++       * MDIO device, so just "pass through" that DT node to get to the
++       * regulator phandle.
++       * The PHY regulator is optional, though: ignore if we cannot find
++       * a phy-supply property.
++       */
++      mdio_node = ofnode_get_parent(args.node);
++      ret= ofnode_parse_phandle_with_args(mdio_node, "phy-supply", NULL, 0, 0,
++                                          &args);
++      if (ret && ret != -ENOENT) {
++              dev_err(dev, "failed to get PHY supply node\n");
++              return ret;
++      }
++      if (!ret) {
++              ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, args.node,
++                                                &priv->phy_reg);
++              if (ret) {
++                      dev_err(dev, "failed to get PHY regulator node\n");
++                      return ret;
++              }
++      }
++
+       return 0;
+ }
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4003-net-sun8i-emac-Add-a-structure-for-variant-data.patch b/package/boot/uboot-sunxi/patches/4003-net-sun8i-emac-Add-a-structure-for-variant-data.patch
new file mode 100644 (file)
index 0000000..6ada199
--- /dev/null
@@ -0,0 +1,152 @@
+From 2c3f0b528257cb37445a63c7f25813c399f8b742 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Jan 2023 16:51:02 -0600
+Subject: [PATCH 4003/4052] net: sun8i-emac: Add a structure for variant data
+
+Currently, EMAC variants are distinguished by their identity, but this
+gets unwieldy as more overlapping variants are added. Add a structure so
+we can describe the individual feature differences between the variants.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sun8i_emac.c | 65 +++++++++++++++++++++++++++-------------
+ 1 file changed, 45 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index e800a326b8..986e565cd8 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -127,7 +127,7 @@
+ DECLARE_GLOBAL_DATA_PTR;
+-enum emac_variant {
++enum emac_variant_id {
+       A83T_EMAC = 1,
+       H3_EMAC,
+       A64_EMAC,
+@@ -135,6 +135,10 @@ enum emac_variant {
+       H6_EMAC,
+ };
++struct emac_variant {
++      enum emac_variant_id    variant;
++};
++
+ struct emac_dma_desc {
+       u32 status;
+       u32 ctl_size;
+@@ -160,7 +164,7 @@ struct emac_eth_dev {
+       u32 tx_slot;
+       bool use_internal_phy;
+-      enum emac_variant variant;
++      const struct emac_variant *variant;
+       void *mac_reg;
+       phys_addr_t sysctl_reg;
+       struct phy_device *phydev;
+@@ -317,7 +321,7 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+ {
+       u32 reg;
+-      if (priv->variant == R40_GMAC) {
++      if (priv->variant->variant == R40_GMAC) {
+               /* Select RGMII for R40 */
+               reg = readl(priv->sysctl_reg + 0x164);
+               reg |= SC_ETCS_INT_GMII |
+@@ -333,9 +337,9 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+       reg = sun8i_emac_set_syscon_ephy(priv, reg);
+       reg &= ~(SC_ETCS_MASK | SC_EPIT);
+-      if (priv->variant == H3_EMAC ||
+-          priv->variant == A64_EMAC ||
+-          priv->variant == H6_EMAC)
++      if (priv->variant->variant == H3_EMAC ||
++          priv->variant->variant == A64_EMAC ||
++          priv->variant->variant == H6_EMAC)
+               reg &= ~SC_RMII_EN;
+       switch (priv->interface) {
+@@ -349,9 +353,9 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+               reg |= SC_EPIT | SC_ETCS_INT_GMII;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+-              if (priv->variant == H3_EMAC ||
+-                  priv->variant == A64_EMAC ||
+-                  priv->variant == H6_EMAC) {
++              if (priv->variant->variant == H3_EMAC ||
++                  priv->variant->variant == A64_EMAC ||
++                  priv->variant->variant == H6_EMAC) {
+                       reg |= SC_RMII_EN | SC_ETCS_EXT_GMII;
+               break;
+               }
+@@ -806,7 +810,7 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+               return -EINVAL;
+       }
+-      priv->variant = dev_get_driver_data(dev);
++      priv->variant = (const void *)dev_get_driver_data(dev);
+       if (!priv->variant) {
+               printf("%s: Missing variant\n", __func__);
+@@ -860,7 +864,7 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+       if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
+               return -EINVAL;
+-      if (priv->variant == H3_EMAC) {
++      if (priv->variant->variant == H3_EMAC) {
+               ret = sun8i_handle_internal_phy(dev, priv);
+               if (ret)
+                       return ret;
+@@ -900,16 +904,37 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+       return 0;
+ }
++static const struct emac_variant emac_variant_a83t = {
++      .variant                = A83T_EMAC,
++};
++
++static const struct emac_variant emac_variant_h3 = {
++      .variant                = H3_EMAC,
++};
++
++static const struct emac_variant emac_variant_r40 = {
++      .variant                = R40_GMAC,
++};
++
++static const struct emac_variant emac_variant_a64 = {
++      .variant                = A64_EMAC,
++};
++
++static const struct emac_variant emac_variant_h6 = {
++      .variant                = H6_EMAC,
++};
++
+ static const struct udevice_id sun8i_emac_eth_ids[] = {
+-      {.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC },
+-      {.compatible = "allwinner,sun50i-a64-emac",
+-              .data = (uintptr_t)A64_EMAC },
+-      {.compatible = "allwinner,sun8i-a83t-emac",
+-              .data = (uintptr_t)A83T_EMAC },
+-      {.compatible = "allwinner,sun8i-r40-gmac",
+-              .data = (uintptr_t)R40_GMAC },
+-      {.compatible = "allwinner,sun50i-h6-emac",
+-              .data = (uintptr_t)H6_EMAC },
++      { .compatible = "allwinner,sun8i-a83t-emac",
++        .data = (ulong)&emac_variant_a83t },
++      { .compatible = "allwinner,sun8i-h3-emac",
++        .data = (ulong)&emac_variant_h3 },
++      { .compatible = "allwinner,sun8i-r40-gmac",
++        .data = (ulong)&emac_variant_r40 },
++      { .compatible = "allwinner,sun50i-a64-emac",
++        .data = (ulong)&emac_variant_a64 },
++      { .compatible = "allwinner,sun50i-h6-emac",
++        .data = (ulong)&emac_variant_h6 },
+       { }
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4004-net-sun8i-emac-Add-a-flag-for-RMII-support.patch b/package/boot/uboot-sunxi/patches/4004-net-sun8i-emac-Add-a-flag-for-RMII-support.patch
new file mode 100644 (file)
index 0000000..80f5aa8
--- /dev/null
@@ -0,0 +1,77 @@
+From 0050a54e83e4e7c094a1ff1b3f67a4d9aebc22d8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Jan 2023 16:51:03 -0600
+Subject: [PATCH 4004/4052] net: sun8i-emac: Add a flag for RMII support
+
+Describe this feature instead of using the SoC ID.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sun8i_emac.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index 986e565cd8..f232b8f087 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -137,6 +137,7 @@ enum emac_variant_id {
+ struct emac_variant {
+       enum emac_variant_id    variant;
++      bool                    support_rmii;
+ };
+ struct emac_dma_desc {
+@@ -337,9 +338,7 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+       reg = sun8i_emac_set_syscon_ephy(priv, reg);
+       reg &= ~(SC_ETCS_MASK | SC_EPIT);
+-      if (priv->variant->variant == H3_EMAC ||
+-          priv->variant->variant == A64_EMAC ||
+-          priv->variant->variant == H6_EMAC)
++      if (priv->variant->support_rmii)
+               reg &= ~SC_RMII_EN;
+       switch (priv->interface) {
+@@ -353,13 +352,10 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+               reg |= SC_EPIT | SC_ETCS_INT_GMII;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+-              if (priv->variant->variant == H3_EMAC ||
+-                  priv->variant->variant == A64_EMAC ||
+-                  priv->variant->variant == H6_EMAC) {
++              if (priv->variant->support_rmii) {
+                       reg |= SC_RMII_EN | SC_ETCS_EXT_GMII;
+-              break;
++                      break;
+               }
+-              /* RMII not supported on A83T */
+       default:
+               debug("%s: Invalid PHY interface\n", __func__);
+               return -EINVAL;
+@@ -910,6 +906,7 @@ static const struct emac_variant emac_variant_a83t = {
+ static const struct emac_variant emac_variant_h3 = {
+       .variant                = H3_EMAC,
++      .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_r40 = {
+@@ -918,10 +915,12 @@ static const struct emac_variant emac_variant_r40 = {
+ static const struct emac_variant emac_variant_a64 = {
+       .variant                = A64_EMAC,
++      .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_h6 = {
+       .variant                = H6_EMAC,
++      .support_rmii           = true,
+ };
+ static const struct udevice_id sun8i_emac_eth_ids[] = {
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4005-net-sun8i-emac-Add-a-flag-for-the-internal-PHY-switc.patch b/package/boot/uboot-sunxi/patches/4005-net-sun8i-emac-Add-a-flag-for-the-internal-PHY-switc.patch
new file mode 100644 (file)
index 0000000..47b36f3
--- /dev/null
@@ -0,0 +1,47 @@
+From 1c627c8d633cb2bc98db5897a8ff2b5e56c232fe Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Jan 2023 16:51:04 -0600
+Subject: [PATCH 4005/4052] net: sun8i-emac: Add a flag for the internal PHY
+ switch
+
+Describe this feature instead of using the SoC ID.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sun8i_emac.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index f232b8f087..36cc2498b5 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -137,6 +137,7 @@ enum emac_variant_id {
+ struct emac_variant {
+       enum emac_variant_id    variant;
++      bool                    soc_has_internal_phy;
+       bool                    support_rmii;
+ };
+@@ -860,7 +861,7 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+       if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
+               return -EINVAL;
+-      if (priv->variant->variant == H3_EMAC) {
++      if (priv->variant->soc_has_internal_phy) {
+               ret = sun8i_handle_internal_phy(dev, priv);
+               if (ret)
+                       return ret;
+@@ -906,6 +907,7 @@ static const struct emac_variant emac_variant_a83t = {
+ static const struct emac_variant emac_variant_h3 = {
+       .variant                = H3_EMAC,
++      .soc_has_internal_phy   = true,
+       .support_rmii           = true,
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4006-net-sun8i-emac-Use-common-syscon-setup-for-R40.patch b/package/boot/uboot-sunxi/patches/4006-net-sun8i-emac-Use-common-syscon-setup-for-R40.patch
new file mode 100644 (file)
index 0000000..444f6d1
--- /dev/null
@@ -0,0 +1,133 @@
+From a31d1f97e36d42f80f3d04b07df121b6da142dc8 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Jan 2023 16:51:05 -0600
+Subject: [PATCH 4006/4052] 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.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sun8i_emac.c | 32 +++++++++++++++-----------------
+ 1 file changed, 15 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index 36cc2498b5..231aac19e3 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -137,6 +137,7 @@ enum emac_variant_id {
+ struct emac_variant {
+       enum emac_variant_id    variant;
++      uint                    syscon_offset;
+       bool                    soc_has_internal_phy;
+       bool                    support_rmii;
+ };
+@@ -168,7 +169,7 @@ struct emac_eth_dev {
+       const struct 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;
+@@ -323,18 +324,7 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+ {
+       u32 reg;
+-      if (priv->variant->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);
+@@ -370,7 +360,7 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,
+               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;
+ }
+@@ -793,6 +783,7 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+       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;
+@@ -838,13 +829,15 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+                     __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;
+       }
++      priv->sysctl_reg = (void *)syscon_base + priv->variant->syscon_offset;
++
+       pdata->phy_interface = -1;
+       priv->phyaddr = -1;
+       priv->use_internal_phy = false;
+@@ -903,25 +896,30 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+ static const struct emac_variant emac_variant_a83t = {
+       .variant                = A83T_EMAC,
++      .syscon_offset          = 0x30,
+ };
+ static const struct emac_variant emac_variant_h3 = {
+       .variant                = H3_EMAC,
++      .syscon_offset          = 0x30,
+       .soc_has_internal_phy   = true,
+       .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_r40 = {
+       .variant                = R40_GMAC,
++      .syscon_offset          = 0x164,
+ };
+ static const struct emac_variant emac_variant_a64 = {
+       .variant                = A64_EMAC,
++      .syscon_offset          = 0x30,
+       .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_h6 = {
+       .variant                = H6_EMAC,
++      .syscon_offset          = 0x30,
+       .support_rmii           = true,
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4007-net-sun8i-emac-Remove-the-SoC-variant-ID.patch b/package/boot/uboot-sunxi/patches/4007-net-sun8i-emac-Remove-the-SoC-variant-ID.patch
new file mode 100644 (file)
index 0000000..5e521ac
--- /dev/null
@@ -0,0 +1,70 @@
+From 645050bccaab8ab2b27077f2801da4b723ab8268 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Sun, 22 Jan 2023 16:51:06 -0600
+Subject: [PATCH 4007/4052] net: sun8i-emac: Remove the SoC variant ID
+
+Now that all differences in functionality are covered by individual
+flags, remove the enumeration of SoC variants.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/sun8i_emac.c | 14 --------------
+ 1 file changed, 14 deletions(-)
+
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index 231aac19e3..04c3274fbe 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -127,16 +127,7 @@
+ DECLARE_GLOBAL_DATA_PTR;
+-enum emac_variant_id {
+-      A83T_EMAC = 1,
+-      H3_EMAC,
+-      A64_EMAC,
+-      R40_GMAC,
+-      H6_EMAC,
+-};
+-
+ struct emac_variant {
+-      enum emac_variant_id    variant;
+       uint                    syscon_offset;
+       bool                    soc_has_internal_phy;
+       bool                    support_rmii;
+@@ -895,30 +886,25 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+ }
+ static const struct emac_variant emac_variant_a83t = {
+-      .variant                = A83T_EMAC,
+       .syscon_offset          = 0x30,
+ };
+ static const struct emac_variant emac_variant_h3 = {
+-      .variant                = H3_EMAC,
+       .syscon_offset          = 0x30,
+       .soc_has_internal_phy   = true,
+       .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_r40 = {
+-      .variant                = R40_GMAC,
+       .syscon_offset          = 0x164,
+ };
+ static const struct emac_variant emac_variant_a64 = {
+-      .variant                = A64_EMAC,
+       .syscon_offset          = 0x30,
+       .support_rmii           = true,
+ };
+ static const struct emac_variant emac_variant_h6 = {
+-      .variant                = H6_EMAC,
+       .syscon_offset          = 0x30,
+       .support_rmii           = true,
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4008-sunxi-remove-CONFIG_MACPWR.patch b/package/boot/uboot-sunxi/patches/4008-sunxi-remove-CONFIG_MACPWR.patch
new file mode 100644 (file)
index 0000000..3d20b50
--- /dev/null
@@ -0,0 +1,399 @@
+From e7d4da422816303af8fcbcb2e6d9b09843d31b33 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:48 +0100
+Subject: [PATCH 4008/4052] sunxi: remove CONFIG_MACPWR
+
+The CONFIG_MACPWR Kconfig symbol is used to point to a GPIO that enables
+the power for the Ethernet "MAC" (mostly PHY, really).
+In the DT this is described with the phy-supply property in the MAC DT
+node, pointing to a (GPIO controlled) regulator. Since we need Ethernet
+only in U-Boot proper, and use a DM driver there, we should use the DT
+instead of hardcoding this.
+
+Add code to the sun8i_emac and sunxi_emac drivers to check the DT for
+that regulator and enable it, at probe time. Then drop the current code
+from board.c, which was doing that job before.
+This allows us to remove the MACPWR Kconfig definition and the respective
+values from the defconfigs.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/mach-sunxi/Kconfig           |  7 -------
+ board/sunxi/board.c                   | 12 +-----------
+ configs/Bananapi_M2_Ultra_defconfig   |  1 -
+ configs/Bananapi_defconfig            |  1 -
+ configs/Bananapro_defconfig           |  1 -
+ configs/Lamobo_R1_defconfig           |  1 -
+ configs/Mele_A1000_defconfig          |  1 -
+ configs/Orangepi_defconfig            |  1 -
+ configs/Orangepi_mini_defconfig       |  1 -
+ configs/bananapi_m1_plus_defconfig    |  1 -
+ configs/bananapi_m2_plus_h3_defconfig |  1 -
+ configs/bananapi_m2_plus_h5_defconfig |  1 -
+ configs/i12-tvbox_defconfig           |  1 -
+ configs/jesurun_q5_defconfig          |  1 -
+ configs/mixtile_loftq_defconfig       |  1 -
+ configs/nanopi_m1_plus_defconfig      |  1 -
+ configs/nanopi_neo_plus2_defconfig    |  1 -
+ configs/nanopi_r1s_h5_defconfig       |  1 -
+ configs/orangepi_pc2_defconfig        |  1 -
+ configs/orangepi_plus2e_defconfig     |  1 -
+ configs/orangepi_plus_defconfig       |  1 -
+ configs/pine_h64_defconfig            |  1 -
+ configs/zeropi_defconfig              |  1 -
+ drivers/net/sun8i_emac.c              |  9 +++++++--
+ 24 files changed, 8 insertions(+), 41 deletions(-)
+
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index c78a553493..d716054f72 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -645,13 +645,6 @@ config OLD_SUNXI_KERNEL_COMPAT
+       Set this to enable various workarounds for old kernels, this results in
+       sub-optimal settings for newer kernels, only enable if needed.
+-config MACPWR
+-      string "MAC power pin"
+-      default ""
+-      help
+-        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
+diff --git a/board/sunxi/board.c b/board/sunxi/board.c
+index fe0e7bc2d9..9900c66ed0 100644
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -187,7 +187,7 @@ enum env_location env_get_location(enum env_operation op, int prio)
+ /* add board specific code here */
+ int board_init(void)
+ {
+-      __maybe_unused int id_pfr1, ret, macpwr_pin;
++      __maybe_unused int id_pfr1, ret;
+       gd->bd->bi_boot_params = (PHYS_SDRAM_0 + 0x100);
+@@ -224,15 +224,6 @@ int board_init(void)
+       if (ret)
+               return ret;
+-      /* strcmp() would look better, but doesn't get optimised away. */
+-      if (CONFIG_MACPWR[0]) {
+-              macpwr_pin = sunxi_name_to_gpio(CONFIG_MACPWR);
+-              if (macpwr_pin >= 0) {
+-                      gpio_request(macpwr_pin, "macpwr");
+-                      gpio_direction_output(macpwr_pin, 1);
+-              }
+-      }
+-
+ #if CONFIG_IS_ENABLED(DM_I2C)
+       /*
+        * Temporary workaround for enabling I2C clocks until proper sunxi DM
+@@ -240,7 +231,6 @@ int board_init(void)
+        */
+       i2c_init_board();
+ #endif
+-
+       eth_init_board();
+       return 0;
+diff --git a/configs/Bananapi_M2_Ultra_defconfig b/configs/Bananapi_M2_Ultra_defconfig
+index a5fe76af56..2cc7bbbd8b 100644
+--- a/configs/Bananapi_M2_Ultra_defconfig
++++ b/configs/Bananapi_M2_Ultra_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-r40-bananapi-m2-ultra"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_R40=y
+ CONFIG_DRAM_CLK=576
+-CONFIG_MACPWR="PA17"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB1_VBUS_PIN="PH23"
+ CONFIG_USB2_VBUS_PIN="PH23"
+diff --git a/configs/Bananapi_defconfig b/configs/Bananapi_defconfig
+index 6c2a1f630e..f4910ba13a 100644
+--- a/configs/Bananapi_defconfig
++++ b/configs/Bananapi_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-bananapi"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_VIDEO_COMPOSITE=y
+ CONFIG_GMAC_TX_DELAY=3
+ CONFIG_AHCI=y
+diff --git a/configs/Bananapro_defconfig b/configs/Bananapro_defconfig
+index 94fd74754e..02be8971df 100644
+--- a/configs/Bananapro_defconfig
++++ b/configs/Bananapro_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-bananapro"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_USB1_VBUS_PIN="PH0"
+ CONFIG_USB2_VBUS_PIN="PH1"
+ CONFIG_VIDEO_COMPOSITE=y
+diff --git a/configs/Lamobo_R1_defconfig b/configs/Lamobo_R1_defconfig
+index 9639cb6aad..66f57ab3c8 100644
+--- a/configs/Lamobo_R1_defconfig
++++ b/configs/Lamobo_R1_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-lamobo-r1"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_GMAC_TX_DELAY=4
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/Mele_A1000_defconfig b/configs/Mele_A1000_defconfig
+index f5b6d908cd..9ac2e4839d 100644
+--- a/configs/Mele_A1000_defconfig
++++ b/configs/Mele_A1000_defconfig
+@@ -3,7 +3,6 @@ CONFIG_ARCH_SUNXI=y
+ CONFIG_DEFAULT_DEVICE_TREE="sun4i-a10-a1000"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN4I=y
+-CONFIG_MACPWR="PH15"
+ CONFIG_VIDEO_VGA=y
+ CONFIG_VIDEO_COMPOSITE=y
+ CONFIG_AHCI=y
+diff --git a/configs/Orangepi_defconfig b/configs/Orangepi_defconfig
+index c89a9a1f9d..53edf525ec 100644
+--- a/configs/Orangepi_defconfig
++++ b/configs/Orangepi_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-orangepi"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_USB1_VBUS_PIN="PH26"
+ CONFIG_USB2_VBUS_PIN="PH22"
+ CONFIG_VIDEO_VGA=y
+diff --git a/configs/Orangepi_mini_defconfig b/configs/Orangepi_mini_defconfig
+index fe9ce808a1..ccf3267017 100644
+--- a/configs/Orangepi_mini_defconfig
++++ b/configs/Orangepi_mini_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-orangepi-mini"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=3
+ CONFIG_USB1_VBUS_PIN="PH26"
+ CONFIG_USB2_VBUS_PIN="PH22"
+diff --git a/configs/bananapi_m1_plus_defconfig b/configs/bananapi_m1_plus_defconfig
+index 0fbb619d62..a432a01f6b 100644
+--- a/configs/bananapi_m1_plus_defconfig
++++ b/configs/bananapi_m1_plus_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-bananapi-m1-plus"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=432
+-CONFIG_MACPWR="PH23"
+ CONFIG_VIDEO_COMPOSITE=y
+ CONFIG_GMAC_TX_DELAY=3
+ CONFIG_AHCI=y
+diff --git a/configs/bananapi_m2_plus_h3_defconfig b/configs/bananapi_m2_plus_h3_defconfig
+index 26ced59fb0..a8f9b5044b 100644
+--- a/configs/bananapi_m2_plus_h3_defconfig
++++ b/configs/bananapi_m2_plus_h3_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-bananapi-m2-plus"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+diff --git a/configs/bananapi_m2_plus_h5_defconfig b/configs/bananapi_m2_plus_h5_defconfig
+index fb6c945919..1634f62619 100644
+--- a/configs/bananapi_m2_plus_h5_defconfig
++++ b/configs/bananapi_m2_plus_h5_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-bananapi-m2-plus"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H5=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+diff --git a/configs/i12-tvbox_defconfig b/configs/i12-tvbox_defconfig
+index 257dd89af4..37f0f53ae7 100644
+--- a/configs/i12-tvbox_defconfig
++++ b/configs/i12-tvbox_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-i12-tvbox"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN7I=y
+ CONFIG_DRAM_CLK=384
+-CONFIG_MACPWR="PH21"
+ CONFIG_VIDEO_COMPOSITE=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/jesurun_q5_defconfig b/configs/jesurun_q5_defconfig
+index 0ff666b2ee..c99be7cea4 100644
+--- a/configs/jesurun_q5_defconfig
++++ b/configs/jesurun_q5_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun4i-a10-jesurun-q5"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN4I=y
+ CONFIG_DRAM_CLK=312
+-CONFIG_MACPWR="PH19"
+ CONFIG_USB0_VBUS_PIN="PB9"
+ CONFIG_VIDEO_COMPOSITE=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/mixtile_loftq_defconfig b/configs/mixtile_loftq_defconfig
+index 0e4cdc4467..2f92228eb7 100644
+--- a/configs/mixtile_loftq_defconfig
++++ b/configs/mixtile_loftq_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun6i-a31-mixtile-loftq"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN6I=y
+ CONFIG_DRAM_ZQ=251
+-CONFIG_MACPWR="PA21"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB1_VBUS_PIN="PH24"
+ CONFIG_USB2_VBUS_PIN=""
+diff --git a/configs/nanopi_m1_plus_defconfig b/configs/nanopi_m1_plus_defconfig
+index 76655d79ae..078e98b644 100644
+--- a/configs/nanopi_m1_plus_defconfig
++++ b/configs/nanopi_m1_plus_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-nanopi-m1-plus"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=408
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+diff --git a/configs/nanopi_neo_plus2_defconfig b/configs/nanopi_neo_plus2_defconfig
+index 924ff38f17..85ff31c6fe 100644
+--- a/configs/nanopi_neo_plus2_defconfig
++++ b/configs/nanopi_neo_plus2_defconfig
+@@ -6,7 +6,6 @@ CONFIG_MACH_SUN50I_H5=y
+ CONFIG_DRAM_CLK=408
+ CONFIG_DRAM_ZQ=3881977
+ # CONFIG_DRAM_ODT_EN is not set
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+diff --git a/configs/nanopi_r1s_h5_defconfig b/configs/nanopi_r1s_h5_defconfig
+index 27cf172d72..2a6f94afe4 100644
+--- a/configs/nanopi_r1s_h5_defconfig
++++ b/configs/nanopi_r1s_h5_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_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SUN8I_EMAC=y
+diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig
+index 777af8c60e..fb6fbaf787 100644
+--- a/configs/orangepi_pc2_defconfig
++++ b/configs/orangepi_pc2_defconfig
+@@ -5,7 +5,6 @@ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H5=y
+ CONFIG_DRAM_CLK=672
+ CONFIG_DRAM_ZQ=3881977
+-CONFIG_MACPWR="PD6"
+ CONFIG_SPL_SPI_SUNXI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/orangepi_plus2e_defconfig b/configs/orangepi_plus2e_defconfig
+index 138a6a72b8..5e2cbc48ea 100644
+--- a/configs/orangepi_plus2e_defconfig
++++ b/configs/orangepi_plus2e_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-orangepi-plus2e"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_SPL_I2C=y
+diff --git a/configs/orangepi_plus_defconfig b/configs/orangepi_plus_defconfig
+index ed585881d4..092ce77a6c 100644
+--- a/configs/orangepi_plus_defconfig
++++ b/configs/orangepi_plus_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-orangepi-plus"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=672
+-CONFIG_MACPWR="PD6"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB1_VBUS_PIN="PG13"
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig
+index 6dac6098d0..4712b8e469 100644
+--- a/configs/pine_h64_defconfig
++++ b/configs/pine_h64_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-pine-h64"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN50I_H6=y
+ CONFIG_SUNXI_DRAM_H6_LPDDR3=y
+-CONFIG_MACPWR="PC16"
+ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB3_VBUS_PIN="PL5"
+ CONFIG_SPL_SPI_SUNXI=y
+diff --git a/configs/zeropi_defconfig b/configs/zeropi_defconfig
+index 11f3715e6d..7901bffd15 100644
+--- a/configs/zeropi_defconfig
++++ b/configs/zeropi_defconfig
+@@ -4,7 +4,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-zeropi"
+ CONFIG_SPL=y
+ CONFIG_MACH_SUN8I_H3=y
+ CONFIG_DRAM_CLK=408
+-CONFIG_MACPWR="PD6"
+ # CONFIG_VIDEO_DE2 is not set
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+ CONFIG_CONSOLE_MUX=y
+diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
+index 04c3274fbe..7b60a60ad5 100644
+--- a/drivers/net/sun8i_emac.c
++++ b/drivers/net/sun8i_emac.c
+@@ -29,6 +29,7 @@
+ #include <net.h>
+ #include <reset.h>
+ #include <wait_bit.h>
++#include <power/regulator.h>
+ #define MDIO_CMD_MII_BUSY             BIT(0)
+ #define MDIO_CMD_MII_WRITE            BIT(1)
+@@ -167,9 +168,8 @@ struct emac_eth_dev {
+       struct clk ephy_clk;
+       struct reset_ctl tx_rst;
+       struct reset_ctl ephy_rst;
+-#if CONFIG_IS_ENABLED(DM_GPIO)
+       struct gpio_desc reset_gpio;
+-#endif
++      struct udevice *phy_reg;
+ };
+@@ -720,6 +720,9 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
+       sun8i_emac_set_syscon(sun8i_pdata, priv);
++      if (priv->phy_reg)
++              regulator_set_enable(priv->phy_reg, true);
++
+       sun8i_mdio_init(dev->name, dev);
+       priv->bus = miiphy_get_dev_by_name(dev->name);
+@@ -829,6 +832,8 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev)
+       priv->sysctl_reg = (void *)syscon_base + priv->variant->syscon_offset;
++      device_get_supply_regulator(dev, "phy-supply", &priv->phy_reg);
++
+       pdata->phy_interface = -1;
+       priv->phyaddr = -1;
+       priv->use_internal_phy = false;
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4009-pinctrl-sunxi-add-GPIO-in-out-wrappers.patch b/package/boot/uboot-sunxi/patches/4009-pinctrl-sunxi-add-GPIO-in-out-wrappers.patch
new file mode 100644 (file)
index 0000000..f42b0e9
--- /dev/null
@@ -0,0 +1,169 @@
+From 23bc60ec0f0a66e5afca0dbc71b42fc4d0216153 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:49 +0100
+Subject: [PATCH 4009/4052] pinctrl: sunxi: add GPIO in/out wrappers
+
+So far we were open-coding the pincontroller's GPIO output/input access
+in each function using that.
+
+Provide functions that wrap that nicely, and follow the existing pattern
+(set/get_{bank,}), so users don't need to know about the internals, and
+we can abstract the new D1 pinctrl more easily.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h |  4 +++
+ arch/arm/mach-sunxi/pinmux.c           | 28 +++++++++++++++
+ drivers/gpio/sunxi_gpio.c              | 49 +++++---------------------
+ 3 files changed, 40 insertions(+), 41 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
+index 437e86479c..2e7c84e410 100644
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -222,6 +222,10 @@ void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val);
+ void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
+ int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset);
+ int sunxi_gpio_get_cfgpin(u32 pin);
++void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio, int pin, bool set);
++void sunxi_gpio_set_output(u32 pin, bool set);
++int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin);
++int sunxi_gpio_get_output(u32 pin);
+ void sunxi_gpio_set_drv(u32 pin, u32 val);
+ void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val);
+ void sunxi_gpio_set_pull(u32 pin, u32 val);
+diff --git a/arch/arm/mach-sunxi/pinmux.c b/arch/arm/mach-sunxi/pinmux.c
+index c95fcee9f6..751cac8e09 100644
+--- a/arch/arm/mach-sunxi/pinmux.c
++++ b/arch/arm/mach-sunxi/pinmux.c
+@@ -45,6 +45,34 @@ int sunxi_gpio_get_cfgpin(u32 pin)
+       return sunxi_gpio_get_cfgbank(pio, pin);
+ }
++void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio, int pin, bool set)
++{
++      u32 mask = 1U << GPIO_NUM(pin);
++
++      clrsetbits_le32(&pio->dat, set ? 0 : mask, set ? mask : 0);
++}
++
++void sunxi_gpio_set_output(u32 pin, bool set)
++{
++      u32 bank = GPIO_BANK(pin);
++      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++
++      sunxi_gpio_set_output_bank(pio, pin, set);
++}
++
++int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin)
++{
++      return !!(readl(&pio->dat) & (1U << GPIO_NUM(pin)));
++}
++
++int sunxi_gpio_get_output(u32 pin)
++{
++      u32 bank = GPIO_BANK(pin);
++      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++
++      return sunxi_gpio_get_output_bank(pio, pin);
++}
++
+ void sunxi_gpio_set_drv(u32 pin, u32 val)
+ {
+       u32 bank = GPIO_BANK(pin);
+diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
+index 1e85db179a..6796375d35 100644
+--- a/drivers/gpio/sunxi_gpio.c
++++ b/drivers/gpio/sunxi_gpio.c
+@@ -19,37 +19,6 @@
+ #include <dt-bindings/gpio/gpio.h>
+ #if !CONFIG_IS_ENABLED(DM_GPIO)
+-static int sunxi_gpio_output(u32 pin, u32 val)
+-{
+-      u32 dat;
+-      u32 bank = GPIO_BANK(pin);
+-      u32 num = GPIO_NUM(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+-
+-      dat = readl(&pio->dat);
+-      if (val)
+-              dat |= 0x1 << num;
+-      else
+-              dat &= ~(0x1 << num);
+-
+-      writel(dat, &pio->dat);
+-
+-      return 0;
+-}
+-
+-static int sunxi_gpio_input(u32 pin)
+-{
+-      u32 dat;
+-      u32 bank = GPIO_BANK(pin);
+-      u32 num = GPIO_NUM(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
+-
+-      dat = readl(&pio->dat);
+-      dat >>= num;
+-
+-      return dat & 0x1;
+-}
+-
+ int gpio_request(unsigned gpio, const char *label)
+ {
+       return 0;
+@@ -70,18 +39,21 @@ int gpio_direction_input(unsigned gpio)
+ int gpio_direction_output(unsigned gpio, int value)
+ {
+       sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
++      sunxi_gpio_set_output(gpio, value);
+-      return sunxi_gpio_output(gpio, value);
++      return 0;
+ }
+ int gpio_get_value(unsigned gpio)
+ {
+-      return sunxi_gpio_input(gpio);
++      return sunxi_gpio_get_output(gpio);
+ }
+ int gpio_set_value(unsigned gpio, int value)
+ {
+-      return sunxi_gpio_output(gpio, value);
++      sunxi_gpio_set_output(gpio, value);
++
++      return 0;
+ }
+ int sunxi_name_to_gpio(const char *name)
+@@ -135,13 +107,8 @@ int sunxi_name_to_gpio(const char *name)
+ static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
+ {
+       struct sunxi_gpio_plat *plat = dev_get_plat(dev);
+-      u32 num = GPIO_NUM(offset);
+-      unsigned dat;
+-
+-      dat = readl(&plat->regs->dat);
+-      dat >>= num;
+-      return dat & 0x1;
++      return sunxi_gpio_get_output_bank(plat->regs, offset) & 0x1;
+ }
+ static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
+@@ -181,7 +148,7 @@ static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
+               u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
+               u32 num = GPIO_NUM(offset);
+-              clrsetbits_le32(&plat->regs->dat, 1 << num, value << num);
++              sunxi_gpio_set_output_bank(plat->regs, num, value);
+               sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
+       } else if (flags & GPIOD_IS_IN) {
+               u32 pull = 0;
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4010-pinctrl-sunxi-remove-struct-sunxi_gpio.patch b/package/boot/uboot-sunxi/patches/4010-pinctrl-sunxi-remove-struct-sunxi_gpio.patch
new file mode 100644 (file)
index 0000000..ed0f92e
--- /dev/null
@@ -0,0 +1,347 @@
+From 8e8e3f442213d583fed0d9c7666de7a6c05110a2 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:50 +0100
+Subject: [PATCH 4010/4052] pinctrl: sunxi: remove struct sunxi_gpio
+
+So far every Allwinner SoC used the same basic pincontroller/GPIO
+register frame, and just differed by the number of implemented banks and
+pins, plus some special functionality from time to time. However the D1
+and successors use a slightly different pinctrl register layout.
+Use that opportunity to drop "struct sunxi_gpio", that described that
+MMIO frame in a C struct. That approach is somewhat frowned upon in the
+Linux world and rarely used there, though still popular with U-Boot.
+
+Switching from a C struct to a "base address plus offset" approach allows
+to switch between the two models more dynamically, without reverting to
+preprocessor macros and #ifdef's.
+
+Model the pinctrl MMIO register frame in the usual "base address +
+offset" way, and replace a hard-to-parse CPP macro with a more readable
+static function.
+All the users get converted over. There are no functional changes at
+this point, it just prepares the stages for the D1 and friends.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h | 67 +++++++++++---------------
+ arch/arm/mach-sunxi/pinmux.c           | 66 +++++++++++++------------
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c  | 14 +++---
+ 3 files changed, 71 insertions(+), 76 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
+index 2e7c84e410..96a29aa023 100644
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -28,13 +28,6 @@
+ #define SUNXI_GPIO_H  7
+ #define SUNXI_GPIO_I  8
+-/*
+- * This defines the number of GPIO banks for the _main_ GPIO controller.
+- * You should fix up the padding in struct sunxi_gpio_reg below if you
+- * change this.
+- */
+-#define SUNXI_GPIO_BANKS 9
+-
+ /*
+  * sun6i/sun8i and later SoCs have an additional GPIO controller (R_PIO)
+  * at a different register offset.
+@@ -52,46 +45,42 @@
+ #define SUNXI_GPIO_M  12
+ #define SUNXI_GPIO_N  13
+-struct sunxi_gpio {
+-      u32 cfg[4];
+-      u32 dat;
+-      u32 drv[2];
+-      u32 pull[2];
+-};
+-
+-/* gpio interrupt control */
+-struct sunxi_gpio_int {
+-      u32 cfg[3];
+-      u32 ctl;
+-      u32 sta;
+-      u32 deb;                /* interrupt debounce */
+-};
+-
+-struct sunxi_gpio_reg {
+-      struct sunxi_gpio gpio_bank[SUNXI_GPIO_BANKS];
+-      u8 res[0xbc];
+-      struct sunxi_gpio_int gpio_int;
+-};
+-
+ #define SUN50I_H6_GPIO_POW_MOD_SEL    0x340
+ #define SUN50I_H6_GPIO_POW_MOD_VAL    0x348
+-#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])
+-
+ #define GPIO_BANK(pin)                ((pin) >> 5)
+ #define GPIO_NUM(pin)         ((pin) & 0x1f)
++#define GPIO_CFG_REG_OFFSET   0x00
+ #define GPIO_CFG_INDEX(pin)   (((pin) & 0x1f) >> 3)
+ #define GPIO_CFG_OFFSET(pin)  ((((pin) & 0x1f) & 0x7) << 2)
++#define GPIO_DAT_REG_OFFSET   0x10
++
++#define GPIO_DRV_REG_OFFSET   0x14
+ #define GPIO_DRV_INDEX(pin)   (((pin) & 0x1f) >> 4)
+ #define GPIO_DRV_OFFSET(pin)  ((((pin) & 0x1f) & 0xf) << 1)
++#define GPIO_PULL_REG_OFFSET  0x1c
+ #define GPIO_PULL_INDEX(pin)  (((pin) & 0x1f) >> 4)
+ #define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
++#define SUNXI_PINCTRL_BANK_SIZE 0x24
++
++static inline void* BANK_TO_GPIO(int bank)
++{
++      void *pio_base;
++
++      if (bank < SUNXI_GPIO_L) {
++              pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
++      } else {
++              pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
++              bank -= SUNXI_GPIO_L;
++      }
++
++      return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
++}
++
+ /* GPIO bank sizes */
+ #define SUNXI_GPIOS_PER_BANK  32
+@@ -214,22 +203,22 @@ enum sunxi_gpio_number {
+ #define SUNXI_GPIO_AXP0_GPIO_COUNT    6
+ struct sunxi_gpio_plat {
+-      struct sunxi_gpio       *regs;
++      void                    *regs;
+       char                    bank_name[3];
+ };
+-void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val);
++void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val);
+ void sunxi_gpio_set_cfgpin(u32 pin, u32 val);
+-int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset);
++int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset);
+ int sunxi_gpio_get_cfgpin(u32 pin);
+-void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio, int pin, bool set);
++void sunxi_gpio_set_output_bank(void *bank_base, int pin, bool set);
+ void sunxi_gpio_set_output(u32 pin, bool set);
+-int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin);
++int sunxi_gpio_get_output_bank(void *bank_base, int pin);
+ int sunxi_gpio_get_output(u32 pin);
+ void sunxi_gpio_set_drv(u32 pin, u32 val);
+-void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val);
++void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val);
+ void sunxi_gpio_set_pull(u32 pin, u32 val);
+-void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val);
++void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val);
+ int sunxi_name_to_gpio(const char *name);
+ #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
+diff --git a/arch/arm/mach-sunxi/pinmux.c b/arch/arm/mach-sunxi/pinmux.c
+index 751cac8e09..17d1a7bdb9 100644
+--- a/arch/arm/mach-sunxi/pinmux.c
++++ b/arch/arm/mach-sunxi/pinmux.c
+@@ -9,29 +9,30 @@
+ #include <asm/io.h>
+ #include <asm/arch/gpio.h>
+-void sunxi_gpio_set_cfgbank(struct sunxi_gpio *pio, int bank_offset, u32 val)
++void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
+ {
+-      u32 index = GPIO_CFG_INDEX(bank_offset);
+-      u32 offset = GPIO_CFG_OFFSET(bank_offset);
++      u32 index = GPIO_CFG_INDEX(pin_offset);
++      u32 offset = GPIO_CFG_OFFSET(pin_offset);
+-      clrsetbits_le32(&pio->cfg[index], 0xf << offset, val << offset);
++      clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
++                      0xfU << offset, val << offset);
+ }
+ void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *pio = BANK_TO_GPIO(bank);
+-      sunxi_gpio_set_cfgbank(pio, pin, val);
++      sunxi_gpio_set_cfgbank(pio, pin % 32, val);
+ }
+-int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
++int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
+ {
+-      u32 index = GPIO_CFG_INDEX(bank_offset);
+-      u32 offset = GPIO_CFG_OFFSET(bank_offset);
++      u32 index = GPIO_CFG_INDEX(pin_offset);
++      u32 offset = GPIO_CFG_OFFSET(pin_offset);
+       u32 cfg;
+-      cfg = readl(&pio->cfg[index]);
++      cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
+       cfg >>= offset;
+       return cfg & 0xf;
+@@ -40,35 +41,38 @@ int sunxi_gpio_get_cfgbank(struct sunxi_gpio *pio, int bank_offset)
+ int sunxi_gpio_get_cfgpin(u32 pin)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *bank_base = BANK_TO_GPIO(bank);
+-      return sunxi_gpio_get_cfgbank(pio, pin);
++      return sunxi_gpio_get_cfgbank(bank_base, pin % 32);
+ }
+-void sunxi_gpio_set_output_bank(struct sunxi_gpio *pio, int pin, bool set)
++void sunxi_gpio_set_output_bank(void *bank_base, int pin, bool set)
+ {
+       u32 mask = 1U << GPIO_NUM(pin);
+-      clrsetbits_le32(&pio->dat, set ? 0 : mask, set ? mask : 0);
++      clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
++                      set ? 0 : mask, set ? mask : 0);
+ }
+ void sunxi_gpio_set_output(u32 pin, bool set)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *pio = BANK_TO_GPIO(bank);
+       sunxi_gpio_set_output_bank(pio, pin, set);
+ }
+-int sunxi_gpio_get_output_bank(struct sunxi_gpio *pio, int pin)
++int sunxi_gpio_get_output_bank(void *bank_base, int pin)
+ {
+-      return !!(readl(&pio->dat) & (1U << GPIO_NUM(pin)));
++      u32 mask = 1U << GPIO_NUM(pin);
++
++      return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & mask);
+ }
+ int sunxi_gpio_get_output(u32 pin)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *pio = BANK_TO_GPIO(bank);
+       return sunxi_gpio_get_output_bank(pio, pin);
+ }
+@@ -76,31 +80,33 @@ int sunxi_gpio_get_output(u32 pin)
+ void sunxi_gpio_set_drv(u32 pin, u32 val)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *bank_base = BANK_TO_GPIO(bank);
+-      sunxi_gpio_set_drv_bank(pio, pin, val);
++      sunxi_gpio_set_drv_bank(bank_base, pin % 32, val);
+ }
+-void sunxi_gpio_set_drv_bank(struct sunxi_gpio *pio, u32 bank_offset, u32 val)
++void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
+ {
+-      u32 index = GPIO_DRV_INDEX(bank_offset);
+-      u32 offset = GPIO_DRV_OFFSET(bank_offset);
++      u32 index = GPIO_DRV_INDEX(pin_offset);
++      u32 offset = GPIO_DRV_OFFSET(pin_offset);
+-      clrsetbits_le32(&pio->drv[index], 0x3 << offset, val << offset);
++      clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
++                      0x3U << offset, val << offset);
+ }
+ void sunxi_gpio_set_pull(u32 pin, u32 val)
+ {
+       u32 bank = GPIO_BANK(pin);
+-      struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
++      void *bank_base = BANK_TO_GPIO(bank);
+-      sunxi_gpio_set_pull_bank(pio, pin, val);
++      sunxi_gpio_set_pull_bank(bank_base, pin % 32, val);
+ }
+-void sunxi_gpio_set_pull_bank(struct sunxi_gpio *pio, int bank_offset, u32 val)
++void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
+ {
+-      u32 index = GPIO_PULL_INDEX(bank_offset);
+-      u32 offset = GPIO_PULL_OFFSET(bank_offset);
++      u32 index = GPIO_PULL_INDEX(pin_offset);
++      u32 offset = GPIO_PULL_OFFSET(pin_offset);
+-      clrsetbits_le32(&pio->pull[index], 0x3 << offset, val << offset);
++      clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
++                      0x3U << offset, val << offset);
+ }
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index c4fbda7a92..b0144edcf4 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -35,7 +35,7 @@ struct sunxi_pinctrl_desc {
+ };
+ struct sunxi_pinctrl_plat {
+-      struct sunxi_gpio __iomem *base;
++      void __iomem *base;
+ };
+ static int sunxi_pinctrl_get_pins_count(struct udevice *dev)
+@@ -86,8 +86,8 @@ static int sunxi_pinctrl_pinmux_set(struct udevice *dev, uint pin_selector,
+             sunxi_pinctrl_get_function_name(dev, func_selector),
+             desc->functions[func_selector].mux);
+-      sunxi_gpio_set_cfgbank(plat->base + bank, pin,
+-                             desc->functions[func_selector].mux);
++      sunxi_gpio_set_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE,
++                             pin, desc->functions[func_selector].mux);
+       return 0;
+ }
+@@ -102,7 +102,7 @@ static const struct pinconf_param sunxi_pinctrl_pinconf_params[] = {
+ static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
+                                         uint bank, uint pin, uint bias)
+ {
+-      struct sunxi_gpio *regs = &plat->base[bank];
++      void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
+       sunxi_gpio_set_pull_bank(regs, pin, bias);
+@@ -112,7 +112,7 @@ static int sunxi_pinctrl_pinconf_set_pull(struct sunxi_pinctrl_plat *plat,
+ static int sunxi_pinctrl_pinconf_set_drive(struct sunxi_pinctrl_plat *plat,
+                                          uint bank, uint pin, uint drive)
+ {
+-      struct sunxi_gpio *regs = &plat->base[bank];
++      void *regs = plat->base + bank * SUNXI_PINCTRL_BANK_SIZE;
+       if (drive < 10 || drive > 40)
+               return -EINVAL;
+@@ -148,7 +148,7 @@ static int sunxi_pinctrl_get_pin_muxing(struct udevice *dev, uint pin_selector,
+       struct sunxi_pinctrl_plat *plat = dev_get_plat(dev);
+       int bank = pin_selector / SUNXI_GPIOS_PER_BANK;
+       int pin  = pin_selector % SUNXI_GPIOS_PER_BANK;
+-      int mux  = sunxi_gpio_get_cfgbank(plat->base + bank, pin);
++      int mux  = sunxi_gpio_get_cfgbank(plat->base + bank * SUNXI_PINCTRL_BANK_SIZE, pin);
+       switch (mux) {
+       case SUNXI_GPIO_INPUT:
+@@ -206,7 +206,7 @@ static int sunxi_pinctrl_bind(struct udevice *dev)
+               if (!gpio_plat)
+                       return -ENOMEM;
+-              gpio_plat->regs = plat->base + i;
++              gpio_plat->regs = plat->base + i * SUNXI_PINCTRL_BANK_SIZE;
+               gpio_plat->bank_name[0] = 'P';
+               gpio_plat->bank_name[1] = 'A' + desc->first_bank + i;
+               gpio_plat->bank_name[2] = '\0';
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4011-pinctrl-sunxi-move-pinctrl-code-and-remove-GPIO_EXTR.patch b/package/boot/uboot-sunxi/patches/4011-pinctrl-sunxi-move-pinctrl-code-and-remove-GPIO_EXTR.patch
new file mode 100644 (file)
index 0000000..bd597e9
--- /dev/null
@@ -0,0 +1,307 @@
+From 18045603ba0d381200f86e2acefe28ce1b5ed071 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:51 +0100
+Subject: [PATCH 4011/4052] pinctrl: sunxi: move pinctrl code and remove
+ GPIO_EXTRA_HEADER
+
+U-Boot's generic GPIO_EXTRA_HEADER is a convenience symbol to allow code
+to more easily include platform specific GPIO headers. This should not
+be needed in a DM world anymore, since the generic GPIO framework
+handles that nicely.
+For Allwinner boards we still need to deal with non-DM GPIO in the SPL,
+but this should become the exception, not the rule.
+
+Make this more obvious by removing the definition of GPIO_EXTRA_HEADER,
+and just force every legacy user of platform specific GPIO to include
+the new sunxi_gpio.h header explicitly. Everyone doing so should feel
+ashamed and should find a way to avoid it from now on.
+This also moves and renames the existing sunxi-specific low level
+pinctrl routines from arch/arm/mach-sunxi into board/sunxi, and the
+gpio.h header to the generic include/ directory, so the common code can
+be shared outside of arch/arm.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/Kconfig                                             | 1 -
+ arch/arm/mach-sunxi/Makefile                                 | 1 -
+ arch/arm/mach-sunxi/board.c                                  | 1 +
+ arch/arm/mach-sunxi/dram_suniv.c                             | 2 +-
+ arch/arm/mach-sunxi/spl_spi_sunxi.c                          | 1 +
+ board/sunxi/Makefile                                         | 1 +
+ board/sunxi/board.c                                          | 1 +
+ board/sunxi/chip.c                                           | 2 +-
+ arch/arm/mach-sunxi/pinmux.c => board/sunxi/pinctrl.c        | 5 ++++-
+ drivers/gpio/axp_gpio.c                                      | 1 +
+ drivers/gpio/sunxi_gpio.c                                    | 1 +
+ drivers/i2c/sun6i_p2wi.c                                     | 2 +-
+ drivers/i2c/sun8i_rsb.c                                      | 2 +-
+ drivers/mmc/sunxi_mmc.c                                      | 1 +
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c                        | 1 +
+ drivers/video/hitachi_tx18d42vm_lcd.c                        | 1 +
+ drivers/video/ssd2828.c                                      | 1 -
+ drivers/video/sunxi/sunxi_display.c                          | 1 +
+ drivers/video/sunxi/sunxi_lcd.c                              | 1 +
+ .../include/asm/arch-sunxi/gpio.h => include/sunxi_gpio.h    | 0
+ 20 files changed, 19 insertions(+), 8 deletions(-)
+ rename arch/arm/mach-sunxi/pinmux.c => board/sunxi/pinctrl.c (94%)
+ rename arch/arm/include/asm/arch-sunxi/gpio.h => include/sunxi_gpio.h (100%)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index d5a6d293ce..2904e91ad3 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1106,7 +1106,6 @@ config ARCH_SUNXI
+       select DM_MMC if MMC
+       select DM_SCSI if SCSI
+       select DM_SERIAL
+-      select GPIO_EXTRA_HEADER
+       select OF_BOARD_SETUP
+       select OF_CONTROL
+       select OF_SEPARATE
+diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
+index 58f807cb82..671211e932 100644
+--- a/arch/arm/mach-sunxi/Makefile
++++ b/arch/arm/mach-sunxi/Makefile
+@@ -10,7 +10,6 @@ obj-y        += board.o
+ obj-y += clock.o
+ obj-y += cpu_info.o
+ obj-y += dram_helpers.o
+-obj-y += pinmux.o
+ obj-$(CONFIG_SUN6I_PRCM)      += prcm.o
+ obj-$(CONFIG_AXP_PMIC_BUS)    += pmic_bus.o
+ obj-$(CONFIG_MACH_SUNIV)      += clock_sun6i.o
+diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index 391a65a549..ec46ab9279 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -17,6 +17,7 @@
+ #include <i2c.h>
+ #include <serial.h>
+ #include <spl.h>
++#include <sunxi_gpio.h>
+ #include <asm/cache.h>
+ #include <asm/gpio.h>
+ #include <asm/io.h>
+diff --git a/arch/arm/mach-sunxi/dram_suniv.c b/arch/arm/mach-sunxi/dram_suniv.c
+index 3aa3ce7627..9e583e1855 100644
+--- a/arch/arm/mach-sunxi/dram_suniv.c
++++ b/arch/arm/mach-sunxi/dram_suniv.c
+@@ -13,10 +13,10 @@
+ #include <asm/io.h>
+ #include <asm/arch/clock.h>
+ #include <asm/arch/dram.h>
+-#include <asm/arch/gpio.h>
+ #include <linux/bitops.h>
+ #include <linux/delay.h>
+ #include <hang.h>
++#include <sunxi_gpio.h>
+ #define SDR_T_CAS                     (0x2)
+ #define SDR_T_RAS                     (0x8)
+diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
+index 81159cfee6..c2410dd7bb 100644
+--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
++++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
+@@ -13,6 +13,7 @@
+ #include <linux/bitops.h>
+ #include <linux/delay.h>
+ #include <linux/libfdt.h>
++#include <sunxi_gpio.h>
+ #ifdef CONFIG_SPL_OS_BOOT
+ #error CONFIG_SPL_OS_BOOT is not supported yet
+diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile
+index d96b7897b6..7763b032c8 100644
+--- a/board/sunxi/Makefile
++++ b/board/sunxi/Makefile
+@@ -7,6 +7,7 @@
+ # (C) Copyright 2000-2003
+ # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ obj-y += board.o
++obj-y += pinctrl.o
+ obj-$(CONFIG_SUN7I_GMAC)      += gmac.o
+ obj-$(CONFIG_MACH_SUN4I)      += dram_sun4i_auto.o
+ obj-$(CONFIG_MACH_SUN5I)      += dram_sun5i_auto.o
+diff --git a/board/sunxi/board.c b/board/sunxi/board.c
+index 9900c66ed0..661137f43c 100644
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -38,6 +38,7 @@
+ #include <asm/armv7.h>
+ #endif
+ #include <asm/gpio.h>
++#include <sunxi_gpio.h>
+ #include <asm/io.h>
+ #include <u-boot/crc.h>
+ #include <env_internal.h>
+diff --git a/board/sunxi/chip.c b/board/sunxi/chip.c
+index cde04bebe9..eeee6319e7 100644
+--- a/board/sunxi/chip.c
++++ b/board/sunxi/chip.c
+@@ -12,7 +12,7 @@
+ #include <w1-eeprom.h>
+ #include <dm/device-internal.h>
+-#include <asm/arch/gpio.h>
++#include <sunxi_gpio.h>
+ #include <extension_board.h>
+diff --git a/arch/arm/mach-sunxi/pinmux.c b/board/sunxi/pinctrl.c
+similarity index 94%
+rename from arch/arm/mach-sunxi/pinmux.c
+rename to board/sunxi/pinctrl.c
+index 17d1a7bdb9..494d92c73b 100644
+--- a/arch/arm/mach-sunxi/pinmux.c
++++ b/board/sunxi/pinctrl.c
+@@ -3,11 +3,14 @@
+  * (C) Copyright 2007-2011
+  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+  * Tom Cubie <tangliang@allwinnertech.com>
++ *
++ * Low level GPIO/pin controller access functions, to be shared by non-DM
++ * SPL code and the DM pinctrl/GPIO drivers.
+  */
+ #include <common.h>
+ #include <asm/io.h>
+-#include <asm/arch/gpio.h>
++#include <sunxi_gpio.h>
+ void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
+ {
+diff --git a/drivers/gpio/axp_gpio.c b/drivers/gpio/axp_gpio.c
+index 35585dc8ac..14a99ce4c9 100644
+--- a/drivers/gpio/axp_gpio.c
++++ b/drivers/gpio/axp_gpio.c
+@@ -14,6 +14,7 @@
+ #include <dm/lists.h>
+ #include <dm/root.h>
+ #include <errno.h>
++#include <sunxi_gpio.h>
+ static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
+diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
+index 6796375d35..921cf43b25 100644
+--- a/drivers/gpio/sunxi_gpio.c
++++ b/drivers/gpio/sunxi_gpio.c
+@@ -17,6 +17,7 @@
+ #include <asm/io.h>
+ #include <asm/gpio.h>
+ #include <dt-bindings/gpio/gpio.h>
++#include <sunxi_gpio.h>
+ #if !CONFIG_IS_ENABLED(DM_GPIO)
+ int gpio_request(unsigned gpio, const char *label)
+diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c
+index d221323295..b8e07a533c 100644
+--- a/drivers/i2c/sun6i_p2wi.c
++++ b/drivers/i2c/sun6i_p2wi.c
+@@ -20,10 +20,10 @@
+ #include <errno.h>
+ #include <i2c.h>
+ #include <reset.h>
++#include <sunxi_gpio.h>
+ #include <time.h>
+ #include <asm/io.h>
+ #include <asm/arch/cpu.h>
+-#include <asm/arch/gpio.h>
+ #include <asm/arch/p2wi.h>
+ #include <asm/arch/prcm.h>
+ #include <asm/arch/sys_proto.h>
+diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c
+index 47fa05b6d1..f36f2c7afa 100644
+--- a/drivers/i2c/sun8i_rsb.c
++++ b/drivers/i2c/sun8i_rsb.c
+@@ -14,10 +14,10 @@
+ #include <dm.h>
+ #include <errno.h>
+ #include <i2c.h>
++#include <sunxi_gpio.h>
+ #include <reset.h>
+ #include <time.h>
+ #include <asm/arch/cpu.h>
+-#include <asm/arch/gpio.h>
+ #include <asm/arch/prcm.h>
+ #include <asm/arch/rsb.h>
+diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
+index 23bc7da917..03e33753fc 100644
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -27,6 +27,7 @@
+ #include <asm/arch/cpu.h>
+ #include <asm/arch/mmc.h>
+ #include <linux/delay.h>
++#include <sunxi_gpio.h>
+ #ifndef CCM_MMC_CTRL_MODE_SEL_NEW
+ #define CCM_MMC_CTRL_MODE_SEL_NEW     0
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index b0144edcf4..4c52e3fa74 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -7,6 +7,7 @@
+ #include <dm/pinctrl.h>
+ #include <errno.h>
+ #include <malloc.h>
++#include <sunxi_gpio.h>
+ #include <asm/gpio.h>
+diff --git a/drivers/video/hitachi_tx18d42vm_lcd.c b/drivers/video/hitachi_tx18d42vm_lcd.c
+index 87c4d27438..95984fe3d3 100644
+--- a/drivers/video/hitachi_tx18d42vm_lcd.c
++++ b/drivers/video/hitachi_tx18d42vm_lcd.c
+@@ -10,6 +10,7 @@
+ #include <linux/delay.h>
+ #include <asm/gpio.h>
++#include <sunxi_gpio.h>
+ #include <errno.h>
+ /*
+diff --git a/drivers/video/ssd2828.c b/drivers/video/ssd2828.c
+index 4cdcbe7755..948f5e74d0 100644
+--- a/drivers/video/ssd2828.c
++++ b/drivers/video/ssd2828.c
+@@ -12,7 +12,6 @@
+ #include <common.h>
+ #include <malloc.h>
+ #include <mipi_display.h>
+-#include <asm/arch/gpio.h>
+ #include <asm/gpio.h>
+ #include <linux/delay.h>
+diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
+index 9110a48482..8da44a1bb6 100644
+--- a/drivers/video/sunxi/sunxi_display.c
++++ b/drivers/video/sunxi/sunxi_display.c
+@@ -31,6 +31,7 @@
+ #include <malloc.h>
+ #include <video.h>
+ #include <dm/uclass-internal.h>
++#include <sunxi_gpio.h>
+ #include "../videomodes.h"
+ #include "../anx9804.h"
+ #include "../hitachi_tx18d42vm_lcd.h"
+diff --git a/drivers/video/sunxi/sunxi_lcd.c b/drivers/video/sunxi/sunxi_lcd.c
+index 8b9c3b2bfa..7a01cc343c 100644
+--- a/drivers/video/sunxi/sunxi_lcd.c
++++ b/drivers/video/sunxi/sunxi_lcd.c
+@@ -17,6 +17,7 @@
+ #include <asm/arch/lcdc.h>
+ #include <asm/global_data.h>
+ #include <asm/gpio.h>
++#include <sunxi_gpio.h>
+ struct sunxi_lcd_priv {
+       struct display_timing timing;
+diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/include/sunxi_gpio.h
+similarity index 100%
+rename from arch/arm/include/asm/arch-sunxi/gpio.h
+rename to include/sunxi_gpio.h
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4012-pinctrl-sunxi-move-PIO_BASE-into-sunxi_gpio.h.patch b/package/boot/uboot-sunxi/patches/4012-pinctrl-sunxi-move-PIO_BASE-into-sunxi_gpio.h.patch
new file mode 100644 (file)
index 0000000..48e1446
--- /dev/null
@@ -0,0 +1,113 @@
+From c983afccce5c1290dff892ec09b8d0cafef936d4 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:52 +0100
+Subject: [PATCH 4012/4052] pinctrl: sunxi: move PIO_BASE into sunxi_gpio.h
+
+On the Allwinner platform we were describing a quite comprehensive
+memory map in a per-SoC header unser arch/arm.
+In the old days that was used by every driver, but nowadays it should
+only be needed by SPL drivers (not using the DT). Many addresses in
+there were never used, and some are not needed anymore.
+
+To avoid a dependency on CPU specific headers in an arch specific
+directory, move the definition of the pinctroller MMIO base address into
+the sunxi_gpio.h header, because the SPL routines for GPIO should be the
+only one needing this address.
+This is a first step towards getting rid of cpu_sun[x]i.h completely,
+and allows to remove the inclusion of that file from the sunxi_gpio.h
+header.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/include/asm/arch-sunxi/cpu_sun4i.h     |  2 --
+ arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h |  2 --
+ arch/arm/include/asm/arch-sunxi/cpu_sun9i.h     |  2 --
+ include/sunxi_gpio.h                            | 12 +++++++++++-
+ 4 files changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+index f7ecc790db..d6fe51f24b 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+@@ -91,7 +91,6 @@
+ #define SUNXI_CCM_BASE                        0x01c20000
+ #define SUNXI_INTC_BASE                       0x01c20400
+-#define SUNXI_PIO_BASE                        0x01c20800
+ #define SUNXI_TIMER_BASE              0x01c20c00
+ #ifndef CONFIG_SUNXI_GEN_SUN6I
+ #define SUNXI_PWM_BASE                        0x01c20e00
+@@ -210,7 +209,6 @@ defined(CONFIG_MACH_SUN50I)
+ #define SUNXI_R_TWI_BASE              0x01f02400
+ #define SUNXI_R_UART_BASE             0x01f02800
+-#define SUNXI_R_PIO_BASE              0x01f02c00
+ #define SUN6I_P2WI_BASE                       0x01f03400
+ #define SUNXI_RSB_BASE                        0x01f03400
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+index d9cf8ae042..9b6bf84360 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+@@ -22,7 +22,6 @@
+ #define SUNXI_SIDC_BASE                       0x03006000
+ #define SUNXI_SID_BASE                        0x03006200
+ #define SUNXI_TIMER_BASE              0x03009000
+-#define SUNXI_PIO_BASE                        0x0300B000
+ #define SUNXI_PSI_BASE                        0x0300C000
+ #define SUNXI_GIC400_BASE             0x03020000
+@@ -68,7 +67,6 @@
+ #define SUNXI_R_CPUCFG_BASE           0x07000400
+ #define SUNXI_PRCM_BASE                       0x07010000
+ #define SUNXI_R_WDOG_BASE             0x07020400
+-#define SUNXI_R_PIO_BASE              0x07022000
+ #define SUNXI_R_UART_BASE             0x07080000
+ #define SUNXI_R_TWI_BASE              0x07081400
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
+index 9c2d11b590..20025be231 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
+@@ -81,7 +81,6 @@
+ /* APB0 Module */
+ #define SUNXI_CCM_BASE                        (REGS_APB0_BASE + 0x0000)
+ #define SUNXI_CCMMODULE_BASE          (REGS_APB0_BASE + 0x0400)
+-#define SUNXI_PIO_BASE                        (REGS_APB0_BASE + 0x0800)
+ #define SUNXI_TIMER_BASE              (REGS_APB0_BASE + 0x0C00)
+ #define SUNXI_PWM_BASE                        (REGS_APB0_BASE + 0x1400)
+ #define SUNXI_LRADC_BASE              (REGS_APB0_BASE + 0x1800)
+@@ -102,7 +101,6 @@
+ /* RCPUS Module */
+ #define SUNXI_PRCM_BASE                       (REGS_RCPUS_BASE + 0x1400)
+ #define SUNXI_R_UART_BASE             (REGS_RCPUS_BASE + 0x2800)
+-#define SUNXI_R_PIO_BASE              (REGS_RCPUS_BASE + 0x2c00)
+ #define SUNXI_RSB_BASE                        (REGS_RCPUS_BASE + 0x3400)
+ /* Misc. */
+diff --git a/include/sunxi_gpio.h b/include/sunxi_gpio.h
+index 96a29aa023..2e06745a1c 100644
+--- a/include/sunxi_gpio.h
++++ b/include/sunxi_gpio.h
+@@ -9,7 +9,17 @@
+ #define _SUNXI_GPIO_H
+ #include <linux/types.h>
+-#include <asm/arch/cpu.h>
++
++#if defined(CONFIG_MACH_SUN9I)
++#define SUNXI_PIO_BASE                0x06000800
++#define SUNXI_R_PIO_BASE      0x08002c00
++#elif defined(CONFIG_SUN50I_GEN_H6)
++#define SUNXI_PIO_BASE                0x0300b000
++#define SUNXI_R_PIO_BASE      0x07022000
++#else
++#define SUNXI_PIO_BASE                0x01c20800
++#define SUNXI_R_PIO_BASE      0x01f02c00
++#endif
+ /*
+  * sunxi has 9 banks of gpio, they are:
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4013-pinctrl-sunxi-add-new-D1-pinctrl-support.patch b/package/boot/uboot-sunxi/patches/4013-pinctrl-sunxi-add-new-D1-pinctrl-support.patch
new file mode 100644 (file)
index 0000000..c6e24da
--- /dev/null
@@ -0,0 +1,92 @@
+From 536e6204d5e32f4ce30ba99fcfee087aa725f4bd Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:53 +0100
+Subject: [PATCH 4013/4052] pinctrl: sunxi: add new D1 pinctrl support
+
+For the first time since at least the Allwinner A10 SoCs, the D1 (and
+related cores) use a new pincontroller MMIO register layout, so we
+cannot use our hardcoded, fixed offsets anymore.
+Ideally this would all be handled by devicetree and DM drivers, but for
+the DT-less SPL we still need the legacy interfaces.
+
+Add a new Kconfig symbol to differenciate between the two generations of
+pincontrollers, and just use that to just switch some basic symbols.
+The rest is already abstracted enough, so works out of the box.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/mach-sunxi/Kconfig |  6 ++++++
+ include/sunxi_gpio.h        | 26 +++++++++++++++++++++-----
+ 2 files changed, 27 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index d716054f72..b328ce8960 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -113,6 +113,12 @@ config SUNXI_SRAM_ADDRESS
+ config SUNXI_A64_TIMER_ERRATUM
+       bool
++config SUNXI_NEW_PINCTRL
++      bool
++      ---help---
++      The Allwinner D1 and other new SoCs use a different register map
++      for the GPIO block, which we need to know about in the SPL.
++
+ # Note only one of these may be selected at a time! But hidden choices are
+ # not supported by Kconfig
+ config SUNXI_GEN_SUN4I
+diff --git a/include/sunxi_gpio.h b/include/sunxi_gpio.h
+index 2e06745a1c..61978db6db 100644
+--- a/include/sunxi_gpio.h
++++ b/include/sunxi_gpio.h
+@@ -68,15 +68,32 @@
+ #define GPIO_DAT_REG_OFFSET   0x10
+ #define GPIO_DRV_REG_OFFSET   0x14
+-#define GPIO_DRV_INDEX(pin)   (((pin) & 0x1f) >> 4)
+-#define GPIO_DRV_OFFSET(pin)  ((((pin) & 0x1f) & 0xf) << 1)
++
++/*            Newer SoCs use a slightly different register layout */
++#ifdef CONFIG_SUNXI_NEW_PINCTRL
++/* pin drive strength: 4 bits per pin */
++#define GPIO_DRV_INDEX(pin)   ((pin) / 8)
++#define GPIO_DRV_OFFSET(pin)  (((pin) % 8) * 4)
++
++#define GPIO_PULL_REG_OFFSET  0x24
++
++#define SUNXI_PINCTRL_BANK_SIZE       0x30
++#define SUNXI_GPIO_DISABLE    0xf
++
++#else /* older generation pin controllers */
++/* pin drive strength: 2 bits per pin */
++#define GPIO_DRV_INDEX(pin)   ((pin) / 16)
++#define GPIO_DRV_OFFSET(pin)  (((pin) % 16) * 2)
+ #define GPIO_PULL_REG_OFFSET  0x1c
++
++#define SUNXI_PINCTRL_BANK_SIZE       0x24
++#define SUNXI_GPIO_DISABLE    0x7
++#endif
++
+ #define GPIO_PULL_INDEX(pin)  (((pin) & 0x1f) >> 4)
+ #define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
+-#define SUNXI_PINCTRL_BANK_SIZE 0x24
+-
+ static inline void* BANK_TO_GPIO(int bank)
+ {
+       void *pio_base;
+@@ -132,7 +149,6 @@ enum sunxi_gpio_number {
+ /* GPIO pin function config */
+ #define SUNXI_GPIO_INPUT      0
+ #define SUNXI_GPIO_OUTPUT     1
+-#define SUNXI_GPIO_DISABLE    7
+ #define SUN8I_H3_GPA_UART0    2
+ #define SUN8I_H3_GPA_UART2    2
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4014-sunxi-introduce-NCAT2-generation-model.patch b/package/boot/uboot-sunxi/patches/4014-sunxi-introduce-NCAT2-generation-model.patch
new file mode 100644 (file)
index 0000000..8babf71
--- /dev/null
@@ -0,0 +1,347 @@
+From 8f46a2cd8d00bf19cc6b18383a250d1669c88fc9 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:54 +0100
+Subject: [PATCH 4014/4052] sunxi: introduce NCAT2 generation model
+
+Allwinner seems to typically stick to a common MMIO memory map for
+several SoCs, but from time to time does some breaking changes, which
+also introduce new generations of some peripherals. The last time this
+happened with the H6, which apart from re-organising the base addresses
+also changed the clock controller significantly. We added a
+CONFIG_SUN50I_GEN_H6 symbol back then to mark SoCs sharing those traits.
+
+Now the Allwinner D1 changes the memory map again, and also extends the
+pincontroller, among other peripherals.
+To mark this generation of SoCs, add a CONFIG_SUNXI_GEN_NCAT2 symbol,
+this name is reportedly used in the Allwinner BSP code, and prevents us
+from inventing our own name.
+
+Add this new symbol to some guards that were already checking for the H6
+generation, since many features are shared between the two (like the
+renovated clock controller).
+
+This paves the way to introduce a first user of this generation.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/include/asm/arch-sunxi/clock.h       |  2 +-
+ arch/arm/include/asm/arch-sunxi/cpu.h         |  2 +
+ .../include/asm/arch-sunxi/cpu_sunxi_ncat2.h  | 43 +++++++++++++++++++
+ arch/arm/include/asm/arch-sunxi/mmc.h         |  2 +-
+ arch/arm/include/asm/arch-sunxi/prcm.h        |  2 +-
+ arch/arm/include/asm/arch-sunxi/timer.h       |  2 +-
+ arch/arm/mach-sunxi/Kconfig                   | 12 +++++-
+ arch/arm/mach-sunxi/Makefile                  |  1 +
+ arch/arm/mach-sunxi/board.c                   | 22 ++++++----
+ common/spl/Kconfig                            |  2 +-
+ drivers/i2c/mvtwsi.c                          |  3 +-
+ drivers/mmc/sunxi_mmc.c                       | 10 +++--
+ include/sunxi_gpio.h                          |  3 ++
+ 13 files changed, 87 insertions(+), 19 deletions(-)
+ create mode 100644 arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+
+diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
+index 2cfd540742..3d34261b0e 100644
+--- a/arch/arm/include/asm/arch-sunxi/clock.h
++++ b/arch/arm/include/asm/arch-sunxi/clock.h
+@@ -16,7 +16,7 @@
+ /* clock control module regs definition */
+ #if defined(CONFIG_MACH_SUN8I_A83T)
+ #include <asm/arch/clock_sun8i_a83t.h>
+-#elif defined(CONFIG_SUN50I_GEN_H6)
++#elif defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+ #include <asm/arch/clock_sun50i_h6.h>
+ #elif defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) || \
+       defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUNIV)
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu.h b/arch/arm/include/asm/arch-sunxi/cpu.h
+index b08f202374..768c6572d6 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu.h
+@@ -10,6 +10,8 @@
+ #include <asm/arch/cpu_sun9i.h>
+ #elif defined(CONFIG_SUN50I_GEN_H6)
+ #include <asm/arch/cpu_sun50i_h6.h>
++#elif defined(CONFIG_SUNXI_GEN_NCAT2)
++#include <asm/arch/cpu_sunxi_ncat2.h>
+ #else
+ #include <asm/arch/cpu_sun4i.h>
+ #endif
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+new file mode 100644
+index 0000000000..b13be2c4e8
+--- /dev/null
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+@@ -0,0 +1,43 @@
++/*
++ * (C) Copyright 2022 Arm Limited
++ *
++ * SPDX-License-Identifier:   GPL-2.0+
++ */
++
++#ifndef _SUNXI_CPU_SUNXI_NCAT2_H
++#define _SUNXI_CPU_SUNXI_NCAT2_H
++
++#define SUNXI_CCM_BASE                        0x02001000
++#define SUNXI_TIMER_BASE              0x02050000
++
++#define SUNXI_UART0_BASE              0x02500000
++#define SUNXI_UART1_BASE              0x02500400
++#define SUNXI_UART2_BASE              0x02500800
++#define SUNXI_UART3_BASE              0x02500C00
++#define SUNXI_TWI0_BASE                       0x02502000
++#define SUNXI_TWI1_BASE                       0x02502400
++#define SUNXI_TWI2_BASE                       0x02502800
++#define SUNXI_TWI3_BASE                       0x02502C00
++
++#define SUNXI_SRAMC_BASE              0x03000000
++/* SID address space starts at 0x03006000, but e-fuse is at offset 0x200 */
++#define SUNXI_SIDC_BASE                       0x03006000
++#define SUNXI_SID_BASE                        0x03006200
++#define SUNXI_GIC400_BASE             0x03020000
++
++#define SUNXI_MMC0_BASE                       0x04020000
++#define SUNXI_MMC1_BASE                       0x04021000
++#define SUNXI_MMC2_BASE                       0x04022000
++
++#define SUNXI_R_CPUCFG_BASE           0x07000400
++
++#define SUNXI_CPUX_BASE                       0x09010000
++#define SUNXI_CPUCFG_BASE             0
++
++#ifndef __ASSEMBLY__
++void sunxi_board_init(void);
++void sunxi_reset(void);
++int sunxi_get_sid(unsigned int *sid);
++#endif
++
++#endif /* _SUNXI_CPU_SUNXI_NCAT2_H */
+diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
+index 5daacf10eb..8ed3e0459c 100644
+--- a/arch/arm/include/asm/arch-sunxi/mmc.h
++++ b/arch/arm/include/asm/arch-sunxi/mmc.h
+@@ -45,7 +45,7 @@ struct sunxi_mmc {
+       u32 chda;               /* 0x90 */
+       u32 cbda;               /* 0x94 */
+       u32 res2[26];
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+       u32 res3[17];
+       u32 samp_dl;
+       u32 res4[46];
+diff --git a/arch/arm/include/asm/arch-sunxi/prcm.h b/arch/arm/include/asm/arch-sunxi/prcm.h
+index 5106076f5e..c5418cfd28 100644
+--- a/arch/arm/include/asm/arch-sunxi/prcm.h
++++ b/arch/arm/include/asm/arch-sunxi/prcm.h
+@@ -9,7 +9,7 @@
+ #define _SUNXI_PRCM_H
+ /* prcm regs definition */
+-#if defined(CONFIG_SUN50I_GEN_H6)
++#if defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+ #include <asm/arch/prcm_sun50i.h>
+ #else
+ #include <asm/arch/prcm_sun6i.h>
+diff --git a/arch/arm/include/asm/arch-sunxi/timer.h b/arch/arm/include/asm/arch-sunxi/timer.h
+index bb5626d893..e17db8588e 100644
+--- a/arch/arm/include/asm/arch-sunxi/timer.h
++++ b/arch/arm/include/asm/arch-sunxi/timer.h
+@@ -76,7 +76,7 @@ struct sunxi_timer_reg {
+       struct sunxi_tgp tgp[4];
+       u8 res5[8];
+       u32 cpu_cfg;
+-#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+       u8 res3[16];
+       struct sunxi_wdog wdog[5];      /* We have 5 watchdogs */
+ #endif
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index b328ce8960..60ca1239dd 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -102,7 +102,7 @@ config AXP_PMIC_BUS
+ 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 || SUNXI_GEN_NCAT2
+       default 0x0
+       ---help---
+       Older Allwinner SoCs have their mask boot ROM mapped just below 4GB,
+@@ -144,6 +144,14 @@ config SUN50I_GEN_H6
+       Select this for sunxi SoCs which have H6 like peripherals, clocks
+       and memory map.
++config SUNXI_GEN_NCAT2
++      bool
++      select MMC_SUNXI_HAS_NEW_MODE
++      select SUPPORT_SPL
++      ---help---
++      Select this for sunxi SoCs which have D1 like peripherals, clocks
++      and memory map.
++
+ config SUNXI_DRAM_DW
+       bool
+       ---help---
+@@ -760,6 +768,7 @@ config VIDEO_SUNXI
+       depends on !MACH_SUN9I
+       depends on !MACH_SUN50I
+       depends on !SUN50I_GEN_H6
++      depends on !SUNXI_GEN_NCAT2
+       select VIDEO
+       select DISPLAY
+       imply VIDEO_DT_SIMPLEFB
+@@ -973,6 +982,7 @@ config SPL_STACK_R_ADDR
+       default 0x2fe00000 if MACH_SUN9I
+       default 0x4fe00000 if MACH_SUN50I
+       default 0x4fe00000 if SUN50I_GEN_H6
++      default 0x4fe00000 if SUNXI_GEN_NCAT2
+ config SPL_SPI_SUNXI
+       bool "Support for SPI Flash on Allwinner SoCs in SPL"
+diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
+index 671211e932..1d4c70ec35 100644
+--- a/arch/arm/mach-sunxi/Makefile
++++ b/arch/arm/mach-sunxi/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_MACH_SUN8I)     += clock_sun6i.o
+ endif
+ obj-$(CONFIG_MACH_SUN9I)      += clock_sun9i.o gtbus_sun9i.o
+ obj-$(CONFIG_SUN50I_GEN_H6)   += clock_sun50i_h6.o
++obj-$(CONFIG_SUNXI_GEN_NCAT2) += clock_sun50i_h6.o
+ ifndef CONFIG_ARM64
+ obj-y += timer.o
+ endif
+diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index ec46ab9279..51b8e708b0 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -176,13 +176,19 @@ static int gpio_init(void)
+ #error Unsupported console port number. Please fix pin mux settings in board.c
+ #endif
+-#ifdef CONFIG_SUN50I_GEN_H6
+-      /* Update PIO power bias configuration by copy hardware detected value */
+-      val = readl(SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
+-      writel(val, SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
+-      val = readl(SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
+-      writel(val, SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
+-#endif
++      /*
++       * Update PIO power bias configuration by copying the hardware
++       * detected value.
++       */
++      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++          IS_ENABLED(CONFIG_SUN50I_GEN_NCAT2)) {
++              val = readl(SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
++              writel(val, SUNXI_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
++      }
++      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6)) {
++              val = readl(SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_VAL);
++              writel(val, SUNXI_R_PIO_BASE + SUN50I_H6_GPIO_POW_MOD_SEL);
++      }
+       return 0;
+ }
+@@ -481,7 +487,7 @@ void reset_cpu(void)
+               /* sun5i sometimes gets stuck without this */
+               writel(WDT_MODE_RESET_EN | WDT_MODE_EN, &wdog->mode);
+       }
+-#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#elif defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+ #if defined(CONFIG_MACH_SUN50I_H6)
+       /* WDOG is broken for some H6 rev. use the R_WDOG instead */
+       static const struct sunxi_wdog *wdog =
+diff --git a/common/spl/Kconfig b/common/spl/Kconfig
+index 3c2af453ab..06bcedca7d 100644
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -265,7 +265,7 @@ config SPL_TEXT_BASE
+       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 0x20060 if SUN50I_GEN_H6 || SUNXI_GEN_NCAT2
+       default 0x00060 if ARCH_SUNXI
+       default 0xfffc0000 if ARCH_ZYNQMP
+       default 0x0
+diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
+index 93bbc6916e..5c9b92ccf9 100644
+--- a/drivers/i2c/mvtwsi.c
++++ b/drivers/i2c/mvtwsi.c
+@@ -124,7 +124,8 @@ enum mvtwsi_ctrl_register_fields {
+  * on other platforms, it is a normal r/w bit, which is cleared by writing 0.
+  */
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || \
++    defined(CONFIG_SUNXI_GEN_NCAT2)
+ #define       MVTWSI_CONTROL_CLEAR_IFLG       0x00000008
+ #else
+ #define       MVTWSI_CONTROL_CLEAR_IFLG       0x00000000
+diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
+index 03e33753fc..a8e590561c 100644
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -57,6 +57,7 @@ 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_SUNXI_GEN_NCAT2) ||
+              IS_ENABLED(CONFIG_MACH_SUN8I_R40);
+ }
+@@ -191,7 +192,7 @@ static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
+       rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
+       writel(rval, &priv->reg->clkcr);
+-#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
++#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
+       /* A64 supports calibration of delays on MMC controller and we
+        * have to set delay of zero before starting calibration.
+        * Allwinner BSP driver sets a delay only in the case of
+@@ -530,7 +531,8 @@ struct mmc *sunxi_mmc_init(int sdc_no)
+       cfg->host_caps = MMC_MODE_4BIT;
+       if ((IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN8I) ||
+-          IS_ENABLED(CONFIG_SUN50I_GEN_H6)) && (sdc_no == 2))
++          IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++          IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) && (sdc_no == 2))
+               cfg->host_caps = MMC_MODE_8BIT;
+       cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+@@ -544,7 +546,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
+       /* config ahb clock */
+       debug("init mmc %d clock and io\n", sdc_no);
+-#if !defined(CONFIG_SUN50I_GEN_H6)
++#if !defined(CONFIG_SUN50I_GEN_H6) && !defined(CONFIG_SUNXI_GEN_NCAT2)
+       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
+ #ifdef CONFIG_SUNXI_GEN_SUN6I
+@@ -619,7 +621,7 @@ 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_SUNXI_GEN_NCAT2))
+               return 0x830;
+       return 0x88;
+diff --git a/include/sunxi_gpio.h b/include/sunxi_gpio.h
+index 61978db6db..8cf9047ff9 100644
+--- a/include/sunxi_gpio.h
++++ b/include/sunxi_gpio.h
+@@ -16,6 +16,9 @@
+ #elif defined(CONFIG_SUN50I_GEN_H6)
+ #define SUNXI_PIO_BASE                0x0300b000
+ #define SUNXI_R_PIO_BASE      0x07022000
++#elif defined(CONFIG_SUNXI_GEN_NCAT2)
++#define SUNXI_PIO_BASE                0x02000000
++#define SUNXI_R_PIO_BASE      0
+ #else
+ #define SUNXI_PIO_BASE                0x01c20800
+ #define SUNXI_R_PIO_BASE      0x01f02c00
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4015-pinctrl-sunxi-add-Allwinner-D1-pinctrl-description.patch b/package/boot/uboot-sunxi/patches/4015-pinctrl-sunxi-add-Allwinner-D1-pinctrl-description.patch
new file mode 100644 (file)
index 0000000..297fcb9
--- /dev/null
@@ -0,0 +1,80 @@
+From 8d93569214bc09410ea6eaa98d0636b94d030bb8 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:55 +0100
+Subject: [PATCH 4015/4052] pinctrl: sunxi: add Allwinner D1 pinctrl
+ description
+
+Apart from using the new pinctrl MMIO register layout, the Allwinner D1
+and related SoCs still need to usual set of mux values hardcoded in
+U-Boot's pinctrl driver.
+Add the values we need so far to this list, so that DM based drivers
+will just work without further ado.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/pinctrl/sunxi/Kconfig         |  4 ++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 28 +++++++++++++++++++++++++++
+ 2 files changed, 32 insertions(+)
+
+diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
+index 77da90836b..c8f937d91e 100644
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -124,4 +124,8 @@ config PINCTRL_SUN50I_H616_R
+       default MACH_SUN50I_H616
+       select PINCTRL_SUNXI
++config PINCTRL_SUN20I_D1
++      bool "Support for the Allwinner D1/R528 PIO"
++      select PINCTRL_SUNXI
++
+ endif
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index 4c52e3fa74..614cfe6b73 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -735,6 +735,28 @@ static const struct sunxi_pinctrl_desc __maybe_unused sun50i_h616_r_pinctrl_desc
+       .num_banks      = 1,
+ };
++static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
++      { "emac",       8 },    /* PE0-PE15 */
++      { "gpio_in",    0 },
++      { "gpio_out",   1 },
++      { "mmc0",       2 },    /* PF0-PF5 */
++      { "mmc2",       3 },    /* PC1-PC7 */
++      { "spi0",       2 },    /* PC2-PC7 */
++#if IS_ENABLED(CONFIG_UART0_PORT_F)
++      { "uart0",      3 },    /* PF2-PF4 */
++#else
++      { "uart0",      6 },    /* PB2-PB3 */
++#endif
++      { "uart3",      7 },    /* PB6-PB9 */
++};
++
++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 udevice_id sunxi_pinctrl_ids[] = {
+ #ifdef CONFIG_PINCTRL_SUNIV_F1C100S
+       {
+@@ -891,6 +913,12 @@ static const struct udevice_id sunxi_pinctrl_ids[] = {
+               .compatible = "allwinner,sun50i-h616-r-pinctrl",
+               .data = (ulong)&sun50i_h616_r_pinctrl_desc,
+       },
++#endif
++#ifdef CONFIG_PINCTRL_SUN20I_D1
++      {
++              .compatible = "allwinner,sun20i-d1-pinctrl",
++              .data = (ulong)&sun20i_d1_pinctrl_desc,
++      },
+ #endif
+       {}
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4016-clk-sunxi-Add-support-for-the-D1-CCU.patch b/package/boot/uboot-sunxi/patches/4016-clk-sunxi-Add-support-for-the-D1-CCU.patch
new file mode 100644 (file)
index 0000000..6f5013b
--- /dev/null
@@ -0,0 +1,418 @@
+From 43f55d26fbe4c6cf7d4dced762167bb4c4a52993 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 21 Jul 2023 14:45:56 +0100
+Subject: [PATCH 4016/4052] 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.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Acked-by: Sean Anderson <seanga2@gmail.com>
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/clk/sunxi/Kconfig                 |   6 +
+ drivers/clk/sunxi/Makefile                |   1 +
+ drivers/clk/sunxi/clk_d1.c                |  84 ++++++++++++
+ drivers/clk/sunxi/clk_sunxi.c             |   5 +
+ include/dt-bindings/clock/sun20i-d1-ccu.h | 158 ++++++++++++++++++++++
+ include/dt-bindings/reset/sun20i-d1-ccu.h |  79 +++++++++++
+ 6 files changed, 333 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
+
+diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
+index bf11fad6ee..f65e482ba4 100644
+--- 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
+diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
+index 895da02ebe..90a277489d 100644
+--- 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
+diff --git a/drivers/clk/sunxi/clk_d1.c b/drivers/clk/sunxi/clk_d1.c
+new file mode 100644
+index 0000000000..9dae761de8
+--- /dev/null
++++ b/drivers/clk/sunxi/clk_d1.c
+@@ -0,0 +1,84 @@
++// 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_APB0]              = GATE_DUMMY,
++
++      [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),
++};
+diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
+index ec02a2d037..a0011a35d9 100644
+--- 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_desc;
+ 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;
+@@ -214,6 +215,10 @@ static const struct udevice_id sunxi_clk_ids[] = {
+ #ifdef CONFIG_CLK_SUNIV_F1C100S
+       { .compatible = "allwinner,suniv-f1c100s-ccu",
+         .data = (ulong)&f1c100s_ccu_desc },
++#endif
++#ifdef CONFIG_CLK_SUN20I_D1
++      { .compatible = "allwinner,sun20i-d1-ccu",
++        .data = (ulong)&d1_ccu_desc },
+ #endif
+       { }
+ };
+diff --git a/include/dt-bindings/clock/sun20i-d1-ccu.h b/include/dt-bindings/clock/sun20i-d1-ccu.h
+new file mode 100644
+index 0000000000..e143b99297
+--- /dev/null
++++ b/include/dt-bindings/clock/sun20i-d1-ccu.h
+@@ -0,0 +1,158 @@
++/* 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
++#define CLK_BUS_CAN0          145
++#define CLK_BUS_CAN1          146
++
++#endif /* _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_ */
+diff --git a/include/dt-bindings/reset/sun20i-d1-ccu.h b/include/dt-bindings/reset/sun20i-d1-ccu.h
+new file mode 100644
+index 0000000000..f8001cf50b
+--- /dev/null
++++ b/include/dt-bindings/reset/sun20i-d1-ccu.h
+@@ -0,0 +1,79 @@
++/* 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
++#define RST_BUS_CAN0          66
++#define RST_BUS_CAN1          67
++
++#endif /* _DT_BINDINGS_RST_SUN20I_D1_CCU_H_ */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4017-sunxi-clock-D1-R528-Enable-PLL-LDO-during-PLL1-setup.patch b/package/boot/uboot-sunxi/patches/4017-sunxi-clock-D1-R528-Enable-PLL-LDO-during-PLL1-setup.patch
new file mode 100644 (file)
index 0000000..c4f040e
--- /dev/null
@@ -0,0 +1,53 @@
+From 1b5b04c85989c73be3da502ce788e847b83f8e10 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:57 +0100
+Subject: [PATCH 4017/4052] sunxi: clock: D1/R528: Enable PLL LDO during PLL1
+ setup
+
+The D1/R528/T113s SoCs introduce a new "LDO enable" bit in the CPUX_PLL.
+Just enable that when we program that PLL.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h |  1 +
+ arch/arm/mach-sunxi/clock_sun50i_h6.c             | 12 +++++++-----
+ 2 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+index 37df4410ea..9895c2c220 100644
+--- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
++++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+@@ -228,6 +228,7 @@ struct sunxi_ccm_reg {
+ /* pll1 bit field */
+ #define CCM_PLL1_CTRL_EN              BIT(31)
++#define CCM_PLL1_LDO_EN                       BIT(30)
+ #define CCM_PLL1_LOCK_EN              BIT(29)
+ #define CCM_PLL1_LOCK                 BIT(28)
+ #define CCM_PLL1_OUT_EN                       BIT(27)
+diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+index 7926394cf7..90110eab10 100644
+--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
++++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+@@ -86,11 +86,13 @@ void clock_set_pll1(unsigned int clk)
+       writel(val, &ccm->cpu_axi_cfg);
+       /* clk = 24*n/p, p is ignored if clock is >288MHz */
+-      writel(CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2 |
+-#ifdef CONFIG_MACH_SUN50I_H616
+-             CCM_PLL1_OUT_EN |
+-#endif
+-             CCM_PLL1_CTRL_N(clk / 24000000), &ccm->pll1_cfg);
++      val = CCM_PLL1_CTRL_EN | CCM_PLL1_LOCK_EN | CCM_PLL1_CLOCK_TIME_2;
++      val |= CCM_PLL1_CTRL_N(clk / 24000000);
++      if (IS_ENABLED(CONFIG_MACH_SUN50I_H616))
++             val |= CCM_PLL1_OUT_EN;
++      if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
++             val |= CCM_PLL1_OUT_EN | CCM_PLL1_LDO_EN;
++      writel(val, &ccm->pll1_cfg);
+       while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_LOCK)) {}
+       /* Switch CPU to PLL1 */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4018-sunxi-clock-support-D1-R528-PLL6-clock.patch b/package/boot/uboot-sunxi/patches/4018-sunxi-clock-support-D1-R528-PLL6-clock.patch
new file mode 100644 (file)
index 0000000..b3ebf3e
--- /dev/null
@@ -0,0 +1,70 @@
+From a601a3257233308d99c5f34c44e26043ac196491 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:58 +0100
+Subject: [PATCH 4018/4052] sunxi: clock: support D1/R528 PLL6 clock
+
+The PLL_PERIPH0 clock changed a bit in the D1/R528/T113s SoCs: there is
+new P0 divider at bits [18:16], and the M divider is 1.
+
+Add code to support this version of "PLL6".
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ .../include/asm/arch-sunxi/clock_sun50i_h6.h  |  2 ++
+ arch/arm/mach-sunxi/clock_sun50i_h6.c         | 24 +++++++++++++------
+ 2 files changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+index 9895c2c220..8471e11aa0 100644
+--- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
++++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+@@ -249,6 +249,8 @@ struct sunxi_ccm_reg {
+ #define CCM_PLL6_CTRL_EN              BIT(31)
+ #define CCM_PLL6_LOCK_EN              BIT(29)
+ #define CCM_PLL6_LOCK                 BIT(28)
++#define CCM_PLL6_CTRL_P0_SHIFT                16
++#define CCM_PLL6_CTRL_P0_MASK         (0x7 << CCM_PLL6_CTRL_P0_SHIFT)
+ #define CCM_PLL6_CTRL_N_SHIFT         8
+ #define CCM_PLL6_CTRL_N_MASK          (0xff << CCM_PLL6_CTRL_N_SHIFT)
+ #define CCM_PLL6_CTRL_DIV1_SHIFT      0
+diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+index 90110eab10..607efe6a9c 100644
+--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
++++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+@@ -107,16 +107,26 @@ unsigned int clock_get_pll6(void)
+ {
+       struct sunxi_ccm_reg *const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+-      int m = IS_ENABLED(CONFIG_MACH_SUN50I_H6) ? 4 : 2;
+-
+       uint32_t rval = readl(&ccm->pll6_cfg);
+       int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT) + 1;
+-      int div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
+-                      CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
+       int div2 = ((rval & CCM_PLL6_CTRL_DIV2_MASK) >>
+-                      CCM_PLL6_CTRL_DIV2_SHIFT) + 1;
+-      /* The register defines PLL6-2X or PLL6-4X, not plain PLL6 */
+-      return 24000000 / m * n / div1 / div2;
++                  CCM_PLL6_CTRL_DIV2_SHIFT) + 1;
++      int div1, m;
++
++      if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) {
++              div1 = ((rval & CCM_PLL6_CTRL_P0_MASK) >>
++                      CCM_PLL6_CTRL_P0_SHIFT) + 1;
++              m = 1;
++      } else {
++              div1 = ((rval & CCM_PLL6_CTRL_DIV1_MASK) >>
++                      CCM_PLL6_CTRL_DIV1_SHIFT) + 1;
++              if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
++                      m = 4;
++              else
++                      m = 2;
++      }
++
++      return 24000000U * n / m / div1 / div2;
+ }
+ int clock_twi_onoff(int port, int state)
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4019-sunxi-clock-h6-prepare-for-PRCM-less-SoCs.patch b/package/boot/uboot-sunxi/patches/4019-sunxi-clock-h6-prepare-for-PRCM-less-SoCs.patch
new file mode 100644 (file)
index 0000000..d3f70d9
--- /dev/null
@@ -0,0 +1,75 @@
+From 5f144dac504c89850a5e37e475b1745137f81d1f Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:45:59 +0100
+Subject: [PATCH 4019/4052] sunxi: clock: h6: prepare for PRCM less SoCs
+
+The Allwinner D1/R528/T113 SoCs have a very minimal separate
+"management" power plane, with almost no device attached to it (so
+no r_i2c or r_uart). This means we don't need to flip any clock gates in
+the PRCM block, which in fact those SoCs do not have.
+
+Prepare the code for those SoCs by making the PRCM block optional in the
+H6 SPL clock code, which we otherwise share to this new family of SoCs.
+If the memory map (cpu.h) does not define the PRCM address, we simply
+skip any attempt to program gates there.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/mach-sunxi/clock_sun50i_h6.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+index 607efe6a9c..c3a4623d34 100644
+--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
++++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+@@ -4,14 +4,20 @@
+ #include <asm/arch/clock.h>
+ #include <asm/arch/prcm.h>
++#ifndef SUNXI_PRCM_BASE
++#define SUNXI_PRCM_BASE 0
++#endif
++
+ #ifdef CONFIG_SPL_BUILD
+-void clock_init_safe(void)
++
++static void clock_init_safe_prcm(void)
+ {
+-      struct sunxi_ccm_reg *const ccm =
+-              (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+       struct sunxi_prcm_reg *const prcm =
+               (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
++      if (!prcm)
++              return;
++
+       if (IS_ENABLED(CONFIG_MACH_SUN50I_H616)) {
+               /* this seems to enable PLLs on H616 */
+               setbits_le32(&prcm->sys_pwroff_gating, 0x10);
+@@ -27,6 +33,14 @@ void clock_init_safe(void)
+               /* set PLL VDD LDO output to 1.14 V */
+               setbits_le32(&prcm->pll_ldo_cfg, 0x60000);
+       }
++}
++
++void clock_init_safe(void)
++{
++      struct sunxi_ccm_reg *const ccm =
++              (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
++
++      clock_init_safe_prcm();
+       clock_set_pll1(408000000);
+@@ -141,6 +155,8 @@ int clock_twi_onoff(int port, int state)
+       value = BIT(GATE_SHIFT) | BIT (RESET_SHIFT);
+       if (port == 5) {
++              if (!prcm)
++                      return -ENODEV;
+               shift = 0;
+               ptr = &prcm->twi_gate_reset;
+       } else {
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4020-Kconfig-sunxi-prepare-for-using-drivers-ram-sunxi.patch b/package/boot/uboot-sunxi/patches/4020-Kconfig-sunxi-prepare-for-using-drivers-ram-sunxi.patch
new file mode 100644 (file)
index 0000000..953f894
--- /dev/null
@@ -0,0 +1,58 @@
+From 9d9fdd0d200b0af1250186186cd9061a72f4c341 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Sat, 26 Aug 2023 16:56:03 +0200
+Subject: [PATCH 4020/4052] Kconfig: sunxi: prepare for using drivers/ram/sunxi
+
+At the moment all Allwinner DRAM initialisation routines are stored in
+arch/arm/mach-sunxi, even though those "drivers" are just a giant
+collection of writel's, without any architectural dependency.
+
+The R528/T113-s SoC (with ARM cores) and the D1/D1s Soc (with RISC-V
+cores) share the same die, so should share the same DRAM init routines as
+well.
+
+To prepare for this, add a new sunxi directory inside drivers/ram, and
+add some stub entries to prepare for the addition of the share DRAM code
+for those SoCs.
+
+The RISC-V D1(s) SoCs will probably use SPL_DM, so make this entry
+depend on that already.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ drivers/ram/Kconfig       |  1 +
+ drivers/ram/sunxi/Kconfig | 13 +++++++++++++
+ 2 files changed, 14 insertions(+)
+ create mode 100644 drivers/ram/sunxi/Kconfig
+
+diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
+index e085119963..636374be59 100644
+--- a/drivers/ram/Kconfig
++++ b/drivers/ram/Kconfig
+@@ -112,3 +112,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"
+diff --git a/drivers/ram/sunxi/Kconfig b/drivers/ram/sunxi/Kconfig
+new file mode 100644
+index 0000000000..97e261de54
+--- /dev/null
++++ b/drivers/ram/sunxi/Kconfig
+@@ -0,0 +1,13 @@
++config DRAM_SUN20I_D1
++      bool "DM DRAM driver support for Allwinner D1"
++      depends on RAM && ARCH_SUNXI
++      default y
++      help
++        This enables support for DRAM drivers using the driver model
++        for Allwinner SoCs.
++
++config DRAM_SUN8I_R528
++      bool "DRAM driver support for Allwinner R528/T113s"
++      default y if MACH_SUN8I_R528
++      help
++        Select this DRAM controller driver for the R528/T113s SoCs.
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4021-sunxi-add-R528-T113-s3-D1-s-DRAM-initialisation-code.patch b/package/boot/uboot-sunxi/patches/4021-sunxi-add-R528-T113-s3-D1-s-DRAM-initialisation-code.patch
new file mode 100644 (file)
index 0000000..ba5d907
--- /dev/null
@@ -0,0 +1,1660 @@
+From 2c2c7ff45ae5a37909042dce3dbd66fa5bdb5fdb Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:46:01 +0100
+Subject: [PATCH 4021/4052] sunxi: add R528/T113-s3/D1(s) DRAM initialisation
+ code
+
+The Allwinner R528/T113-s/D1/D1s SoCs all share the same die, so use the
+same DRAM initialisation code.
+Make use of prior art here and lift some code from awboot[1], which
+carried init code based on earlier decompilation efforts, but with a
+GPL2 license tag.
+This code has been heavily reworked and cleaned up, to match previous
+DRAM routines for other SoCs, and also to be closer to U-Boot's coding
+style and support routines.
+The actual DRAM chip timing parameters are included in the main file,
+since they cover all DRAM types, and are protected by a new Kconfig
+CONFIG_SUNXI_DRAM_TYPE symbol, which allows the compiler to pick only
+the relevant settings, at build time.
+
+The relevant DRAM chips/board specific configuration parameters are
+delivered via Kconfig, so this code here should work for all supported
+SoCs and DRAM chips combinations.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ drivers/Makefile                   |    1 +
+ drivers/ram/Makefile               |    3 +
+ drivers/ram/sunxi/Kconfig          |   59 ++
+ drivers/ram/sunxi/Makefile         |    4 +
+ drivers/ram/sunxi/dram_sun20i_d1.c | 1432 ++++++++++++++++++++++++++++
+ drivers/ram/sunxi/dram_sun20i_d1.h |   73 ++
+ 6 files changed, 1572 insertions(+)
+ create mode 100644 drivers/ram/sunxi/Makefile
+ create mode 100644 drivers/ram/sunxi/dram_sun20i_d1.c
+ create mode 100644 drivers/ram/sunxi/dram_sun20i_d1.h
+
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 15d19d0c8a..1542ce7caf 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -52,6 +52,7 @@ obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/
+ obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/
+ obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/
+ obj-$(CONFIG_ARCH_IMX9) += ddr/imx/imx9/
++obj-$(CONFIG_DRAM_SUN8I_R528) += ram/
+ obj-$(CONFIG_SPL_DM_RESET) += reset/
+ obj-$(CONFIG_SPL_MUSB_NEW) += usb/musb-new/
+ obj-$(CONFIG_SPL_USB_GADGET) += usb/gadget/
+diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
+index 83948e2c43..ae3cf65fa4 100644
+--- a/drivers/ram/Makefile
++++ b/drivers/ram/Makefile
+@@ -10,6 +10,9 @@ obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/
+ obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
+ obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o
++obj-$(CONFIG_DRAM_SUN8I_R528) += sunxi/
++
++
+ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+ obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o
+diff --git a/drivers/ram/sunxi/Kconfig b/drivers/ram/sunxi/Kconfig
+index 97e261de54..657f47a870 100644
+--- a/drivers/ram/sunxi/Kconfig
++++ b/drivers/ram/sunxi/Kconfig
+@@ -11,3 +11,62 @@ config DRAM_SUN8I_R528
+       default y if MACH_SUN8I_R528
+       help
+         Select this DRAM controller driver for the R528/T113s SoCs.
++
++if DRAM_SUN20I_D1 || DRAM_SUN8I_R528
++
++config DRAM_SUNXI_ODT_EN
++      hex "DRAM ODT EN parameter"
++      default 0x1
++      help
++        ODT EN value from vendor DRAM settings.
++
++config DRAM_SUNXI_TPR0
++      hex "DRAM TPR0 parameter"
++      default 0x0
++      help
++        TPR0 value from vendor DRAM settings.
++
++config DRAM_SUNXI_TPR11
++      hex "DRAM TPR11 parameter"
++      default 0x0
++      help
++        TPR11 value from vendor DRAM settings.
++
++config DRAM_SUNXI_TPR12
++      hex "DRAM TPR12 parameter"
++      default 0x0
++      help
++        TPR12 value from vendor DRAM settings.
++
++config DRAM_SUNXI_TPR13
++      hex "DRAM TPR13 parameter"
++      default 0x0
++      help
++        TPR13 value from vendor DRAM settings. It tells which features
++        should be configured.
++
++choice
++      prompt "DRAM chip type"
++      default SUNXI_DRAM_TYPE_DDR3 if DRAM_SUN8I_R528 || DRAM_SUN20I_D1
++
++config SUNXI_DRAM_TYPE_DDR2
++        bool "DDR2 chips"
++
++config SUNXI_DRAM_TYPE_DDR3
++        bool "DDR3 chips"
++
++config SUNXI_DRAM_TYPE_LPDDR2
++        bool "LPDDR2 chips"
++
++config SUNXI_DRAM_TYPE_LPDDR3
++        bool "LPDDR3 chips"
++endchoice
++
++config SUNXI_DRAM_TYPE
++      int
++      default 2 if SUNXI_DRAM_TYPE_DDR2
++      default 3 if SUNXI_DRAM_TYPE_DDR3
++      default 6 if SUNXI_DRAM_TYPE_LPDDR2
++      default 7 if SUNXI_DRAM_TYPE_LPDDR3
++
++endif
+diff --git a/drivers/ram/sunxi/Makefile b/drivers/ram/sunxi/Makefile
+new file mode 100644
+index 0000000000..d6fb2cf0b6
+--- /dev/null
++++ b/drivers/ram/sunxi/Makefile
+@@ -0,0 +1,4 @@
++# SPDX-License-Identifier: GPL-2.0+
++
++obj-$(CONFIG_DRAM_SUN20I_D1) += dram_sun20i_d1.o
++obj-$(CONFIG_DRAM_SUN8I_R528) += dram_sun20i_d1.o
+diff --git a/drivers/ram/sunxi/dram_sun20i_d1.c b/drivers/ram/sunxi/dram_sun20i_d1.c
+new file mode 100644
+index 0000000000..c766fc2406
+--- /dev/null
++++ b/drivers/ram/sunxi/dram_sun20i_d1.c
+@@ -0,0 +1,1432 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Allwinner D1/D1s/R528/T113-sx DRAM initialisation
++ *
++ * As usual there is no documentation for the memory controller or PHY IP
++ * used here. The baseline of this code was lifted from awboot[1], which
++ * seems to be based on some form of de-compilation of some original Allwinner
++ * code bits (with a GPL2 license tag from the very beginning).
++ * This version here is a reworked version, to match the U-Boot coding style
++ * and style of the other Allwinner DRAM drivers.
++ *
++ * [1] https://github.com/szemzoa/awboot.git
++ */
++
++#include <asm/io.h>
++#include <common.h>
++#ifdef CONFIG_RAM
++  #include <dm.h>
++  #include <ram.h>
++#endif
++#include <linux/delay.h>
++
++#include "dram_sun20i_d1.h"
++
++#ifndef SUNXI_SID_BASE
++#define SUNXI_SID_BASE        0x3006200
++#endif
++
++#ifndef SUNXI_CCM_BASE
++#define SUNXI_CCM_BASE        0x2001000
++#endif
++
++static void sid_read_ldoB_cal(const dram_para_t *para)
++{
++      uint32_t reg;
++
++      reg = (readl(SUNXI_SID_BASE + 0x1c) & 0xff00) >> 8;
++
++      if (reg == 0)
++              return;
++
++      switch (para->dram_type) {
++      case SUNXI_DRAM_TYPE_DDR2:
++              break;
++      case SUNXI_DRAM_TYPE_DDR3:
++              if (reg > 0x20)
++                      reg -= 0x16;
++              break;
++      default:
++              reg = 0;
++              break;
++      }
++
++      clrsetbits_le32(0x3000150, 0xff00, reg << 8);
++}
++
++static void dram_voltage_set(const dram_para_t *para)
++{
++      int vol;
++
++      switch (para->dram_type) {
++      case SUNXI_DRAM_TYPE_DDR2:
++              vol = 47;
++              break;
++      case SUNXI_DRAM_TYPE_DDR3:
++              vol = 25;
++              break;
++      default:
++              vol = 0;
++              break;
++      }
++
++      clrsetbits_le32(0x3000150, 0x20ff00, vol << 8);
++
++      udelay(1);
++
++      sid_read_ldoB_cal(para);
++}
++
++static void dram_enable_all_master(void)
++{
++      writel(~0, 0x3102020);
++      writel(0xff, 0x3102024);
++      writel(0xffff, 0x3102028);
++      udelay(10);
++}
++
++static void dram_disable_all_master(void)
++{
++      writel(1, 0x3102020);
++      writel(0, 0x3102024);
++      writel(0, 0x3102028);
++      udelay(10);
++}
++
++static void eye_delay_compensation(const dram_para_t *para)
++{
++      uint32_t delay;
++      unsigned long ptr;
++
++      // DATn0IOCR, n =  0...7
++      delay = (para->dram_tpr11 & 0xf) << 9;
++      delay |= (para->dram_tpr12 & 0xf) << 1;
++      for (ptr = 0x3103310; ptr < 0x3103334; ptr += 4)
++              setbits_le32(ptr, delay);
++
++      // DATn1IOCR, n =  0...7
++      delay = (para->dram_tpr11 & 0xf0) << 5;
++      delay |= (para->dram_tpr12 & 0xf0) >> 3;
++      for (ptr = 0x3103390; ptr != 0x31033b4; ptr += 4)
++              setbits_le32(ptr, delay);
++
++      // PGCR0: assert AC loopback FIFO reset
++      clrbits_le32(0x3103100, 0x04000000);
++
++      // ??
++
++      delay = (para->dram_tpr11 & 0xf0000) >> 7;
++      delay |= (para->dram_tpr12 & 0xf0000) >> 15;
++      setbits_le32(0x3103334, delay);
++      setbits_le32(0x3103338, delay);
++
++      delay = (para->dram_tpr11 & 0xf00000) >> 11;
++      delay |= (para->dram_tpr12 & 0xf00000) >> 19;
++      setbits_le32(0x31033b4, delay);
++      setbits_le32(0x31033b8, delay);
++
++      setbits_le32(0x310333c, (para->dram_tpr11 & 0xf0000) << 9);
++      setbits_le32(0x31033bc, (para->dram_tpr11 & 0xf00000) << 5);
++
++      // PGCR0: release AC loopback FIFO reset
++      setbits_le32(0x3103100, BIT(26));
++
++      udelay(1);
++
++      delay = (para->dram_tpr10 & 0xf0) << 4;
++      for (ptr = 0x3103240; ptr != 0x310327c; ptr += 4)
++              setbits_le32(ptr, delay);
++      for (ptr = 0x3103228; ptr != 0x3103240; ptr += 4)
++              setbits_le32(ptr, delay);
++
++      setbits_le32(0x3103218, (para->dram_tpr10 & 0x0f) << 8);
++      setbits_le32(0x310321c, (para->dram_tpr10 & 0x0f) << 8);
++
++      setbits_le32(0x3103280, (para->dram_tpr10 & 0xf00) >> 4);
++}
++
++/*
++ * 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.
++ */
++static void mctl_set_timing_params(const dram_para_t *para,
++                                 const dram_config_t *config)
++{
++      /* DRAM_TPR0 */
++      u8 tccd         = 2;
++      u8 tfaw;
++      u8 trrd;
++      u8 trcd;
++      u8 trc;
++
++      /* DRAM_TPR1 */
++      u8 txp;
++      u8 twtr;
++      u8 trtp         = 4;
++      u8 twr;
++      u8 trp;
++      u8 tras;
++
++      /* DRAM_TPR2 */
++      u16 trefi;
++      u16 trfc;
++
++      u8 tcksrx;
++      u8 tckesr;
++      u8 trd2wr;
++      u8 twr2rd;
++      u8 trasmax;
++      u8 twtp;
++      u8 tcke;
++      u8 tmod;
++      u8 tmrd;
++      u8 tmrw;
++
++      u8 tcl;
++      u8 tcwl;
++      u8 t_rdata_en;
++      u8 wr_latency;
++
++      u32 mr0;
++      u32 mr1;
++      u32 mr2;
++      u32 mr3;
++
++      u32 tdinit0;
++      u32 tdinit1;
++      u32 tdinit2;
++      u32 tdinit3;
++
++      switch (para->dram_type) {
++      case SUNXI_DRAM_TYPE_DDR2:
++              /* DRAM_TPR0 */
++              tfaw            = ns_to_t(50);
++              trrd            = ns_to_t(10);
++              trcd            = ns_to_t(20);
++              trc             = ns_to_t(65);
++
++              /* DRAM_TPR1 */
++              txp             = 2;
++              twtr            = ns_to_t(8);
++              twr             = ns_to_t(15);
++              trp             = ns_to_t(15);
++              tras            = ns_to_t(45);
++
++              /* DRAM_TRP2 */
++              trfc            = ns_to_t(328);
++              trefi           = ns_to_t(7800) / 32;
++
++              trasmax         = CONFIG_DRAM_CLK / 30;
++              if (CONFIG_DRAM_CLK < 409) {
++                      t_rdata_en      = 1;
++                      tcl             = 3;
++                      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;
++              tmrw            = 0;
++              twr2rd          = twtr + 5;
++              tcwl            = 0;
++
++              mr1             = para->dram_mr1;
++              mr2             = 0;
++              mr3             = 0;
++
++              tdinit0         = 200 * CONFIG_DRAM_CLK + 1;
++              tdinit1         = 100 * CONFIG_DRAM_CLK / 1000 + 1;
++              tdinit2         = 200 * CONFIG_DRAM_CLK + 1;
++              tdinit3         = 1 * CONFIG_DRAM_CLK + 1;
++
++              break;
++      case SUNXI_DRAM_TYPE_DDR3:
++              trfc            = ns_to_t(350);
++              trefi           = ns_to_t(7800) / 32 + 1;       // XXX
++
++              twtr            = ns_to_t(8) + 2;               // + 2 ? XXX
++              /* Only used by trd2wr calculation, which gets discard below */
++//            twr             = max(ns_to_t(15), 2);
++              trrd            = max(ns_to_t(10), 2);
++              txp             = max(ns_to_t(10), 2);
++
++              if (CONFIG_DRAM_CLK <= 800) {
++                      tfaw            = ns_to_t(50);
++                      trcd            = ns_to_t(15);
++                      trp             = ns_to_t(15);
++                      trc             = ns_to_t(53);
++                      tras            = ns_to_t(38);
++
++                      mr0             = 0x1c70;
++                      mr2             = 0x18;
++                      tcl             = 6;
++                      wr_latency      = 2;
++                      tcwl            = 4;
++                      t_rdata_en      = 4;
++              } else {
++                      tfaw            = ns_to_t(35);
++                      trcd            = ns_to_t(14);
++                      trp             = ns_to_t(14);
++                      trc             = ns_to_t(48);
++                      tras            = ns_to_t(34);
++
++                      mr0             = 0x1e14;
++                      mr2             = 0x20;
++                      tcl             = 7;
++                      wr_latency      = 3;
++                      tcwl            = 5;
++                      t_rdata_en      = 5;
++              }
++
++              trasmax         = CONFIG_DRAM_CLK / 30;
++              twtp            = tcwl + 2 + twtr;              // WL+BL/2+tWTR
++              /* Gets overwritten below */
++//            trd2wr          = tcwl + 2 + twr;               // WL+BL/2+tWR
++              twr2rd          = tcwl + twtr;                  // WL+tWTR
++
++              tdinit0         = 500 * CONFIG_DRAM_CLK + 1;    // 500 us
++              tdinit1         = 360 * CONFIG_DRAM_CLK / 1000 + 1;   // 360 ns
++              tdinit2         = 200 * CONFIG_DRAM_CLK + 1;    // 200 us
++              tdinit3         = 1 * CONFIG_DRAM_CLK + 1;      //   1 us
++
++              mr1             = para->dram_mr1;
++              mr3             = 0;
++              tcke            = 3;
++              tcksrx          = 5;
++              tckesr          = 4;
++              if (((config->dram_tpr13 & 0xc) == 0x04) || CONFIG_DRAM_CLK < 912)
++                      trd2wr     = 5;
++              else
++                      trd2wr     = 6;
++
++              tmod            = 12;
++              tmrd            = 4;
++              tmrw            = 0;
++
++              break;
++      case SUNXI_DRAM_TYPE_LPDDR2:
++              tfaw            = max(ns_to_t(50), 4);
++              trrd            = max(ns_to_t(10), 1);
++              trcd            = max(ns_to_t(24), 2);
++              trc             = ns_to_t(70);
++              txp             = ns_to_t(8);
++              if (txp < 2) {
++                      txp++;
++                      twtr    = 2;
++              } else {
++                      twtr    = txp;
++              }
++              twr             = max(ns_to_t(15), 2);
++              trp             = ns_to_t(17);
++              tras            = ns_to_t(42);
++              trefi           = ns_to_t(3900) / 32;
++              trfc            = ns_to_t(210);
++
++              trasmax         = CONFIG_DRAM_CLK / 60;
++              mr3             = para->dram_mr3;
++              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 * CONFIG_DRAM_CLK + 1;
++              tdinit1         = 100 * CONFIG_DRAM_CLK / 1000 + 1;
++              tdinit2         = 11 * CONFIG_DRAM_CLK + 1;
++              tdinit3         = 1 * CONFIG_DRAM_CLK + 1;
++              twr2rd          = twtr + 5;
++              tcwl            = 2;
++              mr1             = 195;
++              mr0             = 0;
++
++              break;
++      case SUNXI_DRAM_TYPE_LPDDR3:
++              tfaw            = max(ns_to_t(50), 4);
++              trrd            = max(ns_to_t(10), 1);
++              trcd            = max(ns_to_t(24), 2);
++              trc             = ns_to_t(70);
++              twtr            = max(ns_to_t(8), 2);
++              twr             = max(ns_to_t(15), 2);
++              trp             = ns_to_t(17);
++              tras            = ns_to_t(42);
++              trefi           = ns_to_t(3900) / 32;
++              trfc            = ns_to_t(210);
++              txp             = twtr;
++
++              trasmax         = CONFIG_DRAM_CLK / 60;
++              if (CONFIG_DRAM_CLK < 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             = para->dram_mr3;
++              tcksrx          = 5;
++              tckesr          = 5;
++              trd2wr          = 13;
++              tcke            = 3;
++              tmod            = 12;
++              tdinit0         = 400 * CONFIG_DRAM_CLK + 1;
++              tdinit1         = 500 * CONFIG_DRAM_CLK / 1000 + 1;
++              tdinit2         = 11 * CONFIG_DRAM_CLK + 1;
++              tdinit3         = 1 * CONFIG_DRAM_CLK + 1;
++              tmrd            = 5;
++              tmrw            = 5;
++              twr2rd          = tcwl + twtr + 5;
++              mr1             = 195;
++              mr0             = 0;
++
++              break;
++      default:
++              trfc            = 128;
++              trp             = 6;
++              trefi           = 98;
++              txp             = 10;
++              twr             = 8;
++              twtr            = 3;
++              tras            = 14;
++              tfaw            = 16;
++              trc             = 20;
++              trcd            = 6;
++              trrd            = 3;
++
++              twr2rd          = 8;
++              tcksrx          = 4;
++              tckesr          = 3;
++              trd2wr          = 4;
++              trasmax         = 27;
++              twtp            = 12;
++              tcke            = 2;
++              tmod            = 6;
++              tmrd            = 2;
++              tmrw            = 0;
++              tcwl            = 3;
++              tcl             = 3;
++              wr_latency      = 1;
++              t_rdata_en      = 1;
++              mr3             = 0;
++              mr2             = 0;
++              mr1             = 0;
++              mr0             = 0;
++              tdinit3         = 0;
++              tdinit2         = 0;
++              tdinit1         = 0;
++              tdinit0         = 0;
++
++              break;
++      }
++
++      /* Set mode registers */
++      writel(mr0, 0x3103030);
++      writel(mr1, 0x3103034);
++      writel(mr2, 0x3103038);
++      writel(mr3, 0x310303c);
++      /* TODO: dram_odt_en is either 0x0 or 0x1, so right shift looks weird */
++      writel((para->dram_odt_en >> 4) & 0x3, 0x310302c);
++
++      /* Set dram timing DRAMTMG0 - DRAMTMG5 */
++      writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | (tras << 0),
++              0x3103058);
++      writel((txp << 16) | (trtp << 8) | (trc << 0),
++              0x310305c);
++      writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | (twr2rd << 0),
++              0x3103060);
++      writel((tmrw << 16) | (tmrd << 12) | (tmod << 0),
++              0x3103064);
++      writel((trcd << 24) | (tccd << 16) | (trrd << 8) | (trp << 0),
++              0x3103068);
++      writel((tcksrx << 24) | (tcksrx << 16) | (tckesr << 8) | (tcke << 0),
++              0x310306c);
++
++      /* Set dual rank timing */
++      clrsetbits_le32(0x3103078, 0xf000ffff,
++                      (CONFIG_DRAM_CLK < 800) ? 0xf0006610 : 0xf0007610);
++
++      /* Set phy interface time PITMG0, PTR3, PTR4 */
++      writel((0x2 << 24) | (t_rdata_en << 16) | BIT(8) | (wr_latency << 0),
++              0x3103080);
++      writel(((tdinit0 << 0) | (tdinit1 << 20)), 0x3103050);
++      writel(((tdinit2 << 0) | (tdinit3 << 20)), 0x3103054);
++
++      /* Set refresh timing and mode */
++      writel((trefi << 16) | (trfc << 0), 0x3103090);
++      writel((trefi << 15) & 0x0fff0000, 0x3103094);
++}
++
++// Purpose of this routine seems to be to initialize the PLL driving
++// the MBUS and sdram.
++//
++static int ccu_set_pll_ddr_clk(int index, const dram_para_t *para,
++                             const dram_config_t *config)
++{
++      unsigned int val, clk, n;
++
++      if (config->dram_tpr13 & BIT(6))
++              clk = para->dram_tpr9;
++      else
++              clk = para->dram_clk;
++
++      // set VCO clock divider
++      n = (clk * 2) / 24;
++
++      val = readl(SUNXI_CCM_BASE + 0x10);
++      val &= ~0x0007ff03;                     // clear dividers
++      val |= (n - 1) << 8;                    // set PLL division
++      val |= BIT(31) | BIT(30);               // enable PLL and LDO
++      writel(val | BIT(29), SUNXI_CCM_BASE + 0x10);
++
++      // wait for PLL to lock
++      while ((readl(SUNXI_CCM_BASE + 0x10) & BIT(28)) == 0)
++              ;
++
++      udelay(20);
++
++      // enable PLL output
++      setbits_le32(SUNXI_CCM_BASE + 0x0, BIT(27));
++
++      // turn clock gate on
++      val = readl(SUNXI_CCM_BASE + 0x800);
++      val &= ~0x03000303;             // select DDR clk source, n=1, m=1
++      val |= BIT(31);                 // turn clock on
++      writel(val, SUNXI_CCM_BASE + 0x800);
++
++      return n * 24;
++}
++
++/* Set up the PLL and clock gates for the DRAM controller and MBUS clocks. */
++static void mctl_sys_init(const dram_para_t *para, const dram_config_t *config)
++{
++      // assert MBUS reset
++      clrbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
++
++      // turn off sdram clock gate, assert sdram reset
++      clrbits_le32(SUNXI_CCM_BASE + 0x80c, 0x10001);
++      clrsetbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(30), BIT(27));
++      udelay(10);
++
++      // set ddr pll clock
++      ccu_set_pll_ddr_clk(0, para, config);
++      udelay(100);
++      dram_disable_all_master();
++
++      // release sdram reset
++      setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(16));
++
++      // release MBUS reset
++      setbits_le32(SUNXI_CCM_BASE + 0x540, BIT(30));
++      setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(30));
++
++      udelay(5);
++
++      // turn on sdram clock gate
++      setbits_le32(SUNXI_CCM_BASE + 0x80c, BIT(0));
++
++      // turn dram clock gate on, trigger sdr clock update
++      setbits_le32(SUNXI_CCM_BASE + 0x800, BIT(31) | BIT(27));
++      udelay(5);
++
++      // mCTL clock enable
++      writel(0x8000, 0x310300c);
++      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).
++//
++static void mctl_com_init(const dram_para_t *para, const dram_config_t *config)
++{
++      uint32_t val, width;
++      unsigned long ptr;
++      int i;
++
++      // purpose ??
++      clrsetbits_le32(0x3102008, 0x3f00, 0x2000);
++
++      // set SDRAM type and word width
++      val  = readl(0x3102000) & ~0x00fff000;
++      val |= (para->dram_type & 0x7) << 16;           // DRAM type
++      val |= (~config->dram_para2 & 0x1) << 12;               // DQ width
++      val |= BIT(22);                                 // ??
++      if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
++          para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
++              val |= BIT(19);         // type 6 and 7 must use 1T
++      } else {
++              if (config->dram_tpr13 & BIT(5))
++                      val |= BIT(19);
++      }
++      writel(val, 0x3102000);
++
++      // init rank / bank / row for single/dual or two different ranks
++      if ((config->dram_para2 & BIT(8)) &&
++          ((config->dram_para2 & 0xf000) != 0x1000))
++              width = 32;
++      else
++              width = 16;
++
++      ptr = 0x3102000;
++      for (i = 0; i < width; i += 16) {
++              val = readl(ptr) & 0xfffff000;
++
++              val |= (config->dram_para2 >> 12) & 0x3; // rank
++              val |= ((config->dram_para1 >> (i + 12)) << 2) & 0x4; // bank - 2
++              val |= (((config->dram_para1 >> (i + 4)) - 1) << 4) & 0xff; // row - 1
++
++              // convert from page size to column addr width - 3
++              switch ((config->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(val, ptr);
++              ptr += 4;
++      }
++
++      // set ODTMAP based on number of ranks in use
++      val = (readl(0x3102000) & 0x1) ? 0x303 : 0x201;
++      writel(val, 0x3103120);
++
++      // set mctl reg 3c4 to zero when using half DQ
++      if (config->dram_para2 & BIT(0))
++              writel(0, 0x31033c4);
++
++      // purpose ??
++      if (para->dram_tpr4) {
++                setbits_le32(0x3102000, (para->dram_tpr4 & 0x3) << 25);
++                setbits_le32(0x3102004, (para->dram_tpr4 & 0x7fc) << 10);
++      }
++}
++
++static const uint8_t ac_remapping_tables[][22] = {
++      [0] = { 0 },
++      [1] = {  1,  9,  3,  7,  8, 18,  4, 13,  5,  6, 10,
++               2, 14, 12,  0,  0, 21, 17, 20, 19, 11, 22 },
++      [2] = {  4,  9,  3,  7,  8, 18,  1, 13,  2,  6, 10,
++               5, 14, 12,  0,  0, 21, 17, 20, 19, 11, 22 },
++      [3] = {  1,  7,  8, 12, 10, 18,  4, 13,  5,  6,  3,
++               2,  9,  0,  0,  0, 21, 17, 20, 19, 11, 22 },
++      [4] = {  4, 12, 10,  7,  8, 18,  1, 13,  2,  6,  3,
++               5,  9,  0,  0,  0, 21, 17, 20, 19, 11, 22 },
++      [5] = { 13,  2,  7,  9, 12, 19,  5,  1,  6,  3,  4,
++               8, 10,  0,  0,  0, 21, 22, 18, 17, 11, 20 },
++      [6] = {  3, 10,  7, 13,  9, 11,  1,  2,  4,  6,  8,
++               5, 12,  0,  0,  0, 20,  1,  0, 21, 22, 17 },
++      [7] = {  3,  2,  4,  7,  9,  1, 17, 12, 18, 14, 13,
++               8, 15,  6, 10,  5, 19, 22, 16, 21, 20, 11 },
++};
++
++/*
++ * This routine chooses one of several remapping tables for 22 lines.
++ * It is unclear which lines are being remapped. It seems to pick
++ * table cfg7 for the Nezha board.
++ */
++static void mctl_phy_ac_remapping(const dram_para_t *para,
++                                const dram_config_t *config)
++{
++      const uint8_t *cfg;
++      uint32_t fuse, val;
++
++      /*
++       * It is unclear whether the LPDDRx types don't need any remapping,
++       * or whether the original code just didn't provide tables.
++       */
++      if (para->dram_type != SUNXI_DRAM_TYPE_DDR2 &&
++          para->dram_type != SUNXI_DRAM_TYPE_DDR3)
++              return;
++
++      fuse = (readl(SUNXI_SID_BASE + 0x28) & 0xf00) >> 8;
++      debug("DDR efuse: 0x%x\n", fuse);
++
++      if (para->dram_type == SUNXI_DRAM_TYPE_DDR2) {
++              if (fuse == 15)
++                      return;
++              cfg = ac_remapping_tables[6];
++      } else {
++              if (config->dram_tpr13 & 0xc0000) {
++                      cfg = ac_remapping_tables[7];
++              } else {
++                      switch (fuse) {
++                      case 8: cfg = ac_remapping_tables[2]; break;
++                      case 9: cfg = ac_remapping_tables[3]; break;
++                      case 10: cfg = ac_remapping_tables[5]; break;
++                      case 11: cfg = ac_remapping_tables[4]; break;
++                      default:
++                      case 12: cfg = ac_remapping_tables[1]; break;
++                      case 13:
++                      case 14: cfg = ac_remapping_tables[0]; break;
++                      }
++              }
++      }
++
++      val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
++            (cfg[1] << 10) | (cfg[0] << 5);
++      writel(val, 0x3102500);
++
++      val = (cfg[10] << 25) | (cfg[9] << 20) | (cfg[8] << 15) |
++            (cfg[ 7] << 10) | (cfg[6] <<  5) | cfg[5];
++      writel(val, 0x3102504);
++
++      val = (cfg[15] << 20) | (cfg[14] << 15) | (cfg[13] << 10) |
++            (cfg[12] <<  5) | cfg[11];
++      writel(val, 0x3102508);
++
++      val = (cfg[21] << 25) | (cfg[20] << 20) | (cfg[19] << 15) |
++            (cfg[18] << 10) | (cfg[17] <<  5) | cfg[16];
++      writel(val, 0x310250c);
++
++      val = (cfg[4] << 25) | (cfg[3] << 20) | (cfg[2] << 15) |
++            (cfg[1] << 10) | (cfg[0] <<  5) | 1;
++      writel(val, 0x3102500);
++}
++
++// Init the controller channel. The key part is placing commands in the main
++// command register (PIR, 0x3103000) and checking command status (PGSR0, 0x3103010).
++//
++static unsigned int mctl_channel_init(unsigned int ch_index,
++                                    const dram_para_t *para,
++                                    const dram_config_t *config)
++{
++      unsigned int val, dqs_gating_mode;
++
++      dqs_gating_mode = (config->dram_tpr13 & 0xc) >> 2;
++
++      // set DDR clock to half of CPU clock
++      clrsetbits_le32(0x310200c, 0xfff, (para->dram_clk / 2) - 1);
++
++      // MRCTRL0 nibble 3 undocumented
++      clrsetbits_le32(0x3103108, 0xf00, 0x300);
++
++      if (para->dram_odt_en)
++              val = 0;
++      else
++              val = BIT(5);
++
++      // DX0GCR0
++      if (para->dram_clk > 672)
++              clrsetbits_le32(0x3103344, 0xf63e, val);
++      else
++              clrsetbits_le32(0x3103344, 0xf03e, val);
++
++      // DX1GCR0
++      if (para->dram_clk > 672) {
++                setbits_le32(0x3103344, 0x400);
++              clrsetbits_le32(0x31033c4, 0xf63e, val);
++      } else {
++              clrsetbits_le32(0x31033c4, 0xf03e, val);
++      }
++
++      // 0x3103208 undocumented
++      setbits_le32(0x3103208, BIT(1));
++
++      eye_delay_compensation(para);
++
++      // set PLL SSCG ?
++      val = readl(0x3103108);
++      if (dqs_gating_mode == 1) {
++              clrsetbits_le32(0x3103108, 0xc0, 0);
++              clrbits_le32(0x31030bc, 0x107);
++      } else if (dqs_gating_mode == 2) {
++              clrsetbits_le32(0x3103108, 0xc0, 0x80);
++
++              clrsetbits_le32(0x31030bc, 0x107,
++                              (((config->dram_tpr13 >> 16) & 0x1f) - 2) | 0x100);
++              clrsetbits_le32(0x310311c, BIT(31), BIT(27));
++      } else {
++              clrbits_le32(0x3103108, 0x40);
++              udelay(10);
++              setbits_le32(0x3103108, 0xc0);
++      }
++
++      if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR2 ||
++          para->dram_type == SUNXI_DRAM_TYPE_LPDDR3) {
++              if (dqs_gating_mode == 1)
++                      clrsetbits_le32(0x310311c, 0x080000c0, 0x80000000);
++              else
++                      clrsetbits_le32(0x310311c, 0x77000000, 0x22000000);
++      }
++
++      clrsetbits_le32(0x31030c0, 0x0fffffff,
++                      (config->dram_para2 & BIT(12)) ? 0x03000001 : 0x01000007);
++
++      if (readl(0x70005d4) & BIT(16)) {
++              clrbits_le32(0x7010250, 0x2);
++              udelay(10);
++      }
++
++      // Set ZQ config
++      clrsetbits_le32(0x3103140, 0x3ffffff,
++                      (para->dram_zq & 0x00ffffff) | BIT(25));
++
++      // Initialise DRAM controller
++      if (dqs_gating_mode == 1) {
++              //writel(0x52, 0x3103000); // prep PHY reset + PLL init + z-cal
++              writel(0x53, 0x3103000); // Go
++
++              while ((readl(0x3103010) & 0x1) == 0) {
++              } // wait for IDONE
++              udelay(10);
++
++              // 0x520 = prep DQS gating + DRAM init + d-cal
++              if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
++                      writel(0x5a0, 0x3103000);               // + DRAM reset
++              else
++                      writel(0x520, 0x3103000);
++      } else {
++              if ((readl(0x70005d4) & (1 << 16)) == 0) {
++                      // prep DRAM init + PHY reset + d-cal + PLL init + z-cal
++                      if (para->dram_type == SUNXI_DRAM_TYPE_DDR3)
++                              writel(0x1f2, 0x3103000);       // + DRAM reset
++                      else
++                              writel(0x172, 0x3103000);
++              } else {
++                      // prep PHY reset + d-cal + z-cal
++                      writel(0x62, 0x3103000);
++              }
++      }
++
++      setbits_le32(0x3103000, 0x1);            // GO
++
++      udelay(10);
++      while ((readl(0x3103010) & 0x1) == 0) {
++      } // wait for IDONE
++
++      if (readl(0x70005d4) & BIT(16)) {
++              clrsetbits_le32(0x310310c, 0x06000000, 0x04000000);
++              udelay(10);
++
++              setbits_le32(0x3103004, 0x1);
++
++              while ((readl(0x3103018) & 0x7) != 0x3) {
++              }
++
++              clrbits_le32(0x7010250, 0x1);
++              udelay(10);
++
++              clrbits_le32(0x3103004, 0x1);
++
++              while ((readl(0x3103018) & 0x7) != 0x1) {
++              }
++
++              udelay(15);
++
++              if (dqs_gating_mode == 1) {
++                      clrbits_le32(0x3103108, 0xc0);
++                      clrsetbits_le32(0x310310c, 0x06000000, 0x02000000);
++                      udelay(1);
++                      writel(0x401, 0x3103000);
++
++                      while ((readl(0x3103010) & 0x1) == 0) {
++                      }
++              }
++      }
++
++      // Check for training error
++      if (readl(0x3103010) & BIT(20)) {
++              printf("ZQ calibration error, check external 240 ohm resistor\n");
++              return 0;
++      }
++
++      // STATR = Zynq STAT? Wait for status 'normal'?
++      while ((readl(0x3103018) & 0x1) == 0) {
++      }
++
++      setbits_le32(0x310308c, BIT(31));
++      udelay(10);
++      clrbits_le32(0x310308c, BIT(31));
++      udelay(10);
++      setbits_le32(0x3102014, BIT(31));
++      udelay(10);
++
++      clrbits_le32(0x310310c, 0x06000000);
++
++      if (dqs_gating_mode == 1)
++              clrsetbits_le32(0x310311c, 0xc0, 0x40);
++
++      return 1;
++}
++
++static unsigned int calculate_rank_size(uint32_t regval)
++{
++      unsigned int bits;
++
++      bits = (regval >> 8) & 0xf;     /* page size - 3 */
++      bits += (regval >> 4) & 0xf;    /* row width - 1 */
++      bits += (regval >> 2) & 0x3;    /* bank count - 2 */
++      bits -= 14;                     /* 1MB = 20 bits, minus above 6 = 14 */
++
++      return 1U << bits;
++}
++
++/*
++ * 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.
++ */
++static unsigned int DRAMC_get_dram_size(void)
++{
++      uint32_t val;
++      unsigned int size;
++
++      val = readl(0x3102000);         /* MC_WORK_MODE0 */
++      size = calculate_rank_size(val);
++      if ((val & 0x3) == 0)           /* single rank? */
++              return size;
++
++      val = readl(0x3102004);         /* MC_WORK_MODE1 */
++      if ((val & 0x3) == 0)           /* two identical ranks? */
++              return size * 2;
++
++      /* add sizes of both ranks */
++      return size + calculate_rank_size(val);
++}
++
++/*
++ * 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.
++ */
++static int dqs_gate_detect(dram_config_t *config)
++{
++      uint32_t dx0, dx1;
++
++      if ((readl(0x3103010) & BIT(22)) == 0) {
++              config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
++              debug("dual rank and full DQ\n");
++
++              return 1;
++      }
++
++      dx0 = (readl(0x3103348) & 0x3000000) >> 24;
++      if (dx0 == 0) {
++              config->dram_para2 = (config->dram_para2 & ~0xf) | 0x1001;
++              debug("dual rank and half DQ\n");
++
++              return 1;
++      }
++
++      if (dx0 == 2) {
++              dx1 = (readl(0x31033c8) & 0x3000000) >> 24;
++              if (dx1 == 2) {
++                      config->dram_para2 = config->dram_para2 & ~0xf00f;
++                      debug("single rank and full DQ\n");
++              } else {
++                      config->dram_para2 = (config->dram_para2 & ~0xf00f) | BIT(0);
++                      debug("single rank and half DQ\n");
++              }
++
++              return 1;
++      }
++
++      if ((config->dram_tpr13 & BIT(29)) == 0)
++              return 0;
++
++      debug("DX0 state: %d\n", dx0);
++      debug("DX1 state: %d\n", dx1);
++
++      return 0;
++}
++
++static int dramc_simple_wr_test(unsigned int mem_mb, int len)
++{
++      unsigned int  offs      = (mem_mb / 2) << 18; // half of memory size
++      unsigned int  patt1 = 0x01234567;
++      unsigned int  patt2 = 0xfedcba98;
++      unsigned int *addr, v1, v2, i;
++
++      addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
++      for (i = 0; i != len; i++, addr++) {
++              writel(patt1 + i, (unsigned long)addr);
++              writel(patt2 + i, (unsigned long)(addr + offs));
++      }
++
++      addr = (unsigned int *)CFG_SYS_SDRAM_BASE;
++      for (i = 0; i != len; i++) {
++              v1 = readl((unsigned long)(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((unsigned long)(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;
++              }
++      }
++
++      debug("DRAM: simple test OK\n");
++      return 0;
++}
++
++// Set the Vref mode for the controller
++//
++static void mctl_vrefzq_init(const dram_para_t *para, const dram_config_t *config)
++{
++      if (config->dram_tpr13 & BIT(17))
++              return;
++
++      clrsetbits_le32(0x3103110, 0x7f7f7f7f, para->dram_tpr5);
++
++      // IOCVR1
++      if ((config->dram_tpr13 & BIT(16)) == 0)
++              clrsetbits_le32(0x3103114, 0x7f, para->dram_tpr6 & 0x7f);
++}
++
++// 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.
++//
++static int mctl_core_init(const dram_para_t *para, const dram_config_t *config)
++{
++      mctl_sys_init(para, config);
++
++      mctl_vrefzq_init(para, config);
++
++      mctl_com_init(para, config);
++
++      mctl_phy_ac_remapping(para, config);
++
++      mctl_set_timing_params(para, config);
++
++      return mctl_channel_init(0, para, config);
++}
++
++/*
++ * This routine sizes a DRAM device by cycling through address lines and
++ * figuring out if they are 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.
++ */
++static int auto_scan_dram_size(const dram_para_t *para, dram_config_t *config)
++{
++      unsigned int rval, i, j, rank, maxrank, offs;
++      unsigned int shft;
++      unsigned long ptr, mc_work_mode, chk;
++
++      if (mctl_core_init(para, config) == 0) {
++              printf("DRAM initialisation error : 0\n");
++              return 0;
++      }
++
++      maxrank = (config->dram_para2 & 0xf000) ? 2 : 1;
++      mc_work_mode = 0x3102000;
++      offs = 0;
++
++      /* write test pattern */
++      for (i = 0, ptr = CFG_SYS_SDRAM_BASE; i < 64; i++, ptr += 4)
++              writel((i & 0x1) ? ptr : ~ptr, ptr);
++
++      for (rank = 0; rank < maxrank;) {
++              /* set row mode */
++              clrsetbits_le32(mc_work_mode, 0xf0c, 0x6f0);
++              udelay(1);
++
++              // Scan per address line, until address wraps (i.e. see shadow)
++              for (i = 11; i < 17; i++) {
++                      chk = CFG_SYS_SDRAM_BASE + (1U << (i + 11));
++                      ptr = CFG_SYS_SDRAM_BASE;
++                      for (j = 0; j < 64; j++) {
++                              if (readl(chk) != ((j & 1) ? ptr : ~ptr))
++                                      break;
++                              ptr += 4;
++                              chk += 4;
++                      }
++                      if (j == 64)
++                              break;
++              }
++              if (i > 16)
++                      i = 16;
++              debug("rank %d row = %d\n", rank, i);
++
++              /* Store rows in para 1 */
++              shft = offs + 4;
++              rval = config->dram_para1;
++              rval &= ~(0xff << shft);
++              rval |= i << shft;
++              config->dram_para1 = rval;
++
++              if (rank == 1)          /* Set bank mode for rank0 */
++                      clrsetbits_le32(0x3102000, 0xffc, 0x6a4);
++
++              /* Set bank mode for current rank */
++              clrsetbits_le32(mc_work_mode, 0xffc, 0x6a4);
++              udelay(1);
++
++              // Test if bit A23 is BA2 or mirror XXX A22?
++              chk = CFG_SYS_SDRAM_BASE + (1U << 22);
++              ptr = CFG_SYS_SDRAM_BASE;
++              for (i = 0, j = 0; i < 64; i++) {
++                      if (readl(chk) != ((i & 1) ? ptr : ~ptr)) {
++                              j = 1;
++                              break;
++                      }
++                      ptr += 4;
++                      chk += 4;
++              }
++
++              debug("rank %d bank = %d\n", rank, (j + 1) << 2); /* 4 or 8 */
++
++              /* Store banks in para 1 */
++              shft = 12 + offs;
++              rval = config->dram_para1;
++              rval &= ~(0xf << shft);
++              rval |= j << shft;
++              config->dram_para1 = rval;
++
++              if (rank == 1)          /* Set page mode for rank0 */
++                      clrsetbits_le32(0x3102000, 0xffc, 0xaa0);
++
++              /* Set page mode for current rank */
++              clrsetbits_le32(mc_work_mode, 0xffc, 0xaa0);
++              udelay(1);
++
++              // Scan per address line, until address wraps (i.e. see shadow)
++              for (i = 9; i < 14; i++) {
++                      chk = CFG_SYS_SDRAM_BASE + (1U << i);
++                      ptr = CFG_SYS_SDRAM_BASE;
++                      for (j = 0; j < 64; j++) {
++                              if (readl(chk) != ((j & 1) ? ptr : ~ptr))
++                                      break;
++                              ptr += 4;
++                              chk += 4;
++                      }
++                      if (j == 64)
++                              break;
++              }
++              if (i > 13)
++                      i = 13;
++
++              unsigned int pgsize = (i == 9) ? 0 : (1 << (i - 10));
++              debug("rank %d page size = %d KB\n", rank, pgsize);
++
++              /* Store page size */
++              shft = offs;
++              rval = config->dram_para1;
++              rval &= ~(0xf << shft);
++              rval |= pgsize << shft;
++              config->dram_para1 = rval;
++
++              // Move to next rank
++              rank++;
++              if (rank != maxrank) {
++                      if (rank == 1) {
++                              /* MC_WORK_MODE */
++                              clrsetbits_le32(0x3202000, 0xffc, 0x6f0);
++
++                              /* MC_WORK_MODE2 */
++                              clrsetbits_le32(0x3202004, 0xffc, 0x6f0);
++                      }
++                      /* store rank1 config in upper half of para1 */
++                      offs += 16;
++                      mc_work_mode += 4;      /* move to MC_WORK_MODE2 */
++              }
++      }
++      if (maxrank == 2) {
++              config->dram_para2 &= 0xfffff0ff;
++              /* note: rval is equal to para->dram_para1 here */
++              if ((rval & 0xffff) == (rval >> 16)) {
++                      debug("rank1 config same as rank0\n");
++              } else {
++                      config->dram_para2 |= BIT(8);
++                      debug("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 and width findings.
++ */
++static int auto_scan_dram_rank_width(const dram_para_t *para,
++                                   dram_config_t *config)
++{
++      unsigned int s1 = config->dram_tpr13;
++      unsigned int s2 = config->dram_para1;
++
++      config->dram_para1 = 0x00b000b0;
++      config->dram_para2 = (config->dram_para2 & ~0xf) | BIT(12);
++
++      /* set DQS probe mode */
++      config->dram_tpr13 = (config->dram_tpr13 & ~0x8) | BIT(2) | BIT(0);
++
++      mctl_core_init(para, config);
++
++      if (readl(0x3103010) & BIT(20))
++              return 0;
++
++      if (dqs_gate_detect(config) == 0)
++              return 0;
++
++      config->dram_tpr13 = s1;
++      config->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.
++ */
++static int auto_scan_dram_config(const dram_para_t *para,
++                               dram_config_t *config)
++{
++      if (((config->dram_tpr13 & BIT(14)) == 0) &&
++          (auto_scan_dram_rank_width(para, config) == 0)) {
++              printf("ERROR: auto scan dram rank & width failed\n");
++              return 0;
++      }
++
++      if (((config->dram_tpr13 & BIT(0)) == 0) &&
++          (auto_scan_dram_size(para, config) == 0)) {
++              printf("ERROR: auto scan dram size failed\n");
++              return 0;
++      }
++
++      if ((config->dram_tpr13 & BIT(15)) == 0)
++              config->dram_tpr13 |= BIT(14) | BIT(13) | BIT(1) | BIT(0);
++
++      return 1;
++}
++
++static int init_DRAM(int type, const dram_para_t *para)
++{
++      dram_config_t config = {
++              .dram_para1     = 0x000010d2,
++              .dram_para2     = 0,
++              .dram_tpr13     = CONFIG_DRAM_SUNXI_TPR13,
++      };
++      u32 rc, mem_size_mb;
++
++      debug("DRAM BOOT DRIVE INFO: %s\n", "V0.24");
++      debug("DRAM CLK = %d MHz\n", para->dram_clk);
++      debug("DRAM Type = %d (2:DDR2,3:DDR3)\n", para->dram_type);
++      if ((para->dram_odt_en & 0x1) == 0)
++              debug("DRAMC read ODT off\n");
++      else
++              debug("DRAMC ZQ value: 0x%x\n", para->dram_zq);
++
++      /* Test ZQ status */
++      if (config.dram_tpr13 & BIT(16)) {
++              debug("DRAM only have internal ZQ\n");
++              setbits_le32(0x3000160, BIT(8));
++              writel(0, 0x3000168);
++              udelay(10);
++      } else {
++              clrbits_le32(0x3000160, 0x3);
++              writel(config.dram_tpr13 & BIT(16), 0x7010254);
++              udelay(10);
++              clrsetbits_le32(0x3000160, 0x108, BIT(1));
++              udelay(10);
++              setbits_le32(0x3000160, BIT(0));
++              udelay(20);
++              debug("ZQ value = 0x%x\n", readl(0x300016c));
++      }
++
++      dram_voltage_set(para);
++
++      /* Set SDRAM controller auto config */
++      if ((config.dram_tpr13 & BIT(0)) == 0) {
++              if (auto_scan_dram_config(para, &config) == 0) {
++                      printf("auto_scan_dram_config() FAILED\n");
++                      return 0;
++              }
++      }
++
++      /* report ODT */
++      rc = para->dram_mr1;
++      if ((rc & 0x44) == 0)
++              debug("DRAM ODT off\n");
++      else
++              debug("DRAM ODT value: 0x%x\n", rc);
++
++      /* Init core, final run */
++      if (mctl_core_init(para, &config) == 0) {
++              printf("DRAM initialisation error: 1\n");
++              return 0;
++      }
++
++      /* Get SDRAM size */
++      /* TODO: who ever puts a negative number in the top half? */
++      rc = config.dram_para2;
++      if (rc & BIT(31)) {
++              rc = (rc >> 16) & ~BIT(15);
++      } else {
++              rc = DRAMC_get_dram_size();
++              debug("DRAM: size = %dMB\n", rc);
++              config.dram_para2 = (config.dram_para2 & 0xffffU) | rc << 16;
++      }
++      mem_size_mb = rc;
++
++      /* Purpose ?? */
++      if (config.dram_tpr13 & BIT(30)) {
++              rc = para->dram_tpr8;
++              if (rc == 0)
++                      rc = 0x10000200;
++              writel(rc, 0x31030a0);
++              writel(0x40a, 0x310309c);
++              setbits_le32(0x3103004, BIT(0));
++              debug("Enable Auto SR\n");
++      } else {
++              clrbits_le32(0x31030a0, 0xffff);
++              clrbits_le32(0x3103004, 0x1);
++      }
++
++      /* Purpose ?? */
++      if (config.dram_tpr13 & BIT(9)) {
++              clrsetbits_le32(0x3103100, 0xf000, 0x5000);
++      } else {
++              if (para->dram_type != SUNXI_DRAM_TYPE_LPDDR2)
++                      clrbits_le32(0x3103100, 0xf000);
++      }
++
++      setbits_le32(0x3103140, BIT(31));
++
++      /* CHECK: is that really writing to a different register? */
++      if (config.dram_tpr13 & BIT(8))
++              writel(readl(0x3103140) | 0x300, 0x31030b8);
++
++      if (config.dram_tpr13 & BIT(16))
++              clrbits_le32(0x3103108, BIT(13));
++      else
++              setbits_le32(0x3103108, BIT(13));
++
++      /* Purpose ?? */
++      if (para->dram_type == SUNXI_DRAM_TYPE_LPDDR3)
++              clrsetbits_le32(0x310307c, 0xf0000, 0x1000);
++
++      dram_enable_all_master();
++      if (config.dram_tpr13 & BIT(28)) {
++              if ((readl(0x70005d4) & BIT(16)) ||
++                  dramc_simple_wr_test(mem_size_mb, 4096))
++                      return 0;
++      }
++
++      return mem_size_mb;
++}
++
++      static const dram_para_t para = {
++              .dram_clk       = CONFIG_DRAM_CLK,
++              .dram_type      = CONFIG_SUNXI_DRAM_TYPE,
++              .dram_zq        = CONFIG_DRAM_ZQ,
++              .dram_odt_en    = CONFIG_DRAM_SUNXI_ODT_EN,
++              .dram_mr0       = 0x1c70,
++              .dram_mr1       = 0x42,
++              .dram_mr2       = 0x18,
++              .dram_mr3       = 0,
++              .dram_tpr0      = 0x004a2195,
++              .dram_tpr1      = 0x02423190,
++              .dram_tpr2      = 0x0008b061,
++              .dram_tpr3      = 0xb4787896, // unused
++              .dram_tpr4      = 0,
++              .dram_tpr5      = 0x48484848,
++              .dram_tpr6      = 0x00000048,
++              .dram_tpr7      = 0x1620121e, // unused
++              .dram_tpr8      = 0,
++              .dram_tpr9      = 0, // clock?
++              .dram_tpr10     = 0,
++              .dram_tpr11     = CONFIG_DRAM_SUNXI_TPR11,
++              .dram_tpr12     = CONFIG_DRAM_SUNXI_TPR12,
++      };
++
++unsigned long sunxi_dram_init(void)
++{
++      return init_DRAM(0, &para) * 1024UL * 1024;
++};
++
++#ifdef CONFIG_RAM             /* using the driver model */
++struct sunxi_ram_priv {
++      size_t size;
++};
++
++static int sunxi_ram_probe(struct udevice *dev)
++{
++      struct sunxi_ram_priv *priv = dev_get_priv(dev);
++      unsigned long dram_size;
++
++      debug("%s: %s: probing\n", __func__, dev->name);
++
++      dram_size = sunxi_dram_init();
++      if (!dram_size) {
++              printf("DRAM init failed: %d\n", ret);
++              return -ENODEV;
++      }
++
++      priv->size = dram_size;
++
++      return 0;
++}
++
++static int sunxi_ram_get_info(struct udevice *dev, struct ram_info *info)
++{
++      struct sunxi_ram_priv *priv = dev_get_priv(dev);
++
++      debug("%s: %s: getting info\n", __func__, dev->name);
++
++      info->base = CFG_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                                /* CONFIG_RAM (using driver model) */
+diff --git a/drivers/ram/sunxi/dram_sun20i_d1.h b/drivers/ram/sunxi/dram_sun20i_d1.h
+new file mode 100644
+index 0000000000..91383f6cf1
+--- /dev/null
++++ b/drivers/ram/sunxi/dram_sun20i_d1.h
+@@ -0,0 +1,73 @@
++// SPDX-License-Identifier:   GPL-2.0+
++/*
++ * D1/R528/T113 DRAM controller register and constant defines
++ *
++ * (C) Copyright 2022 Arm Ltd.
++ * Based on H6 and H616 header, which are:
++ * (C) Copyright 2017  Icenowy Zheng <icenowy@aosc.io>
++ * (C) Copyright 2020  Jernej Skrabec <jernej.skrabec@siol.net>
++ *
++ */
++
++#ifndef _SUNXI_DRAM_SUN20I_D1_H
++#define _SUNXI_DRAM_SUN20I_D1_H
++
++enum sunxi_dram_type {
++      SUNXI_DRAM_TYPE_DDR2 = 2,
++      SUNXI_DRAM_TYPE_DDR3 = 3,
++      SUNXI_DRAM_TYPE_LPDDR2 = 6,
++      SUNXI_DRAM_TYPE_LPDDR3 = 7,
++};
++
++/*
++ * This structure contains a mixture of fixed configuration settings,
++ * variables that are used at runtime to communicate settings between
++ * different stages and functions, and unused values.
++ * This is copied from Allwinner's boot0 data structure, which can be
++ * found at offset 0x38 in any boot0 binary. To allow matching up some
++ * board specific settings, this struct is kept compatible, even though
++ * we don't need all members in our code.
++ */
++typedef struct dram_para {
++      /* normal configuration */
++      const u32       dram_clk;
++      const u32       dram_type;
++      const u32       dram_zq;
++      const u32       dram_odt_en;
++
++      /* timing configuration */
++      const u32       dram_mr0;
++      const u32       dram_mr1;
++      const u32       dram_mr2;
++      const u32       dram_mr3;
++      const u32       dram_tpr0;      //DRAMTMG0
++      const u32       dram_tpr1;      //DRAMTMG1
++      const u32       dram_tpr2;      //DRAMTMG2
++      const u32       dram_tpr3;      //DRAMTMG3
++      const u32       dram_tpr4;      //DRAMTMG4
++      const u32       dram_tpr5;      //DRAMTMG5
++      const u32       dram_tpr6;      //DRAMTMG8
++      const u32       dram_tpr7;
++      const u32       dram_tpr8;
++      const u32       dram_tpr9;
++      const u32       dram_tpr10;
++      const u32       dram_tpr11;
++      const u32       dram_tpr12;
++} dram_para_t;
++
++typedef struct dram_config {
++      /* control configuration */
++      u32     dram_para1;
++      u32     dram_para2;
++      /* contains a bitfield of DRAM setup settings */
++      u32     dram_tpr13;
++} dram_config_t;
++
++static inline int ns_to_t(int nanoseconds)
++{
++      const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
++
++      return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
++}
++
++#endif /* _SUNXI_DRAM_SUN20I_D1_H */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4022-sunxi-add-Allwinner-R528-T113-SoC-support.patch b/package/boot/uboot-sunxi/patches/4022-sunxi-add-Allwinner-R528-T113-SoC-support.patch
new file mode 100644 (file)
index 0000000..a07e8d9
--- /dev/null
@@ -0,0 +1,202 @@
+From 6dfc8d5a9ea84c7e7221f6a7d840feaa60479b1c Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:46:02 +0100
+Subject: [PATCH 4022/4052] sunxi: add Allwinner R528/T113 SoC support
+
+This adds the remaining code bits to teach U-Boot about Allwinner's
+newest SoC generation. This was introduced with the RISC-V based
+Allwinner D1 SoC, which actually shares a die with the ARM cores versions
+called R528 (BGA, without DRAM) and T113s (QFP, with embedded DRAM).
+
+This adds the new Kconfig stanza, using the two newly introduced symbols
+for the new SoC generation and pincontroller. It also adds the new symbols
+to the relavent code places, to set all the hardcoded bits directly.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Tested-by: Maksim Kiselev <bigunclemax@gmail.com>
+---
+ arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h |  9 +++++++--
+ arch/arm/mach-sunxi/Kconfig                       | 11 +++++++++++
+ arch/arm/mach-sunxi/board.c                       |  8 ++++++++
+ arch/arm/mach-sunxi/clock_sun50i_h6.c             |  2 ++
+ arch/arm/mach-sunxi/cpu_info.c                    |  2 ++
+ common/spl/Kconfig                                |  1 +
+ drivers/clk/sunxi/Kconfig                         |  1 +
+ drivers/mmc/sunxi_mmc.c                           |  1 +
+ drivers/pinctrl/sunxi/Kconfig                     |  1 +
+ 9 files changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+index 8471e11aa0..a84a57e5b4 100644
+--- a/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
++++ b/arch/arm/include/asm/arch-sunxi/clock_sun50i_h6.h
+@@ -266,7 +266,7 @@ struct sunxi_ccm_reg {
+ #define CCM_CPU_AXI_AXI_MASK          0x3
+ #define CCM_CPU_AXI_DEFAULT_FACTORS   0x301
+-#ifdef CONFIG_MACH_SUN50I_H6
++#ifdef CONFIG_MACH_SUN50I_H6                          /* H6 */
+ #define CCM_PLL6_DEFAULT              0xa0006300
+ /* psi_ahb1_ahb2 bit field */
+@@ -277,7 +277,7 @@ struct sunxi_ccm_reg {
+ /* apb1 bit field */
+ #define CCM_APB1_DEFAULT              0x03000102
+-#elif CONFIG_MACH_SUN50I_H616
++#elif CONFIG_MACH_SUN50I_H616                         /* H616 */
+ #define CCM_PLL6_DEFAULT              0xa8003100
+ /* psi_ahb1_ahb2 bit field */
+@@ -288,6 +288,11 @@ struct sunxi_ccm_reg {
+ /* apb1 bit field */
+ #define CCM_APB1_DEFAULT              0x03000102
++#elif CONFIG_MACH_SUN8I_R528                          /* R528 */
++#define CCM_PLL6_DEFAULT              0xe8216300
++#define CCM_PSI_AHB1_AHB2_DEFAULT     0x03000002
++//#define CCM_AHB3_DEFAULT            0x03000002
++#define CCM_APB1_DEFAULT              0x03000102
+ #endif
+ /* apb2 bit field */
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 60ca1239dd..77b510cdfe 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -316,6 +316,15 @@ config MACH_SUN8I_R40
+       select PHY_SUN4I_USB
+       imply SPL_SYS_I2C_LEGACY
++config MACH_SUN8I_R528
++      bool "sun8i (Allwinner R528)"
++      select CPU_V7A
++      select SUNXI_GEN_NCAT2
++      select SUNXI_NEW_PINCTRL
++      select MMC_SUNXI_HAS_NEW_MODE
++      select SUPPORT_SPL
++      select DRAM_SUN8I_R528
++
+ config MACH_SUN8I_V3S
+       bool "sun8i (Allwinner V3/V3s/S3/S3L)"
+       select CPU_V7A
+@@ -612,6 +621,7 @@ config SYS_CLK_FREQ
+       default 1008000000 if MACH_SUN9I
+       default 888000000 if MACH_SUN50I_H6
+       default 1008000000 if MACH_SUN50I_H616
++      default 1008000000 if MACH_SUN8I_R528
+ config SYS_CONFIG_NAME
+       default "suniv" if MACH_SUNIV
+@@ -620,6 +630,7 @@ config SYS_CONFIG_NAME
+       default "sun6i" if MACH_SUN6I
+       default "sun7i" if MACH_SUN7I
+       default "sun8i" if MACH_SUN8I
++      default "sun8i" if MACH_SUN8I_R528
+       default "sun9i" if MACH_SUN9I
+       default "sun50i" if MACH_SUN50I
+       default "sun50i" if MACH_SUN50I_H6
+diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index 51b8e708b0..8980ffb509 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -147,6 +147,10 @@ static int gpio_init(void)
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0);
+       sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0);
+       sunxi_gpio_set_pull(SUNXI_GPH(13), SUNXI_GPIO_PULL_UP);
++#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN8I_R528)
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(2), 6);
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(3), 6);
++      sunxi_gpio_set_pull(SUNXI_GPE(3), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUNIV)
+       sunxi_gpio_set_cfgpin(SUNXI_GPA(2), SUNIV_GPE_UART0);
+       sunxi_gpio_set_cfgpin(SUNXI_GPA(3), SUNIV_GPE_UART0);
+@@ -163,6 +167,10 @@ static int gpio_init(void)
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2);
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
+       sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
++#elif CONFIG_CONS_INDEX == 4 && defined(CONFIG_MACH_SUN8I_R528)
++      sunxi_gpio_set_cfgpin(SUNXI_GPB(6), 7);
++      sunxi_gpio_set_cfgpin(SUNXI_GPB(7), 7);
++      sunxi_gpio_set_pull(SUNXI_GPB(7), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I)
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART);
+diff --git a/arch/arm/mach-sunxi/clock_sun50i_h6.c b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+index c3a4623d34..bf21a71542 100644
+--- a/arch/arm/mach-sunxi/clock_sun50i_h6.c
++++ b/arch/arm/mach-sunxi/clock_sun50i_h6.c
+@@ -52,7 +52,9 @@ void clock_init_safe(void)
+                       CCM_CPU_AXI_DEFAULT_FACTORS);
+       writel(CCM_PSI_AHB1_AHB2_DEFAULT, &ccm->psi_ahb1_ahb2_cfg);
++#ifdef CCM_AHB3_DEFAULT
+       writel(CCM_AHB3_DEFAULT, &ccm->ahb3_cfg);
++#endif
+       writel(CCM_APB1_DEFAULT, &ccm->apb1_cfg);
+       /*
+diff --git a/arch/arm/mach-sunxi/cpu_info.c b/arch/arm/mach-sunxi/cpu_info.c
+index 7eef178859..7fecc3b88d 100644
+--- a/arch/arm/mach-sunxi/cpu_info.c
++++ b/arch/arm/mach-sunxi/cpu_info.c
+@@ -93,6 +93,8 @@ int print_cpuinfo(void)
+       printf("CPU:   Allwinner R40 (SUN8I %04x)\n", sunxi_get_sram_id());
+ #elif defined CONFIG_MACH_SUN8I_V3S
+       printf("CPU:   Allwinner V3s (SUN8I %04x)\n", sunxi_get_sram_id());
++#elif defined CONFIG_MACH_SUN8I_R528
++      puts("CPU:   Allwinner R528 (SUN8I)\n");
+ #elif defined CONFIG_MACH_SUN9I
+       puts("CPU:   Allwinner A80 (SUN9I)\n");
+ #elif defined CONFIG_MACH_SUN50I
+diff --git a/common/spl/Kconfig b/common/spl/Kconfig
+index 06bcedca7d..196a250ef9 100644
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -357,6 +357,7 @@ config SPL_STACK
+       default 0x91ffb8 if ARCH_MX6 && !MX6_OCRAM_256KB
+       default 0x118000 if MACH_SUN50I_H6
+       default 0x58000 if MACH_SUN50I_H616
++      default 0x40000 if MACH_SUN8I_R528
+       default 0x54000 if MACH_SUN50I || MACH_SUN50I_H5
+       default 0x18000 if MACH_SUN9I
+       default 0x8000 if ARCH_SUNXI
+diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
+index f65e482ba4..8bdc094489 100644
+--- a/drivers/clk/sunxi/Kconfig
++++ b/drivers/clk/sunxi/Kconfig
+@@ -89,6 +89,7 @@ config CLK_SUN8I_H3
+ config CLK_SUN20I_D1
+       bool "Clock driver for Allwinner D1"
++      default MACH_SUN8I_R528
+       help
+         This enables common clock driver support for platforms based
+         on Allwinner D1 SoC.
+diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
+index a8e590561c..0837e8bb30 100644
+--- a/drivers/mmc/sunxi_mmc.c
++++ b/drivers/mmc/sunxi_mmc.c
+@@ -708,6 +708,7 @@ static const struct udevice_id sunxi_mmc_ids[] = {
+       { .compatible = "allwinner,sun50i-h6-emmc" },
+       { .compatible = "allwinner,sun50i-a100-mmc" },
+       { .compatible = "allwinner,sun50i-a100-emmc" },
++      { .compatible = "allwinner,sun20i-d1-mmc" },
+       { /* sentinel */ }
+ };
+diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
+index c8f937d91e..cbd6179598 100644
+--- a/drivers/pinctrl/sunxi/Kconfig
++++ b/drivers/pinctrl/sunxi/Kconfig
+@@ -126,6 +126,7 @@ config PINCTRL_SUN50I_H616_R
+ config PINCTRL_SUN20I_D1
+       bool "Support for the Allwinner D1/R528 PIO"
++      default MACH_SUN8I_R528
+       select PINCTRL_SUNXI
+ endif
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4023-sunxi-refactor-serial-base-addresses-to-avoid-asm-ar.patch b/package/boot/uboot-sunxi/patches/4023-sunxi-refactor-serial-base-addresses-to-avoid-asm-ar.patch
new file mode 100644 (file)
index 0000000..6edcd1d
--- /dev/null
@@ -0,0 +1,265 @@
+From 81723d361cf210f94a49ba4084a5e1267a9bc390 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:46:03 +0100
+Subject: [PATCH 4023/4052] sunxi: refactor serial base addresses to avoid
+ asm/arch/cpu.h
+
+At the moment we have each SoC's memory map defined in its own cpu.h,
+which is included in include/configs/sunxi_common.h. This will be a
+problem with the introduction of Allwinner RISC-V support.
+
+Remove the inclusion of that header file from the common config header,
+instead move the required serial base addresses (for the SPL) into a
+separate header file. Then include the original cpu.h file only where
+we really need it, which is only under arch/arm now.
+
+This disentangles the architecture specific header files from the
+generic code.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/cpu/armv7/sunxi/sram.c               |  1 +
+ arch/arm/cpu/armv8/fel_utils.S                |  1 +
+ arch/arm/include/asm/arch-sunxi/boot0.h       |  2 ++
+ arch/arm/include/asm/arch-sunxi/clock.h       |  1 +
+ arch/arm/include/asm/arch-sunxi/cpu_sun4i.h   | 15 ---------
+ .../include/asm/arch-sunxi/cpu_sun50i_h6.h    |  5 ---
+ arch/arm/include/asm/arch-sunxi/cpu_sun9i.h   |  7 ----
+ .../include/asm/arch-sunxi/cpu_sunxi_ncat2.h  |  4 ---
+ arch/arm/include/asm/arch-sunxi/serial.h      | 32 +++++++++++++++++++
+ arch/arm/mach-sunxi/gtbus_sun9i.c             |  1 +
+ arch/arm/mach-sunxi/timer.c                   |  1 +
+ include/configs/sunxi-common.h                |  2 +-
+ 12 files changed, 40 insertions(+), 32 deletions(-)
+ create mode 100644 arch/arm/include/asm/arch-sunxi/serial.h
+
+diff --git a/arch/arm/cpu/armv7/sunxi/sram.c b/arch/arm/cpu/armv7/sunxi/sram.c
+index 28564c2846..28ff6a1b7c 100644
+--- a/arch/arm/cpu/armv7/sunxi/sram.c
++++ b/arch/arm/cpu/armv7/sunxi/sram.c
+@@ -12,6 +12,7 @@
+ #include <common.h>
+ #include <init.h>
+ #include <asm/io.h>
++#include <asm/arch/cpu.h>
+ void sunxi_sram_init(void)
+ {
+diff --git a/arch/arm/cpu/armv8/fel_utils.S b/arch/arm/cpu/armv8/fel_utils.S
+index 2fe38a1a04..939869b9ff 100644
+--- a/arch/arm/cpu/armv8/fel_utils.S
++++ b/arch/arm/cpu/armv8/fel_utils.S
+@@ -10,6 +10,7 @@
+ #include <config.h>
+ #include <asm/system.h>
+ #include <linux/linkage.h>
++#include <asm/arch/cpu.h>
+ /*
+  * We don't overwrite save_boot_params() here, to save the FEL state upon
+diff --git a/arch/arm/include/asm/arch-sunxi/boot0.h b/arch/arm/include/asm/arch-sunxi/boot0.h
+index 46b7e073b5..8ff7ca9b20 100644
+--- a/arch/arm/include/asm/arch-sunxi/boot0.h
++++ b/arch/arm/include/asm/arch-sunxi/boot0.h
+@@ -3,6 +3,8 @@
+  * Configuration settings for the Allwinner A64 (sun50i) CPU
+  */
++#include <asm/arch/cpu.h>
++
+ #if defined(CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER) && !defined(CONFIG_SPL_BUILD)
+ /* reserve space for BOOT0 header information */
+       b       reset
+diff --git a/arch/arm/include/asm/arch-sunxi/clock.h b/arch/arm/include/asm/arch-sunxi/clock.h
+index 3d34261b0e..fcc8966cb0 100644
+--- a/arch/arm/include/asm/arch-sunxi/clock.h
++++ b/arch/arm/include/asm/arch-sunxi/clock.h
+@@ -9,6 +9,7 @@
+ #define _SUNXI_CLOCK_H
+ #include <linux/types.h>
++#include <asm/arch/cpu.h>
+ #define CLK_GATE_OPEN                 0x1
+ #define CLK_GATE_CLOSE                        0x0
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+index d6fe51f24b..3daee2f574 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun4i.h
+@@ -128,20 +128,6 @@ defined(CONFIG_MACH_SUN50I)
+ #define SUNXI_CPUCFG_BASE             0x01c25c00
+ #endif
+-#ifdef CONFIG_MACH_SUNIV
+-#define SUNXI_UART0_BASE              0x01c25000
+-#define SUNXI_UART1_BASE              0x01c25400
+-#define SUNXI_UART2_BASE              0x01c25800
+-#else
+-#define SUNXI_UART0_BASE              0x01c28000
+-#define SUNXI_UART1_BASE              0x01c28400
+-#define SUNXI_UART2_BASE              0x01c28800
+-#endif
+-#define SUNXI_UART3_BASE              0x01c28c00
+-#define SUNXI_UART4_BASE              0x01c29000
+-#define SUNXI_UART5_BASE              0x01c29400
+-#define SUNXI_UART6_BASE              0x01c29800
+-#define SUNXI_UART7_BASE              0x01c29c00
+ #define SUNXI_PS2_0_BASE              0x01c2a000
+ #define SUNXI_PS2_1_BASE              0x01c2a400
+@@ -208,7 +194,6 @@ defined(CONFIG_MACH_SUN50I)
+ #endif
+ #define SUNXI_R_TWI_BASE              0x01f02400
+-#define SUNXI_R_UART_BASE             0x01f02800
+ #define SUN6I_P2WI_BASE                       0x01f03400
+ #define SUNXI_RSB_BASE                        0x01f03400
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+index 9b6bf84360..15ee092d35 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+@@ -42,10 +42,6 @@
+ #define SUNXI_DRAM_PHY0_BASE          0x04800000
+ #endif
+-#define SUNXI_UART0_BASE              0x05000000
+-#define SUNXI_UART1_BASE              0x05000400
+-#define SUNXI_UART2_BASE              0x05000800
+-#define SUNXI_UART3_BASE              0x05000C00
+ #define SUNXI_TWI0_BASE                       0x05002000
+ #define SUNXI_TWI1_BASE                       0x05002400
+ #define SUNXI_TWI2_BASE                       0x05002800
+@@ -67,7 +63,6 @@
+ #define SUNXI_R_CPUCFG_BASE           0x07000400
+ #define SUNXI_PRCM_BASE                       0x07010000
+ #define SUNXI_R_WDOG_BASE             0x07020400
+-#define SUNXI_R_UART_BASE             0x07080000
+ #define SUNXI_R_TWI_BASE              0x07081400
+ #ifndef __ASSEMBLY__
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h b/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
+index 20025be231..2bf2675d5c 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sun9i.h
+@@ -86,12 +86,6 @@
+ #define SUNXI_LRADC_BASE              (REGS_APB0_BASE + 0x1800)
+ /* APB1 Module */
+-#define SUNXI_UART0_BASE              (REGS_APB1_BASE + 0x0000)
+-#define SUNXI_UART1_BASE              (REGS_APB1_BASE + 0x0400)
+-#define SUNXI_UART2_BASE              (REGS_APB1_BASE + 0x0800)
+-#define SUNXI_UART3_BASE              (REGS_APB1_BASE + 0x0C00)
+-#define SUNXI_UART4_BASE              (REGS_APB1_BASE + 0x1000)
+-#define SUNXI_UART5_BASE              (REGS_APB1_BASE + 0x1400)
+ #define SUNXI_TWI0_BASE                       (REGS_APB1_BASE + 0x2800)
+ #define SUNXI_TWI1_BASE                       (REGS_APB1_BASE + 0x2C00)
+ #define SUNXI_TWI2_BASE                       (REGS_APB1_BASE + 0x3000)
+@@ -100,7 +94,6 @@
+ /* RCPUS Module */
+ #define SUNXI_PRCM_BASE                       (REGS_RCPUS_BASE + 0x1400)
+-#define SUNXI_R_UART_BASE             (REGS_RCPUS_BASE + 0x2800)
+ #define SUNXI_RSB_BASE                        (REGS_RCPUS_BASE + 0x3400)
+ /* Misc. */
+diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+index b13be2c4e8..961a3b37c9 100644
+--- a/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
++++ b/arch/arm/include/asm/arch-sunxi/cpu_sunxi_ncat2.h
+@@ -10,10 +10,6 @@
+ #define SUNXI_CCM_BASE                        0x02001000
+ #define SUNXI_TIMER_BASE              0x02050000
+-#define SUNXI_UART0_BASE              0x02500000
+-#define SUNXI_UART1_BASE              0x02500400
+-#define SUNXI_UART2_BASE              0x02500800
+-#define SUNXI_UART3_BASE              0x02500C00
+ #define SUNXI_TWI0_BASE                       0x02502000
+ #define SUNXI_TWI1_BASE                       0x02502400
+ #define SUNXI_TWI2_BASE                       0x02502800
+diff --git a/arch/arm/include/asm/arch-sunxi/serial.h b/arch/arm/include/asm/arch-sunxi/serial.h
+new file mode 100644
+index 0000000000..9386287b65
+--- /dev/null
++++ b/arch/arm/include/asm/arch-sunxi/serial.h
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ *  hardcoded UART base addresses for early SPL use
++ *
++ *  Copyright (c) 2022  Arm Ltd.
++ */
++
++#ifndef SUNXI_SERIAL_MEMMAP_H
++#define SUNXI_SERIAL_MEMMAP_H
++
++#if defined(CONFIG_MACH_SUN9I)
++#define SUNXI_UART0_BASE              0x07000000
++#define SUNXI_R_UART_BASE             0x08002800
++#elif defined(CONFIG_SUN50I_GEN_H6)
++#define SUNXI_UART0_BASE              0x05000000
++#define SUNXI_R_UART_BASE             0x07080000
++#elif defined(CONFIG_MACH_SUNIV)
++#define SUNXI_UART0_BASE              0x01c25000
++#define SUNXI_R_UART_BASE             0
++#elif defined(CONFIG_SUNXI_GEN_NCAT2)
++#define SUNXI_UART0_BASE              0x02500000
++#define SUNXI_R_UART_BASE             0               // 0x07080000 (?>
++#else
++#define SUNXI_UART0_BASE              0x01c28000
++#define SUNXI_R_UART_BASE             0x01f02800
++#endif
++
++#define SUNXI_UART1_BASE              (SUNXI_UART0_BASE + 0x400)
++#define SUNXI_UART2_BASE              (SUNXI_UART0_BASE + 0x800)
++#define SUNXI_UART3_BASE              (SUNXI_UART0_BASE + 0xc00)
++
++#endif /* SUNXI_SERIAL_MEMMAP_H */
+diff --git a/arch/arm/mach-sunxi/gtbus_sun9i.c b/arch/arm/mach-sunxi/gtbus_sun9i.c
+index cf011c4cfa..5624621b50 100644
+--- a/arch/arm/mach-sunxi/gtbus_sun9i.c
++++ b/arch/arm/mach-sunxi/gtbus_sun9i.c
+@@ -8,6 +8,7 @@
+ #include <common.h>
+ #include <asm/io.h>
++#include <asm/arch/cpu.h>
+ #include <asm/arch/gtbus_sun9i.h>
+ #include <asm/arch/sys_proto.h>
+diff --git a/arch/arm/mach-sunxi/timer.c b/arch/arm/mach-sunxi/timer.c
+index fc9d419a25..9a6f6c06d8 100644
+--- a/arch/arm/mach-sunxi/timer.c
++++ b/arch/arm/mach-sunxi/timer.c
+@@ -10,6 +10,7 @@
+ #include <time.h>
+ #include <asm/global_data.h>
+ #include <asm/io.h>
++#include <asm/arch/cpu.h>
+ #include <asm/arch/timer.h>
+ #include <linux/delay.h>
+diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
+index d2d70f0fc2..b8ca77d031 100644
+--- 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 */
+@@ -24,6 +23,7 @@
+ #define CFG_SYS_NS16550_CLK           24000000
+ #endif
+ #if !CONFIG_IS_ENABLED(DM_SERIAL)
++#include <asm/arch/serial.h>
+ # define CFG_SYS_NS16550_COM1         SUNXI_UART0_BASE
+ # define CFG_SYS_NS16550_COM2         SUNXI_UART1_BASE
+ # define CFG_SYS_NS16550_COM3         SUNXI_UART2_BASE
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4024-riscv-dts-allwinner-Add-the-D1-D1s-SoC-devicetree.patch b/package/boot/uboot-sunxi/patches/4024-riscv-dts-allwinner-Add-the-D1-D1s-SoC-devicetree.patch
new file mode 100644 (file)
index 0000000..5dc93e3
--- /dev/null
@@ -0,0 +1,1156 @@
+From 8cd3f54a64857a8f60033817859f87ded8e22918 Mon Sep 17 00:00:00 2001
+From: Samuel Holland <samuel@sholland.org>
+Date: Fri, 21 Jul 2023 14:46:04 +0100
+Subject: [PATCH 4024/4052] riscv: dts: allwinner: Add the D1/D1s SoC
+ devicetree
+
+D1 (aka D1-H), D1s (aka F133), R528, and T113 are a family of SoCs based
+on a single die, or at a pair of dies derived from the same design.
+
+D1 and D1s contain a single T-HEAD Xuantie C906 CPU, whereas R528 and
+T113 contain a pair of Cortex-A7's. D1 and R528 are the full version of
+the chip with a BGA package, whereas D1s and T113 are low-pin-count QFP
+variants.
+
+Because the original design supported both ARM and RISC-V CPUs, some
+peripherals are duplicated. In addition, all variants except D1s contain
+a HiFi 4 DSP with its own set of peripherals.
+
+The devicetrees are organized to minimize duplication:
+ - Common perhiperals are described in sunxi-d1s-t113.dtsi
+ - DSP-related peripherals are described in sunxi-d1-t113.dtsi
+ - RISC-V specific hardware is described in sun20i-d1s.dtsi
+ - Functionality unique to the D1 variant is described in sun20i-d1.dtsi
+
+The SOC_PERIPHERAL_IRQ macro handles the different #interrupt-cells
+values between the ARM (GIC) and RISC-V (PLIC) versions of the SoC.
+
+Signed-off-by: Samuel Holland <samuel@sholland.org>
+---
+ arch/riscv/dts/sun20i-common-regulators.dtsi |  28 +
+ arch/riscv/dts/sun20i-d1.dtsi                |  66 ++
+ arch/riscv/dts/sun20i-d1s.dtsi               |  76 ++
+ arch/riscv/dts/sunxi-d1-t113.dtsi            |  15 +
+ arch/riscv/dts/sunxi-d1s-t113.dtsi           | 846 +++++++++++++++++++
+ include/dt-bindings/clock/sun20i-d1-r-ccu.h  |  19 +
+ include/dt-bindings/reset/sun20i-d1-r-ccu.h  |  16 +
+ 7 files changed, 1066 insertions(+)
+ create mode 100644 arch/riscv/dts/sun20i-common-regulators.dtsi
+ create mode 100644 arch/riscv/dts/sun20i-d1.dtsi
+ create mode 100644 arch/riscv/dts/sun20i-d1s.dtsi
+ create mode 100644 arch/riscv/dts/sunxi-d1-t113.dtsi
+ create mode 100644 arch/riscv/dts/sunxi-d1s-t113.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
+
+diff --git a/arch/riscv/dts/sun20i-common-regulators.dtsi b/arch/riscv/dts/sun20i-common-regulators.dtsi
+new file mode 100644
+index 0000000000..9b03fca244
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-common-regulators.dtsi
+@@ -0,0 +1,28 @@
++// 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 = <&reg_vcc>;
++      };
++};
++
++&pio {
++      vcc-pb-supply = <&reg_vcc_3v3>;
++      vcc-pc-supply = <&reg_vcc_3v3>;
++      vcc-pd-supply = <&reg_vcc_3v3>;
++      vcc-pe-supply = <&reg_vcc_3v3>;
++      vcc-pf-supply = <&reg_vcc_3v3>;
++      vcc-pg-supply = <&reg_vcc_3v3>;
++};
+diff --git a/arch/riscv/dts/sun20i-d1.dtsi b/arch/riscv/dts/sun20i-d1.dtsi
+new file mode 100644
+index 0000000000..97e7cbb325
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1.dtsi
+@@ -0,0 +1,66 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++#include "sun20i-d1s.dtsi"
++#include "sunxi-d1-t113.dtsi"
++
++/ {
++      soc {
++              lradc: keys@2009800 {
++                      compatible = "allwinner,sun20i-d1-lradc",
++                                   "allwinner,sun50i-r329-lradc";
++                      reg = <0x2009800 0x400>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(61) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_LRADC>;
++                      resets = <&ccu RST_BUS_LRADC>;
++                      status = "disabled";
++              };
++
++              i2s0: i2s@2032000 {
++                      compatible = "allwinner,sun20i-d1-i2s",
++                                   "allwinner,sun50i-r329-i2s";
++                      reg = <0x2032000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(26) 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>;
++              };
++      };
++};
++
++&pio {
++      /omit-if-no-ref/
++      dmic_pb11_d0_pin: dmic-pb11-d0-pin {
++              pins = "PB11";
++              function = "dmic";
++      };
++
++      /omit-if-no-ref/
++      dmic_pe17_clk_pin: dmic-pe17-clk-pin {
++              pins = "PE17";
++              function = "dmic";
++      };
++
++      /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/
++      uart0_pb8_pins: uart0-pb8-pins {
++              pins = "PB8", "PB9";
++              function = "uart0";
++      };
++};
+diff --git a/arch/riscv/dts/sun20i-d1s.dtsi b/arch/riscv/dts/sun20i-d1s.dtsi
+new file mode 100644
+index 0000000000..8275630af9
+--- /dev/null
++++ b/arch/riscv/dts/sun20i-d1s.dtsi
+@@ -0,0 +1,76 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++#define SOC_PERIPHERAL_IRQ(nr)        (nr + 16)
++
++#include "sunxi-d1s-t113.dtsi"
++
++/ {
++      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>;
++                      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";
++                      operating-points-v2 = <&opp_table_cpu>;
++                      riscv,isa = "rv64imafdc";
++                      #cooling-cells = <2>;
++
++                      cpu0_intc: interrupt-controller {
++                              compatible = "riscv,cpu-intc";
++                              interrupt-controller;
++                              #address-cells = <0>;
++                              #interrupt-cells = <1>;
++                      };
++              };
++      };
++
++      opp_table_cpu: opp-table-cpu {
++              compatible = "operating-points-v2";
++
++              opp-408000000 {
++                      opp-hz = /bits/ 64 <408000000>;
++                      opp-microvolt = <900000 900000 1100000>;
++              };
++
++              opp-1080000000 {
++                      opp-hz = /bits/ 64 <1008000000>;
++                      opp-microvolt = <900000 900000 1100000>;
++              };
++      };
++
++      soc {
++              interrupt-parent = <&plic>;
++
++              riscv_wdt: watchdog@6011000 {
++                      compatible = "allwinner,sun20i-d1-wdt";
++                      reg = <0x6011000 0x20>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(131) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&dcxo>, <&rtc CLK_OSC32K>;
++                      clock-names = "hosc", "losc";
++              };
++
++              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 = <175>;
++                      #address-cells = <0>;
++                      #interrupt-cells = <2>;
++              };
++      };
++};
+diff --git a/arch/riscv/dts/sunxi-d1-t113.dtsi b/arch/riscv/dts/sunxi-d1-t113.dtsi
+new file mode 100644
+index 0000000000..b7156123df
+--- /dev/null
++++ b/arch/riscv/dts/sunxi-d1-t113.dtsi
+@@ -0,0 +1,15 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2021-2022 Samuel Holland <samuel@sholland.org>
++
++/ {
++      soc {
++              dsp_wdt: watchdog@1700400 {
++                      compatible = "allwinner,sun20i-d1-wdt";
++                      reg = <0x1700400 0x20>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&dcxo>, <&rtc CLK_OSC32K>;
++                      clock-names = "hosc", "losc";
++                      status = "reserved";
++              };
++      };
++};
+diff --git a/arch/riscv/dts/sunxi-d1s-t113.dtsi b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+new file mode 100644
+index 0000000000..922e8e0e2c
+--- /dev/null
++++ b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+@@ -0,0 +1,846 @@
++// 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>
++
++/ {
++      #address-cells = <1>;
++      #size-cells = <1>;
++
++      dcxo: dcxo-clk {
++              compatible = "fixed-clock";
++              clock-output-names = "dcxo";
++              #clock-cells = <0>;
++      };
++
++      de: display-engine {
++              compatible = "allwinner,sun20i-d1-display-engine";
++              allwinner,pipelines = <&mixer0>, <&mixer1>;
++              status = "disabled";
++      };
++
++      soc {
++              compatible = "simple-bus";
++              ranges;
++              dma-noncoherent;
++              #address-cells = <1>;
++              #size-cells = <1>;
++
++              pio: pinctrl@2000000 {
++                      compatible = "allwinner,sun20i-d1-pinctrl";
++                      reg = <0x2000000 0x800>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(69) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(71) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(73) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(75) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(77) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(79) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_APB0>,
++                               <&dcxo>,
++                               <&rtc CLK_OSC32K>;
++                      clock-names = "apb", "hosc", "losc";
++                      gpio-controller;
++                      interrupt-controller;
++                      #gpio-cells = <3>;
++                      #interrupt-cells = <3>;
++
++                      /omit-if-no-ref/
++                      clk_pg11_pin: clk-pg11-pin {
++                              pins = "PG11";
++                              function = "clk";
++                      };
++
++                      /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/
++                      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/
++                      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";
++                      };
++
++                      /omit-if-no-ref/
++                      uart3_pb_pins: uart3-pb-pins {
++                              pins = "PB6", "PB7";
++                              function = "uart3";
++                      };
++              };
++
++              ccu: clock-controller@2001000 {
++                      compatible = "allwinner,sun20i-d1-ccu";
++                      reg = <0x2001000 0x1000>;
++                      clocks = <&dcxo>,
++                               <&rtc CLK_OSC32K>,
++                               <&rtc CLK_IOSC>;
++                      clock-names = "hosc", "losc", "iosc";
++                      #clock-cells = <1>;
++                      #reset-cells = <1>;
++              };
++
++              dmic: dmic@2031000 {
++                      compatible = "allwinner,sun20i-d1-dmic",
++                                   "allwinner,sun50i-h6-dmic";
++                      reg = <0x2031000 0x400>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(24) 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>;
++              };
++
++              i2s1: i2s@2033000 {
++                      compatible = "allwinner,sun20i-d1-i2s",
++                                   "allwinner,sun50i-r329-i2s";
++                      reg = <0x2033000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(27) 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 = <SOC_PERIPHERAL_IRQ(28) 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 = <SOC_PERIPHERAL_IRQ(59) IRQ_TYPE_LEVEL_HIGH>,
++                                   <SOC_PERIPHERAL_IRQ(60) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&dcxo>;
++              };
++
++              wdt: watchdog@20500a0 {
++                      compatible = "allwinner,sun20i-d1-wdt-reset",
++                                   "allwinner,sun20i-d1-wdt";
++                      reg = <0x20500a0 0x20>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(63) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&dcxo>, <&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 = <SOC_PERIPHERAL_IRQ(2) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART0>;
++                      resets = <&ccu RST_BUS_UART0>;
++                      dmas = <&dma 14>, <&dma 14>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              uart1: serial@2500400 {
++                      compatible = "snps,dw-apb-uart";
++                      reg = <0x2500400 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(3) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART1>;
++                      resets = <&ccu RST_BUS_UART1>;
++                      dmas = <&dma 15>, <&dma 15>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              uart2: serial@2500800 {
++                      compatible = "snps,dw-apb-uart";
++                      reg = <0x2500800 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(4) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART2>;
++                      resets = <&ccu RST_BUS_UART2>;
++                      dmas = <&dma 16>, <&dma 16>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              uart3: serial@2500c00 {
++                      compatible = "snps,dw-apb-uart";
++                      reg = <0x2500c00 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(5) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART3>;
++                      resets = <&ccu RST_BUS_UART3>;
++                      dmas = <&dma 17>, <&dma 17>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              uart4: serial@2501000 {
++                      compatible = "snps,dw-apb-uart";
++                      reg = <0x2501000 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(6) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART4>;
++                      resets = <&ccu RST_BUS_UART4>;
++                      dmas = <&dma 18>, <&dma 18>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              uart5: serial@2501400 {
++                      compatible = "snps,dw-apb-uart";
++                      reg = <0x2501400 0x400>;
++                      reg-io-width = <4>;
++                      reg-shift = <2>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(7) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_UART5>;
++                      resets = <&ccu RST_BUS_UART5>;
++                      dmas = <&dma 19>, <&dma 19>;
++                      dma-names = "tx", "rx";
++                      status = "disabled";
++              };
++
++              i2c0: i2c@2502000 {
++                      compatible = "allwinner,sun20i-d1-i2c",
++                                   "allwinner,sun8i-v536-i2c",
++                                   "allwinner,sun6i-a31-i2c";
++                      reg = <0x2502000 0x400>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(9) 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 = <SOC_PERIPHERAL_IRQ(10) 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 = <SOC_PERIPHERAL_IRQ(11) 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 = <SOC_PERIPHERAL_IRQ(12) 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>;
++              };
++
++              dma: dma-controller@3002000 {
++                      compatible = "allwinner,sun20i-d1-dma";
++                      reg = <0x3002000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(50) 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>;
++              };
++
++              crypto: crypto@3040000 {
++                      compatible = "allwinner,sun20i-d1-crypto";
++                      reg = <0x3040000 0x800>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(52) 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>,
++                            <0x3103000 0x1000>;
++                      reg-names = "mbus", "dram";
++                      interrupts = <SOC_PERIPHERAL_IRQ(43) 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 = <SOC_PERIPHERAL_IRQ(40) 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 = <SOC_PERIPHERAL_IRQ(41) 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 = <SOC_PERIPHERAL_IRQ(42) 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 = <SOC_PERIPHERAL_IRQ(29) 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 = <&dcxo>,
++                               <&dcxo>;
++                      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 = <SOC_PERIPHERAL_IRQ(30) 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 = <SOC_PERIPHERAL_IRQ(31) 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 = <SOC_PERIPHERAL_IRQ(33) 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 = <SOC_PERIPHERAL_IRQ(34) 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 = <SOC_PERIPHERAL_IRQ(46) 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>;
++                                      };
++                              };
++                      };
++              };
++
++              dsi: dsi@5450000 {
++                      compatible = "allwinner,sun20i-d1-mipi-dsi",
++                                   "allwinner,sun50i-a100-mipi-dsi";
++                      reg = <0x5450000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(92) 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";
++
++                      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 = <SOC_PERIPHERAL_IRQ(92) 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>;
++                      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>;
++
++                                      tcon_top_mixer0_in_mixer0: endpoint {
++                                              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 = <SOC_PERIPHERAL_IRQ(90) 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>;
++                                      #address-cells = <1>;
++                                      #size-cells = <0>;
++
++                                      tcon_lcd0_out_dsi: endpoint@1 {
++                                              reg = <1>;
++                                              remote-endpoint = <&dsi_in_tcon_lcd0>;
++                                      };
++                              };
++                      };
++              };
++
++              tcon_tv0: lcd-controller@5470000 {
++                      compatible = "allwinner,sun20i-d1-tcon-tv";
++                      reg = <0x5470000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(91) 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>;
++                                      };
++                              };
++                      };
++              };
++
++              ppu: power-controller@7001000 {
++                      compatible = "allwinner,sun20i-d1-ppu";
++                      reg = <0x7001000 0x1000>;
++                      clocks = <&r_ccu CLK_BUS_R_PPU>;
++                      resets = <&r_ccu RST_BUS_R_PPU>;
++                      #power-domain-cells = <1>;
++              };
++
++              r_ccu: clock-controller@7010000 {
++                      compatible = "allwinner,sun20i-d1-r-ccu";
++                      reg = <0x7010000 0x400>;
++                      clocks = <&dcxo>,
++                               <&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 = <SOC_PERIPHERAL_IRQ(144) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&r_ccu CLK_BUS_R_RTC>,
++                               <&dcxo>,
++                               <&r_ccu CLK_R_AHB>;
++                      clock-names = "bus", "hosc", "ahb";
++                      #clock-cells = <1>;
++              };
++      };
++};
+diff --git a/include/dt-bindings/clock/sun20i-d1-r-ccu.h b/include/dt-bindings/clock/sun20i-d1-r-ccu.h
+new file mode 100644
+index 0000000000..4c2697fd32
+--- /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_ */
+diff --git a/include/dt-bindings/reset/sun20i-d1-r-ccu.h b/include/dt-bindings/reset/sun20i-d1-r-ccu.h
+new file mode 100644
+index 0000000000..d93d6423d2
+--- /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_ */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4025-ARM-dts-sunxi-add-Allwinner-T113-s-SoC-.dtsi.patch b/package/boot/uboot-sunxi/patches/4025-ARM-dts-sunxi-add-Allwinner-T113-s-SoC-.dtsi.patch
new file mode 100644 (file)
index 0000000..944b19f
--- /dev/null
@@ -0,0 +1,113 @@
+From 032126b42512e91b2c8e918fd33a3ed7e96ac8df Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:46:05 +0100
+Subject: [PATCH 4025/4052] ARM: dts: sunxi: add Allwinner T113-s SoC .dtsi
+
+The Allwinner T113-s SoC is apparently using the same (or at least a very
+similar) die as the D1/D1s, but replaces the single RISC-V core with
+two Arm Cortex-A7 cores.
+Since the D1 core .dtsi already describes all common peripherals, we
+just need a DT describing the ARM specific peripherals: the CPU cores,
+the Generic Timer, the GIC and the PMU.
+We include the core .dtsi directly from the riscv DT directory.
+
+The ARM core version of the DT specifies the CPUX watchdog as
+"reserved", which means it won't be recognised by U-Boot. Override this
+in our generic sunxi-u-boot.dtsi, to let U-Boot pick up this watchdog,
+so that the generic reset driver will work.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/dts/sun8i-t113s.dtsi  | 59 ++++++++++++++++++++++++++++++++++
+ arch/arm/dts/sunxi-u-boot.dtsi |  7 ++++
+ 2 files changed, 66 insertions(+)
+ create mode 100644 arch/arm/dts/sun8i-t113s.dtsi
+
+diff --git a/arch/arm/dts/sun8i-t113s.dtsi b/arch/arm/dts/sun8i-t113s.dtsi
+new file mode 100644
+index 0000000000..ce00883130
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s.dtsi
+@@ -0,0 +1,59 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#define SOC_PERIPHERAL_IRQ(nr) GIC_SPI nr
++
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <../../riscv/dts/sunxi-d1s-t113.dtsi>
++#include <../../riscv/dts/sunxi-d1-t113.dtsi>
++
++/ {
++      interrupt-parent = <&gic>;
++
++      cpus {
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              cpu0: cpu@0 {
++                      compatible = "arm,cortex-a7";
++                      device_type = "cpu";
++                      reg = <0>;
++                      clocks = <&ccu CLK_CPUX>;
++                      clock-names = "cpu";
++              };
++
++              cpu1: cpu@1 {
++                      compatible = "arm,cortex-a7";
++                      device_type = "cpu";
++                      reg = <1>;
++                      clocks = <&ccu CLK_CPUX>;
++                      clock-names = "cpu";
++              };
++      };
++
++      gic: interrupt-controller@1c81000 {
++              compatible = "arm,gic-400";
++              reg = <0x03021000 0x1000>,
++                    <0x03022000 0x2000>,
++                    <0x03024000 0x2000>,
++                    <0x03026000 0x2000>;
++              interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++              interrupt-controller;
++              #interrupt-cells = <3>;
++      };
++
++      timer {
++              compatible = "arm,armv7-timer";
++              interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++                           <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++                           <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
++                           <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
++      };
++
++      pmu {
++              compatible = "arm,cortex-a7-pmu";
++              interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
++                           <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
++              interrupt-affinity = <&cpu0>, <&cpu1>;
++      };
++};
+diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi
+index e959eb2a40..27de5b8eac 100644
+--- a/arch/arm/dts/sunxi-u-boot.dtsi
++++ b/arch/arm/dts/sunxi-u-boot.dtsi
+@@ -23,6 +23,13 @@
+       };
+ };
++/* Let U-Boot be the firmware layer that controls the watchdog. */
++#ifdef CONFIG_MACH_SUN8I_R528
++&wdt {
++      status = "okay";
++};
++#endif
++
+ &binman {
+       u-boot-sunxi-with-spl {
+               filename = "u-boot-sunxi-with-spl.bin";
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4026-sunxi-add-MangoPi-MQ-R-board-support.patch b/package/boot/uboot-sunxi/patches/4026-sunxi-add-MangoPi-MQ-R-board-support.patch
new file mode 100644 (file)
index 0000000..4051d78
--- /dev/null
@@ -0,0 +1,229 @@
+From dd2f024850f1da845073eaa90867b7250837f3e1 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Fri, 21 Jul 2023 14:46:06 +0100
+Subject: [PATCH 4026/4052] sunxi: add MangoPi MQ-R board support
+
+This copies the T113s specific DTs from the Linux kernel tree
+(v6.4-rc1), and adds a defconfig to get the board booted.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/dts/Makefile                         |   2 +
+ .../arm/dts/sun8i-t113s-mangopi-mq-r-t113.dts |  35 +++++
+ arch/arm/dts/sunxi-d1s-t113-mangopi-mq-r.dtsi | 126 ++++++++++++++++++
+ configs/mangopi_mq_r_defconfig                |  15 +++
+ 4 files changed, 178 insertions(+)
+ create mode 100644 arch/arm/dts/sun8i-t113s-mangopi-mq-r-t113.dts
+ create mode 100644 arch/arm/dts/sunxi-d1s-t113-mangopi-mq-r.dtsi
+ create mode 100644 configs/mangopi_mq_r_defconfig
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index c160e884bf..41ee9c4c65 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -710,6 +710,8 @@ dtb-$(CONFIG_MACH_SUN8I_V3S) += \
+       sun8i-s3-pinecube.dtb \
+       sun8i-v3-sl631-imx179.dtb \
+       sun8i-v3s-licheepi-zero.dtb
++dtb-$(CONFIG_MACH_SUN8I_R528) += \
++      sun8i-t113s-mangopi-mq-r-t113.dtb
+ dtb-$(CONFIG_MACH_SUN50I_H5) += \
+       sun50i-h5-bananapi-m2-plus.dtb \
+       sun50i-h5-emlid-neutis-n5-devboard.dtb \
+diff --git a/arch/arm/dts/sun8i-t113s-mangopi-mq-r-t113.dts b/arch/arm/dts/sun8i-t113s-mangopi-mq-r-t113.dts
+new file mode 100644
+index 0000000000..94e24b5926
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s-mangopi-mq-r-t113.dts
+@@ -0,0 +1,35 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/dts-v1/;
++
++#include "sun8i-t113s.dtsi"
++#include "sunxi-d1s-t113-mangopi-mq-r.dtsi"
++
++/ {
++      model = "MangoPi MQ-R-T113";
++      compatible = "widora,mangopi-mq-r-t113", "allwinner,sun8i-t113s";
++
++      aliases {
++              ethernet0 = &rtl8189ftv;
++      };
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&cpu1 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&mmc1 {
++      rtl8189ftv: wifi@1 {
++              reg = <1>;
++              interrupt-parent = <&pio>;
++              interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 = WL_WAKE_AP */
++              interrupt-names = "host-wake";
++      };
++};
+diff --git a/arch/arm/dts/sunxi-d1s-t113-mangopi-mq-r.dtsi b/arch/arm/dts/sunxi-d1s-t113-mangopi-mq-r.dtsi
+new file mode 100644
+index 0000000000..e9bc749488
+--- /dev/null
++++ b/arch/arm/dts/sunxi-d1s-t113-mangopi-mq-r.dtsi
+@@ -0,0 +1,126 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++/*
++ * Common peripherals and configurations for MangoPi MQ-R boards.
++ */
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/leds/common.h>
++
++/ {
++      aliases {
++              serial3 = &uart3;
++      };
++
++      chosen {
++              stdout-path = "serial3:115200n8";
++      };
++
++      leds {
++              compatible = "gpio-leds";
++
++              led-0 {
++                      color = <LED_COLOR_ID_BLUE>;
++                      function = LED_FUNCTION_STATUS;
++                      gpios = <&pio 3 22 GPIO_ACTIVE_LOW>; /* PD22 */
++              };
++      };
++
++      /* board wide 5V supply directly from the USB-C socket */
++      reg_vcc5v: regulator-5v {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-5v";
++              regulator-min-microvolt = <5000000>;
++              regulator-max-microvolt = <5000000>;
++              regulator-always-on;
++      };
++
++      /* SY8008 DC/DC regulator on the board */
++      reg_3v3: regulator-3v3 {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-3v3";
++              regulator-min-microvolt = <3300000>;
++              regulator-max-microvolt = <3300000>;
++              vin-supply = <&reg_vcc5v>;
++      };
++
++      /* SY8008 DC/DC regulator on the board, also supplying VDD-SYS */
++      reg_vcc_core: regulator-core {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-core";
++              regulator-min-microvolt = <880000>;
++              regulator-max-microvolt = <880000>;
++              vin-supply = <&reg_vcc5v>;
++      };
++
++      /* XC6206 LDO on the board */
++      reg_avdd2v8: regulator-avdd {
++              compatible = "regulator-fixed";
++              regulator-name = "avdd2v8";
++              regulator-min-microvolt = <2800000>;
++              regulator-max-microvolt = <2800000>;
++              vin-supply = <&reg_3v3>;
++      };
++
++      wifi_pwrseq: wifi-pwrseq {
++              compatible = "mmc-pwrseq-simple";
++              reset-gpios = <&pio 6 12 GPIO_ACTIVE_LOW>; /* PG12 */
++      };
++};
++
++&dcxo {
++      clock-frequency = <24000000>;
++};
++
++&ehci1 {
++      status = "okay";
++};
++
++&mmc0 {
++      pinctrl-0 = <&mmc0_pins>;
++      pinctrl-names = "default";
++      vmmc-supply = <&reg_3v3>;
++      cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
++      disable-wp;
++      bus-width = <4>;
++      status = "okay";
++};
++
++&mmc1 {
++      pinctrl-0 = <&mmc1_pins>;
++      pinctrl-names = "default";
++      vmmc-supply = <&reg_3v3>;
++      non-removable;
++      bus-width = <4>;
++      mmc-pwrseq = <&wifi_pwrseq>;
++      status = "okay";
++};
++
++&ohci1 {
++      status = "okay";
++};
++
++&pio {
++      vcc-pb-supply = <&reg_3v3>;
++      vcc-pd-supply = <&reg_3v3>;
++      vcc-pe-supply = <&reg_avdd2v8>;
++      vcc-pf-supply = <&reg_3v3>;
++      vcc-pg-supply = <&reg_3v3>;
++};
++
++&uart3 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart3_pb_pins>;
++      status = "okay";
++};
++
++/* The USB-C socket has its CC pins pulled to GND, so is hardwired as a UFP. */
++&usb_otg {
++      dr_mode = "peripheral";
++      status = "okay";
++};
++
++&usbphy {
++      usb1_vbus-supply = <&reg_vcc5v>;
++      status = "okay";
++};
+diff --git a/configs/mangopi_mq_r_defconfig b/configs/mangopi_mq_r_defconfig
+new file mode 100644
+index 0000000000..66ae639326
+--- /dev/null
++++ b/configs/mangopi_mq_r_defconfig
+@@ -0,0 +1,15 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-mangopi-mq-r-t113"
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_R528=y
++CONFIG_DRAM_CLK=792
++CONFIG_DRAM_ZQ=8092667
++CONFIG_SUNXI_MINIMUM_DRAM_MB=128
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_DRAM_SUNXI_ODT_EN=0
++CONFIG_DRAM_SUNXI_TPR0=0x004a2195
++CONFIG_DRAM_SUNXI_TPR11=0x340000
++CONFIG_DRAM_SUNXI_TPR12=0x46
++CONFIG_DRAM_SUNXI_TPR13=0x34000100
++CONFIG_CONS_INDEX=4
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4027-net-add-ICPlus-PHY-driver.patch b/package/boot/uboot-sunxi/patches/4027-net-add-ICPlus-PHY-driver.patch
new file mode 100644 (file)
index 0000000..9b519db
--- /dev/null
@@ -0,0 +1,174 @@
+From 243168af9a9a30516a5826b383bd86312cc246bf Mon Sep 17 00:00:00 2001
+From: Yegor Yefremov <yegorslists@googlemail.com>
+Date: Wed, 28 Nov 2012 11:15:18 +0100
+Subject: [PATCH 4027/4052] net: add ICPlus PHY driver
+
+The driver code was taken from Linux kernel source:
+drivers/net/phy/icplus.c
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
+---
+ drivers/net/phy/Kconfig  |  3 ++
+ drivers/net/phy/Makefile |  1 +
+ drivers/net/phy/icplus.c | 94 ++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/phy.c    |  3 ++
+ include/phy.h            |  1 +
+ 5 files changed, 102 insertions(+)
+ create mode 100644 drivers/net/phy/icplus.c
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 5eaff053a0..93980398f1 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -165,6 +165,9 @@ config PHY_DAVICOM
+ config PHY_ET1011C
+       bool "LSI TruePHY ET1011C support"
++config PHY_ICPLUS
++      bool "IC+ IP101 Ethernet PHY support"
++
+ config PHY_LXT
+       bool "LXT971 Ethernet PHY support"
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index d38e99e717..5b6b78631d 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_PHY_CORTINA) += cortina.o
+ obj-$(CONFIG_PHY_CORTINA_ACCESS) += ca_phy.o
+ obj-$(CONFIG_PHY_DAVICOM) += davicom.o
+ obj-$(CONFIG_PHY_ET1011C) += et1011c.o
++obj-$(CONFIG_PHY_ICPLUS) += icplus.o
+ obj-$(CONFIG_PHY_LXT) += lxt.o
+ obj-$(CONFIG_PHY_MARVELL) += marvell.o
+ obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o
+diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
+new file mode 100644
+index 0000000000..dd5c59259d
+--- /dev/null
++++ b/drivers/net/phy/icplus.c
+@@ -0,0 +1,94 @@
++/*
++ * ICPlus PHY drivers
++ *
++ * 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
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ *
++ */
++#include <phy.h>
++
++/* IP101A/G - IP1001 */
++#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */
++#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */
++#define IP1001_PHASE_SEL_MASK           3       /* IP1001 RX/TXPHASE_SEL */
++#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */
++#define IP101A_G_APS_ON                 2       /* IP101A/G APS Mode bit */
++#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */
++#define IP101A_G_IRQ_PIN_USED           (1<<15) /* INTR pin used */
++#define IP101A_G_IRQ_DEFAULT            IP101A_G_IRQ_PIN_USED
++
++static int ip1001_config(struct phy_device *phydev)
++{
++      int c;
++
++      /* Enable Auto Power Saving mode */
++      c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2);
++      if (c < 0)
++              return c;
++      c |= IP1001_APS_ON;
++      c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c);
++      if (c < 0)
++              return c;
++
++      /* INTR pin used: speed/link/duplex will cause an interrupt */
++      c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS,
++                    IP101A_G_IRQ_DEFAULT);
++      if (c < 0)
++              return c;
++
++      if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
++              /*
++               * Additional delay (2ns) used to adjust RX clock phase
++               * at RGMII interface
++               */
++              c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS);
++              if (c < 0)
++                      return c;
++
++              c |= IP1001_PHASE_SEL_MASK;
++              c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS,
++                            c);
++              if (c < 0)
++                      return c;
++      }
++
++      return 0;
++}
++
++static int ip1001_startup(struct phy_device *phydev)
++{
++      genphy_update_link(phydev);
++      genphy_parse_link(phydev);
++
++      return 0;
++}
++static struct phy_driver IP1001_driver = {
++      .name = "ICPlus IP1001",
++      .uid = 0x02430d90,
++      .mask = 0x0ffffff0,
++      .features = PHY_GBIT_FEATURES,
++      .config = &ip1001_config,
++      .startup = &ip1001_startup,
++      .shutdown = &genphy_shutdown,
++};
++
++int phy_icplus_init(void)
++{
++      phy_register(&IP1001_driver);
++
++      return 0;
++}
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index 80230b907c..9e22db3fc8 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -514,6 +514,9 @@ int phy_init(void)
+ #ifdef CONFIG_PHY_ET1011C
+       phy_et1011c_init();
+ #endif
++#ifdef CONFIG_PHY_ICPLUS
++      phy_icplus_init();
++#endif
+ #ifdef CONFIG_PHY_LXT
+       phy_lxt_init();
+ #endif
+diff --git a/include/phy.h b/include/phy.h
+index 87aa86c2e7..749285f15e 100644
+--- a/include/phy.h
++++ b/include/phy.h
+@@ -325,6 +325,7 @@ int phy_cortina_init(void);
+ int phy_cortina_access_init(void);
+ int phy_davicom_init(void);
+ int phy_et1011c_init(void);
++int phy_icplus_init(void);
+ int phy_lxt_init(void);
+ int phy_marvell_init(void);
+ int phy_micrel_ksz8xxx_init(void);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4028-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethe.patch b/package/boot/uboot-sunxi/patches/4028-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethe.patch
new file mode 100644 (file)
index 0000000..c2e6f27
--- /dev/null
@@ -0,0 +1,493 @@
+From 424386ebda2d0fb0e00bb192572a7050bf5b084b Mon Sep 17 00:00:00 2001
+From: Yanhong Wang <yanhong.wang@starfivetech.com>
+Date: Thu, 25 May 2023 17:36:27 +0800
+Subject: [PATCH 4028/4052] net: phy: Add driver for Motorcomm yt8531 gigabit
+ ethernet phy
+
+Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have
+verified the driver on StarFive VisionFive2 board.
+
+Signed-off-by: Yanhong Wang <yanhong.wang@starfivetech.com>
+Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
+---
+ drivers/net/phy/Kconfig     |   6 +
+ drivers/net/phy/Makefile    |   1 +
+ drivers/net/phy/motorcomm.c | 437 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 444 insertions(+)
+ create mode 100644 drivers/net/phy/motorcomm.c
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 93980398f1..0a99682c27 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -215,6 +215,12 @@ config PHY_MICREL_KSZ8XXX
+ endif # PHY_MICREL
++config PHY_MOTORCOMM
++      tristate "Motorcomm PHYs"
++      help
++        Enables support for Motorcomm network PHYs.
++        Currently supports the YT8531 Gigabit Ethernet PHYs.
++
+ config PHY_MSCC
+       bool "Microsemi Corp Ethernet PHYs support"
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 5b6b78631d..9637a138f8 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -24,6 +24,7 @@ obj-$(CONFIG_PHY_MARVELL) += marvell.o
+ obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o
+ obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o
+ obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o
++obj-$(CONFIG_PHY_MOTORCOMM) += motorcomm.o
+ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
+ obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o
+ obj-$(CONFIG_PHY_NXP_TJA11XX) += nxp-tja11xx.o
+diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
+new file mode 100644
+index 0000000000..e822fd76f2
+--- /dev/null
++++ b/drivers/net/phy/motorcomm.c
+@@ -0,0 +1,437 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Motorcomm 8531 PHY driver.
++ *
++ * Copyright (C) 2023 StarFive Technology Co., Ltd.
++ */
++
++#include <config.h>
++#include <common.h>
++#include <malloc.h>
++#include <phy.h>
++#include <linux/bitfield.h>
++
++#define PHY_ID_YT8531                         0x4f51e91b
++#define PHY_ID_MASK                           GENMASK(31, 0)
++
++/* Extended Register's Address Offset Register */
++#define YTPHY_PAGE_SELECT                     0x1E
++
++/* Extended Register's Data Register */
++#define YTPHY_PAGE_DATA                       0x1F
++
++#define YTPHY_SYNCE_CFG_REG                   0xA012
++
++#define YTPHY_DTS_OUTPUT_CLK_DIS              0
++#define YTPHY_DTS_OUTPUT_CLK_25M              25000000
++#define YTPHY_DTS_OUTPUT_CLK_125M             125000000
++
++#define YT8531_SCR_SYNCE_ENABLE               BIT(6)
++/* 1b0 output 25m clock   *default*
++ * 1b1 output 125m clock
++ */
++#define YT8531_SCR_CLK_FRE_SEL_125M           BIT(4)
++#define YT8531_SCR_CLK_SRC_MASK               GENMASK(3, 1)
++#define YT8531_SCR_CLK_SRC_PLL_125M           0
++#define YT8531_SCR_CLK_SRC_UTP_RX             1
++#define YT8531_SCR_CLK_SRC_SDS_RX             2
++#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3
++#define YT8531_SCR_CLK_SRC_REF_25M            4
++#define YT8531_SCR_CLK_SRC_SSC_25M            5
++
++/* 1b0 use original tx_clk_rgmii  *default*
++ * 1b1 use inverted tx_clk_rgmii.
++ */
++#define YT8531_RC1R_TX_CLK_SEL_INVERTED       BIT(14)
++#define YT8531_RC1R_RX_DELAY_MASK             GENMASK(13, 10)
++#define YT8531_RC1R_FE_TX_DELAY_MASK          GENMASK(7, 4)
++#define YT8531_RC1R_GE_TX_DELAY_MASK          GENMASK(3, 0)
++#define YT8531_RC1R_RGMII_0_000_NS            0
++#define YT8531_RC1R_RGMII_0_150_NS            1
++#define YT8531_RC1R_RGMII_0_300_NS            2
++#define YT8531_RC1R_RGMII_0_450_NS            3
++#define YT8531_RC1R_RGMII_0_600_NS            4
++#define YT8531_RC1R_RGMII_0_750_NS            5
++#define YT8531_RC1R_RGMII_0_900_NS            6
++#define YT8531_RC1R_RGMII_1_050_NS            7
++#define YT8531_RC1R_RGMII_1_200_NS            8
++#define YT8531_RC1R_RGMII_1_350_NS            9
++#define YT8531_RC1R_RGMII_1_500_NS            10
++#define YT8531_RC1R_RGMII_1_650_NS            11
++#define YT8531_RC1R_RGMII_1_800_NS            12
++#define YT8531_RC1R_RGMII_1_950_NS            13
++#define YT8531_RC1R_RGMII_2_100_NS            14
++#define YT8531_RC1R_RGMII_2_250_NS            15
++
++/* Phy gmii clock gating Register */
++#define YT8531_CLOCK_GATING_REG               0xC
++#define YT8531_CGR_RX_CLK_EN                  BIT(12)
++
++/* Specific Status Register */
++#define YTPHY_SPECIFIC_STATUS_REG             0x11
++#define YTPHY_DUPLEX_MASK                     BIT(13)
++#define YTPHY_DUPLEX_SHIFT                    13
++#define YTPHY_SPEED_MODE_MASK                 GENMASK(15, 14)
++#define YTPHY_SPEED_MODE_SHIFT                        14
++
++#define YT8531_EXTREG_SLEEP_CONTROL1_REG      0x27
++#define YT8531_ESC1R_SLEEP_SW                 BIT(15)
++#define YT8531_ESC1R_PLLON_SLP                        BIT(14)
++
++#define YT8531_RGMII_CONFIG1_REG              0xA003
++
++#define YT8531_CHIP_CONFIG_REG                        0xA001
++#define YT8531_CCR_SW_RST                     BIT(15)
++/* 1b0 disable 1.9ns rxc clock delay  *default*
++ * 1b1 enable 1.9ns rxc clock delay
++ */
++#define YT8531_CCR_RXC_DLY_EN                 BIT(8)
++#define YT8531_CCR_RXC_DLY_1_900_NS           1900
++
++/* bits in struct ytphy_plat_priv->flag */
++#define TX_CLK_ADJ_ENABLED                    BIT(0)
++#define AUTO_SLEEP_DISABLED                   BIT(1)
++#define KEEP_PLL_ENABLED                      BIT(2)
++#define TX_CLK_10_INVERTED                    BIT(3)
++#define TX_CLK_100_INVERTED                   BIT(4)
++#define TX_CLK_1000_INVERTED                  BIT(5)
++
++struct ytphy_plat_priv {
++      u32 rx_delay_ps;
++      u32 tx_delay_ps;
++      u32 clk_out_frequency;
++      u32 flag;
++};
++
++/**
++ * struct ytphy_cfg_reg_map - map a config value to a register value
++ * @cfg: value in device configuration
++ * @reg: value in the register
++ */
++struct ytphy_cfg_reg_map {
++      u32 cfg;
++      u32 reg;
++};
++
++static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = {
++      /* for tx delay / rx delay with YT8531_CCR_RXC_DLY_EN is not set. */
++      { 0,    YT8531_RC1R_RGMII_0_000_NS },
++      { 150,  YT8531_RC1R_RGMII_0_150_NS },
++      { 300,  YT8531_RC1R_RGMII_0_300_NS },
++      { 450,  YT8531_RC1R_RGMII_0_450_NS },
++      { 600,  YT8531_RC1R_RGMII_0_600_NS },
++      { 750,  YT8531_RC1R_RGMII_0_750_NS },
++      { 900,  YT8531_RC1R_RGMII_0_900_NS },
++      { 1050, YT8531_RC1R_RGMII_1_050_NS },
++      { 1200, YT8531_RC1R_RGMII_1_200_NS },
++      { 1350, YT8531_RC1R_RGMII_1_350_NS },
++      { 1500, YT8531_RC1R_RGMII_1_500_NS },
++      { 1650, YT8531_RC1R_RGMII_1_650_NS },
++      { 1800, YT8531_RC1R_RGMII_1_800_NS },
++      { 1950, YT8531_RC1R_RGMII_1_950_NS },   /* default tx/rx delay */
++      { 2100, YT8531_RC1R_RGMII_2_100_NS },
++      { 2250, YT8531_RC1R_RGMII_2_250_NS },
++
++      /* only for rx delay with YT8531_CCR_RXC_DLY_EN is set. */
++      { 0    + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_000_NS },
++      { 150  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_150_NS },
++      { 300  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_300_NS },
++      { 450  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_450_NS },
++      { 600  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_600_NS },
++      { 750  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_750_NS },
++      { 900  + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_0_900_NS },
++      { 1050 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_050_NS },
++      { 1200 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_200_NS },
++      { 1350 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_350_NS },
++      { 1500 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_500_NS },
++      { 1650 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_650_NS },
++      { 1800 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_800_NS },
++      { 1950 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_1_950_NS },
++      { 2100 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_2_100_NS },
++      { 2250 + YT8531_CCR_RXC_DLY_1_900_NS,   YT8531_RC1R_RGMII_2_250_NS }
++};
++
++static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
++                                   u32 val,
++                                   u16 *rxc_dly_en)
++{
++      int tb_size = ARRAY_SIZE(ytphy_rgmii_delays);
++      int tb_size_half = tb_size / 2;
++      int i;
++
++      /* when rxc_dly_en is NULL, it is get the delay for tx, only half of
++       * tb_size is valid.
++       */
++      if (!rxc_dly_en)
++              tb_size = tb_size_half;
++
++      for (i = 0; i < tb_size; i++) {
++              if (ytphy_rgmii_delays[i].cfg == val) {
++                      if (rxc_dly_en && i < tb_size_half)
++                              *rxc_dly_en = 0;
++                      return ytphy_rgmii_delays[i].reg;
++              }
++      }
++
++      pr_warn("Unsupported value %d, using default (%u)\n",
++              val, YT8531_RC1R_RGMII_1_950_NS);
++
++      /* when rxc_dly_en is not NULL, it is get the delay for rx.
++       * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps,
++       * so YT8531_CCR_RXC_DLY_EN should not be set.
++       */
++      if (rxc_dly_en)
++              *rxc_dly_en = 0;
++
++      return YT8531_RC1R_RGMII_1_950_NS;
++}
++
++static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask,
++                          u16 set)
++{
++      int ret;
++
++      ret = phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_SELECT, regnum);
++      if (ret < 0)
++              return ret;
++
++      return phy_modify(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, mask, set);
++}
++
++static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
++{
++      struct ytphy_plat_priv  *priv = phydev->priv;
++      u16 rxc_dly_en = YT8531_CCR_RXC_DLY_EN;
++      u32 rx_reg, tx_reg;
++      u16 mask, val = 0;
++      int ret;
++
++      rx_reg = ytphy_get_delay_reg_value(phydev, priv->rx_delay_ps,
++                                         &rxc_dly_en);
++      tx_reg = ytphy_get_delay_reg_value(phydev, priv->tx_delay_ps,
++                                         NULL);
++
++      switch (phydev->interface) {
++      case PHY_INTERFACE_MODE_RGMII:
++              rxc_dly_en = 0;
++              break;
++      case PHY_INTERFACE_MODE_RGMII_RXID:
++              val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg);
++              break;
++      case PHY_INTERFACE_MODE_RGMII_TXID:
++              rxc_dly_en = 0;
++              val |= FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg);
++              break;
++      case PHY_INTERFACE_MODE_RGMII_ID:
++              val |= FIELD_PREP(YT8531_RC1R_RX_DELAY_MASK, rx_reg) |
++                     FIELD_PREP(YT8531_RC1R_GE_TX_DELAY_MASK, tx_reg);
++              break;
++      default: /* do not support other modes */
++              return -EOPNOTSUPP;
++      }
++
++      ret = ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG,
++                             YT8531_CCR_RXC_DLY_EN, rxc_dly_en);
++      if (ret < 0)
++              return ret;
++
++      /* Generally, it is not necessary to adjust YT8531_RC1R_FE_TX_DELAY */
++      mask = YT8531_RC1R_RX_DELAY_MASK | YT8531_RC1R_GE_TX_DELAY_MASK;
++      return ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG, mask, val);
++}
++
++static int yt8531_parse_status(struct phy_device *phydev)
++{
++      int val;
++      int speed, speed_mode;
++
++      val = phy_read(phydev, MDIO_DEVAD_NONE, YTPHY_SPECIFIC_STATUS_REG);
++      if (val < 0)
++              return val;
++
++      speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT;
++      switch (speed_mode) {
++      case 2:
++              speed = SPEED_1000;
++              break;
++      case 1:
++              speed = SPEED_100;
++              break;
++      default:
++              speed = SPEED_10;
++              break;
++      }
++
++      phydev->speed = speed;
++      phydev->duplex = (val & YTPHY_DUPLEX_MASK) >> YTPHY_DUPLEX_SHIFT;
++
++      return 0;
++}
++
++static int yt8531_startup(struct phy_device *phydev)
++{
++      struct ytphy_plat_priv  *priv = phydev->priv;
++      u16 val = 0;
++      int ret;
++
++      ret = genphy_update_link(phydev);
++      if (ret)
++              return ret;
++
++      ret = yt8531_parse_status(phydev);
++      if (ret)
++              return ret;
++
++      if (phydev->speed < 0)
++              return -EINVAL;
++
++      if (!(priv->flag & TX_CLK_ADJ_ENABLED))
++              return 0;
++
++      switch (phydev->speed) {
++      case SPEED_1000:
++              if (priv->flag & TX_CLK_1000_INVERTED)
++                      val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
++              break;
++      case SPEED_100:
++              if (priv->flag & TX_CLK_100_INVERTED)
++                      val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
++              break;
++      case SPEED_10:
++              if (priv->flag & TX_CLK_10_INVERTED)
++                      val = YT8531_RC1R_TX_CLK_SEL_INVERTED;
++              break;
++      default:
++              printf("UNKNOWN SPEED\n");
++              return -EINVAL;
++      }
++
++      ret = ytphy_modify_ext(phydev, YT8531_RGMII_CONFIG1_REG,
++                             YT8531_RC1R_TX_CLK_SEL_INVERTED, val);
++      if (ret < 0)
++              pr_warn("Modify TX_CLK_SEL err:%d\n", ret);
++
++      return 0;
++}
++
++static void ytphy_dt_parse(struct phy_device *phydev)
++{
++      struct ytphy_plat_priv  *priv = phydev->priv;
++
++      priv->clk_out_frequency = ofnode_read_u32_default(phydev->node,
++                                                        "motorcomm,clk-out-frequency-hz",
++                                                        YTPHY_DTS_OUTPUT_CLK_DIS);
++      priv->rx_delay_ps = ofnode_read_u32_default(phydev->node,
++                                                  "rx-internal-delay-ps",
++                                                  YT8531_RC1R_RGMII_1_950_NS);
++      priv->tx_delay_ps = ofnode_read_u32_default(phydev->node,
++                                                  "tx-internal-delay-ps",
++                                                  YT8531_RC1R_RGMII_1_950_NS);
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,auto-sleep-disabled"))
++              priv->flag |= AUTO_SLEEP_DISABLED;
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,keep-pll-enabled"))
++              priv->flag |= KEEP_PLL_ENABLED;
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-adj-enabled"))
++              priv->flag |= TX_CLK_ADJ_ENABLED;
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-10-inverted"))
++              priv->flag |= TX_CLK_10_INVERTED;
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-100-inverted"))
++              priv->flag |= TX_CLK_100_INVERTED;
++
++      if (ofnode_read_bool(phydev->node, "motorcomm,tx-clk-1000-inverted"))
++              priv->flag |= TX_CLK_1000_INVERTED;
++}
++
++static int yt8531_config(struct phy_device *phydev)
++{
++      struct ytphy_plat_priv  *priv = phydev->priv;
++      u16 mask, val;
++      int ret;
++
++      ret = genphy_config_aneg(phydev);
++      if (ret < 0)
++              return ret;
++
++      ytphy_dt_parse(phydev);
++      switch (priv->clk_out_frequency) {
++      case YTPHY_DTS_OUTPUT_CLK_DIS:
++              mask = YT8531_SCR_SYNCE_ENABLE;
++              val = 0;
++              break;
++      case YTPHY_DTS_OUTPUT_CLK_25M:
++              mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
++                         YT8531_SCR_CLK_FRE_SEL_125M;
++              val = YT8531_SCR_SYNCE_ENABLE |
++                        FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
++                                   YT8531_SCR_CLK_SRC_REF_25M);
++              break;
++      case YTPHY_DTS_OUTPUT_CLK_125M:
++              mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
++                         YT8531_SCR_CLK_FRE_SEL_125M;
++              val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M |
++                        FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
++                                   YT8531_SCR_CLK_SRC_PLL_125M);
++              break;
++      default:
++              pr_warn("Freq err:%u\n", priv->clk_out_frequency);
++              return -EINVAL;
++      }
++
++      ret = ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask,
++                             val);
++      if (ret < 0)
++              return ret;
++
++      ret = ytphy_rgmii_clk_delay_config(phydev);
++      if (ret < 0)
++              return ret;
++
++      if (priv->flag & AUTO_SLEEP_DISABLED) {
++              /* disable auto sleep */
++              ret = ytphy_modify_ext(phydev,
++                                     YT8531_EXTREG_SLEEP_CONTROL1_REG,
++                                     YT8531_ESC1R_SLEEP_SW, 0);
++              if (ret < 0)
++                      return ret;
++      }
++
++      if (priv->flag & KEEP_PLL_ENABLED) {
++              /* enable RXC clock when no wire plug */
++              ret = ytphy_modify_ext(phydev,
++                                     YT8531_CLOCK_GATING_REG,
++                                     YT8531_CGR_RX_CLK_EN, 0);
++              if (ret < 0)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static int yt8531_probe(struct phy_device *phydev)
++{
++      struct ytphy_plat_priv  *priv;
++
++      priv = calloc(1, sizeof(struct ytphy_plat_priv));
++      if (!priv)
++              return -ENOMEM;
++
++      phydev->priv = priv;
++
++      return 0;
++}
++
++U_BOOT_PHY_DRIVER(motorcomm8531) = {
++      .name          = "YT8531 Gigabit Ethernet",
++      .uid           = PHY_ID_YT8531,
++      .mask          = PHY_ID_MASK,
++      .features      = PHY_GBIT_FEATURES,
++      .probe         = &yt8531_probe,
++      .config        = &yt8531_config,
++      .startup       = &yt8531_startup,
++      .shutdown      = &genphy_shutdown,
++};
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4029-net-phy-backport-and-update-driver-for-Motorcomm-yt8.patch b/package/boot/uboot-sunxi/patches/4029-net-phy-backport-and-update-driver-for-Motorcomm-yt8.patch
new file mode 100644 (file)
index 0000000..b445a1f
--- /dev/null
@@ -0,0 +1,68 @@
+From d7448cb6d2a3dfe8c76f4807fba748c1c83a387c Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Mon, 5 Jun 2023 18:15:15 +0200
+Subject: [PATCH 4029/4052] net: phy: backport and update driver for Motorcomm
+ yt8531 phy
+
+Don't use U_BOOT_PHY_DRIVER yet.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ drivers/net/phy/motorcomm.c | 9 ++++++++-
+ drivers/net/phy/phy.c       | 3 +++
+ include/phy.h               | 1 +
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
+index e822fd76f2..eb2dd65c4a 100644
+--- a/drivers/net/phy/motorcomm.c
++++ b/drivers/net/phy/motorcomm.c
+@@ -425,7 +425,7 @@ static int yt8531_probe(struct phy_device *phydev)
+       return 0;
+ }
+-U_BOOT_PHY_DRIVER(motorcomm8531) = {
++static struct phy_driver YT8531_driver =  {
+       .name          = "YT8531 Gigabit Ethernet",
+       .uid           = PHY_ID_YT8531,
+       .mask          = PHY_ID_MASK,
+@@ -435,3 +435,10 @@ U_BOOT_PHY_DRIVER(motorcomm8531) = {
+       .startup       = &yt8531_startup,
+       .shutdown      = &genphy_shutdown,
+ };
++
++int phy_motorcomm_init(void)
++{
++        phy_register(&YT8531_driver);
++
++        return 0;
++}
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index 9e22db3fc8..3613c3dd17 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -532,6 +532,9 @@ int phy_init(void)
+ #ifdef CONFIG_PHY_MESON_GXL
+       phy_meson_gxl_init();
+ #endif
++#ifdef CONFIG_PHY_MOTORCOMM
++      phy_motorcomm_init();
++#endif
+ #ifdef CONFIG_PHY_NATSEMI
+       phy_natsemi_init();
+ #endif
+diff --git a/include/phy.h b/include/phy.h
+index 749285f15e..05208d7f3d 100644
+--- a/include/phy.h
++++ b/include/phy.h
+@@ -331,6 +331,7 @@ int phy_marvell_init(void);
+ int phy_micrel_ksz8xxx_init(void);
+ int phy_micrel_ksz90x1_init(void);
+ int phy_meson_gxl_init(void);
++int phy_motorcomm_init(void);
+ int phy_natsemi_init(void);
+ int phy_nxp_c45_tja11xx_init(void);
+ int phy_nxp_tja11xx_init(void);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4030-sunxi-SPL-SPI-Add-SPI-boot-support-for-the-Allwinner.patch b/package/boot/uboot-sunxi/patches/4030-sunxi-SPL-SPI-Add-SPI-boot-support-for-the-Allwinner.patch
new file mode 100644 (file)
index 0000000..a480219
--- /dev/null
@@ -0,0 +1,206 @@
+From e711e33258167beee01ae3768eff708eb72bcf6b Mon Sep 17 00:00:00 2001
+From: Maxim Kiselev <bigunclemax@gmail.com>
+Date: Fri, 19 May 2023 16:40:07 +0300
+Subject: [PATCH 4030/4052] sunxi: SPL SPI: Add SPI boot support for the
+ Allwinner R528/T113 SoCs
+
+R528/T113 SoCs uses the same SPI IP as the H6, also have the same clocks
+and reset bits layout, but the CCU base is different. Another difference
+is that the new SoCs do not have a clock divider inside. Instead of this
+we should configure sample mode depending on input clock rate.
+
+The pin assignment is also different: the H6 uses PC0, the R528/T113 PC4
+instead. This makes for a change in spi0_pinmux_setup() routine.
+
+This patch extends the H6/H616 #ifdef guards to also cover the R528/T113,
+using the shared CONFIG_SUNXI_GEN_NCAT2 and CONFIG_MACH_SUN8I_R528
+symbols. Also use CONFIG_SUNXI_GEN_NCAT2 symbol for the Kconfig
+dependency.
+
+Signed-off-by: Maxim Kiselev <bigunclemax@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/mach-sunxi/Kconfig         |  2 +-
+ arch/arm/mach-sunxi/spl_spi_sunxi.c | 78 +++++++++++++++++++++--------
+ 2 files changed, 58 insertions(+), 22 deletions(-)
+
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 77b510cdfe..81d2a173d0 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -997,7 +997,7 @@ config SPL_STACK_R_ADDR
+ 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
++      depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || SUN50I_GEN_H6 || MACH_SUNIV || SUNXI_GEN_NCAT2
+       help
+         Enable support for SPI Flash. This option allows SPL to read from
+         sunxi SPI Flash. It uses the same method as the boot ROM, so does
+diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
+index c2410dd7bb..3cfbf56d59 100644
+--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
++++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
+@@ -73,18 +73,27 @@
+ #define SUN6I_CTL_ENABLE            BIT(0)
+ #define SUN6I_CTL_MASTER            BIT(1)
+ #define SUN6I_CTL_SRST              BIT(31)
++#define SUN6I_TCR_SDM               BIT(13)
+ #define SUN6I_TCR_XCH               BIT(31)
+ /*****************************************************************************/
+-#define CCM_AHB_GATING0             (0x01C20000 + 0x60)
+-#define CCM_H6_SPI_BGR_REG          (0x03001000 + 0x96c)
+-#ifdef CONFIG_SUN50I_GEN_H6
+-#define CCM_SPI0_CLK                (0x03001000 + 0x940)
++#if defined(CONFIG_SUN50I_GEN_H6)
++#define CCM_BASE                    0x03001000
++#elif defined(CONFIG_SUNXI_GEN_NCAT2)
++#define CCM_BASE                    0x02001000
+ #else
+-#define CCM_SPI0_CLK                (0x01C20000 + 0xA0)
++#define CCM_BASE                    0x01C20000
+ #endif
+-#define SUN6I_BUS_SOFT_RST_REG0     (0x01C20000 + 0x2C0)
++
++#define CCM_AHB_GATING0             (CCM_BASE + 0x60)
++#define CCM_H6_SPI_BGR_REG          (CCM_BASE + 0x96c)
++#if defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
++#define CCM_SPI0_CLK                (CCM_BASE + 0x940)
++#else
++#define CCM_SPI0_CLK                (CCM_BASE + 0xA0)
++#endif
++#define SUN6I_BUS_SOFT_RST_REG0     (CCM_BASE + 0x2C0)
+ #define AHB_RESET_SPI0_SHIFT        20
+ #define AHB_GATE_OFFSET_SPI0        20
+@@ -102,17 +111,22 @@
+  */
+ static void spi0_pinmux_setup(unsigned int pin_function)
+ {
+-      /* All chips use PC0 and PC2. */
+-      sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
++      /* All chips use PC2. And all chips use PC0, except R528/T113 */
++      if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528))
++              sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
++
+       sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function);
+-      /* All chips except H6 and H616 use PC1. */
+-      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++      /* All chips except H6/H616/R528/T113 use PC1. */
++      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) &&
++          !IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function);
+-      if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
++      if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) ||
++          IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function);
+-      if (IS_ENABLED(CONFIG_MACH_SUN50I_H616))
++      if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) ||
++          IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(4), pin_function);
+       /* Older generations use PC23 for CS, newer ones use PC3. */
+@@ -126,7 +140,8 @@ static void spi0_pinmux_setup(unsigned int pin_function)
+ static bool is_sun6i_gen_spi(void)
+ {
+       return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ||
+-             IS_ENABLED(CONFIG_SUN50I_GEN_H6);
++             IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++             IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2);
+ }
+ static uintptr_t spi0_base_address(void)
+@@ -137,6 +152,9 @@ static uintptr_t spi0_base_address(void)
+       if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
+               return 0x05010000;
++      if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
++              return 0x04025000;
++
+       if (!is_sun6i_gen_spi() ||
+           IS_ENABLED(CONFIG_MACH_SUNIV))
+               return 0x01C05000;
+@@ -152,23 +170,30 @@ static void spi0_enable_clock(void)
+       uintptr_t base = spi0_base_address();
+       /* Deassert SPI0 reset on SUN6I */
+-      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++          IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
+               setbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+       else if (is_sun6i_gen_spi())
+               setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+                            (1 << AHB_RESET_SPI0_SHIFT));
+       /* Open the SPI0 gate */
+-      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) &&
++          !IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
+               setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+       if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
+               /* Divide by 32, clock source is AHB clock 200MHz */
+               writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL);
+       } else {
+-              /* Divide by 4 */
+-              writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
+-                                        SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
++              /* New SoCs do not have a clock divider inside */
++              if (!IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) {
++                      /* Divide by 4 */
++                      writel(SPI0_CLK_DIV_BY_4,
++                             base + (is_sun6i_gen_spi() ? SUN6I_SPI0_CCTL :
++                             SUN4I_SPI0_CCTL));
++              }
++
+               /* 24MHz from OSC24M */
+               writel((1 << 31), CCM_SPI0_CLK);
+       }
+@@ -180,6 +205,14 @@ static void spi0_enable_clock(void)
+               /* Wait for completion */
+               while (readl(base + SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
+                       ;
++
++              /*
++               * For new SoCs we should configure sample mode depending on
++               * input clock. As 24MHz from OSC24M is used, we could use
++               * normal sample mode by setting SDM bit in the TCR register
++               */
++              if (IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
++                      setbits_le32(base + SUN6I_SPI0_TCR, SUN6I_TCR_SDM);
+       } else {
+               /* Enable SPI in the master mode and reset FIFO */
+               setbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+@@ -206,11 +239,13 @@ static void spi0_disable_clock(void)
+               writel(0, CCM_SPI0_CLK);
+       /* Close the SPI0 gate */
+-      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++      if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) &&
++          !IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
+               clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+       /* Assert SPI0 reset on SUN6I */
+-      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6))
++      if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
++          IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2))
+               clrbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+       else if (is_sun6i_gen_spi())
+               clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+@@ -224,7 +259,8 @@ static void spi0_init(void)
+       if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
+           IS_ENABLED(CONFIG_SUN50I_GEN_H6))
+               pin_function = SUN50I_GPC_SPI0;
+-      else if (IS_ENABLED(CONFIG_MACH_SUNIV))
++      else if (IS_ENABLED(CONFIG_MACH_SUNIV) ||
++               IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+               pin_function = SUNIV_GPC_SPI0;
+       spi0_pinmux_setup(pin_function);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4031-spi-sunxi-Add-support-for-R329-D1-R528-T113-SPI-cont.patch b/package/boot/uboot-sunxi/patches/4031-spi-sunxi-Add-support-for-R329-D1-R528-T113-SPI-cont.patch
new file mode 100644 (file)
index 0000000..f8486b4
--- /dev/null
@@ -0,0 +1,122 @@
+From 66aa5102c53c8e462fa5311c7abd252defc74b96 Mon Sep 17 00:00:00 2001
+From: Maxim Kiselev <bigunclemax@gmail.com>
+Date: Fri, 19 May 2023 16:40:08 +0300
+Subject: [PATCH 4031/4052] spi: sunxi: Add support for R329/D1/R528/T113 SPI
+ controller
+
+These SoCs have two SPI controllers that are quite similar to the SPI
+on previous Allwinner SoCs. The main difference is that new SoCs
+don't have a clock divider (SPI_CCR register) inside SPI IP.
+
+Instead SPI sample mode should be configured depending on the input clock.
+
+For now SPI input clock source selection is not supported by this driver,
+and only HOSC@24MHz can be used as input clock. Therefore, according to
+the, manual we could change the SPI sample mode from delay half
+cycle(default) to normal.
+
+This patch adds a quirk for this kind of SPI controllers
+
+Signed-off-by: Maxim Kiselev <bigunclemax@gmail.com>
+Tested-by: Sam Edwards <CFSworks@gmail.com>
+---
+ drivers/spi/spi-sunxi.c | 34 +++++++++++++++++++++++++++++++++-
+ 1 file changed, 33 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
+index c56d82d998..9ec6b359e2 100644
+--- a/drivers/spi/spi-sunxi.c
++++ b/drivers/spi/spi-sunxi.c
+@@ -117,6 +117,8 @@ enum sun4i_spi_bits {
+       SPI_TCR_XCH,
+       SPI_TCR_CS_MANUAL,
+       SPI_TCR_CS_LEVEL,
++      SPI_TCR_SDC,
++      SPI_TCR_SDM,
+       SPI_FCR_TF_RST,
+       SPI_FCR_RF_RST,
+       SPI_FSR_RF_CNT_MASK,
+@@ -128,6 +130,7 @@ struct sun4i_spi_variant {
+       u32 fifo_depth;
+       bool has_soft_reset;
+       bool has_burst_ctl;
++      bool has_clk_ctl;
+ };
+ struct sun4i_spi_plat {
+@@ -302,7 +305,19 @@ static int sun4i_spi_claim_bus(struct udevice *dev)
+       setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
+                    SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
+-      sun4i_spi_set_speed_mode(dev->parent);
++      if (priv->variant->has_clk_ctl) {
++              sun4i_spi_set_speed_mode(dev->parent);
++      } else {
++              /*
++               * At this moment there is no ability to change input clock.
++               * Therefore, we can only use default HOSC@24MHz clock and
++               * set SPI sampling mode to normal
++               */
++              clrsetbits_le32(SPI_REG(priv, SPI_TCR),
++                              SPI_BIT(priv, SPI_TCR_SDC) |
++                              SPI_BIT(priv, SPI_TCR_SDM),
++                              SPI_BIT(priv, SPI_TCR_SDM));
++      }
+       return 0;
+ }
+@@ -516,6 +531,8 @@ static const u32 sun6i_spi_bits[] = {
+       [SPI_TCR_CS_MASK]       = 0x30,
+       [SPI_TCR_CS_MANUAL]     = BIT(6),
+       [SPI_TCR_CS_LEVEL]      = BIT(7),
++      [SPI_TCR_SDC]           = BIT(11),
++      [SPI_TCR_SDM]           = BIT(13),
+       [SPI_TCR_XCH]           = BIT(31),
+       [SPI_FCR_RF_RST]        = BIT(15),
+       [SPI_FCR_TF_RST]        = BIT(31),
+@@ -526,6 +543,7 @@ static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
+       .regs                   = sun4i_spi_regs,
+       .bits                   = sun4i_spi_bits,
+       .fifo_depth             = 64,
++      .has_clk_ctl            = true,
+ };
+ static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
+@@ -534,6 +552,7 @@ static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
+       .fifo_depth             = 128,
+       .has_soft_reset         = true,
+       .has_burst_ctl          = true,
++      .has_clk_ctl            = true,
+ };
+ static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
+@@ -542,6 +561,15 @@ static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
+       .fifo_depth             = 64,
+       .has_soft_reset         = true,
+       .has_burst_ctl          = true,
++      .has_clk_ctl            = true,
++};
++
++static const struct sun4i_spi_variant sun50i_r329_spi_variant = {
++      .regs                   = sun6i_spi_regs,
++      .bits                   = sun6i_spi_bits,
++      .fifo_depth             = 64,
++      .has_soft_reset         = true,
++      .has_burst_ctl          = true,
+ };
+ static const struct udevice_id sun4i_spi_ids[] = {
+@@ -557,6 +585,10 @@ static const struct udevice_id sun4i_spi_ids[] = {
+         .compatible = "allwinner,sun8i-h3-spi",
+         .data = (ulong)&sun8i_h3_spi_variant,
+       },
++      {
++        .compatible = "allwinner,sun50i-r329-spi",
++        .data = (ulong)&sun50i_r329_spi_variant,
++      },
+       { /* sentinel */ }
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4032-riscv-dts-allwinner-d1-Add-SPI-controllers-node.patch b/package/boot/uboot-sunxi/patches/4032-riscv-dts-allwinner-d1-Add-SPI-controllers-node.patch
new file mode 100644 (file)
index 0000000..f946f1f
--- /dev/null
@@ -0,0 +1,77 @@
+From b447d68238499753c42c5baa9f42db778673a023 Mon Sep 17 00:00:00 2001
+From: Maxim Kiselev <bigunclemax@gmail.com>
+Date: Fri, 19 May 2023 16:40:09 +0300
+Subject: [PATCH 4032/4052] riscv: dts: allwinner: d1: Add SPI controllers node
+
+Some boards form the MangoPi family (MQ\MQ-Dual\MQ-R) may have
+an optional SPI flash that connects to the SPI0 controller.
+
+This controller is the same for R329/D1/R528/T113s SoCs and
+should be supported by the sun50i-r329-spi driver.
+
+So let's add its DT nodes.
+
+Signed-off-by: Maxim Kiselev <bigunclemax@gmail.com>
+Reviewed-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/riscv/dts/sunxi-d1s-t113.dtsi | 37 ++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+diff --git a/arch/riscv/dts/sunxi-d1s-t113.dtsi b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+index 922e8e0e2c..1bb1e5cae6 100644
+--- a/arch/riscv/dts/sunxi-d1s-t113.dtsi
++++ b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+@@ -108,6 +108,12 @@
+                               function = "emac";
+                       };
++                      /omit-if-no-ref/
++                      spi0_pins: spi0-pins {
++                              pins = "PC2", "PC3", "PC4", "PC5";
++                              function = "spi0";
++                      };
++
+                       /omit-if-no-ref/
+                       uart1_pg6_pins: uart1-pg6-pins {
+                               pins = "PG6", "PG7";
+@@ -447,6 +453,37 @@
+                       #size-cells = <0>;
+               };
++              spi0: spi@4025000 {
++                      compatible = "allwinner,sun20i-d1-spi",
++                                   "allwinner,sun50i-r329-spi";
++                      reg = <0x04025000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(15) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
++                      clock-names = "ahb", "mod";
++                      dmas = <&dma 22>, <&dma 22>;
++                      dma-names = "rx", "tx";
++                      resets = <&ccu RST_BUS_SPI0>;
++                      status = "disabled";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
++              spi1: spi@4026000 {
++                      compatible = "allwinner,sun20i-d1-spi-dbi",
++                                   "allwinner,sun50i-r329-spi-dbi",
++                                   "allwinner,sun50i-r329-spi";
++                      reg = <0x04026000 0x1000>;
++                      interrupts = <SOC_PERIPHERAL_IRQ(16) IRQ_TYPE_LEVEL_HIGH>;
++                      clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
++                      clock-names = "ahb", "mod";
++                      dmas = <&dma 23>, <&dma 23>;
++                      dma-names = "rx", "tx";
++                      resets = <&ccu RST_BUS_SPI1>;
++                      status = "disabled";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++              };
++
+               usb_otg: usb@4100000 {
+                       compatible = "allwinner,sun20i-d1-musb",
+                                    "allwinner,sun8i-a33-musb";
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4033-mtd-spi-nand-backport-from-upstream-kernel.patch b/package/boot/uboot-sunxi/patches/4033-mtd-spi-nand-backport-from-upstream-kernel.patch
new file mode 100644 (file)
index 0000000..6883cce
--- /dev/null
@@ -0,0 +1,1569 @@
+From 0abff85e4947d6ef306f9e11ad07a7db91fa2700 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Wed, 27 Jul 2022 16:36:13 +0800
+Subject: [PATCH 4033/4052] mtd: spi-nand: backport from upstream kernel
+
+Backport new features from upstream kernel
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/mtd/nand/spi/Kconfig      |   8 +
+ drivers/mtd/nand/spi/core.c       | 101 ++++++----
+ drivers/mtd/nand/spi/gigadevice.c | 322 ++++++++++++++++++++++++++----
+ drivers/mtd/nand/spi/macronix.c   | 173 +++++++++++++---
+ drivers/mtd/nand/spi/micron.c     |  50 ++---
+ drivers/mtd/nand/spi/toshiba.c    |  66 +++---
+ drivers/mtd/nand/spi/winbond.c    | 171 +++++++++++++---
+ include/linux/mtd/spinand.h       |  86 +++++---
+ 8 files changed, 753 insertions(+), 224 deletions(-)
+
+diff --git a/drivers/mtd/nand/spi/Kconfig b/drivers/mtd/nand/spi/Kconfig
+index 0777dfdf0a..bbd0981968 100644
+--- a/drivers/mtd/nand/spi/Kconfig
++++ b/drivers/mtd/nand/spi/Kconfig
+@@ -5,3 +5,11 @@ menuconfig MTD_SPI_NAND
+       select SPI_MEM
+       help
+         This is the framework for the SPI NAND device drivers.
++
++config MTD_SPI_NAND_W25N01KV
++      tristate "Winbond W25N01KV Support"
++      select MTD_SPI_NAND
++      default n
++      help
++        Winbond W25N01KV share the same ID with W25N01GV. However, they have
++        different attributes.
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index 134bf22c80..46ce48e0ea 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -17,6 +17,7 @@
+ #include <linux/mtd/spinand.h>
+ #include <linux/of.h>
+ #include <linux/slab.h>
++#include <linux/string.h>
+ #include <linux/spi/spi.h>
+ #include <linux/spi/spi-mem.h>
+ #else
+@@ -451,10 +452,11 @@ out:
+       return status & STATUS_BUSY ? -ETIMEDOUT : 0;
+ }
+-static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
++static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
++                            u8 ndummy, u8 *buf)
+ {
+-      struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
+-                                               SPINAND_MAX_ID_LEN);
++      struct spi_mem_op op = SPINAND_READID_OP(
++              naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
+       int ret;
+       ret = spi_mem_exec_op(spinand->slave, &op);
+@@ -464,18 +466,6 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
+       return ret;
+ }
+-static int spinand_reset_op(struct spinand_device *spinand)
+-{
+-      struct spi_mem_op op = SPINAND_RESET_OP;
+-      int ret;
+-
+-      ret = spi_mem_exec_op(spinand->slave, &op);
+-      if (ret)
+-              return ret;
+-
+-      return spinand_wait(spinand, NULL);
+-}
+-
+ static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
+ {
+       return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock);
+@@ -836,24 +826,63 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+       &winbond_spinand_manufacturer,
+ };
+-static int spinand_manufacturer_detect(struct spinand_device *spinand)
++static int spinand_manufacturer_match(struct spinand_device *spinand,
++                                    enum spinand_readid_method rdid_method)
+ {
++      u8 *id = spinand->id.data;
+       unsigned int i;
+       int ret;
+       for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
+-              ret = spinand_manufacturers[i]->ops->detect(spinand);
+-              if (ret > 0) {
+-                      spinand->manufacturer = spinand_manufacturers[i];
+-                      return 0;
+-              } else if (ret < 0) {
+-                      return ret;
+-              }
++              const struct spinand_manufacturer *manufacturer =
++                      spinand_manufacturers[i];
++
++              if (id[0] != manufacturer->id)
++                      continue;
++
++              ret = spinand_match_and_init(spinand,
++                                           manufacturer->chips,
++                                           manufacturer->nchips,
++                                           rdid_method);
++              if (ret < 0)
++                      continue;
++
++              spinand->manufacturer = manufacturer;
++              return 0;
+       }
+       return -ENOTSUPP;
+ }
++static int spinand_id_detect(struct spinand_device *spinand)
++{
++      u8 *id = spinand->id.data;
++      int ret;
++
++      ret = spinand_read_id_op(spinand, 0, 0, id);
++      if (ret)
++              return ret;
++      ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE);
++      if (!ret)
++              return 0;
++
++      ret = spinand_read_id_op(spinand, 1, 0, id);
++      if (ret)
++              return ret;
++      ret = spinand_manufacturer_match(spinand,
++                                       SPINAND_READID_METHOD_OPCODE_ADDR);
++      if (!ret)
++              return 0;
++
++      ret = spinand_read_id_op(spinand, 0, 1, id);
++      if (ret)
++              return ret;
++      ret = spinand_manufacturer_match(spinand,
++                                       SPINAND_READID_METHOD_OPCODE_DUMMY);
++
++      return ret;
++}
++
+ static int spinand_manufacturer_init(struct spinand_device *spinand)
+ {
+       if (spinand->manufacturer->ops->init)
+@@ -909,9 +938,9 @@ spinand_select_op_variant(struct spinand_device *spinand,
+  * @spinand: SPI NAND object
+  * @table: SPI NAND device description table
+  * @table_size: size of the device description table
++ * @rdid_method: read id method to match
+  *
+- * Should be used by SPI NAND manufacturer drivers when they want to find a
+- * match between a device ID retrieved through the READ_ID command and an
++ * Match between a device ID retrieved through the READ_ID command and an
+  * entry in the SPI NAND description table. If a match is found, the spinand
+  * object will be initialized with information provided by the matching
+  * spinand_info entry.
+@@ -920,8 +949,10 @@ spinand_select_op_variant(struct spinand_device *spinand,
+  */
+ int spinand_match_and_init(struct spinand_device *spinand,
+                          const struct spinand_info *table,
+-                         unsigned int table_size, u8 devid)
++                         unsigned int table_size,
++                         enum spinand_readid_method rdid_method)
+ {
++      u8 *id = spinand->id.data;
+       struct nand_device *nand = spinand_to_nand(spinand);
+       unsigned int i;
+@@ -929,13 +960,17 @@ int spinand_match_and_init(struct spinand_device *spinand,
+               const struct spinand_info *info = &table[i];
+               const struct spi_mem_op *op;
+-              if (devid != info->devid)
++              if (rdid_method != info->devid.method)
++                      continue;
++
++              if (memcmp(id + 1, info->devid.id, info->devid.len))
+                       continue;
+               nand->memorg = table[i].memorg;
+               nand->eccreq = table[i].eccreq;
+               spinand->eccinfo = table[i].eccinfo;
+               spinand->flags = table[i].flags;
++              spinand->id.len = 1 + table[i].devid.len;
+               spinand->select_target = table[i].select_target;
+               op = spinand_select_op_variant(spinand,
+@@ -967,17 +1002,7 @@ static int spinand_detect(struct spinand_device *spinand)
+       struct nand_device *nand = spinand_to_nand(spinand);
+       int ret;
+-      ret = spinand_reset_op(spinand);
+-      if (ret)
+-              return ret;
+-
+-      ret = spinand_read_id_op(spinand, spinand->id.data);
+-      if (ret)
+-              return ret;
+-
+-      spinand->id.len = SPINAND_MAX_ID_LEN;
+-
+-      ret = spinand_manufacturer_detect(spinand);
++      ret = spinand_id_detect(spinand);
+       if (ret) {
+               dev_err(spinand->slave->dev, "unknown raw ID %*phN\n",
+                       SPINAND_MAX_ID_LEN, spinand->id.data);
+diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
+index a2c93486f4..5357f02ddc 100644
+--- a/drivers/mtd/nand/spi/gigadevice.c
++++ b/drivers/mtd/nand/spi/gigadevice.c
+@@ -22,8 +22,13 @@
+ #define GD5FXGQXXEXXG_REG_STATUS2             0xf0
++#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK                (7 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS        (1 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
++
+ /* Q4 devices, QUADIO: Dummy bytes valid for 1 and 2 GBit variants */
+-static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
++static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+@@ -31,8 +36,17 @@ static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+-/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
+-static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
++static SPINAND_OP_VARIANTS(read_cache_variants_f,
++              SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
++
++/* For Q5 devices, QUADIO use different dummy byte settings */
++/* Q5 1Gb */
++static SPINAND_OP_VARIANTS(dummy2_read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+@@ -40,6 +54,15 @@ static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++/* Q5 2Gb & 4Gb */
++static SPINAND_OP_VARIANTS(dummy4_read_cache_variants,
++              SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
+ static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+@@ -48,7 +71,65 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+-static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
++static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 8;
++      region->length = 8;
++
++      return 0;
++}
++
++static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      if (section) {
++              region->offset = 16 * section;
++              region->length = 8;
++      } else {
++              /* section 0 has one byte reserved for bad block mark */
++              region->offset = 1;
++              region->length = 7;
++      }
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
++      .ecc = gd5fxgq4xa_ooblayout_ecc,
++      .rfree = gd5fxgq4xa_ooblayout_free,
++};
++
++static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
++                                       u8 status)
++{
++      switch (status & STATUS_ECC_MASK) {
++      case STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
++              /* 1-7 bits are flipped. return the maximum. */
++              return 7;
++
++      case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
++              return 8;
++
++      case STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
++static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                      struct mtd_oob_region *region)
+ {
+       if (section)
+@@ -60,7 +141,7 @@ static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+       return 0;
+ }
+-static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
++static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
+                                       struct mtd_oob_region *region)
+ {
+       if (section)
+@@ -73,7 +154,13 @@ static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
+       return 0;
+ }
+-static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
++/* Valid for Q4/Q5 and Q6 (untested) devices */
++static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
++      .ecc = gd5fxgqx_variant2_ooblayout_ecc,
++      .rfree = gd5fxgqx_variant2_ooblayout_free,
++};
++
++static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
+                                       u8 status)
+ {
+       u8 status2;
+@@ -152,59 +239,214 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
+       return -EINVAL;
+ }
+-static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
+-      .ecc = gd5fxgqxxexxg_ooblayout_ecc,
+-      .rfree = gd5fxgqxxexxg_ooblayout_free,
++static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
++                                      u8 status)
++{
++      switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
++      case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
++              return 3;
++
++      case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
++              return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
++      }
++
++      return -EINVAL;
++}
++
++static int esmt_1_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 8;
++      region->length = 8;
++
++      return 0;
++}
++
++static int esmt_1_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 2;
++      region->length = 6;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops esmt_1_ooblayout = {
++      .ecc = esmt_1_ooblayout_ecc,
++      .rfree = esmt_1_ooblayout_free,
+ };
+ static const struct spinand_info gigadevice_spinand_table[] = {
+-      SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
+-                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++      SPINAND_INFO("F50L1G41LB",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+-                   SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
++                   SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+-                   SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
+-                                   gd5fxgq4xexxg_ecc_get_status)),
+-      SPINAND_INFO("GD5F1GQ5UExxG", 0x51,
++                   SPINAND_ECCINFO(&esmt_1_ooblayout, NULL)),
++      SPINAND_INFO("GD5F1GQ4xA",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F2GQ4xA",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
++                   NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F4GQ4xA",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
++                   NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ4UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq4uexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ4UFxxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq4ufxxg_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ5UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+-                   SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
++                   SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+-                   0,
+-                   SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq5xexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F2GQ5UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq5xexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F4GQ6UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x55),
++                   NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq5xexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F1GM7UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x91),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq4uexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F2GM7UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x92),
++                       NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
++                       NAND_ECCREQ(8, 512),
++                       SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                       SPINAND_HAS_QE_BIT,
++                       SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq4uexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F4GM8UExxG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x95),
++                       NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
++                       NAND_ECCREQ(8, 512),
++                       SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                       SPINAND_HAS_QE_BIT,
++                       SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq4uexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ5UExxH",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x31),
++                       NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                       NAND_ECCREQ(4, 512),
++                       SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                       SPINAND_HAS_QE_BIT,
++                       SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq5xexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F2GQ5UExxH",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
++                       NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
++                       NAND_ECCREQ(4, 512),
++                       SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                       SPINAND_HAS_QE_BIT,
++                       SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++                                   gd5fxgq5xexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F4GQ6UExxH",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
++                       NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
++                       NAND_ECCREQ(4, 512),
++                       SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                       SPINAND_HAS_QE_BIT,
++                       SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+                                    gd5fxgq5xexxg_ecc_get_status)),
+ };
+-static int gigadevice_spinand_detect(struct spinand_device *spinand)
+-{
+-      u8 *id = spinand->id.data;
+-      int ret;
+-
+-      /*
+-       * For GD NANDs, There is an address byte needed to shift in before IDs
+-       * are read out, so the first byte in raw_id is dummy.
+-       */
+-      if (id[1] != SPINAND_MFR_GIGADEVICE)
+-              return 0;
+-
+-      ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
+-                                   ARRAY_SIZE(gigadevice_spinand_table),
+-                                   id[2]);
+-      if (ret)
+-              return ret;
+-
+-      return 1;
+-}
+-
+ static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
+-      .detect = gigadevice_spinand_detect,
+ };
+ const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
+       .id = SPINAND_MFR_GIGADEVICE,
+       .name = "GigaDevice",
++      .chips = gigadevice_spinand_table,
++      .nchips = ARRAY_SIZE(gigadevice_spinand_table),
+       .ops = &gigadevice_spinand_manuf_ops,
+ };
+diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
+index 6d643a8000..34e622d6e9 100644
+--- a/drivers/mtd/nand/spi/macronix.c
++++ b/drivers/mtd/nand/spi/macronix.c
+@@ -105,7 +105,8 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
+ }
+ static const struct spinand_info macronix_spinand_table[] = {
+-      SPINAND_INFO("MX35LF1GE4AB", 0x12,
++      SPINAND_INFO("MX35LF1GE4AB",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -114,7 +115,8 @@ static const struct spinand_info macronix_spinand_table[] = {
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+-      SPINAND_INFO("MX35LF2GE4AB", 0x22,
++      SPINAND_INFO("MX35LF2GE4AB",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -122,7 +124,96 @@ static const struct spinand_info macronix_spinand_table[] = {
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+-      SPINAND_INFO("MX35UF4GE4AD", 0xb7,
++      SPINAND_INFO("MX35LF2GE4AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
++                   NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35LF4GE4AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
++                   NAND_MEMORG(1, 4096, 128, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35LF1G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
++      SPINAND_INFO("MX35LF2G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
++      SPINAND_INFO("MX35LF4G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
++                   NAND_MEMORG(1, 4096, 256, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
++      SPINAND_INFO("MX31LF1GE4BC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX31UF1GE4BC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++
++      SPINAND_INFO("MX35LF2G14AC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
++                   NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF4G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
++                   NAND_MEMORG(1, 4096, 256, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF4GE4AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -131,7 +222,28 @@ static const struct spinand_info macronix_spinand_table[] = {
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+-      SPINAND_INFO("MX35UF2GE4AD", 0xa6,
++      SPINAND_INFO("MX35UF2G14AC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
++                   NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF2G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF2GE4AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -140,16 +252,38 @@ static const struct spinand_info macronix_spinand_table[] = {
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+-      SPINAND_INFO("MX35UF2GE4AC", 0xa2,
++      SPINAND_INFO("MX35UF2GE4AC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
++                       SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF1G14AC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
++                                   mx35lf1ge4ab_ecc_get_status)),
++      SPINAND_INFO("MX35UF1G24AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+-      SPINAND_INFO("MX35UF1GE4AD", 0x96,
++      SPINAND_INFO("MX35UF1GE4AD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -158,7 +292,8 @@ static const struct spinand_info macronix_spinand_table[] = {
+                    SPINAND_HAS_QE_BIT,
+                    SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+                                    mx35lf1ge4ab_ecc_get_status)),
+-      SPINAND_INFO("MX35UF1GE4AC", 0x92,
++      SPINAND_INFO("MX35UF1GE4AC",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(4, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -170,33 +305,13 @@ static const struct spinand_info macronix_spinand_table[] = {
+ };
+-static int macronix_spinand_detect(struct spinand_device *spinand)
+-{
+-      u8 *id = spinand->id.data;
+-      int ret;
+-
+-      /*
+-       * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
+-       * raw_id is garbage.
+-       */
+-      if (id[1] != SPINAND_MFR_MACRONIX)
+-              return 0;
+-
+-      ret = spinand_match_and_init(spinand, macronix_spinand_table,
+-                                   ARRAY_SIZE(macronix_spinand_table),
+-                                   id[2]);
+-      if (ret)
+-              return ret;
+-
+-      return 1;
+-}
+-
+ static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
+-      .detect = macronix_spinand_detect,
+ };
+ const struct spinand_manufacturer macronix_spinand_manufacturer = {
+       .id = SPINAND_MFR_MACRONIX,
+       .name = "Macronix",
++      .chips = macronix_spinand_table,
++      .nchips = ARRAY_SIZE(macronix_spinand_table),
+       .ops = &macronix_spinand_manuf_ops,
+ };
+diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
+index 6bacf14aaf..cecd3db958 100644
+--- a/drivers/mtd/nand/spi/micron.c
++++ b/drivers/mtd/nand/spi/micron.c
+@@ -120,7 +120,8 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand,
+ static const struct spinand_info micron_spinand_table[] = {
+       /* M79A 2Gb 3.3V */
+-      SPINAND_INFO("MT29F2G01ABAGD", 0x24,
++      SPINAND_INFO("MT29F2G01ABAGD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -130,7 +131,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M79A 2Gb 1.8V */
+-      SPINAND_INFO("MT29F2G01ABBGD", 0x25,
++      SPINAND_INFO("MT29F2G01ABBGD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -140,7 +142,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M78A 1Gb 3.3V */
+-      SPINAND_INFO("MT29F1G01ABAFD", 0x14,
++      SPINAND_INFO("MT29F1G01ABAFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -150,7 +153,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M78A 1Gb 1.8V */
+-      SPINAND_INFO("MT29F1G01ABAFD", 0x15,
++      SPINAND_INFO("MT29F1G01ABAFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -160,7 +164,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M79A 4Gb 3.3V */
+-      SPINAND_INFO("MT29F4G01ADAGD", 0x36,
++      SPINAND_INFO("MT29F4G01ADAGD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -171,7 +176,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                                    micron_8_ecc_get_status),
+                    SPINAND_SELECT_TARGET(micron_select_target)),
+       /* M70A 4Gb 3.3V */
+-      SPINAND_INFO("MT29F4G01ABAFD", 0x34,
++      SPINAND_INFO("MT29F4G01ABAFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -181,7 +187,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M70A 4Gb 1.8V */
+-      SPINAND_INFO("MT29F4G01ABBFD", 0x35,
++      SPINAND_INFO("MT29F4G01ABBFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -191,7 +198,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_ECCINFO(&micron_8_ooblayout,
+                                    micron_8_ecc_get_status)),
+       /* M70A 8Gb 3.3V */
+-      SPINAND_INFO("MT29F8G01ADAFD", 0x46,
++      SPINAND_INFO("MT29F8G01ADAFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -202,7 +210,8 @@ static const struct spinand_info micron_spinand_table[] = {
+                                    micron_8_ecc_get_status),
+                    SPINAND_SELECT_TARGET(micron_select_target)),
+       /* M70A 8Gb 1.8V */
+-      SPINAND_INFO("MT29F8G01ADBFD", 0x47,
++      SPINAND_INFO("MT29F8G01ADBFD",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -214,26 +223,6 @@ static const struct spinand_info micron_spinand_table[] = {
+                    SPINAND_SELECT_TARGET(micron_select_target)),
+ };
+-static int micron_spinand_detect(struct spinand_device *spinand)
+-{
+-      u8 *id = spinand->id.data;
+-      int ret;
+-
+-      /*
+-       * Micron SPI NAND read ID need a dummy byte,
+-       * so the first byte in raw_id is dummy.
+-       */
+-      if (id[1] != SPINAND_MFR_MICRON)
+-              return 0;
+-
+-      ret = spinand_match_and_init(spinand, micron_spinand_table,
+-                                   ARRAY_SIZE(micron_spinand_table), id[2]);
+-      if (ret)
+-              return ret;
+-
+-      return 1;
+-}
+-
+ static int micron_spinand_init(struct spinand_device *spinand)
+ {
+       /*
+@@ -248,12 +237,13 @@ static int micron_spinand_init(struct spinand_device *spinand)
+ }
+ static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
+-      .detect = micron_spinand_detect,
+       .init = micron_spinand_init,
+ };
+ const struct spinand_manufacturer micron_spinand_manufacturer = {
+       .id = SPINAND_MFR_MICRON,
+       .name = "Micron",
++      .chips = micron_spinand_table,
++      .nchips = ARRAY_SIZE(micron_spinand_table),
+       .ops = &micron_spinand_manuf_ops,
+ };
+diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
+index c2cd3b426b..e057b08c70 100644
+--- a/drivers/mtd/nand/spi/toshiba.c
++++ b/drivers/mtd/nand/spi/toshiba.c
+@@ -111,7 +111,8 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
+ static const struct spinand_info toshiba_spinand_table[] = {
+       /* 3.3V 1Gb (1st generation) */
+-      SPINAND_INFO("TC58CVG0S3HRAIG", 0xC2,
++      SPINAND_INFO("TC58CVG0S3HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -121,7 +122,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 3.3V 2Gb (1st generation) */
+-      SPINAND_INFO("TC58CVG1S3HRAIG", 0xCB,
++      SPINAND_INFO("TC58CVG1S3HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -131,7 +133,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 3.3V 4Gb (1st generation) */
+-      SPINAND_INFO("TC58CVG2S0HRAIG", 0xCD,
++      SPINAND_INFO("TC58CVG2S0HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -141,7 +144,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 1Gb (1st generation) */
+-      SPINAND_INFO("TC58CYG0S3HRAIG", 0xB2,
++      SPINAND_INFO("TC58CYG0S3HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -151,7 +155,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 2Gb (1st generation) */
+-      SPINAND_INFO("TC58CYG1S3HRAIG", 0xBB,
++      SPINAND_INFO("TC58CYG1S3HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -161,7 +166,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 4Gb (1st generation) */
+-      SPINAND_INFO("TC58CYG2S0HRAIG", 0xBD,
++      SPINAND_INFO("TC58CYG2S0HRAIG",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -176,7 +182,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+        * QE_BIT.
+        */
+       /* 3.3V 1Gb (2nd generation) */
+-      SPINAND_INFO("TC58CVG0S3HRAIJ", 0xE2,
++      SPINAND_INFO("TC58CVG0S3HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -186,7 +193,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 3.3V 2Gb (2nd generation) */
+-      SPINAND_INFO("TC58CVG1S3HRAIJ", 0xEB,
++      SPINAND_INFO("TC58CVG1S3HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -196,7 +204,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 3.3V 4Gb (2nd generation) */
+-      SPINAND_INFO("TC58CVG2S0HRAIJ", 0xED,
++      SPINAND_INFO("TC58CVG2S0HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -206,7 +215,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 3.3V 8Gb (2nd generation) */
+-      SPINAND_INFO("TH58CVG3S0HRAIJ", 0xE4,
++      SPINAND_INFO("TH58CVG3S0HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
+                    NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -216,7 +226,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 1Gb (2nd generation) */
+-      SPINAND_INFO("TC58CYG0S3HRAIJ", 0xD2,
++      SPINAND_INFO("TC58CYG0S3HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -226,7 +237,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 2Gb (2nd generation) */
+-      SPINAND_INFO("TC58CYG1S3HRAIJ", 0xDB,
++      SPINAND_INFO("TC58CYG1S3HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -236,7 +248,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 4Gb (2nd generation) */
+-      SPINAND_INFO("TC58CYG2S0HRAIJ", 0xDD,
++      SPINAND_INFO("TC58CYG2S0HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -246,7 +259,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                    SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
+                                    tx58cxgxsxraix_ecc_get_status)),
+       /* 1.8V 8Gb (2nd generation) */
+-      SPINAND_INFO("TH58CYG3S0HRAIJ", 0xD4,
++      SPINAND_INFO("TH58CYG3S0HRAIJ",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
+                    NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -257,33 +271,13 @@ static const struct spinand_info toshiba_spinand_table[] = {
+                                    tx58cxgxsxraix_ecc_get_status)),
+ };
+-static int toshiba_spinand_detect(struct spinand_device *spinand)
+-{
+-      u8 *id = spinand->id.data;
+-      int ret;
+-
+-      /*
+-       * Toshiba SPI NAND read ID needs a dummy byte,
+-       * so the first byte in id is garbage.
+-       */
+-      if (id[1] != SPINAND_MFR_TOSHIBA)
+-              return 0;
+-
+-      ret = spinand_match_and_init(spinand, toshiba_spinand_table,
+-                                   ARRAY_SIZE(toshiba_spinand_table),
+-                                   id[2]);
+-      if (ret)
+-              return ret;
+-
+-      return 1;
+-}
+-
+ static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
+-      .detect = toshiba_spinand_detect,
+ };
+ const struct spinand_manufacturer toshiba_spinand_manufacturer = {
+       .id = SPINAND_MFR_TOSHIBA,
+       .name = "Toshiba",
++      .chips = toshiba_spinand_table,
++      .nchips = ARRAY_SIZE(toshiba_spinand_table),
+       .ops = &toshiba_spinand_manuf_ops,
+ };
+diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
+index c119486efb..7a108cb3e6 100644
+--- a/drivers/mtd/nand/spi/winbond.c
++++ b/drivers/mtd/nand/spi/winbond.c
+@@ -19,6 +19,25 @@
+ #define WINBOND_CFG_BUF_READ          BIT(3)
++#define W25N02_N04KV_STATUS_ECC_MASK          (3 << 4)
++#define W25N02_N04KV_STATUS_ECC_NO_BITFLIPS   (0 << 4)
++#define W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS  (1 << 4)
++#define W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS  (3 << 4)
++#define W25N02_N04KV_STATUS_ECC_UNCOR_ERROR   (2 << 4)
++
++#define W25N01_M02GV_STATUS_ECC_MASK          (3 << 4)
++#define W25N01_M02GV_STATUS_ECC_NO_BITFLIPS   (0 << 4)
++#define W25N01_M02GV_STATUS_ECC_1_BITFLIPS    (1 << 4)
++#define W25N01_M02GV_STATUS_ECC_UNCOR_ERROR   (2 << 4)
++
++#if IS_ENABLED(CONFIG_MTD_SPI_NAND_W25N01KV)
++#define W25N01KV_STATUS_ECC_MASK              (3 << 4)
++#define W25N01KV_STATUS_ECC_NO_BITFLIPS               (0 << 4)
++#define W25N01KV_STATUS_ECC_1_3_BITFLIPS      (1 << 4)
++#define W25N01KV_STATUS_ECC_4_BITFLIPS                (3 << 4)
++#define W25N01KV_STATUS_ECC_UNCOR_ERROR               (2 << 4)
++#endif
++
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+@@ -35,6 +54,35 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
++static int w25n02kv_n04kv_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 64;
++      region->length = 16;
++
++      return 0;
++}
++
++static int w25n02kv_n04kv_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 2;
++      region->length = 14;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops w25n02kv_n04kv_ooblayout = {
++      .ecc = w25n02kv_n04kv_ooblayout_ecc,
++      .rfree = w25n02kv_n04kv_ooblayout_free,
++};
++
+ static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *region)
+ {
+@@ -78,8 +126,63 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
+       return spi_mem_exec_op(spinand->slave, &op);
+ }
++#if IS_ENABLED(CONFIG_MTD_SPI_NAND_W25N01KV)
++static int w25n01kv_ecc_get_status(struct spinand_device *spinand,
++                                      u8 status)
++{
++      switch (status & W25N01KV_STATUS_ECC_MASK) {
++      case W25N01KV_STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case W25N01KV_STATUS_ECC_1_3_BITFLIPS:
++              return 3;
++
++      case W25N01KV_STATUS_ECC_4_BITFLIPS:
++              return 4;
++
++      case W25N01KV_STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++#endif
++
++static int w25n02kv_n04kv_ecc_get_status(struct spinand_device *spinand,
++                                      u8 status)
++{
++      switch (status & W25N02_N04KV_STATUS_ECC_MASK) {
++      case W25N02_N04KV_STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS:
++              return 3;
++
++      case W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS:
++              return 4;
++
++      /* W25N02_N04KV_use internal 8bit ECC algorithm.
++       * But the ECC strength is 4 bit requried.
++       * Return 3 if the bit bit flip count less than 5.
++       * Return 4 if the bit bit flip count more than 5 to 8.
++      */
++
++      case W25N02_N04KV_STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
+ static const struct spinand_info winbond_spinand_table[] = {
+-      SPINAND_INFO("W25M02GV", 0xAB,
++      SPINAND_INFO("W25M02GV",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+                    NAND_ECCREQ(1, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -88,7 +191,19 @@ static const struct spinand_info winbond_spinand_table[] = {
+                    0,
+                    SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+                    SPINAND_SELECT_TARGET(w25m02gv_select_target)),
+-      SPINAND_INFO("W25N01GV", 0xAA,
++#if IS_ENABLED(CONFIG_MTD_SPI_NAND_W25N01KV)
++      SPINAND_INFO("W25N01KV",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
++                   NAND_MEMORG(1, 2048, 96, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout, w25n01kv_ecc_get_status)),
++#else
++      SPINAND_INFO("W25N01GV",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_ECCREQ(1, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -96,32 +211,31 @@ static const struct spinand_info winbond_spinand_table[] = {
+                                             &update_cache_variants),
+                    0,
+                    SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+-};
+-
+-/**
+- * winbond_spinand_detect - initialize device related part in spinand_device
+- * struct if it is a Winbond device.
+- * @spinand: SPI NAND device structure
+- */
+-static int winbond_spinand_detect(struct spinand_device *spinand)
+-{
+-      u8 *id = spinand->id.data;
+-      int ret;
+-
+-      /*
+-       * Winbond SPI NAND read ID need a dummy byte,
+-       * so the first byte in raw_id is dummy.
++#endif
++      SPINAND_INFO("W25N02KV",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
++                                   w25n02kv_n04kv_ecc_get_status)),
++      /* W25N04KV has 2-die(lun), however, it can select die automatically.
++       * Treat it as single die here and double block size.
+        */
+-      if (id[1] != SPINAND_MFR_WINBOND)
+-              return 0;
+-
+-      ret = spinand_match_and_init(spinand, winbond_spinand_table,
+-                                   ARRAY_SIZE(winbond_spinand_table), id[2]);
+-      if (ret)
+-              return ret;
+-
+-      return 1;
+-}
++      SPINAND_INFO("W25N04KV",
++                   SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
++                   NAND_MEMORG(1, 2048, 128, 64, 4096, 2, 1, 1),
++                   NAND_ECCREQ(4, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
++                                   w25n02kv_n04kv_ecc_get_status)),
++};
+ static int winbond_spinand_init(struct spinand_device *spinand)
+ {
+@@ -142,12 +256,13 @@ static int winbond_spinand_init(struct spinand_device *spinand)
+ }
+ static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
+-      .detect = winbond_spinand_detect,
+       .init = winbond_spinand_init,
+ };
+ const struct spinand_manufacturer winbond_spinand_manufacturer = {
+       .id = SPINAND_MFR_WINBOND,
+       .name = "Winbond",
++      .chips = winbond_spinand_table,
++      .nchips = ARRAY_SIZE(winbond_spinand_table),
+       .ops = &winbond_spinand_manuf_ops,
+ };
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 15bcd59f34..3a138f977e 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -39,15 +39,15 @@
+                  SPI_MEM_OP_NO_DUMMY,                                 \
+                  SPI_MEM_OP_NO_DATA)
+-#define SPINAND_READID_OP(ndummy, buf, len)                           \
++#define SPINAND_READID_OP(naddr, ndummy, buf, len)                    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1),                             \
+-                 SPI_MEM_OP_NO_ADDR,                                  \
++                 SPI_MEM_OP_ADDR(naddr, 0, 1),                        \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 1))
+ #define SPINAND_SET_FEATURE_OP(reg, valptr)                           \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1),                             \
+-                 SPI_MEM_OP_ADDR(1, reg, 1),                          \
++                 SPI_MEM_OP_ADDR(1, reg, 1),                                  \
+                  SPI_MEM_OP_NO_DUMMY,                                 \
+                  SPI_MEM_OP_DATA_OUT(1, valptr, 1))
+@@ -75,18 +75,36 @@
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 1))
++#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len)\
++      SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),               \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 1))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
++#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 2))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
++#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 4))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len)        \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 2),                         \
+@@ -153,37 +171,46 @@ struct spinand_device;
+  * @data: buffer containing the id bytes. Currently 4 bytes large, but can
+  *      be extended if required
+  * @len: ID length
+- *
+- * struct_spinand_id->data contains all bytes returned after a READ_ID command,
+- * including dummy bytes if the chip does not emit ID bytes right after the
+- * READ_ID command. The responsibility to extract real ID bytes is left to
+- * struct_manufacurer_ops->detect().
+  */
+ struct spinand_id {
+       u8 data[SPINAND_MAX_ID_LEN];
+       int len;
+ };
++enum spinand_readid_method {
++      SPINAND_READID_METHOD_OPCODE,
++      SPINAND_READID_METHOD_OPCODE_ADDR,
++      SPINAND_READID_METHOD_OPCODE_DUMMY,
++};
++
++/**
++ * struct spinand_devid - SPI NAND device id structure
++ * @id: device id of current chip
++ * @len: number of bytes in device id
++ * @method: method to read chip id
++ *        There are 3 possible variants:
++ *        SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
++ *        after read_id opcode.
++ *        SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
++ *        read_id opcode + 1-byte address.
++ *        SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
++ *        read_id opcode + 1 dummy byte.
++ */
++struct spinand_devid {
++      const u8 *id;
++      const u8 len;
++      const enum spinand_readid_method method;
++};
++
+ /**
+  * struct manufacurer_ops - SPI NAND manufacturer specific operations
+- * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
+- *        the core calls the struct_manufacurer_ops->detect() hook of each
+- *        registered manufacturer until one of them return 1. Note that
+- *        the first thing to check in this hook is that the manufacturer ID
+- *        in struct_spinand_device->id matches the manufacturer whose
+- *        ->detect() hook has been called. Should return 1 if there's a
+- *        match, 0 if the manufacturer ID does not match and a negative
+- *        error code otherwise. When true is returned, the core assumes
+- *        that properties of the NAND chip (spinand->base.memorg and
+- *        spinand->base.eccreq) have been filled
+  * @init: initialize a SPI NAND device
+  * @cleanup: cleanup a SPI NAND device
+  *
+  * Each SPI NAND manufacturer driver should implement this interface so that
+- * NAND chips coming from this vendor can be detected and initialized properly.
++ * NAND chips coming from this vendor can be initialized properly.
+  */
+ struct spinand_manufacturer_ops {
+-      int (*detect)(struct spinand_device *spinand);
+       int (*init)(struct spinand_device *spinand);
+       void (*cleanup)(struct spinand_device *spinand);
+ };
+@@ -192,11 +219,16 @@ struct spinand_manufacturer_ops {
+  * struct spinand_manufacturer - SPI NAND manufacturer instance
+  * @id: manufacturer ID
+  * @name: manufacturer name
++ * @devid_len: number of bytes in device ID
++ * @chips: supported SPI NANDs under current manufacturer
++ * @nchips: number of SPI NANDs available in chips array
+  * @ops: manufacturer operations
+  */
+ struct spinand_manufacturer {
+       u8 id;
+       char *name;
++      const struct spinand_info *chips;
++      const size_t nchips;
+       const struct spinand_manufacturer_ops *ops;
+ };
+@@ -268,7 +300,7 @@ struct spinand_ecc_info {
+  */
+ struct spinand_info {
+       const char *model;
+-      u8 devid;
++      struct spinand_devid devid;
+       u32 flags;
+       struct nand_memory_organization memorg;
+       struct nand_ecc_req eccreq;
+@@ -282,6 +314,13 @@ struct spinand_info {
+                            unsigned int target);
+ };
++#define SPINAND_ID(__method, ...)                                     \
++      {                                                               \
++              .id = (const u8[]){ __VA_ARGS__ },                      \
++              .len = sizeof((u8[]){ __VA_ARGS__ }),                   \
++              .method = __method,                                     \
++      }
++
+ #define SPINAND_INFO_OP_VARIANTS(__read, __write, __update)           \
+       {                                                               \
+               .read_cache = __read,                                   \
+@@ -440,9 +479,10 @@ static inline void spinand_set_ofnode(struct spinand_device *spinand,
+ }
+ #endif /* __UBOOT__ */
+-int spinand_match_and_init(struct spinand_device *dev,
++int spinand_match_and_init(struct spinand_device *spinand,
+                          const struct spinand_info *table,
+-                         unsigned int table_size, u8 devid);
++                         unsigned int table_size,
++                         enum spinand_readid_method rdid_method);
+ int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
+ int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4034-sunxi-psci-clean-away-preprocessor-macros.patch b/package/boot/uboot-sunxi/patches/4034-sunxi-psci-clean-away-preprocessor-macros.patch
new file mode 100644 (file)
index 0000000..9088102
--- /dev/null
@@ -0,0 +1,163 @@
+From 0ecc2b9041144670a3fbaabd2c77cfe2cf85f930 Mon Sep 17 00:00:00 2001
+From: Sam Edwards <cfsworks@gmail.com>
+Date: Wed, 16 Aug 2023 10:34:16 -0700
+Subject: [PATCH 4034/4052] sunxi: psci: clean away preprocessor macros
+
+This patch restructures psci.c to get away from the "many different
+function definitions switched by #ifdef" paradigm to the preferred style
+of having a single function definition with `if (IS_ENABLED(...))` to
+make the optimizer include only the appropriate function bodies instead.
+
+There are no functional changes here.
+
+Signed-off-by: Sam Edwards <CFSworks@gmail.com>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/cpu/armv7/sunxi/psci.c | 102 +++++++++++++-------------------
+ 1 file changed, 42 insertions(+), 60 deletions(-)
+
+diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
+index e1d3638b5c..7804e0933b 100644
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -76,11 +76,8 @@ static void __secure __mdelay(u32 ms)
+       isb();
+ }
+-static void __secure clamp_release(u32 __maybe_unused *clamp)
++static void __secure clamp_release(u32 *clamp)
+ {
+-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
+-      defined(CONFIG_MACH_SUN8I_H3) || \
+-      defined(CONFIG_MACH_SUN8I_R40)
+       u32 tmp = 0x1ff;
+       do {
+               tmp >>= 1;
+@@ -88,83 +85,68 @@ static void __secure clamp_release(u32 __maybe_unused *clamp)
+       } while (tmp);
+       __mdelay(10);
+-#endif
+ }
+-static void __secure clamp_set(u32 __maybe_unused *clamp)
++static void __secure clamp_set(u32 *clamp)
+ {
+-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || \
+-      defined(CONFIG_MACH_SUN8I_H3) || \
+-      defined(CONFIG_MACH_SUN8I_R40)
+       writel(0xff, clamp);
+-#endif
+ }
+-static void __secure sunxi_power_switch(u32 *clamp, u32 *pwroff, bool on,
+-                                      int cpu)
++static void __secure sunxi_set_entry_address(void *entry)
+ {
+-      if (on) {
+-              /* Release power clamp */
+-              clamp_release(clamp);
+-
+-              /* Clear power gating */
+-              clrbits_le32(pwroff, BIT(cpu));
++      /* secondary core entry address is programmed differently on R40 */
++      if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
++              writel((u32)entry,
++                     SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
+       } else {
+-              /* Set power gating */
+-              setbits_le32(pwroff, BIT(cpu));
++              struct sunxi_cpucfg_reg *cpucfg =
++                      (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-              /* Activate power clamp */
+-              clamp_set(clamp);
++              writel((u32)entry, &cpucfg->priv0);
+       }
+ }
+-#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)
++static void __secure sunxi_cpu_set_power(int cpu, bool on)
+ {
++      u32 *clamp = NULL;
++      u32 *pwroff;
+       struct sunxi_cpucfg_reg *cpucfg =
+               (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-      writel((u32)entry, &cpucfg->priv0);
+-}
+-#endif
++      /* sun7i (A20) is different from other single cluster SoCs */
++      if (IS_ENABLED(CONFIG_MACH_SUN7I)) {
++              clamp = &cpucfg->cpu1_pwr_clamp;
++              pwroff = &cpucfg->cpu1_pwroff;
++      } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
++              clamp = (void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu);
++              pwroff = (void *)cpucfg + SUN8I_R40_PWROFF;
++      } else {
++              struct sunxi_prcm_reg *prcm =
++                      (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+-#ifdef CONFIG_MACH_SUN7I
+-/* sun7i (A20) is different from other single cluster SoCs */
+-static void __secure sunxi_cpu_set_power(int __always_unused cpu, bool on)
+-{
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++              if (IS_ENABLED(CONFIG_MACH_SUN6I) ||
++                  IS_ENABLED(CONFIG_MACH_SUN8I_H3))
++                      clamp = &prcm->cpu_pwr_clamp[cpu];
+-      sunxi_power_switch(&cpucfg->cpu1_pwr_clamp, &cpucfg->cpu1_pwroff,
+-                         on, 0);
+-}
+-#elif defined CONFIG_MACH_SUN8I_R40
+-static void __secure sunxi_cpu_set_power(int cpu, bool on)
+-{
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++              pwroff = &prcm->cpu_pwroff;
++      }
+-      sunxi_power_switch((void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu),
+-                         (void *)cpucfg + SUN8I_R40_PWROFF,
+-                         on, cpu);
+-}
+-#else /* ! CONFIG_MACH_SUN7I && ! CONFIG_MACH_SUN8I_R40 */
+-static void __secure sunxi_cpu_set_power(int cpu, bool on)
+-{
+-      struct sunxi_prcm_reg *prcm =
+-              (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
++      if (on) {
++              /* Release power clamp */
++              if (clamp)
++                      clamp_release(clamp);
+-      sunxi_power_switch(&prcm->cpu_pwr_clamp[cpu], &prcm->cpu_pwroff,
+-                         on, cpu);
++              /* Clear power gating */
++              clrbits_le32(pwroff, BIT(cpu));
++      } else {
++              /* Set power gating */
++              setbits_le32(pwroff, BIT(cpu));
++
++              /* Activate power clamp */
++              if (clamp)
++                      clamp_set(clamp);
++      }
+ }
+-#endif /* CONFIG_MACH_SUN7I */
+ void __secure sunxi_cpu_power_off(u32 cpuid)
+ {
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4035-sunxi-psci-refactor-register-access-to-separate-func.patch b/package/boot/uboot-sunxi/patches/4035-sunxi-psci-refactor-register-access-to-separate-func.patch
new file mode 100644 (file)
index 0000000..ad3685b
--- /dev/null
@@ -0,0 +1,146 @@
+From a6ee36e14e484a0a00e6b03ebbe1a380f41fdcf9 Mon Sep 17 00:00:00 2001
+From: Sam Edwards <cfsworks@gmail.com>
+Date: Wed, 16 Aug 2023 10:34:17 -0700
+Subject: [PATCH 4035/4052] sunxi: psci: refactor register access to separate
+ functions
+
+This is to prepare for R528, which does not have the typical
+"CPUCFG" block; it has a "CPUX" block which provides these
+same functions but is organized differently.
+
+Moving the hardware-access bits to their own functions separates the
+logic from the hardware so we can reuse the same logic.
+
+Signed-off-by: Sam Edwards <CFSworks@gmail.com>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/cpu/armv7/sunxi/psci.c | 66 +++++++++++++++++++++++----------
+ 1 file changed, 47 insertions(+), 19 deletions(-)
+
+diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
+index 7804e0933b..e2845f21ab 100644
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -92,7 +92,7 @@ static void __secure clamp_set(u32 *clamp)
+       writel(0xff, clamp);
+ }
+-static void __secure sunxi_set_entry_address(void *entry)
++static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry)
+ {
+       /* secondary core entry address is programmed differently on R40 */
+       if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
+@@ -148,30 +148,60 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
+       }
+ }
+-void __secure sunxi_cpu_power_off(u32 cpuid)
++static void __secure sunxi_cpu_set_reset(int cpu, bool reset)
++{
++      struct sunxi_cpucfg_reg *cpucfg =
++              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++
++      writel(reset ? 0b00 : 0b11, &cpucfg->cpu[cpu].rst);
++}
++
++static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
+ {
+       struct sunxi_cpucfg_reg *cpucfg =
+               (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++
++      if (lock)
++              clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++      else
++              setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++}
++
++static bool __secure sunxi_cpu_poll_wfi(int cpu)
++{
++      struct sunxi_cpucfg_reg *cpucfg =
++              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++
++      return !!(readl(&cpucfg->cpu[cpu].status) & BIT(2));
++}
++
++static void __secure sunxi_cpu_invalidate_cache(int cpu)
++{
++      struct sunxi_cpucfg_reg *cpucfg =
++              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
++
++      clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
++}
++
++void __secure sunxi_cpu_power_off(u32 cpuid)
++{
+       u32 cpu = cpuid & 0x3;
+       /* Wait for the core to enter WFI */
+-      while (1) {
+-              if (readl(&cpucfg->cpu[cpu].status) & BIT(2))
+-                      break;
++      while (!sunxi_cpu_poll_wfi(cpu))
+               __mdelay(1);
+-      }
+       /* Assert reset on target CPU */
+-      writel(0, &cpucfg->cpu[cpu].rst);
++      sunxi_cpu_set_reset(cpu, true);
+       /* Lock CPU (Disable external debug access) */
+-      clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++      sunxi_cpu_set_locking(cpu, true);
+       /* Power down CPU */
+       sunxi_cpu_set_power(cpuid, false);
+-      /* Unlock CPU (Disable external debug access) */
+-      setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++      /* Unlock CPU (Reenable external debug access) */
++      sunxi_cpu_set_locking(cpu, false);
+ }
+ static u32 __secure cp15_read_scr(void)
+@@ -228,33 +258,31 @@ out:
+ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
+                        u32 context_id)
+ {
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+       u32 cpu = (mpidr & 0x3);
+       /* store target PC and context id */
+       psci_save(cpu, pc, context_id);
+       /* Set secondary core power on PC */
+-      sunxi_set_entry_address(&psci_cpu_entry);
++      sunxi_cpu_set_entry(cpu, &psci_cpu_entry);
+       /* Assert reset on target CPU */
+-      writel(0, &cpucfg->cpu[cpu].rst);
++      sunxi_cpu_set_reset(cpu, true);
+       /* Invalidate L1 cache */
+-      clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
++      sunxi_cpu_invalidate_cache(cpu);
+       /* Lock CPU (Disable external debug access) */
+-      clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++      sunxi_cpu_set_locking(cpu, true);
+       /* 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);
++      sunxi_cpu_set_reset(cpu, false);
+-      /* Unlock CPU (Disable external debug access) */
+-      setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++      /* Unlock CPU (Reenable external debug access) */
++      sunxi_cpu_set_locking(cpu, false);
+       return ARM_PSCI_RET_SUCCESS;
+ }
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4036-sunxi-psci-stop-modeling-register-layout-with-C-stru.patch b/package/boot/uboot-sunxi/patches/4036-sunxi-psci-stop-modeling-register-layout-with-C-stru.patch
new file mode 100644 (file)
index 0000000..d47202e
--- /dev/null
@@ -0,0 +1,215 @@
+From 6213b44b5dc472ceb28fb6082559a995e510d35b Mon Sep 17 00:00:00 2001
+From: Sam Edwards <cfsworks@gmail.com>
+Date: Wed, 16 Aug 2023 10:34:18 -0700
+Subject: [PATCH 4036/4052] sunxi: psci: stop modeling register layout with C
+ structs
+
+Since the sunxi support nowadays generally prefers #defined register
+offsets instead of modeling register layouts using C structs, now is a
+good time to do this for PSCI as well. This patch moves away from using
+the structs `sunxi_cpucfg_reg` and `sunxi_prcm_reg` in psci.c.
+
+The former struct and its associated header file existed only to support
+PSCI code, so also delete them altogether.
+
+Signed-off-by: Sam Edwards <CFSworks@gmail.com>
+---
+ arch/arm/cpu/armv7/sunxi/psci.c          | 57 ++++++++------------
+ arch/arm/include/asm/arch-sunxi/cpucfg.h | 67 ------------------------
+ 2 files changed, 23 insertions(+), 101 deletions(-)
+ delete mode 100644 arch/arm/include/asm/arch-sunxi/cpucfg.h
+
+diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
+index e2845f21ab..6ecdd05250 100644
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -11,8 +11,6 @@
+ #include <asm/cache.h>
+ #include <asm/arch/cpu.h>
+-#include <asm/arch/cpucfg.h>
+-#include <asm/arch/prcm.h>
+ #include <asm/armv7.h>
+ #include <asm/gic.h>
+ #include <asm/io.h>
+@@ -27,6 +25,17 @@
+ #define       GICD_BASE       (SUNXI_GIC400_BASE + GIC_DIST_OFFSET)
+ #define       GICC_BASE       (SUNXI_GIC400_BASE + GIC_CPU_OFFSET_A15)
++/*
++ * Offsets into the CPUCFG block applicable to most SUNXIs.
++ */
++#define SUNXI_CPU_RST(cpu)                    (0x40 + (cpu) * 0x40 + 0x0)
++#define SUNXI_CPU_STATUS(cpu)                 (0x40 + (cpu) * 0x40 + 0x8)
++#define SUNXI_GEN_CTRL                                (0x184)
++#define SUNXI_PRIV0                           (0x1a4)
++#define SUN7I_CPU1_PWR_CLAMP                  (0x1b0)
++#define SUN7I_CPU1_PWROFF                     (0x1b4)
++#define SUNXI_DBG_CTRL1                               (0x1e4)
++
+ /*
+  * R40 is different from other single cluster SoCs.
+  *
+@@ -99,10 +108,7 @@ static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry)
+               writel((u32)entry,
+                      SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
+       } else {
+-              struct sunxi_cpucfg_reg *cpucfg =
+-                      (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-
+-              writel((u32)entry, &cpucfg->priv0);
++              writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0);
+       }
+ }
+@@ -110,25 +116,20 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
+ {
+       u32 *clamp = NULL;
+       u32 *pwroff;
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+       /* sun7i (A20) is different from other single cluster SoCs */
+       if (IS_ENABLED(CONFIG_MACH_SUN7I)) {
+-              clamp = &cpucfg->cpu1_pwr_clamp;
+-              pwroff = &cpucfg->cpu1_pwroff;
++              clamp = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWR_CLAMP;
++              pwroff = (void *)SUNXI_CPUCFG_BASE + SUN7I_CPU1_PWROFF;
+       } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
+-              clamp = (void *)cpucfg + SUN8I_R40_PWR_CLAMP(cpu);
+-              pwroff = (void *)cpucfg + SUN8I_R40_PWROFF;
++              clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu);
++              pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF;
+       } else {
+-              struct sunxi_prcm_reg *prcm =
+-                      (struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+-
+               if (IS_ENABLED(CONFIG_MACH_SUN6I) ||
+                   IS_ENABLED(CONFIG_MACH_SUN8I_H3))
+-                      clamp = &prcm->cpu_pwr_clamp[cpu];
++                      clamp = (void *)SUNXI_PRCM_BASE + 0x140 + cpu * 0x4;
+-              pwroff = &prcm->cpu_pwroff;
++              pwroff = (void *)SUNXI_PRCM_BASE + 0x100;
+       }
+       if (on) {
+@@ -150,37 +151,25 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
+ static void __secure sunxi_cpu_set_reset(int cpu, bool reset)
+ {
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-
+-      writel(reset ? 0b00 : 0b11, &cpucfg->cpu[cpu].rst);
++      writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu));
+ }
+ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
+ {
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-
+       if (lock)
+-              clrbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++              clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu));
+       else
+-              setbits_le32(&cpucfg->dbg_ctrl1, BIT(cpu));
++              setbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu));
+ }
+ static bool __secure sunxi_cpu_poll_wfi(int cpu)
+ {
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-
+-      return !!(readl(&cpucfg->cpu[cpu].status) & BIT(2));
++      return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2));
+ }
+ static void __secure sunxi_cpu_invalidate_cache(int cpu)
+ {
+-      struct sunxi_cpucfg_reg *cpucfg =
+-              (struct sunxi_cpucfg_reg *)SUNXI_CPUCFG_BASE;
+-
+-      clrbits_le32(&cpucfg->gen_ctrl, BIT(cpu));
++      clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu));
+ }
+ void __secure sunxi_cpu_power_off(u32 cpuid)
+diff --git a/arch/arm/include/asm/arch-sunxi/cpucfg.h b/arch/arm/include/asm/arch-sunxi/cpucfg.h
+deleted file mode 100644
+index 4aaebe0a97..0000000000
+--- a/arch/arm/include/asm/arch-sunxi/cpucfg.h
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0+ */
+-/*
+- * Sunxi A31 CPUCFG register definition.
+- *
+- * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com
+- */
+-
+-#ifndef _SUNXI_CPUCFG_H
+-#define _SUNXI_CPUCFG_H
+-
+-#include <linux/compiler.h>
+-#include <linux/types.h>
+-
+-#ifndef __ASSEMBLY__
+-
+-struct __packed sunxi_cpucfg_cpu {
+-      u32 rst;                /* base + 0x0 */
+-      u32 ctrl;               /* base + 0x4 */
+-      u32 status;             /* base + 0x8 */
+-      u8 res[0x34];           /* base + 0xc */
+-};
+-
+-struct __packed sunxi_cpucfg_reg {
+-      u8 res0[0x40];          /* 0x000 */
+-      struct sunxi_cpucfg_cpu cpu[4];         /* 0x040 */
+-      u8 res1[0x44];          /* 0x140 */
+-      u32 gen_ctrl;           /* 0x184 */
+-      u32 l2_status;          /* 0x188 */
+-      u8 res2[0x4];           /* 0x18c */
+-      u32 event_in;           /* 0x190 */
+-      u8 res3[0xc];           /* 0x194 */
+-      u32 super_standy_flag;  /* 0x1a0 */
+-      u32 priv0;              /* 0x1a4 */
+-      u32 priv1;              /* 0x1a8 */
+-      u8 res4[0x4];           /* 0x1ac */
+-      u32 cpu1_pwr_clamp;     /* 0x1b0 sun7i only */
+-      u32 cpu1_pwroff;        /* 0x1b4 sun7i only */
+-      u8 res5[0x2c];          /* 0x1b8 */
+-      u32 dbg_ctrl1;          /* 0x1e4 */
+-      u8 res6[0x18];          /* 0x1e8 */
+-      u32 idle_cnt0_low;      /* 0x200 */
+-      u32 idle_cnt0_high;     /* 0x204 */
+-      u32 idle_cnt0_ctrl;     /* 0x208 */
+-      u8 res8[0x4];           /* 0x20c */
+-      u32 idle_cnt1_low;      /* 0x210 */
+-      u32 idle_cnt1_high;     /* 0x214 */
+-      u32 idle_cnt1_ctrl;     /* 0x218 */
+-      u8 res9[0x4];           /* 0x21c */
+-      u32 idle_cnt2_low;      /* 0x220 */
+-      u32 idle_cnt2_high;     /* 0x224 */
+-      u32 idle_cnt2_ctrl;     /* 0x228 */
+-      u8 res10[0x4];          /* 0x22c */
+-      u32 idle_cnt3_low;      /* 0x230 */
+-      u32 idle_cnt3_high;     /* 0x234 */
+-      u32 idle_cnt3_ctrl;     /* 0x238 */
+-      u8 res11[0x4];          /* 0x23c */
+-      u32 idle_cnt4_low;      /* 0x240 */
+-      u32 idle_cnt4_high;     /* 0x244 */
+-      u32 idle_cnt4_ctrl;     /* 0x248 */
+-      u8 res12[0x34];         /* 0x24c */
+-      u32 cnt64_ctrl;         /* 0x280 */
+-      u32 cnt64_low;          /* 0x284 */
+-      u32 cnt64_high;         /* 0x288 */
+-};
+-
+-#endif /* __ASSEMBLY__ */
+-#endif /* _SUNXI_CPUCFG_H */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4037-sunxi-psci-implement-PSCI-on-R528.patch b/package/boot/uboot-sunxi/patches/4037-sunxi-psci-implement-PSCI-on-R528.patch
new file mode 100644 (file)
index 0000000..a9c40e7
--- /dev/null
@@ -0,0 +1,151 @@
+From 59c86f6f0c3abc711b018b1ad3795d601103cadc Mon Sep 17 00:00:00 2001
+From: Sam Edwards <cfsworks@gmail.com>
+Date: Wed, 16 Aug 2023 10:34:19 -0700
+Subject: [PATCH 4037/4052] sunxi: psci: implement PSCI on R528
+
+This patch adds the necessary code to make nonsec booting and PSCI
+secondary core management functional on the R528/T113.
+
+Signed-off-by: Sam Edwards <CFSworks@gmail.com>
+Tested-by: Maksim Kiselev <bigunclemax@gmail.com>
+---
+ arch/arm/cpu/armv7/sunxi/psci.c | 48 ++++++++++++++++++++++++++++++++-
+ arch/arm/mach-sunxi/Kconfig     |  2 ++
+ include/configs/sunxi-common.h  |  8 ++++++
+ 3 files changed, 57 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
+index 6ecdd05250..b4ce4f6def 100644
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -47,6 +47,19 @@
+ #define SUN8I_R40_PWR_CLAMP(cpu)              (0x120 + (cpu) * 0x4)
+ #define SUN8I_R40_SRAMC_SOFT_ENTRY_REG0               (0xbc)
++/*
++ * R528 is also different, as it has both cores powered up (but held in reset
++ * state) after the SoC is reset. Like the R40, it uses a "soft" entry point
++ * address register, but unlike the R40, it uses a newer "CPUX" block to manage
++ * CPU state, rather than the older CPUCFG system.
++ */
++#define SUN8I_R528_SOFT_ENTRY                 (0x1c8)
++#define SUN8I_R528_C0_RST_CTRL                        (0x0000)
++#define SUN8I_R528_C0_CTRL_REG0                       (0x0010)
++#define SUN8I_R528_C0_CPU_STATUS              (0x0080)
++
++#define SUN8I_R528_C0_STATUS_STANDBYWFI               (16)
++
+ static void __secure cp15_write_cntp_tval(u32 tval)
+ {
+       asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
+@@ -103,10 +116,13 @@ static void __secure clamp_set(u32 *clamp)
+ static void __secure sunxi_cpu_set_entry(int __always_unused cpu, void *entry)
+ {
+-      /* secondary core entry address is programmed differently on R40 */
++      /* secondary core entry address is programmed differently on R40/528 */
+       if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
+               writel((u32)entry,
+                      SUNXI_SRAMC_BASE + SUN8I_R40_SRAMC_SOFT_ENTRY_REG0);
++      } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              writel((u32)entry,
++                     SUNXI_R_CPUCFG_BASE + SUN8I_R528_SOFT_ENTRY);
+       } else {
+               writel((u32)entry, SUNXI_CPUCFG_BASE + SUNXI_PRIV0);
+       }
+@@ -124,6 +140,9 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
+       } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R40)) {
+               clamp = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWR_CLAMP(cpu);
+               pwroff = (void *)SUNXI_CPUCFG_BASE + SUN8I_R40_PWROFF;
++      } else if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              /* R528 leaves both cores powered up, manages them via reset */
++              return;
+       } else {
+               if (IS_ENABLED(CONFIG_MACH_SUN6I) ||
+                   IS_ENABLED(CONFIG_MACH_SUN8I_H3))
+@@ -151,11 +170,27 @@ static void __secure sunxi_cpu_set_power(int cpu, bool on)
+ static void __secure sunxi_cpu_set_reset(int cpu, bool reset)
+ {
++      if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              if (reset) {
++                      clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
++                                   BIT(cpu));
++              } else {
++                      setbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_RST_CTRL,
++                                   BIT(cpu));
++              }
++              return;
++      }
++
+       writel(reset ? 0b00 : 0b11, SUNXI_CPUCFG_BASE + SUNXI_CPU_RST(cpu));
+ }
+ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
+ {
++      if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              /* Not required on R528 */
++              return;
++      }
++
+       if (lock)
+               clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_DBG_CTRL1, BIT(cpu));
+       else
+@@ -164,11 +199,22 @@ static void __secure sunxi_cpu_set_locking(int cpu, bool lock)
+ static bool __secure sunxi_cpu_poll_wfi(int cpu)
+ {
++      if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              return !!(readl(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CPU_STATUS) &
++                        BIT(SUN8I_R528_C0_STATUS_STANDBYWFI + cpu));
++      }
++
+       return !!(readl(SUNXI_CPUCFG_BASE + SUNXI_CPU_STATUS(cpu)) & BIT(2));
+ }
+ static void __secure sunxi_cpu_invalidate_cache(int cpu)
+ {
++      if (IS_ENABLED(CONFIG_MACH_SUN8I_R528)) {
++              clrbits_le32(SUNXI_CPUCFG_BASE + SUN8I_R528_C0_CTRL_REG0,
++                           BIT(cpu));
++              return;
++      }
++
+       clrbits_le32(SUNXI_CPUCFG_BASE + SUNXI_GEN_CTRL, BIT(cpu));
+ }
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 81d2a173d0..7233ecbc1c 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -319,6 +319,8 @@ config MACH_SUN8I_R40
+ config MACH_SUN8I_R528
+       bool "sun8i (Allwinner R528)"
+       select CPU_V7A
++      select CPU_V7_HAS_NONSEC
++      select ARCH_SUPPORT_PSCI
+       select SUNXI_GEN_NCAT2
+       select SUNXI_NEW_PINCTRL
+       select MMC_SUNXI_HAS_NEW_MODE
+diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
+index b8ca77d031..67eb0d25db 100644
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -33,6 +33,14 @@
+ /* CPU */
++/*
++ * Newer ARM SoCs have moved the GIC, but have not updated their ARM cores to
++ * reflect the correct address in CBAR/PERIPHBASE.
++ */
++#if defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
++#define CFG_ARM_GIC_BASE_ADDRESS      0x03020000
++#endif
++
+ /*
+  * The DRAM Base differs between some models. We cannot use macros for the
+  * CONFIG_FOO defines which contain the DRAM base address since they end
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4038-HACK-sunxi-psci-be-compatible-with-v1-of-R528-patchs.patch b/package/boot/uboot-sunxi/patches/4038-HACK-sunxi-psci-be-compatible-with-v1-of-R528-patchs.patch
new file mode 100644 (file)
index 0000000..ddb13c5
--- /dev/null
@@ -0,0 +1,38 @@
+From 1ae024a941fcbb196a02cf78c710a2120e86f52c Mon Sep 17 00:00:00 2001
+From: Sam Edwards <cfsworks@gmail.com>
+Date: Wed, 16 Aug 2023 10:34:20 -0700
+Subject: [PATCH 4038/4052] HACK: sunxi: psci: be compatible with v1 of R528
+ patchset
+
+This is a hack for reviewer QoL. It is not being submitted for mainline
+inclusion.
+---
+ arch/arm/cpu/armv7/sunxi/psci.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c
+index b4ce4f6def..27bac291d5 100644
+--- a/arch/arm/cpu/armv7/sunxi/psci.c
++++ b/arch/arm/cpu/armv7/sunxi/psci.c
+@@ -60,6 +60,18 @@
+ #define SUN8I_R528_C0_STATUS_STANDBYWFI               (16)
++/* 3 hacks for compatibility across v1/v2 of Andre's R528 support series */
++#ifndef SUNXI_R_CPUCFG_BASE
++#define SUNXI_R_CPUCFG_BASE                   0
++#endif
++#ifndef SUNXI_PRCM_BASE
++#define SUNXI_PRCM_BASE                               0
++#endif
++#if defined(SUNXI_CPUX_BASE) && defined(SUNXI_CPUCFG_BASE)
++#undef SUNXI_CPUCFG_BASE
++#define SUNXI_CPUCFG_BASE SUNXI_CPUX_BASE
++#endif
++
+ static void __secure cp15_write_cntp_tval(u32 tval)
+ {
+       asm volatile ("mcr p15, 0, %0, c14, c2, 0" : : "r" (tval));
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4039-sunxi-add-uart0_pins-on-Port-E-PE2-PE3-on-D1s-T133.patch b/package/boot/uboot-sunxi/patches/4039-sunxi-add-uart0_pins-on-Port-E-PE2-PE3-on-D1s-T133.patch
new file mode 100644 (file)
index 0000000..58a7982
--- /dev/null
@@ -0,0 +1,30 @@
+From d71edd5b4c744fd7eae2973819765b5c6aced322 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 3 Jun 2023 00:52:04 +0200
+Subject: [PATCH 4039/4052] sunxi: add uart0_pins on Port E PE2/PE3 on D1s/T133
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/riscv/dts/sunxi-d1s-t113.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/riscv/dts/sunxi-d1s-t113.dtsi b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+index 1bb1e5cae6..567aa43d70 100644
+--- a/arch/riscv/dts/sunxi-d1s-t113.dtsi
++++ b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+@@ -131,6 +131,12 @@
+                               pins = "PB6", "PB7";
+                               function = "uart3";
+                       };
++
++                      /omit-if-no-ref/
++                      uart0_pins: uart0-pins {
++                              pins = "PE2", "PE3";
++                              function = "uart0";
++                      };
+               };
+               ccu: clock-controller@2001000 {
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4040-sunxi-add-support-for-MangoPI-MQDual-T113-variant.patch b/package/boot/uboot-sunxi/patches/4040-sunxi-add-support-for-MangoPI-MQDual-T113-variant.patch
new file mode 100644 (file)
index 0000000..7e85de4
--- /dev/null
@@ -0,0 +1,110 @@
+From 759dea3364c28424cf8c94c327ffc60682d87ad3 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 3 Jun 2023 00:52:40 +0200
+Subject: [PATCH 4040/4052] sunxi: add support for MangoPI MQDual T113 variant
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/Makefile                         |  3 +-
+ .../dts/sun8i-t113s-mangopi-mqdual-t113.dts   | 50 +++++++++++++++++++
+ configs/mangopi_mqdual_t113_defconfig         | 17 +++++++
+ 3 files changed, 69 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/dts/sun8i-t113s-mangopi-mqdual-t113.dts
+ create mode 100644 configs/mangopi_mqdual_t113_defconfig
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index 41ee9c4c65..4207f17601 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -711,7 +711,8 @@ dtb-$(CONFIG_MACH_SUN8I_V3S) += \
+       sun8i-v3-sl631-imx179.dtb \
+       sun8i-v3s-licheepi-zero.dtb
+ dtb-$(CONFIG_MACH_SUN8I_R528) += \
+-      sun8i-t113s-mangopi-mq-r-t113.dtb
++      sun8i-t113s-mangopi-mq-r-t113.dtb \
++      sun8i-t113s-mangopi-mqdual-t113.dtb
+ dtb-$(CONFIG_MACH_SUN50I_H5) += \
+       sun50i-h5-bananapi-m2-plus.dtb \
+       sun50i-h5-emlid-neutis-n5-devboard.dtb \
+diff --git a/arch/arm/dts/sun8i-t113s-mangopi-mqdual-t113.dts b/arch/arm/dts/sun8i-t113s-mangopi-mqdual-t113.dts
+new file mode 100644
+index 0000000000..7de3ddb92f
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s-mangopi-mqdual-t113.dts
+@@ -0,0 +1,50 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/dts-v1/;
++
++#include "sun8i-t113s.dtsi"
++#include "sunxi-d1s-t113-mangopi-mq-r.dtsi"
++
++/ {
++      model = "MangoPi MQDual T113";
++      compatible = "widora,mangopi-mqdual-t113", "allwinner,sun8i-t113s";
++
++      aliases {
++              serial0 = &uart0;
++              ethernet0 = &rtl8189ftv;
++      };
++
++      chosen {
++              stdout-path = "serial0:115200n8";
++      };
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&cpu1 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&mmc1 {
++      rtl8189ftv: wifi@1 {
++              reg = <1>;
++              interrupt-parent = <&pio>;
++              interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>; /* PG10 = WL_WAKE_AP */
++              interrupt-names = "host-wake";
++      };
++};
++
++&uart0 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart0_pins>;
++      status = "okay";
++};
++
++&uart3 {
++      status = "disabled";
++};
+diff --git a/configs/mangopi_mqdual_t113_defconfig b/configs/mangopi_mqdual_t113_defconfig
+new file mode 100644
+index 0000000000..98b90c55f4
+--- /dev/null
++++ b/configs/mangopi_mqdual_t113_defconfig
+@@ -0,0 +1,17 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-mangopi-mqdual-t113"
++CONFIG_SUNXI_MINIMUM_DRAM_MB=128
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_R528=y
++CONFIG_CONS_INDEX=1
++CONFIG_MMC0_CD_PIN="PF6"
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_SYS_MONITOR_LEN=786432
++CONFIG_DRAM_CLK=792
++CONFIG_DRAM_ZQ=8092667
++CONFIG_DRAM_SUNXI_ODT_EN=0
++CONFIG_DRAM_SUNXI_TPR0=0x004a2195
++CONFIG_DRAM_SUNXI_TPR11=0x340000
++CONFIG_DRAM_SUNXI_TPR12=0x46
++CONFIG_DRAM_SUNXI_TPR13=0x34000100
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4041-sunxi-add-support-for-UART5-in-Port-E-group-on-T133.patch b/package/boot/uboot-sunxi/patches/4041-sunxi-add-support-for-UART5-in-Port-E-group-on-T133.patch
new file mode 100644 (file)
index 0000000..1b5ceed
--- /dev/null
@@ -0,0 +1,70 @@
+From 5e15e7c630e4710cf60432373ff0fe838ed58d79 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 3 Jun 2023 23:41:31 +0200
+Subject: [PATCH 4041/4052] sunxi: add support for UART5 in Port E group on
+ T133
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/include/asm/arch-sunxi/serial.h | 1 +
+ arch/arm/mach-sunxi/board.c              | 4 ++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c    | 1 +
+ include/configs/sunxi-common.h           | 3 +++
+ 4 files changed, 9 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/serial.h b/arch/arm/include/asm/arch-sunxi/serial.h
+index 9386287b65..48d0f42a3b 100644
+--- a/arch/arm/include/asm/arch-sunxi/serial.h
++++ b/arch/arm/include/asm/arch-sunxi/serial.h
+@@ -20,6 +20,7 @@
+ #elif defined(CONFIG_SUNXI_GEN_NCAT2)
+ #define SUNXI_UART0_BASE              0x02500000
+ #define SUNXI_R_UART_BASE             0               // 0x07080000 (?>
++#define SUNXI_UART5_BASE              (SUNXI_UART0_BASE + 0x1400)
+ #else
+ #define SUNXI_UART0_BASE              0x01c28000
+ #define SUNXI_R_UART_BASE             0x01f02800
+diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index 8980ffb509..50693d216b 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -175,6 +175,10 @@ static int gpio_init(void)
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART);
+       sunxi_gpio_set_pull(SUNXI_GPL(3), SUNXI_GPIO_PULL_UP);
++#elif CONFIG_CONS_INDEX == 6 && defined(CONFIG_MACH_SUN8I_R528)
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(6), 9);
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(7), 9);
++      sunxi_gpio_set_pull(SUNXI_GPE(7), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN8I) && \
+                               !defined(CONFIG_MACH_SUN8I_R40)
+       sunxi_gpio_set_cfgpin(SUNXI_GPG(6), SUN8I_GPG_UART1);
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index 614cfe6b73..2717d79bc3 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -748,6 +748,7 @@ static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
+       { "uart0",      6 },    /* PB2-PB3 */
+ #endif
+       { "uart3",      7 },    /* PB6-PB9 */
++      { "uart5",      3 },    /* PE6-PE7 */
+ };
+ static const struct sunxi_pinctrl_desc __maybe_unused sun20i_d1_pinctrl_desc = {
+diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
+index 67eb0d25db..e6efc4fad8 100644
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -29,6 +29,9 @@
+ # define CFG_SYS_NS16550_COM3         SUNXI_UART2_BASE
+ # define CFG_SYS_NS16550_COM4         SUNXI_UART3_BASE
+ # define CFG_SYS_NS16550_COM5         SUNXI_R_UART_BASE
++#if defined(CONFIG_SUNXI_GEN_NCAT2)
++# define CFG_SYS_NS16550_COM6         SUNXI_UART5_BASE
++#endif
+ #endif
+ /* CPU */
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4042-sunxi-add-MYIR-MYD-YT113X-board.patch b/package/boot/uboot-sunxi/patches/4042-sunxi-add-MYIR-MYD-YT113X-board.patch
new file mode 100644 (file)
index 0000000..4969c82
--- /dev/null
@@ -0,0 +1,131 @@
+From 316c22da82fd1d66f8c081a5cba039ebde7af433 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sun, 4 Jun 2023 00:13:45 +0200
+Subject: [PATCH 4042/4052] sunxi: add MYIR MYD-YT113X board
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/Makefile                        |  3 +-
+ arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dts | 68 ++++++++++++++++++++
+ configs/myir_myd_t113x_defconfig             | 20 ++++++
+ 3 files changed, 90 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dts
+ create mode 100644 configs/myir_myd_t113x_defconfig
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index 4207f17601..6fb49de59a 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -712,7 +712,8 @@ dtb-$(CONFIG_MACH_SUN8I_V3S) += \
+       sun8i-v3s-licheepi-zero.dtb
+ dtb-$(CONFIG_MACH_SUN8I_R528) += \
+       sun8i-t113s-mangopi-mq-r-t113.dtb \
+-      sun8i-t113s-mangopi-mqdual-t113.dtb
++      sun8i-t113s-mangopi-mqdual-t113.dtb \
++      sun8i-t113s-myir-myd-yt113x.dtb
+ dtb-$(CONFIG_MACH_SUN50I_H5) += \
+       sun50i-h5-bananapi-m2-plus.dtb \
+       sun50i-h5-emlid-neutis-n5-devboard.dtb \
+diff --git a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dts b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dts
+new file mode 100644
+index 0000000000..afd0d8f532
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x.dts
+@@ -0,0 +1,68 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/dts-v1/;
++
++#include "sun8i-t113s.dtsi"
++#include "sunxi-d1s-t113-mangopi-mq-r.dtsi"
++
++/ {
++      model = "MYIR MYD-YT113X";
++      compatible = "myir,myd-yt113x", "myir,myc-yt113x", "allwinner,sun8i-t113s";
++
++      aliases {
++              serial5 = &uart5;
++      };
++
++      chosen {
++              stdout-path = "serial5:115200n8";
++      };
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&cpu1 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&mmc2_pins {
++      bias-pull-up;
++      drive-strength = <40>;
++};
++
++&mmc2 {
++      pinctrl-0 = <&mmc2_pins>;
++      pinctrl-names = "default";
++      vmmc-supply = <&reg_3v3>;
++      non-removable;
++      bus-width = <4>;
++      status = "okay";
++
++      emmc: emmc@0 {
++              reg = <0>;
++              compatible = "mmc-card";
++              broken-hpi;
++      };
++};
++
++&pio {
++      /omit-if-no-ref/
++      uart5_pins: uart5-pins {
++              pins = "PE6", "PE7";
++              function = "uart5";
++      };
++};
++
++&uart5 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart5_pins>;
++      status = "okay";
++};
++
++&uart3 {
++      status = "disabled";
++};
+diff --git a/configs/myir_myd_t113x_defconfig b/configs/myir_myd_t113x_defconfig
+new file mode 100644
+index 0000000000..2ae442c3ca
+--- /dev/null
++++ b/configs/myir_myd_t113x_defconfig
+@@ -0,0 +1,20 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-myir-myd-yt113x"
++CONFIG_SUNXI_MINIMUM_DRAM_MB=128
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_R528=y
++CONFIG_CONS_INDEX=6
++CONFIG_MMC0_CD_PIN="PF6"
++CONFIG_MMC_SUNXI_SLOT_EXTRA=2
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_SYS_MONITOR_LEN=786432
++CONFIG_DRAM_CLK=792
++CONFIG_DRAM_ZQ=8092667
++CONFIG_DRAM_SUNXI_ODT_EN=0
++CONFIG_DRAM_SUNXI_TPR0=0x004a2195
++CONFIG_DRAM_SUNXI_TPR11=0x340000
++CONFIG_DRAM_SUNXI_TPR12=0x46
++CONFIG_DRAM_SUNXI_TPR13=0x34000100
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_OHCI_HCD=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4043-sunxi-add-support-for-UART3-on-PE-pins.patch b/package/boot/uboot-sunxi/patches/4043-sunxi-add-support-for-UART3-on-PE-pins.patch
new file mode 100644 (file)
index 0000000..c7345d2
--- /dev/null
@@ -0,0 +1,100 @@
+From f3cfc41de396835ca4dbccbc54294c608ed9ff6f Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 3 Jun 2023 23:57:46 +0200
+Subject: [PATCH 4043/4052] sunxi: add support for UART3 on PE pins
+
+Some boards use Port E pins for muxing the UART3 as console. Add a new
+Kconfig option allowing to select this (mimicking MMC_PINS_PH).
+
+Pinmux taken from https://bbs.aw-ol.com/assets/uploads/files/1648883311844-t113-s3_datasheet_v1.2.pdf
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/mach-sunxi/Kconfig           |  6 ++++++
+ arch/arm/mach-sunxi/board.c           | 10 ++++++++--
+ arch/riscv/dts/sunxi-d1s-t113.dtsi    |  6 ++++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c |  4 ++++
+ 4 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 7233ecbc1c..6f5e438713 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -666,6 +666,12 @@ config UART0_PORT_F
+       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 UART3_PINS_PE
++      bool "Pins for uart3 are on Port E"
++      ---help---
++      Select this option for boards where uart3 uses the Port E pinmux.
++      (Some T113-S3 boards use uart3 as console.)
++
+ config OLD_SUNXI_KERNEL_COMPAT
+       bool "Enable workarounds for booting old kernels"
+       ---help---
+diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index 50693d216b..85dbad0552 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -168,16 +168,22 @@ static int gpio_init(void)
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
+       sunxi_gpio_set_pull(SUNXI_GPB(1), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 4 && defined(CONFIG_MACH_SUN8I_R528)
++#if defined(CONFIG_UART3_PINS_PE)
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(8), 5);
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(9), 5);
++      sunxi_gpio_set_pull(SUNXI_GPE(9), SUNXI_GPIO_PULL_UP);
++#else
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(6), 7);
+       sunxi_gpio_set_cfgpin(SUNXI_GPB(7), 7);
+       sunxi_gpio_set_pull(SUNXI_GPB(7), SUNXI_GPIO_PULL_UP);
++#endif
+ #elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I)
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART);
+       sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART);
+       sunxi_gpio_set_pull(SUNXI_GPL(3), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 6 && defined(CONFIG_MACH_SUN8I_R528)
+-      sunxi_gpio_set_cfgpin(SUNXI_GPE(6), 9);
+-      sunxi_gpio_set_cfgpin(SUNXI_GPE(7), 9);
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(6), 3);
++      sunxi_gpio_set_cfgpin(SUNXI_GPE(7), 3);
+       sunxi_gpio_set_pull(SUNXI_GPE(7), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN8I) && \
+                               !defined(CONFIG_MACH_SUN8I_R40)
+diff --git a/arch/riscv/dts/sunxi-d1s-t113.dtsi b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+index 567aa43d70..324353905f 100644
+--- a/arch/riscv/dts/sunxi-d1s-t113.dtsi
++++ b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+@@ -132,6 +132,12 @@
+                               function = "uart3";
+                       };
++                      /omit-if-no-ref/
++                      uart3_pe_pins: uart3-pe-pins {
++                              pins = "PE8", "PE9";
++                              function = "uart3";
++                      };
++
+                       /omit-if-no-ref/
+                       uart0_pins: uart0-pins {
+                               pins = "PE2", "PE3";
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index 2717d79bc3..e466808e4e 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -747,7 +747,11 @@ static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = {
+ #else
+       { "uart0",      6 },    /* PB2-PB3 */
+ #endif
++#if IS_ENABLED(CONFIG_UART3_PINS_E)
++      { "uart3",      5 },    /* PE8-PE9 */
++else
+       { "uart3",      7 },    /* PB6-PB9 */
++#endif
+       { "uart5",      3 },    /* PE6-PE7 */
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4044-sunxi-add-support-for-Rongpin-RP-T113-board.patch b/package/boot/uboot-sunxi/patches/4044-sunxi-add-support-for-Rongpin-RP-T113-board.patch
new file mode 100644 (file)
index 0000000..b48f076
--- /dev/null
@@ -0,0 +1,160 @@
+From 4903155257eae57c25fa61e75630f71bf5823009 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 3 Jun 2023 23:42:33 +0200
+Subject: [PATCH 4044/4052] sunxi: add support for Rongpin RP-T113 board
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/Makefile                        |  3 +-
+ arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts | 99 ++++++++++++++++++++
+ configs/rongpin_rp_t113_defconfig            | 18 ++++
+ 3 files changed, 119 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+ create mode 100644 configs/rongpin_rp_t113_defconfig
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index 6fb49de59a..be89021657 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -713,7 +713,8 @@ dtb-$(CONFIG_MACH_SUN8I_V3S) += \
+ dtb-$(CONFIG_MACH_SUN8I_R528) += \
+       sun8i-t113s-mangopi-mq-r-t113.dtb \
+       sun8i-t113s-mangopi-mqdual-t113.dtb \
+-      sun8i-t113s-myir-myd-yt113x.dtb
++      sun8i-t113s-myir-myd-yt113x.dtb \
++      sun8i-t113s-rongpin-rp-t113.dtb
+ dtb-$(CONFIG_MACH_SUN50I_H5) += \
+       sun50i-h5-bananapi-m2-plus.dtb \
+       sun50i-h5-emlid-neutis-n5-devboard.dtb \
+diff --git a/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+new file mode 100644
+index 0000000000..3f7633210b
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+@@ -0,0 +1,99 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/gpio/gpio.h>
++
++/dts-v1/;
++
++#include "sun8i-t113s.dtsi"
++
++/ {
++      model = "Rongpin RP-T113";
++      compatible = "rongpin,rp-t113", "allwinner,sun8i-t113s";
++
++      aliases {
++              serial3 = &uart3;
++      };
++
++      chosen {
++              stdout-path = "serial3:115200n8";
++      };
++
++      /* board wide 5V supply directly from the USB-C socket */
++      reg_vcc5v: regulator-5v {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-5v";
++              regulator-min-microvolt = <5000000>;
++              regulator-max-microvolt = <5000000>;
++              regulator-always-on;
++      };
++
++      /* SY8008 DC/DC regulator on the board */
++      reg_3v3: regulator-3v3 {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-3v3";
++              regulator-min-microvolt = <3300000>;
++              regulator-max-microvolt = <3300000>;
++              vin-supply = <&reg_vcc5v>;
++      };
++
++      /* SY8008 DC/DC regulator on the board, also supplying VDD-SYS */
++      reg_vcc_core: regulator-core {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-core";
++              regulator-min-microvolt = <880000>;
++              regulator-max-microvolt = <880000>;
++              vin-supply = <&reg_vcc5v>;
++      };
++
++      /* XC6206 LDO on the board */
++      reg_avdd2v8: regulator-avdd {
++              compatible = "regulator-fixed";
++              regulator-name = "avdd2v8";
++              regulator-min-microvolt = <2800000>;
++              regulator-max-microvolt = <2800000>;
++              vin-supply = <&reg_3v3>;
++      };
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&cpu1 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&pio {
++      vcc-pb-supply = <&reg_3v3>;
++      vcc-pd-supply = <&reg_3v3>;
++      vcc-pe-supply = <&reg_avdd2v8>;
++      vcc-pf-supply = <&reg_3v3>;
++      vcc-pg-supply = <&reg_3v3>;
++};
++
++&uart3 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart3_pe_pins>;
++      status = "okay";
++};
++
++&mmc0 {
++      pinctrl-0 = <&mmc0_pins>;
++      pinctrl-names = "default";
++      vmmc-supply = <&reg_3v3>;
++      cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>;
++      disable-wp;
++      bus-width = <4>;
++      status = "okay";
++};
++
++&mmc2 {
++      pinctrl-0 = <&mmc2_pins>;
++      pinctrl-names = "default";
++      vmmc-supply = <&reg_3v3>;
++      non-removable;
++      bus-width = <4>;
++      status = "okay";
++};
+diff --git a/configs/rongpin_rp_t113_defconfig b/configs/rongpin_rp_t113_defconfig
+new file mode 100644
+index 0000000000..9b5a5bcd65
+--- /dev/null
++++ b/configs/rongpin_rp_t113_defconfig
+@@ -0,0 +1,18 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-rongpin-rp-t113"
++CONFIG_SUNXI_MINIMUM_DRAM_MB=128
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_R528=y
++CONFIG_CONS_INDEX=4
++CONFIG_MMC0_CD_PIN="PF6"
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_SYS_MONITOR_LEN=786432
++CONFIG_DRAM_CLK=792
++CONFIG_DRAM_ZQ=8092667
++CONFIG_DRAM_SUNXI_ODT_EN=0
++CONFIG_DRAM_SUNXI_TPR0=0x004a2195
++CONFIG_DRAM_SUNXI_TPR11=0x340000
++CONFIG_DRAM_SUNXI_TPR12=0x46
++CONFIG_DRAM_SUNXI_TPR13=0x34000100
++CONFIG_UART3_PINS_PE=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4045-sunxi-add-MYIR-MYD-YT113X-SPI-board.patch b/package/boot/uboot-sunxi/patches/4045-sunxi-add-MYIR-MYD-YT113X-SPI-board.patch
new file mode 100644 (file)
index 0000000..9afb798
--- /dev/null
@@ -0,0 +1,140 @@
+From b13b4017649837d97c73e855448474a9792ab93d Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 29 Jul 2023 11:23:47 +0200
+Subject: [PATCH 4045/4052] sunxi: add MYIR MYD-YT113X-SPI board
+
+Instead of eMMC, this board sports a 256Mb SPI NAND flash.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/Makefile                         |  1 +
+ .../dts/sun8i-t113s-myir-myd-yt113x-spi.dts   | 59 +++++++++++++++++++
+ configs/myir_myd_t113x-spi_defconfig          | 38 ++++++++++++
+ 3 files changed, 98 insertions(+)
+ create mode 100644 arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+ create mode 100644 configs/myir_myd_t113x-spi_defconfig
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index be89021657..267f7bc07e 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -714,6 +714,7 @@ dtb-$(CONFIG_MACH_SUN8I_R528) += \
+       sun8i-t113s-mangopi-mq-r-t113.dtb \
+       sun8i-t113s-mangopi-mqdual-t113.dtb \
+       sun8i-t113s-myir-myd-yt113x.dtb \
++      sun8i-t113s-myir-myd-yt113x-spi.dtb \
+       sun8i-t113s-rongpin-rp-t113.dtb
+ dtb-$(CONFIG_MACH_SUN50I_H5) += \
+       sun50i-h5-bananapi-m2-plus.dtb \
+diff --git a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+new file mode 100644
+index 0000000000..f72bab29a6
+--- /dev/null
++++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+@@ -0,0 +1,59 @@
++// SPDX-License-Identifier: (GPL-2.0+ or MIT)
++// Copyright (C) 2022 Arm Ltd.
++
++#include <dt-bindings/interrupt-controller/irq.h>
++
++/dts-v1/;
++
++#include "sun8i-t113s.dtsi"
++#include "sunxi-d1s-t113-mangopi-mq-r.dtsi"
++
++/ {
++      model = "MYIR MYD-YT113X (SPI)";
++      compatible = "myir,myd-yt113x", "myir,myc-yt113x", "allwinner,sun8i-t113s";
++
++      aliases {
++              serial5 = &uart5;
++      };
++
++      chosen {
++              stdout-path = "serial5:115200n8";
++      };
++};
++
++&cpu0 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&cpu1 {
++      cpu-supply = <&reg_vcc_core>;
++};
++
++&pio {
++      /omit-if-no-ref/
++      uart5_pins: uart5-pins {
++              pins = "PE6", "PE7";
++              function = "uart5";
++      };
++};
++
++&uart5 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&uart5_pins>;
++      status = "okay";
++};
++
++&uart3 {
++      status = "disabled";
++};
++
++&spi0 {
++      pinctrl-names = "default";
++      pinctrl-0 = <&spi0_pins>;
++      status = "okay";
++      spi_nand@0 {
++              compatible = "spi-nand";
++              reg = <0>;
++              spi-max-frequency = <52000000>;
++      };
++};
+diff --git a/configs/myir_myd_t113x-spi_defconfig b/configs/myir_myd_t113x-spi_defconfig
+new file mode 100644
+index 0000000000..a433fe0449
+--- /dev/null
++++ b/configs/myir_myd_t113x-spi_defconfig
+@@ -0,0 +1,38 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-t113s-myir-myd-yt113x-spi"
++CONFIG_SUNXI_MINIMUM_DRAM_MB=128
++CONFIG_SPL=y
++CONFIG_SPL_SPI_SUNXI=y
++CONFIG_MTD_SPI_NAND=y
++CONFIG_MACH_SUN8I_R528=y
++CONFIG_CONS_INDEX=6
++CONFIG_MMC0_CD_PIN="PF6"
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_SYS_MONITOR_LEN=786432
++CONFIG_DRAM_CLK=792
++CONFIG_DRAM_ZQ=8092667
++CONFIG_DRAM_SUNXI_ODT_EN=0
++CONFIG_DRAM_SUNXI_TPR0=0x004a2195
++CONFIG_DRAM_SUNXI_TPR11=0x340000
++CONFIG_DRAM_SUNXI_TPR12=0x46
++CONFIG_DRAM_SUNXI_TPR13=0x34000100
++CONFIG_CLK_SUN20I_D1=y
++CONFIG_PHY_MOTORCOMM=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_RGMII=y
++CONFIG_RMII=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_SYS_MTDPARTS_RUNTIME=y
++CONFIG_NAND_STM32_FMC2=y
++CONFIG_SYS_NAND_ONFI_DETECTION=y
++CONFIG_MTD_SPI_NAND=y
++CONFIG_DM_SPI_FLASH=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_SPANSION=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_SPI_FLASH_WINBOND=y
++# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
++CONFIG_SPI_FLASH_MTD=y
++CONFIG_SPI=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4046-sunxi-add-support-for-emac-on-PG-pins.patch b/package/boot/uboot-sunxi/patches/4046-sunxi-add-support-for-emac-on-PG-pins.patch
new file mode 100644 (file)
index 0000000..071b499
--- /dev/null
@@ -0,0 +1,34 @@
+From b3a2b860f3f0760ef356d312f01f68a68c05294b Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 29 Jul 2023 11:29:26 +0200
+Subject: [PATCH 4046/4052] sunxi: add support for emac on PG pins
+
+Some boards use Port G pins for muxing EMAC.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/riscv/dts/sunxi-d1s-t113.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/riscv/dts/sunxi-d1s-t113.dtsi b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+index 324353905f..2426c71f25 100644
+--- a/arch/riscv/dts/sunxi-d1s-t113.dtsi
++++ b/arch/riscv/dts/sunxi-d1s-t113.dtsi
+@@ -101,6 +101,14 @@
+                               function = "emac";
+                       };
++                      /omit-if-no-ref/
++                      rgmii_pg_pins: rgmii-pg-pins {
++                              pins = "PG0", "PG1", "PG2", "PG3", "PG4",
++                                     "PG5", "PG6", "PG7", "PG8", "PG9",
++                                     "PG11", "PG12", "PG13", "PG14", "PG15";
++                              function = "emac";
++                      };
++
+                       /omit-if-no-ref/
+                       rmii_pe_pins: rmii-pe-pins {
+                               pins = "PE0", "PE1", "PE2", "PE3", "PE4",
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4047-sunxi-add-ethernet-support-on-MYIR-MYD-YT113X-SPI.patch b/package/boot/uboot-sunxi/patches/4047-sunxi-add-ethernet-support-on-MYIR-MYD-YT113X-SPI.patch
new file mode 100644 (file)
index 0000000..2a3e52c
--- /dev/null
@@ -0,0 +1,62 @@
+From 4a461963583fe845500c9e5227fa47811cab7136 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 29 Jul 2023 11:34:19 +0200
+Subject: [PATCH 4047/4052] sunxi: add ethernet support on MYIR MYD-YT113X-SPI
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../dts/sun8i-t113s-myir-myd-yt113x-spi.dts   | 34 +++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+index f72bab29a6..431d5593d6 100644
+--- a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
++++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+@@ -19,6 +19,23 @@
+       chosen {
+               stdout-path = "serial5:115200n8";
+       };
++
++      reg_vcc5v: regulator-5v {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-5v";
++              regulator-min-microvolt = <5000000>;
++              regulator-max-microvolt = <5000000>;
++              regulator-always-on;
++      };
++
++      /* SY8008 DC/DC regulator on the board */
++      reg_3v3: regulator-3v3 {
++              compatible = "regulator-fixed";
++              regulator-name = "vcc-3v3";
++              regulator-min-microvolt = <3300000>;
++              regulator-max-microvolt = <3300000>;
++              vin-supply = <&reg_vcc5v>;
++      };
+ };
+ &cpu0 {
+@@ -57,3 +74,20 @@
+               spi-max-frequency = <52000000>;
+       };
+ };
++
++&emac {
++      pinctrl-names = "default";
++      pinctrl-0 = <&rgmii_pg_pins>;
++      phy-supply = <&reg_3v3>;
++      phy-handle = <&ext_rgmii_phy>;
++      phy-mode = "rgmii-id";
++
++      status = "okay";
++};
++
++&mdio {
++      ext_rgmii_phy: ethernet-phy@4 {
++              compatible = "ethernet-phy-ieee802.3-c22";
++              reg = <4>;
++      };
++};
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4048-sunxi-enable-emac-on-Rongpin-RP-T113.patch b/package/boot/uboot-sunxi/patches/4048-sunxi-enable-emac-on-Rongpin-RP-T113.patch
new file mode 100644 (file)
index 0000000..6a2a3d9
--- /dev/null
@@ -0,0 +1,93 @@
+From 01d239cb0daaaca75ffc71adecd19a55e755c296 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sun, 4 Jun 2023 15:40:42 +0200
+Subject: [PATCH 4048/4052] sunxi: enable emac on Rongpin RP-T113
+
+The emac is connected to an IC+ IP101 PHY, for which the driver
+has been re-added (it was removed in 2014).
+
+Currently the driver init fails with the below, so further tweaking
+will be required.
+
+CPU:   Allwinner R528 (SUN8I)
+Model: Rongpin RP-T113
+DRAM:  128 MiB
+Core:  36 devices, 15 uclasses, devicetree: separate
+MMC:   mmc@4020000: 0, mmc@4022000: 1
+Loading Environment from FAT... Unable to read "uboot.env" from mmc0:1...
+In:    serial@2500c00
+Out:   serial@2500c00
+Err:   serial@2500c00
+Net:   eth_sun8i_emac ethernet@4500000: failed to get TX clock
+No ethernet found.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts | 28 ++++++++++++++++++++
+ configs/rongpin_rp_t113_defconfig            |  3 +++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+index 3f7633210b..348ae5eec6 100644
+--- a/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
++++ b/arch/arm/dts/sun8i-t113s-rongpin-rp-t113.dts
+@@ -55,6 +55,16 @@
+               regulator-max-microvolt = <2800000>;
+               vin-supply = <&reg_3v3>;
+       };
++
++        reg_gmac_3v3: gmac-3v3 {
++                compatible = "regulator-fixed";
++                regulator-name = "gmac-3v3";
++                regulator-min-microvolt = <3300000>;
++                regulator-max-microvolt = <3300000>;
++                startup-delay-us = <100000>;
++                enable-active-high;
++                gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
++      };
+ };
+ &cpu0 {
+@@ -79,6 +89,17 @@
+       status = "okay";
+ };
++&emac {
++      pinctrl-names = "default";
++      pinctrl-0 = <&rmii_pe_pins>;
++
++      phy-supply = <&reg_3v3>;
++      phy-handle = <&ext_rgmii_phy>;
++      phy-mode = "rmii";
++
++      status = "okay";
++};
++
+ &mmc0 {
+       pinctrl-0 = <&mmc0_pins>;
+       pinctrl-names = "default";
+@@ -97,3 +118,10 @@
+       bus-width = <4>;
+       status = "okay";
+ };
++
++&mdio {
++      ext_rgmii_phy: ethernet-phy@1 {
++              compatible = "ethernet-phy-ieee802.3-c22";
++              reg = <1>;
++      };
++};
+diff --git a/configs/rongpin_rp_t113_defconfig b/configs/rongpin_rp_t113_defconfig
+index 9b5a5bcd65..e234934f50 100644
+--- a/configs/rongpin_rp_t113_defconfig
++++ b/configs/rongpin_rp_t113_defconfig
+@@ -16,3 +16,6 @@ CONFIG_DRAM_SUNXI_TPR11=0x340000
+ CONFIG_DRAM_SUNXI_TPR12=0x46
+ CONFIG_DRAM_SUNXI_TPR13=0x34000100
+ CONFIG_UART3_PINS_PE=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_PHY_ICPLUS=y
++CONFIG_RMII=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4049-sunxi-enable-gmac-on-MYIR-MYD-YT113X-with-the-YT8531.patch b/package/boot/uboot-sunxi/patches/4049-sunxi-enable-gmac-on-MYIR-MYD-YT113X-with-the-YT8531.patch
new file mode 100644 (file)
index 0000000..024e5db
--- /dev/null
@@ -0,0 +1,36 @@
+From fac8490193f271477ee4a9a3d749862461e7051c Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Mon, 5 Jun 2023 17:57:15 +0200
+Subject: [PATCH 4049/4052] sunxi: enable gmac on MYIR MYD-YT113X with the
+ YT8531 PHY
+
+The gmac is connected to a Motorcomm YT8531, for which the driver
+has been picked from Starfive and ported over.
+
+Support is not yet added in DTS, only for compile testing.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ configs/myir_myd_t113x_defconfig | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/configs/myir_myd_t113x_defconfig b/configs/myir_myd_t113x_defconfig
+index 2ae442c3ca..8bffcb7acd 100644
+--- a/configs/myir_myd_t113x_defconfig
++++ b/configs/myir_myd_t113x_defconfig
+@@ -18,3 +18,12 @@ CONFIG_DRAM_SUNXI_TPR12=0x46
+ CONFIG_DRAM_SUNXI_TPR13=0x34000100
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_OHCI_HCD=y
++CONFIG_PHY_MOTORCOMM=y
++CONFIG_SUN8I_EMAC=y
++CONFIG_RGMII=y
++CONFIG_RMII=y
++CONFIG_SUPPORT_EMMC_BOOT=y
++CONFIG_MMC_IO_VOLTAGE=y
++CONFIG_SPL_MMC_IO_VOLTAGE=y
++CONFIG_MMC_HS200_SUPPORT=y
++CONFIG_SPL_MMC_HS200_SUPPORT=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4050-arm-dts-add-partition-table-for-MYIR-MYD-YT113X-SPI.patch b/package/boot/uboot-sunxi/patches/4050-arm-dts-add-partition-table-for-MYIR-MYD-YT113X-SPI.patch
new file mode 100644 (file)
index 0000000..d0983ee
--- /dev/null
@@ -0,0 +1,60 @@
+From 2fac27b1c5de843377d9413425a079a6ce3a13e3 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 26 Aug 2023 17:45:03 +0200
+Subject: [PATCH 4050/4052] arm: dts: add partition table for MYIR
+ MYD-YT113X-SPI
+
+The original bootloader reports the following as the partition table:
+
+device nand0 <nand>, # parts = 4
+ #: name                size            offset          mask_flags
+ 0: boot0               0x00100000      0x00000000      1
+ 1: uboot               0x00300000      0x00100000      1
+ 2: secure_storage      0x00100000      0x00400000      1
+ 3: sys                 0x0fb00000      0x00500000      0
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ .../dts/sun8i-t113s-myir-myd-yt113x-spi.dts   | 26 +++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+index 431d5593d6..a5fd8c6bea 100644
+--- a/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
++++ b/arch/arm/dts/sun8i-t113s-myir-myd-yt113x-spi.dts
+@@ -72,6 +72,32 @@
+               compatible = "spi-nand";
+               reg = <0>;
+               spi-max-frequency = <52000000>;
++
++              partitions {
++                      compatible = "fixed-partitions";
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++
++                      partition@0 {
++                              label = "boot0";
++                              reg = <0x0 0x100000>;
++                      };
++
++                      partition@100000 {
++                              label = "uboot";
++                              reg = <0x0 0x300000>;
++                      };
++
++                      partition@400000 {
++                              label = "secure_storage";
++                              reg = <0x0 0x400000>;
++                      };
++
++                      partition@500000 {
++                              label = "sys";
++                              reg = <0x0 0xfb00000>;
++                      };
++              };
+       };
+ };
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4051-configs-enable-UBI-support-for-MYIR-MYD-YT113X-SPI.patch b/package/boot/uboot-sunxi/patches/4051-configs-enable-UBI-support-for-MYIR-MYD-YT113X-SPI.patch
new file mode 100644 (file)
index 0000000..bfed20b
--- /dev/null
@@ -0,0 +1,22 @@
+From 4e383529bbbb24d359afa9c06864c890f466b212 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 26 Aug 2023 17:46:22 +0200
+Subject: [PATCH 4051/4052] configs: enable UBI support for MYIR MYD-YT113X-SPI
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ configs/myir_myd_t113x-spi_defconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/configs/myir_myd_t113x-spi_defconfig b/configs/myir_myd_t113x-spi_defconfig
+index a433fe0449..a1c2a82c87 100644
+--- a/configs/myir_myd_t113x-spi_defconfig
++++ b/configs/myir_myd_t113x-spi_defconfig
+@@ -36,3 +36,4 @@ CONFIG_SPI_FLASH_WINBOND=y
+ # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
+ CONFIG_SPI_FLASH_MTD=y
+ CONFIG_SPI=y
++CONFIG_MTD_UBI_FASTMAP=y
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/patches/4052-sunxi-r528-d1-t113-add-SDC2-pinmux-on-PC2-7-pins.patch b/package/boot/uboot-sunxi/patches/4052-sunxi-r528-d1-t113-add-SDC2-pinmux-on-PC2-7-pins.patch
new file mode 100644 (file)
index 0000000..e0e7a5e
--- /dev/null
@@ -0,0 +1,31 @@
+From ac986d0e4da7ccdf48c7d2369531c8bd0bd1b57d Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Sat, 26 Aug 2023 21:09:17 +0200
+Subject: [PATCH 4052/4052] sunxi: r528/d1/t113: add SDC2 pinmux on PC2-7 pins
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ board/sunxi/board.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/board/sunxi/board.c b/board/sunxi/board.c
+index 661137f43c..c00629f9b5 100644
+--- a/board/sunxi/board.c
++++ b/board/sunxi/board.c
+@@ -424,6 +424,13 @@ static void mmc_pinmux_setup(int sdc)
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_SDC2);
+               sunxi_gpio_set_pull(SUNXI_GPC(24), SUNXI_GPIO_PULL_UP);
+               sunxi_gpio_set_drv(SUNXI_GPC(24), 2);
++#elif defined(CONFIG_MACH_SUN8I_R528)
++              /* SDC2: PC2-PC7 */
++              for (pin = SUNXI_GPC(2); pin <= SUNXI_GPC(7); pin++) {
++                      sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SDC2);
++                      sunxi_gpio_set_pull(pin, SUNXI_GPIO_PULL_UP);
++                      sunxi_gpio_set_drv(pin, 2);
++              }
+ #elif defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I)
+               /* SDC2: PC5-PC6, PC8-PC16 */
+               for (pin = SUNXI_GPC(5); pin <= SUNXI_GPC(6); pin++) {
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-sunxi/uEnv-t113.ttyS3.txt b/package/boot/uboot-sunxi/uEnv-t113.ttyS3.txt
new file mode 100644 (file)
index 0000000..2f5fee7
--- /dev/null
@@ -0,0 +1,8 @@
+setenv fdt_high ffffffff
+setenv mmc_rootpart 2
+part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
+setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
+setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
+setenv bootargs console=ttyS3,115200 earlyprintk root=PARTUUID=${uuid} rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-sunxi/uEnv-t113.ttyS5.txt b/package/boot/uboot-sunxi/uEnv-t113.ttyS5.txt
new file mode 100644 (file)
index 0000000..353429b
--- /dev/null
@@ -0,0 +1,8 @@
+setenv fdt_high ffffffff
+setenv mmc_rootpart 2
+part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
+setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
+setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
+setenv bootargs console=ttyS5,115200 earlyprintk root=PARTUUID=${uuid} rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd