soc/sifive/fu540: Support booting from SD card

Change-Id: I18948d31c0bf0bf9d641480a35fc710b9ee8ae84
Signed-off-by: Xiang Wang <merle@hardenedlinux.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/35119
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/src/mainboard/sifive/hifive-unleashed/Kconfig b/src/mainboard/sifive/hifive-unleashed/Kconfig
index 2453178..fc9bc1e 100644
--- a/src/mainboard/sifive/hifive-unleashed/Kconfig
+++ b/src/mainboard/sifive/hifive-unleashed/Kconfig
@@ -19,6 +19,7 @@
 	select BOARD_ROMSIZE_KB_32768
 	select MISSING_BOARD_RESET
 	select FLATTENED_DEVICE_TREE
+	select SPI_SDCARD
 
 config HEAP_SIZE
 	default 0x10000
diff --git a/src/mainboard/sifive/hifive-unleashed/media.c b/src/mainboard/sifive/hifive-unleashed/media.c
index b0198a7..45d1f1a 100644
--- a/src/mainboard/sifive/hifive-unleashed/media.c
+++ b/src/mainboard/sifive/hifive-unleashed/media.c
@@ -15,15 +15,60 @@
  */
 
 #include <boot_device.h>
+#include <symbols.h>
+#include <cbfs.h>
+#include <arch/mmio.h>
+#include <soc/addressmap.h>
 #include <soc/spi.h>
+#include <soc/clock.h>
+#include <console/console.h>
+#include <spi_sdcard.h>
+
+/* follow is the FSBL boot device defined by ZSBL of sifive
+ * FSBL replaced by bootblock of coreboot
+ * MSEL_SPInx1 -> test if boot from memory-mapped on SPIn
+ * MSEL_SPInx4 -> test if boot from memory-mapped on QPIn
+ * MSEL_SPInSD -> test if boot from sdcard mount on SPIn */
+#define MSEL_SPI0x1(m)	(((m) == 5) || ((m) == 14))
+#define MSEL_SPI0x4(m)	(((m) == 6) || ((m) == 10) || ((m) == 15))
+#define MSEL_SPI1x1(m)	((m) == 12)
+#define MSEL_SPI1x4(m)	(((m) == 7) || ((m) == 13))
+#define MSEL_SPI1SD(m)	((m) ==  8)
+#define MSEL_SPI2x1(m)	((m) ==  9)
+#define MSEL_SPI2SD(m)	((m) == 11)
+
+static struct spi_sdcard card;
 
 /* At 0x20000000: A 256MiB long memory-mapped view of the flash at QSPI0 */
-static struct mem_region_device mdev =
+static struct mem_region_device spi_mdev =
 	MEM_REGION_DEV_RO_INIT((void *)0x20000000, CONFIG_ROM_SIZE);
 
+static ssize_t unleashed_sd_readat(const struct region_device *rdev, void *dest,
+					size_t offset, size_t count)
+{
+	spi_sdcard_read(&card, dest, offset, count);
+	return count;
+}
+
+static const struct region_device_ops unleashed_sd_ops = {
+	.mmap   = mmap_helper_rdev_mmap,
+	.munmap = mmap_helper_rdev_munmap,
+	.readat = unleashed_sd_readat,
+};
+
+
+static struct mmap_helper_region_device sd_mdev =
+	MMAP_HELPER_REGION_INIT(&unleashed_sd_ops, 0, CONFIG_ROM_SIZE);
+
 const struct region_device *boot_device_ro(void)
 {
-	return &mdev.rdev;
+	uint32_t m = read32((uint32_t *)FU540_MSEL);
+	if (MSEL_SPI0x1(m) || MSEL_SPI0x4(m))
+		return &spi_mdev.rdev;
+	if (MSEL_SPI2SD(m))
+		return &sd_mdev.rdev;
+	die("Wrong configuration of MSEL\n");
+	return NULL;
 }
 
 const static struct fu540_spi_mmap_config spi_mmap_config = {
@@ -39,11 +84,20 @@
 
 void boot_device_init(void)
 {
-	struct spi_slave slave;
-
-	/* initialize spi controller */
-	spi_setup_slave(0, 0, &slave);
-
-	/* map flash to memory space */
-	fu540_spi_mmap(&slave, &spi_mmap_config);
+	uint32_t m = read32((uint32_t *)FU540_MSEL);
+	if (MSEL_SPI0x1(m) || MSEL_SPI0x4(m)) {
+		struct spi_slave slave;
+		/* initialize spi controller */
+		spi_setup_slave(0, 0, &slave);
+		/* map flash to memory space */
+		fu540_spi_mmap(&slave, &spi_mmap_config);
+		return;
+	}
+	if (MSEL_SPI2SD(m)) {
+		spi_sdcard_init(&card, 2, 0);
+		mmap_helper_device_init(&sd_mdev,
+			_cbfs_cache, REGION_SIZE(cbfs_cache));
+		return;
+	}
+	die("Wrong configuration of MSEL\n");
 }
diff --git a/src/soc/sifive/fu540/include/soc/memlayout.ld b/src/soc/sifive/fu540/include/soc/memlayout.ld
index 1d11aa0..df30ede 100644
--- a/src/soc/sifive/fu540/include/soc/memlayout.ld
+++ b/src/soc/sifive/fu540/include/soc/memlayout.ld
@@ -28,10 +28,12 @@
 	CAR_STACK(FU540_L2LIM + 64K, 20K)
 	PRERAM_CBMEM_CONSOLE(FU540_L2LIM + 84K, 8K)
 	ROMSTAGE(FU540_L2LIM + 128K, 128K)
+	PRERAM_CBFS_CACHE(FU540_L2LIM + 256K, 128K)
 	L2LIM_END(FU540_L2LIM + 2M)
 
 	DRAM_START(FU540_DRAM)
 	REGION(opensbi, FU540_DRAM, 128K, 4K)
 	RAMSTAGE(FU540_DRAM + 128K, 256K)
 	MEM_STACK(FU540_DRAM + 448K, 20K)
+	POSTRAM_CBFS_CACHE(FU540_DRAM + 512K, 32M - 512K)
 }