uboot之Nor flash操作完全解析

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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值