blob: 5de8efce19a5482bc25b27db525baf7c270f266e [file] [log] [blame]
Simon Glassef5e3892022-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 Glassef5e3892022-04-24 23:31:06 -06009#include <bootflow.h>
10#include <bootstd.h>
11#include <dm.h>
Simon Glass6a6638f2023-01-17 10:47:15 -070012#include <env.h>
Simon Glassef5e3892022-04-24 23:31:06 -060013#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
20DECLARE_GLOBAL_DATA_PTR;
21
22/* These are used if filename-prefixes is not present */
23const char *const default_prefixes[] = {"/", "/boot/", NULL};
24
25static int bootstd_of_to_plat(struct udevice *dev)
26{
27 struct bootstd_priv *priv = dev_get_priv(dev);
28 int ret;
29
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",
33 &priv->prefixes);
34 dev_read_string_list(dev, "bootdev-order",
35 &priv->bootdev_order);
Simon Glasse64c2952023-01-06 08:52:42 -060036
37 priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme");
Simon Glassef5e3892022-04-24 23:31:06 -060038 }
39
40 return 0;
41}
42
43static void bootstd_clear_glob_(struct bootstd_priv *priv)
44{
45 while (!list_empty(&priv->glob_head)) {
46 struct bootflow *bflow;
47
48 bflow = list_first_entry(&priv->glob_head, struct bootflow,
49 glob_node);
Simon Glassa8f5be12022-04-24 23:31:09 -060050 bootflow_remove(bflow);
Simon Glassef5e3892022-04-24 23:31:06 -060051 }
52}
53
54void bootstd_clear_glob(void)
55{
56 struct bootstd_priv *std;
57
58 if (bootstd_get_priv(&std))
59 return;
60
61 bootstd_clear_glob_(std);
62}
63
64static int bootstd_remove(struct udevice *dev)
65{
66 struct bootstd_priv *priv = dev_get_priv(dev);
67
68 free(priv->prefixes);
69 free(priv->bootdev_order);
70 bootstd_clear_glob_(priv);
71
72 return 0;
73}
74
Simon Glass6a6638f2023-01-17 10:47:15 -070075const char *const *const bootstd_get_bootdev_order(struct udevice *dev,
76 bool *okp)
Simon Glassef5e3892022-04-24 23:31:06 -060077{
78 struct bootstd_priv *std = dev_get_priv(dev);
Simon Glass6a6638f2023-01-17 10:47:15 -070079 const char *targets = env_get("boot_targets");
80
81 *okp = true;
82 log_debug("- targets %s %p\n", targets, std->bootdev_order);
83 if (targets && *targets) {
84 str_free_list(std->env_order);
85 std->env_order = str_to_list(targets);
86 if (!std->env_order) {
87 *okp = false;
88 return NULL;
89 }
90 return std->env_order;
91 }
Simon Glassef5e3892022-04-24 23:31:06 -060092
93 return std->bootdev_order;
94}
95
96const char *const *const bootstd_get_prefixes(struct udevice *dev)
97{
98 struct bootstd_priv *std = dev_get_priv(dev);
99
100 return std->prefixes ? std->prefixes : default_prefixes;
101}
102
103int bootstd_get_priv(struct bootstd_priv **stdp)
104{
105 struct udevice *dev;
106 int ret;
107
108 ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
109 if (ret)
110 return ret;
111 *stdp = dev_get_priv(dev);
112
113 return 0;
114}
115
116static int bootstd_probe(struct udevice *dev)
117{
118 struct bootstd_priv *std = dev_get_priv(dev);
119
120 INIT_LIST_HEAD(&std->glob_head);
121
122 return 0;
123}
124
125/* For now, bind the boormethod device if none are found in the devicetree */
126int dm_scan_other(bool pre_reloc_only)
127{
Simon Glassa950d312022-04-24 23:31:08 -0600128 struct driver *drv = ll_entry_start(struct driver, driver);
129 const int n_ents = ll_entry_count(struct driver, driver);
130 struct udevice *dev, *bootstd;
131 int i, ret;
Simon Glassef5e3892022-04-24 23:31:06 -0600132
133 /* These are not needed before relocation */
134 if (!(gd->flags & GD_FLG_RELOC))
135 return 0;
136
137 /* Create a bootstd device if needed */
138 uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
139 if (!bootstd) {
140 ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
141 &bootstd);
142 if (ret)
143 return log_msg_ret("bootstd", ret);
144 }
145
Simon Glassa950d312022-04-24 23:31:08 -0600146 /* If there are no bootmeth devices, create them */
147 uclass_find_first_device(UCLASS_BOOTMETH, &dev);
148 if (dev)
149 return 0;
150
151 for (i = 0; i < n_ents; i++, drv++) {
Simon Glassbd18b692022-07-30 15:52:28 -0600152 if (drv->id == UCLASS_BOOTMETH) {
Simon Glassa950d312022-04-24 23:31:08 -0600153 const char *name = drv->name;
154
155 if (!strncmp("bootmeth_", name, 9))
156 name += 9;
157 ret = device_bind(bootstd, drv, name, 0, ofnode_null(),
158 &dev);
159 if (ret)
160 return log_msg_ret("meth", ret);
161 }
162 }
163
Simon Glassef5e3892022-04-24 23:31:06 -0600164 return 0;
165}
166
167static const struct udevice_id bootstd_ids[] = {
168 { .compatible = "u-boot,boot-std" },
169 { }
170};
171
172U_BOOT_DRIVER(bootstd_drv) = {
173 .id = UCLASS_BOOTSTD,
174 .name = "bootstd_drv",
175 .of_to_plat = bootstd_of_to_plat,
176 .probe = bootstd_probe,
177 .remove = bootstd_remove,
178 .of_match = bootstd_ids,
179 .priv_auto = sizeof(struct bootstd_priv),
180};
181
182UCLASS_DRIVER(bootstd) = {
183 .id = UCLASS_BOOTSTD,
184 .name = "bootstd",
185#if CONFIG_IS_ENABLED(OF_REAL)
186 .post_bind = dm_scan_fdt_dev,
187#endif
188};