移植uboot第五步:支持NORFlash

之前已经将板子设为NAND启动了,但这只是能从NANDcopy代码,不代表板子就支持了以后对NANDFlash的读写操作。
启动板子以后输出信息:

CPUID: 32440001
FCLK:      400 MHz
HCLK:      100 MHz
PCLK:       50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: *** failed ***
### ERROR ### Please RESET the board ###

其中说明了Flash: *** failed ***,表示确实flash没有支持。

一. 复制这个错误到到SI中搜索,结果如下:

#if !defined(CONFIG_SYS_NO_FLASH)
    puts("Flash: ");

    flash_size = flash_init();
    if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
        char *s = getenv("flashchecksum");

        print_size(flash_size, "");
        /*
         * Compute and print flash CRC if flashchecksum is set to 'y'
         *
         * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
         */
        if (s && (*s == 'y')) {
            printf("  CRC: %08X", crc32(0,
                (const unsigned char *) CONFIG_SYS_FLASH_BASE,
                flash_size));
        }
        putc('\n');
# else  /* !CONFIG_SYS_FLASH_CHECKSUM */
        print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
    } else {
        puts("0 KB\n\r");
        puts(failed);
        hang();
    }
#endif

可以知道是if语句不成立,导致输出failed,也就是说读取flash大小的时候flash_size值为0。

先把这两句话注释掉

puts(failed);
hang();     //表示阻塞中,程序到这里就死循环

进入nand初始化函数flash_init();

for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
        flash_info[i].flash_id = FLASH_UNKNOWN;

        /* Optionally write flash configuration register */
        cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
                     cfi_flash_config_reg(i));

        if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
            flash_get_size(cfi_flash_bank_addr(i), i);
        size += flash_info[i].size;

这里可以看到Flash的大小是由size 这个变量决定的。
进入flash_get_size(),看到里面有一些debug

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

这些debug的开关是宏定义的,因此在文件上的上端

#define DEBUG   
#define _DEBUG  1

因为不知道具体他们编写的时候DEBUG是什么格式,因此两种都写了

编译,烧写。

Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr (null) cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
fwc addr (null) cmd ff 00ff 16bit x 16 bit
fwc addr (null) cmd 90 0090 16bit x 16 bit
fwc addr (null) cmd ff 00ff 16bit x 16 bit
JEDEC PROBE: ID 13 ea00 0

二. JEDEC PROBE: ID c2 2249 0 这句话其中的c2表示厂家ID,2249表示机器ID。查阅NORFlash手册,发现这两个ID是正确的,但是没有检测到,说明程序底层驱动是对的,但是板子没支持这个NOR。搜索JEDEC PROBE:

flash_read_jedec_ids(info);
debug("JEDEC PROBE: ID %x %x %x\n",
info->manufacturer_id,
info->device_id,
info->device_id2);
if (jedec_flash_match(info, info->start[0]))
    break;
else
    unmap_physmem((void *)info->start[0],
MAP_NOCACHE);

进入jedec_flash_match函数:

/*-----------------------------------------------------------------------
 * match jedec ids against table. If a match is found, fill flash_info entry
 */
int jedec_flash_match(flash_info_t *info, ulong base)
{
    int ret = 0;
    int i;
    ulong mask = 0xFFFF;
    if (info->chipwidth == 1)
        mask = 0xFF;

    for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
        if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
            (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
            fill_info(info, &jedec_table[i], base);
            ret = 1;
            break;
        }
    }
    return ret;
}

进入jedec_table数组查看:

static const struct amd_flash_info jedec_table[] = {
#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
    {
        .mfr_id     = (u16)SST_MANUFACT,
        .dev_id     = SST39LF020,
        .name       = "SST 39LF020",
        .uaddr      = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_256KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,64),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
    {
        .mfr_id     = (u16)AMD_MANUFACT,
        .dev_id     = AM29LV040B,
        .name       = "AMD AM29LV040B",
        .uaddr      = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id     = (u16)SST_MANUFACT,
        .dev_id     = SST39LF040,
        .name       = "SST 39LF040",
        .uaddr      = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,128),
        }
    },
    {
        .mfr_id     = (u16)STM_MANUFACT,
        .dev_id     = STM_ID_M29W040B,
        .name       = "ST Micro M29W040B",
        .uaddr      = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000,8),
        }
    },
    {
        .mfr_id     = (u16)MX_MANUFACT,
        .dev_id     = MX29LV040,
        .name       = "MXIC MX29LV040",
        .uaddr      = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id     = (u16)WINB_MANUFACT,
        .dev_id     = W39L040A,
        .name       = "WINBOND W39L040A",
        .uaddr      = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id     = (u16)AMIC_MANUFACT,
        .dev_id     = A29L040,
        .name       = "AMIC A29L040",
        .uaddr      = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
    {
        .mfr_id     = (u16)EON_MANUFACT,
        .dev_id     = EN29LV040A,
        .name       = "EON EN29LV040A",
        .uaddr      = {
            [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x10000, 8),
        }
    },
#endif
#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
    {
        .mfr_id     = (u16)AMD_MANUFACT,
        .dev_id     = AM29F400BB,
        .name       = "AMD AM29F400BB",
        .uaddr      = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
    {
        .mfr_id     = (u16)AMD_MANUFACT,
        .dev_id     = AM29LV400BB,
        .name       = "AMD AM29LV400BB",
        .uaddr      = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_512KiB,
        .CmdSet     = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000,1),
            ERASEINFO(0x02000,2),
            ERASEINFO(0x08000,1),
            ERASEINFO(0x10000,7),
        }
    },
    {
        .mfr_id     = (u16)AMD_MANUFACT,
        .dev_id     = AM29LV800BB,
        .name       = "AMD AM29LV800BB",
        .uaddr      = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize    = SIZE_1MiB,
        .CmdSet     = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions= 4,
        .regions    = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 15),
        }
    },
    {
        .mfr_id     = (u16)STM_MANUFACT,
        .dev_id     = STM29F400BB,
        .name       = "ST Micro M29F400BB",
        .uaddr      = {
            [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
        },
        .DevSize        = SIZE_512KiB,
        .CmdSet         = CFI_CMDSET_AMD_LEGACY,
        .NumEraseRegions    = 4,
        .regions        = {
            ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 7),
        }
    },
#endif
};

查询以后发现,确实是这里面没有我们所使用的NORFlash。
进入机器ID的宏定义代码,里面找到了这个:

#define MX_MANUFACT 0x00C200C2  /* MXIC    manuf. ID in D23..D16, D7..D0 */

C2就是我们使用的NORFlash,说明uboot是能够支持的,只是数组中没有将其写入。更改数组,加入我们自己的NORflash,使其能够支持。
因为数组中有宏定义,我也不打算破坏它的结构了,随便复制了一个将其粘贴到数组的最后端,#endif的下面。

{
        .mfr_id     = (u16)SST_MANUFACT,
        .dev_id     = SST39LF020,
        .name       = "SST 39LF020",
        .uaddr      = {
            [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
        },
        .DevSize    = SIZE_256KiB,
        .CmdSet     = P_ID_AMD_STD,
        .NumEraseRegions= 1,
        .regions    = {
            ERASEINFO(0x01000,64),
        }
    },

a.将厂家ID:mfr_id修改为MX_MANUFACT,

b.机器ID:dev_id修改为0x2249,

c.名字:name修改为”MXIC MT29LV160DB”
uaddr解锁地址改为[1] = MTD_UADDR_0x0555_0x02AA /* x16 / /*NOR flash 解锁地址 /
[0]表示NOR是8位的,我使用的是16位的,因此改为1。NORFlash使用的时候会锁定,因此写的时候要先解锁,在一些地址中写入值才能解锁。解锁地址可以查阅手册。

d.大小:DevSize修改为SIZE_2MiB

e.NumEraseRegions改为4。
NOR的结构不同,擦除块是不同的,例如一个flash可能分成了十块,每块128kb,也有可能一个flash前十块是128kb,后十块是256kb,可以查阅手册,有多少种块,就写几,我使用的NOR有4中,分别8字节2块,16字节1块,32字节1块,64字节31块。

f.

regions = {
            ERASEINFO(0x01000,64),
        }

修改为:

.regions    = {
    ERASEINFO(16 * 1024 , 1),
    ERASEINFO(8 * 1024  , 2),
    ERASEINFO(32 * 1024 , 1),
    ERASEINFO(64 * 1024 , 31),
}

这个就是说明擦除块的分布情况,从上往下分别是NOR中地址从低到高排布。

make,烧写,运行。
出现警告,说擦除块太多。查看以后是宏定义值为19,值小于我们的擦除块数量,将其修改为128。 其实这个值多少都可以,只要大于使用的擦除块就行了。

三. 调试时出现一个bug,对移植来说关联不大,但是很有可能在以后造成错误,这里就把它修改一下。
重定位的时候东西都移了,但是栈指针没有修改,要重新设置栈,否则所有的东西都在0x33F00000,只有栈在0x30000000,在0x33F00000之前是考虑空出来了一块区域给栈用的,现在没有重新定位栈,导致都没有用。程序能跑,但是这样的话,要时刻小心不能使用0x30000000之后的这块区域,否则修改到变量了,uboot很有可能会死。
在start.S中设置一个全局变量

.globl base_sp
base_sp:
    .long 0

board_init_f函数本质上是一个计算uboot存放位置的函数,在这里可以找到为栈设置的地址。

base_sp = addr_sp;

在重定位代码以后,将栈指针重新设置

ldr r1, _TEXT_BASE
ldr sp, base_sp         /* 重新设置栈 */

/* 调用第二阶段代码 */
bl  board_init_r

编译,烧写,运行。

U-Boot 2012.04.01 (Aug 12 2016 - 00:17:17)

CPUID: 32440001
FCLK:      400 MHz
HCLK:      100 MHz
PCLK:       50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit
fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit
fwc addr 00005554 cmd 55 0055 16bit x 16 bit
fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit
fwc addr (null) cmd f0 00f0 16bit x 16 bit
JEDEC PROBE: ID c2 2249 0
2 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   CS8900-0
SMDK2410 # 

成功了

猜你喜欢

转载自blog.csdn.net/ltc844139730/article/details/52188053
今日推荐