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

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