blob: 12c90c4ec1ba5f3e6267b9d648960584906812ce [file] [log] [blame]
Simon Glass017656e2022-04-24 23:31:07 -06001/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright 2021 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#ifndef __bootdev_h
8#define __bootdev_h
9
Simon Glassceace3a2023-11-18 14:04:53 -070010#include <dm/uclass-id.h>
Simon Glass017656e2022-04-24 23:31:07 -060011#include <linux/list.h>
12
13struct bootflow;
14struct bootflow_iter;
Simon Glass5acb97a2023-01-17 10:47:33 -070015struct bootstd_priv;
Simon Glass017656e2022-04-24 23:31:07 -060016struct udevice;
17
18/**
19 * enum bootdev_prio_t - priority of each bootdev
20 *
21 * These values are associated with each bootdev and set up by the driver.
22 *
23 * Smallest value is the highest priority. By default, bootdevs are scanned from
24 * highest to lowest priority
Simon Glass7e1f6a42023-01-17 10:48:08 -070025 *
26 * BOOTDEVP_0_NONE: Invalid value, do not use
27 * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before
28 * starting any bootflow scan
29 * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and
30 * generally very quick to access, e.g. less than 100ms
31 * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but
32 * take a significant fraction of a second to access
33 * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus
34 * enumeration to find, but this enumeration happens quickly, typically under
35 * 100ms
36 * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus
37 * enumeration to find. The enumeration takes significant fraction of a second
38 * to complete
39 * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily
40 * available. Typically used for an internal Ethernet device
41 * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time
42 * to start up, or are less desirable. Typically used for secondary Ethernet
43 * devices. Note that USB ethernet devices are found during USB enumeration,
44 * so do not use this priority
Simon Glass017656e2022-04-24 23:31:07 -060045 */
46enum bootdev_prio_t {
Simon Glass7e1f6a42023-01-17 10:48:08 -070047 BOOTDEVP_0_NONE,
48 BOOTDEVP_1_PRE_SCAN,
49 BOOTDEVP_2_INTERNAL_FAST,
50 BOOTDEVP_3_INTERNAL_SLOW,
51 BOOTDEVP_4_SCAN_FAST,
52 BOOTDEVP_5_SCAN_SLOW,
53 BOOTDEVP_6_NET_BASE,
54 BOOTDEVP_7_NET_FALLBACK,
Simon Glass017656e2022-04-24 23:31:07 -060055
56 BOOTDEVP_COUNT,
57};
58
Simon Glass5acb97a2023-01-17 10:47:33 -070059struct bootdev_hunter;
60
61/**
62 * bootdev_hunter_func - function to probe for bootdevs of a given type
63 *
64 * This should hunt around for bootdevs of the given type, binding them as it
65 * finds them. This may involve bus enumeration, etc.
66 *
67 * @info: Info structure describing this hunter
68 * @show: true to show information from the hunter
Tony Dinh81356b42023-11-02 11:51:15 -070069 * Returns: 0 if OK, -ENOENT on device not found, otherwise -ve on error
Simon Glass5acb97a2023-01-17 10:47:33 -070070 */
71typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show);
72
73/**
74 * struct bootdev_hunter - information about how to hunt for bootdevs
75 *
76 * @prio: Scanning priority of this hunter
77 * @uclass: Uclass ID for the media associated with this bootdev
78 * @drv: bootdev driver for the things found by this hunter
79 * @hunt: Function to call to hunt for bootdevs of this type (NULL if none)
80 *
81 * Some bootdevs are not visible until other devices are enumerated. For
82 * example, USB bootdevs only appear when the USB bus is enumerated.
83 *
84 * On the other hand, we don't always want to enumerate all the buses just to
85 * find the first valid bootdev. Ideally we want to work through them in
86 * priority order, so that the fastest bootdevs are discovered first.
87 *
88 * This struct holds information about the bootdev so we can determine the probe
89 * order and how to hunt for bootdevs of this type
90 */
91struct bootdev_hunter {
92 enum bootdev_prio_t prio;
93 enum uclass_id uclass;
94 struct driver *drv;
95 bootdev_hunter_func hunt;
96};
97
98/* declare a new bootdev hunter */
99#define BOOTDEV_HUNTER(__name) \
100 ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter)
101
102/* access a bootdev hunter by name */
103#define BOOTDEV_HUNTER_GET(__name) \
104 ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter)
105
Simon Glass017656e2022-04-24 23:31:07 -0600106/**
107 * struct bootdev_uc_plat - uclass information about a bootdev
108 *
109 * This is attached to each device in the bootdev uclass and accessible via
110 * dev_get_uclass_plat(dev)
111 *
Simon Glass017656e2022-04-24 23:31:07 -0600112 * @piro: Priority of this bootdev
113 */
114struct bootdev_uc_plat {
Simon Glass017656e2022-04-24 23:31:07 -0600115 enum bootdev_prio_t prio;
116};
117
118/** struct bootdev_ops - Operations for the bootdev uclass */
119struct bootdev_ops {
120 /**
Simon Glassd6e39d12023-01-17 10:47:26 -0700121 * get_bootflow() - get a bootflow (optional)
122 *
123 * If this is NULL then the default implementaton is used, which is
124 * default_get_bootflow()
Simon Glass017656e2022-04-24 23:31:07 -0600125 *
126 * @dev: Bootflow device to check
127 * @iter: Provides current dev, part, method to get. Should update
128 * max_part if there is a partition table. Should update state,
129 * subdir, fname, buf, size according to progress
130 * @bflow: Updated bootflow if found
131 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this
132 * device, -ENOSYS if this device doesn't support bootflows,
133 * other -ve value on other error
134 */
135 int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter,
136 struct bootflow *bflow);
137};
138
139#define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops)
140
141/**
142 * bootdev_get_bootflow() - get a bootflow
143 *
144 * @dev: Bootflow device to check
145 * @iter: Provides current part, method to get
146 * @bflow: Returns bootflow if found
147 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device,
148 * -ENOSYS if this device doesn't support bootflows, other -ve value on
149 * other error
150 */
151int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
152 struct bootflow *bflow);
153
154/**
155 * bootdev_bind() - Bind a new named bootdev device
156 *
157 * @parent: Parent of the new device
158 * @drv_name: Driver name to use for the bootdev device
159 * @name: Name for the device (parent name is prepended)
160 * @devp: the new device (which has not been probed)
161 */
162int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name,
163 struct udevice **devp);
164
165/**
166 * bootdev_find_in_blk() - Find a bootdev in a block device
167 *
168 * @dev: Bootflow device associated with this block device
169 * @blk: Block device to search
170 * @iter: Provides current dev, part, method to get. Should update
171 * max_part if there is a partition table
172 * @bflow: On entry, provides information about the partition and device to
173 * check. On exit, returns bootflow if found
174 * Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
175 */
176int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk,
177 struct bootflow_iter *iter, struct bootflow *bflow);
178
179/**
180 * bootdev_list() - List all available bootdevs
181 *
182 * @probe: true to probe devices, false to leave them as is
183 */
184void bootdev_list(bool probe);
185
186/**
Simon Glass017656e2022-04-24 23:31:07 -0600187 * bootdev_first_bootflow() - Get the first bootflow from a bootdev
188 *
189 * Returns the first bootflow attached to a bootdev
190 *
191 * @dev: bootdev device
192 * @bflowp: Returns a pointer to the bootflow
193 * Return: 0 if found, -ENOENT if there are no bootflows
194 */
195int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp);
196
197/**
198 * bootdev_next_bootflow() - Get the next bootflow from a bootdev
199 *
200 * Returns the next bootflow attached to a bootdev
201 *
202 * @bflowp: On entry, the last bootflow returned , e.g. from
203 * bootdev_first_bootflow()
204 * Return: 0 if found, -ENOENT if there are no more bootflows
205 */
206int bootdev_next_bootflow(struct bootflow **bflowp);
207
208/**
209 * bootdev_find_by_label() - Look up a bootdev by label
210 *
211 * Each bootdev has a label which contains the media-uclass name and a number,
212 * e.g. 'mmc2'. This looks up the label and returns the associated bootdev
213 *
214 * The lookup is performed based on the media device's sequence number. So for
215 * 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2.
216 *
217 * @label: Label to look up (e.g. "mmc1" or "mmc0")
218 * @devp: Returns the bootdev device found, or NULL if none (note it does not
219 * return the media device, but its bootdev child)
Simon Glasse22fe922023-01-17 10:48:05 -0700220 * @method_flagsp: If non-NULL, returns any flags implied by the label
221 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
Simon Glass017656e2022-04-24 23:31:07 -0600222 * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
Simon Glasse22fe922023-01-17 10:48:05 -0700223 * -ENOENT if there is no device with that number
Simon Glass017656e2022-04-24 23:31:07 -0600224 */
Simon Glasse22fe922023-01-17 10:48:05 -0700225int bootdev_find_by_label(const char *label, struct udevice **devp,
226 int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600227
228/**
229 * bootdev_find_by_any() - Find a bootdev by name, label or sequence
230 *
231 * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find
232 * @devp: returns the device found, on success
Simon Glasse22fe922023-01-17 10:48:05 -0700233 * @method_flagsp: If non-NULL, returns any flags implied by the label
234 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
Simon Glass4108c6b2023-04-24 13:49:47 +1200235 * Return: 0 if OK, -EPFNOSUPPORT if the uclass is not supported by this board,
Simon Glasse22fe922023-01-17 10:48:05 -0700236 * -ENOENT if there is no device with that number
Simon Glass017656e2022-04-24 23:31:07 -0600237 */
Simon Glasse22fe922023-01-17 10:48:05 -0700238int bootdev_find_by_any(const char *name, struct udevice **devp,
239 int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600240
241/**
Simon Glass484e4072023-01-17 10:48:14 -0700242 * bootdev_setup_iter() - Set up iteration through bootdevs
Simon Glass017656e2022-04-24 23:31:07 -0600243 *
Simon Glassba3d5372023-01-17 10:48:15 -0700244 * This sets up the an interation, based on the provided device or label. If
245 * neither is provided, the iteration is based on the priority of each bootdev,
246 * the * bootdev-order property in the bootstd node (or the boot_targets env
247 * var).
Simon Glass017656e2022-04-24 23:31:07 -0600248 *
249 * @iter: Iterator to update with the order
Simon Glassba3d5372023-01-17 10:48:15 -0700250 * @label: label to scan, or NULL to scan all
Simon Glass017656e2022-04-24 23:31:07 -0600251 * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
252 * device to scan. Returns the first device to use, which is the passed-in
253 * @devp if it was non-NULL
Simon Glass484e4072023-01-17 10:48:14 -0700254 * @method_flagsp: If non-NULL, returns any flags implied by the label
255 * (enum bootflow_meth_flags_t), 0 if none
Simon Glass017656e2022-04-24 23:31:07 -0600256 * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
257 * on other error
258 */
Simon Glassba3d5372023-01-17 10:48:15 -0700259int bootdev_setup_iter(struct bootflow_iter *iter, const char *label,
260 struct udevice **devp, int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600261
Simon Glass5acb97a2023-01-17 10:47:33 -0700262/**
263 * bootdev_list_hunters() - List the available bootdev hunters
264 *
265 * These provide a way to find new bootdevs by enumerating buses, etc. This
266 * function lists the available hunters
267 *
268 * @std: Pointer to bootstd private info
269 */
270void bootdev_list_hunters(struct bootstd_priv *std);
271
Simon Glass1248d2b2023-01-17 10:47:34 -0700272/**
273 * bootdev_hunt() - Hunt for bootdevs matching a particular spec
274 *
275 * This runs the selected hunter (or all if @spec is NULL) to try to find new
276 * bootdevs.
277 *
278 * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must
279 * match a uclass name so that the hunter can be determined. Any trailing number
280 * is ignored
281 * @show: true to show each hunter before using it
282 * Returns: 0 if OK, -ve on error
283 */
284int bootdev_hunt(const char *spec, bool show);
285
Simon Glass3e9f6be2023-01-17 10:48:07 -0700286/**
287 * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority
288 *
289 * This runs all hunters which can find bootdevs of the given priority.
290 *
291 * @prio: Priority to use
292 * @show: true to show each hunter as it is used
293 * Returns: 0 if OK, -ve on error
294 */
295int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
296
Simon Glassde567b12023-01-17 10:48:09 -0700297/**
Simon Glass62b03cc2023-09-20 07:29:49 -0600298 * bootdev_unhunt() - Mark a device as needing to be hunted again
299 *
300 * @id: uclass ID to update
301 * Return: 0 if done, -EALREADY if already in this state, -ENOENT if no hunter
302 * found for that uclass
303 */
304int bootdev_unhunt(enum uclass_id id);
305
306/**
Simon Glassde567b12023-01-17 10:48:09 -0700307 * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
308 *
309 * Runs the hunter for the label, then tries to find the bootdev, possible
310 * created by the hunter
311 *
312 * @label: Label to look up (e.g. "mmc1" or "mmc0")
313 * @devp: Returns the bootdev device found, or NULL if none (note it does not
314 * return the media device, but its bootdev child)
315 * @method_flagsp: If non-NULL, returns any flags implied by the label
316 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
317 * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
318 * -ENOENT if there is no device with that number
319 */
320int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
321 int *method_flagsp);
322
Simon Glassac06b26a2023-01-17 10:48:10 -0700323/**
324 * bootdev_next_label() - Move to the next bootdev in the label sequence
325 *
326 * Looks through the remaining labels until it finds one that matches a bootdev.
327 * Bootdev scanners are used as needed. For example a label "mmc1" results in
328 * running the "mmc" bootdrv.
329 *
330 * @iter: Interation info, containing iter->cur_label
331 * @devp: New bootdev found, if any was found
332 * @method_flagsp: If non-NULL, returns any flags implied by the label
333 * (enum bootflow_meth_flags_t), 0 if none
334 * Returns 0 if OK, -ENODEV if no bootdev was found
335 */
336int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
337 int *method_flagsp);
338
Simon Glass660a9952023-01-17 10:48:11 -0700339/**
340 * bootdev_next_prio() - Find the next bootdev in priority order
341 *
342 * This moves @devp to the next bootdev with the current priority. If there is
343 * none, then it moves to the next priority and scans for new bootdevs there.
344 *
345 * @iter: Interation info, containing iter->cur_prio
346 * @devp: On entry this is the previous bootdev that was considered. On exit
347 * this is the new bootdev, if any was found
348 * Returns 0 on success (*devp is updated), -ENODEV if there are no more
349 * bootdevs at any priority
350 */
351int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp);
352
Simon Glass017656e2022-04-24 23:31:07 -0600353#if CONFIG_IS_ENABLED(BOOTSTD)
354/**
Simon Glassb1dc36a2023-01-17 10:47:25 -0700355 * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
356 *
Simon Glassb1d581d2023-07-30 11:15:14 -0600357 * Please use bootdev_setup_for_sibling_blk() instead since it supports multiple
Simon Glassb1dc36a2023-01-17 10:47:25 -0700358 * (child) block devices for each media device.
Simon Glass017656e2022-04-24 23:31:07 -0600359 *
360 * Creates a bootdev device as a child of @parent. This should be called from
361 * the driver's bind() method or its uclass' post_bind() method.
362 *
363 * If a child bootdev already exists, this function does nothing
364 *
365 * @parent: Parent device (e.g. MMC or Ethernet)
366 * @drv_name: Name of bootdev driver to bind
367 * Return: 0 if OK, -ve on error
368 */
369int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name);
370
Simon Glass37804f32024-09-20 09:24:26 +0200371#if CONFIG_IS_ENABLED(BOOTSTD)
Simon Glass017656e2022-04-24 23:31:07 -0600372/**
Simon Glassb1d581d2023-07-30 11:15:14 -0600373 * bootdev_setup_for_sibling_blk() - Bind a new bootdev device for a blk device
Simon Glass017656e2022-04-24 23:31:07 -0600374 *
375 * Creates a bootdev device as a sibling of @blk. This should be called from
376 * the driver's bind() method or its uclass' post_bind() method, at the same
377 * time as the bould device is bound
378 *
379 * If a device of the same name already exists, this function does nothing
380 *
381 * @parent: Parent device (e.g. MMC or Ethernet)
382 * @drv_name: Name of bootdev driver to bind
383 * Return: 0 if OK, -ve on error
384 */
Simon Glassb1d581d2023-07-30 11:15:14 -0600385int bootdev_setup_for_sibling_blk(struct udevice *blk, const char *drv_name);
Simon Glass37804f32024-09-20 09:24:26 +0200386#else
387static int bootdev_setup_for_sibling_blk(struct udevice *blk,
388 const char *drv_name)
389{
390 return 0;
391}
392#endif
Simon Glass017656e2022-04-24 23:31:07 -0600393
394/**
395 * bootdev_get_sibling_blk() - Locate the block device for a bootdev
396 *
397 * @dev: bootdev to check
398 * @blkp: returns associated block device
399 * Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other
400 * error
401 */
402int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp);
403
404/**
Simon Glassc8694782024-11-15 16:19:24 -0700405 * bootdev_get_from_blk() - Get the bootdev given a block device
406 *
407 * @blk: Block device to check
408 * @bootdebp: Returns the bootdev found, if any
409 * Return 0 if OK, -ve on error
410 */
411int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp);
412
413/**
Simon Glass017656e2022-04-24 23:31:07 -0600414 * bootdev_unbind_dev() - Unbind a bootdev device
415 *
416 * Remove and unbind a bootdev device which is a child of @parent. This should
417 * be called from the driver's unbind() method or its uclass' post_bind()
418 * method.
419 *
420 * @parent: Parent device (e.g. MMC or Ethernet)
421 * Return: 0 if OK, -ve on error
422 */
423int bootdev_unbind_dev(struct udevice *parent);
424#else
425static inline int bootdev_setup_for_dev(struct udevice *parent,
426 const char *drv_name)
427{
428 return 0;
429}
430
Simon Glassb1d581d2023-07-30 11:15:14 -0600431static inline int bootdev_setup_for_sibling_blk(struct udevice *blk,
432 const char *drv_name)
Simon Glass017656e2022-04-24 23:31:07 -0600433{
434 return 0;
435}
436
437static inline int bootdev_unbind_dev(struct udevice *parent)
438{
439 return 0;
440}
441#endif
442
443#endif