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