1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * 'bootmeth' command
4  *
5  * Copyright 2021 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #include <bootdev.h>
10 #include <bootmeth.h>
11 #include <bootstd.h>
12 #include <command.h>
13 #include <dm.h>
14 #include <env.h>
15 #include <malloc.h>
16 #include <dm/uclass-internal.h>
17 
do_bootmeth_list(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])18 static int do_bootmeth_list(struct cmd_tbl *cmdtp, int flag, int argc,
19 			    char *const argv[])
20 {
21 	struct bootstd_priv *std;
22 	struct udevice *dev;
23 	bool use_order;
24 	bool all = false;
25 	int ret;
26 	int i;
27 
28 	if (argc > 1 && *argv[1] == '-') {
29 		all = strchr(argv[1], 'a');
30 		argc--;
31 		argv++;
32 	}
33 
34 	ret = bootstd_get_priv(&std);
35 	if (ret) {
36 		printf("Cannot get bootstd (err=%d)\n", ret);
37 		return CMD_RET_FAILURE;
38 	}
39 
40 	printf("Order  Seq  Name                Description\n");
41 	printf("-----  ---  ------------------  ------------------\n");
42 
43 	/*
44 	 * Use the ordering if we have one, so long as we are not trying to list
45 	 * all bootmethds
46 	 */
47 	use_order = std->bootmeth_count && !all;
48 	if (use_order)
49 		dev = std->bootmeth_order[0];
50 	else
51 		ret = uclass_find_first_device(UCLASS_BOOTMETH, &dev);
52 
53 	for (i = 0; dev;) {
54 		struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(dev);
55 		int order = i;
56 
57 		/*
58 		 * With the -a flag we may list bootdevs that are not in the
59 		 * ordering. Find their place in the order
60 		 */
61 		if (all && std->bootmeth_count) {
62 			int j;
63 
64 			/* Find the position of this bootmeth in the order */
65 			order = -1;
66 			for (j = 0; j < std->bootmeth_count; j++) {
67 				if (std->bootmeth_order[j] == dev)
68 					order = j;
69 			}
70 		}
71 
72 		if (ucp->flags & BOOTMETHF_GLOBAL)
73 			printf("%5s", "glob");
74 		else if (order == -1)
75 			printf("%5s", "-");
76 		else
77 			printf("%5x", order);
78 		printf("  %3x  %-19.19s %s\n", dev_seq(dev), dev->name,
79 		       ucp->desc);
80 		i++;
81 		if (use_order)
82 			dev = std->bootmeth_order[i];
83 		else
84 			uclass_find_next_device(&dev);
85 	}
86 	printf("-----  ---  ------------------  ------------------\n");
87 	printf("(%d bootmeth%s)\n", i, i != 1 ? "s" : "");
88 
89 	return 0;
90 }
91 
do_bootmeth_order(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])92 static int do_bootmeth_order(struct cmd_tbl *cmdtp, int flag, int argc,
93 			     char *const argv[])
94 {
95 	int ret;
96 
97 	ret = bootmeth_set_order(argv[1]);
98 	if (ret) {
99 		printf("Failed (err=%d)\n", ret);
100 		return CMD_RET_FAILURE;
101 	}
102 	env_set("bootmeths", argv[1]);
103 
104 	return 0;
105 }
106 
do_bootmeth_set(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])107 static int do_bootmeth_set(struct cmd_tbl *cmdtp, int flag, int argc,
108 			     char *const argv[])
109 {
110 	int ret;
111 
112 	if (argc < 4) {
113 		printf("Required parameters not provided\n");
114 		return CMD_RET_FAILURE;
115 	}
116 
117 	ret = bootmeth_set_property(argv[1], argv[2], argv[3]);
118 	if (ret) {
119 		printf("Failed (err=%d)\n", ret);
120 		return CMD_RET_FAILURE;
121 	}
122 
123 	return 0;
124 }
125 
126 U_BOOT_LONGHELP(bootmeth,
127 	"list [-a]     - list available bootmeths (-a all)\n"
128 	"bootmeth order [<bd> ...]  - select bootmeth order / subset to use\n"
129 	"bootmeth set <bootmeth> <property> <value> - set optional property");
130 
131 U_BOOT_CMD_WITH_SUBCMDS(bootmeth, "Boot methods", bootmeth_help_text,
132 	U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootmeth_list),
133 	U_BOOT_SUBCMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_bootmeth_order),
134 	U_BOOT_SUBCMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bootmeth_set));
135