五、移植u-boot-2016.03到Jz2440之修改代码支持NOR Flash

5. 移植u-boot-2016.03修改代码支持NOR Flash

从上一节把uboot烧写到NAND启动后,最后打印出Flash: 0 Bytes,如下图所示。我们的Jz2440开发板的NOR Flash是2MB的,那么为什么显示Flash是0Bytes呢?显然,此时的uboot还没支持NOR Flash,所以不是识别开发板的NOR Flash大小。
在这里插入图片描述

5.1 分析u-boot-2016.03源码之NOR Flash

(1) 我们在source insight中搜索**“Flash:”**这个字符串出现在哪里,在 common/board_r.c中有 initr_flash函数,该函数放在 init_sequence_r函数指针数组了,被 board_init_r函数调用,initr_flash函数的代码如下:

static int initr_flash(void)
{
    
    
	ulong flash_size = 0;
	bd_t *bd = gd->bd;

	puts("Flash: ");  /* 打印 Flash: */

	if (board_flash_wp_on())  /*空函数,返回0*/
		printf("Uninitialized - Write Protect On\n");
	else
		flash_size = flash_init();

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

	/* update start of FLASH memory    */
#ifdef CONFIG_SYS_FLASH_BASE
	bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
#endif
	/* size of FLASH memory (final value) */
	bd->bi_flashsize = flash_size;

#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
	/* Make a update of the Memctrl. */
	update_flash_size(flash_size);
#endif


#if defined(CONFIG_OXC) || defined(CONFIG_RMU)
	/* flash mapped at end of memory map */
	bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
	bd->bi_flashoffset = monitor_flash_len;	/* reserved area for monitor */
#endif
	return 0;
}

从上面的代码可知,显然 initr_flash函数通过调用 flash_init函数获取 NOR Flash空间的大小,flash_init函数的代码如下:(该函数在 drivers/mtd/cfi_flash.c)

unsigned long flash_init (void)
{
    
    
	unsigned long size = 0;
	int i;

#ifdef CONFIG_SYS_FLASH_PROTECTION   /*CONFIG_SYS_FLASH_PROTECTION 没定义*/
	/* read environment from EEPROM */
	char s[64];
	getenv_f("unlock", s, sizeof(s));
#endif

#ifdef CONFIG_CFI_FLASH /* for driver model */ /*CONFIG_CFI_FLASH 没定义*/
	cfi_flash_init_dm();
#endif

	/* Init: no FLASHes known */
	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;
		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
    
    
#ifndef CONFIG_SYS_FLASH_QUIET_TEST   /*CONFIG_SYS_FLASH_QUIET_TEST没定义*/
			printf ("## Unknown flash on Bank %d "
				"- Size = 0x%08lx = %ld MB\n",
				i+1, flash_info[i].size,
				flash_info[i].size >> 20);
#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
		}
#ifdef CONFIG_SYS_FLASH_PROTECTION  /*CONFIG_SYS_FLASH_PROTECTION没定义*/
		else if (strcmp(s, "yes") == 0) {
    
    
			/*
			 * Only the U-Boot image and it's environment
			 * is protected, all other sectors are
			 * unprotected (unlocked) if flash hardware
			 * protection is used (CONFIG_SYS_FLASH_PROTECTION)
			 * and the environment variable "unlock" is
			 * set to "yes".
			 */
			if (flash_info[i].legacy_unlock) {
    
    
				int k;

				/*
				 * Disable legacy_unlock temporarily,
				 * since flash_real_protect would
				 * relock all other sectors again
				 * otherwise.
				 */
				flash_info[i].legacy_unlock = 0;

				/*
				 * Legacy unlocking (e.g. Intel J3) ->
				 * unlock only one sector. This will
				 * unlock all sectors.
				 */
				flash_real_protect (&flash_info[i], 0, 0);

				flash_info[i].legacy_unlock = 1;

				/*
				 * Manually mark other sectors as
				 * unlocked (unprotected)
				 */
				for (k = 1; k < flash_info[i].sector_count; k++)
					flash_info[i].protect[k] = 0;
			} else {
    
    
				/*
				 * No legancy unlocking -> unlock all sectors
				 */
				flash_protect (FLAG_PROTECT_CLEAR,
					       flash_info[i].start[0],
					       flash_info[i].start[0]
					       + flash_info[i].size - 1,
					       &flash_info[i]);
			}
		}
#endif /* CONFIG_SYS_FLASH_PROTECTION */
	}

	flash_protect_default();
#ifdef CONFIG_FLASH_CFI_MTD  /*CONFIG_FLASH_CFI_MTD 没定义*/
	cfi_mtd_init();
#endif

	return (size);
}

上面的程序有一个if判断语句:

		if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
			flash_get_size(cfi_flash_bank_addr(i), i);

从字面意思看出flash_detect_legacy为旧的检测flash,flash_get_size就应该为新的检测flash机制,先看一下旧的,没看出什么,再看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 查到:
include/common.h中有如下代码:

#define debug(fmt, args...)			\
	debug_cond(_DEBUG, fmt, ##args)

很明显应该是用的 _DEBUG,搜索 _DEBUG,在 include/common.h中有:

#ifdef DEBUG
#define _DEBUG	1
#else
#define _DEBUG	0
#endif

那么我们就把#define DEBUG给加上,在jz2440.h中定义如下:

#define DEBUG	 

重新编译u-boot烧写到NOR Flash,并设置为NOR Flash启动,启动后后串口有如下结果输出:
在这里插入图片描述
从打印的这句话:JEDEC PROBE: ID c2 2249 0
可知厂家ID是c2,设备ID是2249,查看NOR Flash(MX29LV160DBT)的数据手册有:
在这里插入图片描述
从数据手册可知,MX29LV160DBT的设备厂家ID是C2,设备ID是2249,与uboot读出的厂家ID、设备ID相符。所以,现在的uboot是可以正常读出NOR Flash的厂家ID、设备ID的。

(2) 根据打印信息,在源码中搜索字符串“JEDEC PROBE:”在drivers/mtd/cfi_flash.c中的flash_detect_legacy函数中有如下代码片段:

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

从上面的代码可知厂家ID、设备ID是如何打印的;同时还需要通过jedec_flash_match函数进行匹配,jedec_flash_match函数代码如下:(在drivers/mtd/jedec_flash.c)

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_flash_match发现一个数组jedec_table,匹配设备的ID用的应该就是这个数组里的内容了,查看数组如下:


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
......

5.2 修改代码支持NOR Flash

(1) 在amd_flash_info 这个结构体数组里的内容,定义了许多类型的flash,每一个定义就是一个flash芯片。我们在里面自己定义我们的芯片结构项:

{
    
    
         .mfr_id     =  (u16)0x00C2,/*厂家ID*/
         .dev_id     = 0x2249,           /*设备ID*/
         .name       = "MXIC MX29LV160DB",
         .uaddr      = {
    
    
             [1] = MTD_UADDR_0x0555_0x02AA /* x16 *//*NOR FLASH看到的解锁地址*/
         },
         .DevSize        = SIZE_2MiB,
         .CmdSet         = P_ID_AMD_STD,
         .NumEraseRegions    = 4, /* 擦除区域的数目 */
         .regions        = {
    
    
             ERASEINFO(16*1024, 1),
             ERASEINFO(8*1024, 2),
             ERASEINFO(32*1024, 1),
             ERASEINFO(64*1024, 31),

         }
     },

然后,重新编译u-boot,烧写到NOR Flash并启动运行,打印信息有如下:
在这里插入图片描述
从上面的信息可知,uboot已经识别出NOR Flash空间的大小2MiB,但是还显示错误ERROR: too many flash sectors
(2) 从源码中搜索错误ERROR: too many flash sectors,发现在drivers/mtd/cfi_flash.c有如下代码:

if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
    
    
					printf("ERROR: too many flash sectors\n");
					break;
				}

跳转到CONFIG_SYS_MAX_FLASH_SECT这个定义(在jz2440.h中),有:

#define CONFIG_SYS_MAX_FLASH_SECT	(19)

从下图的NOR Flash的数据手册可知,Secter总共有35个;因此,把CONFIG_SYS_MAX_FLASH_SECT宏定义改为::

#define CONFIG_SYS_MAX_FLASH_SECT	(35)

在这里插入图片描述
此外,在jz2440.h中把Debug调试信息去掉:

/*#define DEBUG	*/

注:jz2440.h中注释不能使用 双斜杠"//" 注释,否则,编译的时候会自动在uboot顶层目录下的链接脚本u-boot.lds添加"//#define DEBUG",所下图所示:
在这里插入图片描述
然后编译时会产生如下错误:
在这里插入图片描述
重新编译u-boot,烧写到NOR Flash并启动运行,打印信息如下:
在这里插入图片描述
从上图可知,已经可以清晰看到uboot识别出NOR Flash空间大小:Flash: 2 MiB,而且错误ERROR: too many flash sectors也消失了。

5.3 测试

(1) 先解除写保护,在串口中输入:protect off all
(2) 输入:flinfo;打印正常:
在这里插入图片描述
(3) 输入:erase 80000 8ffff
在这里插入图片描述
(4) 输入:cp.b 30000000 80000 10000
在这里插入图片描述
从上图可知,NOR Flash 写成功。

(5) 测试norflash写功能的完整性:
在串口输入以下命令:

protect off all   //关闭写保护
erase 80000 8ffff
cp.b 30000000 80000 10000
md.b 80000      //显示0x80000地址的内容
md.b 30000000
cmp.b 30000000 80000 10000  //比较0x30000000地址的内容与0x80000地址的内容,比较数据长度0x10000字节

结果如下图:
在这里插入图片描述
由上图可知,NOR Flash读写测试成功。

猜你喜欢

转载自blog.csdn.net/qq_35031421/article/details/104448162