📄 nand_legacy.c
字号:
} 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)) { /* if ecc_code is null, write without ecc, www.arm9.net */ if (ecc_code && (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; } } /* Calculate and write the second ECC if we have enough data */ //if ((nand->oobblock == 512) && (last == nand->oobblock)) { /* if ecc_code is null, write without ecc, www.arm9.net */ if (ecc_code && (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; } }#endif /* Prepad for partial page programming !!! */ for (i = 0; i < col; i++) nand->data_buf[i] = 0xff; /* Postpad for partial page programming !!! oob is already padded */ for (i = last; i < nand->oobblock; i++) nand->data_buf[i] = 0xff; /* Send command to begin auto page programming */ 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); } /* if ecc_code is null, write without ecc, www.arm9.net */ if (ecc_code) writecnt = nand->oobblock + nand->oobsize; else writecnt = nand->oobblock; /* Write out complete page of data */ if (nand->bus16) { for (i = 0; i < writecnt; i += 2) { WRITE_NAND (nand->data_buf[i] + (nand->data_buf[i + 1] << 8), nand->IO_ADDR); } } else { for (i = 0; i < writecnt; 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);#ifdef NAND_NO_RB { u_char ret_val; 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); return -1; }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* * The NAND device assumes that it is always writing to * a cleanly erased page. Hence, it performs its internal * write verification only on bits that transitioned from * 1 to 0. The device does NOT verify the whole page on a * byte by byte basis. It is possible that the page was * not completely erased or the page is becoming unusable * due to wear. The read with ECC would catch the error * later when the ECC page check fails, but we would rather * catch it early in the page write stage. Better to write * no data than invalid data. */ /* Send command to read back the page */ if (col < nand->eccsize) NanD_Command (nand, NAND_CMD_READ0); else 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 */ 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; } } }#ifdef CONFIG_MTD_NAND_ECC /* * We also want to check that the ECC bytes wrote * correctly for the same reasons stated above. */ /* if ecc_code is null, write without ecc, www.arm9.net */ if (ecc_code) { 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); return -1; } } }#endif /* CONFIG_MTD_NAND_ECC */#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */ return 0;}static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, size_t * retlen, const u_char * buf, u_char * ecc_code){ int i, page, col, cnt, ret = 0; /* Do not allow write past end of device */ if ((to + len) > nand->totlen) { printf ("%s: Attempt to write past end of page\n", __FUNCTION__); return -1; } /* Shift to get page */ page = ((int) to) >> nand->page_shift; /* Get the starting column */ col = to & (nand->oobblock - 1); /* Initialize return length value */ *retlen = 0; /* 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 */ /* Check the WP bit */ NanD_Command(nand, NAND_CMD_STATUS); if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { printf ("%s: Device is write protected!!!\n", __FUNCTION__); ret = -1; goto out; } /* Loop until all data is written */ while (*retlen < len) { /* Invalidate cache, if we write to this page */ if (nand->cache_page == page) nand->cache_page = -1; /* Write data into buffer */ 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++) { 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) goto out; /* Next data start at page boundary */ col = 0; /* Update written bytes count */ *retlen += cnt; /* Increment page address */ page++; } /* Return happy */ *retlen = len;out: /* De-select the NAND device */ NAND_DISABLE_CE(nand); /* set pin high */#ifdef CONFIG_OMAP1510 archflashwp(0,1);#endif#ifdef CFG_NAND_WP NAND_WP_ON();#endif return ret;}/* read from the 16 bytes of oob data that correspond to a 512 byte * page or 2 256-byte pages. */int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, size_t * retlen, u_char * buf){ int len256 = 0; struct Nand *mychip; int ret = 0; mychip = &nand->chips[ofs >> nand->chipshift]; /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with nand_read_ecc. */ if (nand->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } NAND_ENABLE_CE(nand); /* set pin low */ NanD_Command(nand, NAND_CMD_READOOB); 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 */ /* next OOB block, but it didn't work here. mf. */ if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; NanD_ReadBuf(nand, buf, len256); NanD_Command(nand, NAND_CMD_READOOB); NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); } NanD_ReadBuf(nand, &buf[len256], len - len256); *retlen = len; /* Reading the full OOB data drops us off of the end of the page, * causing the flash device to go into busy mode, so we need * to wait until ready 11.4.1 and Toshiba TC58256FT nands */ ret = NanD_WaitReady(nand, 1); NAND_DISABLE_CE(nand); /* set pin high */ return ret;}/* write to the 16 bytes of oob data that correspond to a 512 byte * page or 2 256-byte pages. */int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, size_t * retlen, const u_char * buf){ int len256 = 0; int i; unsigned long nandptr = nand->IO_ADDR;#ifdef PSYCHO_DEBUG printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n", (long)ofs, len, buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);#endif NAND_ENABLE_CE(nand); /* set pin low to enable chip */ /* Reset the chip */ NanD_Command(nand, NAND_CMD_RESET); /* issue the Read2 command to set the pointer to the Spare Data Area. */ NanD_Command(nand, NAND_CMD_READOOB);/* bug fixed by www.arm9.net * write oob sequence: * 1. NAND_CMD_READOOB * 2. NAND_CMD_SEQIN * 3. Address * 4. Data * 5. NAND_CMD_PAGEPROG * 6. NAND_CMD_STATUS */#if 0 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); }#endif /* update address for 2M x 8bit devices. OOB starts on the second */ /* page to maintain compatibility with nand_read_ecc. */ if (nand->page256) { if (!(ofs & 0x8)) ofs += 0x100; else ofs -= 0x8; } /* issue the Serial Data In command to initial the Page Program process */ NanD_Command(nand, NAND_CMD_SEQIN); 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 */ /* next OOB block, but it didn't work here. mf. */ if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { len256 = (ofs | 0x7) + 1 - ofs; for (i = 0; i < len256; 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); }#endif if (READ_NAND(nandptr) & 1) { puts ("Error programming oob data\n"); /* There was an error */ NAND_DISABLE_CE(nand); /* set pin high */ *retlen = 0; return -1; } NanD_Command(nand, NAND_CMD_SEQIN); NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); } if (nand->bus16) { for (i = len256; i < len; i += 2) { WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -