nand_bcm_umi.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*****************************************************************************
  2. * Copyright 2003 - 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. #ifndef NAND_BCM_UMI_H
  15. #define NAND_BCM_UMI_H
  16. /* ---- Include Files ---------------------------------------------------- */
  17. #include <mach/reg_umi.h>
  18. #include <mach/reg_nand.h>
  19. #include <cfg_global.h>
  20. /* ---- Constants and Types ---------------------------------------------- */
  21. #if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
  22. #define NAND_ECC_BCH (CFG_GLOBAL_CHIP_REV > 0xA0)
  23. #else
  24. #define NAND_ECC_BCH 0
  25. #endif
  26. #define CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES 13
  27. #if NAND_ECC_BCH
  28. #ifdef BOOT0_BUILD
  29. #define NAND_ECC_NUM_BYTES 13
  30. #else
  31. #define NAND_ECC_NUM_BYTES CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES
  32. #endif
  33. #else
  34. #define NAND_ECC_NUM_BYTES 3
  35. #endif
  36. #define NAND_DATA_ACCESS_SIZE 512
  37. /* ---- Variable Externs ------------------------------------------ */
  38. /* ---- Function Prototypes --------------------------------------- */
  39. int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
  40. int numEccBytes);
  41. /* Check in device is ready */
  42. static inline int nand_bcm_umi_dev_ready(void)
  43. {
  44. return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
  45. }
  46. /* Wait until device is ready */
  47. static inline void nand_bcm_umi_wait_till_ready(void)
  48. {
  49. while (nand_bcm_umi_dev_ready() == 0)
  50. ;
  51. }
  52. /* Enable Hamming ECC */
  53. static inline void nand_bcm_umi_hamming_enable_hwecc(void)
  54. {
  55. /* disable and reset ECC, 512 byte page */
  56. REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
  57. REG_UMI_NAND_ECC_CSR_256BYTE);
  58. /* enable ECC */
  59. REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
  60. }
  61. #if NAND_ECC_BCH
  62. /* BCH ECC specifics */
  63. #define ECC_BITS_PER_CORRECTABLE_BIT 13
  64. /* Enable BCH Read ECC */
  65. static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
  66. {
  67. /* disable and reset ECC */
  68. REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
  69. /* Turn on ECC */
  70. REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
  71. }
  72. /* Enable BCH Write ECC */
  73. static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
  74. {
  75. /* disable and reset ECC */
  76. REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
  77. /* Turn on ECC */
  78. REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
  79. }
  80. /* Config number of BCH ECC bytes */
  81. static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
  82. {
  83. uint32_t nValue;
  84. uint32_t tValue;
  85. uint32_t kValue;
  86. uint32_t numBits = numEccBytes * 8;
  87. /* disable and reset ECC */
  88. REG_UMI_BCH_CTRL_STATUS =
  89. REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
  90. REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
  91. /* Every correctible bit requires 13 ECC bits */
  92. tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
  93. /* Total data in number of bits for generating and computing BCH ECC */
  94. nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8;
  95. /* K parameter is used internally. K = N - (T * 13) */
  96. kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
  97. /* Write the settings */
  98. REG_UMI_BCH_N = nValue;
  99. REG_UMI_BCH_T = tValue;
  100. REG_UMI_BCH_K = kValue;
  101. }
  102. /* Pause during ECC read calculation to skip bytes in OOB */
  103. static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
  104. {
  105. REG_UMI_BCH_CTRL_STATUS =
  106. REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
  107. REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
  108. }
  109. /* Resume during ECC read calculation after skipping bytes in OOB */
  110. static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
  111. {
  112. REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
  113. }
  114. /* Poll read ECC calc to check when hardware completes */
  115. static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
  116. {
  117. uint32_t regVal;
  118. do {
  119. /* wait for ECC to be valid */
  120. regVal = REG_UMI_BCH_CTRL_STATUS;
  121. } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
  122. return regVal;
  123. }
  124. /* Poll write ECC calc to check when hardware completes */
  125. static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
  126. {
  127. /* wait for ECC to be valid */
  128. while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
  129. == 0)
  130. ;
  131. }
  132. /* Read the OOB and ECC, for kernel write OOB to a buffer */
  133. #if defined(__KERNEL__) && !defined(STANDALONE)
  134. static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
  135. uint8_t *eccCalc, int numEccBytes, uint8_t *oobp)
  136. #else
  137. static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
  138. uint8_t *eccCalc, int numEccBytes)
  139. #endif
  140. {
  141. int eccPos = 0;
  142. int numToRead = 16; /* There are 16 bytes per sector in the OOB */
  143. /* ECC is already paused when this function is called */
  144. if (pageSize != NAND_DATA_ACCESS_SIZE) {
  145. /* skip BI */
  146. #if defined(__KERNEL__) && !defined(STANDALONE)
  147. *oobp++ = REG_NAND_DATA8;
  148. #else
  149. REG_NAND_DATA8;
  150. #endif
  151. numToRead--;
  152. }
  153. while (numToRead > numEccBytes) {
  154. /* skip free oob region */
  155. #if defined(__KERNEL__) && !defined(STANDALONE)
  156. *oobp++ = REG_NAND_DATA8;
  157. #else
  158. REG_NAND_DATA8;
  159. #endif
  160. numToRead--;
  161. }
  162. if (pageSize == NAND_DATA_ACCESS_SIZE) {
  163. /* read ECC bytes before BI */
  164. nand_bcm_umi_bch_resume_read_ecc_calc();
  165. while (numToRead > 11) {
  166. #if defined(__KERNEL__) && !defined(STANDALONE)
  167. *oobp = REG_NAND_DATA8;
  168. eccCalc[eccPos++] = *oobp;
  169. oobp++;
  170. #else
  171. eccCalc[eccPos++] = REG_NAND_DATA8;
  172. #endif
  173. numToRead--;
  174. }
  175. nand_bcm_umi_bch_pause_read_ecc_calc();
  176. if (numToRead == 11) {
  177. /* read BI */
  178. #if defined(__KERNEL__) && !defined(STANDALONE)
  179. *oobp++ = REG_NAND_DATA8;
  180. #else
  181. REG_NAND_DATA8;
  182. #endif
  183. numToRead--;
  184. }
  185. }
  186. /* read ECC bytes */
  187. nand_bcm_umi_bch_resume_read_ecc_calc();
  188. while (numToRead) {
  189. #if defined(__KERNEL__) && !defined(STANDALONE)
  190. *oobp = REG_NAND_DATA8;
  191. eccCalc[eccPos++] = *oobp;
  192. oobp++;
  193. #else
  194. eccCalc[eccPos++] = REG_NAND_DATA8;
  195. #endif
  196. numToRead--;
  197. }
  198. }
  199. /* Helper function to write ECC */
  200. static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos,
  201. uint8_t *oobp, uint8_t eccVal)
  202. {
  203. if (eccBytePos <= numEccBytes)
  204. *oobp = eccVal;
  205. }
  206. /* Write OOB with ECC */
  207. static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
  208. uint8_t *oobp, int numEccBytes)
  209. {
  210. uint32_t eccVal = 0xffffffff;
  211. /* wait for write ECC to be valid */
  212. nand_bcm_umi_bch_poll_write_ecc_calc();
  213. /*
  214. ** Get the hardware ecc from the 32-bit result registers.
  215. ** Read after 512 byte accesses. Format B3B2B1B0
  216. ** where B3 = ecc3, etc.
  217. */
  218. if (pageSize == NAND_DATA_ACCESS_SIZE) {
  219. /* Now fill in the ECC bytes */
  220. if (numEccBytes >= 13)
  221. eccVal = REG_UMI_BCH_WR_ECC_3;
  222. /* Usually we skip CM in oob[0,1] */
  223. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
  224. (eccVal >> 16) & 0xff);
  225. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1],
  226. (eccVal >> 8) & 0xff);
  227. /* Write ECC in oob[2,3,4] */
  228. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2],
  229. eccVal & 0xff); /* ECC 12 */
  230. if (numEccBytes >= 9)
  231. eccVal = REG_UMI_BCH_WR_ECC_2;
  232. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
  233. (eccVal >> 24) & 0xff); /* ECC11 */
  234. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4],
  235. (eccVal >> 16) & 0xff); /* ECC10 */
  236. /* Always Skip BI in oob[5] */
  237. } else {
  238. /* Always Skip BI in oob[0] */
  239. /* Now fill in the ECC bytes */
  240. if (numEccBytes >= 13)
  241. eccVal = REG_UMI_BCH_WR_ECC_3;
  242. /* Usually skip CM in oob[1,2] */
  243. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
  244. (eccVal >> 16) & 0xff);
  245. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2],
  246. (eccVal >> 8) & 0xff);
  247. /* Write ECC in oob[3-15] */
  248. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3],
  249. eccVal & 0xff); /* ECC12 */
  250. if (numEccBytes >= 9)
  251. eccVal = REG_UMI_BCH_WR_ECC_2;
  252. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
  253. (eccVal >> 24) & 0xff); /* ECC11 */
  254. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5],
  255. (eccVal >> 16) & 0xff); /* ECC10 */
  256. }
  257. /* Fill in the remainder of ECC locations */
  258. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6],
  259. (eccVal >> 8) & 0xff); /* ECC9 */
  260. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7],
  261. eccVal & 0xff); /* ECC8 */
  262. if (numEccBytes >= 5)
  263. eccVal = REG_UMI_BCH_WR_ECC_1;
  264. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
  265. (eccVal >> 24) & 0xff); /* ECC7 */
  266. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9],
  267. (eccVal >> 16) & 0xff); /* ECC6 */
  268. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10],
  269. (eccVal >> 8) & 0xff); /* ECC5 */
  270. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11],
  271. eccVal & 0xff); /* ECC4 */
  272. if (numEccBytes >= 1)
  273. eccVal = REG_UMI_BCH_WR_ECC_0;
  274. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
  275. (eccVal >> 24) & 0xff); /* ECC3 */
  276. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13],
  277. (eccVal >> 16) & 0xff); /* ECC2 */
  278. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14],
  279. (eccVal >> 8) & 0xff); /* ECC1 */
  280. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15],
  281. eccVal & 0xff); /* ECC0 */
  282. }
  283. #endif
  284. #endif /* NAND_BCM_UMI_H */