xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/spl-boot-order.c (revision 14be0258b50b8ea42e3c6d32115fd2b203bfcb4a)
19b0bc593SPhilipp Tomsich /*
29b0bc593SPhilipp Tomsich  * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
39b0bc593SPhilipp Tomsich  *
49b0bc593SPhilipp Tomsich  * SPDX-License-Identifier:     GPL-2.0+
59b0bc593SPhilipp Tomsich  */
69b0bc593SPhilipp Tomsich 
79b0bc593SPhilipp Tomsich #include <common.h>
89b0bc593SPhilipp Tomsich #include <dm.h>
99b0bc593SPhilipp Tomsich #include <mmc.h>
10332967aeSYifeng Zhao #include <nand.h>
119b0bc593SPhilipp Tomsich #include <spl.h>
129b0bc593SPhilipp Tomsich 
1309a3210fSKever Yang #if CONFIG_IS_ENABLED(OF_CONTROL) && ! CONFIG_IS_ENABLED(OF_PLATDATA)
14309353d5SPhilipp Tomsich /**
15309353d5SPhilipp Tomsich  * spl_node_to_boot_device() - maps from a DT-node to a SPL boot device
16309353d5SPhilipp Tomsich  * @node:	of_offset of the node
17309353d5SPhilipp Tomsich  *
18309353d5SPhilipp Tomsich  * The SPL framework uses BOOT_DEVICE_... constants to identify its boot
19309353d5SPhilipp Tomsich  * sources.  These may take on a device-specific meaning, depending on
20309353d5SPhilipp Tomsich  * what nodes are enabled in a DTS (e.g. BOOT_DEVICE_MMC1 may refer to
21309353d5SPhilipp Tomsich  * different controllers/block-devices, depending on which SD/MMC controllers
22309353d5SPhilipp Tomsich  * are enabled in any given DTS).  This function maps from a DT-node back
23309353d5SPhilipp Tomsich  * onto a BOOT_DEVICE_... constant, considering the currently active devices.
24309353d5SPhilipp Tomsich  *
25309353d5SPhilipp Tomsich  * Returns
26309353d5SPhilipp Tomsich  *   -ENOENT, if no device matching the node could be found
27309353d5SPhilipp Tomsich  *   -ENOSYS, if the device matching the node can not be mapped onto a
28309353d5SPhilipp Tomsich  *            SPL boot device (e.g. the third MMC device)
29309353d5SPhilipp Tomsich  *   -1, for unspecified failures
30309353d5SPhilipp Tomsich  *   a positive integer (from the BOOT_DEVICE_... family) on succes.
31309353d5SPhilipp Tomsich  */
329b0bc593SPhilipp Tomsich static int spl_node_to_boot_device(int node)
339b0bc593SPhilipp Tomsich {
349b0bc593SPhilipp Tomsich 	struct udevice *parent;
359b0bc593SPhilipp Tomsich 
369b0bc593SPhilipp Tomsich 	/*
379b0bc593SPhilipp Tomsich 	 * This should eventually move into the SPL code, once SPL becomes
389b0bc593SPhilipp Tomsich 	 * aware of the block-device layer.  Until then (and to avoid unneeded
399b0bc593SPhilipp Tomsich 	 * delays in getting this feature out, it lives at the board-level).
409b0bc593SPhilipp Tomsich 	 */
419b0bc593SPhilipp Tomsich 	if (!uclass_get_device_by_of_offset(UCLASS_MMC, node, &parent)) {
429b0bc593SPhilipp Tomsich 		struct udevice *dev;
439b0bc593SPhilipp Tomsich 		struct blk_desc *desc = NULL;
449b0bc593SPhilipp Tomsich 
459b0bc593SPhilipp Tomsich 		for (device_find_first_child(parent, &dev);
469b0bc593SPhilipp Tomsich 		     dev;
479b0bc593SPhilipp Tomsich 		     device_find_next_child(&dev)) {
489b0bc593SPhilipp Tomsich 			if (device_get_uclass_id(dev) == UCLASS_BLK) {
499b0bc593SPhilipp Tomsich 				desc = dev_get_uclass_platdata(dev);
509b0bc593SPhilipp Tomsich 				break;
519b0bc593SPhilipp Tomsich 			}
529b0bc593SPhilipp Tomsich 		}
539b0bc593SPhilipp Tomsich 
549b0bc593SPhilipp Tomsich 		if (!desc)
559b0bc593SPhilipp Tomsich 			return -ENOENT;
569b0bc593SPhilipp Tomsich 
579b0bc593SPhilipp Tomsich 		switch (desc->devnum) {
589b0bc593SPhilipp Tomsich 		case 0:
599b0bc593SPhilipp Tomsich 			return BOOT_DEVICE_MMC1;
609b0bc593SPhilipp Tomsich 		case 1:
619b0bc593SPhilipp Tomsich 			return BOOT_DEVICE_MMC2;
629b0bc593SPhilipp Tomsich 		default:
639b0bc593SPhilipp Tomsich 			return -ENOSYS;
649b0bc593SPhilipp Tomsich 		}
659b0bc593SPhilipp Tomsich 	}
669b0bc593SPhilipp Tomsich 
679b0bc593SPhilipp Tomsich 	/*
689b0bc593SPhilipp Tomsich 	 * SPL doesn't differentiate SPI flashes, so we keep the detection
699b0bc593SPhilipp Tomsich 	 * brief and inaccurate... hopefully, the common SPL layer can be
709b0bc593SPhilipp Tomsich 	 * extended with awareness of the BLK layer (and matching OF_CONTROL)
719b0bc593SPhilipp Tomsich 	 * soon.
729b0bc593SPhilipp Tomsich 	 */
739b0bc593SPhilipp Tomsich 	if (!uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, &parent))
740afd346fSJon Lin #ifndef CONFIG_SPL_MTD_SUPPORT
750afd346fSJon Lin 		return BOOT_DEVICE_SPI;
760afd346fSJon Lin #else
77c9b995fdSJon Lin 		return BOOT_DEVICE_MTD_BLK_SPI_NOR;
789b0bc593SPhilipp Tomsich 
79*14be0258SJason Zhu 	if (!uclass_get_device_by_of_offset(UCLASS_MTD, node, &parent)) {
80*14be0258SJason Zhu 		struct udevice *dev;
81*14be0258SJason Zhu 		struct blk_desc *desc = NULL;
82*14be0258SJason Zhu 
83*14be0258SJason Zhu 		for (device_find_first_child(parent, &dev);
84*14be0258SJason Zhu 		     dev;
85*14be0258SJason Zhu 		     device_find_next_child(&dev)) {
86*14be0258SJason Zhu 			if (device_get_uclass_id(dev) == UCLASS_BLK) {
87*14be0258SJason Zhu 				desc = dev_get_uclass_platdata(dev);
88*14be0258SJason Zhu 				break;
89*14be0258SJason Zhu 			}
90*14be0258SJason Zhu 		}
91*14be0258SJason Zhu 
92*14be0258SJason Zhu 		if (!desc)
93*14be0258SJason Zhu 			return -ENOENT;
94*14be0258SJason Zhu 
95*14be0258SJason Zhu 		switch (desc->devnum) {
96*14be0258SJason Zhu 		case 0:
97*14be0258SJason Zhu 			return BOOT_DEVICE_MTD_BLK_NAND;
98*14be0258SJason Zhu 		case 1:
99*14be0258SJason Zhu 			return BOOT_DEVICE_MTD_BLK_SPI_NAND;
100*14be0258SJason Zhu 		default:
101*14be0258SJason Zhu 			return -ENOSYS;
102*14be0258SJason Zhu 		}
103*14be0258SJason Zhu 	}
1044bac908bSJason Zhu #endif
1054bac908bSJason Zhu 
1069b0bc593SPhilipp Tomsich 	return -1;
1079b0bc593SPhilipp Tomsich }
1089b0bc593SPhilipp Tomsich 
1092d5ea11eSPhilipp Tomsich /**
1102d5ea11eSPhilipp Tomsich  * board_spl_was_booted_from() - retrieves the of-path the SPL was loaded from
1112d5ea11eSPhilipp Tomsich  *
1122d5ea11eSPhilipp Tomsich  * To support a 'same-as-spl' specification in the search-order for the next
1132d5ea11eSPhilipp Tomsich  * stage, we need a SoC- or board-specific way to handshake with what 'came
1142d5ea11eSPhilipp Tomsich  * before us' (either a BROM or TPL stage) and map the info retrieved onto
1152d5ea11eSPhilipp Tomsich  * a OF path.
1162d5ea11eSPhilipp Tomsich  *
1172d5ea11eSPhilipp Tomsich  * Returns
1182d5ea11eSPhilipp Tomsich  *   NULL, on failure or if the device could not be identified
1192d5ea11eSPhilipp Tomsich  *   a of_path (a string), on success
1202d5ea11eSPhilipp Tomsich  */
1212d5ea11eSPhilipp Tomsich __weak const char *board_spl_was_booted_from(void)
1222d5ea11eSPhilipp Tomsich {
1232d5ea11eSPhilipp Tomsich 	debug("%s: no support for 'same-as-spl' for this board\n", __func__);
1242d5ea11eSPhilipp Tomsich 	return NULL;
1252d5ea11eSPhilipp Tomsich }
1262d5ea11eSPhilipp Tomsich 
1279b0bc593SPhilipp Tomsich void board_boot_order(u32 *spl_boot_list)
1289b0bc593SPhilipp Tomsich {
1299b0bc593SPhilipp Tomsich 	const void *blob = gd->fdt_blob;
1309b0bc593SPhilipp Tomsich 	int chosen_node = fdt_path_offset(blob, "/chosen");
1319b0bc593SPhilipp Tomsich 	int idx = 0;
1329b0bc593SPhilipp Tomsich 	int elem;
1339b0bc593SPhilipp Tomsich 	int boot_device;
1349b0bc593SPhilipp Tomsich 	int node;
1359b0bc593SPhilipp Tomsich 	const char *conf;
1369b0bc593SPhilipp Tomsich 
1379b0bc593SPhilipp Tomsich 	if (chosen_node < 0) {
1389b0bc593SPhilipp Tomsich 		debug("%s: /chosen not found, using spl_boot_device()\n",
1399b0bc593SPhilipp Tomsich 		      __func__);
1409b0bc593SPhilipp Tomsich 		spl_boot_list[0] = spl_boot_device();
1419b0bc593SPhilipp Tomsich 		return;
1429b0bc593SPhilipp Tomsich 	}
1439b0bc593SPhilipp Tomsich 
1449b0bc593SPhilipp Tomsich 	for (elem = 0;
1459b0bc593SPhilipp Tomsich 	     (conf = fdt_stringlist_get(blob, chosen_node,
1469b0bc593SPhilipp Tomsich 					"u-boot,spl-boot-order", elem, NULL));
1479b0bc593SPhilipp Tomsich 	     elem++) {
1482d5ea11eSPhilipp Tomsich 		const char *alias;
1492d5ea11eSPhilipp Tomsich 
1502d5ea11eSPhilipp Tomsich 		/* Handle the case of 'same device the SPL was loaded from' */
1512d5ea11eSPhilipp Tomsich 		if (strncmp(conf, "same-as-spl", 11) == 0) {
1522d5ea11eSPhilipp Tomsich 			conf = board_spl_was_booted_from();
1532d5ea11eSPhilipp Tomsich 			if (!conf)
1542d5ea11eSPhilipp Tomsich 				continue;
1552d5ea11eSPhilipp Tomsich 		}
1562d5ea11eSPhilipp Tomsich 
1579b0bc593SPhilipp Tomsich 		/* First check if the list element is an alias */
1582d5ea11eSPhilipp Tomsich 		alias = fdt_get_alias(blob, conf);
1599b0bc593SPhilipp Tomsich 		if (alias)
1609b0bc593SPhilipp Tomsich 			conf = alias;
1619b0bc593SPhilipp Tomsich 
1629b0bc593SPhilipp Tomsich 		/* Try to resolve the config item (or alias) as a path */
1639b0bc593SPhilipp Tomsich 		node = fdt_path_offset(blob, conf);
1649b0bc593SPhilipp Tomsich 		if (node < 0) {
1659b0bc593SPhilipp Tomsich 			debug("%s: could not find %s in FDT", __func__, conf);
1669b0bc593SPhilipp Tomsich 			continue;
1679b0bc593SPhilipp Tomsich 		}
1689b0bc593SPhilipp Tomsich 
1699b0bc593SPhilipp Tomsich 		/* Try to map this back onto SPL boot devices */
1709b0bc593SPhilipp Tomsich 		boot_device = spl_node_to_boot_device(node);
1719b0bc593SPhilipp Tomsich 		if (boot_device < 0) {
1729b0bc593SPhilipp Tomsich 			debug("%s: could not map node @%x to a boot-device\n",
1739b0bc593SPhilipp Tomsich 			      __func__, node);
1749b0bc593SPhilipp Tomsich 			continue;
1759b0bc593SPhilipp Tomsich 		}
1769b0bc593SPhilipp Tomsich 
1779b0bc593SPhilipp Tomsich 		spl_boot_list[idx++] = boot_device;
1789b0bc593SPhilipp Tomsich 	}
1799b0bc593SPhilipp Tomsich 
1809b0bc593SPhilipp Tomsich 	/* If we had no matches, fall back to spl_boot_device */
1819b0bc593SPhilipp Tomsich 	if (idx == 0)
1829b0bc593SPhilipp Tomsich 		spl_boot_list[0] = spl_boot_device();
1839b0bc593SPhilipp Tomsich }
1849b0bc593SPhilipp Tomsich #endif
185