📄 cmd_nand.c
字号:
return -1; } NAND_DISABLE_CE(nand); /* set pin high */ *retlen = len; return 0;}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). */ static struct jffs2_unknown_node clean_marker = { JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, 8 /* 8 bytes in this node */ };#ifndef CONFIG_S3C2440 unsigned long nandptr = nand->IO_ADDR;#endif 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; } /* Select the NAND device */#ifdef CONFIG_OMAP1510 archflashwp(0,0);#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, &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 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_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2, start, len, retlen, buf);}#endif /* CONFIG_JFFS2_NAND */#ifdef CONFIG_AESOP_YAFFS/* * NAND Flash Page write function for YAFFS image write */int nand_write_page_yaffs (int, u_char *);int nand_write_page_yaffs (int page, u_char *buff){ int i; struct nand_chip *nand = &nand_dev_desc[curr_device]; NAND_ENABLE_CE(nand); /* set pin low */ /* 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); /* Write out complete page of data with OOB */ for (i = 0; i < (nand->oobblock + nand->oobsize); i++) WRITE_NAND(buff[i], nand->IO_ADDR); /* Send command to actually program the data */ NanD_Command(nand, NAND_CMD_PAGEPROG); NanD_Command(nand, NAND_CMD_STATUS); /* See if device thinks it succeeded */ if (READ_NAND(nand->IO_ADDR) & 0x01) { NAND_DISABLE_CE(nand); /* set pin high */ printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page); return -1; } /* * 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 */ NanD_Command(nand, NAND_CMD_READ0); NanD_Address(nand, ADDR_COLUMN_PAGE, page << nand->page_shift); /* Loop through and verify the data */ for (i = 0; i < (nand->oobblock + nand->oobsize); i++) { if (buff[i] != READ_NAND(nand->IO_ADDR)) { NAND_DISABLE_CE(nand); /* set pin high */ printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page); return -1; } } NAND_DISABLE_CE(nand); /* set pin high */ return 0;}#endif /* CONFIG_AESOP_YAFFS */#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -