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