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
留言列表