以u(píng)boot2010.06為例解說norflash工作原理
根據(jù)根目錄makefile文件得知系統(tǒng)從start.S啟動(dòng),在start.S里面看到函數(shù)跳轉(zhuǎn)到start_armboot 里面調(diào)用了flash_init ()初始化,這里我們知道是對(duì)flash進(jìn)行初始化。那么這個(gè)函數(shù)在哪里呢? 在board/samsung/smdk2440/flash.c下。于是我們?cè)谶@個(gè)flash.c文件下分析flash
????????????? 我用的norflash是EN29LV160AB這個(gè)型號(hào),和uboot源碼里有些出入 所以在分析的過程中我們適當(dāng)更改部分配置
先從宏定義開始看
#define FLASH_BANK_SIZE?PHYS_FLASH_SIZE??? //從字面分析 應(yīng)該是定義flashBANK空間? 我們的flash是2M的 所有后面的PHYS_FLASH_SIZE???= 0x20000000
#define MAIN_SECT_SIZE? 0x8000?/*?32 KB */???? //定義了主要的sect(扇區(qū))大小,看EN29LV手冊(cè)? 我們總共有35個(gè)扇區(qū) 31個(gè)大小為32K
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
//其中CONFIG_SYS_MAX_FLASH_BANKS在smdk2410.h里定義#define CONFIG_SYS_MAX_FLASH_SECT?(35)?/* max number of sectors on one chip */
#define CMD_READ_ARRAY??0x000000F0? //下面幾個(gè)宏定義在EN29LV里面都有說明 是常用的命令數(shù)據(jù)
#define CMD_UNLOCK1??0x000000AA
#define CMD_UNLOCK2??0x00000055
#define CMD_ERASE_SETUP??0x00000080
#define CMD_ERASE_CONFIRM?0x00000030
#define CMD_PROGRAM??0x000000A0
#define CMD_UNLOCK_BYPASS?0x00000020
//以下兩個(gè)宏為EN29LV手冊(cè)中提到的命令寫入的地址一個(gè)是0x555 一個(gè)是2AA 至于為什么左移一位,是設(shè)計(jì)時(shí) norflash的地址A0通常接ARM芯片地址的A1為 所以地址左移
#define MEM_FLASH_ADDR1??(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1)))
#define MEM_FLASH_ADDR2??(*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1)))
#define BIT_ERASE_DONE??0x00000080
#define BIT_RDY_MASK??0x00000080
#define BIT_PROGRAM_ERROR?0x00000020
#define BIT_TIMEOUT??0x80000000?/* our flag */
#define READY 1
#define ERR?? 2
#define TMO?? 4
//搞清楚了上面的宏定義 再看下面的幾個(gè)函數(shù)就好理解多了。。。。
ulong flash_init (void)????? //flash初始化函數(shù)
{
?int i, j;
?ulong size = 0;
?for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {?????? //對(duì)BANK區(qū)初始化 一般只用到BANK0 所以這里只循環(huán)一次? 這里是通用寫法
??ulong flashbase = 0;
??flash_info[i].flash_id =???????? //根據(jù)flash型號(hào) 賦予flashid號(hào) 我們也可以自定義
#if defined(CONFIG_AMD_LV400)
???(AMD_MANUFACT & FLASH_VENDMASK) |
???(AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
???(AMD_MANUFACT & FLASH_VENDMASK) |
???(AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
#endif
???flash_info[i].size = FLASH_BANK_SIZE;????????????? //賦值當(dāng)前BANK中flash占用大小? 這里我們的norflash才2M? arm9一個(gè)bank有128M 我們只占用了2M
??flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;???????????????//有多少個(gè)扇區(qū)?前面提到 總共35個(gè)
??memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);??? //受保護(hù)的扇區(qū)
??if (i == 0)
???flashbase = PHYS_FLASH_1;???????????????????????????????? //flash起始地址? = 0x00000000
??else
???panic ("configured too many flash banks!n");
for (j = 0; j < flash_info[i].sector_count; j++)?
{
??? if (j <= 3)?
?? {
??????? /* 1st one is 8 KB */
?????? if (j == 0)?
????? {
???????????? flash_info[i].start[j] = flashbase + 0;?????? //由EN29LV手冊(cè) 第一個(gè)扇區(qū)大小為8K? 起始地址為0x00000000
????? }
????? /* 2nd and 3rd are both 4 KB */
????? if ((j == 1) || (j == 2))?
??? ?{
?????????? flash_info[i].start[j] = flashbase + 0x2000 + (j - 1) * 0x1000;??? //第二個(gè)和第三個(gè)扇區(qū)大小為4K 起始地址緊跟在8K后
?????}
???? /* 4th?16 KB */
???? if (j == 3)?
?? ?{
?????????? flash_info[i].start[j] = flashbase + 0x4000;
??? ?}
?}?
?else?
?{
????? ?flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE;??????//其余31個(gè)扇區(qū)皆為32K
?}
}
size += flash_info[i].size;?????? //獲得整個(gè)flash的大小 2M
?flash_protect (FLAG_PROTECT_SET,
???????? CONFIG_SYS_FLASH_BASE,
???????? CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
???????? &flash_info[0]);
?flash_protect (FLAG_PROTECT_SET,
???????? CONFIG_ENV_ADDR,
???????? CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
?return size;
}
int flash_erase (flash_info_t * info, int s_first, int s_last)??? // flash擦除函數(shù)
{
?ushort result;
?int iflag, cflag, prot, sect;
?int rc = ERR_OK;
?int chip;
?/* first look for protection bits */
?if (info->flash_id == FLASH_UNKNOWN)
??return ERR_UNKNOWN_FLASH_TYPE;
?if ((s_first < 0) || (s_first > s_last)) {
??return ERR_INVAL;
?}
?if ((info->flash_id & FLASH_VENDMASK) !=
???? (AMD_MANUFACT & FLASH_VENDMASK)) {
??return ERR_UNKNOWN_FLASH_VENDOR;
?}????????????????????? //以上都是一些驗(yàn)證信息 flash不對(duì) 提示錯(cuò)誤
?prot = 0;
?for (sect = s_first; sect <= s_last; ++sect) {?????????????? //如果有受保護(hù)扇區(qū) 也擦除不成功
??if (info->protect[sect]) {
???prot++;
??}
?}
?if (prot)
??return ERR_PROTECTED;
?/*
? * Disable interrupts which might cause a timeout
? * here. Remember that our exception vectors are
? * at address 0 in the flash, and we don't want a
? * (ticker) exception to happen while the flash
? * chip is in programming mode.
? */
?cflag = icache_status ();
?icache_disable ();
?iflag = disable_interrupts ();
?/* Start erase on unprotected sectors */
?for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {????? //按扇區(qū)一個(gè)個(gè)擦除
??printf ("Erasing sector %2d ... ", sect);
??/* arm simple, non interrupt dependent timer */
??reset_timer_masked ();
??if (info->protect[sect] == 0) {?/* not protected */
???vu_short *addr = (vu_short *) (info->start[sect]);??????????? //從第一個(gè)扇區(qū)開始擦除
???MEM_FLASH_ADDR1 = CMD_UNLOCK1;????????????????????? //前面提到過 這些EN29LV手冊(cè)里都有提示? 就是往flash里寫命令的格式
???MEM_FLASH_ADDR2 = CMD_UNLOCK2;
???MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
???MEM_FLASH_ADDR1 = CMD_UNLOCK1;
???MEM_FLASH_ADDR2 = CMD_UNLOCK2;
???*addr = CMD_ERASE_CONFIRM;
???/* wait until flash is ready */
???chip = 0;
???do {
????result = *addr;
????/* check timeout */
????if (get_timer_masked () >
??????? CONFIG_SYS_FLASH_ERASE_TOUT) {
?????MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
?????chip = TMO;
?????break;
????}
????if (!chip
??????? && (result & 0xFFFF) & BIT_ERASE_DONE)
?????chip = READY;
????if (!chip
??????? && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
?????chip = ERR;
???} while (!chip);
???MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
???if (chip == ERR) {
????rc = ERR_PROG_ERROR;
????goto outahere;
???}
???if (chip == TMO) {
????rc = ERR_TIMOUT;
????goto outahere;
???}
???printf ("ok.n");
??} else {?/* it was protected */
???printf ("protected!n");
??}
?}
?if (ctrlc ())
??printf ("User Interrupt!n");
????? outahere:
?/* allow flash to settle - wait 10 ms */
?udelay_masked (10000);
?if (iflag)
??enable_interrupts ();
?if (cflag)
??icache_enable ();
?return rc;
}
static int write_hword (flash_info_t * info, ulong dest, ushort data)??? //向flash里寫一個(gè)半字 16bit
{
?vu_short *addr = (vu_short *) dest;???????????????????????? //dest表示flash里的地址
?ushort result;
?int rc = ERR_OK;
?int cflag, iflag;
?int chip;
?/*
? * Check if Flash is (sufficiently) erased
? */
?result = *addr;
?if ((result & data) != data)????????????????? //檢查flash是否擦除 擦除后就全是FFFF了
??return ERR_NOT_ERASED;
?/*
? * Disable interrupts which might cause a timeout
? * here. Remember that our exception vectors are
? * at address 0 in the flash, and we don't want a
? * (ticker) exception to happen while the flash
? * chip is in programming mode.
? */
?cflag = icache_status ();
?icache_disable ();
?iflag = disable_interrupts ();
?MEM_FLASH_ADDR1 = CMD_UNLOCK1;
?MEM_FLASH_ADDR2 = CMD_UNLOCK2;
?MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
?*addr = CMD_PROGRAM;?????????????????????? //手冊(cè)里的寫半字命令
?*addr = data;
?/* arm simple, non interrupt dependent timer */
?reset_timer_masked ();
?/* wait until flash is ready */
?chip = 0;
?do {
??result = *addr;
??/* check timeout */
??if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) {
???chip = ERR | TMO;
???break;
??}
??if (!chip && ((result & 0x80) == (data & 0x80)))
???chip = READY;
??if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) {
???result = *addr;
???if ((result & 0x80) == (data & 0x80))
????chip = READY;
???else
????chip = ERR;
??}
?} while (!chip);
?*addr = CMD_READ_ARRAY;
?if (chip == ERR || *addr != data)
??rc = ERR_PROG_ERROR;
?if (iflag)
??enable_interrupts ();
?if (cflag)
??icache_enable ();
?return rc;
}
/*-----------------------------------------------------------------------
?* Copy memory to flash.
?*/
int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)????????????????? //flash寫?? 會(huì)調(diào)用上面的寫hword命令? 這個(gè)是寫一片
{
?ulong cp, wp;
?int l;
?int i, rc;
?ushort data;
?wp = (addr & ~1);?/* get lower word aligned address */
?/*
? * handle unaligned start bytes
? */
?if ((l = addr - wp) != 0) {
??data = 0;
??for (i = 0, cp = wp; i < l; ++i, ++cp) {
???data = (data >> 8) | (*(uchar *) cp << 8);
??}
??for (; i < 2 && cnt > 0; ++i) {
???data = (data >> 8) | (*src++ << 8);
???--cnt;
???++cp;
??}
??for (; cnt == 0 && i < 2; ++i, ++cp) {
???data = (data >> 8) | (*(uchar *) cp << 8);
??}
??if ((rc = write_hword (info, wp, data)) != 0) {
???return (rc);
??}
??wp += 2;
?}
?/*
? * handle word aligned part
? */
?while (cnt >= 2) {
??data = *((vu_short *) src);
??if ((rc = write_hword (info, wp, data)) != 0) {
???return (rc);
??}
??src += 2;
??wp += 2;
??cnt -= 2;
?}
?if (cnt == 0) {
??return ERR_OK;
?}
?/*
? * handle unaligned tail bytes
? */
?data = 0;
?for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) {
??data = (data >> 8) | (*src++ << 8);
??--cnt;
?}
?for (; i < 2; ++i, ++cp) {
??data = (data >> 8) | (*(uchar *) cp << 8);
?}
?return write_hword (info, wp, data);
}
?