uboot-mediatek: update to U-Boot 2024.01 release
[openwrt/openwrt.git] / package / boot / uboot-mediatek / patches / 100-04-env-add-support-for-generic-MTD-device.patch
1 From efc3e6f5d29f87a433b42f15a0b87e04b7cd498d Mon Sep 17 00:00:00 2001
2 From: Weijie Gao <weijie.gao@mediatek.com>
3 Date: Wed, 3 Mar 2021 10:11:32 +0800
4 Subject: [PATCH 38/71] env: add support for generic MTD device
5
6 Add an env driver for generic MTD device.
7
8 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
9 ---
10 cmd/nvedit.c | 3 +-
11 env/Kconfig | 37 +++++-
12 env/Makefile | 1 +
13 env/env.c | 3 +
14 env/mtd.c | 256 +++++++++++++++++++++++++++++++++++++++++
15 include/env_internal.h | 1 +
16 tools/Makefile | 1 +
17 7 files changed, 299 insertions(+), 3 deletions(-)
18 create mode 100644 env/mtd.c
19
20 --- a/env/Kconfig
21 +++ b/env/Kconfig
22 @@ -61,7 +61,7 @@ config ENV_IS_DEFAULT
23 !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \
24 !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \
25 !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \
26 - !ENV_IS_IN_UBI
27 + !ENV_IS_IN_UBI && !ENV_IS_IN_MTD
28 select ENV_IS_NOWHERE
29
30 config ENV_IS_NOWHERE
31 @@ -254,6 +254,27 @@ config ENV_IS_IN_MMC
32 offset: "u-boot,mmc-env-offset", "u-boot,mmc-env-offset-redundant".
33 CONFIG_ENV_OFFSET and CONFIG_ENV_OFFSET_REDUND are not used.
34
35 +config ENV_IS_IN_MTD
36 + bool "Environment in a MTD device"
37 + depends on !CHAIN_OF_TRUST
38 + depends on MTD
39 + help
40 + Define this if you have a MTD device which you want to use for
41 + the environment.
42 +
43 + - CONFIG_ENV_MTD_NAME:
44 + - CONFIG_ENV_OFFSET:
45 + - CONFIG_ENV_SIZE:
46 +
47 + These three #defines specify the MTD device where the environment
48 + is stored, offset and size of the environment area within the MTD
49 + device. CONFIG_ENV_OFFSET must be aligned to an erase block boundary.
50 +
51 + - CONFIG_ENV_SIZE_REDUND:
52 +
53 + This #define specify the maximum size allowed for read/write/erase
54 + with skipped bad blocks starting from ENV_OFFSET.
55 +
56 config ENV_IS_IN_NAND
57 bool "Environment in a NAND device"
58 depends on !CHAIN_OF_TRUST
59 @@ -561,10 +582,16 @@ config ENV_ADDR_REDUND
60 Offset from the start of the device (or partition) of the redundant
61 environment location.
62
63 +config ENV_MTD_NAME
64 + string "Name of the MTD device storing the environment"
65 + depends on ENV_IS_IN_MTD
66 + help
67 + Name of the MTD device that stores the environment
68 +
69 config ENV_OFFSET
70 hex "Environment offset"
71 depends on ENV_IS_IN_EEPROM || ENV_IS_IN_MMC || ENV_IS_IN_NAND || \
72 - ENV_IS_IN_SPI_FLASH
73 + ENV_IS_IN_SPI_FLASH || ENV_IS_IN_MTD
74 default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
75 default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
76 default 0xF0000 if ARCH_SUNXI
77 @@ -622,6 +649,12 @@ config ENV_SECT_SIZE
78 help
79 Size of the sector containing the environment.
80
81 +config ENV_SIZE_REDUND
82 + hex "Redundant environment size"
83 + depends on ENV_IS_IN_MTD
84 + help
85 + The maximum size allowed for read/write/erase with skipped bad blocks.
86 +
87 config ENV_UBI_PART
88 string "UBI partition name"
89 depends on ENV_IS_IN_UBI
90 --- a/env/Makefile
91 +++ b/env/Makefile
92 @@ -24,6 +24,7 @@ obj-$(CONFIG_$(SPL_TPL_)ENV_IS_NOWHERE)
93 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MMC) += mmc.o
94 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FAT) += fat.o
95 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_EXT4) += ext4.o
96 +obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_MTD) += mtd.o
97 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_NAND) += nand.o
98 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_SPI_FLASH) += sf.o
99 obj-$(CONFIG_$(SPL_TPL_)ENV_IS_IN_FLASH) += flash.o
100 --- a/env/env.c
101 +++ b/env/env.c
102 @@ -46,6 +46,9 @@ static enum env_location env_locations[]
103 #ifdef CONFIG_ENV_IS_IN_MMC
104 ENVL_MMC,
105 #endif
106 +#ifdef CONFIG_ENV_IS_IN_MTD
107 + ENVL_MTD,
108 +#endif
109 #ifdef CONFIG_ENV_IS_IN_NAND
110 ENVL_NAND,
111 #endif
112 --- /dev/null
113 +++ b/env/mtd.c
114 @@ -0,0 +1,256 @@
115 +/* SPDX-License-Identifier: GPL-2.0 */
116 +/*
117 + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
118 + *
119 + * Author: Weijie Gao <weijie.gao@mediatek.com>
120 + */
121 +
122 +#include <command.h>
123 +#include <env.h>
124 +#include <env_internal.h>
125 +#include <errno.h>
126 +#include <linux/kernel.h>
127 +#include <linux/stddef.h>
128 +#include <linux/types.h>
129 +#include <linux/mtd/mtd.h>
130 +#include <malloc.h>
131 +#include <memalign.h>
132 +#include <mtd.h>
133 +#include <search.h>
134 +
135 +#if CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE
136 +#undef CONFIG_ENV_SIZE_REDUND
137 +#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE
138 +#endif
139 +
140 +#if defined(ENV_IS_EMBEDDED)
141 +env_t *env_ptr = &environment;
142 +#else /* ! ENV_IS_EMBEDDED */
143 +env_t *env_ptr;
144 +#endif /* ENV_IS_EMBEDDED */
145 +
146 +DECLARE_GLOBAL_DATA_PTR;
147 +
148 +static int env_mtd_init(void)
149 +{
150 +#if defined(ENV_IS_EMBEDDED)
151 + int crc1_ok = 0, crc2_ok = 0;
152 + env_t *tmp_env1;
153 +
154 + tmp_env1 = env_ptr;
155 + crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
156 +
157 + if (!crc1_ok && !crc2_ok) {
158 + gd->env_addr = 0;
159 + gd->env_valid = ENV_INVALID;
160 +
161 + return 0;
162 + } else if (crc1_ok && !crc2_ok) {
163 + gd->env_valid = ENV_VALID;
164 + }
165 +
166 + if (gd->env_valid == ENV_VALID)
167 + env_ptr = tmp_env1;
168 +
169 + gd->env_addr = (ulong)env_ptr->data;
170 +
171 +#else /* ENV_IS_EMBEDDED */
172 + gd->env_addr = (ulong)&default_environment[0];
173 + gd->env_valid = ENV_VALID;
174 +#endif /* ENV_IS_EMBEDDED */
175 +
176 + return 0;
177 +}
178 +
179 +static struct mtd_info *env_mtd_get_dev(void)
180 +{
181 + struct mtd_info *mtd;
182 +
183 + mtd_probe_devices();
184 +
185 + mtd = get_mtd_device_nm(CONFIG_ENV_MTD_NAME);
186 + if (IS_ERR(mtd) || !mtd) {
187 + printf("MTD device '%s' not found\n", CONFIG_ENV_MTD_NAME);
188 + return NULL;
189 + }
190 +
191 + return mtd;
192 +}
193 +
194 +static inline bool mtd_addr_is_block_aligned(struct mtd_info *mtd, u64 addr)
195 +{
196 + return (addr & mtd->erasesize_mask) == 0;
197 +}
198 +
199 +static int mtd_io_skip_bad(struct mtd_info *mtd, bool read, loff_t offset,
200 + size_t length, size_t redund, u8 *buffer)
201 +{
202 + struct mtd_oob_ops io_op = {};
203 + size_t remaining = length;
204 + loff_t off, end;
205 + int ret;
206 +
207 + io_op.mode = MTD_OPS_PLACE_OOB;
208 + io_op.len = mtd->writesize;
209 + io_op.datbuf = (void *)buffer;
210 +
211 + /* Search for the first good block after the given offset */
212 + off = offset;
213 + end = (off + redund) | (mtd->erasesize - 1);
214 + while (mtd_block_isbad(mtd, off) && off < end)
215 + off += mtd->erasesize;
216 +
217 + /* Reached end position */
218 + if (off >= end)
219 + return -EIO;
220 +
221 + /* Loop over the pages to do the actual read/write */
222 + while (remaining) {
223 + /* Skip the block if it is bad */
224 + if (mtd_addr_is_block_aligned(mtd, off) &&
225 + mtd_block_isbad(mtd, off)) {
226 + off += mtd->erasesize;
227 + continue;
228 + }
229 +
230 + if (read)
231 + ret = mtd_read_oob(mtd, off, &io_op);
232 + else
233 + ret = mtd_write_oob(mtd, off, &io_op);
234 +
235 + if (ret) {
236 + printf("Failure while %s at offset 0x%llx\n",
237 + read ? "reading" : "writing", off);
238 + break;
239 + }
240 +
241 + off += io_op.retlen;
242 + remaining -= io_op.retlen;
243 + io_op.datbuf += io_op.retlen;
244 + io_op.oobbuf += io_op.oobretlen;
245 +
246 + /* Reached end position */
247 + if (off >= end)
248 + return -EIO;
249 + }
250 +
251 + return 0;
252 +}
253 +
254 +#ifdef CONFIG_CMD_SAVEENV
255 +static int mtd_erase_skip_bad(struct mtd_info *mtd, loff_t offset,
256 + size_t length, size_t redund)
257 +{
258 + struct erase_info erase_op = {};
259 + loff_t end = (offset + redund) | (mtd->erasesize - 1);
260 + int ret;
261 +
262 + erase_op.mtd = mtd;
263 + erase_op.addr = offset;
264 + erase_op.len = length;
265 +
266 + while (erase_op.len) {
267 + ret = mtd_erase(mtd, &erase_op);
268 +
269 + /* Abort if its not a bad block error */
270 + if (ret != -EIO)
271 + return ret;
272 +
273 + printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr);
274 +
275 + /* Skip bad block and continue behind it */
276 + erase_op.len -= erase_op.fail_addr - erase_op.addr;
277 + erase_op.len -= mtd->erasesize;
278 + erase_op.addr = erase_op.fail_addr + mtd->erasesize;
279 +
280 + /* Reached end position */
281 + if (erase_op.addr >= end)
282 + return -EIO;
283 + }
284 +
285 + return 0;
286 +}
287 +
288 +static int env_mtd_save(void)
289 +{
290 + ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
291 + struct mtd_info *mtd;
292 + int ret = 0;
293 +
294 + ret = env_export(env_new);
295 + if (ret)
296 + return ret;
297 +
298 + mtd = env_mtd_get_dev();
299 + if (!mtd)
300 + return 1;
301 +
302 + printf("Erasing on MTD device '%s'... ", mtd->name);
303 +
304 + ret = mtd_erase_skip_bad(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
305 + CONFIG_ENV_SIZE_REDUND);
306 +
307 + puts(ret ? "FAILED\n" : "OK\n");
308 +
309 + if (ret) {
310 + put_mtd_device(mtd);
311 + return 1;
312 + }
313 +
314 + printf("Writing to MTD device '%s'... ", mtd->name);
315 +
316 + ret = mtd_io_skip_bad(mtd, false, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
317 + CONFIG_ENV_SIZE_REDUND, (u8 *)env_new);
318 +
319 + puts(ret ? "FAILED\n" : "OK\n");
320 +
321 + put_mtd_device(mtd);
322 +
323 + return !!ret;
324 +}
325 +#endif /* CONFIG_CMD_SAVEENV */
326 +
327 +static int readenv(size_t offset, u_char *buf)
328 +{
329 + struct mtd_info *mtd;
330 + int ret;
331 +
332 + mtd = env_mtd_get_dev();
333 + if (!mtd)
334 + return 1;
335 +
336 + ret = mtd_io_skip_bad(mtd, true, offset, CONFIG_ENV_SIZE,
337 + CONFIG_ENV_SIZE_REDUND, buf);
338 +
339 + put_mtd_device(mtd);
340 +
341 + return !!ret;
342 +}
343 +
344 +static int env_mtd_load(void)
345 +{
346 +#if !defined(ENV_IS_EMBEDDED)
347 + ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
348 + int ret;
349 +
350 + ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
351 + if (ret) {
352 + env_set_default("readenv() failed", 0);
353 + return -EIO;
354 + }
355 +
356 + return env_import(buf, 1, H_EXTERNAL);
357 +#endif /* ! ENV_IS_EMBEDDED */
358 +
359 + return 0;
360 +}
361 +
362 +U_BOOT_ENV_LOCATION(mtd) = {
363 + .location = ENVL_MTD,
364 + ENV_NAME("MTD")
365 + .load = env_mtd_load,
366 +#if defined(CONFIG_CMD_SAVEENV)
367 + .save = env_save_ptr(env_mtd_save),
368 +#endif
369 + .init = env_mtd_init,
370 +};
371 --- a/include/env_internal.h
372 +++ b/include/env_internal.h
373 @@ -109,6 +109,7 @@ enum env_location {
374 ENVL_FAT,
375 ENVL_FLASH,
376 ENVL_MMC,
377 + ENVL_MTD,
378 ENVL_NAND,
379 ENVL_NVRAM,
380 ENVL_ONENAND,
381 --- a/tools/Makefile
382 +++ b/tools/Makefile
383 @@ -37,6 +37,7 @@ subdir-$(HOST_TOOLS_ALL) += gdb
384 ENVCRC-$(CONFIG_ENV_IS_IN_EEPROM) = y
385 ENVCRC-$(CONFIG_ENV_IS_IN_FLASH) = y
386 ENVCRC-$(CONFIG_ENV_IS_IN_ONENAND) = y
387 +ENVCRC-$(CONFIG_ENV_IS_IN_MTD) = y
388 ENVCRC-$(CONFIG_ENV_IS_IN_NAND) = y
389 ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y
390 ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y