Example #1
0
/*****************************************************************************
* 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;
}