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