加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

以uboot2010.06为例解说norflash工作原理

发布时间:2020-12-15 18:21:12 所属栏目:百科 来源:网络整理
导读:根据根目录makefile文件得知系统从start.S启动,在start.S里面看到函数跳转到start_armboot 里面调用了flash_init ()初始化,这里我们知道是对flash进行初始化。那么这个函数在哪里呢? 在 board/samsung/smdk2440/flash.c下。于是我们在这个flash.c文件下分

根据根目录makefile文件得知系统从start.S启动,在start.S里面看到函数跳转到start_armboot 里面调用了flash_init ()初始化,这里我们知道是对flash进行初始化。那么这个函数在哪里呢? 在board/samsung/smdk2440/flash.c下。于是我们在这个flash.c文件下分析flash

????????????? 我用的norflash是EN29LV160AB这个型号,和uboot源码里有些出入 所以在分析的过程中我们适当更改部分配置

先从宏定义开始看

#define FLASH_BANK_SIZE?PHYS_FLASH_SIZE??? //从字面分析 应该是定义flashBANK空间? 我们的flash是2M的 所有后面的PHYS_FLASH_SIZE???= 0x20000000

#define MAIN_SECT_SIZE? 0x8000?/*?32 KB */???? //定义了主要的sect(扇区)大小,看EN29LV手册? 我们总共有35个扇区 31个大小为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? //下面几个宏定义在EN29LV里面都有说明 是常用的命令数据
#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

//以下两个宏为EN29LV手册中提到的命令写入的地址一个是0x555 一个是2AA 至于为什么左移一位,是设计时 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

//搞清楚了上面的宏定义 再看下面的几个函数就好理解多了。。。。

ulong flash_init (void)????? //flash初始化函数
{
?int i,j;
?ulong size = 0;

?for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {?????? //对BANK区初始化 一般只用到BANK0 所以这里只循环一次? 这里是通用写法
??ulong flashbase = 0;

??flash_info[i].flash_id =???????? //根据flash型号 赋予flashid号 我们也可以自定义
#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;????????????? //赋值当前BANK中flash占用大小? 这里我们的norflash才2M? arm9一个bank有128M 我们只占用了2M

??flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;???????????????//有多少个扇区?前面提到 总共35个
??memset (flash_info[i].protect,CONFIG_SYS_MAX_FLASH_SECT);??? //受保护的扇区
??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手册 第一个扇区大小为8K? 起始地址为0x00000000
????? }

????? /* 2nd and 3rd are both 4 KB */
????? if ((j == 1) || (j == 2))?

??? ?{
?????????? flash_info[i].start[j] = flashbase + 0x2000 + (j - 1) * 0x1000;??? //第二个和第三个扇区大小为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个扇区皆为32K
?}
}
size += flash_info[i].size;?????? //获得整个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擦除函数

{
?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;
?}????????????????????? //以上都是一些验证信息 flash不对 提示错误

?prot = 0;
?for (sect = s_first; sect <= s_last; ++sect) {?????????????? //如果有受保护扇区 也擦除不成功
??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++) {????? //按扇区一个个擦除
??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]);??????????? //从第一个扇区开始擦除

???MEM_FLASH_ADDR1 = CMD_UNLOCK1;????????????????????? //前面提到过 这些EN29LV手册里都有提示? 就是往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里写一个半字 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;?????????????????????? //手册里的写半字命令
?*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写?? 会调用上面的写hword命令? 这个是写一片
{
?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,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,data); }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读