1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * 'cedit' command
4 *
5 * Copyright 2023 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#include <common.h>
10#include <abuf.h>
11#include <cedit.h>
12#include <command.h>
13#include <dm.h>
14#include <expo.h>
15#include <fs.h>
16#include <malloc.h>
17#include <mapmem.h>
18#include <dm/ofnode.h>
19#include <linux/sizes.h>
20
21struct expo *cur_exp;
22
23static int check_cur_expo(void)
24{
25	if (!cur_exp) {
26		printf("No expo loaded\n");
27		return -ENOENT;
28	}
29
30	return 0;
31}
32
33static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
34			 char *const argv[])
35{
36	const char *fname;
37	struct expo *exp;
38	oftree tree;
39	ulong size;
40	void *buf;
41	int ret;
42
43	if (argc < 4)
44		return CMD_RET_USAGE;
45	fname = argv[3];
46
47	ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
48	if (ret) {
49		printf("File not found\n");
50		return CMD_RET_FAILURE;
51	}
52
53	tree = oftree_from_fdt(buf);
54	if (!oftree_valid(tree)) {
55		printf("Cannot create oftree\n");
56		return CMD_RET_FAILURE;
57	}
58
59	ret = expo_build(oftree_root(tree), &exp);
60	oftree_dispose(tree);
61	if (ret) {
62		printf("Failed to build expo: %dE\n", ret);
63		return CMD_RET_FAILURE;
64	}
65
66	cur_exp = exp;
67
68	return 0;
69}
70
71static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc,
72			      char *const argv[])
73{
74	const char *fname;
75	struct abuf buf;
76	loff_t bytes;
77	int ret;
78
79	if (argc < 4)
80		return CMD_RET_USAGE;
81	fname = argv[3];
82
83	if (check_cur_expo())
84		return CMD_RET_FAILURE;
85
86	ret = cedit_write_settings(cur_exp, &buf);
87	if (ret) {
88		printf("Failed to write settings: %dE\n", ret);
89		return CMD_RET_FAILURE;
90	}
91
92	if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
93		return CMD_RET_FAILURE;
94
95	ret = fs_write(fname, map_to_sysmem(abuf_data(&buf)), 0,
96		       abuf_size(&buf), &bytes);
97	if (ret)
98		return CMD_RET_FAILURE;
99
100	return 0;
101}
102
103static int do_cedit_read_fdt(struct cmd_tbl *cmdtp, int flag, int argc,
104			     char *const argv[])
105{
106	const char *fname;
107	void *buf;
108	oftree tree;
109	ulong size;
110	int ret;
111
112	if (argc < 4)
113		return CMD_RET_USAGE;
114	fname = argv[3];
115
116	ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
117	if (ret) {
118		printf("File not found\n");
119		return CMD_RET_FAILURE;
120	}
121
122	tree = oftree_from_fdt(buf);
123	if (!oftree_valid(tree)) {
124		free(buf);
125		printf("Cannot create oftree\n");
126		return CMD_RET_FAILURE;
127	}
128
129	ret = cedit_read_settings(cur_exp, tree);
130	oftree_dispose(tree);
131	free(buf);
132	if (ret) {
133		printf("Failed to read settings: %dE\n", ret);
134		return CMD_RET_FAILURE;
135	}
136
137	return 0;
138}
139
140static int do_cedit_write_env(struct cmd_tbl *cmdtp, int flag, int argc,
141			      char *const argv[])
142{
143	bool verbose;
144	int ret;
145
146	if (check_cur_expo())
147		return CMD_RET_FAILURE;
148
149	verbose = argc > 1 && !strcmp(argv[1], "-v");
150
151	ret = cedit_write_settings_env(cur_exp, verbose);
152	if (ret) {
153		printf("Failed to write settings to environment: %dE\n", ret);
154		return CMD_RET_FAILURE;
155	}
156
157	return 0;
158}
159
160static int do_cedit_read_env(struct cmd_tbl *cmdtp, int flag, int argc,
161			     char *const argv[])
162{
163	bool verbose;
164	int ret;
165
166	if (check_cur_expo())
167		return CMD_RET_FAILURE;
168
169	verbose = argc > 1 && !strcmp(argv[1], "-v");
170
171	ret = cedit_read_settings_env(cur_exp, verbose);
172	if (ret) {
173		printf("Failed to read settings from environment: %dE\n", ret);
174		return CMD_RET_FAILURE;
175	}
176
177	return 0;
178}
179
180static int do_cedit_write_cmos(struct cmd_tbl *cmdtp, int flag, int argc,
181			       char *const argv[])
182{
183	struct udevice *dev;
184	bool verbose = false;
185	int ret;
186
187	if (check_cur_expo())
188		return CMD_RET_FAILURE;
189
190	if (argc > 1 && !strcmp(argv[1], "-v")) {
191		verbose = true;
192		argc--;
193		argv++;
194	}
195
196	if (argc > 1)
197		ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev);
198	else
199		ret = uclass_first_device_err(UCLASS_RTC, &dev);
200	if (ret) {
201		printf("Failed to get RTC device: %dE\n", ret);
202		return CMD_RET_FAILURE;
203	}
204
205	if (cedit_write_settings_cmos(cur_exp, dev, verbose)) {
206		printf("Failed to write settings to CMOS\n");
207		return CMD_RET_FAILURE;
208	}
209
210	return 0;
211}
212
213static int do_cedit_read_cmos(struct cmd_tbl *cmdtp, int flag, int argc,
214			      char *const argv[])
215{
216	struct udevice *dev;
217	bool verbose = false;
218	int ret;
219
220	if (check_cur_expo())
221		return CMD_RET_FAILURE;
222
223	if (argc > 1 && !strcmp(argv[1], "-v")) {
224		verbose = true;
225		argc--;
226		argv++;
227	}
228
229	if (argc > 1)
230		ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev);
231	else
232		ret = uclass_first_device_err(UCLASS_RTC, &dev);
233	if (ret) {
234		printf("Failed to get RTC device: %dE\n", ret);
235		return CMD_RET_FAILURE;
236	}
237
238	ret = cedit_read_settings_cmos(cur_exp, dev, verbose);
239	if (ret) {
240		printf("Failed to read settings from CMOS: %dE\n", ret);
241		return CMD_RET_FAILURE;
242	}
243
244	return 0;
245}
246
247static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
248			char *const argv[])
249{
250	ofnode node;
251	int ret;
252
253	if (check_cur_expo())
254		return CMD_RET_FAILURE;
255
256	node = ofnode_path("/bootstd/cedit-theme");
257	if (ofnode_valid(node)) {
258		ret = expo_apply_theme(cur_exp, node);
259		if (ret)
260			return CMD_RET_FAILURE;
261	} else {
262		log_warning("No theme found\n");
263	}
264	ret = cedit_run(cur_exp);
265	if (ret) {
266		log_err("Failed (err=%dE)\n", ret);
267		return CMD_RET_FAILURE;
268	}
269
270	return 0;
271}
272
273U_BOOT_LONGHELP(cedit,
274	"load <interface> <dev[:part]> <filename>   - load config editor\n"
275	"cedit read_fdt <i/f> <dev[:part]> <filename>     - read settings\n"
276	"cedit write_fdt <i/f> <dev[:part]> <filename>    - write settings\n"
277	"cedit read_env [-v]                              - read settings from env vars\n"
278	"cedit write_env [-v]                             - write settings to env vars\n"
279	"cedit read_cmos [-v] [dev]                       - read settings from CMOS RAM\n"
280	"cedit write_cmos [-v] [dev]                      - write settings to CMOS RAM\n"
281	"cedit run                                        - run config editor");
282
283U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text,
284	U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load),
285	U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt),
286	U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt),
287	U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env),
288	U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env),
289	U_BOOT_SUBCMD_MKENT(read_cmos, 2, 1, do_cedit_read_cmos),
290	U_BOOT_SUBCMD_MKENT(write_cmos, 2, 1, do_cedit_write_cmos),
291	U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run),
292);
293