Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532211
  • 博文数量: 101
  • 博客积分: 1889
  • 博客等级: 上尉
  • 技术积分: 906
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-14 16:22
文章分类

全部博文(101)

文章存档

2012年(11)

2011年(19)

2010年(59)

2009年(12)

我的朋友

分类: LINUX

2010-05-28 15:37:13

书接上回

/*-----------------------------------------------------------------------
 * Copy memory to flash.
 * Make sure all target addresses are within Flash bounds,
 * and no protected sectors are hit.
 * Returns:
 * ERR_OK 0 - OK
 * ERR_TIMOUT 1 - write timeout
 * ERR_NOT_ERASED 2 - Flash not erased
 * ERR_PROTECTED 4 - target range includes protected sectors
 * ERR_INVAL 8 - target address not in Flash memory
 * ERR_ALIGN 16 - target address not aligned on boundary
 * (only some targets require alignment)
 */

int
flash_write (char *src, ulong addr, ulong cnt)
{
    int i;
    ulong end = addr + cnt - 1;

//环境参数的结束地址?在flash里的结束地址

    flash_info_t *info_first = addr2info (addr);
//这是在做什么呢?下面有解释,他返回了这个地址对应的flash_info结构

    flash_info_t *info_last = addr2info (end );
//同样,返回了对应flash_info结构,这两个flash_info可能不同,但是这里肯定相同。

    flash_info_t *info;
    if (cnt == 0) {
//不写也可以认为是成功的写操作

        return (ERR_OK);
    }

    if (!info_first || !info_last) {
// 出错判断

        return (ERR_INVAL);
    }
    for (info = info_first; info <= info_last; ++info) {

// 这个多余了,只有一个flash_info结构


        ulong b_end = info->start[0] + info->size; /* bank end addr 结束地址2M */
        short s_end = info->sector_count - 1;
//扇区数量


        for (i=0; i<info->sector_count; ++i) {
//扫描所有扇区


            ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];

            if ((end >= info->start[i]) && (addr < e_addr) &&
                (info->protect[i] != 0) ) {
                return (ERR_PROTECTED);
            }
        }
    }

    /* finally write data to flash */
    for (info = info_first; info <= info_last && cnt>0; ++info) {
//只有一遍

        ulong len;

        len = info->start[0] + info->size - addr;
        if (len > cnt)
            len = cnt;
        if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
//这里是真正的写操作

            return (i);
        }
        cnt -= len;
        addr += len;
        src += len;
    }
    return (ERR_OK);
}
/*
addr2info 他根据给定的地址,确认自己所在那个bank,然后返回这个bank的flash_info结构。*/

flash_info_t *
addr2info (ulong addr)
{
    flash_info_t *info;
    int i;

    for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
//扫描所有bank


        if (info->flash_id != FLASH_UNKNOWN &&
            addr >= info->start[0] &&
            
/* WARNING - The '- 1' is needed if the flash
             * is at the end of the address space, since
             * info->start[0] + info->size wraps back to 0.
             * Please don't change this unless you understand this.
             */

            addr <= info->start[0] + info->size - 1) {
            return (info);
        }
    }

    return (NULL);
}

//希望这个函数返回0

write_buff(info, (uchar *)src, addr, len)
write_buff(info, (uchar *)0x0xxxxx, 0xf0000, 0x10000)

/*-----------------------------------------------------------------------
 * Copy memory to flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
 */

int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
{
    ulong wp;
    ulong cp;
    int aln;
    cfiword_t cword;
    int i, rc;

    /* get lower aligned address */
    /* get lower aligned address */
    wp = (addr & ~(info->portwidth - 1));

//不要地址的最x(0,1,2)地位,分别对应8,16,32bit数据的nor

 /* handle unaligned start 处理没有对齐的部分*/
    if ((aln = addr - wp) != 0) {
        cword.l = 0;
        cp = wp;
        for (i = 0; i < aln; ++i, ++cp)
            flash_add_byte (info, &cword, (*(uchar *) cp));

        for (; (i < info->portwidth) && (cnt > 0); i++) {
            flash_add_byte (info, &cword, *src++);
            cnt--;
            cp++;
        }
        for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
            flash_add_byte (info, &cword, (*(uchar *) cp));
        if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
            return rc;
        wp = cp;
    }

    /* handle the aligned part */
    while (cnt >= info->portwidth) {
//处理对齐的部分,从这里分析 呵呵。

        cword.l = 0;
        for (i = 0; i < info->portwidth; i++) {
// 我的是16位的,所以循环了两次

            flash_add_byte (info, &cword, *src++);
//下边有解释


        }
        if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
            return rc;
        wp += info->portwidth;
        cnt -= info->portwidth;
    }
    if (cnt == 0) {
        return (0);
    }
   /* handle unaligned tail bytes */
    cword.l = 0;
    for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
        flash_add_byte (info, &cword, *src++);
        --cnt;
    }
    for (; i < info->portwidth; ++i, ++cp) {
        flash_add_byte (info, &cword, (*(uchar *) cp));
    }

    return flash_write_cfiword (info, wp, cword);
}

//将内存中2字节的数据组合到一起。小端模式。


static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
{
    unsigned short w;
    unsigned int l;
    unsigned long long ll;

    switch (info->portwidth) {
    case FLASH_CFI_8BIT:
        cword->c = c;
        break;
    case FLASH_CFI_16BIT:
//这里,


        w = c;
        w <<= 8;
        cword->w = (cword->w >> 8) | w;

//这就是小端的方式,后来的那个8bit 放到了这个字的高 byte,把这个16BIT 的数据组合到一起

        break;
    case FLASH_CFI_32BIT:
        l = c;
        l <<= 24;
        cword->l = (cword->l >> 8) | l;
        break;
    case FLASH_CFI_64BIT:
        ll = c;
        ll <<= 56;
        cword->ll = (cword->ll >> 8) | ll;
        break;
    }
}

//wp是待写入的地址,cword是要写入的数据

flash_write_cfiword (info, wp, cword)

static int flash_write_cfiword (flash_info_t * info, ulong dest,
                cfiword_t cword)
{
    cfiptr_t ctladdr;
    cfiptr_t cptr;
    int flag;

    ctladdr.cp = flash_make_addr (info, 0, 0);
    cptr.cp = (uchar *) dest;

    /* Check if Flash is (sufficiently) erased */
    switch (info->portwidth) {
    case FLASH_CFI_8BIT:
        flag = ((cptr.cp[0] & cword.c) == cword.c);
        break;
    case FLASH_CFI_16BIT:
        flag = ((cptr.wp[0] & cword.w) == cword.w);
//这里,如果刚才的擦除操作成功的话,给定地址处应该为0xffff,这里flag应该为1

        break;
    case FLASH_CFI_32BIT:
        flag = ((cptr.lp[0] & cword.l) == cword.l);
        break;
    case FLASH_CFI_64BIT:
        flag = ((cptr.llp[0] & cword.ll) == cword.ll);
        break;
    default:
        return 2;
    }
    if (!flag)
        return 2;

    /* Disable interrupts which might cause a timeout here */
    flag = disable_interrupts ();

    switch (info->vendor) {
    case CFI_CMDSET_INTEL_EXTENDED:
    case CFI_CMDSET_INTEL_STANDARD:
        flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
        flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
        break;
    case CFI_CMDSET_AMD_EXTENDED:
    case CFI_CMDSET_AMD_STANDARD:
        flash_unlock_seq (info, 0);
        flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
        break;
    default:
//我为sst39vf1601加的写命令序列


        flash_write_cmd (info, 0, 0x5555, 0xaa);
        flash_write_cmd (info, 0, 0x2aaa, 0x55);
        flash_write_cmd (info, 0, 0x5555, 0xa0);
    }

    switch (info->portwidth) {
    case FLASH_CFI_8BIT:
        cptr.cp[0] = cword.c;
        break;
    case FLASH_CFI_16BIT:
        cptr.wp[0] = cword.w;
//到了这里才真正把数据写到数据线上


        break;
    case FLASH_CFI_32BIT:
        cptr.lp[0] = cword.l;
        break;
    case FLASH_CFI_64BIT:
        cptr.llp[0] = cword.ll;
        break;
    }
    /* re-enable interrupts if necessary */
    if (flag)
        enable_interrupts ();

    return flash_full_status_check (info, find_sector (info, dest),
//这一步检查写入操作的成功吗?这个函数上面已经作了修改了

                    info->write_tout, "write");
//注意这里的info->write_tout初始化的时候正确不正确,不然可有你好看的


}
/*
到了这里,写入操作完毕。
上面的所有操作都依赖正确的初始化配置,下面分析下flash的初始化过程
这个函数填写flash_info[i].flash_id,获取flash的大小,然后把需要保护的区间,软件保护起来。而flash_get_size完成了大部分初始化工作
*/

static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];/* FLASH chips info */
unsigned long flash_init (void)
{
    unsigned long size = 0;
    int i;

/* Init: no FLASHes known */
    for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
        flash_info[i].flash_id = SST_ID_xF1601; 填写flash_id
        size += flash_info[i].size = flash_get_size (bank_base[i], i);
//获取nor容量


        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
            printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
                i, flash_info[i].size, flash_info[i].size << 20);
        }
    }

    /* Monitor protection ON by default 这里对uboot所在的扇区加锁*/
    flash_protect (FLAG_PROTECT_SET, CFG_MONITOR_BASE,
               CFG_MONITOR_BASE + monitor_flash_len - 1,
               flash_get_info(CFG_MONITOR_BASE));

    /* Environment protection ON by default 这里对存储 环境参数 的扇区加锁*/
    flash_protect (FLAG_PROTECT_SET, CFG_ENV_ADDR,
               CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
               flash_get_info(CFG_ENV_ADDR));
    return (size);
}
//主要分析下flash_get_size这个函数

//现看看bank_base[0]是什么

static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST;
#define CFG_FLASH_BANKS_LIST { CFG_FLASH_BASE }=0x00000000
//就是bank_base[1] = {0x00000000};所以


flash_get_size (0x00000000,0)
/*The following code cannot be run from FLASH!*/
ulong flash_get_size (ulong base, int banknum)
{
    flash_info_t *info = &flash_info[banknum];
    int i, j;
    flash_sect_t sect_cnt;
    unsigned long sector;
    unsigned long tmp;
    int size_ratio;
    uchar num_erase_regions;
    int erase_region_size;
    int erase_region_count;

    info->start[0] = base;

    if (flash_detect_cfi (info)) {

//首先探测这个nor是不是cfi接口兼容的。

        debug ("pass flash_detect_cfi()\n");
        info->vendor = flash_read_ushort (info, 0, 0);

//填充flash_info.vendor 这个vendor是0x00bf,但是在这里读错了,

 
//因为他返回的是0x4bbf,不是0xbf

        info->vendor = CFI_SST_1601_LZD;

//所以我人为的加了下面的语句,呵呵。可能是读的太快了吧,不管了。


        switch (info->vendor) {
            case CFI_SST_1601_LZD:
//这个是我加的,CFI_SST_1601_LZD = 0x00bf

            default:
                info->cmd_reset = SST_FLASH_CMD_RESET;
//填充flash_info.cmd_reset,设置复位命令

                break;
        }
        debug ("manufacturer is %x\n", info->vendor);
        size_ratio = info->portwidth / info->chipwidth;
        /* if the chip is x8/x16 reduce the ratio by half */
        if ((info->interface == FLASH_CFI_X8X16)
//这里不满足条件


            && (info->chipwidth == FLASH_CFI_BY8)) {
            size_ratio >>= 1;
        }
        num_erase_regions = flash_read_uchar (info, FLASH_OFFSET_NUM_ERASE_REGIONS);
        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;
            erase_region_size = 0xffff+1;
            erase_region_count = 32;
            debug ("erase_region_count = %d erase_region_size = %d\n",
                erase_region_count, erase_region_size);
            for (j = 0; j < erase_region_count; j++) {

//这里完成了各个扇区地址的确定

                info->start[sect_cnt] = sector;
                sector += (erase_region_size * size_ratio);

                info->protect[sect_cnt] = 0;
//起初没有任何保护


                sect_cnt++;
            }
         info->sector_count = sect_cnt;
//确定扇区的数量

        /* multiply the size by the number of chips */
        info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
//确定大小,2^15=2M byte


        info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
//不支持


        tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
        info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
debug ("info->erase_blk_tout:%d\n", info->erase_blk_tout);

        tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) *
            (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT));
        info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
debug ("info->buffer_write_tout:%d\n", info->buffer_write_tout);

        tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) *
              (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT));
        info->write_tout = ~0;

//这里要把得到的us变成ms,应该是1ms了,因为datasheet上说最大25us。

debug ("info->write_tout:%d\n", info->write_tout);

// 但是我改成了~0,因为这个参数让我写不成功,所以我增加了timeout

        info->flash_id = FLASH_MAN_CFI;
        if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) {
            info->portwidth >>= 1; /* XXX - Need to test on x8/x16 in parallel. */
        }
    }
    flash_write_cmd (info, 0, 0, info->cmd_reset);
//这里必须要复位一下,回到read 模式,否则就处在cfi模式里,出不来了。150+70ns就ok。

    debug ("info->size : %d\n", info->size);
    return (info->size);
}
//到了这里就ok了。


//这个函数将进入cfi的QRY模式,并完成chipwidth和portwidth的设置,都是2,返回1

static int flash_detect_cfi (flash_info_t * info)
{
    debug ("flash detect cfi\n");

    for (info->portwidth = CFG_FLASH_CFI_WIDTH;
         info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
        for (info->chipwidth = FLASH_CFI_BY8;
             info->chipwidth <= info->portwidth;
             info->chipwidth <<= 1) {
            flash_write_cmd (info, 0, 0x5555, 0xaa);
//进入cfi的QRY模式


            flash_write_cmd (info, 0, 0x2aaa, 0x55);
            flash_write_cmd (info, 0, 0x5555, 0x98);
            if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
                && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
                && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
                info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
                debug ("device interface is %d\n",
                       info->interface);
                debug ("found port %d chip %d ",
                       info->portwidth, info->chipwidth);
                debug ("port %d bits chip %d bits\n",
                       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
                       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
                return 1;
            }
        }
    }
    debug ("not found\n");
    return 0;
}
/*
下面我们来看看这个神秘的0xxxxx地址是怎么确定的,可以猜测到,他是个内存地址,而且,这个地址里有环境变量的值,
而且这个环境变量的值是从0xf0000这块flash里拷贝到内存的。:-)
*/

//在board.c里有下面的初始化指针数组

init_fnc_t *init_sequence[] = {
    cpu_init, /* basic cpu dependent setup */
    board_init, /* basic board dependent setup */
    interrupt_init, /* set up exceptions */
    env_init,
//就是这个函数负责环境参数的初始化

//......

/*
在common/env_flash.c中
不要忘了这个 env_t *env_ptr = (env_t *)CFG_ENV_ADDR 哦!
CFG_ENV_ADDR 这个预定义 确定了我们的环境变量在nor flash的什么位置。
*/

int env_init(void)
{
    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
//如果这段数据通过了crc校验,就设置下面两个变量。

        gd->env_addr = (ulong)&(env_ptr->data);
//这个全局量确定了环境数据的地址

        gd->env_valid = 1;
//这个量指示,用norflash 里的环境变量数据,程序当然会运行到这里。

        return(0);
    }
    gd->env_addr = (ulong)&default_environment[0];

//否则就用默认的环境参数

    gd->env_valid = 0;
//相反

    return (0);
}

typedef struct environment_s {
    unsigned long crc; /* CRC32 over data bytes */
//前四个字节是crc校验的值

    unsigned char data[ENV_SIZE]; /* Environment data */
//这里是环境变量字符串

} env_t;

# define ENV_HEADER_SIZE (sizeof(unsigned long))
#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)

//出于好奇,看看 default_environment是什么。

uchar default_environment[] = {
#ifdef CONFIG_BOOTARGS
    "bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND
    "bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
#ifdef CONFIG_RAMBOOTCOMMAND
    "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
#endif
#ifdef CONFIG_NFSBOOTCOMMAND
    "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
    "baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
#endif
#ifdef CONFIG_LOADS_ECHO
    "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
#endif
#ifdef CONFIG_ETHADDR
    "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
#endif
#ifdef CONFIG_ETH1ADDR
    "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
#endif
#ifdef CONFIG_ETH2ADDR
    "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
#endif
#ifdef CONFIG_ETH3ADDR
    "eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
#endif
#ifdef CONFIG_IPADDR
    "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
#endif
#ifdef CONFIG_SERVERIP
    "serverip=" MK_STR(CONFIG_SERVERIP) "\0"
#endif
#ifdef CFG_AUTOLOAD
    "autoload=" CFG_AUTOLOAD "\0"
#endif
#ifdef CONFIG_PREBOOT
    "preboot=" CONFIG_PREBOOT "\0"
#endif
#ifdef CONFIG_ROOTPATH
    "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
#endif
#ifdef CONFIG_GATEWAYIP
    "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
#endif
#ifdef CONFIG_NETMASK
    "netmask=" MK_STR(CONFIG_NETMASK) "\0"
#endif
#ifdef CONFIG_HOSTNAME
    "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
#endif
#ifdef CONFIG_BOOTFILE
    "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
#endif
#ifdef CONFIG_LOADADDR
    "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
#endif
#ifdef CONFIG_CLOCKS_IN_MHZ
    "clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
    "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
#endif
#ifdef CONFIG_EXTRA_ENV_SETTINGS
    CONFIG_EXTRA_ENV_SETTINGS
#endif
    "\0"
};
/*
符合道理,呵呵。现在
gd->env_addr = (ulong)&(env_ptr->data) = 0xf0000 + 4
gd->env_valid = 1;
显然,环境变量如果只在flash中,setenv这样的命令,将不能工作,因为setenv只是在内存中改变环境参数的值,
printenv可以查看到改变的值。*/

//在下面的函数中

void env_relocate (void)
{
    /*We must allocate a buffer for the environment */
    env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
//首先分配内存,看到希望了,^_^

    /*After relocation to RAM, we can always use the "memory" functions */
    env_get_char = env_get_char_memory;

    if (gd->env_valid == 0) {
//经过刚才env_init的初始化,gd->env_valid 这个值是1

        if (sizeof(default_environment) > ENV_SIZE)
        {
            puts ("*** Error - default environment is too large\n\n");
            return;
        }
        memset (env_ptr, 0, sizeof(env_t));
        memcpy (env_ptr->data,
            default_environment,
            sizeof(default_environment));
        env_crc_update ();
        gd->env_valid = 1;
    }
    else {
//所以到了这里


        env_relocate_spec ();
    }
    gd->env_addr = (ulong)&(env_ptr->data);
}

void env_relocate_spec (void)
{
    memcpy (env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
}

memcpy (env_ptr, 0xf0000, 0x10000);
//上面分析0xxxxx地址是什么的过程是一个反推过程。

 

完!

阅读(2268) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~