您的位置:首页 > 其它

uboot之Nor flash操作完全解析

2012-04-20 12:31 260 查看
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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: