bcm_umi_bch.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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
  142. "%s data %02x %02x %02x %02x "
  143. "%02x %02x %02x %02x\n",
  144. __func__, datap[0], datap[1], datap[2], datap[3],
  145. datap[4], datap[5], datap[6], datap[7]);
  146. printk(KERN_WARNING
  147. "%s ecc %02x %02x %02x %02x "
  148. "%02x %02x %02x %02x %02x %02x "
  149. "%02x %02x %02x\n",
  150. __func__, eccCalc[0], eccCalc[1], eccCalc[2],
  151. eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
  152. eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
  153. eccCalc[11], eccCalc[12]);
  154. BUG();
  155. #endif
  156. mtd->ecc_stats.failed++;
  157. } else {
  158. #if defined(NAND_BCM_UMI_DEBUG)
  159. if (stat > 0) {
  160. printk(KERN_INFO
  161. "%s %d correctable_errors detected\n",
  162. __func__, stat);
  163. }
  164. #endif
  165. mtd->ecc_stats.corrected += stat;
  166. max_bitflips = max_t(unsigned int, max_bitflips, stat);
  167. }
  168. }
  169. return max_bitflips;
  170. }
  171. /****************************************************************************
  172. *
  173. * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
  174. * @mtd: mtd info structure
  175. * @chip: nand chip info structure
  176. * @buf: data buffer
  177. * @oob_required: must write chip->oob_poi to OOB
  178. *
  179. ***************************************************************************/
  180. static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
  181. struct nand_chip *chip, const uint8_t *buf, int oob_required)
  182. {
  183. int sectorIdx = 0;
  184. int eccsize = chip->ecc.size;
  185. int eccsteps = chip->ecc.steps;
  186. const uint8_t *datap = buf;
  187. uint8_t *oobp = chip->oob_poi;
  188. int sectorOobSize = mtd->oobsize / eccsteps;
  189. for (sectorIdx = 0; sectorIdx < eccsteps;
  190. sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
  191. /* Enable hardware ECC before writing the buf */
  192. nand_bcm_umi_bch_enable_write_hwecc();
  193. bcm_umi_nand_write_buf(mtd, datap, eccsize);
  194. nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
  195. NAND_ECC_NUM_BYTES);
  196. }
  197. bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
  198. return 0;
  199. }