bootstd-uclass.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Uclass implementation for standard boot
  4. *
  5. * Copyright 2021 Google LLC
  6. * Written by Simon Glass <sjg@chromium.org>
  7. */
  8. #include <common.h>
  9. #include <bootflow.h>
  10. #include <bootstd.h>
  11. #include <dm.h>
  12. #include <env.h>
  13. #include <log.h>
  14. #include <malloc.h>
  15. #include <dm/device-internal.h>
  16. #include <dm/lists.h>
  17. #include <dm/read.h>
  18. #include <dm/uclass-internal.h>
  19. DECLARE_GLOBAL_DATA_PTR;
  20. /* These are used if filename-prefixes is not present */
  21. const char *const default_prefixes[] = {"/", "/boot/", NULL};
  22. static int bootstd_of_to_plat(struct udevice *dev)
  23. {
  24. struct bootstd_priv *priv = dev_get_priv(dev);
  25. int ret;
  26. if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
  27. /* Don't check errors since livetree and flattree are different */
  28. ret = dev_read_string_list(dev, "filename-prefixes",
  29. &priv->prefixes);
  30. dev_read_string_list(dev, "bootdev-order",
  31. &priv->bootdev_order);
  32. priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme");
  33. }
  34. return 0;
  35. }
  36. static void bootstd_clear_glob_(struct bootstd_priv *priv)
  37. {
  38. while (!list_empty(&priv->glob_head)) {
  39. struct bootflow *bflow;
  40. bflow = list_first_entry(&priv->glob_head, struct bootflow,
  41. glob_node);
  42. bootflow_remove(bflow);
  43. }
  44. }
  45. void bootstd_clear_glob(void)
  46. {
  47. struct bootstd_priv *std;
  48. if (bootstd_get_priv(&std))
  49. return;
  50. bootstd_clear_glob_(std);
  51. }
  52. static int bootstd_remove(struct udevice *dev)
  53. {
  54. struct bootstd_priv *priv = dev_get_priv(dev);
  55. free(priv->prefixes);
  56. free(priv->bootdev_order);
  57. bootstd_clear_glob_(priv);
  58. return 0;
  59. }
  60. const char *const *const bootstd_get_bootdev_order(struct udevice *dev,
  61. bool *okp)
  62. {
  63. struct bootstd_priv *std = dev_get_priv(dev);
  64. const char *targets = env_get("boot_targets");
  65. *okp = true;
  66. log_debug("- targets %s %p\n", targets, std->bootdev_order);
  67. if (targets && *targets) {
  68. str_free_list(std->env_order);
  69. std->env_order = str_to_list(targets);
  70. if (!std->env_order) {
  71. *okp = false;
  72. return NULL;
  73. }
  74. return std->env_order;
  75. }
  76. return std->bootdev_order;
  77. }
  78. const char *const *const bootstd_get_prefixes(struct udevice *dev)
  79. {
  80. struct bootstd_priv *std = dev_get_priv(dev);
  81. return std->prefixes ? std->prefixes : default_prefixes;
  82. }
  83. int bootstd_get_priv(struct bootstd_priv **stdp)
  84. {
  85. struct udevice *dev;
  86. int ret;
  87. ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
  88. if (ret)
  89. return ret;
  90. *stdp = dev_get_priv(dev);
  91. return 0;
  92. }
  93. static int bootstd_probe(struct udevice *dev)
  94. {
  95. struct bootstd_priv *std = dev_get_priv(dev);
  96. INIT_LIST_HEAD(&std->glob_head);
  97. return 0;
  98. }
  99. /* For now, bind the boormethod device if none are found in the devicetree */
  100. int dm_scan_other(bool pre_reloc_only)
  101. {
  102. struct driver *drv = ll_entry_start(struct driver, driver);
  103. const int n_ents = ll_entry_count(struct driver, driver);
  104. struct udevice *dev, *bootstd;
  105. int i, ret;
  106. /* These are not needed before relocation */
  107. if (!(gd->flags & GD_FLG_RELOC))
  108. return 0;
  109. /* Create a bootstd device if needed */
  110. uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
  111. if (!bootstd) {
  112. ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
  113. &bootstd);
  114. if (ret)
  115. return log_msg_ret("bootstd", ret);
  116. }
  117. /* If there are no bootmeth devices, create them */
  118. uclass_find_first_device(UCLASS_BOOTMETH, &dev);
  119. if (dev)
  120. return 0;
  121. for (i = 0; i < n_ents; i++, drv++) {
  122. if (drv->id == UCLASS_BOOTMETH) {
  123. const char *name = drv->name;
  124. if (!strncmp("bootmeth_", name, 9))
  125. name += 9;
  126. ret = device_bind(bootstd, drv, name, 0, ofnode_null(),
  127. &dev);
  128. if (ret)
  129. return log_msg_ret("meth", ret);
  130. }
  131. }
  132. return 0;
  133. }
  134. static const struct udevice_id bootstd_ids[] = {
  135. { .compatible = "u-boot,boot-std" },
  136. { }
  137. };
  138. U_BOOT_DRIVER(bootstd_drv) = {
  139. .id = UCLASS_BOOTSTD,
  140. .name = "bootstd_drv",
  141. .of_to_plat = bootstd_of_to_plat,
  142. .probe = bootstd_probe,
  143. .remove = bootstd_remove,
  144. .of_match = bootstd_ids,
  145. .priv_auto = sizeof(struct bootstd_priv),
  146. };
  147. UCLASS_DRIVER(bootstd) = {
  148. .id = UCLASS_BOOTSTD,
  149. .name = "bootstd",
  150. #if CONFIG_IS_ENABLED(OF_REAL)
  151. .post_bind = dm_scan_fdt_dev,
  152. #endif
  153. };