]>
Commit | Line | Data |
---|---|---|
201417d7 SG |
1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
2 | /* | |
3 | * Copyright 2021 Google LLC | |
4 | * Written by Simon Glass <[email protected]> | |
5 | */ | |
6 | ||
7 | #ifndef __bootdev_h | |
8 | #define __bootdev_h | |
9 | ||
10 | #include <linux/list.h> | |
11 | ||
12 | struct bootflow; | |
13 | struct bootflow_iter; | |
14 | struct 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 | */ | |
24 | enum 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 | */ | |
45 | struct 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 */ | |
51 | struct 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 | */ | |
80 | int 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 | */ | |
91 | int 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 | */ | |
105 | int 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 | */ | |
113 | void 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 | */ | |
123 | void 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 | */ | |
138 | int 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 | */ | |
149 | int 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 | */ | |
160 | int 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 | */ | |
177 | int 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 | */ | |
186 | int 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 | */ | |
203 | int 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 | */ | |
218 | int 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 | */ | |
233 | int 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 | */ | |
243 | int 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 | */ | |
255 | int bootdev_unbind_dev(struct udevice *parent); | |
256 | #else | |
257 | static inline int bootdev_setup_for_dev(struct udevice *parent, | |
258 | const char *drv_name) | |
259 | { | |
260 | return 0; | |
261 | } | |
262 | ||
263 | static inline int bootdev_setup_sibling_blk(struct udevice *blk, | |
264 | const char *drv_name) | |
265 | { | |
266 | return 0; | |
267 | } | |
268 | ||
269 | static inline int bootdev_unbind_dev(struct udevice *parent) | |
270 | { | |
271 | return 0; | |
272 | } | |
273 | #endif | |
274 | ||
275 | #endif |