core.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2017 Free Electrons
  4. *
  5. * Authors:
  6. * Boris Brezillon <boris.brezillon@free-electrons.com>
  7. * Peter Pan <peterpandong@micron.com>
  8. */
  9. #define pr_fmt(fmt) "nand: " fmt
  10. #include <common.h>
  11. #ifndef __UBOOT__
  12. #include <linux/compat.h>
  13. #include <linux/module.h>
  14. #endif
  15. #include <linux/bitops.h>
  16. #include <linux/mtd/nand.h>
  17. /**
  18. * nanddev_isbad() - Check if a block is bad
  19. * @nand: NAND device
  20. * @pos: position pointing to the block we want to check
  21. *
  22. * Return: true if the block is bad, false otherwise.
  23. */
  24. bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
  25. {
  26. if (nanddev_bbt_is_initialized(nand)) {
  27. unsigned int entry;
  28. int status;
  29. entry = nanddev_bbt_pos_to_entry(nand, pos);
  30. status = nanddev_bbt_get_block_status(nand, entry);
  31. /* Lazy block status retrieval */
  32. if (status == NAND_BBT_BLOCK_STATUS_UNKNOWN) {
  33. if (nand->ops->isbad(nand, pos))
  34. status = NAND_BBT_BLOCK_FACTORY_BAD;
  35. else
  36. status = NAND_BBT_BLOCK_GOOD;
  37. nanddev_bbt_set_block_status(nand, entry, status);
  38. }
  39. if (status == NAND_BBT_BLOCK_WORN ||
  40. status == NAND_BBT_BLOCK_FACTORY_BAD)
  41. return true;
  42. return false;
  43. }
  44. return nand->ops->isbad(nand, pos);
  45. }
  46. EXPORT_SYMBOL_GPL(nanddev_isbad);
  47. /**
  48. * nanddev_markbad() - Mark a block as bad
  49. * @nand: NAND device
  50. * @pos: position of the block to mark bad
  51. *
  52. * Mark a block bad. This function is updating the BBT if available and
  53. * calls the low-level markbad hook (nand->ops->markbad()).
  54. *
  55. * Return: 0 in case of success, a negative error code otherwise.
  56. */
  57. int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos)
  58. {
  59. struct mtd_info *mtd = nanddev_to_mtd(nand);
  60. unsigned int entry;
  61. int ret = 0;
  62. if (nanddev_isbad(nand, pos))
  63. return 0;
  64. ret = nand->ops->markbad(nand, pos);
  65. if (ret)
  66. pr_warn("failed to write BBM to block @%llx (err = %d)\n",
  67. nanddev_pos_to_offs(nand, pos), ret);
  68. if (!nanddev_bbt_is_initialized(nand))
  69. goto out;
  70. entry = nanddev_bbt_pos_to_entry(nand, pos);
  71. ret = nanddev_bbt_set_block_status(nand, entry, NAND_BBT_BLOCK_WORN);
  72. if (ret)
  73. goto out;
  74. ret = nanddev_bbt_update(nand);
  75. out:
  76. if (!ret)
  77. mtd->ecc_stats.badblocks++;
  78. return ret;
  79. }
  80. EXPORT_SYMBOL_GPL(nanddev_markbad);
  81. /**
  82. * nanddev_isreserved() - Check whether an eraseblock is reserved or not
  83. * @nand: NAND device
  84. * @pos: NAND position to test
  85. *
  86. * Checks whether the eraseblock pointed by @pos is reserved or not.
  87. *
  88. * Return: true if the eraseblock is reserved, false otherwise.
  89. */
  90. bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos)
  91. {
  92. unsigned int entry;
  93. int status;
  94. if (!nanddev_bbt_is_initialized(nand))
  95. return false;
  96. /* Return info from the table */
  97. entry = nanddev_bbt_pos_to_entry(nand, pos);
  98. status = nanddev_bbt_get_block_status(nand, entry);
  99. return status == NAND_BBT_BLOCK_RESERVED;
  100. }
  101. EXPORT_SYMBOL_GPL(nanddev_isreserved);
  102. /**
  103. * nanddev_erase() - Erase a NAND portion
  104. * @nand: NAND device
  105. * @pos: position of the block to erase
  106. *
  107. * Erases the block if it's not bad.
  108. *
  109. * Return: 0 in case of success, a negative error code otherwise.
  110. */
  111. int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos)
  112. {
  113. unsigned int entry;
  114. if (nanddev_isbad(nand, pos) || nanddev_isreserved(nand, pos)) {
  115. pr_warn("attempt to erase a bad/reserved block @%llx\n",
  116. nanddev_pos_to_offs(nand, pos));
  117. if (nanddev_isreserved(nand, pos))
  118. return -EIO;
  119. /* remove bad block from BBT */
  120. entry = nanddev_bbt_pos_to_entry(nand, pos);
  121. nanddev_bbt_set_block_status(nand, entry,
  122. NAND_BBT_BLOCK_STATUS_UNKNOWN);
  123. }
  124. return nand->ops->erase(nand, pos);
  125. }
  126. EXPORT_SYMBOL_GPL(nanddev_erase);
  127. /**
  128. * nanddev_mtd_erase() - Generic mtd->_erase() implementation for NAND devices
  129. * @mtd: MTD device
  130. * @einfo: erase request
  131. *
  132. * This is a simple mtd->_erase() implementation iterating over all blocks
  133. * concerned by @einfo and calling nand->ops->erase() on each of them.
  134. *
  135. * Note that mtd->_erase should not be directly assigned to this helper,
  136. * because there's no locking here. NAND specialized layers should instead
  137. * implement there own wrapper around nanddev_mtd_erase() taking the
  138. * appropriate lock before calling nanddev_mtd_erase().
  139. *
  140. * Return: 0 in case of success, a negative error code otherwise.
  141. */
  142. int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
  143. {
  144. struct nand_device *nand = mtd_to_nanddev(mtd);
  145. struct nand_pos pos, last;
  146. int ret;
  147. nanddev_offs_to_pos(nand, einfo->addr, &pos);
  148. nanddev_offs_to_pos(nand, einfo->addr + einfo->len - 1, &last);
  149. while (nanddev_pos_cmp(&pos, &last) <= 0) {
  150. ret = nanddev_erase(nand, &pos);
  151. if (ret) {
  152. einfo->fail_addr = nanddev_pos_to_offs(nand, &pos);
  153. return ret;
  154. }
  155. nanddev_pos_next_eraseblock(nand, &pos);
  156. }
  157. return 0;
  158. }
  159. EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
  160. /**
  161. * nanddev_init() - Initialize a NAND device
  162. * @nand: NAND device
  163. * @ops: NAND device operations
  164. * @owner: NAND device owner
  165. *
  166. * Initializes a NAND device object. Consistency checks are done on @ops and
  167. * @nand->memorg. Also takes care of initializing the BBT.
  168. *
  169. * Return: 0 in case of success, a negative error code otherwise.
  170. */
  171. int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
  172. struct module *owner)
  173. {
  174. struct mtd_info *mtd = nanddev_to_mtd(nand);
  175. struct nand_memory_organization *memorg = nanddev_get_memorg(nand);
  176. if (!nand || !ops)
  177. return -EINVAL;
  178. if (!ops->erase || !ops->markbad || !ops->isbad)
  179. return -EINVAL;
  180. if (!memorg->bits_per_cell || !memorg->pagesize ||
  181. !memorg->pages_per_eraseblock || !memorg->eraseblocks_per_lun ||
  182. !memorg->planes_per_lun || !memorg->luns_per_target ||
  183. !memorg->ntargets)
  184. return -EINVAL;
  185. nand->rowconv.eraseblock_addr_shift =
  186. fls(memorg->pages_per_eraseblock - 1);
  187. nand->rowconv.lun_addr_shift = fls(memorg->eraseblocks_per_lun - 1) +
  188. nand->rowconv.eraseblock_addr_shift;
  189. nand->ops = ops;
  190. mtd->type = memorg->bits_per_cell == 1 ?
  191. MTD_NANDFLASH : MTD_MLCNANDFLASH;
  192. mtd->flags = MTD_CAP_NANDFLASH;
  193. mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
  194. mtd->writesize = memorg->pagesize;
  195. mtd->writebufsize = memorg->pagesize;
  196. mtd->oobsize = memorg->oobsize;
  197. mtd->size = nanddev_size(nand);
  198. mtd->owner = owner;
  199. return nanddev_bbt_init(nand);
  200. }
  201. EXPORT_SYMBOL_GPL(nanddev_init);
  202. /**
  203. * nanddev_cleanup() - Release resources allocated in nanddev_init()
  204. * @nand: NAND device
  205. *
  206. * Basically undoes what has been done in nanddev_init().
  207. */
  208. void nanddev_cleanup(struct nand_device *nand)
  209. {
  210. if (nanddev_bbt_is_initialized(nand))
  211. nanddev_bbt_cleanup(nand);
  212. }
  213. EXPORT_SYMBOL_GPL(nanddev_cleanup);
  214. MODULE_DESCRIPTION("Generic NAND framework");
  215. MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
  216. MODULE_LICENSE("GPL v2");