logogcn

To be a better man 专注于嵌入式开发 ARM LINUX WINCE
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

U-boot之flash初始化完全代码分析

Posted on 2010-12-01 09:17  logogcn  阅读(1047)  评论(0编辑  收藏  举报


一 代码分析

 

1、Board->dave->flash.c

#include <common.h>

#include <asm/hardware.h>

#include "../common/flash.c"

#包含必须的头文件

static ulong flash_get_size (vu_long * addr, flash_info_t * info);

static void flash_get_offsets (ulong base, flash_info_t * info);

#声明两个静态函数

FLASH初始化

unsigned long flash_init (void)

{

#ifdef __DEBUG_START_FROM_SRAM__

    return CFG_DUMMY_FLASH_SIZE;

#如果定义了__DEBUG_START_FROM_SRAM__也就是从ram启动,则返回CFG_DUMMY_FLASH_SIZE

#else

    unsigned long size_b0;

    int i;

    /* Init: no FLASHes known */

    for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {

        flash_info[i].flash_id = FLASH_UNKNOWN;

    }

    #初始标识Flash的bank为FLASH_UNKNOWN

    /* Static FLASH Bank configuration here - FIXME XXX */

    size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);

    #调用flash_get_size函数,获取flash的大小,存入size_b0

    if (flash_info[0].flash_id == FLASH_UNKNOWN) {

        printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",

            size_b0, size_b0<<20);

    }

    #判断Flash是否是列表中所有的,如果没有,打印信息。具体列表在flash_get_size函数中

    /* Setup offsets */

    flash_get_offsets (0, &flash_info[0]);

    #设置起始偏移地址。“0”表示基地址,“&flash_info[0]”bank0的基地址

    /* Monitor protection ON by default */

    (void)flash_protect(FLAG_PROTECT_SET,

                -CFG_MONITOR_LEN,

                0xffffffff,

                &flash_info[0]);

    #flash保护,见flash_protect函数

    flash_info[0].size = size_b0;

    #将size_b0存入flash_info[0]

    return (size_b0);

#endif

}

2、Board->dave->command->flash.c

#include <common.h>

#include <asm/processor.h>

#包含必要的头文件

flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips    */

#定义数组flash_info为flash_info_t类型,该类型的定义见3

static int write_word (flash_info_t *info, ulong dest, ulong data);

#声明静态函数

获取FLASH偏移地址

static void flash_get_offsets (ulong base, flash_info_t *info)

{

    int i;

    short n;

    /* set up sector start address table */

    #设置起始地址表。判断Flash类型,厂商和片名,如果都不符合,则执行else的内容

    if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||

        ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {

        for (i = 0; i < info->sector_count; i++)

        info->start[i] = base + (i * 0x00010000);

    } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {

        /* set sector offsets for bottom boot block type    */

        for (i=0; i<8; ++i) {       /*  8 x 8k boot sectors */

            info->start[i] = base;

            base += 8 << 10;

        }

        while (i < info->sector_count) {    /* 64k regular sectors  */

            info->start[i] = base;

            base += 64 << 10;

            ++i;

        }

    } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {

        /* set sector offsets for top boot block type       */

        base += info->size;

        i = info->sector_count;

        for (n=0; n<8; ++n) {       /*  8 x 8k boot sectors */

            base -= 8 << 10;

            --i;

            info->start[i] = base;

        }

        while (i > 0) {         /* 64k regular sectors  */

            base -= 64 << 10;

            --i;

            info->start[i] = base;

        }

    } else {

        if (info->flash_id & FLASH_BTYPE) {

        /* set sector offsets for bottom boot block type    */

        info->start[0] = base + 0x00000000;

        info->start[1] = base + 0x00004000;

        info->start[2] = base + 0x00006000;

        info->start[3] = base + 0x00008000;

        for (i = 4; i < info->sector_count; i++) {

            info->start[i] = base + (i * 0x00010000) - 0x00030000;

        }

        } else {

        /* set sector offsets for top boot block type       */

        #如果都不是以上的类型,设置物理片段的起始地址

        i = info->sector_count - 1;

        info->start[i--] = base + info->size - 0x00004000;

        info->start[i--] = base + info->size - 0x00006000;

        info->start[i--] = base + info->size - 0x00008000;

        for (; i >= 0; i--) {

            info->start[i] = base + i * 0x00010000;

        }

        }

    }

}

FLASH信息打印输出

void flash_print_info  (flash_info_t *info)

{

    int i;

    int k;

    int size;

    int erased;

    volatile unsigned long *flash;

 

    if (info->flash_id == FLASH_UNKNOWN) {

        printf ("missing or unknown FLASH type\n");

        return;

    }

    switch (info->flash_id & FLASH_VENDMASK) {

    case FLASH_MAN_AMD: printf ("AMD ");        break;

    case FLASH_MAN_FUJ: printf ("FUJITSU ");        break;

    case FLASH_MAN_SST: printf ("SST ");        break;

    case FLASH_MAN_STM: printf ("ST  ");    break;

    default:        printf ("Unknown Vendor "); break;

    }

    switch (info->flash_id & FLASH_TYPEMASK) {

    case FLASH_AM400B:  printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");

                break;

    case FLASH_AM400T:  printf ("AM29LV400T (4 Mbit, top boot sector)\n");

                break;

    case FLASH_AM800B:  printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");

                break;

    case FLASH_AM800T:  printf ("AM29LV800T (8 Mbit, top boot sector)\n");

                break;

    case FLASH_AM160B:  printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");

                break;

    case FLASH_AM160T:  printf ("AM29LV160T (16 Mbit, top boot sector)\n");

                break;

    case FLASH_AM320T:  printf ("AM29LV320T (32 M, top sector)\n");

                break;

    case FLASH_AM320B:  printf ("AM29LV320B (32 M, bottom sector)\n");

                break;

    case FLASH_AMDL322T:    printf ("AM29DL322T (32 M, top sector)\n");

                break;

    case FLASH_AMDL322B:    printf ("AM29DL322B (32 M, bottom sector)\n");

                break;

    case FLASH_AMDL323T:    printf ("AM29DL323T (32 M, top sector)\n");

                break;

    case FLASH_AMDL323B:    printf ("AM29DL323B (32 M, bottom sector)\n");

                break;

    case FLASH_AM640U:  printf ("AM29LV640D (64 M, uniform sector)\n");

                break;

    case FLASH_SST800A: printf ("SST39LF/VF800 (8 Mbit, uniform sector size)\n");

                break;

    case FLASH_SST160A: printf ("SST39LF/VF160 (16 Mbit, uniform sector size)\n");

                break;

    case FLASH_STMW320DT:   printf ("M29W320DT (32 M, top sector)\n");

                break;

    default:        printf ("Unknown Chip Type\n");

                break;

    }

    printf ("  Size: %ld MB in %d Sectors\n",

        info->size >> 20, info->sector_count);

    printf ("  Sector Start Addresses:");

    for (i=0; i<info->sector_count; ++i) {

#ifdef CFG_FLASH_EMPTY_INFO

        /*

         * Check if whole sector is erased

         */

        if (i != (info->sector_count-1))

          size = info->start[i+1] - info->start[i];

        else

          size = info->start[0] + info->size - info->start[i];

        erased = 1;

        flash = (volatile unsigned long *)info->start[i];

        size = size >> 2;        /* divide by 4 for longword access */

        for (k=0; k<size; k++)

          {

            if (*flash++ != 0xffffffff)

              {

            erased = 0;

            break;

              }

          }

 

        if ((i % 5) == 0)

            printf ("\n   ");

        /* print empty and read-only info */

        printf (" %08lX%s%s",

            info->start[i],

            erased ? " E" : "  ",

            info->protect[i] ? "RO " : "   ");

#else

        if ((i % 5) == 0)

            printf ("\n   ");

        printf (" %08lX%s",

            info->start[i],

            info->protect[i] ? " (RO)" : "     ");

#endif

 

    }

    printf ("\n");

    return;

}

获取FLASH大小

static ulong flash_get_size (vu_long *addr, flash_info_t *info)

{

    short i;

    short n;

    CFG_FLASH_WORD_SIZE value;

    ulong base = (ulong)addr;

    volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)addr;

#CFG_FLASH_WORD_SIZE等于unsign short在B2.h中定义

 

    debug("[%s, %d] Entering ...\n", __FUNCTION__, __LINE__);

    /* Write auto select command: read Manufacturer ID */

    addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

    addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

    addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00900090;

#B2.h中定义#define CFG_FLASH_ADDR0 0x5555   

#define CFG_FLASH_ADDR1 0x2AAA   

    <<<<<<无法理解?>>>>>>

    value = addr2[CFG_FLASH_READ0];

#获取flash的厂商ID

    switch (value) {

    case (CFG_FLASH_WORD_SIZE)AMD_MANUFACT:

        info->flash_id = FLASH_MAN_AMD;

        break;

    case (CFG_FLASH_WORD_SIZE)FUJ_MANUFACT:

        info->flash_id = FLASH_MAN_FUJ;

        break;

    case (CFG_FLASH_WORD_SIZE)SST_MANUFACT:

        info->flash_id = FLASH_MAN_SST;

        break;

    case (CFG_FLASH_WORD_SIZE)STM_MANUFACT:

        info->flash_id = FLASH_MAN_STM;

        break;

    default:

        info->flash_id = FLASH_UNKNOWN;

        info->sector_count = 0;

        info->size = 0;

        return (0);         /* no or unknown flash  */

    }

    value = addr2[CFG_FLASH_READ1];     /* device ID        */

    #获取flash的设备ID

    switch (value) {

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400T:

        info->flash_id += FLASH_AM400T;

        info->sector_count = 11;

        info->size = 0x00080000;

        break;              /* => 0.5 MB        */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV400B:

        info->flash_id += FLASH_AM400B;

        info->sector_count = 11;

        info->size = 0x00080000;

        break;              /* => 0.5 MB        */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800T:

        info->flash_id += FLASH_AM800T;

        info->sector_count = 19;

        info->size = 0x00100000;

        break;              /* => 1 MB      */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV800B:

        info->flash_id += FLASH_AM800B;

        info->sector_count = 19;

        info->size = 0x00100000;

        break;              /* => 1 MB      */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160T:

        info->flash_id += FLASH_AM160T;

        info->sector_count = 35;

        info->size = 0x00200000;

        break;              /* => 2 MB      */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV160B:

        info->flash_id += FLASH_AM160B;

        info->sector_count = 35;

        info->size = 0x00200000;

        break;              /* => 2 MB      */

    case (CFG_FLASH_WORD_SIZE)STM_ID_29W320DT:

        info->flash_id += FLASH_STMW320DT;

        info->sector_count = 67;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T:

        info->flash_id += FLASH_AM320T;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B:

        info->flash_id += FLASH_AM320B;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322T:

        info->flash_id += FLASH_AMDL322T;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_DL322B:

        info->flash_id += FLASH_AMDL322B;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323T:

        info->flash_id += FLASH_AMDL323T;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_DL323B:

        info->flash_id += FLASH_AMDL323B;

        info->sector_count = 71;

        info->size = 0x00400000;  break; /* => 4 MB  */

    case (CFG_FLASH_WORD_SIZE)AMD_ID_LV640U:

        info->flash_id += FLASH_AM640U;

        info->sector_count = 128;

        info->size = 0x00800000;  break; /* => 8 MB  */

    case (CFG_FLASH_WORD_SIZE)SST_ID_xF800A:

        info->flash_id += FLASH_SST800A;

        info->sector_count = 16;

        info->size = 0x00100000;

        break;              /* => 1 MB      */

    case (CFG_FLASH_WORD_SIZE)SST_ID_xF160A:

        info->flash_id += FLASH_SST160A;

        info->sector_count = 32;

        info->size = 0x00200000;

        break;              /* => 2 MB      */

    default:

        info->flash_id = FLASH_UNKNOWN;

        return (0);         /* => no or unknown flash */

    }

   #根据开发板Flash的情况,设定id,sector_count,size参数,若无则皆为0

    /* set up sector start address table */

   #设定起始地址表,与flash_get_offsets中的相同

    if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||

        ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U)) {

        for (i = 0; i < info->sector_count; i++)

        info->start[i] = base + (i * 0x00010000);

    } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324B)) {

        /* set sector offsets for bottom boot block type    */

        for (i=0; i<8; ++i) {       /*  8 x 8k boot sectors */

            info->start[i] = base;

            base += 8 << 10;

        }

        while (i < info->sector_count) {    /* 64k regular sectors  */

            info->start[i] = base;

            base += 64 << 10;

            ++i;

        }

    } else if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL322T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL323T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||

           ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMDL324T)) {

        /* set sector offsets for top boot block type       */

        base += info->size;

        i = info->sector_count;

        for (n=0; n<8; ++n) {       /*  8 x 8k boot sectors */

            base -= 8 << 10;

            --i;

            info->start[i] = base;

        }

        while (i > 0) {         /* 64k regular sectors  */

            base -= 64 << 10;

            --i;

            info->start[i] = base;

        }

    } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_STMW320DT) {

        /* set sector offsets for top boot block type       */

        base += info->size;

        i = info->sector_count;

        /*  1 x 16k boot sector */

        base -= 16 << 10;

        --i;

        info->start[i] = base;

        /*  2 x 8k  boot sectors */

        for (n=0; n<2; ++n) {

            base -= 8 << 10;

            --i;

            info->start[i] = base;

 


        }

 


        /*  1 x 32k boot sector */

        base -= 32 << 10;

        --i;

        info->start[i] = base;

 

        while (i > 0) {         /* 64k regular sectors  */

            base -= 64 << 10;

            --i;

            info->start[i] = base;

        }

    } else {

        if (info->flash_id & FLASH_BTYPE) {

        /* set sector offsets for bottom boot block type    */

        info->start[0] = base + 0x00000000;

        info->start[1] = base + 0x00004000;

        info->start[2] = base + 0x00006000;

        info->start[3] = base + 0x00008000;

        for (i = 4; i < info->sector_count; i++) {

            info->start[i] = base + (i * 0x00010000) - 0x00030000;

        }

        } else {

        /* set sector offsets for top boot block type       */

        i = info->sector_count - 1;

        info->start[i--] = base + info->size - 0x00004000;

        info->start[i--] = base + info->size - 0x00006000;

        info->start[i--] = base + info->size - 0x00008000;

        for (; i >= 0; i--) {

            info->start[i] = base + i * 0x00010000;

        }

        }

    }

#检测保护的片段

    for (i = 0; i < info->sector_count; i++) {

        /* read sector protection at sector address, (A7 .. A0) = 0x02 */

        /* D0 = 1 if protected */

        addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);

        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)

          info->protect[i] = 0;

        else

          info->protect[i] = addr2[CFG_FLASH_READ2] & 1;

    }

 

    if (info->flash_id != FLASH_UNKNOWN) {

        addr2 = (CFG_FLASH_WORD_SIZE *)info->start[0];

        *addr2 = (CFG_FLASH_WORD_SIZE)0x00F000F0;   /* reset bank */

    }

    return (info->size);

}

擦除函数

int flash_erase (flash_info_t *info, int s_first, int s_last)

{

    volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);

    volatile CFG_FLASH_WORD_SIZE *addr2;

    int flag, prot, sect, l_sect;

    ulong start, now, last;

    int i;

    if ((s_first < 0) || (s_first > s_last)) {

        if (info->flash_id == FLASH_UNKNOWN) {

            printf ("- missing\n");

        } else {

            printf ("- no sectors to erase\n");

        }

        return 1;

    }

    if (info->flash_id == FLASH_UNKNOWN) {

        printf ("Can't erase unknown flash type - aborted\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 {

        printf ("\n");

    }

    l_sect = -1;

    /* Disable interrupts which might cause a timeout here */

    flag = disable_interrupts();

    /* Start erase on unprotected sectors */

    for (sect = s_first; sect<=s_last; sect++) {

        if (info->protect[sect] == 0) { /* not protected */

            addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);

            if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {

            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

            addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;

            addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

            addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

            addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050;  /* block erase */

            for (i=0; i<50; i++)

              udelay(1000);  /* wait 1 ms */

            } else {

            if (sect == s_first) {

                addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

                addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

                addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;

                addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

                addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

            }

            addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030;  /* sector erase */

            }

            l_sect = sect;

        }

    }

    /* re-enable interrupts if necessary */

    if (flag)

        enable_interrupts();

    /* wait at least 80us - let's wait 1 ms */

    udelay (1000);

    /*

     * We wait for the last triggered sector

     */

    if (l_sect < 0)

        goto DONE;

    start = get_timer (0);

    last  = start;

    addr = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);

    while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080)

{

        if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {

            printf ("Timeout\n");

            return 1;

        }

        /* show that we're waiting */

        if ((now - last) > 1000) {  /* every second */

            putc ('.');

            last = now;

        }

    }

DONE:

    /* reset to read mode */

    addr = (CFG_FLASH_WORD_SIZE *)info->start[0];

    addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0;  /* reset bank */

 

    printf (" done\n");

    return 0;

}

/*-----------------------------------------------------------------------

 * 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 cp, wp, data;

    int i, l, rc;

 

    wp = (addr & ~3);   /* 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) {

#ifdef CONFIG_B2

            data = data | ((*(uchar *)cp)<<(8*i));

#else

            data = (data << 8) | (*(uchar *)cp);

#endif

        }

        for (; i<4 && cnt>0; ++i) {

#ifdef CONFIG_B2

            data = data  | ((*src++)<<(8*i));

#else

            data = (data << 8) | *src++;

#endif

            --cnt;

            ++cp;

        }

        for (; cnt==0 && i<4; ++i, ++cp) {

#ifdef CONFIG_B2

            data = data | ((*(uchar *)cp)<<(8*i));

#else

            data = (data << 8) | (*(uchar *)cp);

#endif

        }

 

        if ((rc = write_word(info, wp, data)) != 0) {

            return (rc);

        }

        wp += 4;

    }

 

    /*

     * handle word aligned part

     */

    while (cnt >= 4) {

        data = 0;

#ifdef CONFIG_B2

        data = (*(ulong*)src);

        src += 4;

#else

        for (i=0; i<4; ++i) {

            data = (data << 8) | *src++;

        }

#endif

        if ((rc = write_word(info, wp, data)) != 0) {

            return (rc);

        }

        wp  += 4;

        cnt -= 4;

    }

 

    if (cnt == 0) {

        return (0);

    }

 

    /*

     * handle unaligned tail bytes

     */

    data = 0;

    for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {

#ifdef CONFIG_B2

        data = data  | ((*src++)<<(8*i));

#else

        data = (data << 8) | *src++;

#endif

        --cnt;

    }

    for (; i<4; ++i, ++cp) {

#ifdef CONFIG_B2

        data = data | ((*(uchar *)cp)<<(8*i));

#else

        data = (data << 8) | (*(uchar *)cp);

#endif

    }

 

    return (write_word(info, wp, data));

}

 

/*-----------------------------------------------------------------------

 * Write a word to Flash, returns:

 * 0 - OK

 * 1 - write timeout

 * 2 - Flash not erased

 */

写字函数

static int write_word (flash_info_t *info, ulong dest, ulong data)

{

    volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);

    volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;

    volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;

    ulong start;

    int flag;

    int i;

 

    /* Check if Flash is (sufficiently) erased */

    if ((*((volatile ulong *)dest) & data) != data) {

        return (2);

    }

    /* Disable interrupts which might cause a timeout here */

    flag = disable_interrupts();

 

    for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)

      {

        addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

        addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

        addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;

 

        dest2[i] = data2[i];

 

        /* re-enable interrupts if necessary */

        if (flag)

          enable_interrupts();

 

        /* data polling for D7 */

        start = get_timer (0);

        while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=

           (data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {

          if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {

        return (1);

          }

        }

      }

 

    return (0);

}

3、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;

4、common->flash.c

#include <common.h>

#include <flash.h>

 

#if !defined(CFG_NO_FLASH)

extern flash_info_t  flash_info[]; /* info for FLASH chips */

FLASH保护

void flash_protect (int flag, ulong from, ulong to, flash_info_t *info)

{

    ulong b_end = info->start[0] + info->size - 1;  /* bank end address */

    short s_end = info->sector_count - 1;   /* index of last sector */

    int i;

 

    debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",

        (flag & FLAG_PROTECT_SET) ? "ON" :

            (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",

        from, to);

 

    /* Do nothing if input data is bad. */

    if (info->sector_count == 0 || info->size == 0 || to < from) {

        return;

    }

    #无用数据时什么都不做

    /* There is nothing to do if we have no data about the flash

     * or the protect range and flash range don't overlap.

     */

    if (info->flash_id == FLASH_UNKNOWN ||

        to < info->start[0] || from > b_end) {

        return;

    }

    #写的数据超出范围,或者无数据时,什么都不做

    for (i=0; i<info->sector_count; ++i) {

        ulong end;      /* last address in current sect */

 

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

 

        /* Update protection if any part of the sector

         * is in the specified range.

         */

        if (from <= end && to >= info->start[i]) {

            if (flag & FLAG_PROTECT_CLEAR) {

#if defined(CFG_FLASH_PROTECTION)

                flash_real_protect(info, i, 0);

#else

                info->protect[i] = 0;

#endif  /* CFG_FLASH_PROTECTION */

                debug ("protect off %d\n", i);

            }

            else if (flag & FLAG_PROTECT_SET) {

#if defined(CFG_FLASH_PROTECTION)

                flash_real_protect(info, i, 1);

#else

                info->protect[i] = 1;

#endif  /* CFG_FLASH_PROTECTION */

                debug ("protect on %d\n", i);

            }

        }

    }

}

写地址到info

flash_info_t *addr2info (ulong addr)

{

#ifndef CONFIG_SPD823TS

    flash_info_t *info;

    int i;

 

    for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {

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

        }

        #判断数据是否有用,若有用,则返回info

    }

#endif /* CONFIG_SPD823TS */

    return (NULL);

}

/*-----------------------------------------------------------------------

 * 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)

 */

写FLASH

int flash_write (char *src, ulong addr, ulong cnt)

{

#ifdef CONFIG_SPD823TS

    return (ERR_TIMOUT);    /* any other error codes are possible as well */

#else

    int i;

    ulong         end        = addr + cnt - 1;

    flash_info_t *info_first = addr2info (addr);

    flash_info_t *info_last  = addr2info (end );

    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) {

        ulong b_end = info->start[0] + info->size;  /* bank end addr */

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

#endif /* CONFIG_SPD823TS */

}

错误类型显示

void flash_perror (int err)

{

    switch (err) {

    case ERR_OK:

        break;

    case ERR_TIMOUT:

        puts ("Timeout writing to Flash\n");

        break;

    case ERR_NOT_ERASED:

        puts ("Flash not Erased\n");

        break;

    case ERR_PROTECTED:

        puts ("Can't write to protected Flash sectors\n");

        break;

    case ERR_INVAL:

        puts ("Outside available Flash\n");

        break;

    case ERR_ALIGN:

        puts ("Start and/or end address not on sector boundary\n");

        break;

    case ERR_UNKNOWN_FLASH_VENDOR:

        puts ("Unknown Vendor of Flash\n");

        break;

    case ERR_UNKNOWN_FLASH_TYPE:

        puts ("Unknown Type of Flash\n");

        break;

    case ERR_PROG_ERROR:

        puts ("General Flash Programming Error\n");

        break;

    default:

        printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);

        break;

    }

}

 

二 执行流程

在lib_arm->board.c中的start_armboot函数是第2阶段的起始,我们从这里开始分析:

1)       flash_init()被调用;

2)       初始化所有的BANK为FLASH_UNKNOW;

3)       调用flash_get_size()。通过判断FLASH类型,获得FLASH的大小,并且返回info->size,存

放入size_b0;

4)       调用flash_get_offsets()设置BANK起始地址表,无返回;

5)       调用flash_protect()判断写入信息是否可用

6)       返回size_b0

7)       调用display_flash_config (size);定义为static void display_flash_


本文来自CSDN博客,转载请标明出处:

http://blog.csdn.net/xiehongyu3000/archive/2009/07/02/4317342.aspx