blob: 8c0fd4e63c32396be667aa619831de3415682b39 [file] [log] [blame]
Simon Glass08ad13e2022-04-24 23:31:06 -06001// 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
Simon Glass199f5882024-11-15 16:19:12 -07009#include <alist.h>
Simon Glass08ad13e2022-04-24 23:31:06 -060010#include <bootflow.h>
11#include <bootstd.h>
12#include <dm.h>
Simon Glassa1bcafb2023-01-17 10:47:15 -070013#include <env.h>
Simon Glass08ad13e2022-04-24 23:31:06 -060014#include <log.h>
15#include <malloc.h>
16#include <dm/device-internal.h>
17#include <dm/lists.h>
18#include <dm/read.h>
19#include <dm/uclass-internal.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
23/* These are used if filename-prefixes is not present */
24const char *const default_prefixes[] = {"/", "/boot/", NULL};
25
26static int bootstd_of_to_plat(struct udevice *dev)
27{
28 struct bootstd_priv *priv = dev_get_priv(dev);
29 int ret;
30
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",
34 &priv->prefixes);
35 dev_read_string_list(dev, "bootdev-order",
36 &priv->bootdev_order);
Simon Glassd92bcc42023-01-06 08:52:42 -060037
38 priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme");
Simon Glass08ad13e2022-04-24 23:31:06 -060039 }
40
41 return 0;
42}
43
44static void bootstd_clear_glob_(struct bootstd_priv *priv)
45{
Simon Glass199f5882024-11-15 16:19:12 -070046 struct bootflow *bflow;
Simon Glass08ad13e2022-04-24 23:31:06 -060047
Simon Glass199f5882024-11-15 16:19:12 -070048 alist_for_each(bflow, &priv->bootflows)
Simon Glass03fcbf92022-04-24 23:31:09 -060049 bootflow_remove(bflow);
Simon Glass199f5882024-11-15 16:19:12 -070050 alist_empty(&priv->bootflows);
Simon Glass08ad13e2022-04-24 23:31:06 -060051}
52
53void bootstd_clear_glob(void)
54{
55 struct bootstd_priv *std;
56
57 if (bootstd_get_priv(&std))
58 return;
59
60 bootstd_clear_glob_(std);
61}
62
Simon Glassc01d83f2024-11-15 16:19:08 -070063int bootstd_add_bootflow(struct bootflow *bflow)
64{
65 struct bootstd_priv *std;
Simon Glassc01d83f2024-11-15 16:19:08 -070066 int ret;
67
68 ret = bootstd_get_priv(&std);
69 if (ret)
70 return ret;
71
Simon Glass199f5882024-11-15 16:19:12 -070072 ret = std->bootflows.count;
73 bflow = alist_add(&std->bootflows, *bflow);
74 if (!bflow)
75 return log_msg_ret("bf2", -ENOMEM);
Simon Glassc01d83f2024-11-15 16:19:08 -070076
Simon Glass199f5882024-11-15 16:19:12 -070077 return ret;
Simon Glassc01d83f2024-11-15 16:19:08 -070078}
79
Simon Glass346ab5d2024-11-15 16:19:09 -070080int bootstd_clear_bootflows_for_bootdev(struct udevice *dev)
81{
Simon Glass1d8f8642024-11-15 16:19:11 -070082 struct bootstd_priv *std = bootstd_try_priv();
Simon Glass199f5882024-11-15 16:19:12 -070083 struct bootflow *from, *to;
Simon Glass346ab5d2024-11-15 16:19:09 -070084
Simon Glass199f5882024-11-15 16:19:12 -070085 /* if bootstd does not exist we cannot have any bootflows */
86 if (!std)
87 return 0;
Simon Glass346ab5d2024-11-15 16:19:09 -070088
Simon Glass199f5882024-11-15 16:19:12 -070089 /* Drop any bootflows that mention this dev */
90 alist_for_each_filter(from, to, &std->bootflows) {
91 if (from->dev == dev)
92 bootflow_remove(from);
93 else
94 *to++ = *from;
Simon Glass346ab5d2024-11-15 16:19:09 -070095 }
Simon Glass199f5882024-11-15 16:19:12 -070096 alist_update_end(&std->bootflows, to);
Simon Glass346ab5d2024-11-15 16:19:09 -070097
98 return 0;
99}
100
Simon Glass08ad13e2022-04-24 23:31:06 -0600101static int bootstd_remove(struct udevice *dev)
102{
103 struct bootstd_priv *priv = dev_get_priv(dev);
104
105 free(priv->prefixes);
106 free(priv->bootdev_order);
107 bootstd_clear_glob_(priv);
108
109 return 0;
110}
111
Simon Glassa1bcafb2023-01-17 10:47:15 -0700112const char *const *const bootstd_get_bootdev_order(struct udevice *dev,
113 bool *okp)
Simon Glass08ad13e2022-04-24 23:31:06 -0600114{
115 struct bootstd_priv *std = dev_get_priv(dev);
Simon Glassa1bcafb2023-01-17 10:47:15 -0700116 const char *targets = env_get("boot_targets");
117
118 *okp = true;
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) {
124 *okp = false;
125 return NULL;
126 }
127 return std->env_order;
128 }
Simon Glass08ad13e2022-04-24 23:31:06 -0600129
130 return std->bootdev_order;
131}
132
133const char *const *const bootstd_get_prefixes(struct udevice *dev)
134{
135 struct bootstd_priv *std = dev_get_priv(dev);
136
137 return std->prefixes ? std->prefixes : default_prefixes;
138}
139
Simon Glass2bcd9ea2024-11-15 16:19:10 -0700140struct bootstd_priv *bootstd_try_priv(void)
141{
142 struct udevice *dev;
143
144 dev = uclass_try_first_device(UCLASS_BOOTSTD);
145 if (!dev || !device_active(dev))
146 return NULL;
147
148 return dev_get_priv(dev);
149}
150
Simon Glass08ad13e2022-04-24 23:31:06 -0600151int bootstd_get_priv(struct bootstd_priv **stdp)
152{
153 struct udevice *dev;
154 int ret;
155
156 ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
157 if (ret)
158 return ret;
159 *stdp = dev_get_priv(dev);
160
161 return 0;
162}
163
164static int bootstd_probe(struct udevice *dev)
165{
166 struct bootstd_priv *std = dev_get_priv(dev);
167
Simon Glass199f5882024-11-15 16:19:12 -0700168 alist_init_struct(&std->bootflows, struct bootflow);
Simon Glass08ad13e2022-04-24 23:31:06 -0600169
170 return 0;
171}
172
Heinrich Schuchardt646c8162024-10-08 22:46:14 +0200173/* For now, bind the bootmethod device if none are found in the devicetree */
Simon Glass08ad13e2022-04-24 23:31:06 -0600174int dm_scan_other(bool pre_reloc_only)
175{
Simon Glass4b508b82022-04-24 23:31:08 -0600176 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;
179 int i, ret;
Simon Glass08ad13e2022-04-24 23:31:06 -0600180
181 /* These are not needed before relocation */
182 if (!(gd->flags & GD_FLG_RELOC))
183 return 0;
184
185 /* Create a bootstd device if needed */
186 uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
187 if (!bootstd) {
188 ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
189 &bootstd);
190 if (ret)
191 return log_msg_ret("bootstd", ret);
192 }
193
Simon Glass4b508b82022-04-24 23:31:08 -0600194 /* If there are no bootmeth devices, create them */
195 uclass_find_first_device(UCLASS_BOOTMETH, &dev);
196 if (dev)
197 return 0;
198
199 for (i = 0; i < n_ents; i++, drv++) {
Simon Glass771a2442022-07-30 15:52:28 -0600200 if (drv->id == UCLASS_BOOTMETH) {
Simon Glass4b508b82022-04-24 23:31:08 -0600201 const char *name = drv->name;
202
203 if (!strncmp("bootmeth_", name, 9))
204 name += 9;
205 ret = device_bind(bootstd, drv, name, 0, ofnode_null(),
206 &dev);
207 if (ret)
208 return log_msg_ret("meth", ret);
209 }
210 }
211
Simon Glass08ad13e2022-04-24 23:31:06 -0600212 return 0;
213}
214
215static const struct udevice_id bootstd_ids[] = {
216 { .compatible = "u-boot,boot-std" },
217 { }
218};
219
220U_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),
228};
229
230UCLASS_DRIVER(bootstd) = {
231 .id = UCLASS_BOOTSTD,
232 .name = "bootstd",
233#if CONFIG_IS_ENABLED(OF_REAL)
234 .post_bind = dm_scan_fdt_dev,
235#endif
236};