blob: 9fc219839fe0f8d13cec8aded77b5de41df06ca1 [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;
14struct udevice;
15
16/**
17 * enum bootdev_prio_t - priority of each bootdev
18 *
19 * These values are associated with each bootdev and set up by the driver.
20 *
21 * Smallest value is the highest priority. By default, bootdevs are scanned from
22 * highest to lowest priority
23 */
24enum bootdev_prio_t {
25 BOOTDEVP_0_INTERNAL_FAST = 10,
26 BOOTDEVP_1_INTERNAL_SLOW = 20,
27 BOOTDEVP_2_SCAN_FAST = 30,
28 BOOTDEVP_3_SCAN_SLOW = 40,
29 BOOTDEVP_4_NET_BASE = 50,
30 BOOTDEVP_5_NET_FALLBACK = 60,
31 BOOTDEVP_6_SYSTEM = 70,
32
33 BOOTDEVP_COUNT,
34};
35
36/**
37 * struct bootdev_uc_plat - uclass information about a bootdev
38 *
39 * This is attached to each device in the bootdev uclass and accessible via
40 * dev_get_uclass_plat(dev)
41 *
42 * @bootflows: List of available bootflows for this bootdev
43 * @piro: Priority of this bootdev
44 */
45struct bootdev_uc_plat {
46 struct list_head bootflow_head;
47 enum bootdev_prio_t prio;
48};
49
50/** struct bootdev_ops - Operations for the bootdev uclass */
51struct bootdev_ops {
52 /**
53 * get_bootflow() - get a bootflow
54 *
55 * @dev: Bootflow device to check
56 * @iter: Provides current dev, part, method to get. Should update
57 * max_part if there is a partition table. Should update state,
58 * subdir, fname, buf, size according to progress
59 * @bflow: Updated bootflow if found
60 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this
61 * device, -ENOSYS if this device doesn't support bootflows,
62 * other -ve value on other error
63 */
64 int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter,
65 struct bootflow *bflow);
66};
67
68#define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops)
69
70/**
71 * bootdev_get_bootflow() - get a bootflow
72 *
73 * @dev: Bootflow device to check
74 * @iter: Provides current part, method to get
75 * @bflow: Returns bootflow if found
76 * Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device,
77 * -ENOSYS if this device doesn't support bootflows, other -ve value on
78 * other error
79 */
80int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
81 struct bootflow *bflow);
82
83/**
84 * bootdev_bind() - Bind a new named bootdev device
85 *
86 * @parent: Parent of the new device
87 * @drv_name: Driver name to use for the bootdev device
88 * @name: Name for the device (parent name is prepended)
89 * @devp: the new device (which has not been probed)
90 */
91int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name,
92 struct udevice **devp);
93
94/**
95 * bootdev_find_in_blk() - Find a bootdev in a block device
96 *
97 * @dev: Bootflow device associated with this block device
98 * @blk: Block device to search
99 * @iter: Provides current dev, part, method to get. Should update
100 * max_part if there is a partition table
101 * @bflow: On entry, provides information about the partition and device to
102 * check. On exit, returns bootflow if found
103 * Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
104 */
105int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk,
106 struct bootflow_iter *iter, struct bootflow *bflow);
107
108/**
109 * bootdev_list() - List all available bootdevs
110 *
111 * @probe: true to probe devices, false to leave them as is
112 */
113void bootdev_list(bool probe);
114
115/**
116 * bootdev_clear_bootflows() - Clear bootflows from a bootdev
117 *
118 * Each bootdev maintains a list of discovered bootflows. This provides a
119 * way to clear it. These bootflows are removed from the global list too.
120 *
121 * @dev: bootdev device to update
122 */
123void bootdev_clear_bootflows(struct udevice *dev);
124
125/**
126 * bootdev_add_bootflow() - Add a bootflow to the bootdev's list
127 *
128 * All fields in @bflow must be set up. Note that @bflow->dev is used to add the
129 * bootflow to that device.
130 *
131 * @dev: Bootdevice device to add to
132 * @bflow: Bootflow to add. Note that fields within bflow must be allocated
133 * since this function takes over ownership of these. This functions makes
134 * a copy of @bflow itself (without allocating its fields again), so the
135 * caller must dispose of the memory used by the @bflow pointer itself
136 * Return: 0 if OK, -ENOMEM if out of memory
137 */
138int bootdev_add_bootflow(struct bootflow *bflow);
139
140/**
141 * bootdev_first_bootflow() - Get the first bootflow from a bootdev
142 *
143 * Returns the first bootflow attached to a bootdev
144 *
145 * @dev: bootdev device
146 * @bflowp: Returns a pointer to the bootflow
147 * Return: 0 if found, -ENOENT if there are no bootflows
148 */
149int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp);
150
151/**
152 * bootdev_next_bootflow() - Get the next bootflow from a bootdev
153 *
154 * Returns the next bootflow attached to a bootdev
155 *
156 * @bflowp: On entry, the last bootflow returned , e.g. from
157 * bootdev_first_bootflow()
158 * Return: 0 if found, -ENOENT if there are no more bootflows
159 */
160int bootdev_next_bootflow(struct bootflow **bflowp);
161
162/**
163 * bootdev_find_by_label() - Look up a bootdev by label
164 *
165 * Each bootdev has a label which contains the media-uclass name and a number,
166 * e.g. 'mmc2'. This looks up the label and returns the associated bootdev
167 *
168 * The lookup is performed based on the media device's sequence number. So for
169 * 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2.
170 *
171 * @label: Label to look up (e.g. "mmc1" or "mmc0")
172 * @devp: Returns the bootdev device found, or NULL if none (note it does not
173 * return the media device, but its bootdev child)
174 * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
175 * -ENOENT if there is no device with that number
176 */
177int bootdev_find_by_label(const char *label, struct udevice **devp);
178
179/**
180 * bootdev_find_by_any() - Find a bootdev by name, label or sequence
181 *
182 * @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find
183 * @devp: returns the device found, on success
184 * Return: 0 if OK, -ve on error
185 */
186int bootdev_find_by_any(const char *name, struct udevice **devp);
187
188/**
189 * bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan
190 *
191 * This sets up the ordering information in @iter, based on the priority of each
192 * bootdev and the bootdev-order property in the bootstd node
193 *
194 * If a single device is requested, no ordering is needed
195 *
196 * @iter: Iterator to update with the order
197 * @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
198 * device to scan. Returns the first device to use, which is the passed-in
199 * @devp if it was non-NULL
200 * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
201 * on other error
202 */
203int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp);
204
205#if CONFIG_IS_ENABLED(BOOTSTD)
206/**
207 * bootdev_setup_for_dev() - Bind a new bootdev device
208 *
209 * Creates a bootdev device as a child of @parent. This should be called from
210 * the driver's bind() method or its uclass' post_bind() method.
211 *
212 * If a child bootdev already exists, this function does nothing
213 *
214 * @parent: Parent device (e.g. MMC or Ethernet)
215 * @drv_name: Name of bootdev driver to bind
216 * Return: 0 if OK, -ve on error
217 */
218int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name);
219
220/**
221 * bootdev_setup_for_blk() - Bind a new bootdev device for a blk device
222 *
223 * Creates a bootdev device as a sibling of @blk. This should be called from
224 * the driver's bind() method or its uclass' post_bind() method, at the same
225 * time as the bould device is bound
226 *
227 * If a device of the same name already exists, this function does nothing
228 *
229 * @parent: Parent device (e.g. MMC or Ethernet)
230 * @drv_name: Name of bootdev driver to bind
231 * Return: 0 if OK, -ve on error
232 */
233int bootdev_setup_sibling_blk(struct udevice *blk, const char *drv_name);
234
235/**
236 * bootdev_get_sibling_blk() - Locate the block device for a bootdev
237 *
238 * @dev: bootdev to check
239 * @blkp: returns associated block device
240 * Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other
241 * error
242 */
243int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp);
244
245/**
246 * bootdev_unbind_dev() - Unbind a bootdev device
247 *
248 * Remove and unbind a bootdev device which is a child of @parent. This should
249 * be called from the driver's unbind() method or its uclass' post_bind()
250 * method.
251 *
252 * @parent: Parent device (e.g. MMC or Ethernet)
253 * Return: 0 if OK, -ve on error
254 */
255int bootdev_unbind_dev(struct udevice *parent);
256#else
257static inline int bootdev_setup_for_dev(struct udevice *parent,
258 const char *drv_name)
259{
260 return 0;
261}
262
263static inline int bootdev_setup_sibling_blk(struct udevice *blk,
264 const char *drv_name)
265{
266 return 0;
267}
268
269static inline int bootdev_unbind_dev(struct udevice *parent)
270{
271 return 0;
272}
273#endif
274
275#endif