bbt.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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-bbt: " fmt
  10. #include <common.h>
  11. #include <dm/devres.h>
  12. #include <linux/bitops.h>
  13. #include <linux/mtd/nand.h>
  14. #ifndef __UBOOT__
  15. #include <linux/slab.h>
  16. #endif
  17. /**
  18. * nanddev_bbt_init() - Initialize the BBT (Bad Block Table)
  19. * @nand: NAND device
  20. *
  21. * Initialize the in-memory BBT.
  22. *
  23. * Return: 0 in case of success, a negative error code otherwise.
  24. */
  25. int nanddev_bbt_init(struct nand_device *nand)
  26. {
  27. unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
  28. unsigned int nblocks = nanddev_neraseblocks(nand);
  29. unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
  30. BITS_PER_LONG);
  31. nand->bbt.cache = kzalloc(nwords, GFP_KERNEL);
  32. if (!nand->bbt.cache)
  33. return -ENOMEM;
  34. return 0;
  35. }
  36. EXPORT_SYMBOL_GPL(nanddev_bbt_init);
  37. /**
  38. * nanddev_bbt_cleanup() - Cleanup the BBT (Bad Block Table)
  39. * @nand: NAND device
  40. *
  41. * Undoes what has been done in nanddev_bbt_init()
  42. */
  43. void nanddev_bbt_cleanup(struct nand_device *nand)
  44. {
  45. kfree(nand->bbt.cache);
  46. }
  47. EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
  48. /**
  49. * nanddev_bbt_update() - Update a BBT
  50. * @nand: nand device
  51. *
  52. * Update the BBT. Currently a NOP function since on-flash bbt is not yet
  53. * supported.
  54. *
  55. * Return: 0 in case of success, a negative error code otherwise.
  56. */
  57. int nanddev_bbt_update(struct nand_device *nand)
  58. {
  59. return 0;
  60. }
  61. EXPORT_SYMBOL_GPL(nanddev_bbt_update);
  62. /**
  63. * nanddev_bbt_get_block_status() - Return the status of an eraseblock
  64. * @nand: nand device
  65. * @entry: the BBT entry
  66. *
  67. * Return: a positive number nand_bbt_block_status status or -%ERANGE if @entry
  68. * is bigger than the BBT size.
  69. */
  70. int nanddev_bbt_get_block_status(const struct nand_device *nand,
  71. unsigned int entry)
  72. {
  73. unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
  74. unsigned long *pos = nand->bbt.cache +
  75. ((entry * bits_per_block) / BITS_PER_LONG);
  76. unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
  77. unsigned long status;
  78. if (entry >= nanddev_neraseblocks(nand))
  79. return -ERANGE;
  80. status = pos[0] >> offs;
  81. if (bits_per_block + offs > BITS_PER_LONG)
  82. status |= pos[1] << (BITS_PER_LONG - offs);
  83. return status & GENMASK(bits_per_block - 1, 0);
  84. }
  85. EXPORT_SYMBOL_GPL(nanddev_bbt_get_block_status);
  86. /**
  87. * nanddev_bbt_set_block_status() - Update the status of an eraseblock in the
  88. * in-memory BBT
  89. * @nand: nand device
  90. * @entry: the BBT entry to update
  91. * @status: the new status
  92. *
  93. * Update an entry of the in-memory BBT. If you want to push the updated BBT
  94. * the NAND you should call nanddev_bbt_update().
  95. *
  96. * Return: 0 in case of success or -%ERANGE if @entry is bigger than the BBT
  97. * size.
  98. */
  99. int nanddev_bbt_set_block_status(struct nand_device *nand, unsigned int entry,
  100. enum nand_bbt_block_status status)
  101. {
  102. unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
  103. unsigned long *pos = nand->bbt.cache +
  104. ((entry * bits_per_block) / BITS_PER_LONG);
  105. unsigned int offs = (entry * bits_per_block) % BITS_PER_LONG;
  106. unsigned long val = status & GENMASK(bits_per_block - 1, 0);
  107. if (entry >= nanddev_neraseblocks(nand))
  108. return -ERANGE;
  109. pos[0] &= ~GENMASK(offs + bits_per_block - 1, offs);
  110. pos[0] |= val << offs;
  111. if (bits_per_block + offs > BITS_PER_LONG) {
  112. unsigned int rbits = bits_per_block + offs - BITS_PER_LONG;
  113. pos[1] &= ~GENMASK(rbits - 1, 0);
  114. pos[1] |= val >> (bits_per_block - rbits);
  115. }
  116. return 0;
  117. }
  118. EXPORT_SYMBOL_GPL(nanddev_bbt_set_block_status);