close

1.UBL

2.U-boot

3.Kernel

4.Rootfs (yaffs)

NAND flahs燒錄真的是很麻煩的一件事.Page size, Bad block和ECC機制都需要額外處理.所以目前NAND燒錄器都需要某個程度的客制化.並且TI的UBL和U-BOOT都需要在前面補上Descriptor.JAFFS2/YAFFS2更有其特殊的燒錄模式.所以造成量產上的困擾.

從uboot擷取了ubl or uboot的寫入流程:

if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
    int read;

    if (argc < 4)
        goto usage;

    addr = (ulong)simple_strtoul(argv[2], NULL, 16);

    read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
    printf("\nNAND %s: ", read ? "read" : "write");
    if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
        return 1;

    s = strchr(cmd, '.');
    if (!s || !strcmp(s, ".jffs2") ||
        !strcmp(s, ".e") || !strcmp(s, ".i")) {
        if (read)
            ret = nand_read_skip_bad(nand, off, &size,
                         (u_char *)addr);
        else {
            if(off == 0x20000) {
                // Make UBL Descriptor
                if(make_ubl_desc((u_char *)addr, ubl_size) > 0) {
                    printf("Making UBL Descriptor failed!.\n");
                    return 1;
                }
            } else if(off == 0x320000) {
                // Make Uboot Descriptor
                if(make_uboot_desc((u_char *)addr, uboot_size) > 0) {
                    printf("Making Uboot Descriptor failed!.\n");
                    return 1;
                }
            }
            ret = nand_write_skip_bad(nand, off, &size,
                          (u_char *)addr);
        }
    } 
    else if (s != NULL && !strcmp(s, ".yaffs")) {
        nand_write_options_t opts;
        memset(&opts, 0, sizeof(opts));
        opts.buffer    = (u_char *) addr;
        opts.length    = size;
        opts.offset    = off;
        opts.pad    = 0;
        opts.blockalign = 1;
        opts.quiet      = quiet;
        opts.writeoob    = 1;
        opts.autoplace    = 1;
        opts.forceyaffs = 1;
        nand_write_opts(nand, &opts);
    }
//省略
}
static int make_ubl_desc(u_char *data_addr, size_t size)
{
    unsigned int *ubldesc;
    u_char *tmp_buf, *src_buf;
    size_t numPages;
    
    if(size > UBL_FILE_SIZE) {
        printf("Invalid UBL file size\n");
        return 1;
    }

    tmp_buf = (u_char *)0x87000000;
    
    numPages = 0;
    while ((numPages * CFG_NAND_PAGE_SIZE) < size) {
          numPages++;
    }
    
    // copy to temp buffer..
    memcpy(tmp_buf, data_addr, size);
    
    // make ubl descriptor..
    memset(davinci_desc_buf, 0xFF, CFG_NAND_PAGE_SIZE);
    
    ubldesc = (unsigned int *)davinci_desc_buf;
    ubldesc[0] = 0xA1ACED00; //ubl magic number
    ubldesc[1] = 0x0100;     //ubl fixed entry point;
    ubldesc[2] = numPages;   //ubl number of pages;
    ubldesc[3] = 1;          //ubl search start block;
    ubldesc[4] = 1;          //ubl search start page;
    ubldesc[5] = 0;          //ubl loadaddress;
    
    // copy to ori buffer
    src_buf = (u_char *)data_addr;
    memcpy(src_buf, davinci_desc_buf, CFG_NAND_PAGE_SIZE);
    
    src_buf += CFG_NAND_PAGE_SIZE;
    memcpy(src_buf, tmp_buf, size);

    return 0;
}

而標準的程式並沒有提供上面的部份.只能透過CSS的環境燒錄.所以要做記得跟代理商索取這邊的程式.

另外yaffs有自己的sw ECC, TI也有自己的ECC算法...這也是另外一個麻煩的事情.使得整個燒錄過程複雜許多.

 

void nand_davinci_switch_ecc(int32_t hardware)
{
    struct nand_chip *nand;
    struct mtd_info *mtd;

    if (nand_curr_device < 0 ||
        nand_curr_device >= CFG_MAX_NAND_DEVICE ||
        !nand_info[nand_curr_device].name) {
        printf("Error: Can't switch ecc, no devices available\n");
        return;
    }

    mtd = &nand_info[nand_curr_device];
    nand = mtd->priv;

    nand->options |= NAND_OWN_BUFFERS;

    /* Reset ecc interface */
    nand->ecc.read_page = NULL;
    nand->ecc.write_page = NULL;
    nand->ecc.read_oob = NULL;
    nand->ecc.write_oob = NULL;
    nand->ecc.hwctl = NULL;
    nand->ecc.correct = NULL;
    nand->ecc.calculate = NULL;

    /* Setup the ecc configurations again */
    if (hardware) {
        nand->ecc.mode = NAND_ECC_HW_SYNDROME;
        nand->ecc.size = 512;
        nand->ecc.bytes = 10;
        nand->ecc.prepad = 6;
        nand->bbt_td = &nand_davinci_bbt_main_descr;
        nand->bbt_md = &nand_davinci_bbt_mirror_descr;
        nand->ecc.layout = &nand_davinci_4bit_layout;
        nand->ecc.calculate = nand_davinci_4bit_calculate_ecc;
        nand->ecc.correct = nand_davinci_4bit_correct_data;
        nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc;
        nand->ecc.read_page = davinci_std_read_page_syndrome;
        nand->ecc.write_page = davinci_std_write_page_syndrome;
        nand->ecc.read_oob = davinci_std_read_oob_syndrome;
        nand->ecc.write_oob = davinci_std_write_oob_syndrome;
        printf("HW ECC selected\n");
    } else {
        nand->ecc.mode = NAND_ECC_SOFT;
        /* Use mtd default settings */
        nand->ecc.layout = NULL;
        printf("SW ECC selected\n");
    }

    /* Update NAND handling after ECC mode switch */
    nand_scan_tail(mtd);

    nand->options &= ~NAND_OWN_BUFFERS;
}
**
 * nand_scan_tail - [NAND Interface] Scan for the NAND device
 * @mtd:        MTD device structure
 * @maxchips:        Number of chips to scan for
 *
 * This is the second phase of the normal nand_scan() function. It
 * fills out all the uninitialized function pointers with the defaults
 * and scans for a bad block table if appropriate.
 */
int nand_scan_tail(struct mtd_info *mtd)
{
    int i;
    struct nand_chip *chip = mtd->priv;

    if (!(chip->options & NAND_OWN_BUFFERS))
        chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
    if (!chip->buffers)
        return -ENOMEM;

    /* Set the internal oob buffer location, just after the page data */
    chip->oob_poi = chip->buffers->databuf + mtd->writesize;

    /*
     * If no default placement scheme is given, select an appropriate one
     */
    if (!chip->ecc.layout) {
        switch (mtd->oobsize) {
        case 8:
            chip->ecc.layout = &nand_oob_8;
            break;
        case 16:
            chip->ecc.layout = &nand_oob_16;
            break;
        case 64:
            chip->ecc.layout = &nand_oob_64;
            break;
        case 128:
            chip->ecc.layout = &nand_oob_128;
            break;
        default:
            printk(KERN_WARNING "No oob scheme defined for "
                   "oobsize %d\n", mtd->oobsize);
/*            BUG(); */
        }
    }

    if (!chip->write_page)
        chip->write_page = nand_write_page;

    /*
     * check ECC mode, default to software if 3byte/512byte hardware ECC is
     * selected and we have 256 byte pagesize fallback to software ECC
     */
    if (!chip->ecc.read_page_raw)
        chip->ecc.read_page_raw = nand_read_page_raw;
    if (!chip->ecc.write_page_raw)
        chip->ecc.write_page_raw = nand_write_page_raw;

    switch (chip->ecc.mode) {
    case NAND_ECC_HW:
        /* Use standard hwecc read page function ? */
        if (!chip->ecc.read_page)
            chip->ecc.read_page = nand_read_page_hwecc;
        if (!chip->ecc.write_page)
            chip->ecc.write_page = nand_write_page_hwecc;
        if (!chip->ecc.read_oob)
            chip->ecc.read_oob = nand_read_oob_std;
        if (!chip->ecc.write_oob)
            chip->ecc.write_oob = nand_write_oob_std;

    case NAND_ECC_HW_SYNDROME:
        if ((!chip->ecc.calculate || !chip->ecc.correct ||
             !chip->ecc.hwctl) &&
            (!chip->ecc.read_page ||
             chip->ecc.read_page == nand_read_page_hwecc ||
             !chip->ecc.write_page ||
             chip->ecc.write_page == nand_write_page_hwecc)) {
            printk(KERN_WARNING "No ECC functions supplied, "
                   "Hardware ECC not possible\n");
            BUG();
        }
        /* Use standard syndrome read/write page function ? */
        if (!chip->ecc.read_page)
            chip->ecc.read_page = nand_read_page_syndrome;
        if (!chip->ecc.write_page)
            chip->ecc.write_page = nand_write_page_syndrome;
        if (!chip->ecc.read_oob)
            chip->ecc.read_oob = nand_read_oob_syndrome;
        if (!chip->ecc.write_oob)
            chip->ecc.write_oob = nand_write_oob_syndrome;

        if (mtd->writesize >= chip->ecc.size)
            break;
        printk(KERN_WARNING "%d byte HW ECC not possible on "
               "%d byte page size, fallback to SW ECC\n",
               chip->ecc.size, mtd->writesize);
        chip->ecc.mode = NAND_ECC_SOFT;

    case NAND_ECC_SOFT:
        chip->ecc.calculate = nand_calculate_ecc;
        chip->ecc.correct = nand_correct_data;
        chip->ecc.read_page = nand_read_page_swecc;
        chip->ecc.write_page = nand_write_page_swecc;
        chip->ecc.read_oob = nand_read_oob_std;
        chip->ecc.write_oob = nand_write_oob_std;
        chip->ecc.size = 256;
        chip->ecc.bytes = 3;
        break;

    case NAND_ECC_NONE:
        printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
               "This is not recommended !!\n");
        chip->ecc.read_page = nand_read_page_raw;
        chip->ecc.write_page = nand_write_page_raw;
        chip->ecc.read_oob = nand_read_oob_std;
        chip->ecc.write_oob = nand_write_oob_std;
        chip->ecc.size = mtd->writesize;
        chip->ecc.bytes = 0;
        break;

    default:
        printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
               chip->ecc.mode);
        BUG();
    }

    /*
     * Set the number of read / write steps for one page depending on ECC
     * mode
     */
    chip->ecc.steps = mtd->writesize / chip->ecc.size;
    if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {
        printk(KERN_WARNING "Invalid ecc parameters\n");
        BUG();
    }
    chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;

    /*
     * The number of bytes available for a client to place data into
     * the out of band area
     */
    chip->ecc.layout->oobavail = 0;
    for (i = 0; i < chip->ecc.steps && i < MTD_MAX_OOBFREE_ENTRIES &&
         chip->ecc.layout->oobfree[i].length; i++)
        chip->ecc.layout->oobavail +=
            chip->ecc.layout->oobfree[i].length;
    mtd->oobavail = chip->ecc.layout->oobavail;

    /*
     * Allow subpage writes up to ecc.steps. Not possible for MLC
     * FLASH.
     */
    if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
        !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
        switch(chip->ecc.steps) {
        case 2:
            mtd->subpage_sft = 1;
            break;
        case 4:
        case 8:
            mtd->subpage_sft = 2;
            break;
        }
    }
    chip->subpagesize = mtd->writesize >> mtd->subpage_sft;

    /* Initialize state */
    chip->state = FL_READY;

    /* De-select the device */
    chip->select_chip(mtd, -1);

    /* Invalidate the pagebuffer reference */
    chip->pagebuf = -1;

    /* Fill in remaining MTD driver data */
    mtd->type = MTD_NANDFLASH;
    mtd->flags = MTD_CAP_NANDFLASH;
    mtd->erase = nand_erase;
    mtd->point = NULL;
    mtd->unpoint = NULL;
    mtd->read = nand_read;
    mtd->write = nand_write;
    mtd->read_oob = nand_read_oob;
    mtd->write_oob = nand_write_oob;
    mtd->sync = nand_sync;
    mtd->lock = NULL;
    mtd->unlock = NULL;
    mtd->suspend = nand_suspend;
    mtd->resume = nand_resume;
    mtd->block_isbad = nand_block_isbad;
    mtd->block_markbad = nand_block_markbad;

    /* propagate ecc.layout to mtd_info */
    mtd->ecclayout = chip->ecc.layout;

    /* Check, if we should skip the bad block table scan */
    if (chip->options & NAND_SKIP_BBTSCAN) {
        chip->options |= NAND_BBT_SCANNED;
        return 0;
    }

    chip->scan_bbt(mtd);
    chip->options |= NAND_BBT_SCANNED;

    return 0;
}

光uboot改的就不少, 所以算是一個小工程了. 但主要重點就是ECC怎麼計算以及descriptor

燒錄命令如下:

Updating UBL
DM365: setenv serverip <tftp server IP address>
DM365: dhcp
DM365: tftpboot 0x82000000 ubl.bin
DM365: nand erase 0x20000 0x20000
DM365: nand write 0x82000000 0x20000 0x20000
   
Updating U-Boot
Run the following command to copy U-boot to the device
DM365: tftpboot 0x82000000 u-boot
DM365: nand erase 0x320000 0x40000
DM365: nand write 0x82000000 0x320000 0x40000

Updating the kernel uImage
DM365: setenv bootfile uImage
DM365: setenv serverip <tftp server IP address>
DM365: dhcp
DM365: nand erase 0x680000 0x400000
DM365: nand write 0x80700000 0x680000 0x400000

Restoring the DM365 NAND Flash Filesystem
tftpboot 0x82000000 target_fs.yaffs
DM365: nandecc sw
DM365: nand erase 0xA80000 7480000
DM365: nand write.yaffs 0x82000000 0xA80000 <file size>
DM365: nandecc hw


Updating UBL (support after DVRRDK_v1.0a)

DVR: setenv serverip <tftp server IP address>

DVR: dhcp

DVR: tftpboot 0x82000000 ubl_dvr_dm36x_0.4.0.bin

  Copy UBL from DDR memory to NAND using the following commands

DVR: nand erase 0x20000 0x20000

DVR: nand write 0x82000000 0x20000 0x20000

       

Updating U-Boot

Run the following command to copy U-boot to the device

DVR: tftpboot 0x82000000 u-boot-1.3.4-dm368_dvr.bin

  Copy U-boot from DDR memory to NAND using the following commands

DVR: nand erase 0x320000 0x40000

DVR: nand write 0x82000000 0x320000 0x40000

 

Updating the kernel uImage

DVR: setenv bootfile uImage_DM368_DVR

DVR: setenv serverip <tftp server IP address>

DVR: dhcp

DVR: nand erase 0x680000 0x400000

DVR: nand write 0x80700000 0x680000 0x400000

 

Restoring the DVR NAND Flash Filesystem

tftpboot 0x82000000 dvr_target_fs.yaffs

DVR: nandecc sw

DVR: nand erase 0xA80000 7480000

DVR: nand write.yaffs 0x82000000 0xA80000 <file size>

DVR: nandecc hw

arrow
arrow
    全站熱搜

    Person 發表在 痞客邦 留言(0) 人氣()