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