uboot/boot/bootstd-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Uclass implementation for standard boot
   4 *
   5 * Copyright 2021 Google LLC
   6 * Written by Simon Glass <sjg@chromium.org>
   7 */
   8
   9#include <common.h>
  10#include <bootflow.h>
  11#include <bootstd.h>
  12#include <dm.h>
  13#include <env.h>
  14#include <log.h>
  15#include <malloc.h>
  16#include <dm/device-internal.h>
  17#include <dm/lists.h>
  18#include <dm/read.h>
  19#include <dm/uclass-internal.h>
  20
  21DECLARE_GLOBAL_DATA_PTR;
  22
  23/* These are used if filename-prefixes is not present */
  24const char *const default_prefixes[] = {"/", "/boot/", NULL};
  25
  26static int bootstd_of_to_plat(struct udevice *dev)
  27{
  28        struct bootstd_priv *priv = dev_get_priv(dev);
  29        int ret;
  30
  31        if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
  32                /* Don't check errors since livetree and flattree are different */
  33                ret = dev_read_string_list(dev, "filename-prefixes",
  34                                           &priv->prefixes);
  35                dev_read_string_list(dev, "bootdev-order",
  36                                     &priv->bootdev_order);
  37
  38                priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme");
  39        }
  40
  41        return 0;
  42}
  43
  44static void bootstd_clear_glob_(struct bootstd_priv *priv)
  45{
  46        while (!list_empty(&priv->glob_head)) {
  47                struct bootflow *bflow;
  48
  49                bflow = list_first_entry(&priv->glob_head, struct bootflow,
  50                                         glob_node);
  51                bootflow_remove(bflow);
  52        }
  53}
  54
  55void bootstd_clear_glob(void)
  56{
  57        struct bootstd_priv *std;
  58
  59        if (bootstd_get_priv(&std))
  60                return;
  61
  62        bootstd_clear_glob_(std);
  63}
  64
  65static int bootstd_remove(struct udevice *dev)
  66{
  67        struct bootstd_priv *priv = dev_get_priv(dev);
  68
  69        free(priv->prefixes);
  70        free(priv->bootdev_order);
  71        bootstd_clear_glob_(priv);
  72
  73        return 0;
  74}
  75
  76const char *const *const bootstd_get_bootdev_order(struct udevice *dev,
  77                                                   bool *okp)
  78{
  79        struct bootstd_priv *std = dev_get_priv(dev);
  80        const char *targets = env_get("boot_targets");
  81
  82        *okp = true;
  83        log_debug("- targets %s %p\n", targets, std->bootdev_order);
  84        if (targets && *targets) {
  85                str_free_list(std->env_order);
  86                std->env_order = str_to_list(targets);
  87                if (!std->env_order) {
  88                        *okp = false;
  89                        return NULL;
  90                }
  91                return std->env_order;
  92        }
  93
  94        return std->bootdev_order;
  95}
  96
  97const char *const *const bootstd_get_prefixes(struct udevice *dev)
  98{
  99        struct bootstd_priv *std = dev_get_priv(dev);
 100
 101        return std->prefixes ? std->prefixes : default_prefixes;
 102}
 103
 104int bootstd_get_priv(struct bootstd_priv **stdp)
 105{
 106        struct udevice *dev;
 107        int ret;
 108
 109        ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
 110        if (ret)
 111                return ret;
 112        *stdp = dev_get_priv(dev);
 113
 114        return 0;
 115}
 116
 117static int bootstd_probe(struct udevice *dev)
 118{
 119        struct bootstd_priv *std = dev_get_priv(dev);
 120
 121        INIT_LIST_HEAD(&std->glob_head);
 122
 123        return 0;
 124}
 125
 126/* For now, bind the boormethod device if none are found in the devicetree */
 127int dm_scan_other(bool pre_reloc_only)
 128{
 129        struct driver *drv = ll_entry_start(struct driver, driver);
 130        const int n_ents = ll_entry_count(struct driver, driver);
 131        struct udevice *dev, *bootstd;
 132        int i, ret;
 133
 134        /* These are not needed before relocation */
 135        if (!(gd->flags & GD_FLG_RELOC))
 136                return 0;
 137
 138        /* Create a bootstd device if needed */
 139        uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
 140        if (!bootstd) {
 141                ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
 142                                         &bootstd);
 143                if (ret)
 144                        return log_msg_ret("bootstd", ret);
 145        }
 146
 147        /* If there are no bootmeth devices, create them */
 148        uclass_find_first_device(UCLASS_BOOTMETH, &dev);
 149        if (dev)
 150                return 0;
 151
 152        for (i = 0; i < n_ents; i++, drv++) {
 153                if (drv->id == UCLASS_BOOTMETH) {
 154                        const char *name = drv->name;
 155
 156                        if (!strncmp("bootmeth_", name, 9))
 157                                name += 9;
 158                        ret = device_bind(bootstd, drv, name, 0, ofnode_null(),
 159                                          &dev);
 160                        if (ret)
 161                                return log_msg_ret("meth", ret);
 162                }
 163        }
 164
 165        return 0;
 166}
 167
 168static const struct udevice_id bootstd_ids[] = {
 169        { .compatible = "u-boot,boot-std" },
 170        { }
 171};
 172
 173U_BOOT_DRIVER(bootstd_drv) = {
 174        .id             = UCLASS_BOOTSTD,
 175        .name           = "bootstd_drv",
 176        .of_to_plat     = bootstd_of_to_plat,
 177        .probe          = bootstd_probe,
 178        .remove         = bootstd_remove,
 179        .of_match       = bootstd_ids,
 180        .priv_auto      = sizeof(struct bootstd_priv),
 181};
 182
 183UCLASS_DRIVER(bootstd) = {
 184        .id             = UCLASS_BOOTSTD,
 185        .name           = "bootstd",
 186#if CONFIG_IS_ENABLED(OF_REAL)
 187        .post_bind      = dm_scan_fdt_dev,
 188#endif
 189};
 190