1/* 2 * Broadcom chipcommon NAND flash interface 3 * 4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: nflash.c 501990 2014-09-11 10:54:46Z $ 19 */ 20 21#include <typedefs.h> 22#include <osl.h> 23#include <bcmutils.h> 24#include <siutils.h> 25#include <hndsoc.h> 26#include <sbhndcpu.h> 27#include <sbchipc.h> 28#include <bcmdevs.h> 29#include <nflash.h> 30#include <hndpmu.h> 31 32#ifdef BCMDBG 33#define NFL_MSG(args) printf args 34#else 35#define NFL_MSG(args) 36#endif /* BCMDBG */ 37 38#define NF_RETRIES 1000000 39 40#define NF_SMALL_BADBLOCK_POS 5 41#define NF_LARGE_BADBLOCK_POS 0 42 43/* Private global state */ 44static hndnand_t nflash; 45 46/* Private variables used for BCM4706 only */ 47static uint32 nflash_col_mask; 48static uint32 nflash_row_shift; 49 50 51#undef DEBUG_GEN_1BIT_ERR 52/* 256 bytes for 3 bytes ecc. */ 53#define SOFT_HAMMING_SECTOR_SIZE (256) 54#define SOFT_HAMMING_ECC_BYTES (3) 55 56#define MAX_SOFTECC_OOB_SZ (64) 57static uint8 tmp_page_oob[MAX_SOFTECC_OOB_SZ]; 58 59#define SAME_ECC(recc, cecc) \ 60 ((recc[0] == cecc[0]) && \ 61 (recc[1] == cecc[1]) && \ 62 (recc[2] == cecc[2])) 63 64#if defined(_CFE_) || defined(CFE_FLASH_ERASE_FLASH_ENABLED) 65extern void hamming_compute_256(const uint8 *data, uint8 *code); 66extern int8 hamming_correct_256(uint8 *data, const uint8 *original_code, 67 const uint8 *computed_code); 68 69#define nand_calculate_ecc(mtd, data, ecc)\ 70 hamming_compute_256(data, ecc) 71#define nand_correct_data(mtd, data, read_ecc, calc_ecc)\ 72 hamming_correct_256(data, read_ecc, calc_ecc) 73 74int enable_ecc_correct = 1; 75#else 76extern int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); 77extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); 78int enable_ecc_correct = 0; 79#endif 80 81/* Redefine nand_ecclayout to same as mtd-abi.h */ 82#ifdef CONFIG_BCM47XX 83#define MTD_MAX_OOBFREE_ENTRIES 16 84#else 85#define MTD_MAX_OOBFREE_ENTRIES 8 86#endif 87struct nand_oobfree { 88 uint32 offset; 89 uint32 length; 90}; 91 92struct nand_ecclayout { 93 uint32 eccbytes; 94#ifdef CONFIG_BCM47XX 95 uint32 eccpos[128]; 96#else 97 uint32 eccpos[64]; 98#endif /* CONFIG_BCM47XX */ 99 uint32 oobavail; 100 struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; 101}; 102 103/* Define default oob placement schemes for large and small page devices */ 104static struct nand_ecclayout brcmnand_swecc_nand_oob_8 = { 105 .eccbytes = 3, 106 .eccpos = {0, 1, 2}, 107}; 108 109static struct nand_ecclayout brcmnand_swecc_nand_oob_16 = { 110 .eccbytes = 6, 111 .eccpos = {0, 1, 2, 3, 6, 7}, 112}; 113 114static struct nand_ecclayout brcmnand_swecc_oob_64 = { 115 .eccbytes = 24, 116 .eccpos = { 117 40, 41, 42, 43, 44, 45, 46, 47, 118 48, 49, 50, 51, 52, 53, 54, 55, 119 56, 57, 58, 59, 60, 61, 62, 63}, 120}; 121 122/* For softare ecc reference current layout. */ 123static struct nand_ecclayout *curr_ecclayout = NULL; 124#ifdef DEBUG_GEN_1BIT_ERR 125int enable_inject_err_on_write = 1; 126#endif 127 128/* Prototype */ 129static int nflash_poll(si_t *sih, chipcregs_t *cc); 130static int nflash_readst(si_t *sih, chipcregs_t *cc, uint8 *status); 131static int nflash_readoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf); 132static int nflash_writeoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf); 133 134hndnand_t *nflash_init(si_t *sih); 135static void nflash_enable(hndnand_t *nfl, int enable); 136static int nflash_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf); 137static int nflash_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf); 138static int nflash_erase(hndnand_t *nfl, uint64 offset); 139static int nflash_checkbadb(hndnand_t *nfl, uint64 offset); 140static int nflash_mark_badb(hndnand_t *nfl, uint64 offset); 141 142 143static void 144nflash_enable(hndnand_t *nfl, int enable) 145{ 146 si_t *sih = nfl->sih; 147 148 if (sih->ccrev == 38) { 149 /* BCM5357 NAND boot */ 150 if ((sih->chipst & (1 << 4)) != 0) 151 return; 152 153 if (enable) 154 si_pmu_chipcontrol(sih, 1, CCTRL5357_NFLASH, CCTRL5357_NFLASH); 155 else 156 si_pmu_chipcontrol(sih, 1, CCTRL5357_NFLASH, 0); 157 } 158} 159 160/* Issue a nand flash control command; this is used for BCM4706 */ 161static INLINE int 162nflash_ctrlcmd(osl_t *osh, chipcregs_t *cc, uint ctrlcode) 163{ 164 int cnt = 0; 165 166 W_REG(osh, &cc->nflashctrl, ctrlcode | NFC_START); 167 168 while ((R_REG(osh, &cc->nflashctrl) & NFC_START) != 0) { 169 if (++cnt > NF_RETRIES) { 170 printf("nflash_ctrlcmd: not ready\n"); 171 return -1; 172 } 173 } 174 175 return 0; 176} 177 178/* Issue a nand flash command */ 179static INLINE void 180nflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode) 181{ 182 W_REG(osh, &cc->nand_cmd_start, opcode); 183 /* read after write to flush the command */ 184 R_REG(osh, &cc->nand_cmd_start); 185} 186 187static bool firsttime = TRUE; 188 189static char * 190nflash_check_id(uint8 *id) 191{ 192 char *name = NULL; 193 194 switch (id[0]) { 195 case NFL_VENDOR_AMD: 196 name = "AMD"; 197 break; 198 case NFL_VENDOR_NUMONYX: 199 name = "Numonyx"; 200 break; 201 case NFL_VENDOR_MICRON: 202 name = "Micron"; 203 break; 204 case NFL_VENDOR_TOSHIBA: 205 name = "Toshiba"; 206 break; 207 case NFL_VENDOR_HYNIX: 208 name = "Hynix"; 209 break; 210 case NFL_VENDOR_SAMSUNG: 211 name = "Samsung"; 212 break; 213 case NFL_VENDOR_ESMT: 214 name = "Esmt"; 215 break; 216 case NFL_VENDOR_MXIC: 217 name = "Mxic"; 218 break; 219 case NFL_VENDOR_ZENTEL: 220 name = "Zentel"; 221 break; 222 case NFL_VENDOR_WINBOND: 223 name = "Winbond"; 224 break; 225 default: 226// printf("No NAND flash type found\n"); 227 name = "Unknown"; 228 break; 229 } 230 231 return name; 232} 233 234/* Initialize nand flash access */ 235hndnand_t * 236nflash_init(si_t *sih) 237{ 238 chipcregs_t *cc; 239 uint32 id, id2; 240 char *name = ""; 241 osl_t *osh; 242 int i; 243 uint32 ncf, val; 244 uint32 acc_control; 245 246 ASSERT(sih); 247 248 if ((cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX)) == NULL) 249 return NULL; 250 251 /* Only support chipcommon revision == 38 and BCM4706 for now */ 252 if ((CHIPID(sih->chip) != BCM4706_CHIP_ID) && (sih->ccrev != 38)) 253 return NULL; 254 255 /* Check if nand flash is mounted */ 256 if ((sih->cccaps & CC_CAP_NFLASH) != CC_CAP_NFLASH) 257 return NULL; 258 259 if (!firsttime && nflash.size) 260 return &nflash; 261 262 osh = si_osh(sih); 263 bzero(&nflash, sizeof(nflash)); 264 265 nflash.sih = sih; 266 nflash.core = (void *)cc; 267 nflash.enable = nflash_enable; 268 nflash.read = nflash_read; 269 nflash.write = nflash_write; 270 nflash.erase = nflash_erase; 271 nflash.checkbadb = nflash_checkbadb; 272 nflash.markbadb = nflash_mark_badb; 273 274 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 275 uint32 cpu_freq, clk; 276 uint32 w0, w1, w2, w3, w4; 277 uint32 ctrlcode, val; 278 uint32 totbits = 0, colbits = 0, rowbits; 279 uint32 colbsize, rowbsize; 280 uint32 oobsz_per_sector, plane_sz, plane_num; 281 282 /* Enable nand flash interface of BCM4706 (usign CS1) */ 283 val = R_REG(osh, &cc->eci.flashconf.flashstrconfig) | FLSTRCF4706_NF1; 284 W_REG(osh, &cc->eci.flashconf.flashstrconfig, val); 285 286 /* Configure nand flash bus timing */ 287 if (R_REG(osh, &cc->chipstatus) & CST4706_PKG_OPTION) { 288 cpu_freq = (400000000 / 4); 289 } else { 290 /* Get N divider to determine CPU clock */ 291 W_REG(osh, &cc->pllcontrol_addr, 4); 292 val = (R_REG(osh, &cc->pllcontrol_data) & 0xfff) >> 3; 293 294 /* Fixed reference clock 25MHz and m = 2 */ 295 cpu_freq = (val * 25000000 / 2) / 4; 296 } 297 298 clk = cpu_freq / 1000000; 299 300 w0 = NFLASH_T_WP; 301 w1 = NFLASH_T_RR; 302 w2 = NFLASH_T_CS - NFLASH_T_WP; 303 w3 = NFLASH_T_WH; 304 w4 = NFLASH_T_WB; 305 306 w0 = nflash_ns_to_cycle(w0, clk); 307 w1 = nflash_ns_to_cycle(w1, clk); 308 w2 = nflash_ns_to_cycle(w2, clk); 309 w3 = nflash_ns_to_cycle(w3, clk); 310 w4 = nflash_ns_to_cycle(w4, clk) - 1; 311 312 val = (w4 << NFLASH_WAITCOUNT_W4_SHIFT) | (w3 << NFLASH_WAITCOUNT_W3_SHIFT) 313 | (w2 << NFLASH_WAITCOUNT_W2_SHIFT) 314 | (w1 << NFLASH_WAITCOUNT_W1_SHIFT) | w0; 315 W_REG(osh, &cc->nflashwaitcnt0, val); 316 317 /* Read nand flash ID */ 318 ctrlcode = NFC_CSA | NFC_SPECADDR | NFC_CMD1W | NFC_CMD0 | NFCTRL_ID; 319 320 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 321 return NULL; 322 323 for (i = 0; i < 5; i++) { 324 if (i <= 4) 325 ctrlcode = (NFC_CSA | NFC_1BYTE | NFC_DREAD); 326 else 327 ctrlcode = (NFC_1BYTE | NFC_DREAD); 328 329 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 330 return NULL; 331 else 332 nflash.id[i] = R_REG(osh, &cc->nflashdata) & 0xff; 333 } 334 335 name = nflash_check_id(nflash.id); 336 if (name == NULL) { 337 /* Disable nand flash interface of BCM4706 (usign CS1) */ 338 val = R_REG(osh, &cc->eci.flashconf.flashstrconfig) & ~FLSTRCF4706_NF1; 339 W_REG(osh, &cc->eci.flashconf.flashstrconfig, val); 340 341 return NULL; 342 } 343 nflash.type = nflash.id[0]; 344 345 /* In unit of bytes */ 346 nflash.pagesize = 1024 << (nflash.id[3] & 0x3); 347 nflash.blocksize = (64 * 1024) << ((nflash.id[3] >> 4) & 0x3); 348 349 oobsz_per_sector = (8 << ((nflash.id[3] >> 2) & 0x1)); 350 nflash.oobsize = oobsz_per_sector * (nflash.pagesize / NFL_SECTOR_SIZE); 351 352 /* In unit of MBytes */ 353 plane_sz = (8 << ((nflash.id[4] >> 4) & 0x7)); 354 plane_num = (1 << ((nflash.id[4] >> 2) & 0x3)); 355 nflash.size = plane_sz * plane_num; 356 357 /* Spansion S34ML01G1 does not support id[4]. Override flash size to 128MB */ 358 if ((nflash.id[0] == NFL_VENDOR_AMD) && 359 (nflash.id[1] == 0xf1) && (nflash.id[2] == 0x80) && (nflash.id[3] == 0x1d)) 360 nflash.size = 128; 361 362 for (i = 0; i < 32; i++) { 363 if ((0x1 << i) == nflash.size) { 364 totbits = i + 20; 365 break; 366 } 367 } 368 369 if (totbits == 0) { 370#ifdef BCMDBG 371 NFL_MSG(("nflash_init: failed to find nflash total bits\n")); 372#endif 373 return NULL; 374 } 375 376 for (i = 0; i < 32; i++) { 377 if ((0x1 << i) == nflash.pagesize) { 378 colbits = i + 1; /* including spare oob bytes */ 379 break; 380 } 381 } 382 383 if (colbits == 0) { 384#ifdef BCMDBG 385 NFL_MSG(("nflash_init: failed to find nflash column address bits\n")); 386#endif 387 return NULL; 388 } 389 390 nflash_col_mask = (0x1 << colbits) - 1; 391 nflash_row_shift = colbits; 392 393 colbsize = (colbits + 7) / 8; 394 395 rowbits = totbits - colbits + 1; 396 rowbsize = (rowbits + 7) / 8; 397 398 val = ((rowbsize - 1) << NFCF_ROWSZ_SHIFT) | ((colbsize - 1) << NFCF_COLSZ_SHIFT) 399 | NFCF_DS_8 | NFCF_WE; 400 401 W_REG(osh, &cc->nflashconf, val); 402 403 switch (nflash.oobsize) { 404 case 64: 405 curr_ecclayout = &brcmnand_swecc_oob_64; 406 break; 407 case 16: 408 curr_ecclayout = &brcmnand_swecc_nand_oob_16; 409 break; 410 case 8: 411 curr_ecclayout = &brcmnand_swecc_nand_oob_8; 412 break; 413 default: 414 printf("unsupported oob size %d.\n", nflash.oobsize); 415 return NULL; 416 } 417 } else { 418 nflash_enable(&nflash, 1); 419 nflash_cmd(osh, cc, NCMD_ID_RD); 420 if (nflash_poll(sih, cc) < 0) { 421 nflash_enable(&nflash, 0); 422 return NULL; 423 } 424 nflash_enable(&nflash, 0); 425 id = R_REG(osh, &cc->nand_devid); 426 id2 = R_REG(osh, &cc->nand_devid_x); 427 for (i = 0; i < 5; i++) { 428 if (i < 4) 429 nflash.id[i] = (id >> (8*i)) & 0xff; 430 else 431 nflash.id[i] = id2 & 0xff; 432 } 433 434 name = nflash_check_id(nflash.id); 435 if (name == NULL) 436 return NULL; 437 nflash.type = nflash.id[0]; 438 439 ncf = R_REG(osh, &cc->nand_config); 440 /* Page size (# of bytes) */ 441 val = (ncf & NCF_PAGE_SIZE_MASK) >> NCF_PAGE_SIZE_SHIFT; 442 switch (val) { 443 case 0: 444 nflash.pagesize = 512; 445 break; 446 case 1: 447 nflash.pagesize = (1 << 10) * 2; 448 break; 449 case 2: 450 nflash.pagesize = (1 << 10) * 4; 451 break; 452 case 3: 453 nflash.pagesize = (1 << 10) * 8; 454 break; 455 } 456 /* Block size (# of bytes) */ 457 val = (ncf & NCF_BLOCK_SIZE_MASK) >> NCF_BLOCK_SIZE_SHIFT; 458 switch (val) { 459 case 0: 460 nflash.blocksize = (1 << 10) * 16; 461 break; 462 case 1: 463 nflash.blocksize = (1 << 10) * 128; 464 break; 465 case 2: 466 nflash.blocksize = (1 << 10) * 8; 467 break; 468 case 3: 469 nflash.blocksize = (1 << 10) * 512; 470 break; 471 case 4: 472 nflash.blocksize = (1 << 10) * 256; 473 break; 474 default: 475 printf("Unknown block size\n"); 476 return NULL; 477 } 478 /* NAND flash size in MBytes */ 479 val = (ncf & NCF_DEVICE_SIZE_MASK) >> NCF_DEVICE_SIZE_SHIFT; 480 if (val == 0) { 481 printf("Unknown flash size\n"); 482 return NULL; 483 } 484 nflash.size = (1 << (val - 1)) * 8; 485 486 /* More attribues for ECC functions */ 487 acc_control = R_REG(osh, &cc->nand_acc_control); 488 nflash.ecclevel = (acc_control & NAC_ECC_LEVEL_MASK) >> NAC_ECC_LEVEL_SHIFT; 489 nflash.ecclevel0 = (acc_control & NAC_ECC_LEVEL0_MASK) >> NAC_ECC_LEVEL0_SHIFT; 490 /* make sure that block-0 and block-n use the same ECC level */ 491 if (nflash.ecclevel != nflash.ecclevel0) { 492 acc_control &= ~(NAC_ECC_LEVEL_MASK | NAC_ECC_LEVEL0_MASK); 493 acc_control |= 494 (nflash.ecclevel0 << NAC_ECC_LEVEL0_SHIFT) | 495 (nflash.ecclevel0 << NAC_ECC_LEVEL_SHIFT); 496 W_REG(osh, &cc->nand_acc_control, acc_control); 497 nflash.ecclevel = nflash.ecclevel0; 498 } 499 nflash.phybase = SI_FLASH1; 500 } 501 502 nflash.numblocks = (nflash.size * (1 << 10)) / (nflash.blocksize >> 10); 503 if (firsttime) 504 printf("Found a %s NAND flash with %uB pages or %dKB blocks; total size %dMB\n", 505 name, nflash.pagesize, (nflash.blocksize >> 10), nflash.size); 506 firsttime = FALSE; 507 return nflash.size ? &nflash : NULL; 508} 509 510/* Read len bytes starting at offset into buf. Returns number of bytes read. */ 511static int 512nflash_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf) 513{ 514 si_t *sih = nfl->sih; 515 chipcregs_t *cc = (chipcregs_t *)nfl->core; 516 uint32 mask; 517 osl_t *osh; 518 int i; 519 uint32 *to; 520 uint32 val; 521 uint res; 522 523 ASSERT(sih); 524 525 mask = NFL_SECTOR_SIZE - 1; 526 if ((offset & mask) != 0 || (len & mask) != 0) 527 return 0; 528 if ((((offset + len) >> 20) > nflash.size) || 529 ((((offset + len) >> 20) == nflash.size) && 530 (((offset + len) & ((1 << 20) - 1)) != 0))) 531 return 0; 532 osh = si_osh(sih); 533 to = (uint32 *)buf; 534 res = len; 535 536 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 537 uint32 page_addr, page_offset; 538 uint32 ctrlcode; 539 int prev_page_start_offset = -1; 540 uint page_start_offset; 541 int sector_idx = 0, eccpos; 542 uint8 *pdata; 543 uint8 read_ecc[SOFT_HAMMING_ECC_BYTES]; 544 uint8 calc_ecc[SOFT_HAMMING_ECC_BYTES]; 545 546 /* 4706 only support SW 1-bit hamming ECC */ 547 pdata = (uint8*)buf; 548 while (res > 0) { 549 page_offset = offset & (nflash.pagesize - 1); 550 page_addr = (offset & ~(nflash.pagesize - 1)) * 2; 551 page_addr += page_offset; 552 553 page_start_offset = (offset & ~(uint32)((uint32)nflash.pagesize-1)); 554 if (page_start_offset != prev_page_start_offset) { 555 /* read oob only on new page to read. */ 556 nflash_readoob(sih, cc, page_start_offset, 557 nflash.oobsize, tmp_page_oob); 558 prev_page_start_offset = page_start_offset; 559 } 560 W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask); 561 W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift); 562 563 ctrlcode = NFC_CSA | NFC_CMD1W | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_READ; 564 565 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 566 break; 567 568 if (nflash_poll(sih, cc) < 0) 569 break; 570 571 for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) { 572 if (i < NFL_SECTOR_SIZE - 4) 573 ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DREAD); 574 else 575 ctrlcode = (NFC_4BYTES | NFC_DREAD); 576 577 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 578 return (len - res); 579 580 *to = R_REG(osh, &cc->nflashdata); 581 } 582 583 for (i = 0, sector_idx = (page_offset / SOFT_HAMMING_SECTOR_SIZE); 584 i < (NFL_SECTOR_SIZE / SOFT_HAMMING_SECTOR_SIZE); 585 i++, sector_idx++) { 586 587 /* find correct ecc position on page oob. */ 588 eccpos = sector_idx * SOFT_HAMMING_ECC_BYTES; 589 590 read_ecc[0] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 0]]; 591 read_ecc[1] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 1]]; 592 read_ecc[2] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 2]]; 593 594 nand_calculate_ecc(NULL, pdata, calc_ecc); 595 596 if (enable_ecc_correct && !SAME_ECC(read_ecc, calc_ecc) && 597 nand_correct_data(NULL, pdata, read_ecc, calc_ecc) < 0) { 598 printf("nflash_read: cannot correct data !!\n"); 599 } 600 601 pdata += SOFT_HAMMING_SECTOR_SIZE; 602 } 603 604 res -= NFL_SECTOR_SIZE; 605 offset += NFL_SECTOR_SIZE; 606 } 607 } else { 608 nflash_enable(nfl, 1); 609 while (res > 0) { 610 W_REG(osh, &cc->nand_cmd_addr, offset); 611 nflash_cmd(osh, cc, NCMD_PAGE_RD); 612 if (nflash_poll(sih, cc) < 0) 613 break; 614 if (((val = R_REG(osh, &cc->nand_intfc_status)) & NIST_CACHE_VALID) == 0) 615 break; 616 W_REG(osh, &cc->nand_cache_addr, 0); 617 for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) { 618 *to = R_REG(osh, &cc->nand_cache_data); 619 } 620 621 res -= NFL_SECTOR_SIZE; 622 offset += NFL_SECTOR_SIZE; 623 } 624 nflash_enable(nfl, 0); 625 } 626 627 return (len - res); 628} 629 630/* Poll for command completion. Returns zero when complete. */ 631static int 632nflash_poll(si_t *sih, chipcregs_t *cc) 633{ 634 osl_t *osh; 635 int i; 636 uint32 pollmask; 637 638 ASSERT(sih); 639 osh = si_osh(sih); 640 641 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 642 for (i = 0; i < NF_RETRIES; i++) { 643 if ((R_REG(osh, &cc->nflashctrl) & NFC_RDYBUSY) == NFC_RDYBUSY) { 644 if ((R_REG(osh, &cc->nflashctrl) & NFC_ERROR) == NFC_ERROR) { 645 printf("nflash_poll: error occurred\n"); 646 return -1; 647 } 648 else 649 return 0; 650 } 651 } 652 } else { 653 pollmask = NIST_CTRL_READY|NIST_FLASH_READY; 654 for (i = 0; i < NF_RETRIES; i++) { 655 if ((R_REG(osh, &cc->nand_intfc_status) & pollmask) == pollmask) { 656 return 0; 657 } 658 } 659 } 660 661 printf("nflash_poll: not ready\n"); 662 return -1; 663} 664 665/* Write len bytes starting at offset into buf. Returns number of bytes 666 * written. 667 */ 668static int 669nflash_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf) 670{ 671 si_t *sih = nfl->sih; 672 chipcregs_t *cc = (chipcregs_t *)nfl->core; 673 uint32 mask; 674 osl_t *osh; 675 int i; 676 uint32 *from; 677 uint res; 678 uint32 reg; 679 int ret = 0; 680 uint8 status; 681 682 ASSERT(sih); 683 mask = nflash.pagesize - 1; 684 /* Check offset and length */ 685 if ((offset & mask) != 0 || (len & mask) != 0) 686 return 0; 687 if ((((offset + len) >> 20) > nflash.size) || 688 ((((offset + len) >> 20) == nflash.size) && 689 (((offset + len) & ((1 << 20) - 1)) != 0))) 690 return 0; 691 osh = si_osh(sih); 692 693 from = (uint32 *)buf; 694 res = len; 695 696 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 697 uint32 page_addr; 698 uint32 ctrlcode; 699 uint8 *pdata; 700 int sector_idx, eccpos; 701 uint8 calc_ecc[SOFT_HAMMING_ECC_BYTES]; 702 703 /* 4706 only support SW 1-bit hamming ECC */ 704 pdata = (uint8 *)buf; 705 706 while (res > 0) { 707 nflash_readoob(sih, cc, offset, nflash.oobsize, tmp_page_oob); 708 709 for (i = 0, sector_idx = 0; 710 i < (nflash.pagesize / SOFT_HAMMING_SECTOR_SIZE); 711 i++, sector_idx++) { 712 eccpos = sector_idx * SOFT_HAMMING_ECC_BYTES; 713 nand_calculate_ecc(NULL, pdata, calc_ecc); 714 715 tmp_page_oob[curr_ecclayout->eccpos[eccpos + 0]] = calc_ecc[0]; 716 tmp_page_oob[curr_ecclayout->eccpos[eccpos + 1]] = calc_ecc[1]; 717 tmp_page_oob[curr_ecclayout->eccpos[eccpos + 2]] = calc_ecc[2]; 718 pdata += SOFT_HAMMING_SECTOR_SIZE; 719 } 720 721 /* written a sector */ 722 if (nflash_writeoob(sih, cc, offset, 723 nflash.oobsize, tmp_page_oob) < 0) { 724 printf("\nflash_write write oob fail, offset 0x%08x\n", 725 (uint32)offset); 726 return -1; 727 } 728 729#ifdef DEBUG_GEN_1BIT_ERR 730 for (i = 0; i < enable_inject_err_on_write; i++) { 731 int min_range = (res < nflash.pagesize)? res: nflash.pagesize; 732 min_range /= sizeof(uint32); 733 from[(from[i]%min_range)] ^= 0x04; 734 } 735#endif 736 page_addr = (offset & ~(nflash.pagesize - 1)) * 2; 737 738 W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask); 739 W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift); 740 741 ctrlcode = NFC_CSA | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_PAGEPROG; 742 743 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 744 return -1; 745 746 for (i = 0; i < nflash.pagesize; i += 4, from++) { 747 W_REG(osh, &cc->nflashdata, *from); 748 749 if (i < nflash.pagesize - 4) 750 ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DWRITE); 751 else 752 ctrlcode = (NFC_4BYTES | NFC_DWRITE); 753 754 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 755 return (len - res); 756 } 757 758 if (nflash_ctrlcmd(osh, cc, (NFC_CMD0 | NFCTRL_PROGSTART)) != 0) 759 return -1; 760 761 if (nflash_poll(sih, cc) < 0) 762 return -1; 763 764 if (nflash_readst(sih, cc, &status) != 0) 765 return -1; 766 767 if (status & 1) { 768 printf("nflash_write: failed with status 0x%02x\n", status); 769 return -1; 770 } 771 772 res -= nflash.pagesize; 773 offset += nflash.pagesize; 774 } 775 } else { 776 nflash_enable(nfl, 1); 777 /* disable partial page enable */ 778 reg = R_REG(osh, &cc->nand_acc_control); 779 reg &= ~NAC_PARTIAL_PAGE_EN; 780 W_REG(osh, &cc->nand_acc_control, reg); 781 782 while (res > 0) { 783 W_REG(osh, &cc->nand_cache_addr, 0); 784 for (i = 0; i < nflash.pagesize; i += 4, from++) { 785 if (i % 512 == 0) 786 W_REG(osh, &cc->nand_cmd_addr, i); 787 W_REG(osh, &cc->nand_cache_data, *from); 788 } 789 W_REG(osh, &cc->nand_cmd_addr, offset + nflash.pagesize - 512); 790 nflash_cmd(osh, cc, NCMD_PAGE_PROG); 791 if (nflash_poll(sih, cc) < 0) 792 break; 793 794 /* Check status */ 795 W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD); 796 if (nflash_poll(sih, cc) < 0) 797 break; 798 status = R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS; 799 if (status & 1) { 800 ret = -1; 801 break; 802 } 803 res -= nflash.pagesize; 804 offset += nflash.pagesize; 805 } 806 807 nflash_enable(nfl, 0); 808 if (ret) 809 return ret; 810 } 811 812 return (len - res); 813} 814 815/* Erase a region. Returns number of bytes scheduled for erasure. 816 * Caller should poll for completion. 817 */ 818static int 819nflash_erase(hndnand_t *nfl, uint64 offset) 820{ 821 si_t *sih = nfl->sih; 822 chipcregs_t *cc = (chipcregs_t *)nfl->core; 823 osl_t *osh; 824 int ret = 0; 825 uint8 status = 0; 826 827 ASSERT(sih); 828 829 osh = si_osh(sih); 830 if ((offset >> 20) >= nflash.size) 831 return -1; 832 if ((offset & (nflash.blocksize - 1)) != 0) { 833 return -1; 834 } 835 836 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 837 uint32 ctrlcode; 838 uint32 row_addr; 839 840 row_addr = (offset & ~(nflash.blocksize - 1)) * 2; 841 842 W_REG(osh, &cc->nflashrowaddr, row_addr >> nflash_row_shift); 843 844 ctrlcode = (NFC_CMD1W | NFC_ROW | NFC_CMD0 | NFCTRL_ERASE); 845 846 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 847 return -1; 848 849 if (nflash_poll(sih, cc) < 0) 850 return -1; 851 852 if (nflash_readst(sih, cc, &status) != 0) 853 return -1; 854 855 if (status & 1) { 856 printf("nflash_erase: failed with status 0x%02x\n", status); 857 return -1; 858 } 859 } else { 860 nflash_enable(nfl, 1); 861 W_REG(osh, &cc->nand_cmd_addr, offset); 862 nflash_cmd(osh, cc, NCMD_BLOCK_ERASE); 863 if (nflash_poll(sih, cc) < 0) { 864 ret = -1; 865 goto err; 866 } 867 /* Check status */ 868 W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD); 869 if (nflash_poll(sih, cc) < 0) { 870 ret = -1; 871 goto err; 872 } 873 status = R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS; 874 if (status & 1) 875 ret = -1; 876err: 877 nflash_enable(nfl, 0); 878 } 879 880 return ret; 881} 882 883static int 884nflash_checkbadb(hndnand_t *nfl, uint64 offset) 885{ 886 si_t *sih = nfl->sih; 887 chipcregs_t *cc = (chipcregs_t *)nfl->core; 888 osl_t *osh; 889 int i; 890 uint off; 891 uint32 nand_intfc_status; 892 int ret = 0; 893 894 ASSERT(sih); 895 896 osh = si_osh(sih); 897 if ((offset >> 20) >= nflash.size) 898 return -1; 899 if ((offset & (nflash.blocksize - 1)) != 0) { 900 return -1; 901 } 902 903 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 904 uint8 oob_buf1[8], oob_buf2[8]; 905 uint sec_page_offset; 906 int status1, status2, badblk_pos; 907 908 status1 = nflash_readoob(sih, cc, offset, sizeof(oob_buf1), oob_buf1); 909 910 sec_page_offset = offset + nflash.pagesize; 911 status2 = nflash_readoob(sih, cc, sec_page_offset, sizeof(oob_buf2), oob_buf2); 912 913 if (status1 <= 0 || status2 <= 0) 914 return -1; 915 916 /* Set the bad block position */ 917 if (nflash.pagesize > 512) 918 badblk_pos = NF_LARGE_BADBLOCK_POS; 919 else 920 badblk_pos = NF_SMALL_BADBLOCK_POS; 921 922 if (oob_buf1[badblk_pos] != 0xff || oob_buf2[badblk_pos] != 0xff) 923 return -1; 924 else 925 return 0; 926 } else { 927 nflash_enable(nfl, 1); 928 for (i = 0; i < 2; i++) { 929 off = offset + (nflash.pagesize * i); 930 W_REG(osh, &cc->nand_cmd_addr, off); 931 nflash_cmd(osh, cc, NCMD_SPARE_RD); 932 if (nflash_poll(sih, cc) < 0) { 933 ret = -1; 934 goto err; 935 } 936 nand_intfc_status = R_REG(osh, &cc->nand_intfc_status) & NIST_SPARE_VALID; 937 if (nand_intfc_status != NIST_SPARE_VALID) { 938 ret = -1; 939 goto err; 940 } 941 if ((R_REG(osh, &cc->nand_spare_rd0) & 0xff) != 0xff) { 942 ret = -1; 943 goto err; 944 } 945 } 946err: 947 nflash_enable(nfl, 0); 948 return ret; 949 } 950} 951 952static int 953nflash_mark_badb(hndnand_t *nfl, uint64 offset) 954{ 955 si_t *sih = nfl->sih; 956 chipcregs_t *cc = (chipcregs_t *)nfl->core; 957 osl_t *osh; 958 uint off; 959 int i, ret = 0; 960 uint32 reg; 961 962 ASSERT(sih); 963 964 osh = si_osh(sih); 965 if ((offset >> 20) >= nflash.size) 966 return -1; 967 if ((offset & (nflash.blocksize - 1)) != 0) { 968 return -1; 969 } 970 971 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 972 unsigned char oob_buf[128]; 973 974 /* Force OOB write even nflash_erase return failure */ 975 nflash_erase(nfl, offset); 976 977 memset((void *)oob_buf, 0, nflash.oobsize); 978 979 if (nflash_writeoob(sih, cc, offset, nflash.oobsize, oob_buf) < 0) 980 return -1; 981 982 if (nflash_writeoob(sih, cc, offset + nflash.pagesize, nflash.oobsize, oob_buf) < 0) 983 return -1; 984 } else { 985 nflash_enable(nfl, 1); 986 /* Erase block */ 987 W_REG(osh, &cc->nand_cmd_addr, offset); 988 nflash_cmd(osh, cc, NCMD_BLOCK_ERASE); 989 if (nflash_poll(sih, cc) < 0) { 990 ret = -1; 991 goto err; 992 } 993 994 /* 995 * Enable partial page programming and disable ECC checkbit generation 996 * for PROGRAM_SPARE_AREA 997 */ 998 reg = R_REG(osh, &cc->nand_acc_control); 999 reg |= NAC_PARTIAL_PAGE_EN; 1000 reg &= ~NAC_WR_ECC_EN; 1001 W_REG(osh, &cc->nand_acc_control, reg); 1002 1003 for (i = 0; i < 2; i++) { 1004 off = offset + (nflash.pagesize * i); 1005 W_REG(osh, &cc->nand_cmd_addr, off); 1006 1007 W_REG(osh, &cc->nand_spare_wr0, 0); 1008 W_REG(osh, &cc->nand_spare_wr4, 0); 1009 W_REG(osh, &cc->nand_spare_wr8, 0); 1010 W_REG(osh, &cc->nand_spare_wr12, 0); 1011 1012 nflash_cmd(osh, cc, NCMD_SPARE_PROG); 1013 if (nflash_poll(sih, cc) < 0) { 1014 ret = -1; 1015 goto err; 1016 } 1017 } 1018err: 1019 /* Restore the default value for spare area write registers */ 1020 W_REG(osh, &cc->nand_spare_wr0, 0xffffffff); 1021 W_REG(osh, &cc->nand_spare_wr4, 0xffffffff); 1022 W_REG(osh, &cc->nand_spare_wr8, 0xffffffff); 1023 W_REG(osh, &cc->nand_spare_wr12, 0xffffffff); 1024 1025 /* 1026 * Disable partial page programming and enable ECC checkbit generation 1027 * for PROGRAM_SPARE_AREA 1028 */ 1029 reg = R_REG(osh, &cc->nand_acc_control); 1030 reg &= ~NAC_PARTIAL_PAGE_EN; 1031 reg |= NAC_WR_ECC_EN; 1032 W_REG(osh, &cc->nand_acc_control, reg); 1033 1034 nflash_enable(nfl, 0); 1035 } 1036 return ret; 1037} 1038 1039static int 1040nflash_readst(si_t *sih, chipcregs_t *cc, uint8 *status) 1041{ 1042 osl_t *osh; 1043 int ret = 0; 1044 1045 ASSERT(sih); 1046 1047 osh = si_osh(sih); 1048 1049 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 1050 uint32 ctrlcode; 1051 1052 ctrlcode = (NFC_CSA | NFC_CMD0 | NFCTRL_STATUS); 1053 1054 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1055 return -1; 1056 1057 ctrlcode = (NFC_1BYTE | NFC_DREAD); 1058 1059 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1060 return -1; 1061 1062 *status = (uint8)(R_REG(osh, &cc->nflashdata) & 0xff); 1063 1064 return 0; 1065 } else { 1066 nflash_enable(&nflash, 1); 1067 W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD); 1068 1069 if (nflash_poll(sih, cc) < 0) 1070 ret = -1; 1071 1072 else 1073 *status = (uint8)(R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS); 1074 1075 nflash_enable(&nflash, 0); 1076 return ret; 1077 } 1078} 1079 1080/* To read len bytes of oob data in the page specified in the page address offset */ 1081static int 1082nflash_readoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf) 1083{ 1084 uint32 mask; 1085 osl_t *osh; 1086 int i; 1087 uint32 *to; 1088 uint res; 1089 1090 ASSERT(sih); 1091 1092 mask = nflash.pagesize - 1; 1093 if ((offset & mask) != 0 || (len > nflash.oobsize) || (len & 0x3) != 0) 1094 return -1; 1095 1096 osh = si_osh(sih); 1097 to = (uint32 *)buf; 1098 res = 0; 1099 1100 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 1101 uint32 page_addr, page_offset; 1102 uint32 ctrlcode; 1103 1104 page_addr = (offset & ~(nflash.pagesize - 1)) * 2; 1105 page_offset = nflash.pagesize; 1106 page_addr += page_offset; 1107 1108 W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask); 1109 W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift); 1110 1111 ctrlcode = (NFC_CSA | NFC_CMD1W | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_READ); 1112 1113 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1114 return -1; 1115 1116 if (nflash_poll(sih, cc) < 0) 1117 return -1; 1118 1119 for (i = 0; i < len; i += 4, to++) { 1120 if (i < len - 4) 1121 ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DREAD); 1122 else 1123 ctrlcode = (NFC_4BYTES | NFC_DREAD); 1124 1125 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1126 return -1; 1127 1128 *to = R_REG(osh, &cc->nflashdata); 1129 1130 res += 4; 1131 } 1132 } else 1133 return -1; 1134 1135 return res; 1136} 1137 1138/* To write len bytes of oob data in the page specified in the page address offset */ 1139static int 1140nflash_writeoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf) 1141{ 1142 uint32 mask; 1143 osl_t *osh; 1144 int i; 1145 uint32 *from; 1146 uint res; 1147 1148 ASSERT(sih); 1149 1150 mask = nflash.pagesize - 1; 1151 if ((offset & mask) != 0 || (len > nflash.oobsize) || (len & 0x3) != 0) 1152 return -1; 1153 1154 osh = si_osh(sih); 1155 from = (uint32 *)buf; 1156 res = 0; 1157 1158 if (CHIPID(sih->chip) == BCM4706_CHIP_ID) { 1159 uint32 page_addr, page_offset; 1160 uint32 ctrlcode; 1161 uint8 status; 1162 1163 page_addr = (offset & ~(nflash.pagesize - 1)) * 2; 1164 page_offset = nflash.pagesize; 1165 page_addr += page_offset; 1166 1167 W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask); 1168 W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift); 1169 1170 ctrlcode = (NFC_CSA | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_PAGEPROG); 1171 1172 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1173 return -1; 1174 1175 for (i = 0; i < len; i += 4, from++) { 1176 W_REG(osh, &cc->nflashdata, *from); 1177 1178 if (i < len - 4) 1179 ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DWRITE); 1180 else 1181 ctrlcode = (NFC_4BYTES | NFC_DWRITE); 1182 1183 if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0) 1184 return -1; 1185 1186 res += 4; 1187 } 1188 1189 if (nflash_ctrlcmd(osh, cc, (NFC_CMD0 | NFCTRL_PROGSTART)) != 0) 1190 return -1; 1191 1192 if (nflash_poll(sih, cc) < 0) 1193 return -1; 1194 1195 if (nflash_readst(sih, cc, &status) != 0) 1196 return -1; 1197 1198 if (status & 1) { 1199 printf("nflash_writeoob: failed with status 0x%02x\n", status); 1200 return -1; 1201 } 1202 1203 } else 1204 return -1; 1205 1206 return res; 1207} 1208