嵌入式开发应用的时候有这样一种场景:外围核心硬件一样,但是为了节省成本亦或是为了兼容以前旧的产品,有些设备贴的是spi norflash,有些设备贴的是spi nandflash亦或是其他的存储设备。为了方便代码管理及后续代码的维护,软件设计需要同时支持多种存储设备,实现多种存储设备使用同一套uboot代码。因为不同存储设备的的启动参数不一样,所以就需要设计根据不同存储设备来设置不同的启动参数。也就是说uboot启动的时候需要根据存储设备的类型来调用不同的启动参数。
基本设计思路:
(1)uboot启动后,检测flash类型。
(2)根据不同的flash类型,调用不同的启动参数。
备注:
我测试的设备是海思的3520DV300,uboot是由海思SDk中提供的代码基础上做的修改。
我的存储设备有两种:spi nor flash和 spi nand flash
(一)flash 类型检测
uboot启动的时候会去检测flash的类型,可以通过启动打印消息去跟踪自己设备具体是在哪里检测flash类型。
U-Boot 2010.06 (Feb 13 2019 - 15:56:50)
Check Flash Memory Controller v100 ... Found
SPI Nor(cs 0) ID: 0xc2 0x20 0x19
Block:64KB Chip:32MB Name:"MX25L(256/257)35(E/F)"
SPI Nor total size: 32MB
In: serial
Out: serial
Err: serial
USB: scanning bus for devices...
我使用的Uboot,是在hifmc_common.c文件的hifmc_dev_type_switch函数中检测flash类型。
int spi_flash_type = 0;
/*****************************************************************************/
void hifmc_dev_type_switch(unsigned char type)
{
unsigned int reg, spi_device_type, flash_type;
const char *str[] = {"SPI nor", "SPI nand", "Nand", "Boot"};
if (hifmc_current_dev_type == type)
return;
FMC_PR(BT_DBG, "\t|*-Start switch current device type\n");
if (type > FLASH_TYPE_DEFAULT) {
FMC_PR(BT_DBG, "\t||-Switch unknown device type %d\n", type);
return;
}
if (hifmc_boot_dev_type == FLASH_TYPE_DEFAULT) {
reg = readl((void *)(SYS_CTRL_REG_BASE + REG_SYSSTAT));
FMC_PR(BT_DBG, "\t||-Get system STATUS[%#x]%#x\n",
SYS_CTRL_REG_BASE + REG_SYSSTAT, reg);
hifmc_boot_dev_type = GET_SPI_DEVICE_TYPE(reg);
FMC_PR(BT_DBG, "\t||-Init boot device type to %s flash\n",
str[hifmc_boot_dev_type]);
}
if (type == FLASH_TYPE_DEFAULT)
spi_device_type = hifmc_boot_dev_type;
else
spi_device_type = type;
FMC_PR(BT_DBG, "\t||-Switch type to %s flash\n", str[type]);
reg = readl((void *)(CONFIG_HIFMC_REG_BASE + FMC_CFG));
FMC_PR(BT_DBG, "\t||-Get HIFMC CFG[%#x]%#x\n", FMC_CFG, reg);
flash_type = (reg & FLASH_SEL_MASK) >> FLASH_SEL_SHIFT;
if (spi_device_type != flash_type) {
reg &= ~FLASH_SEL_MASK;
reg |= FMC_CFG_FLASH_SEL(spi_device_type);
writel(reg, (void *)(CONFIG_HIFMC_REG_BASE + FMC_CFG));
FMC_PR(BT_DBG, "\t||-Set HIFMC CFG[%#x]%#x\n", FMC_CFG, reg);
}
hifmc_current_dev_type = spi_device_type;
spi_flash_type = hifmc_current_dev_type;
FMC_PR(BT_DBG, "\t|*-End switch current device type\n");
}
其中spi_flash_type 变量是我自己定义的,用来在其他的文件中判断是属于哪种类型的flash。flash类型uboot是使用宏定义在hifmc_common.h文件中。具体定义如下:
#define FLASH_TYPE_SPI_NOR 0x0
#define FLASH_TYPE_SPI_NAND 0x1
#define FLASH_TYPE_NAND 0x2
#define FLASH_TYPE_DEFAULT 0x3
在我这里,spi_flash_type默认值为0,也就是spi nor flash 类型。
(二)参数设置
nor flash 与nandflash 的启动参数是不同的,设置启动变量参数是在set_default_env中实现,默认启动参数保存在数组default_environment 中。要实现支持不同的flash,就需要定义两个不同的数组来区分。设备的启动参数一般是在include/configs/目录下对应的启动文件中中。在这里,我们在hi3520dv300.h中将参数定义为如下:
/**modify by licaibiao for default flash **/
#define CONFIG_BOOTCOMMAND "nand read 0x82000000 0x100000 0x400000;bootm 0x82000000"
#define CONFIG_BOOTARGS "mem=256M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=yaffs2 mtdparts=hinand:1M(boot),4M(kernel),32M(rootfs),2M(parameter),24M(app&data),32M(data),32M(updatefs)"
/**add by licaibiao for nand flash **/
#define CONFIG_BOOTCOMMAND_NANDFLASH "nand read 0x82000000 0x100000 0x400000;bootm 0x82000000"
#define CONFIG_BOOTARGS_NANDFLASH "mem=256M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=yaffs2 mtdparts=hinand:1M(boot),4M(kernel),32M(rootfs),2M(parameter),24M(app&data),32M(data),32M(updatefs)"
/**add by licaibiao for nor flash **/
#define CONFIG_BOOTCOMMAND_NORFLASH "sf probe 0;sf read 0x82000000 0x100000 0x400000;bootm 0x82000000"
#define CONFIG_BOOTARGS_NORFLASH "mem=256M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),4M(kernel),8M(rootfs),4M(app&data),4M(data),2M(parameter),8M(updatefs)"
同时在default_environment 数据下新建两个数组:norflash_environment与nandflash_environment。然后再将调用default_environment的地方修改为根据不同flash类型来调用不同的数组,实现不同flash调用不同的启动参数。比如下面:
if(0==spi_flash_type)
{
gd->env_addr = (ulong)&norflash_environment[0];
}else if(1==spi_flash_type)
{
gd->env_addr = (ulong)&nandflash_environment[0];
}else
{
gd->env_addr = (ulong)&default_environment[0];
}
数组定义如下:
uchar norflash_environment[] = {
#ifdef CONFIG_BOOTARGS_NORFLASH
"bootargs=" CONFIG_BOOTARGS_NORFLASH "\0"
#endif
#ifdef CONFIG_SLAVE_BOOTARGS
"slave_bootargs=" CONFIG_SLAVE_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND_NORFLASH
"bootcmd=" CONFIG_BOOTCOMMAND_NORFLASH "\0"
#endif
#ifdef CONFIG_SLAVE_BOOTCMD
"slave_bootcmd=" CONFIG_SLAVE_BOOTCMD "\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_MDIO_INTF
"mdio_intf=" CONFIG_MDIO_INTF "\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_ETH4ADDR
"eth4addr=" MK_STR(CONFIG_ETH4ADDR) "\0"
#endif
#ifdef CONFIG_ETH5ADDR
"eth5addr=" MK_STR(CONFIG_ETH5ADDR) "\0"
#endif
#ifdef CONFIG_IPADDR
"ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
#endif
#ifdef CONFIG_SERVERIP
"serverip=" MK_STR(CONFIG_SERVERIP) "\0"
#endif
#ifdef CONFIG_SYS_AUTOLOAD
"autoload=" CONFIG_SYS_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
#if defined(CONFIG_JPEG_ADDR)
"jpeg_addr=" MK_STR(CONFIG_JPEG_ADDR) "\0"
#endif
#if defined(CONFIG_JPEG_SIZE)
"jpeg_size=" MK_STR(CONFIG_JPEG_SIZE) "\0"
#endif
#if defined(CONFIG_JPEG_VOBUF_ADDR)
"vobuf=" MK_STR(CONFIG_JPEG_VOBUF_ADDR) "\0"
#endif
#if defined(CONFIG_HARDWARE_VER)
"hardware_ver=" MK_STR(CONFIG_HARDWARE_VER) "\0"
#endif
"\0"
};
uchar nandflash_environment[] = {
#ifdef CONFIG_BOOTARGS_NANDFLASH
"bootargs=" CONFIG_BOOTARGS_NANDFLASH "\0"
#endif
#ifdef CONFIG_SLAVE_BOOTARGS
"slave_bootargs=" CONFIG_SLAVE_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND_NANDFLASH
"bootcmd=" CONFIG_BOOTCOMMAND_NANDFLASH "\0"
#endif
#ifdef CONFIG_SLAVE_BOOTCMD
"slave_bootcmd=" CONFIG_SLAVE_BOOTCMD "\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_MDIO_INTF
"mdio_intf=" CONFIG_MDIO_INTF "\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_ETH4ADDR
"eth4addr=" MK_STR(CONFIG_ETH4ADDR) "\0"
#endif
#ifdef CONFIG_ETH5ADDR
"eth5addr=" MK_STR(CONFIG_ETH5ADDR) "\0"
#endif
#ifdef CONFIG_IPADDR
"ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
#endif
#ifdef CONFIG_SERVERIP
"serverip=" MK_STR(CONFIG_SERVERIP) "\0"
#endif
#ifdef CONFIG_SYS_AUTOLOAD
"autoload=" CONFIG_SYS_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
#if defined(CONFIG_JPEG_ADDR)
"jpeg_addr=" MK_STR(CONFIG_JPEG_ADDR) "\0"
#endif
#if defined(CONFIG_JPEG_SIZE)
"jpeg_size=" MK_STR(CONFIG_JPEG_SIZE) "\0"
#endif
#if defined(CONFIG_JPEG_VOBUF_ADDR)
"vobuf=" MK_STR(CONFIG_JPEG_VOBUF_ADDR) "\0"
#endif
#if defined(CONFIG_HARDWARE_VER)
"hardware_ver=" MK_STR(CONFIG_HARDWARE_VER) "\0"
#endif
"\0"
};
使用该方法可以实现一套代码同时支持norflash和nandflash设备启动和参数设置。
附uboot启动流程参考博客: