X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fcmd_nand.c;h=b0c01d1205aa50e45ea0e78964a5a3a0f3fd9b1f;hb=5d4ee51061e70118fb598e3aca082dd11a154e87;hp=c2e67abed54fa092117f2502526716e2a5def8ec;hpb=a3d991bd0da8b9fb9dbf2c7481091c3d082b9b13;p=u-boot diff --git a/common/cmd_nand.c b/common/cmd_nand.c index c2e67abed5..b0c01d1205 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -3,6 +3,9 @@ * borrowed heavily from: * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse + * + * Added 16-bit nand support + * (C) 2004 Texas Instruments */ #include @@ -70,10 +73,10 @@ struct nand_oob_config { * Function Prototypes */ static void nand_print(struct nand_chip *nand); -static int nand_rw (struct nand_chip* nand, int cmd, +int nand_rw (struct nand_chip* nand, int cmd, size_t start, size_t len, size_t * retlen, u_char * buf); -static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean); +int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean); static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, size_t * retlen, u_char *buf, u_char *ecc_code); static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, @@ -197,12 +200,12 @@ int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) /* read out-of-band data */ if (cmd & NANDRW_READ) { ret = nand_read_oob(nand_dev_desc + curr_device, - off, size, &total, + off, size, (size_t *)&total, (u_char*)addr); } else { ret = nand_write_oob(nand_dev_desc + curr_device, - off, size, &total, + off, size, (size_t *)&total, (u_char*)addr); } return ret; @@ -219,6 +222,15 @@ int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) else if (cmdtail && !strcmp(cmdtail, ".e")) cmd |= NANDRW_JFFS2; /* skip bad blocks */ #endif +#ifdef CFG_NAND_SKIP_BAD_DOT_I + /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */ + /* ".i" for image -> read skips bad block (no 0xff) */ + else if (cmdtail && !strcmp(cmdtail, ".i")) { + cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ + if (cmd & NANDRW_READ) + cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ + } +#endif /* CFG_NAND_SKIP_BAD_DOT_I */ else if (cmdtail) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; @@ -229,10 +241,10 @@ int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) curr_device, off, size); ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size, - &total, (u_char*)addr); + (size_t *)&total, (u_char*)addr); printf (" %d bytes %s: %s\n", total, - (cmd & NANDRW_READ) ? "read" : "write", + (cmd & NANDRW_READ) ? "read" : "written", ret ? "ERROR" : "OK"); return ret; @@ -387,10 +399,11 @@ U_BOOT_CMD( * not marked bad, or no bad mark position is specified * returns 1 if marked bad or otherwise invalid */ -int check_block(struct nand_chip* nand, unsigned long pos) +int check_block (struct nand_chip *nand, unsigned long pos) { - int retlen; + size_t retlen; uint8_t oob_data; + uint16_t oob_data16[6]; int page0 = pos & (-nand->erasesize); int page1 = page0 + nand->oobblock; int badpos = oob_config.badblock_pos; @@ -401,12 +414,21 @@ int check_block(struct nand_chip* nand, unsigned long pos) if (badpos < 0) return 0; /* no way to check, assume OK */ - /* Note - bad block marker can be on first or second page */ - if (nand_read_oob(nand, page0 + badpos, 1, &retlen, &oob_data) || - oob_data != 0xff || - nand_read_oob(nand, page1 + badpos, 1, &retlen, &oob_data) || - oob_data != 0xff) - return 1; + if (nand->bus16) { + if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16) + || (oob_data16[2] & 0xff00) != 0xff00) + return 1; + if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16) + || (oob_data16[2] & 0xff00) != 0xff00) + return 1; + } else { + /* Note - bad block marker can be on first or second page */ + if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data) + || oob_data != 0xff + || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data) + || oob_data != 0xff) + return 1; + } return 0; } @@ -429,7 +451,7 @@ static void nand_print_bad(struct nand_chip* nand) * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks */ -static int nand_rw (struct nand_chip* nand, int cmd, +int nand_rw (struct nand_chip* nand, int cmd, size_t start, size_t len, size_t * retlen, u_char * buf) { @@ -457,17 +479,14 @@ static int nand_rw (struct nand_chip* nand, int cmd, --len; } continue; - } - else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) { + } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) { start += erasesize; continue; - } - else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) { + } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) { /* skip bad block */ start += erasesize; continue; - } - else { + } else { ret = 1; break; } @@ -479,14 +498,15 @@ static int nand_rw (struct nand_chip* nand, int cmd, if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200)) printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n"); - if (cmd & NANDRW_READ) + if (cmd & NANDRW_READ) { ret = nand_read_ecc(nand, start, min(len, eblk + erasesize - start), - &n, (u_char*)buf, eccbuf); - else + (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); + } else { ret = nand_write_ecc(nand, start, min(len, eblk + erasesize - start), - &n, (u_char*)buf, eccbuf); + (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); + } if (ret) break; @@ -556,7 +576,7 @@ static inline int NanD_Command(struct nand_chip *nand, unsigned char command) if(command == NAND_CMD_RESET){ u_char ret_val; NanD_Command(nand, NAND_CMD_STATUS); - do{ + do { ret_val = READ_NAND(nandptr);/* wait till ready */ } while((ret_val & 0x40) != 0x40); } @@ -593,9 +613,11 @@ static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs) ofs = ofs >> nand->page_shift; - if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) - for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) + if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) { + for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) { WRITE_NAND_ADDRESS(ofs, nandptr); + } + } /* Lower the ALE line */ NAND_CTL_CLRALE(nandptr); @@ -649,11 +671,12 @@ static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip) id = READ_NAND(nand->IO_ADDR); NAND_DISABLE_CE(nand); /* set pin high */ - /* No response - return failure */ - if (mfr == 0xff || mfr == 0) { + #ifdef NAND_DEBUG - printf("NanD_Command (ReadID) got %d %d\n", mfr, id); + printf("NanD_Command (ReadID) got %x %x\n", mfr, id); #endif + if (mfr == 0xff || mfr == 0) { + /* No response - return failure */ return 0; } @@ -662,11 +685,12 @@ static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip) * contain _one_ type of flash part, although that's not a * hardware restriction. */ if (nand->mfr) { - if (nand->mfr == mfr && nand->id == id) + if (nand->mfr == mfr && nand->id == id) { return 1; /* This is another the same the first */ - else + } else { printf("Flash chip at floor %d, chip %d is different:\n", floor, chip); + } } /* Print and store the manufacturer and ID codes. */ @@ -694,13 +718,11 @@ static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip) nand->oobsize = 16; nand->page_shift = 9; } - nand->pageadrlen = - nand_flash_ids[i].pageadrlen; - nand->erasesize = - nand_flash_ids[i].erasesize; - nand->chips_name = - nand_flash_ids[i].name; - return 1; + nand->pageadrlen = nand_flash_ids[i].pageadrlen; + nand->erasesize = nand_flash_ids[i].erasesize; + nand->chips_name = nand_flash_ids[i].name; + nand->bus16 = nand_flash_ids[i].bus16; + return 1; } return 0; } @@ -783,33 +805,74 @@ static void NanD_ScanChips(struct nand_chip *nand) } /* we need to be fast here, 1 us per read translates to 1 second per meg */ -static void NanD_ReadBuf(struct nand_chip *nand, u_char *data_buf, int cntr) +static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr) { unsigned long nandptr = nand->IO_ADDR; - while (cntr >= 16) { - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - *data_buf++ = READ_NAND(nandptr); - cntr -= 16; - } - - while (cntr > 0) { - *data_buf++ = READ_NAND(nandptr); - cntr--; + NanD_Command (nand, NAND_CMD_READ0); + + if (nand->bus16) { + u16 val; + + while (cntr >= 16) { + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + cntr -= 16; + } + + while (cntr > 0) { + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + cntr -= 2; + } + } else { + while (cntr >= 16) { + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + cntr -= 16; + } + + while (cntr > 0) { + *data_buf++ = READ_NAND (nandptr); + cntr--; + } } } @@ -830,7 +893,8 @@ static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, /* Do not allow reads past end of device */ if ((start + len) > nand->totlen) { - printf ("%s: Attempt read beyond end of device %x %x %x\n", __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen); + printf ("%s: Attempt read beyond end of device %x %x %x\n", + __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen); *retlen = 0; return -1; } @@ -851,25 +915,33 @@ static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, /* Loop until all data read */ while (*retlen < len) { - #ifdef CONFIG_MTD_NAND_ECC - /* Do we have this page in cache ? */ if (nand->cache_page == page) goto readdata; /* Send the read command */ NanD_Command(nand, NAND_CMD_READ0); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + /* Read in a page + oob data */ NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize); /* copy data into cache, for read out of cache and if ecc fails */ - if (nand->data_cache) - memcpy (nand->data_cache, nand->data_buf, nand->oobblock + nand->oobsize); + if (nand->data_cache) { + memcpy (nand->data_cache, nand->data_buf, + nand->oobblock + nand->oobsize); + } /* Pick the ECC bytes out of the oob data */ - for (j = 0; j < 6; j++) + for (j = 0; j < 6; j++) { ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])]; + } /* Calculate the ECC and verify it */ /* If block was not written with ECC, skip ECC */ @@ -926,7 +998,14 @@ readdata: #else /* Send the read command */ NanD_Command(nand, NAND_CMD_READ0); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + /* Read the data directly into the return buffer */ if ((*retlen + (nand->oobblock - col)) >= len) { NanD_ReadBuf(nand, buf + *retlen, len - *retlen); @@ -964,6 +1043,7 @@ static int nand_write_page (struct nand_chip *nand, int i; unsigned long nandptr = nand->IO_ADDR; + #ifdef CONFIG_MTD_NAND_ECC #ifdef CONFIG_MTD_NAND_VERIFY_WRITE int ecc_bytes = (nand->oobblock == 512) ? 6 : 3; @@ -980,28 +1060,53 @@ static int nand_write_page (struct nand_chip *nand, /* Read back previous written data, if col > 0 */ if (col) { - NanD_Command(nand, NAND_CMD_READ0); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); - for (i = 0; i < col; i++) - nand->data_buf[i] = READ_NAND (nandptr); + NanD_Command (nand, NAND_CMD_READ0); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + if (nand->bus16) { + u16 val; + + for (i = 0; i < col; i += 2) { + val = READ_NAND (nandptr); + nand->data_buf[i] = val & 0xff; + nand->data_buf[i + 1] = val >> 8; + } + } else { + for (i = 0; i < col; i++) + nand->data_buf[i] = READ_NAND (nandptr); + } } /* Calculate and write the ECC if we have enough data */ if ((col < nand->eccsize) && (last >= nand->eccsize)) { nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0])); - for (i = 0; i < 3; i++) - nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i]; - if (oob_config.eccvalid_pos != -1) - nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] = 0xf0; + for (i = 0; i < 3; i++) { + nand->data_buf[(nand->oobblock + + oob_config.ecc_pos[i])] = ecc_code[i]; + } + if (oob_config.eccvalid_pos != -1) { + nand->data_buf[nand->oobblock + + oob_config.eccvalid_pos] = 0xf0; + } } /* Calculate and write the second ECC if we have enough data */ if ((nand->oobblock == 512) && (last == nand->oobblock)) { nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3])); - for (i = 3; i < 6; i++) - nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i]; - if (oob_config.eccvalid_pos != -1) - nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &= 0x0f; + for (i = 3; i < 6; i++) { + nand->data_buf[(nand->oobblock + + oob_config.ecc_pos[i])] = ecc_code[i]; + } + if (oob_config.eccvalid_pos != -1) { + nand->data_buf[nand->oobblock + + oob_config.eccvalid_pos] &= 0x0f; + } } #endif /* Prepad for partial page programming !!! */ @@ -1013,31 +1118,46 @@ static int nand_write_page (struct nand_chip *nand, nand->data_buf[i] = 0xff; /* Send command to begin auto page programming */ - NanD_Command(nand, NAND_CMD_READ0); - NanD_Command(nand, NAND_CMD_SEQIN); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); + NanD_Command (nand, NAND_CMD_READ0); + NanD_Command (nand, NAND_CMD_SEQIN); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } /* Write out complete page of data */ - for (i = 0; i < (nand->oobblock + nand->oobsize); i++) - WRITE_NAND(nand->data_buf[i], nand->IO_ADDR); + if (nand->bus16) { + for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) { + WRITE_NAND (nand->data_buf[i] + + (nand->data_buf[i + 1] << 8), + nand->IO_ADDR); + } + } else { + for (i = 0; i < (nand->oobblock + nand->oobsize); i++) + WRITE_NAND (nand->data_buf[i], nand->IO_ADDR); + } /* Send command to actually program the data */ - NanD_Command(nand, NAND_CMD_PAGEPROG); - NanD_Command(nand, NAND_CMD_STATUS); + NanD_Command (nand, NAND_CMD_PAGEPROG); + NanD_Command (nand, NAND_CMD_STATUS); #ifdef NAND_NO_RB - { u_char ret_val; + { + u_char ret_val; - do{ - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while((ret_val & 0x40) != 0x40); + do { + ret_val = READ_NAND (nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); } #endif /* See if device thinks it succeeded */ - if (READ_NAND(nand->IO_ADDR) & 0x01) { - printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page); + if (READ_NAND (nand->IO_ADDR) & 0x01) { + printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, + page); return -1; } - #ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* * The NAND device assumes that it is always writing to @@ -1054,16 +1174,34 @@ static int nand_write_page (struct nand_chip *nand, /* Send command to read back the page */ if (col < nand->eccsize) - NanD_Command(nand, NAND_CMD_READ0); + NanD_Command (nand, NAND_CMD_READ0); else - NanD_Command(nand, NAND_CMD_READ1); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); + NanD_Command (nand, NAND_CMD_READ1); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } /* Loop through and verify the data */ - for (i = col; i < last; i++) { - if (nand->data_buf[i] != readb (nand->IO_ADDR)) { - printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page); - return -1; + if (nand->bus16) { + for (i = col; i < last; i = +2) { + if ((nand->data_buf[i] + + (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) { + printf ("%s: Failed write verify, page 0x%08x ", + __FUNCTION__, page); + return -1; + } + } + } else { + for (i = col; i < last; i++) { + if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) { + printf ("%s: Failed write verify, page 0x%08x ", + __FUNCTION__, page); + return -1; + } } } @@ -1072,19 +1210,38 @@ static int nand_write_page (struct nand_chip *nand, * We also want to check that the ECC bytes wrote * correctly for the same reasons stated above. */ - NanD_Command(nand, NAND_CMD_READOOB); - NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); - for (i = 0; i < nand->oobsize; i++) - nand->data_buf[i] = readb (nand->IO_ADDR); + NanD_Command (nand, NAND_CMD_READOOB); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + if (nand->bus16) { + for (i = 0; i < nand->oobsize; i += 2) { + u16 val; + + val = READ_NAND (nand->IO_ADDR); + nand->data_buf[i] = val & 0xff; + nand->data_buf[i + 1] = val >> 8; + } + } else { + for (i = 0; i < nand->oobsize; i++) { + nand->data_buf[i] = READ_NAND (nand->IO_ADDR); + } + } for (i = 0; i < ecc_bytes; i++) { if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) { printf ("%s: Failed ECC write " - "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); + "verify, page 0x%08x, " + "%6i bytes were succesful\n", + __FUNCTION__, page, i); return -1; } } -#endif -#endif +#endif /* CONFIG_MTD_NAND_ECC */ +#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */ return 0; } @@ -1112,6 +1269,10 @@ static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, #ifdef CONFIG_OMAP1510 archflashwp(0,0); #endif +#ifdef CFG_NAND_WP + NAND_WP_OFF(); +#endif + NAND_ENABLE_CE(nand); /* set pin low */ /* Check the WP bit */ @@ -1129,12 +1290,15 @@ static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, nand->cache_page = -1; /* Write data into buffer */ - if ((col + len) >= nand->oobblock) - for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) + if ((col + len) >= nand->oobblock) { + for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) { nand->data_buf[i] = buf[(*retlen + cnt)]; - else - for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) + } + } else { + for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) { nand->data_buf[i] = buf[(*retlen + cnt)]; + } + } /* We use the same function for write and writev !) */ ret = nand_write_page (nand, page, col, i, ecc_code); if (ret) @@ -1159,6 +1323,10 @@ out: #ifdef CONFIG_OMAP1510 archflashwp(0,1); #endif +#ifdef CFG_NAND_WP + NAND_WP_ON(); +#endif + return ret; } @@ -1185,7 +1353,13 @@ static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, NAND_ENABLE_CE(nand); /* set pin low */ NanD_Command(nand, NAND_CMD_READOOB); - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ @@ -1235,7 +1409,13 @@ static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, /* issue the Read2 command to set the pointer to the Spare Data Area. */ NanD_Command(nand, NAND_CMD_READOOB); - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with nand_read_ecc. */ @@ -1248,7 +1428,13 @@ static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, /* issue the Serial Data In command to initial the Page Program process */ NanD_Command(nand, NAND_CMD_SEQIN); - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } /* treat crossing 8-byte OOB data for 2M x 8bit devices */ /* Note: datasheet says it should automaticaly wrap to the */ @@ -1262,9 +1448,9 @@ static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, NanD_Command(nand, NAND_CMD_STATUS); #ifdef NAND_NO_RB { u_char ret_val; - do{ - ret_val = READ_NAND(nandptr); /* wait till ready */ - }while((ret_val & 0x40) != 0x40); + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); } #endif if (READ_NAND(nandptr) & 1) { @@ -1278,16 +1464,22 @@ static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); } - for (i = len256; i < len; i++) - WRITE_NAND(buf[i], nandptr); + if (nand->bus16) { + for (i = len256; i < len; i += 2) { + WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr); + } + } else { + for (i = len256; i < len; i++) + WRITE_NAND(buf[i], nandptr); + } NanD_Command(nand, NAND_CMD_PAGEPROG); NanD_Command(nand, NAND_CMD_STATUS); #ifdef NAND_NO_RB - { u_char ret_val; - do{ - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while((ret_val & 0x40) != 0x40); + { u_char ret_val; + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); } #endif if (READ_NAND(nandptr) & 1) { @@ -1304,7 +1496,7 @@ static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, } -static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) +int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) { /* This is defined as a structure so it will work on any system * using native endian jffs2 (the default). @@ -1329,6 +1521,9 @@ static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) /* Select the NAND device */ #ifdef CONFIG_OMAP1510 archflashwp(0,0); +#endif +#ifdef CFG_NAND_WP + NAND_WP_OFF(); #endif NAND_ENABLE_CE(nand); /* set pin low */ @@ -1367,10 +1562,10 @@ static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) NanD_Command(nand, NAND_CMD_STATUS); #ifdef NAND_NO_RB - { u_char ret_val; - do{ - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while((ret_val & 0x40) != 0x40); + { u_char ret_val; + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); } #endif if (READ_NAND(nandptr) & 1) { @@ -1391,13 +1586,12 @@ static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) if (nand->page256) { p = NAND_JFFS2_OOB8_FSDAPOS; l = NAND_JFFS2_OOB8_FSDALEN; - } - else { + } else { p = NAND_JFFS2_OOB16_FSDAPOS; l = NAND_JFFS2_OOB16_FSDALEN; } - ret = nand_write_oob(nand, ofs + p, l, &n, + ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n, (u_char *)&clean_marker); /* quit here if write failed */ if (ret) @@ -1414,6 +1608,10 @@ out: #ifdef CONFIG_OMAP1510 archflashwp(0,1); #endif +#ifdef CFG_NAND_WP + NAND_WP_ON(); +#endif + return ret; } @@ -1486,22 +1684,38 @@ unsigned long nand_probe(unsigned long physadr) * Pre-calculated 256-way 1 byte column parity */ static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; @@ -1594,8 +1808,7 @@ static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; - } - else { + } else { a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; @@ -1669,4 +1882,17 @@ static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) } #endif + +#ifdef CONFIG_JFFS2_NAND + +int read_jffs2_nand(size_t start, size_t len, + size_t * retlen, u_char * buf, int nanddev) +{ + return nand_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2, + start, len, retlen, buf); +} + +#endif /* CONFIG_JFFS2_NAND */ + + #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */