spl-boot-order.c 4.1 KB

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