xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/spl-boot-order.c (revision f749a0349c88cf56585078dbb67aeefe44e02471)
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 
13c4bf7455SJoseph Chen #ifdef CONFIG_SPL_RAM_DEVICE
board_boot_order(u32 * spl_boot_list)14c4bf7455SJoseph Chen void board_boot_order(u32 *spl_boot_list)
15c4bf7455SJoseph Chen {
16c4bf7455SJoseph Chen 	spl_boot_list[0] = BOOT_DEVICE_RAM;
17c4bf7455SJoseph Chen }
18c4bf7455SJoseph Chen #else
19c4bf7455SJoseph Chen 
2009a3210fSKever Yang #if CONFIG_IS_ENABLED(OF_CONTROL) && ! CONFIG_IS_ENABLED(OF_PLATDATA)
21309353d5SPhilipp Tomsich /**
22309353d5SPhilipp Tomsich  * spl_node_to_boot_device() - maps from a DT-node to a SPL boot device
23309353d5SPhilipp Tomsich  * @node:	of_offset of the node
24309353d5SPhilipp Tomsich  *
25309353d5SPhilipp Tomsich  * The SPL framework uses BOOT_DEVICE_... constants to identify its boot
26309353d5SPhilipp Tomsich  * sources.  These may take on a device-specific meaning, depending on
27309353d5SPhilipp Tomsich  * what nodes are enabled in a DTS (e.g. BOOT_DEVICE_MMC1 may refer to
28309353d5SPhilipp Tomsich  * different controllers/block-devices, depending on which SD/MMC controllers
29309353d5SPhilipp Tomsich  * are enabled in any given DTS).  This function maps from a DT-node back
30309353d5SPhilipp Tomsich  * onto a BOOT_DEVICE_... constant, considering the currently active devices.
31309353d5SPhilipp Tomsich  *
32309353d5SPhilipp Tomsich  * Returns
33309353d5SPhilipp Tomsich  *   -ENOENT, if no device matching the node could be found
34309353d5SPhilipp Tomsich  *   -ENOSYS, if the device matching the node can not be mapped onto a
35309353d5SPhilipp Tomsich  *            SPL boot device (e.g. the third MMC device)
36309353d5SPhilipp Tomsich  *   -1, for unspecified failures
37309353d5SPhilipp Tomsich  *   a positive integer (from the BOOT_DEVICE_... family) on succes.
38309353d5SPhilipp Tomsich  */
spl_node_to_boot_device(int node)399b0bc593SPhilipp Tomsich static int spl_node_to_boot_device(int node)
409b0bc593SPhilipp Tomsich {
419b0bc593SPhilipp Tomsich 	struct udevice *parent;
429b0bc593SPhilipp Tomsich 
43*f749a034SYifeng Zhao 	if (!uclass_get_device_by_of_offset(UCLASS_UFS, node, &parent))
44*f749a034SYifeng Zhao 		return BOOT_DEVICE_UFS;
45*f749a034SYifeng Zhao 
469b0bc593SPhilipp Tomsich 	/*
479b0bc593SPhilipp Tomsich 	 * This should eventually move into the SPL code, once SPL becomes
489b0bc593SPhilipp Tomsich 	 * aware of the block-device layer.  Until then (and to avoid unneeded
499b0bc593SPhilipp Tomsich 	 * delays in getting this feature out, it lives at the board-level).
509b0bc593SPhilipp Tomsich 	 */
519b0bc593SPhilipp Tomsich 	if (!uclass_get_device_by_of_offset(UCLASS_MMC, node, &parent)) {
529b0bc593SPhilipp Tomsich 		struct udevice *dev;
539b0bc593SPhilipp Tomsich 		struct blk_desc *desc = NULL;
549b0bc593SPhilipp Tomsich 
559b0bc593SPhilipp Tomsich 		for (device_find_first_child(parent, &dev);
569b0bc593SPhilipp Tomsich 		     dev;
579b0bc593SPhilipp Tomsich 		     device_find_next_child(&dev)) {
589b0bc593SPhilipp Tomsich 			if (device_get_uclass_id(dev) == UCLASS_BLK) {
599b0bc593SPhilipp Tomsich 				desc = dev_get_uclass_platdata(dev);
609b0bc593SPhilipp Tomsich 				break;
619b0bc593SPhilipp Tomsich 			}
629b0bc593SPhilipp Tomsich 		}
639b0bc593SPhilipp Tomsich 
649b0bc593SPhilipp Tomsich 		if (!desc)
659b0bc593SPhilipp Tomsich 			return -ENOENT;
669b0bc593SPhilipp Tomsich 
679b0bc593SPhilipp Tomsich 		switch (desc->devnum) {
689b0bc593SPhilipp Tomsich 		case 0:
699b0bc593SPhilipp Tomsich 			return BOOT_DEVICE_MMC1;
709b0bc593SPhilipp Tomsich 		case 1:
719b0bc593SPhilipp Tomsich 			return BOOT_DEVICE_MMC2;
729b0bc593SPhilipp Tomsich 		default:
739b0bc593SPhilipp Tomsich 			return -ENOSYS;
749b0bc593SPhilipp Tomsich 		}
759b0bc593SPhilipp Tomsich 	}
769b0bc593SPhilipp Tomsich 
779b0bc593SPhilipp Tomsich 	/*
789b0bc593SPhilipp Tomsich 	 * SPL doesn't differentiate SPI flashes, so we keep the detection
799b0bc593SPhilipp Tomsich 	 * brief and inaccurate... hopefully, the common SPL layer can be
809b0bc593SPhilipp Tomsich 	 * extended with awareness of the BLK layer (and matching OF_CONTROL)
819b0bc593SPhilipp Tomsich 	 * soon.
829b0bc593SPhilipp Tomsich 	 */
839b0bc593SPhilipp Tomsich 	if (!uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, &parent))
840afd346fSJon Lin #ifndef CONFIG_SPL_MTD_SUPPORT
850afd346fSJon Lin 		return BOOT_DEVICE_SPI;
860afd346fSJon Lin #else
87c9b995fdSJon Lin 		return BOOT_DEVICE_MTD_BLK_SPI_NOR;
889b0bc593SPhilipp Tomsich 
8914be0258SJason Zhu 	if (!uclass_get_device_by_of_offset(UCLASS_MTD, node, &parent)) {
9014be0258SJason Zhu 		struct udevice *dev;
9114be0258SJason Zhu 		struct blk_desc *desc = NULL;
9214be0258SJason Zhu 
9314be0258SJason Zhu 		for (device_find_first_child(parent, &dev);
9414be0258SJason Zhu 		     dev;
9514be0258SJason Zhu 		     device_find_next_child(&dev)) {
9614be0258SJason Zhu 			if (device_get_uclass_id(dev) == UCLASS_BLK) {
9714be0258SJason Zhu 				desc = dev_get_uclass_platdata(dev);
9814be0258SJason Zhu 				break;
9914be0258SJason Zhu 			}
10014be0258SJason Zhu 		}
10114be0258SJason Zhu 
10214be0258SJason Zhu 		if (!desc)
10314be0258SJason Zhu 			return -ENOENT;
10414be0258SJason Zhu 
10514be0258SJason Zhu 		switch (desc->devnum) {
10614be0258SJason Zhu 		case 0:
10714be0258SJason Zhu 			return BOOT_DEVICE_MTD_BLK_NAND;
10814be0258SJason Zhu 		case 1:
10914be0258SJason Zhu 			return BOOT_DEVICE_MTD_BLK_SPI_NAND;
11014be0258SJason Zhu 		default:
11114be0258SJason Zhu 			return -ENOSYS;
11214be0258SJason Zhu 		}
11314be0258SJason Zhu 	}
1144bac908bSJason Zhu #endif
1154bac908bSJason Zhu 
116568252a0SYifeng Zhao 	/*
117568252a0SYifeng Zhao 	 * This should eventually move into the SPL code, once SPL becomes
118568252a0SYifeng Zhao 	 * aware of the block-device layer.  Until then (and to avoid unneeded
119568252a0SYifeng Zhao 	 * delays in getting this feature out, it lives at the board-level).
120568252a0SYifeng Zhao 	 */
121568252a0SYifeng Zhao 	if (!uclass_get_device_by_of_offset(UCLASS_RKNAND, node, &parent))
122568252a0SYifeng Zhao 		return BOOT_DEVICE_RKNAND;
123568252a0SYifeng Zhao 
1249b0bc593SPhilipp Tomsich 	return -1;
1259b0bc593SPhilipp Tomsich }
1269b0bc593SPhilipp Tomsich 
1272d5ea11eSPhilipp Tomsich /**
1282d5ea11eSPhilipp Tomsich  * board_spl_was_booted_from() - retrieves the of-path the SPL was loaded from
1292d5ea11eSPhilipp Tomsich  *
1302d5ea11eSPhilipp Tomsich  * To support a 'same-as-spl' specification in the search-order for the next
1312d5ea11eSPhilipp Tomsich  * stage, we need a SoC- or board-specific way to handshake with what 'came
1322d5ea11eSPhilipp Tomsich  * before us' (either a BROM or TPL stage) and map the info retrieved onto
1332d5ea11eSPhilipp Tomsich  * a OF path.
1342d5ea11eSPhilipp Tomsich  *
1352d5ea11eSPhilipp Tomsich  * Returns
1362d5ea11eSPhilipp Tomsich  *   NULL, on failure or if the device could not be identified
1372d5ea11eSPhilipp Tomsich  *   a of_path (a string), on success
1382d5ea11eSPhilipp Tomsich  */
board_spl_was_booted_from(void)1392d5ea11eSPhilipp Tomsich __weak const char *board_spl_was_booted_from(void)
1402d5ea11eSPhilipp Tomsich {
1412d5ea11eSPhilipp Tomsich 	debug("%s: no support for 'same-as-spl' for this board\n", __func__);
1422d5ea11eSPhilipp Tomsich 	return NULL;
1432d5ea11eSPhilipp Tomsich }
1442d5ea11eSPhilipp Tomsich 
board_boot_order(u32 * spl_boot_list)1459b0bc593SPhilipp Tomsich void board_boot_order(u32 *spl_boot_list)
1469b0bc593SPhilipp Tomsich {
1479b0bc593SPhilipp Tomsich 	const void *blob = gd->fdt_blob;
1489b0bc593SPhilipp Tomsich 	int chosen_node = fdt_path_offset(blob, "/chosen");
1499b0bc593SPhilipp Tomsich 	int idx = 0;
1509b0bc593SPhilipp Tomsich 	int elem;
1519b0bc593SPhilipp Tomsich 	int boot_device;
1529b0bc593SPhilipp Tomsich 	int node;
1539b0bc593SPhilipp Tomsich 	const char *conf;
1549b0bc593SPhilipp Tomsich 
1559b0bc593SPhilipp Tomsich 	if (chosen_node < 0) {
1569b0bc593SPhilipp Tomsich 		debug("%s: /chosen not found, using spl_boot_device()\n",
1579b0bc593SPhilipp Tomsich 		      __func__);
1589b0bc593SPhilipp Tomsich 		spl_boot_list[0] = spl_boot_device();
1599b0bc593SPhilipp Tomsich 		return;
1609b0bc593SPhilipp Tomsich 	}
1619b0bc593SPhilipp Tomsich 
1629b0bc593SPhilipp Tomsich 	for (elem = 0;
1639b0bc593SPhilipp Tomsich 	     (conf = fdt_stringlist_get(blob, chosen_node,
1649b0bc593SPhilipp Tomsich 					"u-boot,spl-boot-order", elem, NULL));
1659b0bc593SPhilipp Tomsich 	     elem++) {
1662d5ea11eSPhilipp Tomsich 		const char *alias;
1672d5ea11eSPhilipp Tomsich 
1682d5ea11eSPhilipp Tomsich 		/* Handle the case of 'same device the SPL was loaded from' */
1692d5ea11eSPhilipp Tomsich 		if (strncmp(conf, "same-as-spl", 11) == 0) {
1702d5ea11eSPhilipp Tomsich 			conf = board_spl_was_booted_from();
1712d5ea11eSPhilipp Tomsich 			if (!conf)
1722d5ea11eSPhilipp Tomsich 				continue;
1732d5ea11eSPhilipp Tomsich 		}
1742d5ea11eSPhilipp Tomsich 
1759b0bc593SPhilipp Tomsich 		/* First check if the list element is an alias */
1762d5ea11eSPhilipp Tomsich 		alias = fdt_get_alias(blob, conf);
1779b0bc593SPhilipp Tomsich 		if (alias)
1789b0bc593SPhilipp Tomsich 			conf = alias;
1799b0bc593SPhilipp Tomsich 
1809b0bc593SPhilipp Tomsich 		/* Try to resolve the config item (or alias) as a path */
1819b0bc593SPhilipp Tomsich 		node = fdt_path_offset(blob, conf);
1829b0bc593SPhilipp Tomsich 		if (node < 0) {
1839b0bc593SPhilipp Tomsich 			debug("%s: could not find %s in FDT", __func__, conf);
1849b0bc593SPhilipp Tomsich 			continue;
1859b0bc593SPhilipp Tomsich 		}
1869b0bc593SPhilipp Tomsich 
1879b0bc593SPhilipp Tomsich 		/* Try to map this back onto SPL boot devices */
1889b0bc593SPhilipp Tomsich 		boot_device = spl_node_to_boot_device(node);
1899b0bc593SPhilipp Tomsich 		if (boot_device < 0) {
1909b0bc593SPhilipp Tomsich 			debug("%s: could not map node @%x to a boot-device\n",
1919b0bc593SPhilipp Tomsich 			      __func__, node);
1929b0bc593SPhilipp Tomsich 			continue;
1939b0bc593SPhilipp Tomsich 		}
1949b0bc593SPhilipp Tomsich 
1959b0bc593SPhilipp Tomsich 		spl_boot_list[idx++] = boot_device;
1969b0bc593SPhilipp Tomsich 	}
1979b0bc593SPhilipp Tomsich 
1989b0bc593SPhilipp Tomsich 	/* If we had no matches, fall back to spl_boot_device */
1999b0bc593SPhilipp Tomsich 	if (idx == 0)
2009b0bc593SPhilipp Tomsich 		spl_boot_list[0] = spl_boot_device();
2019b0bc593SPhilipp Tomsich }
2029b0bc593SPhilipp Tomsich #endif
203c4bf7455SJoseph Chen #endif
204