e6e155bc146c9f7ce67ee007cdfdc57a217e3978
[openwrt/staging/noltari.git] / package / boot / uboot-mediatek / patches / 100-09-cmd-add-nmbm-command.patch
1 From 0af8d0aac77f4df4bc7dadbcdea5d9a16f5f3e45 Mon Sep 17 00:00:00 2001
2 From: Weijie Gao <weijie.gao@mediatek.com>
3 Date: Mon, 25 Jul 2022 10:44:57 +0800
4 Subject: [PATCH 43/71] cmd: add nmbm command
5
6 Add nmbm command for debugging, data operations and image-booting support
7
8 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
9 ---
10 cmd/Kconfig | 6 +
11 cmd/Makefile | 1 +
12 cmd/nmbm.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++++
13 3 files changed, 334 insertions(+)
14 create mode 100644 cmd/nmbm.c
15
16 --- a/cmd/Kconfig
17 +++ b/cmd/Kconfig
18 @@ -1260,6 +1260,12 @@ config CMD_NAND_TORTURE
19
20 endif # CMD_NAND
21
22 +config CMD_NMBM
23 + depends on NMBM_MTD
24 + bool "nmbm"
25 + help
26 + NAND mapping block management (NMBM) utility
27 +
28 config CMD_NVME
29 bool "nvme"
30 depends on NVME
31 --- a/cmd/Makefile
32 +++ b/cmd/Makefile
33 @@ -114,6 +114,7 @@ obj-y += legacy-mtd-utils.o
34 endif
35 obj-$(CONFIG_CMD_MUX) += mux.o
36 obj-$(CONFIG_CMD_NAND) += nand.o
37 +obj-$(CONFIG_CMD_NMBM) += nmbm.o
38 obj-$(CONFIG_CMD_NET) += net.o
39 obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o
40 obj-$(CONFIG_CMD_ONENAND) += onenand.o
41 --- /dev/null
42 +++ b/cmd/nmbm.c
43 @@ -0,0 +1,327 @@
44 +// SPDX-License-Identifier: GPL-2.0
45 +/*
46 + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
47 + *
48 + * Author: Weijie Gao <weijie.gao@mediatek.com>
49 + */
50 +
51 +#include <command.h>
52 +#include <image.h>
53 +#include <stdbool.h>
54 +#include <linux/types.h>
55 +#include <linux/mtd/mtd.h>
56 +#include <jffs2/load_kernel.h>
57 +
58 +#include <nmbm/nmbm-mtd.h>
59 +
60 +static int nmbm_parse_offset_size(struct mtd_info *mtd, char *off_str,
61 + char *size_str, uint64_t *off,
62 + uint64_t *size)
63 +{
64 + char *end;
65 +
66 + *off = simple_strtoull(off_str, &end, 16);
67 + if (end == off_str) {
68 + printf("Error: offset '%s' is invalid\n", off_str);
69 + return -EINVAL;
70 + }
71 +
72 + if (*off >= mtd->size) {
73 + printf("Error: offset '0x%llx' is beyond the end of device\n",
74 + *off);
75 + return -EINVAL;
76 + }
77 +
78 + *size = simple_strtoull(size_str, &end, 16);
79 + if (end == off_str) {
80 + printf("Error: size '%s' is invalid\n", off_str);
81 + return -EINVAL;
82 + }
83 +
84 + if (*off + *size > mtd->size) {
85 + printf("Error: size '0x%llx' is too large\n", *size);
86 + return -EINVAL;
87 + }
88 +
89 + return 0;
90 +}
91 +
92 +static int do_nmbm_erase(struct mtd_info *mtd, uint64_t offset, uint64_t size)
93 +{
94 + struct erase_info ei;
95 + int ret;
96 +
97 + memset(&ei, 0, sizeof(ei));
98 +
99 + ei.mtd = mtd;
100 + ei.addr = offset;
101 + ei.len = size;
102 +
103 + printf("Erasing from 0x%llx, size 0x%llx ...\n", offset, size);
104 +
105 + ret = mtd_erase(mtd, &ei);
106 +
107 + if (!ret) {
108 + printf("Succeeded\n");
109 + return CMD_RET_SUCCESS;
110 + }
111 +
112 + printf("Failed at 0x%llx\n", ei.fail_addr);
113 +
114 + return CMD_RET_FAILURE;
115 +}
116 +
117 +static int do_nmbm_rw(int read, struct mtd_info *mtd, uintptr_t addr,
118 + uint64_t offset, size_t size)
119 +{
120 + size_t retlen;
121 + int ret;
122 +
123 + printf("%s 0x%llx, size 0x%zx\n", read ? "Reading from" : "Writing to",
124 + offset, size);
125 +
126 + if (read)
127 + ret = mtd_read(mtd, offset, size, &retlen, (void *)addr);
128 + else
129 + ret = mtd_write(mtd, offset, size, &retlen, (void *)addr);
130 +
131 + if (!ret) {
132 + printf("Succeeded\n");
133 + return CMD_RET_SUCCESS;
134 + }
135 +
136 + printf("Failed at 0x%llx\n", offset + retlen);
137 +
138 + return CMD_RET_FAILURE;
139 +}
140 +
141 +static int do_nmbm_mtd_boot(struct cmd_tbl *cmdtp, struct mtd_info *mtd,
142 + int argc, char *const argv[])
143 +{
144 + bool print_image_contents = true;
145 + uintptr_t loadaddr = image_load_addr;
146 + char *end, *image_name;
147 + const char *ep;
148 + size_t retlen;
149 + uint32_t size;
150 + uint64_t off;
151 + int ret;
152 +
153 +#if defined(CONFIG_CMD_MTDPARTS)
154 + struct mtd_device *partdev;
155 + struct mtd_info *partmtd;
156 + struct part_info *part;
157 + u8 pnum;
158 +#endif
159 +
160 + ep = env_get("autostart");
161 +
162 + if (ep && !strcmp(ep, "yes"))
163 + print_image_contents = false;
164 +
165 + if (argc == 2) {
166 + loadaddr = simple_strtoul(argv[0], &end, 0);
167 + if (*end || end == argv[0]) {
168 + printf("'%s' is not a valid address\n", argv[0]);
169 + return CMD_RET_FAILURE;
170 + }
171 +
172 + argc--;
173 + argv++;
174 + }
175 +
176 + off = simple_strtoull(argv[0], &end, 0);
177 + if (*end || end == argv[0]) {
178 +#if defined(CONFIG_CMD_MTDPARTS)
179 + ret = mtdparts_init();
180 + if (ret)
181 + return CMD_RET_FAILURE;
182 +
183 + ret = find_dev_and_part(argv[0], &partdev, &pnum, &part);
184 + if (ret)
185 + return CMD_RET_FAILURE;
186 +
187 + if (partdev->id->type != MTD_DEV_TYPE_NMBM) {
188 + printf("'%s' is not a NMBM device partition\n",
189 + argv[0]);
190 + return CMD_RET_FAILURE;
191 + }
192 +
193 + partmtd = nmbm_mtd_get_upper_by_index(partdev->id->num);
194 +
195 + if (partmtd != mtd) {
196 + printf("'%s' does not belong to this device\n",
197 + argv[0]);
198 + return CMD_RET_FAILURE;
199 + }
200 +
201 + off = part->offset;
202 +#else
203 + printf("'%s' is not a valid offset\n", argv[0]);
204 + return CMD_RET_FAILURE;
205 +#endif
206 + }
207 +
208 + ret = mtd_read(mtd, off, sizeof(image_header_t), &retlen,
209 + (void *)loadaddr);
210 + if (ret || retlen != sizeof(image_header_t)) {
211 + printf("Failed to read NMBM at offset 0x%08llx\n", off);
212 + return CMD_RET_FAILURE;
213 + }
214 +
215 + switch (genimg_get_format((void *)loadaddr)) {
216 +#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
217 + case IMAGE_FORMAT_LEGACY:
218 + size = image_get_image_size((image_header_t *)loadaddr);
219 + image_name = "legacy";
220 + break;
221 +#endif
222 +#if defined(CONFIG_FIT)
223 + case IMAGE_FORMAT_FIT:
224 + size = fit_get_size((const void *)loadaddr);
225 + image_name = "FIT";
226 + break;
227 +#endif
228 + default:
229 + printf("Error: no Image found at offset 0x%08llx\n", off);
230 + return CMD_RET_FAILURE;
231 + }
232 +
233 + printf("Loading %s image at offset 0x%llx to memory 0x%08lx, size 0x%x ...\n",
234 + image_name, off, loadaddr, size);
235 +
236 + ret = mtd_read(mtd, off, size, &retlen, (void *)loadaddr);
237 + if (ret || retlen != size) {
238 + printf("Error: Failed to load image at offset 0x%08llx\n",
239 + off + retlen);
240 + return CMD_RET_FAILURE;
241 + }
242 +
243 + switch (genimg_get_format((void *)loadaddr)) {
244 +#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
245 + case IMAGE_FORMAT_LEGACY:
246 + if (print_image_contents)
247 + image_print_contents((void *)loadaddr);
248 + break;
249 +#endif
250 +#if defined(CONFIG_FIT)
251 + case IMAGE_FORMAT_FIT:
252 + if (print_image_contents)
253 + fit_print_contents((void *)loadaddr);
254 + break;
255 +#endif
256 + }
257 +
258 + image_load_addr = loadaddr;
259 +
260 + return bootm_maybe_autostart(cmdtp, "nmbm");
261 +}
262 +
263 +static int do_nmbm(struct cmd_tbl *cmdtp, int flag, int argc,
264 + char *const argv[])
265 +{
266 + struct mtd_info *mtd;
267 + uint64_t offset, size;
268 + char *end;
269 + uintptr_t addr;
270 + int ret, all = 0;
271 +
272 + if (argc == 1)
273 + return CMD_RET_USAGE;
274 +
275 + if (!strcmp(argv[1], "list")) {
276 + nmbm_mtd_list_devices();
277 + return CMD_RET_SUCCESS;
278 + }
279 +
280 + if (argc < 3)
281 + return CMD_RET_USAGE;
282 +
283 + if (!strcmp(argv[2], "info"))
284 + return !!nmbm_mtd_print_info(argv[1]);
285 +
286 + if (!strcmp(argv[2], "state"))
287 + return !!nmbm_mtd_print_states(argv[1]);
288 +
289 + if (!strcmp(argv[2], "bad"))
290 + return !!nmbm_mtd_print_bad_blocks(argv[1]);
291 +
292 + if (!strcmp(argv[2], "mapping")) {
293 + if (argc >= 4) {
294 + if (!strcmp(argv[3], "all"))
295 + all = 1;
296 + }
297 +
298 + return nmbm_mtd_print_mappings(argv[1], all);
299 + }
300 +
301 + if (argc < 4)
302 + return CMD_RET_USAGE;
303 +
304 + mtd = get_mtd_device_nm(argv[1]);
305 + if (IS_ERR(mtd)) {
306 + printf("Error: NMBM device '%s' not found\n", argv[1]);
307 + return CMD_RET_FAILURE;
308 + }
309 +
310 + if (mtd->type != MTD_DEV_TYPE_NMBM) {
311 + printf("Error: '%s' is not a NMBM device\n", argv[1]);
312 + return CMD_RET_FAILURE;
313 + }
314 +
315 + if (!strcmp(argv[2], "boot"))
316 + return do_nmbm_mtd_boot(cmdtp, mtd, argc - 3, argv + 3);
317 +
318 + if (argc < 5)
319 + return CMD_RET_USAGE;
320 +
321 + if (!strcmp(argv[2], "erase")) {
322 + ret = nmbm_parse_offset_size(mtd, argv[3], argv[4], &offset,
323 + &size);
324 + if (ret)
325 + return CMD_RET_FAILURE;
326 +
327 + return do_nmbm_erase(mtd, offset, size);
328 + }
329 +
330 + if (argc < 6)
331 + return CMD_RET_USAGE;
332 +
333 + ret = nmbm_parse_offset_size(mtd, argv[4], argv[5], &offset, &size);
334 + if (ret)
335 + return CMD_RET_FAILURE;
336 +
337 + if (size > SIZE_MAX) {
338 + printf("Error: size 0x%llx is too large\n", size);
339 + return -EINVAL;
340 + }
341 +
342 + addr = simple_strtoul(argv[3], &end, 16);
343 + if (end == argv[3]) {
344 + printf("Error: addr '%s' is invalid\n", argv[3]);
345 + return -EINVAL;
346 + }
347 +
348 + if (!strcmp(argv[2], "read"))
349 + return do_nmbm_rw(1, mtd, addr, offset, (size_t)size);
350 +
351 + if (!strcmp(argv[2], "write"))
352 + return do_nmbm_rw(0, mtd, addr, offset, (size_t)size);
353 +
354 + return CMD_RET_USAGE;
355 +}
356 +
357 +U_BOOT_CMD(
358 + nmbm, CONFIG_SYS_MAXARGS, 0, do_nmbm,
359 + "NMBM utility commands",
360 + "\n"
361 + "nmbm list - List NMBM devices\n"
362 + "nmbm <name> info - Display NMBM information\n"
363 + "nmbm <name> state - Display block states\n"
364 + "nmbm <name> bad - Display bad blocks\n"
365 + "nmbm <name> boot <part | [loadaddr] offset> - Boot from NMBM\n"
366 + "nmbm <name> mapping [all] - Display block mapping\n"
367 + "nmbm <name> erase <offset> <size> - Erase blocks\n"
368 + "nmbm <name> read <addr> <offset> <size> - Read data\n"
369 + "nmbm <name> write <addr> <offset> <size> - Write data\n"
370 +);