summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-03-28 11:03:00 +0200
committerSimon Glass <sjg@chromium.org>2017-04-04 20:01:57 -0600
commitd02d11f8ae233316cb99ecb5a732f115c521f51b (patch)
tree83e3ed5c0ea4c65b7c9699cc13d8f3798571c9cd /arch
parent47197682ef8288a610ad22eeac9ec92689a9648d (diff)
rockchip: rk3399: spl: make SPL boot-order configurable via /chosen
The RK3399 does not have any boot selection pins and the BootROM probes the boot interfaces using the following boot-order: 1. SPI 2. eMMC (sdhci in DTS) 3. SD card (sdmmc in DTS) 4. USB loader For ease of deployment, the SPL stage should mirror the boot order of the ROM and use the same probing order (assuming that valid images can be detected by SPL) unless instructed otherwise. The boot-order can then be configured via the 'u-boot,spl-boot-order' property in the chosen-node of the DTS. While this approach is easily extensible to other boards, it is only implemented for the RK3399 for now, as the large SRAM on the RK3399 makes this easy to fit the needed infrastructure into SPL and our production setup already runs with DM, OF_CONTROL and BLK in SPL. The new boot-order property is expected to be used in conjunction with FIT images (and all legacy image formats disabled via Kconfig). A boot-sequence with probing and fallthroughs from SPI via eMMC to SD card (i.e. &spiflash, &sdhci, &sdmmc) has been validated on the RK3399-Q7. Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> Tested-by: Klaus Goger <klaus.goger@theobroma-systems.com> Tested-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> Acked-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-rockchip/rk3399-board-spl.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/arch/arm/mach-rockchip/rk3399-board-spl.c b/arch/arm/mach-rockchip/rk3399-board-spl.c
index 08aa0cb1ca..4f84ec10a5 100644
--- a/arch/arm/mach-rockchip/rk3399-board-spl.c
+++ b/arch/arm/mach-rockchip/rk3399-board-spl.c
@@ -10,6 +10,7 @@
#include <fdtdec.h>
#include <led.h>
#include <malloc.h>
+#include <mmc.h>
#include <ram.h>
#include <spl.h>
#include <asm/gpio.h>
@@ -27,6 +28,104 @@
DECLARE_GLOBAL_DATA_PTR;
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_OF_CONTROL)
+static int spl_node_to_boot_device(int node)
+{
+ struct udevice *parent;
+
+ /*
+ * This should eventually move into the SPL code, once SPL becomes
+ * aware of the block-device layer. Until then (and to avoid unneeded
+ * delays in getting this feature out, it lives at the board-level).
+ */
+ if (!uclass_get_device_by_of_offset(UCLASS_MMC, node, &parent)) {
+ struct udevice *dev;
+ struct blk_desc *desc = NULL;
+
+ for (device_find_first_child(parent, &dev);
+ dev;
+ device_find_next_child(&dev)) {
+ if (device_get_uclass_id(dev) == UCLASS_BLK) {
+ desc = dev_get_uclass_platdata(dev);
+ break;
+ }
+ }
+
+ if (!desc)
+ return -ENOENT;
+
+ switch (desc->devnum) {
+ case 0:
+ return BOOT_DEVICE_MMC1;
+ case 1:
+ return BOOT_DEVICE_MMC2;
+ default:
+ return -ENOSYS;
+ }
+ }
+
+ /*
+ * SPL doesn't differentiate SPI flashes, so we keep the detection
+ * brief and inaccurate... hopefully, the common SPL layer can be
+ * extended with awareness of the BLK layer (and matching OF_CONTROL)
+ * soon.
+ */
+ if (!uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, &parent))
+ return BOOT_DEVICE_SPI;
+
+ return -1;
+}
+
+void board_boot_order(u32 *spl_boot_list)
+{
+ const void *blob = gd->fdt_blob;
+ int chosen_node = fdt_path_offset(blob, "/chosen");
+ int idx = 0;
+ int elem;
+ int boot_device;
+ int node;
+ const char *conf;
+
+ if (chosen_node < 0) {
+ debug("%s: /chosen not found, using spl_boot_device()\n",
+ __func__);
+ spl_boot_list[0] = spl_boot_device();
+ return;
+ }
+
+ for (elem = 0;
+ (conf = fdt_stringlist_get(blob, chosen_node,
+ "u-boot,spl-boot-order", elem, NULL));
+ elem++) {
+ /* First check if the list element is an alias */
+ const char *alias = fdt_get_alias(blob, conf);
+ if (alias)
+ conf = alias;
+
+ /* Try to resolve the config item (or alias) as a path */
+ node = fdt_path_offset(blob, conf);
+ if (node < 0) {
+ debug("%s: could not find %s in FDT", __func__, conf);
+ continue;
+ }
+
+ /* Try to map this back onto SPL boot devices */
+ boot_device = spl_node_to_boot_device(node);
+ if (boot_device < 0) {
+ debug("%s: could not map node @%x to a boot-device\n",
+ __func__, node);
+ continue;
+ }
+
+ spl_boot_list[idx++] = boot_device;
+ }
+
+ /* If we had no matches, fall back to spl_boot_device */
+ if (idx == 0)
+ spl_boot_list[0] = spl_boot_device();
+}
+#endif
+
u32 spl_boot_device(void)
{
return BOOT_DEVICE_MMC1;