bcm_umi_bch.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 page);
  23. static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
  24. struct nand_chip *chip, const uint8_t *buf);
  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. *
  98. ***************************************************************************/
  99. static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
  100. struct nand_chip *chip, uint8_t * buf,
  101. int page)
  102. {
  103. int sectorIdx = 0;
  104. int eccsize = chip->ecc.size;
  105. int eccsteps = chip->ecc.steps;
  106. uint8_t *datap = buf;
  107. uint8_t eccCalc[NAND_ECC_NUM_BYTES];
  108. int sectorOobSize = mtd->oobsize / eccsteps;
  109. int stat;
  110. for (sectorIdx = 0; sectorIdx < eccsteps;
  111. sectorIdx++, datap += eccsize) {
  112. if (sectorIdx > 0) {
  113. /* Seek to page location within sector */
  114. chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
  115. -1);
  116. }
  117. /* Enable hardware ECC before reading the buf */
  118. nand_bcm_umi_bch_enable_read_hwecc();
  119. /* Read in data */
  120. bcm_umi_nand_read_buf(mtd, datap, eccsize);
  121. /* Pause hardware ECC after reading the buf */
  122. nand_bcm_umi_bch_pause_read_ecc_calc();
  123. /* Read the OOB ECC */
  124. chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
  125. mtd->writesize + sectorIdx * sectorOobSize, -1);
  126. nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
  127. NAND_ECC_NUM_BYTES,
  128. chip->oob_poi +
  129. sectorIdx * sectorOobSize);
  130. /* Correct any ECC detected errors */
  131. stat =
  132. nand_bcm_umi_bch_correct_page(datap, eccCalc,
  133. NAND_ECC_NUM_BYTES);
  134. /* Update Stats */
  135. if (stat < 0) {
  136. #if defined(NAND_BCM_UMI_DEBUG)
  137. printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
  138. __func__, sectorIdx);
  139. printk(KERN_WARNING
  140. "%s data %02x %02x %02x %02x "
  141. "%02x %02x %02x %02x\n",
  142. __func__, datap[0], datap[1], datap[2], datap[3],
  143. datap[4], datap[5], datap[6], datap[7]);
  144. printk(KERN_WARNING
  145. "%s ecc %02x %02x %02x %02x "
  146. "%02x %02x %02x %02x %02x %02x "
  147. "%02x %02x %02x\n",
  148. __func__, eccCalc[0], eccCalc[1], eccCalc[2],
  149. eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
  150. eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
  151. eccCalc[11], eccCalc[12]);
  152. BUG();
  153. #endif
  154. mtd->ecc_stats.failed++;
  155. } else {
  156. #if defined(NAND_BCM_UMI_DEBUG)
  157. if (stat > 0) {
  158. printk(KERN_INFO
  159. "%s %d correctable_errors detected\n",
  160. __func__, stat);
  161. }
  162. #endif
  163. mtd->ecc_stats.corrected += stat;
  164. }
  165. }
  166. return 0;
  167. }
  168. /****************************************************************************
  169. *
  170. * bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
  171. * @mtd: mtd info structure
  172. * @chip: nand chip info structure
  173. * @buf: data buffer
  174. *
  175. ***************************************************************************/
  176. static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
  177. struct nand_chip *chip, const uint8_t *buf)
  178. {
  179. int sectorIdx = 0;
  180. int eccsize = chip->ecc.size;
  181. int eccsteps = chip->ecc.steps;
  182. const uint8_t *datap = buf;
  183. uint8_t *oobp = chip->oob_poi;
  184. int sectorOobSize = mtd->oobsize / eccsteps;
  185. for (sectorIdx = 0; sectorIdx < eccsteps;
  186. sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
  187. /* Enable hardware ECC before writing the buf */
  188. nand_bcm_umi_bch_enable_write_hwecc();
  189. bcm_umi_nand_write_buf(mtd, datap, eccsize);
  190. nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
  191. NAND_ECC_NUM_BYTES);
  192. }
  193. bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
  194. }