1 // SPDX-License-Identifier: GPL-2.0+
3 * Uclass implementation for standard boot
5 * Copyright 2021 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
15 #include <dm/device-internal.h>
18 #include <dm/uclass-internal.h>
20 DECLARE_GLOBAL_DATA_PTR;
22 /* These are used if filename-prefixes is not present */
23 const char *const default_prefixes[] = {"/", "/boot/", NULL};
25 static int bootstd_of_to_plat(struct udevice *dev)
27 struct bootstd_priv *priv = dev_get_priv(dev);
30 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
31 /* Don't check errors since livetree and flattree are different */
32 ret = dev_read_string_list(dev, "filename-prefixes",
34 dev_read_string_list(dev, "bootdev-order",
35 &priv->bootdev_order);
41 static void bootstd_clear_glob_(struct bootstd_priv *priv)
43 while (!list_empty(&priv->glob_head)) {
44 struct bootflow *bflow;
46 bflow = list_first_entry(&priv->glob_head, struct bootflow,
48 bootflow_remove(bflow);
52 void bootstd_clear_glob(void)
54 struct bootstd_priv *std;
56 if (bootstd_get_priv(&std))
59 bootstd_clear_glob_(std);
62 static int bootstd_remove(struct udevice *dev)
64 struct bootstd_priv *priv = dev_get_priv(dev);
67 free(priv->bootdev_order);
68 bootstd_clear_glob_(priv);
73 const char *const *const bootstd_get_bootdev_order(struct udevice *dev)
75 struct bootstd_priv *std = dev_get_priv(dev);
77 return std->bootdev_order;
80 const char *const *const bootstd_get_prefixes(struct udevice *dev)
82 struct bootstd_priv *std = dev_get_priv(dev);
84 return std->prefixes ? std->prefixes : default_prefixes;
87 int bootstd_get_priv(struct bootstd_priv **stdp)
92 ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
95 *stdp = dev_get_priv(dev);
100 static int bootstd_probe(struct udevice *dev)
102 struct bootstd_priv *std = dev_get_priv(dev);
104 INIT_LIST_HEAD(&std->glob_head);
109 /* For now, bind the boormethod device if none are found in the devicetree */
110 int dm_scan_other(bool pre_reloc_only)
112 struct driver *drv = ll_entry_start(struct driver, driver);
113 const int n_ents = ll_entry_count(struct driver, driver);
114 struct udevice *dev, *bootstd;
117 /* These are not needed before relocation */
118 if (!(gd->flags & GD_FLG_RELOC))
121 /* Create a bootstd device if needed */
122 uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
124 ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
127 return log_msg_ret("bootstd", ret);
130 /* If there are no bootmeth devices, create them */
131 uclass_find_first_device(UCLASS_BOOTMETH, &dev);
135 for (i = 0; i < n_ents; i++, drv++) {
136 if (drv->id == UCLASS_BOOTMETH) {
137 const char *name = drv->name;
139 if (!strncmp("bootmeth_", name, 9))
141 ret = device_bind(bootstd, drv, name, 0, ofnode_null(),
144 return log_msg_ret("meth", ret);
148 /* Create the system bootdev too */
149 ret = device_bind_driver(bootstd, "system_bootdev", "system-bootdev",
152 return log_msg_ret("sys", ret);
157 static const struct udevice_id bootstd_ids[] = {
158 { .compatible = "u-boot,boot-std" },
162 U_BOOT_DRIVER(bootstd_drv) = {
163 .id = UCLASS_BOOTSTD,
164 .name = "bootstd_drv",
165 .of_to_plat = bootstd_of_to_plat,
166 .probe = bootstd_probe,
167 .remove = bootstd_remove,
168 .of_match = bootstd_ids,
169 .priv_auto = sizeof(struct bootstd_priv),
172 UCLASS_DRIVER(bootstd) = {
173 .id = UCLASS_BOOTSTD,
175 #if CONFIG_IS_ENABLED(OF_REAL)
176 .post_bind = dm_scan_fdt_dev,