顺着昨天的整理下
struct spl_image_info { const char *name; u8 os; ulong load_addr; ulong entry_point; u32 size; u32 flags; };
void board_init_r(gd_t *dummy1, ulong dummy2) { u32 spl_boot_list[] = { BOOT_DEVICE_NONE, BOOT_DEVICE_NONE, BOOT_DEVICE_NONE, BOOT_DEVICE_NONE, BOOT_DEVICE_NONE, }; struct spl_image_info spl_image; if (!(gd->flags & GD_FLG_SPL_INIT)) { if (spl_init()) hang(); } memset(&spl_image, ' ', sizeof(spl_image)); board_boot_order(spl_boot_list); if (boot_from_devices(&spl_image, spl_boot_list, ARRAY_SIZE(spl_boot_list))) { puts("SPL: failed to boot from all boot devicesn"); hang(); } jump_to_image_no_args(&spl_image); }上述代码删减了不会编译的部分,和debug部分,及空函数部分
之前分析,最为重要的就是在boot_from_devices实现
static int boot_from_devices(struct spl_image_info *spl_image, u32 spl_boot_list[], int count) { int i; for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) { struct spl_image_loader *loader; loader = spl_ll_find_loader(spl_boot_list[i]); #if defined(CONFIG_SPL_SERIAL_SUPPORT) && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) if (loader) printf("Trying to boot from %sn", loader->name); else puts("SPL: Unsupported Boot Device!n"); #endif if (loader && !spl_load_image(spl_image, loader)) return 0; } return -ENODEV; }上次的分析已经指明了spl_load_image位于spl_nand.c中的
static int spl_nand_load_image(struct spl_image_info *spl_image, ? ? ? struct spl_boot_device *bootdev) { int err; struct image_header *header; int *src __attribute__((unused)); int *dst __attribute__((unused)); nand_init(); /*use CONFIG_SYS_TEXT_BASE as temporary storage area */ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); #ifdef CONFIG_NAND_ENV_DST spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header); #ifdef CONFIG_ENV_OFFSET_REDUND spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET_REDUND, header); #endif #endif /* Load u-boot */ err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS, ? ?header); nand_deselect(); return err; } #endif以上代码删去不会编译的,空代码,及debug
在分析这个函数之前先看
typedef struct image_header { __be32 ih_magic; /* Image Header Magic Number */ __be32 ih_hcrc; /* Image Header CRC Checksum */ __be32 ih_time; /* Image Creation Timestamp */ __be32 ih_size; /* Image Data Size */ __be32 ih_load; /* Data Load Address */ __be32 ih_ep; /* Entry Point Address */ __be32 ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t;之后到了nand_init()
void nand_init(void) { #ifdef CONFIG_SYS_NAND_SELF_INIT board_nand_init(); #else int i; for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) nand_init_chip(i); #endif printf("%lu MiBn", total_nand_size / 1024); #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(mtd_to_nand(nand_info[nand_curr_device]), nand_curr_device); #endif create_mtd_concat(); }
这里选择默认的初始化即
nand_init_chip则
static void nand_init_chip(int i) { struct nand_chip *nand = &nand_chip[i]; struct mtd_info *mtd = nand_to_mtd(nand); ulong base_addr = base_address[i]; int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; if (maxchips < 1) maxchips = 1; nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; if (board_nand_init(nand)) return; if (nand_scan(mtd, maxchips)) return; nand_register(i, mtd); }这里,从头分析首先看 nand_chip和mtd_info,非常多,这里用到哪里摘出来哪里
struct nand_chip { struct mtd_info mtd;
解释了前两句的关系,nand指向nand_chip[0],mtd指向nand->mtd,其中nand_to_mtd为内联函数
其中
tatic ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST
而后面的config_sys_nand_base_list由自定义的头文件定义。由注释看见
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the * flash device * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the * flash device.其为板级指定的nand_flash_base_address
接着
board_nand_init
为板级制定,追踪已有的s3c2410,是17.3rc uboot自带的,我的板级为nuvton
int board_nand_init(struct nand_chip *nand) { u_int32_t cfg; u_int8_t tacls, twrph0, twrph1; struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand(); debug("board_nand_init()n"); writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon); /* initialize hardware */ #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING) tacls = CONFIG_S3C24XX_TACLS; twrph0 = CONFIG_S3C24XX_TWRPH0; twrph1 = CONFIG_S3C24XX_TWRPH1; #else tacls = 4; twrph0 = 8; twrph1 = 8; #endif cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->nfconf); /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)&nand_reg->nfdata; nand->IO_ADDR_W = (void *)&nand_reg->nfdata; nand->select_chip = NULL; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ #ifdef CONFIG_NAND_SPL nand->read_buf = nand_read_buf; #endif /* hwcontrol always must be implemented */ nand->cmd_ctrl = s3c24x0_hwcontrol; nand->dev_ready = s3c24x0_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC nand->ecc.hwctl = s3c24x0_nand_enable_hwecc; nand->ecc.calculate = s3c24x0_nand_calculate_ecc; nand->ecc.correct = s3c24x0_nand_correct_data; nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; nand->ecc.strength = 1; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT nand->bbt_options |= NAND_BBT_USE_FLASH; #endif debug("end of nand_initn"); return 0; }
nand_scan int nand_scan(struct mtd_info *mtd, int maxchips) { int ret; ret = nand_scan_ident(mtd, maxchips, NULL); if (!ret) ret = nand_scan_tail(mtd); return ret; } /** * nand_scan_ident - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure * @maxchips: number of chips to scan for * @table: alternative NAND ID table * * This is the first phase of the normal nand_scan() function. It reads the * flash ID and sets up MTD fields accordingly. * */ int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { int i, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd_to_nand(mtd); struct nand_flash_dev *type; int ret; if (chip->flash_node) { ret = nand_dt_init(mtd, chip, chip->flash_node); if (ret) return ret; } /* Set the default functions */ nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); /* Read the flash type */ type = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table); if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) pr_warn("No NAND device foundn"); chip->select_chip(mtd, -1); return PTR_ERR(type); } chip->select_chip(mtd, -1); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { chip->select_chip(mtd, i); /* See comment in nand_get_flash_type for reset */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || nand_dev_id != chip->read_byte(mtd)) { chip->select_chip(mtd, -1); break; } chip->select_chip(mtd, -1); } #ifdef DEBUG if (i > 1) pr_info("%d chips detectedn", i); #endif /* Store the number of chips and calc total size for mtd */ chip->numchips = i; mtd->size = i * chip->chipsize; return 0; } /* Register an initialized NAND mtd device with the U-Boot NAND command. */ int nand_register(int devnum, struct mtd_info *mtd) { if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) return -EINVAL; nand_info[devnum] = mtd; sprintf(dev_name[devnum], "nand%d", devnum); mtd->name = dev_name[devnum]; #ifdef CONFIG_MTD_DEVICE /* * Add MTD device so that we can reference it later * via the mtdcore infrastructure (e.g. ubi). */ add_mtd_device(mtd); #endif total_nand_size += mtd->size / 1024; if (nand_curr_device == -1) nand_curr_device = devnum; return 0; }
?
思考,如果正确返回nand结构体的值,也意味着正确返回了mtd,之后的函数采用Uboot原版的方式
所以主要重点在于
board_nand_init
*************************************************************************************************************************************
修改,复制13板的文件到自己的板级目录,着重看这个文件
int board_nand_init(struct nand_chip *nand) { struct mtd_info *mtd; nuc970_nand = &g_nuc970_nand; //struct nuc970_nand_info g_nuc970_nand; // struct nuc970_nand_info *nuc970_nand;最前面的定义, memset((void*)nuc970_nand,0,sizeof(struct nuc970_nand_info)); //CWWeng if (!nuc970_nand) return -1; mtd=&nuc970_nand->mtd; nuc970_nand->chip.controller = &nuc970_nand->controller; /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)REG_SMDATA; nand->IO_ADDR_W = (void *)REG_SMDATA; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ nand->read_buf = nand_read_buf; /* hwcontrol always must be implemented */ nand->cmd_ctrl = nuc970_hwcontrol; nand->cmdfunc = nuc970_nand_command_lp; nand->dev_ready = nuc970_dev_ready; nand->select_chip = nuc970_nand_select_chip; nand->read_byte = nuc970_nand_read_byte; nand->write_buf = nuc970_nand_write_buf; nand->read_buf = nuc970_nand_read_buf; //nand->verify_buf = nuc970_verify_buf; nand->chip_delay = 50; nand->controller = &nuc970_nand->controller; nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; nand->ecc.hwctl = nuc970_nand_enable_hwecc; nand->ecc.calculate = nuc970_nand_calculate_ecc; nand->ecc.correct = nuc970_nand_correct_data; nand->ecc.write_page= nuc970_nand_write_page_hwecc; nand->ecc.read_page = nuc970_nand_read_page_hwecc_oob_first; nand->ecc.read_oob = nuc970_nand_read_oob_hwecc; nand->ecc.layout = &nuc970_nand_oob; mtd->priv = nand; /* initial NAND controller */ writel( (readl(REG_HCLKEN)|(0x300000)), REG_HCLKEN); if (readl(REG_PWRON) & 0x08000000) { writel( 0x55555550, REG_MFP_GPI_L); writel( 0x55555555, REG_MFP_GPI_H); } else { writel( 0x55555555, REG_MFP_GPC_L); writel( 0x05555555, REG_MFP_GPC_H); } // Enable SM_EN writel(NAND_EN, REG_FMICSR); writel(0x20305, REG_SMTCR); // Enable SM_CS0 writel((readl(REG_SMCSR)&(~0x06000000))|0x04000000, REG_SMCSR); writel(0x1, REG_NFECR); /* un-lock write protect */ // NAND Reset writel(readl(REG_SMCSR) | 0x1, REG_SMCSR); // software reset while (readl(REG_SMCSR) & 0x1); /* Detect NAND chips */ /* first scan to find the device and get the page size */ if (nand_scan_ident(&(nuc970_nand->mtd), 1, NULL)) { printf("NAND Flash not found !n"); return -1; }
这里需要修改,与外面的nand_scan_ident一样,我们只要给正确的mtd指针就行
&(nuc970_nand->mtd),所以这里删掉前面的定义,这里采用外面的结构
删除
/* Detect NAND chips */ /* first scan to find the device and get the page size */ if (nand_scan_ident(&(nuc970_nand->mtd), 1, NULL)) { printf("NAND Flash not found !n"); return -1; }
之后都不要变动,makefile,添加编译新的文件,且注意与原来的nand_base间的关系,
obj-y += nuc970_nand.o
检查CONFIG_SPL_NAND_BASE是否定义
将原厂的nand文件放置drivers/mtd/nand/里面注意添加makefile,并注意有没有kconfig的修改
之后看看
/*use CONFIG_SYS_TEXT_BASE as temporary storage area */ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE); #ifdef CONFIG_NAND_ENV_DST spl_nand_load_element(spl_image, CONFIG_ENV_OFFSET, header); #endif /* Load u-boot */ err = spl_nand_load_element(spl_image, CONFIG_SYS_NAND_U_BOOT_OFFS, ? ?header); nand_deselect(); return err; } //这个函数很关键 static int spl_nand_load_element(struct spl_image_info *spl_image, int offset, struct image_header *header) { int err; err = nand_spl_load_image(offset, sizeof(*header), (void *)header); if (err) return err; if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && image_get_magic(header) == FDT_MAGIC) { struct spl_load_info load; debug("Found FITn"); load.dev = NULL; load.priv = NULL; load.filename = NULL; load.bl_len = 1; load.read = spl_nand_fit_read; return spl_load_simple_fit(spl_image, &load, offset, header); } else { err = spl_parse_image_header(spl_image, header); if (err) return err; return nand_spl_load_image(offset, spl_image->size, (void *)(ulong)spl_image->load_addr); } }
其中,采用默认的nand_spl_simple.c中,但是不能编译其,需要在另外的位置添加这个函数,换句话说,只是利用了这个文件里面的函数
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) { //CONFIG_ENV_OFFSET sizeof(*header) (void *)header unsigned int block, lastblock; unsigned int page; /* * offs has to be aligned to a page address! */ block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; while (block <= lastblock) { if (!nand_is_bad_block(block)) { /* * Skip bad blocks */ while (page < CONFIG_SYS_NAND_PAGE_COUNT) { nand_read_page(block, page, dst); dst += CONFIG_SYS_NAND_PAGE_SIZE; page++; } page = 0; } else { lastblock++; } block++; } return 0; } nand_read_page static int nand_read_page(int block, int page, void *dst) { struct nand_chip *this = mtd_to_nand(mtd); u_char ecc_calc[ECCTOTAL]; u_char ecc_code[ECCTOTAL]; u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; int i; int eccsize = CONFIG_SYS_NAND_ECCSIZE; int eccbytes = CONFIG_SYS_NAND_ECCBYTES; int eccsteps = ECCSTEPS; uint8_t *p = dst; nand_command(block, page, 0, NAND_CMD_READ0); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { if (this->ecc.mode != NAND_ECC_SOFT) this->ecc.hwctl(mtd, NAND_ECC_READ); this->read_buf(mtd, p, eccsize); this->ecc.calculate(mtd, p, &ecc_calc[i]); } this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); /* Pick the ECC bytes out of the oob data */ for (i = 0; i < ECCTOTAL; i++) ecc_code[i] = oob_data[nand_ecc_pos[i]]; eccsteps = ECCSTEPS; p = dst; for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { /* No chance to do something with the possible error message * from correct_data(). We just hope that all possible errors * are corrected by this routine. */ this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); } return 0; } static int nand_command(int block, int page, uint32_t offs, u8 cmd) { struct nand_chip *this = mtd_to_nand(mtd); int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; while (!this->dev_ready(mtd)) ; /* Begin command latch cycle */ this->cmd_ctrl(mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); /* Set ALE and clear CLE to start address cycle */ /* Column address */ this->cmd_ctrl(mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); this->cmd_ctrl(mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */ this->cmd_ctrl(mtd, (page_addr >> 8) & 0xff, NAND_CTRL_ALE); /* A[24:17] */ #ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE /* One more address cycle for devices > 32MiB */ this->cmd_ctrl(mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE); /* A[28:25] */ #endif /* Latch in address */ this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* * Wait a while for the data to be ready */ while (!this->dev_ready(mtd)) ; return 0; } //对比13版的,发现简化了不少 static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst) { struct nand_chip *this = mtd->priv; int real_page; real_page = block * (CONFIG_SYS_NAND_BLOCK_SIZE / CONFIG_SYS_NAND_PAGE_SIZE) + page; if (this->ecc.read_page) this->ecc.read_page(mtd, this, dst, real_page); //CWWeng : it calls nuc970_nand_read_page_hwecc_oob_first return 0; } //修改得到我自己的 static int nand_read_page(int block, int page, void *dst) { struct nand_chip *this = mtd_to_nand(mtd); int real_page; real_page = block * (CONFIG_SYS_NAND_BLOCK_SIZE / CONFIG_SYS_NAND_PAGE_SIZE) + page; if (this->ecc.read_page) this->ecc.read_page(mtd, this, dst, real_page); //CWWeng : it calls nuc970_nand_read_page_hwecc_oob_first return 0; } //回过头来最后看 err = spl_parse_image_header(spl_image, header); if (err) return err; return nand_spl_load_image(offset, spl_image->size,(void *)(ulong)spl_image->load_addr); spl_parse_image_header int spl_parse_image_header(struct spl_image_info *spl_image, const struct image_header *header) { u32 header_size = sizeof(struct image_header); if (image_get_magic(header) == IH_MAGIC) { if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY) { /* * On some system (e.g. powerpc), the load-address and * entry-point is located at address 0. We can't load * to 0-0x40. So skip header in this case. */ spl_image->load_addr = image_get_load(header); spl_image->entry_point = image_get_ep(header); spl_image->size = image_get_data_size(header); } else { spl_image->entry_point = image_get_load(header); /* Load including the header */ spl_image->load_addr = spl_image->entry_point - header_size; spl_image->size = image_get_data_size(header) + header_size; } spl_image->os = image_get_os(header); spl_image->name = image_get_name(header); debug("spl: payload image: %.*s load addr: 0x%lx size: %dn", (int)sizeof(spl_image->name), spl_image->name, spl_image->load_addr, spl_image->size); } else { #ifdef CONFIG_SPL_PANIC_ON_RAW_IMAGE /* * CONFIG_SPL_PANIC_ON_RAW_IMAGE is defined when the * code which loads images in SPL cannot guarantee that * absolutely all read errors will be reported. * An example is the LPC32XX MLC NAND driver, which * will consider that a completely unreadable NAND block * is bad, and thus should be skipped silently. */ panic("** no mkimage signature but raw image not supported"); #endif #ifdef CONFIG_SPL_OS_BOOT ulong start, end; if (!bootz_setup((ulong)header, &start, &end)) { spl_image->name = "Linux"; spl_image->os = IH_OS_LINUX; spl_image->load_addr = CONFIG_SYS_LOAD_ADDR; spl_image->entry_point = CONFIG_SYS_LOAD_ADDR; spl_image->size = end - start; debug("spl: payload zImage, load addr: 0x%lx size: %dn", spl_image->load_addr, spl_image->size); return 0; } #endif #ifdef CONFIG_SPL_ABORT_ON_RAW_IMAGE /* Signature not found, proceed to other boot methods. */ return -EINVAL; #else /* Signature not found - assume u-boot.bin */ debug("mkimage signature not found - ih_magic = %xn", header->ih_magic); spl_set_header_raw_uboot(spl_image); #endif } return 0; }
这里面体现了13版和17版的差别,17解析了镜像头部,填充了image的信息,从而做出选择流
return nand_spl_load_image(offset, spl_image->size,(void *)(ulong)spl_image->load_addr);
这里才是真正去加载uboot到ram中
因为手头没有工具,也没有电脑,具体明天开始移植修改?
这里要真的明白一些问题,需要理解env_data,还有uboot,还有header,还有header里面的信息。
当然还有
CONFIG_SYS_TEXT_BASE
这个比较重要的地方
第一遍的认识为,首先进行缓冲存储,此时镜像存储在buffer,最后return真正加载。具体明天细究
几个问题:
1. env_data的组织结构,与uboot的组织结构
2.理解加载地址,运行地址的区别
3.指出来uboot,env_data的load_addr在哪里被指定。
4.nand储存芯片一些必备的常识