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 <nand.h> 11 #include <spl.h> 12 13 #if CONFIG_IS_ENABLED(OF_CONTROL) && ! CONFIG_IS_ENABLED(OF_PLATDATA) 14 /** 15 * spl_node_to_boot_device() - maps from a DT-node to a SPL boot device 16 * @node: of_offset of the node 17 * 18 * The SPL framework uses BOOT_DEVICE_... constants to identify its boot 19 * sources. These may take on a device-specific meaning, depending on 20 * what nodes are enabled in a DTS (e.g. BOOT_DEVICE_MMC1 may refer to 21 * different controllers/block-devices, depending on which SD/MMC controllers 22 * are enabled in any given DTS). This function maps from a DT-node back 23 * onto a BOOT_DEVICE_... constant, considering the currently active devices. 24 * 25 * Returns 26 * -ENOENT, if no device matching the node could be found 27 * -ENOSYS, if the device matching the node can not be mapped onto a 28 * SPL boot device (e.g. the third MMC device) 29 * -1, for unspecified failures 30 * a positive integer (from the BOOT_DEVICE_... family) on succes. 31 */ 32 33 static int spl_node_to_boot_device(int node) 34 { 35 struct udevice *parent; 36 37 if (!uclass_get_device_by_of_offset(UCLASS_SPI, node, &parent)) { 38 struct udevice *spi_dev; 39 40 for (device_find_first_child(parent, &spi_dev); 41 spi_dev; 42 device_find_next_child(&spi_dev)) { 43 if (device_get_uclass_id(spi_dev) == UCLASS_SPI_FLASH) { 44 return BOOT_DEVICE_MTD_BLK_SPI_NOR; 45 } else if (device_get_uclass_id(spi_dev) == UCLASS_MTD) { 46 return BOOT_DEVICE_MTD_BLK_SPI_NAND; 47 } else { 48 printf("Can not find spi flash device\n"); 49 return -ENOSYS; 50 } 51 } 52 } 53 54 /* 55 * This should eventually move into the SPL code, once SPL becomes 56 * aware of the block-device layer. Until then (and to avoid unneeded 57 * delays in getting this feature out, it lives at the board-level). 58 */ 59 if (!uclass_get_device_by_of_offset(UCLASS_MMC, node, &parent)) { 60 struct udevice *dev; 61 struct blk_desc *desc = NULL; 62 63 for (device_find_first_child(parent, &dev); 64 dev; 65 device_find_next_child(&dev)) { 66 if (device_get_uclass_id(dev) == UCLASS_BLK) { 67 desc = dev_get_uclass_platdata(dev); 68 break; 69 } 70 } 71 72 if (!desc) 73 return -ENOENT; 74 75 switch (desc->devnum) { 76 case 0: 77 return BOOT_DEVICE_MMC1; 78 case 1: 79 return BOOT_DEVICE_MMC2; 80 default: 81 return -ENOSYS; 82 } 83 } 84 85 /* 86 * SPL doesn't differentiate SPI flashes, so we keep the detection 87 * brief and inaccurate... hopefully, the common SPL layer can be 88 * extended with awareness of the BLK layer (and matching OF_CONTROL) 89 * soon. 90 */ 91 if (!uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, &parent)) 92 return BOOT_DEVICE_SPI; 93 94 #ifdef CONFIG_SPL_NAND_SUPPORT 95 if (!rk_nand_init()) 96 return BOOT_DEVICE_NAND; 97 #endif 98 99 return -1; 100 } 101 102 /** 103 * board_spl_was_booted_from() - retrieves the of-path the SPL was loaded from 104 * 105 * To support a 'same-as-spl' specification in the search-order for the next 106 * stage, we need a SoC- or board-specific way to handshake with what 'came 107 * before us' (either a BROM or TPL stage) and map the info retrieved onto 108 * a OF path. 109 * 110 * Returns 111 * NULL, on failure or if the device could not be identified 112 * a of_path (a string), on success 113 */ 114 __weak const char *board_spl_was_booted_from(void) 115 { 116 debug("%s: no support for 'same-as-spl' for this board\n", __func__); 117 return NULL; 118 } 119 120 void board_boot_order(u32 *spl_boot_list) 121 { 122 const void *blob = gd->fdt_blob; 123 int chosen_node = fdt_path_offset(blob, "/chosen"); 124 int idx = 0; 125 int elem; 126 int boot_device; 127 int node; 128 const char *conf; 129 130 if (chosen_node < 0) { 131 debug("%s: /chosen not found, using spl_boot_device()\n", 132 __func__); 133 spl_boot_list[0] = spl_boot_device(); 134 return; 135 } 136 137 for (elem = 0; 138 (conf = fdt_stringlist_get(blob, chosen_node, 139 "u-boot,spl-boot-order", elem, NULL)); 140 elem++) { 141 const char *alias; 142 143 /* Handle the case of 'same device the SPL was loaded from' */ 144 if (strncmp(conf, "same-as-spl", 11) == 0) { 145 conf = board_spl_was_booted_from(); 146 if (!conf) 147 continue; 148 } 149 150 /* First check if the list element is an alias */ 151 alias = fdt_get_alias(blob, conf); 152 if (alias) 153 conf = alias; 154 155 /* Try to resolve the config item (or alias) as a path */ 156 node = fdt_path_offset(blob, conf); 157 if (node < 0) { 158 debug("%s: could not find %s in FDT", __func__, conf); 159 continue; 160 } 161 162 /* Try to map this back onto SPL boot devices */ 163 boot_device = spl_node_to_boot_device(node); 164 if (boot_device < 0) { 165 debug("%s: could not map node @%x to a boot-device\n", 166 __func__, node); 167 continue; 168 } 169 170 spl_boot_list[idx++] = boot_device; 171 } 172 173 /* If we had no matches, fall back to spl_boot_device */ 174 if (idx == 0) 175 spl_boot_list[0] = spl_boot_device(); 176 } 177 #endif 178