1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * 'bootdev' command 4 * 5 * Copyright 2021 Google LLC 6 * Written by Simon Glass <sjg@chromium.org> 7 */ 8 9#include <common.h> 10#include <bootdev.h> 11#include <bootflow.h> 12#include <bootstd.h> 13#include <command.h> 14#include <dm.h> 15#include <dm/device-internal.h> 16#include <dm/uclass-internal.h> 17 18static int bootdev_check_state(struct bootstd_priv **stdp) 19{ 20 struct bootstd_priv *std; 21 int ret; 22 23 ret = bootstd_get_priv(&std); 24 if (ret) 25 return ret; 26 if (!std->cur_bootdev) { 27 printf("Please use 'bootdev select' first\n"); 28 return -ENOENT; 29 } 30 *stdp = std; 31 32 return 0; 33} 34 35static int do_bootdev_list(struct cmd_tbl *cmdtp, int flag, int argc, 36 char *const argv[]) 37{ 38 bool probe; 39 40 probe = argc >= 2 && !strcmp(argv[1], "-p"); 41 bootdev_list(probe); 42 43 return 0; 44} 45 46static int do_bootdev_select(struct cmd_tbl *cmdtp, int flag, int argc, 47 char *const argv[]) 48{ 49 struct bootstd_priv *std; 50 struct udevice *dev; 51 int ret; 52 53 ret = bootstd_get_priv(&std); 54 if (ret) 55 return CMD_RET_FAILURE; 56 if (argc < 2) { 57 std->cur_bootdev = NULL; 58 return 0; 59 } 60 if (bootdev_find_by_any(argv[1], &dev, NULL)) 61 return CMD_RET_FAILURE; 62 63 std->cur_bootdev = dev; 64 65 return 0; 66} 67 68static int do_bootdev_info(struct cmd_tbl *cmdtp, int flag, int argc, 69 char *const argv[]) 70{ 71 struct bootstd_priv *priv; 72 struct bootflow *bflow; 73 int ret, i, num_valid; 74 struct udevice *dev; 75 bool probe; 76 77 probe = argc >= 2 && !strcmp(argv[1], "-p"); 78 79 ret = bootdev_check_state(&priv); 80 if (ret) 81 return CMD_RET_FAILURE; 82 83 dev = priv->cur_bootdev; 84 85 /* Count the number of bootflows, including how many are valid*/ 86 num_valid = 0; 87 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0; 88 !ret; 89 ret = bootdev_next_bootflow(&bflow), i++) 90 num_valid += bflow->state == BOOTFLOWST_READY; 91 92 /* 93 * Prove the device, if requested, otherwise assume that there is no 94 * error 95 */ 96 ret = 0; 97 if (probe) 98 ret = device_probe(dev); 99 100 printf("Name: %s\n", dev->name); 101 printf("Sequence: %d\n", dev_seq(dev)); 102 printf("Status: %s\n", ret ? simple_itoa(-ret) : device_active(dev) ? 103 "Probed" : "OK"); 104 printf("Uclass: %s\n", dev_get_uclass_name(dev_get_parent(dev))); 105 printf("Bootflows: %d (%d valid)\n", i, num_valid); 106 107 return 0; 108} 109 110static int do_bootdev_hunt(struct cmd_tbl *cmdtp, int flag, int argc, 111 char *const argv[]) 112{ 113 struct bootstd_priv *priv; 114 const char *spec = NULL; 115 bool list = false; 116 int ret = 0; 117 118 if (argc >= 2) { 119 if (!strcmp(argv[1], "-l")) 120 list = true; 121 else 122 spec = argv[1]; 123 } 124 125 ret = bootstd_get_priv(&priv); 126 if (ret) 127 return ret; 128 if (list) { 129 bootdev_list_hunters(priv); 130 } else { 131 ret = bootdev_hunt(spec, true); 132 if (ret) { 133 printf("Failed (err=%dE)\n", ret); 134 135 return CMD_RET_FAILURE; 136 } 137 } 138 139 return 0; 140} 141 142U_BOOT_LONGHELP(bootdev, 143 "list [-p] - list all available bootdevs (-p to probe)\n" 144 "bootdev hunt [-l|<spec>] - use hunt drivers to find bootdevs\n" 145 "bootdev select <bd> - select a bootdev by name | label | seq\n" 146 "bootdev info [-p] - show information about a bootdev (-p to probe)"); 147 148U_BOOT_CMD_WITH_SUBCMDS(bootdev, "Boot devices", bootdev_help_text, 149 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootdev_list), 150 U_BOOT_SUBCMD_MKENT(hunt, 2, 1, do_bootdev_hunt), 151 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootdev_select), 152 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootdev_info)); 153