mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +00:00
bootstd: Add the bootdev uclass
A 'bootdev' is a device which can be used to boot an operating system. It is a child of the media device (e.g. MMC) which handles reading files from that device, such as a bootflow file. Add a uclass for bootdev and the various helpers needed to make it work. Also add a binding file, empty for now. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
ef5e3891f5
commit
201417d700
6 changed files with 928 additions and 1 deletions
275
include/bootdev.h
Normal file
275
include/bootdev.h
Normal file
|
@ -0,0 +1,275 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#ifndef __bootdev_h
|
||||
#define __bootdev_h
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct bootflow;
|
||||
struct bootflow_iter;
|
||||
struct udevice;
|
||||
|
||||
/**
|
||||
* enum bootdev_prio_t - priority of each bootdev
|
||||
*
|
||||
* These values are associated with each bootdev and set up by the driver.
|
||||
*
|
||||
* Smallest value is the highest priority. By default, bootdevs are scanned from
|
||||
* highest to lowest priority
|
||||
*/
|
||||
enum bootdev_prio_t {
|
||||
BOOTDEVP_0_INTERNAL_FAST = 10,
|
||||
BOOTDEVP_1_INTERNAL_SLOW = 20,
|
||||
BOOTDEVP_2_SCAN_FAST = 30,
|
||||
BOOTDEVP_3_SCAN_SLOW = 40,
|
||||
BOOTDEVP_4_NET_BASE = 50,
|
||||
BOOTDEVP_5_NET_FALLBACK = 60,
|
||||
BOOTDEVP_6_SYSTEM = 70,
|
||||
|
||||
BOOTDEVP_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bootdev_uc_plat - uclass information about a bootdev
|
||||
*
|
||||
* This is attached to each device in the bootdev uclass and accessible via
|
||||
* dev_get_uclass_plat(dev)
|
||||
*
|
||||
* @bootflows: List of available bootflows for this bootdev
|
||||
* @piro: Priority of this bootdev
|
||||
*/
|
||||
struct bootdev_uc_plat {
|
||||
struct list_head bootflow_head;
|
||||
enum bootdev_prio_t prio;
|
||||
};
|
||||
|
||||
/** struct bootdev_ops - Operations for the bootdev uclass */
|
||||
struct bootdev_ops {
|
||||
/**
|
||||
* get_bootflow() - get a bootflow
|
||||
*
|
||||
* @dev: Bootflow device to check
|
||||
* @iter: Provides current dev, part, method to get. Should update
|
||||
* max_part if there is a partition table. Should update state,
|
||||
* subdir, fname, buf, size according to progress
|
||||
* @bflow: Updated bootflow if found
|
||||
* Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this
|
||||
* device, -ENOSYS if this device doesn't support bootflows,
|
||||
* other -ve value on other error
|
||||
*/
|
||||
int (*get_bootflow)(struct udevice *dev, struct bootflow_iter *iter,
|
||||
struct bootflow *bflow);
|
||||
};
|
||||
|
||||
#define bootdev_get_ops(dev) ((struct bootdev_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* bootdev_get_bootflow() - get a bootflow
|
||||
*
|
||||
* @dev: Bootflow device to check
|
||||
* @iter: Provides current part, method to get
|
||||
* @bflow: Returns bootflow if found
|
||||
* Return: 0 if OK, -ESHUTDOWN if there are no more bootflows on this device,
|
||||
* -ENOSYS if this device doesn't support bootflows, other -ve value on
|
||||
* other error
|
||||
*/
|
||||
int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
||||
struct bootflow *bflow);
|
||||
|
||||
/**
|
||||
* bootdev_bind() - Bind a new named bootdev device
|
||||
*
|
||||
* @parent: Parent of the new device
|
||||
* @drv_name: Driver name to use for the bootdev device
|
||||
* @name: Name for the device (parent name is prepended)
|
||||
* @devp: the new device (which has not been probed)
|
||||
*/
|
||||
int bootdev_bind(struct udevice *parent, const char *drv_name, const char *name,
|
||||
struct udevice **devp);
|
||||
|
||||
/**
|
||||
* bootdev_find_in_blk() - Find a bootdev in a block device
|
||||
*
|
||||
* @dev: Bootflow device associated with this block device
|
||||
* @blk: Block device to search
|
||||
* @iter: Provides current dev, part, method to get. Should update
|
||||
* max_part if there is a partition table
|
||||
* @bflow: On entry, provides information about the partition and device to
|
||||
* check. On exit, returns bootflow if found
|
||||
* Return: 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
|
||||
*/
|
||||
int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk,
|
||||
struct bootflow_iter *iter, struct bootflow *bflow);
|
||||
|
||||
/**
|
||||
* bootdev_list() - List all available bootdevs
|
||||
*
|
||||
* @probe: true to probe devices, false to leave them as is
|
||||
*/
|
||||
void bootdev_list(bool probe);
|
||||
|
||||
/**
|
||||
* bootdev_clear_bootflows() - Clear bootflows from a bootdev
|
||||
*
|
||||
* Each bootdev maintains a list of discovered bootflows. This provides a
|
||||
* way to clear it. These bootflows are removed from the global list too.
|
||||
*
|
||||
* @dev: bootdev device to update
|
||||
*/
|
||||
void bootdev_clear_bootflows(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* bootdev_add_bootflow() - Add a bootflow to the bootdev's list
|
||||
*
|
||||
* All fields in @bflow must be set up. Note that @bflow->dev is used to add the
|
||||
* bootflow to that device.
|
||||
*
|
||||
* @dev: Bootdevice device to add to
|
||||
* @bflow: Bootflow to add. Note that fields within bflow must be allocated
|
||||
* since this function takes over ownership of these. This functions makes
|
||||
* a copy of @bflow itself (without allocating its fields again), so the
|
||||
* caller must dispose of the memory used by the @bflow pointer itself
|
||||
* Return: 0 if OK, -ENOMEM if out of memory
|
||||
*/
|
||||
int bootdev_add_bootflow(struct bootflow *bflow);
|
||||
|
||||
/**
|
||||
* bootdev_first_bootflow() - Get the first bootflow from a bootdev
|
||||
*
|
||||
* Returns the first bootflow attached to a bootdev
|
||||
*
|
||||
* @dev: bootdev device
|
||||
* @bflowp: Returns a pointer to the bootflow
|
||||
* Return: 0 if found, -ENOENT if there are no bootflows
|
||||
*/
|
||||
int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp);
|
||||
|
||||
/**
|
||||
* bootdev_next_bootflow() - Get the next bootflow from a bootdev
|
||||
*
|
||||
* Returns the next bootflow attached to a bootdev
|
||||
*
|
||||
* @bflowp: On entry, the last bootflow returned , e.g. from
|
||||
* bootdev_first_bootflow()
|
||||
* Return: 0 if found, -ENOENT if there are no more bootflows
|
||||
*/
|
||||
int bootdev_next_bootflow(struct bootflow **bflowp);
|
||||
|
||||
/**
|
||||
* bootdev_find_by_label() - Look up a bootdev by label
|
||||
*
|
||||
* Each bootdev has a label which contains the media-uclass name and a number,
|
||||
* e.g. 'mmc2'. This looks up the label and returns the associated bootdev
|
||||
*
|
||||
* The lookup is performed based on the media device's sequence number. So for
|
||||
* 'mmc2' this looks for a device in UCLASS_MMC with a dev_seq() of 2.
|
||||
*
|
||||
* @label: Label to look up (e.g. "mmc1" or "mmc0")
|
||||
* @devp: Returns the bootdev device found, or NULL if none (note it does not
|
||||
* return the media device, but its bootdev child)
|
||||
* Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
|
||||
* -ENOENT if there is no device with that number
|
||||
*/
|
||||
int bootdev_find_by_label(const char *label, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* bootdev_find_by_any() - Find a bootdev by name, label or sequence
|
||||
*
|
||||
* @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find
|
||||
* @devp: returns the device found, on success
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int bootdev_find_by_any(const char *name, struct udevice **devp);
|
||||
|
||||
/**
|
||||
* bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan
|
||||
*
|
||||
* This sets up the ordering information in @iter, based on the priority of each
|
||||
* bootdev and the bootdev-order property in the bootstd node
|
||||
*
|
||||
* If a single device is requested, no ordering is needed
|
||||
*
|
||||
* @iter: Iterator to update with the order
|
||||
* @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
|
||||
* device to scan. Returns the first device to use, which is the passed-in
|
||||
* @devp if it was non-NULL
|
||||
* Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
|
||||
* on other error
|
||||
*/
|
||||
int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp);
|
||||
|
||||
#if CONFIG_IS_ENABLED(BOOTSTD)
|
||||
/**
|
||||
* bootdev_setup_for_dev() - Bind a new bootdev device
|
||||
*
|
||||
* Creates a bootdev device as a child of @parent. This should be called from
|
||||
* the driver's bind() method or its uclass' post_bind() method.
|
||||
*
|
||||
* If a child bootdev already exists, this function does nothing
|
||||
*
|
||||
* @parent: Parent device (e.g. MMC or Ethernet)
|
||||
* @drv_name: Name of bootdev driver to bind
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int bootdev_setup_for_dev(struct udevice *parent, const char *drv_name);
|
||||
|
||||
/**
|
||||
* bootdev_setup_for_blk() - Bind a new bootdev device for a blk device
|
||||
*
|
||||
* Creates a bootdev device as a sibling of @blk. This should be called from
|
||||
* the driver's bind() method or its uclass' post_bind() method, at the same
|
||||
* time as the bould device is bound
|
||||
*
|
||||
* If a device of the same name already exists, this function does nothing
|
||||
*
|
||||
* @parent: Parent device (e.g. MMC or Ethernet)
|
||||
* @drv_name: Name of bootdev driver to bind
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int bootdev_setup_sibling_blk(struct udevice *blk, const char *drv_name);
|
||||
|
||||
/**
|
||||
* bootdev_get_sibling_blk() - Locate the block device for a bootdev
|
||||
*
|
||||
* @dev: bootdev to check
|
||||
* @blkp: returns associated block device
|
||||
* Return: 0 if OK, -EINVAL if @dev is not a bootdev device, other -ve on other
|
||||
* error
|
||||
*/
|
||||
int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp);
|
||||
|
||||
/**
|
||||
* bootdev_unbind_dev() - Unbind a bootdev device
|
||||
*
|
||||
* Remove and unbind a bootdev device which is a child of @parent. This should
|
||||
* be called from the driver's unbind() method or its uclass' post_bind()
|
||||
* method.
|
||||
*
|
||||
* @parent: Parent device (e.g. MMC or Ethernet)
|
||||
* Return: 0 if OK, -ve on error
|
||||
*/
|
||||
int bootdev_unbind_dev(struct udevice *parent);
|
||||
#else
|
||||
static inline int bootdev_setup_for_dev(struct udevice *parent,
|
||||
const char *drv_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bootdev_setup_sibling_blk(struct udevice *blk,
|
||||
const char *drv_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int bootdev_unbind_dev(struct udevice *parent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue