移植U-BOOT-2016.11到JZ2440详细教程(5)

让U-boot支持Nor Flash

这节的移植应该是最简单的,修改代码量最少。但是我们还是要对源码进行一个简单的分析。
移植U-BOOT-2016.11到JZ2440详细教程(5)_第1张图片
首先紧接上一节最后的那张图,我们已经让U-boot可以从Nand Flash启动,然后打印出来的调试信息中Flash: 对应的就是Nor Flash的大小,NAND: 就是NAND FALSH的大小。这里发现NAND居然能识别出大小,但是如果我换为Nor启动以后,NAND就又识别不出来了,这边我们先不管他,这节主要还是针对Nor Flash。
首先查一下“Flash:”是在哪里打印的,然后经过分析我们可以得到一下函数调用关系:

注意:以下函数内都经过删减方便分析,只是分析,不需要修改代码

\common\board_r.c,第370行

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

	puts("Flash: ");			//在这里打印了"Flash: "字符串

	if (board_flash_wp_on())
		printf("Uninitialized - Write Protect On\n");
	else
		flash_size = flash_init();		//下一步函数调用

	print_size(flash_size, "");
	putc('\n');

	/* update start of FLASH memory    */
#ifdef CONFIG_SYS_FLASH_BASE
	bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;	//设置Nor Flash基地址也就是0x00000000
#endif
	/* size of FLASH memory (final value) */
	bd->bi_flashsize = flash_size;

#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;
}

我们查找“Flash:”字符串,然后定位到这个函数,接着这个函数调用flash_init();对Flash初始化和识别

\drivers\mtd\cfi_flash.c,第2348行

unsigned long flash_init (void)
{
	unsigned long size = 0;
	int i;
	/* 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))	//如果这种方法检测不出Nor Flash,再使用下一种flash_get_size检测
			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
			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 */
		}
	}
	flash_protect_default();		//恢复Nor Flash保护状态
	return (size);
}

我们先进第一种检测方法的函数看一下,是否能识别我们的Nor Flash。

\drivers\mtd\cfi_flash.c,第1783行

static int flash_detect_legacy(phys_addr_t base, int banknum)
{
	flash_info_t *info = &flash_info[banknum];

	if (board_flash_get_legacy(base, banknum, info)) {
		/* board code may have filled info completely. If not, we
		   use JEDEC ID probing. */
		if (!info->vendor) {
			int modes[] = {
				CFI_CMDSET_AMD_STANDARD,		//AMD公司标准识别模式
				CFI_CMDSET_INTEL_STANDARD		//Inter公司标准识别模式
			};
			int i;

			for (i = 0; i < ARRAY_SIZE(modes); i++) {
				info->vendor = modes[i];
				info->start[0] =
					(ulong)map_physmem(base,
							   info->portwidth,
							   MAP_NOCACHE);
				if (info->portwidth == FLASH_CFI_8BIT
					&& info->interface == FLASH_CFI_X8X16) {		//根据线宽设置解锁地址,我们的线宽是16位,所以解锁地址按照else里面的设置
					info->addr_unlock1 = 0x2AAA;
					info->addr_unlock2 = 0x5555;
				} else {
					info->addr_unlock1 = 0x5555;
					info->addr_unlock2 = 0x2AAA;
				}
				flash_read_jedec_ids(info);					//读厂家ID,设备ID
				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]))	//如果匹配则退出循环,不匹配就按照上面modes[]里面的模式分别读取ID
					break;
				else
					unmap_physmem((void *)info->start[0],
						      info->portwidth);
			}
		}

		switch(info->vendor) {				//根据芯片设置reset指令集
		case CFI_CMDSET_INTEL_PROG_REGIONS:
		case CFI_CMDSET_INTEL_STANDARD:
		case CFI_CMDSET_INTEL_EXTENDED:
			info->cmd_reset = FLASH_CMD_RESET;
			break;
		case CFI_CMDSET_AMD_STANDARD:
		case CFI_CMDSET_AMD_EXTENDED:
		case CFI_CMDSET_AMD_LEGACY:
			info->cmd_reset = AMD_CMD_RESET;
			break;
		}
		info->flash_id = FLASH_MAN_CFI;
		return 1;
	}
	return 0; /* use CFI */
}

这边有一个debug打印调试信息的语句,我们可以先把调试信息打开看一下。要想看打印信息,我们只需要在include\common.h 文件最上方定义一个宏#define DEBUG就行了。

修改完文件,我们重新编译并下载到开发板后可以在串口看到这个信息:
移植U-BOOT-2016.11到JZ2440详细教程(5)_第2张图片
查一下我们的芯片手册,发现我们使用的芯片MX29LV160DB他的ID就是2249,跟打印出来信息一致。
在这里插入图片描述
那么下面另外一个ID be ea00 0是什么意思。记不记得我们上面设置了两种读取方式,一种是ADM标准一种是Inter标准。虽然我们正确读取出了ID但是没有匹配上,for循环就按照Inter的标准接着执行了一次读取ID命令,读出了乱码。
下一步我们就要进入jedec_flash_match函数看一下,为什么匹配不成功。

\drivers\mtd\jedec_flash.c,第493行

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

这个函数的主要功能就是把读取上来得厂家ID和设备ID跟jedec_table数组里的结构体比较,如果全部匹配,那么就把信息填进去,返回成功。
所以我们现在的工作就是在jedec_table数组里面添加一个我们芯片的结构体。

	},
#endif
    {
		.mfr_id		= (u16)MX_MANUFACT,     //厂家ID
		.dev_id		= AM29LV160DB,          //设备ID
		.name		= "MXIC MX29LV160DB",   //名称(自定)
		.uaddr		= {
			[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
		},
		.DevSize	= SIZE_2MiB,            //总大小
		.CmdSet		= P_ID_AMD_STD,         //或者 CFI_CMDSET_AMD_LEGACY 两个宏是一样的
		.NumEraseRegions= 4,
		.regions	= {
			ERASEINFO(0x04000, 1),
            ERASEINFO(0x02000, 2),
            ERASEINFO(0x08000, 1),
            ERASEINFO(0x10000, 31),
		}
	},
};

这个版本跟韦东山老师移植的版本不同的就是把芯片MX29LV160DB的厂家ID和设备ID都定义了出来,我们直接调用就好了。
然后是NumEraseRegionsregions两项分别代表的意思是扇区的种类,以及扇区的大小及个数。这两个项我们就要查一下芯片手册上面的数据。
在这里插入图片描述
由芯片手册我们可以看到16K的扇区有1块,那么就是ERASEINFO(0x04000, 1),,8K的扇区有2块,那么就是ERASEINFO(0x02000, 2), 后面同理。
添加完我们自己芯片的结构体以后,再修改一下.h文件中最大扇区数,不然串口到时候会打印警告。
\include\configs\smdk2440.h,第136行

#define CONFIG_SYS_MAX_FLASH_SECT	(128)

这样我们就都修改好了,然后把DEBUG关了,重新编译烧到开发板上验证一下。
移植U-BOOT-2016.11到JZ2440详细教程(5)_第3张图片

现在U-boot已经识别出Nor Flash的大小了,再试一下是不是能用,使用flinfo,打印一下Nor Flash信息。
移植U-BOOT-2016.11到JZ2440详细教程(5)_第4张图片
取消写保护protect off all
在这里插入图片描述
擦除80000~90000之间的数据erase 80000 8ffff
在这里插入图片描述
复制SDRAM 0x30000000地址起10000个字节到Nor Flash地址0x80000cp.b 30000000 80000 10000

在这里插入图片描述
比较两者之间的数据cmp.b 30000000 80000 10000
在这里插入图片描述
两者数据完全一样,到这里我们的移植的完成了,而且这版的修复了2012版中的SP栈BUG,这个BUG曾经导致0x300000000~0x30001000之间的地址只能读不能写,不然程序会蹦,这是因为那一版的程序,在进入第二阶段之前把gd等数据搬到新地址,却没有重新设置SP,导致SP还是指向0x30001000。
这版是怎么修复这个BUG的可以看一下arch\arm\lib\crt0.S第118行。

新的烧写方式

当U-boot支持Nor Flash以后我们就可以通过ymodem协议烧写U-boot。一般现在的工具都支持Ymodem传输,只要稍微找一下都可以看到,这边推荐用工具Xshell 5,免费的而且有中文版,安装包我会放在文末的链接,ymodem发送功能在这个地方:
移植U-BOOT-2016.11到JZ2440详细教程(5)_第5张图片
把文件下载到0x30000000开始的地址

loady 30000000		

然后马上用ymodem发送文件,这个过程一定要快,不然容易失败。
后面就跟之前的USB烧录一样,解除保护,擦除,拷贝:

protect off all
erase 0 7ffff
cp.b 30000000 0 80000

后续

推荐一个下载芯片手册的网址:链接: [http://datasheet.eeworld.com.cn/]。

补丁yizhi_4和Xshell 5安装包
链接:https://pan.baidu.com/s/1v85_5VApVgmMG9IXrwgCiQ
提取码:bb6y

注意:这边的补丁文件只是相对于上一节的u-boot,直接下载下来的u-boot打这个补丁是没有用的。

你可能感兴趣的:(移植u-boot,2016.11)