bcm_umi_bch.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*****************************************************************************
  2. * Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
  3. *
  4. * Unless you and Broadcom execute a separate written software license
  5. * agreement governing use of this software, this software is licensed to you
  6. * under the terms of the GNU General Public License version 2, available at
  7. * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  8. *
  9. * Notwithstanding the above, under no circumstances may you combine this
  10. * software in any way with any other Broadcom software provided under a
  11. * license other than the GPL, without Broadcom's express prior written
  12. * consent.
  13. *****************************************************************************/
  14. /* ---- Include Files ---------------------------------------------------- */
  15. #include "nand_bcm_umi.h"
  16. /* ---- External Variable Declarations ----------------------------------- */
  17. /* ---- External Function Prototypes ------------------------------------- */
  18. /* ---- Public Variables ------------------------------------------------- */
  19. /* ---- Private Constants and Types -------------------------------------- */
  20. /* ---- Private Function Prototypes -------------------------------------- */
  21. static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
  22. struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
  23. static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
  24. struct nand_chip *chip, const uint8_t *buf, int oob_required);
  25. /* ---- Private Variables ------------------------------------------------ */
  26. /*
  27. ** nand_hw_eccoob
  28. ** New oob placement block for use with hardware ecc generation.
  29. */
  30. static struct nand_ecclayout nand_hw_eccoob_512 = {
  31. /* Reserve 5 for BI indicator */
  32. .oobfree = {
  33. #if (NAND_ECC_NUM_BYTES > 3)
  34. {.offset = 0, .length = 2}
  35. #else
  36. {.offset = 0, .length = 5},
  37. {.offset = 6, .length = 7}
  38. #endif
  39. }
  40. };
  41. /*
  42. ** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
  43. ** except the BI is at byte 0.
  44. */
  45. static struct nand_ecclayout nand_hw_eccoob_2048 = {
  46. /* Reserve 0 as BI indicator */
  47. .oobfree = {
  48. #if (NAND_ECC_NUM_BYTES > 10)
  49. {.offset = 1, .length = 2},
  50. #elif (NAND_ECC_NUM_BYTES > 7)
  51. {.offset = 1, .length = 5},
  52. {.offset = 16, .length = 6},
  53. {.offset = 32, .length = 6},
  54. {.offset = 48, .length = 6}
  55. #else
  56. {.offset = 1, .length = 8},
  57. {.offset = 16, .length = 9},
  58. {.offset = 32, .length = 9},
  59. {.offset = 48, .length = 9}
  60. #endif
  61. }
  62. };
  63. /* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
  64. * except the BI is at byte 0. */
  65. static struct nand_ecclayout nand_hw_eccoob_4096 = {
  66. /* Reserve 0 as BI indicator */
  67. .oobfree = {
  68. #if (NAND_ECC_NUM_BYTES > 10)
  69. {.offset = 1, .length = 2},
  70. {.offset = 16, .length = 3},
  71. {.offset = 32, .length = 3},
  72. {.offset = 48, .length = 3},
  73. {.offset = 64, .length = 3},
  74. {.offset = 80, .length = 3},
  75. {.offset = 96, .length = 3},
  76. {.offset = 112, .length = 3}
  77. #else
  78. {.offset = 1, .length = 5},
  79. {.offset = 16, .length = 6},
  80. {.offset = 32, .length = 6},
  81. {.offset = 48, .length = 6},
  82. {.offset = 64, .length = 6},
  83. {.offset = 80, .length = 6},
  84. {.offset = 96, .length = 6},
  85. {.offset = 112, .length = 6}
  86. #endif
  87. }
  88. };
  89. /* ---- Private Functions ------------------------------------------------ */
  90. /* ==== Public Functions ================================================= */
  91. /****************************************************************************
  92. *
  93. * bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
  94. * @mtd: mtd info structure
  95. * @chip: nand chip info structure
  96. * @buf: buffer to store read data
  97. * @oob_required: caller expects OOB data read to chip->oob_poi
  98. *
  99. ***************************************************************************/
  100. static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
  101. struct nand_chip *chip, uint8_t * buf,
  102. int oob_required, int page)
  103. {
  104. int sectorIdx = 0;
  105. int eccsize = chip->ecc.size;
  106. int eccsteps = chip->ecc.steps;
  107. uint8_t *datap = buf;
  108. uint8_t eccCalc[NAND_ECC_NUM_BYTES];
  109. int sectorOobSize = mtd->oobsize / eccsteps;
  110. int stat;
  111. unsigned int max_bitflips = 0;
  112. for (sectorIdx = 0; sectorIdx < eccsteps;
  113. sectorIdx++, datap += eccsize) {
  114. if (sectorIdx > 0) {
  115. /* Seek to page location within sector */
  116. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
  117. -1);
  118. }
  119. /* Enable hardware ECC before reading the buf */
  120. nand_bcm_umi_bch_enable_read_hwecc();
  121. /* Read in data */
  122. bcm_umi_nand_read_buf(mtd, datap, eccsize);
  123. /* Pause hardware ECC after reading the buf */
  124. nand_bcm_umi_bch_pause_read_ecc_calc();
  125. /* Read the OOB ECC */
  126. chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
  127. mtd->writesize + sectorIdx * sectorOobSize, -1);
  128. nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
  129. NAND_ECC_NUM_BYTES,
  130. chip->oob_poi +
  131. sectorIdx * sectorOobSize);
  132. /* Correct any ECC detected errors */
  133. stat =
  134. nand_bcm_umi_bch_correct_page(datap, eccCalc,
  135. NAND_ECC_NUM_BYTES);
  136. /* Update Stats */
  137. if (stat < 0) {
  138. #if defined(NAND_BCM_UMI_DEBUG)
  139. printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
  140. __func__, sectorIdx);
  141. printk(KERN_WARNING "%s data %*ph\n",
  142. __func__, 8, datap);
  143. printk(KERN_WARNING "%s ecc %*ph\n",
  144. __func__, 13, eccCalc);
  145. BUG();
  146. #endif
  147. mtd->ecc_stats.failed++;
  148. } else {
  149. #if defined(NAND_BCM_UMI_DEBUG)
  150. if (stat > 0) {
  151. printk(KERN_INFO
  152. "%s %d correctable_errors detected\n",
  153. __func__, stat);
  154. }
  155. #endif
  156. mtd->ecc_stats.corrected += stat;
  157. max_bitflips = max_t(unsigned int, max_bitflips, stat);
  158. }
  159. }
  160. return max_bitflips;
  161. }
  162. /****************************************************************************
  163. *
  164. * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
  165. * @mtd: mtd info structure
  166. * @chip: nand chip info structure
  167. * @buf: data buffer
  168. * @oob_required: must write chip->oob_poi to OOB
  169. *
  170. ***************************************************************************/
  171. static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
  172. struct nand_chip *chip, const uint8_t *buf, int oob_required)
  173. {
  174. int sectorIdx = 0;
  175. int eccsize = chip->ecc.size;
  176. int eccsteps = chip->ecc.steps;
  177. const uint8_t *datap = buf;
  178. uint8_t *oobp = chip->oob_poi;
  179. int sectorOobSize = mtd->oobsize / eccsteps;
  180. for (sectorIdx = 0; sectorIdx < eccsteps;
  181. sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
  182. /* Enable hardware ECC before writing the buf */
  183. nand_bcm_umi_bch_enable_write_hwecc();
  184. bcm_umi_nand_write_buf(mtd, datap, eccsize);
  185. nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
  186. NAND_ECC_NUM_BYTES);
  187. }
  188. bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
  189. return 0;
  190. }