blob: b079a91b5b7f337e03211ad4369b8341933e944f [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
10#include <linux/list.h>
11
12struct bootflow;
13struct bootflow_iter;
Simon Glass5acb97a2023-01-17 10:47:33 -070014struct bootstd_priv;
Simon Glass017656e2022-04-24 23:31:07 -060015struct udevice;
16
17/**
18 * enum bootdev_prio_t - priority of each bootdev
19 *
20 * These values are associated with each bootdev and set up by the driver.
21 *
22 * Smallest value is the highest priority. By default, bootdevs are scanned from
23 * highest to lowest priority
Simon Glass7e1f6a42023-01-17 10:48:08 -070024 *
25 * BOOTDEVP_0_NONE: Invalid value, do not use
26 * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before
27 * starting any bootflow scan
28 * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and
29 * generally very quick to access, e.g. less than 100ms
30 * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but
31 * take a significant fraction of a second to access
32 * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus
33 * enumeration to find, but this enumeration happens quickly, typically under
34 * 100ms
35 * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus
36 * enumeration to find. The enumeration takes significant fraction of a second
37 * to complete
38 * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily
39 * available. Typically used for an internal Ethernet device
40 * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time
41 * to start up, or are less desirable. Typically used for secondary Ethernet
42 * devices. Note that USB ethernet devices are found during USB enumeration,
43 * so do not use this priority
Simon Glass017656e2022-04-24 23:31:07 -060044 */
45enum bootdev_prio_t {
Simon Glass7e1f6a42023-01-17 10:48:08 -070046 BOOTDEVP_0_NONE,
47 BOOTDEVP_1_PRE_SCAN,
48 BOOTDEVP_2_INTERNAL_FAST,
49 BOOTDEVP_3_INTERNAL_SLOW,
50 BOOTDEVP_4_SCAN_FAST,
51 BOOTDEVP_5_SCAN_SLOW,
52 BOOTDEVP_6_NET_BASE,
53 BOOTDEVP_7_NET_FALLBACK,
Simon Glass017656e2022-04-24 23:31:07 -060054
55 BOOTDEVP_COUNT,
56};
57
Simon Glass5acb97a2023-01-17 10:47:33 -070058struct bootdev_hunter;
59
60/**
61 * bootdev_hunter_func - function to probe for bootdevs of a given type
62 *
63 * This should hunt around for bootdevs of the given type, binding them as it
64 * finds them. This may involve bus enumeration, etc.
65 *
66 * @info: Info structure describing this hunter
67 * @show: true to show information from the hunter
68 * Returns: 0 if OK, -ve on error
69 */
70typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show);
71
72/**
73 * struct bootdev_hunter - information about how to hunt for bootdevs
74 *
75 * @prio: Scanning priority of this hunter
76 * @uclass: Uclass ID for the media associated with this bootdev
77 * @drv: bootdev driver for the things found by this hunter
78 * @hunt: Function to call to hunt for bootdevs of this type (NULL if none)
79 *
80 * Some bootdevs are not visible until other devices are enumerated. For
81 * example, USB bootdevs only appear when the USB bus is enumerated.
82 *
83 * On the other hand, we don't always want to enumerate all the buses just to
84 * find the first valid bootdev. Ideally we want to work through them in
85 * priority order, so that the fastest bootdevs are discovered first.
86 *
87 * This struct holds information about the bootdev so we can determine the probe
88 * order and how to hunt for bootdevs of this type
89 */
90struct bootdev_hunter {
91 enum bootdev_prio_t prio;
92 enum uclass_id uclass;
93 struct driver *drv;
94 bootdev_hunter_func hunt;
95};
96
97/* declare a new bootdev hunter */
98#define BOOTDEV_HUNTER(__name) \
99 ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter)
100
101/* access a bootdev hunter by name */
102#define BOOTDEV_HUNTER_GET(__name) \
103 ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter)
104
Simon Glass017656e2022-04-24 23:31:07 -0600105/**
106 * struct bootdev_uc_plat - uclass information about a bootdev
107 *
108 * This is attached to each device in the bootdev uclass and accessible via
109 * dev_get_uclass_plat(dev)
110 *
111 * @bootflows: List of available bootflows for this bootdev
112 * @piro: Priority of this bootdev
113 */
114struct bootdev_uc_plat {
115 struct list_head bootflow_head;
116 enum bootdev_prio_t prio;
117};
118
119/** struct bootdev_ops - Operations for the bootdev uclass */
120struct bootdev_ops {
121 /**
Simon Glassd6e39d12023-01-17 10:47:26 -0700122 * get_bootflow() - get a bootflow (optional)
123 *
124 * If this is NULL then the default implementaton is used, which is
125 * default_get_bootflow()
Simon Glass017656e2022-04-24 23:31:07 -0600126 *
127 * @dev: Bootflow device to check
128 * @iter: Provides current dev, part, method to get. Should update
129 * max_part if there is a partition table. Should update state,
130 * subdir, fname, buf, size according to progress
131 * @bflow: Updated bootflow if found
132 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this
133 * device, -ENOSYS if this device doesn't support bootflows,
134 * other -ve value on other error
135 */
136 int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter,
137 struct bootflow *bflow);
138};
139
140#define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops)
141
142/**
143 * bootdev_get_bootflow() - get a bootflow
144 *
145 * @dev: Bootflow device to check
146 * @iter: Provides current part, method to get
147 * @bflow: Returns bootflow if found
148 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device,
149 * -ENOSYS if this device doesn't support bootflows, other -ve value on
150 * other error
151 */
152int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
153 struct bootflow *bflow);
154
155/**
156 * bootdev_bind() - Bind a new named bootdev device
157 *
158 * @parent: Parent of the new device
159 * @drv_name: Driver name to use for the bootdev device
160 * @name: Name for the device (parent name is prepended)
161 * @devp: the new device (which has not been probed)
162 */
163int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name,
164 struct udevice **devp);
165
166/**
167 * bootdev_find_in_blk() - Find a bootdev in a block device
168 *
169 * @dev: Bootflow device associated with this block device
170 * @blk: Block device to search
171 * @iter: Provides current dev, part, method to get. Should update
172 * max_part if there is a partition table
173 * @bflow: On entry, provides information about the partition and device to
174 * check. On exit, returns bootflow if found
175 * Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
176 */
177int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk,
178 struct bootflow_iter *iter, struct bootflow *bflow);
179
180/**
181 * bootdev_list() - List all available bootdevs
182 *
183 * @probe: true to probe devices, false to leave them as is
184 */
185void bootdev_list(bool probe);
186
187/**
188 * bootdev_clear_bootflows() - Clear bootflows from a bootdev
189 *
190 * Each bootdev maintains a list of discovered bootflows. This provides a
191 * way to clear it. These bootflows are removed from the global list too.
192 *
193 * @dev: bootdev device to update
194 */
195void bootdev_clear_bootflows(struct udevice *dev);
196
197/**
198 * bootdev_add_bootflow() - Add a bootflow to the bootdev's list
199 *
200 * All fields in @bflow must be set up. Note that @bflow->dev is used to add the
201 * bootflow to that device.
202 *
Simon Glass41571582023-07-12 09:04:32 -0600203 * @dev: Bootdev device to add to
Simon Glass017656e2022-04-24 23:31:07 -0600204 * @bflow: Bootflow to add. Note that fields within bflow must be allocated
205 * since this function takes over ownership of these. This functions makes
206 * a copy of @bflow itself (without allocating its fields again), so the
207 * caller must dispose of the memory used by the @bflow pointer itself
208 * Return: 0 if OK, -ENOMEM if out of memory
209 */
210int bootdev_add_bootflow(struct bootflow *bflow);
211
212/**
213 * bootdev_first_bootflow() - Get the first bootflow from a bootdev
214 *
215 * Returns the first bootflow attached to a bootdev
216 *
217 * @dev: bootdev device
218 * @bflowp: Returns a pointer to the bootflow
219 * Return: 0 if found, -ENOENT if there are no bootflows
220 */
221int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp);
222
223/**
224 * bootdev_next_bootflow() - Get the next bootflow from a bootdev
225 *
226 * Returns the next bootflow attached to a bootdev
227 *
228 * @bflowp: On entry, the last bootflow returned , e.g. from
229 * bootdev_first_bootflow()
230 * Return: 0 if found, -ENOENT if there are no more bootflows
231 */
232int bootdev_next_bootflow(struct bootflow **bflowp);
233
234/**
235 * bootdev_find_by_label() - Look up a bootdev by label
236 *
237 * Each bootdev has a label which contains the media-uclass name and a number,
238 * e.g. 'mmc2'. This looks up the label and returns the associated bootdev
239 *
240 * The lookup is performed based on the media device's sequence number. So for
241 * 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2.
242 *
243 * @label: Label to look up (e.g. "mmc1" or "mmc0")
244 * @devp: Returns the bootdev device found, or NULL if none (note it does not
245 * return the media device, but its bootdev child)
Simon Glasse22fe922023-01-17 10:48:05 -0700246 * @method_flagsp: If non-NULL, returns any flags implied by the label
247 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
Simon Glass017656e2022-04-24 23:31:07 -0600248 * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
Simon Glasse22fe922023-01-17 10:48:05 -0700249 * -ENOENT if there is no device with that number
Simon Glass017656e2022-04-24 23:31:07 -0600250 */
Simon Glasse22fe922023-01-17 10:48:05 -0700251int bootdev_find_by_label(const char *label, struct udevice **devp,
252 int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600253
254/**
255 * bootdev_find_by_any() - Find a bootdev by name, label or sequence
256 *
257 * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find
258 * @devp: returns the device found, on success
Simon Glasse22fe922023-01-17 10:48:05 -0700259 * @method_flagsp: If non-NULL, returns any flags implied by the label
260 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
Simon Glass4108c6b2023-04-24 13:49:47 +1200261 * Return: 0 if OK, -EPFNOSUPPORT if the uclass is not supported by this board,
Simon Glasse22fe922023-01-17 10:48:05 -0700262 * -ENOENT if there is no device with that number
Simon Glass017656e2022-04-24 23:31:07 -0600263 */
Simon Glasse22fe922023-01-17 10:48:05 -0700264int bootdev_find_by_any(const char *name, struct udevice **devp,
265 int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600266
267/**
Simon Glass484e4072023-01-17 10:48:14 -0700268 * bootdev_setup_iter() - Set up iteration through bootdevs
Simon Glass017656e2022-04-24 23:31:07 -0600269 *
Simon Glassba3d5372023-01-17 10:48:15 -0700270 * This sets up the an interation, based on the provided device or label. If
271 * neither is provided, the iteration is based on the priority of each bootdev,
272 * the * bootdev-order property in the bootstd node (or the boot_targets env
273 * var).
Simon Glass017656e2022-04-24 23:31:07 -0600274 *
275 * @iter: Iterator to update with the order
Simon Glassba3d5372023-01-17 10:48:15 -0700276 * @label: label to scan, or NULL to scan all
Simon Glass017656e2022-04-24 23:31:07 -0600277 * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
278 * device to scan. Returns the first device to use, which is the passed-in
279 * @devp if it was non-NULL
Simon Glass484e4072023-01-17 10:48:14 -0700280 * @method_flagsp: If non-NULL, returns any flags implied by the label
281 * (enum bootflow_meth_flags_t), 0 if none
Simon Glass017656e2022-04-24 23:31:07 -0600282 * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
283 * on other error
284 */
Simon Glassba3d5372023-01-17 10:48:15 -0700285int bootdev_setup_iter(struct bootflow_iter *iter, const char *label,
286 struct udevice **devp, int *method_flagsp);
Simon Glass017656e2022-04-24 23:31:07 -0600287
Simon Glass5acb97a2023-01-17 10:47:33 -0700288/**
289 * bootdev_list_hunters() - List the available bootdev hunters
290 *
291 * These provide a way to find new bootdevs by enumerating buses, etc. This
292 * function lists the available hunters
293 *
294 * @std: Pointer to bootstd private info
295 */
296void bootdev_list_hunters(struct bootstd_priv *std);
297
Simon Glass1248d2b2023-01-17 10:47:34 -0700298/**
299 * bootdev_hunt() - Hunt for bootdevs matching a particular spec
300 *
301 * This runs the selected hunter (or all if @spec is NULL) to try to find new
302 * bootdevs.
303 *
304 * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must
305 * match a uclass name so that the hunter can be determined. Any trailing number
306 * is ignored
307 * @show: true to show each hunter before using it
308 * Returns: 0 if OK, -ve on error
309 */
310int bootdev_hunt(const char *spec, bool show);
311
Simon Glass3e9f6be2023-01-17 10:48:07 -0700312/**
313 * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority
314 *
315 * This runs all hunters which can find bootdevs of the given priority.
316 *
317 * @prio: Priority to use
318 * @show: true to show each hunter as it is used
319 * Returns: 0 if OK, -ve on error
320 */
321int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
322
Simon Glassde567b12023-01-17 10:48:09 -0700323/**
Simon Glass62b03cc2023-09-20 07:29:49 -0600324 * bootdev_unhunt() - Mark a device as needing to be hunted again
325 *
326 * @id: uclass ID to update
327 * Return: 0 if done, -EALREADY if already in this state, -ENOENT if no hunter
328 * found for that uclass
329 */
330int bootdev_unhunt(enum uclass_id id);
331
332/**
Simon Glassde567b12023-01-17 10:48:09 -0700333 * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
334 *
335 * Runs the hunter for the label, then tries to find the bootdev, possible
336 * created by the hunter
337 *
338 * @label: Label to look up (e.g. "mmc1" or "mmc0")
339 * @devp: Returns the bootdev device found, or NULL if none (note it does not
340 * return the media device, but its bootdev child)
341 * @method_flagsp: If non-NULL, returns any flags implied by the label
342 * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
343 * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
344 * -ENOENT if there is no device with that number
345 */
346int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
347 int *method_flagsp);
348
Simon Glassac06b26a2023-01-17 10:48:10 -0700349/**
350 * bootdev_next_label() - Move to the next bootdev in the label sequence
351 *
352 * Looks through the remaining labels until it finds one that matches a bootdev.
353 * Bootdev scanners are used as needed. For example a label "mmc1" results in
354 * running the "mmc" bootdrv.
355 *
356 * @iter: Interation info, containing iter->cur_label
357 * @devp: New bootdev found, if any was found
358 * @method_flagsp: If non-NULL, returns any flags implied by the label
359 * (enum bootflow_meth_flags_t), 0 if none
360 * Returns 0 if OK, -ENODEV if no bootdev was found
361 */
362int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
363 int *method_flagsp);
364
Simon Glass660a9952023-01-17 10:48:11 -0700365/**
366 * bootdev_next_prio() - Find the next bootdev in priority order
367 *
368 * This moves @devp to the next bootdev with the current priority. If there is
369 * none, then it moves to the next priority and scans for new bootdevs there.
370 *
371 * @iter: Interation info, containing iter->cur_prio
372 * @devp: On entry this is the previous bootdev that was considered. On exit
373 * this is the new bootdev, if any was found
374 * Returns 0 on success (*devp is updated), -ENODEV if there are no more
375 * bootdevs at any priority
376 */
377int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp);
378
Simon Glass017656e2022-04-24 23:31:07 -0600379#if CONFIG_IS_ENABLED(BOOTSTD)
380/**
Simon Glassb1dc36a2023-01-17 10:47:25 -0700381 * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
382 *
Simon Glassb1d581d2023-07-30 11:15:14 -0600383 * Please use bootdev_setup_for_sibling_blk() instead since it supports multiple
Simon Glassb1dc36a2023-01-17 10:47:25 -0700384 * (child) block devices for each media device.
Simon Glass017656e2022-04-24 23:31:07 -0600385 *
386 * Creates a bootdev device as a child of @parent. This should be called from
387 * the driver's bind() method or its uclass' post_bind() method.
388 *
389 * If a child bootdev already exists, this function does nothing
390 *
391 * @parent: Parent device (e.g. MMC or Ethernet)
392 * @drv_name: Name of bootdev driver to bind
393 * Return: 0 if OK, -ve on error
394 */
395int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name);
396
397/**
Simon Glassb1d581d2023-07-30 11:15:14 -0600398 * bootdev_setup_for_sibling_blk() - Bind a new bootdev device for a blk device
Simon Glass017656e2022-04-24 23:31:07 -0600399 *
400 * Creates a bootdev device as a sibling of @blk. This should be called from
401 * the driver's bind() method or its uclass' post_bind() method, at the same
402 * time as the bould device is bound
403 *
404 * If a device of the same name already exists, this function does nothing
405 *
406 * @parent: Parent device (e.g. MMC or Ethernet)
407 * @drv_name: Name of bootdev driver to bind
408 * Return: 0 if OK, -ve on error
409 */
Simon Glassb1d581d2023-07-30 11:15:14 -0600410int bootdev_setup_for_sibling_blk(struct udevice *blk, const char *drv_name);
Simon Glass017656e2022-04-24 23:31:07 -0600411
412/**
413 * bootdev_get_sibling_blk() - Locate the block device for a bootdev
414 *
415 * @dev: bootdev to check
416 * @blkp: returns associated block device
417 * Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other
418 * error
419 */
420int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp);
421
422/**
423 * bootdev_unbind_dev() - Unbind a bootdev device
424 *
425 * Remove and unbind a bootdev device which is a child of @parent. This should
426 * be called from the driver's unbind() method or its uclass' post_bind()
427 * method.
428 *
429 * @parent: Parent device (e.g. MMC or Ethernet)
430 * Return: 0 if OK, -ve on error
431 */
432int bootdev_unbind_dev(struct udevice *parent);
433#else
434static inline int bootdev_setup_for_dev(struct udevice *parent,
435 const char *drv_name)
436{
437 return 0;
438}
439
Simon Glassb1d581d2023-07-30 11:15:14 -0600440static inline int bootdev_setup_for_sibling_blk(struct udevice *blk,
441 const char *drv_name)
Simon Glass017656e2022-04-24 23:31:07 -0600442{
443 return 0;
444}
445
446static inline int bootdev_unbind_dev(struct udevice *parent)
447{
448 return 0;
449}
450#endif
451
452#endif