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>
16 #include <dm/device-internal.h>
19 #include <dm/uclass-internal.h>
21 DECLARE_GLOBAL_DATA_PTR
;
23 /* These are used if filename-prefixes is not present */
24 const char *const default_prefixes
[] = {"/", "/boot/", NULL
};
26 static int bootstd_of_to_plat(struct udevice
*dev
)
28 struct bootstd_priv
*priv
= dev_get_priv(dev
);
31 if (IS_ENABLED(CONFIG_BOOTSTD_FULL
)) {
32 /* Don't check errors since livetree and flattree are different */
33 ret
= dev_read_string_list(dev
, "filename-prefixes",
35 dev_read_string_list(dev
, "bootdev-order",
36 &priv
->bootdev_order
);
38 priv
->theme
= ofnode_find_subnode(dev_ofnode(dev
), "theme");
44 static void bootstd_clear_glob_(struct bootstd_priv
*priv
)
46 struct bootflow
*bflow
;
48 alist_for_each(bflow
, &priv
->bootflows
)
49 bootflow_remove(bflow
);
50 alist_empty(&priv
->bootflows
);
53 void bootstd_clear_glob(void)
55 struct bootstd_priv
*std
;
57 if (bootstd_get_priv(&std
))
60 bootstd_clear_glob_(std
);
63 int bootstd_add_bootflow(struct bootflow
*bflow
)
65 struct bootstd_priv
*std
;
68 ret
= bootstd_get_priv(&std
);
72 ret
= std
->bootflows
.count
;
73 bflow
= alist_add(&std
->bootflows
, *bflow
);
75 return log_msg_ret("bf2", -ENOMEM
);
80 int bootstd_clear_bootflows_for_bootdev(struct udevice
*dev
)
82 struct bootstd_priv
*std
= bootstd_try_priv();
83 struct bootflow
*from
, *to
;
85 /* if bootstd does not exist we cannot have any bootflows */
89 /* Drop any bootflows that mention this dev */
90 alist_for_each_filter(from
, to
, &std
->bootflows
) {
92 bootflow_remove(from
);
96 alist_update_end(&std
->bootflows
, to
);
101 static int bootstd_remove(struct udevice
*dev
)
103 struct bootstd_priv
*priv
= dev_get_priv(dev
);
105 free(priv
->prefixes
);
106 free(priv
->bootdev_order
);
107 bootstd_clear_glob_(priv
);
112 const char *const *const bootstd_get_bootdev_order(struct udevice
*dev
,
115 struct bootstd_priv
*std
= dev_get_priv(dev
);
116 const char *targets
= env_get("boot_targets");
119 log_debug("- targets %s %p\n", targets
, std
->bootdev_order
);
120 if (targets
&& *targets
) {
121 str_free_list(std
->env_order
);
122 std
->env_order
= str_to_list(targets
);
123 if (!std
->env_order
) {
127 return std
->env_order
;
130 return std
->bootdev_order
;
133 const char *const *const bootstd_get_prefixes(struct udevice
*dev
)
135 struct bootstd_priv
*std
= dev_get_priv(dev
);
137 return std
->prefixes
? std
->prefixes
: default_prefixes
;
140 struct bootstd_priv
*bootstd_try_priv(void)
144 dev
= uclass_try_first_device(UCLASS_BOOTSTD
);
145 if (!dev
|| !device_active(dev
))
148 return dev_get_priv(dev
);
151 int bootstd_get_priv(struct bootstd_priv
**stdp
)
156 ret
= uclass_first_device_err(UCLASS_BOOTSTD
, &dev
);
159 *stdp
= dev_get_priv(dev
);
164 static int bootstd_probe(struct udevice
*dev
)
166 struct bootstd_priv
*std
= dev_get_priv(dev
);
168 alist_init_struct(&std
->bootflows
, struct bootflow
);
173 /* For now, bind the bootmethod device if none are found in the devicetree */
174 int dm_scan_other(bool pre_reloc_only
)
176 struct driver
*drv
= ll_entry_start(struct driver
, driver
);
177 const int n_ents
= ll_entry_count(struct driver
, driver
);
178 struct udevice
*dev
, *bootstd
;
181 /* These are not needed before relocation */
182 if (!(gd
->flags
& GD_FLG_RELOC
))
185 /* Create a bootstd device if needed */
186 uclass_find_first_device(UCLASS_BOOTSTD
, &bootstd
);
188 ret
= device_bind_driver(gd
->dm_root
, "bootstd_drv", "bootstd",
191 return log_msg_ret("bootstd", ret
);
194 /* If there are no bootmeth devices, create them */
195 uclass_find_first_device(UCLASS_BOOTMETH
, &dev
);
199 for (i
= 0; i
< n_ents
; i
++, drv
++) {
200 if (drv
->id
== UCLASS_BOOTMETH
) {
201 const char *name
= drv
->name
;
203 if (!strncmp("bootmeth_", name
, 9))
205 ret
= device_bind(bootstd
, drv
, name
, 0, ofnode_null(),
208 return log_msg_ret("meth", ret
);
215 static const struct udevice_id bootstd_ids
[] = {
216 { .compatible
= "u-boot,boot-std" },
220 U_BOOT_DRIVER(bootstd_drv
) = {
221 .id
= UCLASS_BOOTSTD
,
222 .name
= "bootstd_drv",
223 .of_to_plat
= bootstd_of_to_plat
,
224 .probe
= bootstd_probe
,
225 .remove
= bootstd_remove
,
226 .of_match
= bootstd_ids
,
227 .priv_auto
= sizeof(struct bootstd_priv
),
230 UCLASS_DRIVER(bootstd
) = {
231 .id
= UCLASS_BOOTSTD
,
233 #if CONFIG_IS_ENABLED(OF_REAL)
234 .post_bind
= dm_scan_fdt_dev
,