U-BOOT/Board/flash.c 分析

 

#include <common.h>

ulong myflush (void);

//请仔细阅读Am29LV400手册

//PHYS_FLASH_SIZE=512KB 定义咋include/configs/embendsky.h中
#define FLASH_BANK_SIZE PHYS_FLASH_SIZE

//根据Am29LV400手册可知 有11个sect。最大sect的大小为64KB
#define MAIN_SECT_SIZE  0x10000 /* 64 KB */

//CFG_MAX_FLASH_BANKS=1 定义咋include/configs/embendsky.h中
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];

//一下所有命令字节的定义 都可以从Am29LV400手册中获得
#define CMD_READ_ARRAY  0x000000F0
#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

//#define PHYS_FLASH_1  0x00000000 /* Flash Bank #1 */
//#define CFG_FLASH_BASE PHYS_FLASH_1 定义在include/configs/embendsky.h中
#define MEM_FLASH_ADDR1  (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555 << 1)))
#define MEM_FLASH_ADDR2  (*(volatile u16 *)(CFG_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)
{
 int i, j;
 ulong size = 0;
//因为我们只用一个nor flash 所以这里的 i=1
 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
  ulong flashbase = 0;
//文件include/configs/embendsky.h中:#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
  flash_info[i].flash_id =
#if defined(CONFIG_AMD_LV400)
//include/flash.h中对flash的MANUFACT,VENDMASK,TYPEMASK有定义,主要是flash的ID
   (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数据结构定义在include/flash.h中,主要存储,记录flash的一些基本信息
   flash_info[i].size = FLASH_BANK_SIZE;
  flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
//memset函数 作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法
//下句意思是:把此flash 清零
  memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
//下面是确定flash的基址
  if (i == 0)
#define PHYS_FLASH_1  0x00000000 /* Flash Bank #1 */
   flashbase = PHYS_FLASH_1;
  else
   panic ("configured too many flash banks!\n");
//  for(j=0;    j<11;                           j++)
//Am29LV400作为启动flash时有两种方式:top boot block sector和bottom boot block sector
//具体的启动方式与具体的硬件连接有关,此文中我们采用的是bottom boot block sector

//总的来说 下面的for循环就是 、确定各个sector的开始与结束地址,详见Am29LV400手册
//因为前三个sector的大小不一致分别是16KB,8KB,8KB,64KB,64KB,64KB,64KB,64KB,64KB,64KB,64KB,
  for (j = 0; j < flash_info[i].sector_count; j++) {
   if (j <= 3) {
    /* 1st one is 16 KB */
    if (j == 0) {
     flash_info[i].start[j] =
      flashbase + 0;
    }

    /* 2nd and 3rd are both 8 KB */
    if ((j == 1) || (j == 2)) {
     flash_info[i].start[j] =
      flashbase + 0x4000 + (j -
              1) *
      0x2000;//8KB
    }

    /* 4th 32 KB */
    if (j == 3) {
     flash_info[i].start[j] =
      flashbase + 0x8000;
    }
   } else {
    flash_info[i].start[j] =
     flashbase + (j - 3) * MAIN_SECT_SIZE;
   }
  }
  size += flash_info[i].size;
 }
//flash_protect函数,
 flash_protect (FLAG_PROTECT_SET,
         CFG_FLASH_BASE,
         CFG_FLASH_BASE + monitor_flash_len - 1,
         &flash_info[0]);

 flash_protect (FLAG_PROTECT_SET,
         CFG_ENV_ADDR,
         CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
//返回flash的存储大小
 return size;
}

/*-----------------------------------------------------------------------
 */
 //打印flash的必要信息
void flash_print_info (flash_info_t * info)
{
 int i;
//判断flash的型号
 switch (info->flash_id & FLASH_VENDMASK) {
 case (AMD_MANUFACT & FLASH_VENDMASK):
  printf ("AMD: ");
  break;
 default:
  printf ("Unknown Vendor ");
  break;
 }
//判断flash的存储大小
 switch (info->flash_id & FLASH_TYPEMASK) {
 case (AMD_ID_LV400B & FLASH_TYPEMASK):
  printf ("1x Amd29LV400BB (4Mbit)\n");
  break;
 case (AMD_ID_LV800B & FLASH_TYPEMASK):
  printf ("1x Amd29LV800BB (8Mbit)\n");
  break;
 default:
  printf ("Unknown Chip Type\n");
  goto Done;
  break;
 }
//打印flash的bit位数和sect的个数
 printf ("  Size: %ld MB in %d Sectors\n",
  info->size >> 20, info->sector_count);
//打印各个sect的起始地址
 printf ("  Sector Start Addresses:");
 for (i = 0; i < info->sector_count; i++) {
  if ((i % 5) == 0) {
   printf ("\n   ");
  }
  printf (" %08lX%s", info->start[i],
   info->protect[i] ? " (RO)" : "     ");
 }
 printf ("\n");

      Done:;
}

/*-----------------------------------------------------------------------
 */
//flash的擦出操作
//    存储flash信息   擦出开始  擦除结束
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
 ushort result;
 int iflag, cflag, prot, sect;
 int rc = ERR_OK;
 int chip;

 /* first look for protection bits */
//flash擦出前,要判断flash的状态,一边进一步的操作
 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;
 }

 prot = 0;
//下面的for循环就是查找s_first和 s_last之间被保护的sect数
 for (sect = s_first; sect <= s_last; ++sect) {
  if (info->protect[sect]) {
   prot++;
  }
 }
//如果port>0即 又被保护的sect,那是不能被擦除的返回ERR_PROTECTED错误
 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.
  */
//函数icache_status ()在cpu/ARM920T/cpu.c中
//cflag中保存了当前chche的状态
 cflag = icache_status ();
//函数icache_disable在cpu/ARM920T/cpu.c中
//使能cache
 icache_disable ();
//函数disable_interrupts ()在cpu/ARM920T/cpu.c中
//iflag保存了禁止interrupt的返回结果
 iflag = disable_interrupts ();

 /* Start erase on unprotected sectors */
 for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
//打印要擦除的sect
  printf ("Erasing sector %2d ... ", sect);

  /* arm simple, non interrupt dependent timer */
//把现在的时间保存,具体的保存位置在函数lastdec = READ_TIMER();
  reset_timer_masked ();

  if (info->protect[sect] == 0) { /* not protected */
//addr指向此sect的起始地址
   vu_short *addr = (vu_short *) (info->start[sect]);

   MEM_FLASH_ADDR1 = CMD_UNLOCK1;
   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-while循环就是准备等待flash ready
   do {
    result = *addr;

    /* check timeout */
//get_timer_masked ()返回超时时间片,并判断是否超过我们设定的超时值
    if (get_timer_masked () >
        CFG_FLASH_ERASE_TOUT) {
     MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
     chip = TMO; //flash超时
     break;
    }

    if (!chip
        && (result & 0xFFFF) & BIT_ERASE_DONE)
     chip = READY; //flash 已准备好

    if (!chip
        && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
     chip = ERR; //flash 编程错误

   } 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 ();
//使能flash
 if (cflag)
  icache_enable ();
//返回flash的erase结果
 return rc;
}

/*-----------------------------------------------------------------------
 * Copy memory to flash
 */
//      flash基本信息   写入的地址  数据大小
static int write_hword (flash_info_t * info, ulong dest, ushort data)
{
//
 vu_short *addr = (vu_short *) dest;
 ushort result;
 int rc = ERR_OK;
 int cflag, iflag;
 int chip;

 /*
  * Check if Flash is (sufficiently) erased
  */
 result = *addr;//dest的地址赋值给result
 if ((result & data) != data)
  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 () > CFG_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)
{
 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);
}

注:此falsh.c文件中涉及到的文件有:

include/configs/embendsky.h
include/flash.h
cpu/ARM920T/cpu.c
cpu/ARM920T/S3C2440/interrupt.c

include/common.h


其中include/flash.h中定义了重要数据结构如下所示:

typedef struct {
 ulong size;   /* total bank size in bytes  */
 ushort sector_count;  /* number of erase units  */
 ulong flash_id;  /* combined device & manufacturer code */
 ulong start[CFG_MAX_FLASH_SECT];   /* physical sector start addresses */
 uchar protect[CFG_MAX_FLASH_SECT]; /* sector protection status */
#ifdef CFG_FLASH_CFI
 uchar portwidth;  /* the width of the port  */
 uchar chipwidth;  /* the width of the chip  */
 ushort buffer_size;  /* # of bytes in write buffer  */
 ulong erase_blk_tout;  /* maximum block erase timeout  */
 ulong write_tout;  /* maximum write timeout  */
 ulong buffer_write_tout; /* maximum buffer write timeout  */
 ushort vendor;   /* the primary vendor id  */
 ushort cmd_reset;  /* Vendor specific reset command */
 ushort interface;  /* used for x8/x16 adjustments  */
 ushort legacy_unlock;  /* support Intel legacy (un)locking */
#endif
} flash_info_t;

此数据结构保存了flash的重要信息,在flash的具体操作中都会使用到,另外flash。h中还定了操作flash的必须的操作码与命令吗,标识码。

include/configs/embendsky.h中定义了对于S3c2440的一些配置文件:除了flash,还有其他的:LCD,DM9000,等等,需要用到时再仔细看。

cpu/ARM920T/cpu.c中包含了cache的操作,操作CP15协处理器的函数,CPU的初始化工作。

cpu/ARM920T/S3C2440/interrupt.c中包含了读写芯片的时间,中断的处理中等。

include/common.h定义了素有要用到的函数的原型声明。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值