uboot 同时支持多种存储设备参数设计与实现

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/li_wen01/article/details/87191477

    嵌入式开发应用的时候有这样一种场景:外围核心硬件一样,但是为了节省成本亦或是为了兼容以前旧的产品,有些设备贴的是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启动流程参考博客:

    uboot分析:uboot的启动过程分析 

    uboot启动阶段修改启动参数方法及分析

    嵌入式Linux开发之uboot启动Linux整体流程分析 

猜你喜欢

转载自blog.csdn.net/li_wen01/article/details/87191477