[PATCH 7/7] sunxi: H6: Enable SPI0 in DT when no eMMC is used

Andre Przywara
2022-01-11T12:47:28Z

On the Allwinner H6 SoC both the SPI0 and the eMMC device share one pin,
so cannot be used simultaneously. On Linux this is a showstopper, since
only one of them would be able to claim the pin, and the probe order is
somewhat random. The DT consequently disables SPI0 in favour of the more
useful eMMC.

But a comment in the DT actually suggests that this could be reversed by
U-Boot, if no eMMC is actually connected. Let's now implement this:
When we fix up the device tree before booting a kernel, we iterate over
all MMC devices, and check if there is an eMMC device among them. If none
can be found, we enable SPI0 instead, to allow Linux access to the SPI
flash.
Since this fixup is not really universally applicable to all boards,
let's hide it behind a Kconfig option, and enable it only on the one
supported board where this makes sense: the Pine H64.

Please note that the SPI functionality is still disabled in U-Boot
proper, the pinmux clash affects us too: it would always disable the eMMC
and so spoil this algorithm here.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm/mach-sunxi/Kconfig | 10 ++++++++
board/sunxi/board.c | 50 +++++++++++++++++++++++++++++++++++++
configs/pine_h64_defconfig | 1 +
3 files changed, 61 insertions(+)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 56ff1e197c..ce66453029 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1047,6 +1047,16 @@ config BLUETOOTH_DT_DEVICE_FIXUP
The used address is "bdaddr" if set, and "ethaddr" with the LSB
flipped elsewise.

+config SUNXI_H6_ENABLE_SPIFLASH
+ bool "Enable H6 SPI flash vs. eMMC enablement"
+ depends on MACH_SUN50I_H6
+ default n
+ help
+ Enable this option if you want U-Boot check for an eMMC device
+ on Allwinner H6 boards, and enable the SPI flash if none is found.
+ SPI0 and MMC2 share one pin, so cannot coexist in Linux. The
+ DT prefers eMMC, but if none is used, we can safely enable SPI.
+
endif

config CHIP_DIP_SCAN
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 2472343d00..e943a16e16 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -942,6 +942,32 @@ static void bluetooth_dt_fixup(void *blob)
"local-bd-address", bdaddr, ETH_ALEN, 1);
}

+/* Iterate over all MMC devices to check if there is an eMMC among them. */
+static bool has_emmc_device(void)
+{
+ struct udevice *dev;
+
+ if (CONFIG_MMC_SUNXI_SLOT_EXTRA == -1)
+ return false;
+
+ for (uclass_first_device(UCLASS_MMC, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+ mmc_init(mmc);
+ if (!mmc->has_init)
+ continue;
+
+ if (IS_SD(mmc))
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
int ft_board_setup(void *blob, struct bd_info *bd)
{
int __maybe_unused r;
@@ -959,6 +985,30 @@ int ft_board_setup(void *blob, struct bd_info *bd)
if (r)
return r;
#endif
+
+ /*
+ * On the H6 SPI0 and MMC2 share one pin, so cannot be used together
+ * (in Linux). The DT thus disables SPI0 in favour of the more
+ * useful eMMC. However if there is no eMMC connected, we can enable
+ * SPI0, to allows access to a SPI flash, for instance.
+ */
+ if (IS_ENABLED(CONFIG_SUNXI_H6_ENABLE_SPIFLASH)) {
+ const char *spi_status, *emmc_status;
+
+ if (has_emmc_device()) {
+ emmc_status = "okay";
+ spi_status = "disabled";
+ } else {
+ emmc_status = "disabled";
+ spi_status = "okay";
+ }
+
+ do_fixup_by_path(blob, "/soc/spi@5010000", "status",
+ spi_status, strlen(spi_status), 0);
+ do_fixup_by_path(blob, "/soc/mmc@4022000", "status",
+ emmc_status, strlen(emmc_status), 0);
+ }
+
return 0;
}

diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig
index 1e730dd9fa..9220af1429 100644
--- a/configs/pine_h64_defconfig
+++ b/configs/pine_h64_defconfig
@@ -9,6 +9,7 @@ CONFIG_MMC0_CD_PIN="PF6"
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_USB3_VBUS_PIN="PL5"
CONFIG_SPL_SPI_SUNXI=y
+CONFIG_SUNXI_H6_ENABLE_SPIFLASH=y
# CONFIG_PSCI_RESET is not set
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPI_FLASH_WINBOND=y
--
2.25.1