100-04-env-add-support-for-generic-MTD-device.patch 10 KB

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