/***************************************************************************** * name : flash_write * * description : write data to nand * * input : ptentry *ptn: flash partition to write * : unsigned extra_per_page: * : void *data: buffer to save data * : unsigned bytes: number of bytes to write * * return : NANDF_ERROR_INIT: Init failed * NANDF_ERROR_ARGS: Input error * NANDF_BAD_BLOCK: bad block * NANDF_ERROR_READ: read error when check bad block * NANDF_ERROR_WRITE: write error and mark bad block error * NANDF_ERROR_WRITE_MARKBAD: write error and mark bad block successful * NANDF_ERROR_SEMTAKE: apply semphore failed * NANDF_ERROR_SEMGIVE: release semphore failed * NANDF_OK: write successful * * other : No *****************************************************************************/ int flash_write(ptentry *ptn, unsigned extra_per_page, const void *data, unsigned bytes) { int ret = 0; u64 startAddr = 0; startAddr = ptn->start; ret = nand_write_oob((u64)startAddr, (u32)data, bytes, extra_per_page,NULL); return ret; }
/* cmd: 0: NANDRW_WRITE write, fail on bad block * 1: NANDRW_READ read, fail on bad block * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks */ int nand_legacy_rw (struct nand_chip* nand, int cmd, size_t start, size_t len, size_t * retlen, u_char * buf) { int ret = 0, n, total = 0; char eccbuf[6]; /* eblk (once set) is the start of the erase block containing the * data being processed. */ unsigned long eblk = ~0; /* force mismatch on first pass */ unsigned long erasesize = nand->erasesize; int bfirstyaffsblk = 1; int page; unsigned long badblk=0, prgmblk=0; unsigned long badblks=0, prgmblks = 0; unsigned long allblks; allblks = (erasesize/nand->oobblock)*(nand->oobblock+nand->oobsize); allblks = (len + allblks - 1) / allblks; if ((cmd & NANDRW_YAFFS) && (len % (nand->oobblock + nand->oobsize))) { printf("Length of the yaffs image should be times of (%d +%d), now it is %d\n", nand->oobblock, nand->oobsize, len); return -1; } if ((cmd & NANDRW_YAFFS) && (start % erasesize)) { printf("Start address of the flash should be %d align\n", erasesize); return -1; } if (cmd & (NANDRW_WRITE | NANDRW_YAFFS)) { printf("Flash params: oobblock = %d, oobsize = %d, erasesize = %d\n", nand->oobblock, nand->oobsize, nand->erasesize); printf("Programming NAND with yaffs image, length = %d\n", len); printf(" Block Programming(addr/count) --- Block bad(addr/count) --- Block programed/All(%%)\n"); printf("------------------------------------------------------------------------------------\n"); } while (len) { if ((start & (-erasesize)) != eblk) { /* have crossed into new erase block, deal with * it if it is sure marked bad. */ eblk = start & (-erasesize); /* start of block */ if (check_block(nand, eblk)) { badblk = eblk; badblks++; if (cmd == (NANDRW_READ | NANDRW_JFFS2)) { while (len > 0 && start - eblk < erasesize) { *(buf++) = 0xff; ++start; ++total; --len; } continue; } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) { start += erasesize; continue; } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) { /* skip bad block */ start += erasesize; continue; } else if (cmd == (NANDRW_WRITE | NANDRW_YAFFS)) { printf(" 0x%08x/%05d 0x%08x/%05d %05d/%05d=%02d%%\r", prgmblk, prgmblks, badblk, badblks, prgmblks, allblks, prgmblks*100/allblks); /* skip bad block */ start += erasesize; continue; } else { ret = 1; break; } } } /* The ECC will not be calculated correctly if less than 512 is written or read */ /* Is request at least 512 bytes AND it starts on a proper boundry */ 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"); /* for yaffs */ if (cmd & (NANDRW_WRITE | NANDRW_YAFFS)) { /* Do some programming, but not in the first block */ if (!bfirstyaffsblk) { prgmblk = start; prgmblks++; printf(" 0x%08x/%05d 0x%08x/%05d %05d/%05d=%02d%%\r", prgmblk, prgmblks, badblk, badblks, prgmblks, allblks, prgmblks*100/allblks); for (page = 0; (page < erasesize/nand->oobblock) && (len - page*(nand->oobblock+nand->oobsize) > 0); page++) { ret = nand_write_ecc(nand, start+page*nand->oobblock, nand->oobblock, (size_t *)&n, (u_char*)buf+page*(nand->oobblock+nand->oobsize), (u_char *)0); /* without ecc */ if (!ret) ret = nand_write_oob(nand, start+page*nand->oobblock, nand->oobsize, (size_t *)&n, (u_char*)buf+page*(nand->oobblock+nand->oobsize)+nand->oobblock); if (ret) break; } n = page * (nand->oobblock+nand->oobsize); } else { bfirstyaffsblk = 0; n = 0; start += erasesize; /* skip first block */ ret = 0; page = 0; } } else if (cmd & NANDRW_READ) { ret = nand_read_ecc(nand, start, min(len, eblk + erasesize - start), (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); } else { ret = nand_write_ecc(nand, start, min(len, eblk + erasesize - start), (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); } if (ret) break; if (cmd & (NANDRW_WRITE | NANDRW_YAFFS)) start += page * nand->oobblock; else start += n; buf += n; total += n; len -= n; } if (retlen) *retlen = total; printf("\n"); return ret; }