nand_bcm_umi.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. while (numToRead > numEccBytes) {
  146. /* skip free oob region */
  147. #if defined(__KERNEL__) && !defined(STANDALONE)
  148. *oobp++ = REG_NAND_DATA8;
  149. #else
  150. REG_NAND_DATA8;
  151. #endif
  152. numToRead--;
  153. }
  154. /* read ECC bytes before BI */
  155. nand_bcm_umi_bch_resume_read_ecc_calc();
  156. while (numToRead > 11) {
  157. #if defined(__KERNEL__) && !defined(STANDALONE)
  158. *oobp = REG_NAND_DATA8;
  159. eccCalc[eccPos++] = *oobp;
  160. oobp++;
  161. #else
  162. eccCalc[eccPos++] = REG_NAND_DATA8;
  163. #endif
  164. }
  165. nand_bcm_umi_bch_pause_read_ecc_calc();
  166. if (numToRead == 11) {
  167. /* read BI */
  168. #if defined(__KERNEL__) && !defined(STANDALONE)
  169. *oobp++ = REG_NAND_DATA8;
  170. #else
  171. REG_NAND_DATA8;
  172. #endif
  173. numToRead--;
  174. }
  175. /* read ECC bytes */
  176. nand_bcm_umi_bch_resume_read_ecc_calc();
  177. while (numToRead) {
  178. #if defined(__KERNEL__) && !defined(STANDALONE)
  179. *oobp = REG_NAND_DATA8;
  180. eccCalc[eccPos++] = *oobp;
  181. oobp++;
  182. #else
  183. eccCalc[eccPos++] = REG_NAND_DATA8;
  184. #endif
  185. numToRead--;
  186. }
  187. } else {
  188. /* skip BI */
  189. #if defined(__KERNEL__) && !defined(STANDALONE)
  190. *oobp++ = REG_NAND_DATA8;
  191. #else
  192. REG_NAND_DATA8;
  193. #endif
  194. numToRead--;
  195. while (numToRead > numEccBytes) {
  196. /* skip free oob region */
  197. #if defined(__KERNEL__) && !defined(STANDALONE)
  198. *oobp++ = REG_NAND_DATA8;
  199. #else
  200. REG_NAND_DATA8;
  201. #endif
  202. numToRead--;
  203. }
  204. /* read ECC bytes */
  205. nand_bcm_umi_bch_resume_read_ecc_calc();
  206. while (numToRead) {
  207. #if defined(__KERNEL__) && !defined(STANDALONE)
  208. *oobp = REG_NAND_DATA8;
  209. eccCalc[eccPos++] = *oobp;
  210. oobp++;
  211. #else
  212. eccCalc[eccPos++] = REG_NAND_DATA8;
  213. #endif
  214. numToRead--;
  215. }
  216. }
  217. }
  218. /* Helper function to write ECC */
  219. static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos,
  220. uint8_t *oobp, uint8_t eccVal)
  221. {
  222. if (eccBytePos <= numEccBytes)
  223. *oobp = eccVal;
  224. }
  225. /* Write OOB with ECC */
  226. static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
  227. uint8_t *oobp, int numEccBytes)
  228. {
  229. uint32_t eccVal = 0xffffffff;
  230. /* wait for write ECC to be valid */
  231. nand_bcm_umi_bch_poll_write_ecc_calc();
  232. /*
  233. ** Get the hardware ecc from the 32-bit result registers.
  234. ** Read after 512 byte accesses. Format B3B2B1B0
  235. ** where B3 = ecc3, etc.
  236. */
  237. if (pageSize == NAND_DATA_ACCESS_SIZE) {
  238. /* Now fill in the ECC bytes */
  239. if (numEccBytes >= 13)
  240. eccVal = REG_UMI_BCH_WR_ECC_3;
  241. /* Usually we skip CM in oob[0,1] */
  242. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
  243. (eccVal >> 16) & 0xff);
  244. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1],
  245. (eccVal >> 8) & 0xff);
  246. /* Write ECC in oob[2,3,4] */
  247. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2],
  248. eccVal & 0xff); /* ECC 12 */
  249. if (numEccBytes >= 9)
  250. eccVal = REG_UMI_BCH_WR_ECC_2;
  251. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
  252. (eccVal >> 24) & 0xff); /* ECC11 */
  253. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4],
  254. (eccVal >> 16) & 0xff); /* ECC10 */
  255. /* Always Skip BI in oob[5] */
  256. } else {
  257. /* Always Skip BI in oob[0] */
  258. /* Now fill in the ECC bytes */
  259. if (numEccBytes >= 13)
  260. eccVal = REG_UMI_BCH_WR_ECC_3;
  261. /* Usually skip CM in oob[1,2] */
  262. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
  263. (eccVal >> 16) & 0xff);
  264. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2],
  265. (eccVal >> 8) & 0xff);
  266. /* Write ECC in oob[3-15] */
  267. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3],
  268. eccVal & 0xff); /* ECC12 */
  269. if (numEccBytes >= 9)
  270. eccVal = REG_UMI_BCH_WR_ECC_2;
  271. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
  272. (eccVal >> 24) & 0xff); /* ECC11 */
  273. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5],
  274. (eccVal >> 16) & 0xff); /* ECC10 */
  275. }
  276. /* Fill in the remainder of ECC locations */
  277. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6],
  278. (eccVal >> 8) & 0xff); /* ECC9 */
  279. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7],
  280. eccVal & 0xff); /* ECC8 */
  281. if (numEccBytes >= 5)
  282. eccVal = REG_UMI_BCH_WR_ECC_1;
  283. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
  284. (eccVal >> 24) & 0xff); /* ECC7 */
  285. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9],
  286. (eccVal >> 16) & 0xff); /* ECC6 */
  287. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10],
  288. (eccVal >> 8) & 0xff); /* ECC5 */
  289. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11],
  290. eccVal & 0xff); /* ECC4 */
  291. if (numEccBytes >= 1)
  292. eccVal = REG_UMI_BCH_WR_ECC_0;
  293. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
  294. (eccVal >> 24) & 0xff); /* ECC3 */
  295. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13],
  296. (eccVal >> 16) & 0xff); /* ECC2 */
  297. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14],
  298. (eccVal >> 8) & 0xff); /* ECC1 */
  299. NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15],
  300. eccVal & 0xff); /* ECC0 */
  301. }
  302. #endif
  303. #endif /* NAND_BCM_UMI_H */