1 /*
2  * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <mmc.h>
10 #include <spl.h>
11 
12 #if CONFIG_IS_ENABLED(OF_CONTROL)
13 static int spl_node_to_boot_device(int node)
14 {
15 	struct udevice *parent;
16 
17 	/*
18 	 * This should eventually move into the SPL code, once SPL becomes
19 	 * aware of the block-device layer.  Until then (and to avoid unneeded
20 	 * delays in getting this feature out, it lives at the board-level).
21 	 */
22 	if (!uclass_get_device_by_of_offset(UCLASS_MMC, node, &parent)) {
23 		struct udevice *dev;
24 		struct blk_desc *desc = NULL;
25 
26 		for (device_find_first_child(parent, &dev);
27 		     dev;
28 		     device_find_next_child(&dev)) {
29 			if (device_get_uclass_id(dev) == UCLASS_BLK) {
30 				desc = dev_get_uclass_platdata(dev);
31 				break;
32 			}
33 		}
34 
35 		if (!desc)
36 			return -ENOENT;
37 
38 		switch (desc->devnum) {
39 		case 0:
40 			return BOOT_DEVICE_MMC1;
41 		case 1:
42 			return BOOT_DEVICE_MMC2;
43 		default:
44 			return -ENOSYS;
45 		}
46 	}
47 
48 	/*
49 	 * SPL doesn't differentiate SPI flashes, so we keep the detection
50 	 * brief and inaccurate... hopefully, the common SPL layer can be
51 	 * extended with awareness of the BLK layer (and matching OF_CONTROL)
52 	 * soon.
53 	 */
54 	if (!uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, &parent))
55 		return BOOT_DEVICE_SPI;
56 
57 	return -1;
58 }
59 
60 void board_boot_order(u32 *spl_boot_list)
61 {
62 	const void *blob = gd->fdt_blob;
63 	int chosen_node = fdt_path_offset(blob, "/chosen");
64 	int idx = 0;
65 	int elem;
66 	int boot_device;
67 	int node;
68 	const char *conf;
69 
70 	if (chosen_node < 0) {
71 		debug("%s: /chosen not found, using spl_boot_device()\n",
72 		      __func__);
73 		spl_boot_list[0] = spl_boot_device();
74 		return;
75 	}
76 
77 	for (elem = 0;
78 	     (conf = fdt_stringlist_get(blob, chosen_node,
79 					"u-boot,spl-boot-order", elem, NULL));
80 	     elem++) {
81 		/* First check if the list element is an alias */
82 		const char *alias = fdt_get_alias(blob, conf);
83 		if (alias)
84 			conf = alias;
85 
86 		/* Try to resolve the config item (or alias) as a path */
87 		node = fdt_path_offset(blob, conf);
88 		if (node < 0) {
89 			debug("%s: could not find %s in FDT", __func__, conf);
90 			continue;
91 		}
92 
93 		/* Try to map this back onto SPL boot devices */
94 		boot_device = spl_node_to_boot_device(node);
95 		if (boot_device < 0) {
96 			debug("%s: could not map node @%x to a boot-device\n",
97 			      __func__, node);
98 			continue;
99 		}
100 
101 		spl_boot_list[idx++] = boot_device;
102 	}
103 
104 	/* If we had no matches, fall back to spl_boot_device */
105 	if (idx == 0)
106 		spl_boot_list[0] = spl_boot_device();
107 }
108 #endif
109