移植u-boot-2016.11到JZ2440(四:修改源码之识别NOR Flash与NAND Flash)

目录

4. 修改源码之识别NOR Flash与NAND Flash
    4.1 修改源码之识别NOR Flash

        4.1.1 分析源码之NOR Flash
        4.1.2 修改源码
        4.1.3 测试
    4.2 修改源码之识别NAND Flash
        4.2.1 分析源码之NAND Flash
        4.2.2 修改相关宏
        4.2.3 添加s3c2440_nand.c文件
        4.2.4 修改s3c2440_nand.c(drivers/mtd/nand/目录下)
            4.2.4.1 添加s3c2440_nand_select()函数
            4.2.4.2 修改board_nand_init()函数
            4.2.4.3 修改s3c24x0_hwcontrol()函数
        4.2.5 解决编译错误
        4.2.6 测试


4. 修改源码之识别NOR Flash与NAND Flash

4.1 修改源码之识别NOR Flash

    只有当ubootNOR Flash启动时,NOR Flash才能被检测到。   
    经过上一节移植u-boot-2016.11到JZ2440(三:修改源码之实现NOR启动与NAND启动)的修改后,再将include/configs/jz2440.h中打开DEBUG调试(添加#define DEBUG重新编译(此时的uboot有0x805ae大小,烧写时注意大小)烧到NOR Flash(使用上一节3.2.3.3 测试里的烧写方式),开发板NOR启动后串口有如下输出:
       

4.1.1 分析源码之NOR Flash

    查找源码知道“Flash:”是在第二阶段调用board_init_r()函数时循环调用init_sequence_r数组里的函数,调用到initr_flash函数时输出的,代码如下所示(common/board_r.c文件中)

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, "");
        
        ... ...
}

    显然NOR Flash大小是通过调用flash_init()函数获得的,该函数代码如下(drivers/mtd/cfi_flash.c文件中)

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))
			flash_get_size(cfi_flash_bank_addr(i), i);
		size += flash_info[i].size;
		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
                ... ...
		}
	}

	flash_protect_default();
	return (size);
}

    显然是flash_info[i].size的值不对导致返回的size不大于0出错的。进入flash_detect_legacy()函数如下:

static int flash_detect_legacy(phys_addr_t base, int banknum)
{
	flash_info_t *info = &flash_info[banknum];
 
        /* 执行if里的内容 */
	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[] = {    /* 定义两种生产厂商,AMD与INTEL */
				CFI_CMDSET_AMD_STANDARD,
				CFI_CMDSET_INTEL_STANDARD
			};
			int i;
                        /* 循环两次 */
			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); 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) {
					info->addr_unlock1 = 0x2AAA;
					info->addr_unlock2 = 0x5555;
				} else {
					info->addr_unlock1 = 0x5555;
					info->addr_unlock2 = 0x2AAA;
				}
				flash_read_jedec_ids(info);    /* 读取芯片ID信息 */
				debug("JEDEC PROBE: ID %x %x %x\n",
						info->manufacturer_id,
						info->device_id,
						info->device_id2);
                                /* 使用jedec规范,通过ID比较是否支持该NOR Flash */
				if (jedec_flash_match(info, info->start[0]))
					break;
				else
					unmap_physmem((void *)info->start[0],
						      MAP_NOCACHE);
			}
		}
                ... ...
		info->flash_id = FLASH_MAN_CFI;
		return 1;
	}
	return 0; /* use CFI */
}

    显然输出的JEDEC PROBE: ID c2 2249 0信息是在这里打印的,含义分别为机器ID:c2,设备ID:2249(flash_read_jedec_ids函数里读取ID,具体的读ID过程看十八、Linux驱动之nor flash驱动,然后调用jedec_flash_match()函数使用jedec规范匹配NOR Flash,源码里该函数对开发板使用的NOR Flash没有匹配成功,返回值为0,进行第二次for循环。
    jedec_flash_match()函数代码如下:

int jedec_flash_match(flash_info_t *info, ulong base)
{
	int ret = 0;
	int i;
	ulong mask = 0xFFFF;
	if (info->chipwidth == 1)
		mask = 0xFF;

        /* 与jedec_table数组的成员比较机器ID、设备ID,匹配成功则调用fill_info填充到flash_info_t结构体 */
	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);    /* 填充info */
			ret = 1;
			break;
		}
	}
	return ret;
}

    与jedec_table全局数组的成员比较机器ID、设备ID,匹配成功则调用fill_info()函数填充该数组成员到flash_info_t结构体,其中就包括info->size的填充,这样最终flash_init()函数里的size += flash_info[i].size就会大于0,否则uboot就会打印错误信息并进入死循环。

4.1.2 修改源码

    显然源码jedec_table全局数组里没有与之前读到的ID信息匹配项,所以没有调用fill_info()函数,接下来便向jedec_table[]数组里添加我们的NOR Flash:MT29LV160DB芯片相关信息(drivers/mtd/jedec_flash.c文件中)

/*MX29LV160DB*/
    {
		.mfr_id         = (u16)MX_MANUFACT,        /* 厂家ID0x00C200C2 (读nor,便是0xc2) */
		.dev_id         = 0x2249,                  /* 设备ID */
		.name           = "MXIC MX29LV160DB",
		.uaddr          = {
		   [1] = MTD_UADDR_0x0555_0x02AA     /* 数组[1]表示是16位nor,解锁地址为:0x555,0x2AA */
		},
		.DevSize        = SIZE_2MiB,
		.CmdSet         = P_ID_AMD_STD,
		.NumEraseRegions= 4,         /* 4种不同的扇区规格 */
		.regions        = {
			ERASEINFO(16*1024, 1),	 /*描述扇区大小,扇区个数 */
			ERASEINFO(8*1024, 2),
			ERASEINFO(32*1024, 1),
			ERASEINFO(64*1024, 31),
		}
    },

    此时重新编译烧写启动后会有错误输出“ERROR:too many flash sectors”,查找发现在fill_info()函数里有如下代码(drivers/mtd/jedec_flash.c文件中)
   
    CONFIG_SYS_MAX_FLASH_SECT宏在include/configs/jz2440.h中默认定义为19,显然小于我们jedec_table[]数组中定义的NOR Flash扇区个数,修改jz2440.h文件中宏CONFIG_SYS_MAX_FLASH_SECT的定义如下:
   
    可以再把之前定义的DEBUG调试宏去掉。

4.1.3 测试

    重新编译,按照上一节3.2.3.3 测试内容进行烧写新ubootNOR Flash,重新NOR启动开发板,串口输出如下:
   
    正确识别出了NOR Flash,并且进入了命令行操作。输入“flinfo”命令如下:
   
    可以看到已经正确读出NOR Flash的信息了,再输入以下命令测试NOR Flash
      protect off all
      erase 90000 +7ffff
      cp.b 30000000 90000 1000   
//烧写在另一个位置
      cmp.b 30000000 90000 1000      //比较是否读写正确
   
效果如下:
   

4.2 修改源码之识别NAND Flash

    下面开始修改源码使U-Boot能识别出NAND Flash

4.2.1 分析源码之NAND Flash

    查找源码知道“NAND:”是在第二阶段调用board_init_r()函数时循环调用init_sequence_r数组里的函数,调用到initr_nand函数时输出的,代码如下所示(common/board_r.c文件中)

static int initr_nand(void)
{
	puts("NAND:  ");
	nand_init();
	return 0;
}

    nand_init函数去掉无用代码后如下(drivers/mtd/nand/nand.c文件中)

#define CONFIG_SYS_MAX_NAND_DEVICE	1    /* jz2440.h中定义 */

/* drivers/mtd/nand/nand.c文件中 */
static unsigned long total_nand_size;    /* total_nand_size初始化为0 */

void nand_init(void)
{
	int i;

	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
		nand_init_chip(i);

	printf("%lu MiB\n", total_nand_size / 1024);
}

    显然通过nand_init_chip函数得到NAND Flash大小,然后打印出来,进入该函数如下(drivers/mtd/nand/nand.c文件中)

static void nand_init_chip(int i)
{
	struct nand_chip *nand = &nand_chip[i];
	struct mtd_info *mtd = nand_to_mtd(nand);
	ulong base_addr = base_address[i];
	int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;

	if (maxchips < 1)
		maxchips = 1;

	nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;

	if (board_nand_init(nand))    /* 单板NAND Flash初始化 */
		return;

	if (nand_scan(mtd, maxchips))
		return;

	nand_register(i, mtd);
}

    其中调用的board_nand_init函数定义在drivers/mtd/nand/s3c2410_nand.c文件中,显然该文件里的函数只支持s3c2410,下面开始修改源码。

4.2.2 修改相关宏

    S3C2440S3C2410NAND Flash上区别较大,首先修改单板配置头文件如下(include/configs/jz2440.h文件中)
   
    在jz2440.h文件中去掉宏CONFIG_NAND_S3C2410CONFIG_SYS_S3C2410_NAND_HWECC,添加宏CONFIG_NAND_S3C2440

4.2.3 添加s3c2440_nand.c文件

    拷贝drivers/mtd/nand/s3c2410_nand.cs3c2440_nand.c到同目录,同时修改该目录下的Makefile如下:
   
    作用是将编译s3c2410_nand.c文件选项改成编译s3c2440_nand.c文件

4.2.4 修改s3c2440_nand.c(drivers/mtd/nand/目录下)

4.2.4.1 添加s3c2440_nand_select()函数

    在board_nand_init()函数前添加s3c2440_nand_select()函数,函数代码如下:

static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

	switch (chipnr) {
	case -1:  //取消选择
		nand->nfcont |= (1<<1);
	break;
	case 0:   /*选中*/
		nand->nfcont&=~(1<<1);
		break;

	default:
		BUG();
	}
}

4.2.4.2 修改board_nand_init()函数

    board_nand_init()函数修改如下:
    1. 将如下代码:
 
    改为(修改时序)

	cfg= (tacls-1<<12)|(twrph0-1<<8)|(twrph1-1<<4);
	writel(cfg, &nand_reg->nfconf);
	writel((1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont);

    2. 将如下代码:   
  
    改为(指定片选函数)
   

4.2.4.3 修改s3c24x0_hwcontrol()函数

    修改s3c24x0_hwcontrol()函数如下:

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
    struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

    if (ctrl & NAND_CLE) {
        /* 发命令 */
        writeb(cmd, &nand->nfcmd);
    }
    else if (ctrl & NAND_ALE) {
        /* 发地址 */
        writeb(cmd, &nand->nfaddr);
    }
}

4.2.5 解决编译错误

    重新编译,有如下错误:

Error: You must add new CONFIG options using Kconfig
The following new ad-hoc CONFIG options were detected:
CONFIG_NAND_S3C2440

Please add these via Kconfig instead. Find a suitable Kconfig
file and add a 'config' or 'menuconfig' option.
make: *** [all] Error 1

    在源码搜索CONFIG_NAND_S3C2410如下(grep -nR "CONFIG_NAND_S3C2410" *):
   
    我们修改了宏CONFIG_NAND_S3C2410CONFIG_NAND_S3C2440,同样将该宏修改到scripts/config_whitelist.txt文件,重新编译,成功。

4.2.6 测试

    按照上一节的3.3.7 测试NAND Flash启动内容进行烧写新ubootNAND FlashNAND启动开发板,串口输出如下:
   
    可以看到NAND启动时,NOR Flash无效,识别出了NAND Flash。输入以下命令测试NAND Flash
      nand erase 0 2000     //擦除nand flash 0~2000地址
      mw.b 30000000 0x55 2000    //写2000个0x55到30000000地址
      nand write 30000000 0 2000    //将30000000地址数据写入nand flash的0地址,大小为2000
      nand dump 0 2000    //打印
   
串口打印如下:
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值