void board_init_r (gd_t *id, ulong dest_addr)
{
char *s;
bd_t *bd;
ulong malloc_start;
#ifndef CONFIG_SYS_NO_FLASH
ulong flash_size;
#endif
gd = id; /* initialize RAM version of global data */
bd = gd->bd;
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
printf ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
WATCHDOG_RESET ();
/*
* Setup trap handlers
*/
trap_init (dest_addr);
monitor_flash_len = (ulong)&__init_end - dest_addr;
WATCHDOG_RESET ();
asm ("sync ; isync");
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
#if !defined(CONFIG_SYS_NO_FLASH)
puts ("FLASH: ");
if ((flash_size = flash_init ()) > 0) {
/* !CONFIG_SYS_FLASH_CHECKSUM */
print_size (flash_size, "\n");
} else {
puts (failed);
hang ();
}
bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; /* update start of FLASH memory */
bd->bi_flashsize = flash_size; /* size of FLASH memory (final value) */
WATCHDOG_RESET ();
/* initialize higher level parts of CPU like time base and timers */
cpu_init_r ();
WATCHDOG_RESET ();
/* relocate environment function pointers etc. */
env_relocate ();
/*
* Fill in missing fields of bd_info.
* We do this here, where we have "normal" access to the
* environment; we used to do this still running from ROM,
* where had to use getenv_r(), which can be pretty slow when
* the environment is in EEPROM.
*/
#ifdef CONFIG_CMD_NET
/* kept around for legacy kernels only ... ignore the next section */
eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
#endif /* CONFIG_CMD_NET */
/* IP Address */
bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
WATCHDOG_RESET ();
/** leave this here (after malloc(), environment and PCI are working) **/
/* Initialize stdio devices */
stdio_init ();
/* Initialize the jump table for applications */
jumptable_init ();
/* Initialize the console (after the relocation and devices init) */
console_init_r ();
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
printf ("U-Boot relocated to %08lx\n", dest_addr);
/*
* Enable Interrupts
*/
interrupt_init ();
/* Must happen after interrupts are initialized since
* an irq handler gets installed
*/
udelay (20);
set_timer (0);
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
WATCHDOG_RESET ();
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
WATCHDOG_RESET ();
puts ("Net: ");
#endif
eth_initialize (bd);
#endif
/* Initialization complete - start the monitor */
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
WATCHDOG_RESET ();
main_loop ();
}
/* NOTREACHED - no way out of command loop except booting */
}
unsigned long flash_init (void)
{
unsigned long size = 0;
int i;
#define BANK_BASE(i) (((phys_addr_t [CFI_MAX_FLASH_BANKS])CONFIG_SYS_FLASH_BANKS_LIST)[i])//获得每个bank基地址
/* Init: no FLASHes known */
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
if (!flash_detect_legacy (BANK_BASE(i), i)) //此flash是否遵从CFI协议
flash_get_size (BANK_BASE(i), i);
size += flash_info[i].size; //获得flash大小
/* Monitor protection ON by default */
#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE) //将所有的uboot代码区域写保护
flash_protect (FLAG_PROTECT_SET,
CONFIG_SYS_MONITOR_BASE,
CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
flash_get_info(CONFIG_SYS_MONITOR_BASE));
#endif
/* Environment protection ON by default */
#ifdef CONFIG_ENV_IS_IN_FLASH
flash_protect (FLAG_PROTECT_SET, //将代码之后的环境变量存储区写保护
CONFIG_ENV_ADDR,
CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
flash_get_info(CONFIG_ENV_ADDR));
#endif
/* Redundant environment protection ON by default */
#ifdef CONFIG_ENV_ADDR_REDUND
flash_protect (FLAG_PROTECT_SET, //在环境变量之后的保留区域写保护
CONFIG_ENV_ADDR_REDUND,
CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1,
flash_get_info(CONFIG_ENV_ADDR_REDUND));
#endif
#if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
debug("autoprotecting from %08x to %08x\n",
apl[i].start, apl[i].start + apl[i].size - 1);
flash_protect (FLAG_PROTECT_SET,
apl[i].start,
apl[i].start + apl[i].size - 1,
flash_get_info(apl[i].start));
}
#endif
#ifdef CONFIG_FLASH_CFI_MTD
cfi_mtd_init();
#endif
return (size);
}
/*
* The following code cannot be run from FLASH!
*
*/
ulong flash_get_size (phys_addr_t base, int banknum)
{
flash_info_t *info = &flash_info[banknum];
int i, j;
flash_sect_t sect_cnt; //块个数
phys_addr_t sector;
unsigned long tmp;
int size_ratio;
uchar num_erase_regions;
int erase_region_size; //擦除的块大小
int erase_region_count; //擦除的块
struct cfi_qry qry;
memset(&qry, 0, sizeof(qry));
info->ext_addr = 0;
info->cfi_version = 0;
#ifdef CONFIG_SYS_FLASH_PROTECTION
info->legacy_unlock = 0;
#endif
info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE); //获得flash基地址0xfff0000
if (flash_detect_cfi (info, &qry)) { //端口配置正确并且找到"QRY"标志,符合CFI端,并且读出相应信息
info->vendor = le16_to_cpu(qry.p_id); //生产厂商指令集
info->ext_addr = le16_to_cpu(qry.p_adr); //原始拓展表地址
num_erase_regions = qry.num_erase_regions;
if (info->ext_addr) { //读取CFI接口版本
info->cfi_version = (ushort) flash_read_uchar (info,
info->ext_addr + 3) << 8;
info->cfi_version |= (ushort) flash_read_uchar (info,
info->ext_addr + 4);
}
#ifdef DEBUG
flash_printqry (&qry);
#endif
switch (info->vendor) { //按厂商选择相应算法
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
cmdset_intel_init(info, &qry);
break;
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
cmdset_amd_init(info, &qry); //软件复位
break;
default:
printf("CFI: Unknown command set 0x%x\n",
info->vendor);
/*
* Unfortunately, this means we don't know how
* to get the chip back to Read mode. Might
* as well try an Intel-style reset...
*/
flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
return 0;
}
/* Do manufacturer-specific fixups */
switch (info->manufacturer_id) {
case 0x0001:
flash_fixup_amd(info, &qry); //查看厂商flash是否几何反转
break;
case 0x001f:
flash_fixup_atmel(info, &qry);
break;
case 0x0020:
flash_fixup_stm(info, &qry);
break;
}
debug ("manufacturer is %d\n", info->vendor);
debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
debug ("device id is 0x%x\n", info->device_id);
debug ("device id2 is 0x%x\n", info->device_id2);
debug ("cfi version is 0x%04x\n", info->cfi_version);
size_ratio = info->portwidth / info->chipwidth; //flash由几片构成
/* if the chip is x8/x16 reduce the ratio by half */
if ((info->interface == FLASH_CFI_X8X16) //使用x8模式
&& (info->chipwidth == FLASH_CFI_BY8)) {
size_ratio >>= 1;
}
debug ("size_ratio %d port %d bits chip %d bits\n",
size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
debug ("found %d erase regions\n", num_erase_regions);
sect_cnt = 0;
sector = base;
for (i = 0; i < num_erase_regions; i++) { //获得该片flash最大可用block数
if (i > NUM_ERASE_REGIONS) {
printf ("%d erase regions found, only %d used\n",
num_erase_regions, NUM_ERASE_REGIONS);
break;
}
tmp = le32_to_cpu(qry.erase_region_info[i]);
debug("erase region %u: 0x%08lx\n", i, tmp);
erase_region_count = (tmp & 0xffff) + 1;
tmp >>= 16;
erase_region_size =
(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;//获得块大小
debug ("erase_region_count = %d erase_region_size = %d\n",
erase_region_count, erase_region_size);
for (j = 0; j < erase_region_count; j++) {
if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { //所有的block 数,为4block
printf("ERROR: too many flash sectors\n");
break;
}
info->start[sect_cnt] =
(ulong)map_physmem(sector,
info->portwidth,
MAP_NOCACHE);
sector += (erase_region_size * size_ratio);//该bank中所有sector
/*
* Only read protection status from
* supported devices (intel...)
*/
switch (info->vendor) { //按厂商查看保护快
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
info->protect[sect_cnt] =
flash_isset (info, sect_cnt,
FLASH_OFFSET_PROTECT,
FLASH_STATUS_PROTECT);
break;
default: //AMD默认不写保护
/* default: not protected */
info->protect[sect_cnt] = 0;
}
sect_cnt++;
}
}
info->sector_count = sect_cnt;
info->size = 1 << qry.dev_size; //获得该chip的大小
/* multiply the size by the number of chips */
info->size *= size_ratio; //计算该bank容量
info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); //获得最大写buffer
tmp = 1 << qry.block_erase_timeout_typ;
info->erase_blk_tout = tmp *
(1 << qry.block_erase_timeout_max);//块擦除时间
tmp = (1 << qry.buf_write_timeout_typ) *
(1 << qry.buf_write_timeout_max);//写buffer时间
/* round up when converting to ms */
info->buffer_write_tout = (tmp + 999) / 1000;
tmp = (1 << qry.word_write_timeout_typ) *
(1 << qry.word_write_timeout_max);
/* round up when converting to ms */
info->write_tout = (tmp + 999) / 1000;
info->flash_id = FLASH_MAN_CFI;
if ((info->interface == FLASH_CFI_X8X16) &&
(info->chipwidth == FLASH_CFI_BY8)) {
/* XXX - Need to test on x8/x16 in parallel. */
info->portwidth >>= 1;
}
flash_write_cmd (info, 0, 0, info->cmd_reset);//复位
}
return (info->size);
}
块擦写函数很简单
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
int rcode = 0;
int prot;
flash_sect_t sect;
if (info->flash_id != FLASH_MAN_CFI) { //未知ID
puts ("Can't erase unknown flash type - aborted\n");
return 1;
}
if ((s_first < 0) || (s_first > s_last)) {
puts ("- no sectors to erase\n");
return 1;
}
prot = 0;
for (sect = s_first; sect <= s_last; ++sect) { //查找保护的块
if (info->protect[sect]) {
prot++;
}
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!\n",
prot);
} else if (flash_verbose) {
putc ('\n');
}
for (sect = s_first; sect <= s_last; sect++) { 对没有保护的块按不同的厂商选择算法
if (info->protect[sect] == 0) { /* not protected */
switch (info->vendor) {
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
flash_write_cmd (info, sect, 0,
FLASH_CMD_CLEAR_STATUS);
flash_write_cmd (info, sect, 0,
FLASH_CMD_BLOCK_ERASE);
flash_write_cmd (info, sect, 0,
FLASH_CMD_ERASE_CONFIRM);
break;
case CFI_CMDSET_AMD_STANDARD: //我们使用的是这个算法
case CFI_CMDSET_AMD_EXTENDED:
flash_unlock_seq (info, sect); //写入指令
flash_write_cmd (info, sect,
info->addr_unlock1,
AMD_CMD_ERASE_START);
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect, 0,
AMD_CMD_ERASE_SECTOR);
break;
#ifdef CONFIG_FLASH_CFI_LEGACY //如果定义了后续算法,使用默认算法
case CFI_CMDSET_AMD_LEGACY:
flash_unlock_seq (info, 0);
flash_write_cmd (info, 0, info->addr_unlock1,
AMD_CMD_ERASE_START);
flash_unlock_seq (info, 0);
flash_write_cmd (info, sect, 0,
AMD_CMD_ERASE_SECTOR);
break;
#endif
default:
debug ("Unkown flash vendor %d\n",
info->vendor);
break;
}
if (flash_full_status_check //检测是否已经擦除
(info, sect, info->erase_blk_tout, "erase")) {
rcode = 1;
} else if (flash_verbose)
putc ('.');
}
}
if (flash_verbose)
puts (" done\n");
return rcode;
}