📄 nand_legacy.c
字号:
((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); 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. */ 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); } } 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); }#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_DISABLE_CE(nand); /* set pin high */ *retlen = len; return 0;}int nand_legacy_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). */ static struct jffs2_unknown_node clean_marker = { JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, 8 /* 8 bytes in this node */ }; unsigned long nandptr; struct Nand *mychip; int ret = 0; if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) { printf ("Offset and size must be sector aligned, erasesize = %d\n", (int) nand->erasesize); return -1; } nandptr = nand->IO_ADDR; /* 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 ("nand_write_ecc: Device is write protected!!!\n"); ret = -1; goto out; } /* 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; } /* FIXME: Do nand in the background. Use timers or schedule_task() */ while(len) { /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/ mychip = &nand->chips[ofs >> nand->chipshift]; /* always check for bad block first, genuine bad blocks * should _never_ be erased. */ if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) { /* Select the NAND device */ NAND_ENABLE_CE(nand); /* set pin low */ NanD_Command(nand, NAND_CMD_ERASE1); NanD_Address(nand, ADDR_PAGE, ofs); NanD_Command(nand, NAND_CMD_ERASE2); 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) { printf ("%s: Error erasing at 0x%lx\n", __FUNCTION__, (long)ofs); /* There was an error */ ret = -1; goto out; } if (clean) { int n; /* return value not used */ int p, l; /* clean marker position and size depend * on the page size, since 256 byte pages * only have 8 bytes of oob data */ if (nand->page256) { p = NAND_JFFS2_OOB8_FSDAPOS; l = NAND_JFFS2_OOB8_FSDALEN; } else { p = NAND_JFFS2_OOB16_FSDAPOS; l = NAND_JFFS2_OOB16_FSDALEN; } ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n, (u_char *)&clean_marker); /* quit here if write failed */ if (ret) goto out; } } ofs += nand->erasesize; len -= nand->erasesize; }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;}static inline int nandcheck(unsigned long potential, unsigned long physadr){ return 0;}unsigned long nand_probe(unsigned long physadr){ struct nand_chip *nand = NULL; int i = 0, ChipID = 1;#ifdef CONFIG_MTD_NAND_ECC_JFFS2 oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0; oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1; oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2; oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3; oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4; oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5; oob_config.eccvalid_pos = 4;#else oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0; oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1; oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2; oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3; oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4; oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5; oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;#endif oob_config.badblock_pos = 5; for (i=0; i<CFG_MAX_NAND_DEVICE; i++) { if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) { nand = &nand_dev_desc[i]; break; } } if (!nand) return (0); memset((char *)nand, 0, sizeof(struct nand_chip)); nand->IO_ADDR = physadr; nand->cache_page = -1; /* init the cache page */ NanD_ScanChips(nand); if (nand->totlen == 0) { /* no chips found, clean up and quit */ memset((char *)nand, 0, sizeof(struct nand_chip)); nand->ChipID = NAND_ChipID_UNKNOWN; return (0); } nand->ChipID = ChipID; if (curr_device == -1) curr_device = i; nand->data_buf = malloc (nand->oobblock + nand->oobsize); if (!nand->data_buf) { puts ("Cannot allocate memory for data structures.\n"); return (0); } return (nand->totlen);}#ifdef CONFIG_MTD_NAND_ECC/* * 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};/* * Creates non-inverted ECC code from line parity */static void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code){ u_char a, b, i, tmp1, tmp2; /* Initialize variables */ a = b = 0x80; tmp1 = tmp2 = 0; /* Calculate first ECC byte */ for (i = 0; i < 4; i++) { if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ tmp1 |= b; b >>= 1; if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ tmp1 |= b; b >>= 1; a >>= 1; } /* Calculate second ECC byte */ b = 0x80; for (i = 0; i < 4; i++) { if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ tmp2 |= b; b >>= 1; if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ tmp2 |= b; b >>= 1; a >>= 1; } /* Store two of the ECC bytes */ ecc_code[0] = tmp1; ecc_code[1] = tmp2;}/* * Calculate 3 byte ECC code for 256 byte block */static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code){ u_char idx, reg1, reg3; int j; /* Initialize variables */ reg1 = reg3 = 0; ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; /* Build up column parity */ for(j = 0; j < 256; j++) { /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[dat[j]]; reg1 ^= idx; /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (u_char) j; } } /* Create non-inverted ECC code from line parity */ nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code); /* Calculate final ECC code */ ecc_code[0] = ~ecc_code[0]; ecc_code[1] = ~ecc_code[1]; ecc_code[2] = ((~reg1) << 2) | 0x03;}/* * Detect and correct a 1 bit error for 256 byte block */static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc){ u_char a, b, c, d1, d2, d3, add, bit, i; /* Do error detection */ d1 = calc_ecc[0] ^ read_ecc[0]; d2 = calc_ecc[1] ^ read_ecc[1]; d3 = calc_ecc[2] ^ read_ecc[2]; if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; } else { a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; /* Found and will correct single bit error in the data */ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { c = 0x80; add = 0; a = 0x80; for (i=0; i<4; i++) { if (d1 & c) add |= a; c >>= 2; a >>= 1; } c = 0x80; for (i=0; i<4; i++) { if (d2 & c) add |= a; c >>= 2; a >>= 1; } bit = 0; b = 0x04; c = 0x80; for (i=0; i<3; i++) { if (d3 & c) bit |= b; c >>= 2; b >>= 1; } b = 0x01; a = dat[add]; a ^= (b << bit); dat[add] = a; return 1; } else { i = 0; while (d1) { if (d1 & 0x01) ++i; d1 >>= 1; } while (d2) { if (d2 & 0x01) ++i; d2 >>= 1; } while (d3) { if (d3 & 0x01) ++i; d3 >>= 1; } if (i == 1) { /* ECC Code Error Correction */ read_ecc[0] = calc_ecc[0]; read_ecc[1] = calc_ecc[1]; read_ecc[2] = calc_ecc[2]; return 2; } else { /* Uncorrectable Error */ return -1; } } } /* Should never happen */ return -1;}#endif#ifdef CONFIG_JFFS2_NANDint read_jffs2_nand(size_t start, size_t len, size_t * retlen, u_char * buf, int nanddev){ return nand_legacy_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2, start, len, retlen, buf);}#endif /* CONFIG_JFFS2_NAND */#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -