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