norflash 分析

        norflash 是一种xip(eXecute In Place结构,类似于sdram),读的速度自然比nandflash快很多,可以在norflash上执行相关程序,但是不能执行写操作(要发一些列写操作命令才能执行)。 

       以s3c2440为例,讲述norflash操作及启动过程。norflash接在片选0上,从cpu看到的地址0启动。

      norflash 分析_第1张图片

然后了解硬件原理图连接:

可以看到norflash 是16位数据总线,cpu每读一次读取16位数据。

norflash 分析_第2张图片

cpu和norflash连接方法:注意cpu的A0没有连接(因为norfalsh数据线是16位的,cpu发一个地址,norfalsh会一次返回16bit数据)。ARM处理器的每个地址对应的是一个BYTE 的数据单元,而 16-BIT 的 FLASH 的每个地址对应的是一个HALF-WORD(16-BIT)的数据单元.为了保持匹配,所以必须错位连接.这样,从ARM处理器发送出来的地址信号的最低位A0对16-BIT FLASH来说就被屏蔽掉了。

norflash 分析_第3张图片

1.实现浏览norflash信息,如厂家ID,设备ID,regions,blocks(或者sections,一个regions含有多个blocks)。

注意linux driver分为两种确定flash类型方式:

jedec:通过命令获取flash厂家id和设备ID,并和开始已经定义好的数组进行比较。来获取flash类型。

cfi:(common flash interface):通过特殊命令获取flash类型,大小等信息。注意下面地址是相对于norflash来看的。

norflash 分析_第4张图片norflash 分析_第5张图片

void do_scan_nor_flash(void)
{
	char str[4];
	unsigned int size;
	int regions, i;
	int region_info_base;
	int block_addr, blocks, block_size, j;
	int cnt;

	int vendor, device;
	
	/* 打印厂家ID、设备ID */
	nor_cmd(0x555, 0xaa);    /* 解锁 */
	nor_cmd(0x2aa, 0x55); 
	nor_cmd(0x555, 0x90);    /* read id */
	vendor = nor_dat(0);
	device = nor_dat(1);
	nor_cmd(0, 0xf0);        /* reset */
	
	nor_cmd(0x55, 0x98);  /* 进入cfi模式 */

	str[0] = nor_dat(0x10);
	str[1] = nor_dat(0x11);
	str[2] = nor_dat(0x12);
	str[3] = '\0';
	printf("str = %s\n\r", str);

	/* 打印容量 */
	size = 1<<(nor_dat(0x27));
	printf("vendor id = 0x%x, device id = 0x%x, nor size = 0x%x, %dM\n\r", vendor, device, size, size/(1024*1024));

	/* 打印各个扇区的起始地址 */
	/* 名词解释:
	 *    erase block region : 里面含有1个或多个block, 它们的大小一样
	 * 一个nor flash含有1个或多个region
	 * 一个region含有1个或多个block(扇区)

	 * Erase block region information:
	 *    前2字节+1    : 表示该region有多少个block 
	 *    后2字节*256  : 表示block的大小
	 */

	regions = nor_dat(0x2c);
	region_info_base = 0x2d;
	block_addr = 0;
	printf("Block/Sector start Address:\n\r");
	cnt = 0;
	for (i = 0; i < regions; i++)
	{
		blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8);
		block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8));
		region_info_base += 4;

//		printf("\n\rregion %d, blocks = %d, block_size = 0x%x, block_addr = 0x%x\n\r", i, blocks, block_size, block_addr);

		for (j = 0; j < blocks; j++)
		{
			/* 打印每个block的起始地址 */
			//printf("0x%08x ", block_addr);
			printHex(block_addr);
			putchar(' ');
			cnt++;
			block_addr += block_size;
			if (cnt % 5 == 0)
				printf("\n\r");
		}
	}
	printf("\n\r");
	/* 退出CFI模式 */
	nor_cmd(0, 0xf0);
}

2.擦除norflash

flash要擦除的话都是以blocks为单位,解锁后输入blocks起始地址(按照上面打印),然后扇区全部变为ff,写的话只能写0。

判断是否擦除完或者写完方法。如果没有擦除完Q6(data bit6)会一直不停的反转,当停止反转后,也就是当前和上一次一样的值,表示擦除完成。(时序怎么考虑?

norflash 分析_第6张图片

一直疑惑要不要考虑时序,继续看下kernel MTD实现代码,也是直接读两次比较。

norflash 分析_第7张图片

void wait_ready(unsigned int addr)
{
	unsigned int val;
	unsigned int pre;

	pre = nor_dat(addr>>1);
	val = nor_dat(addr>>1);
	while ((val & (1<<6)) != (pre & (1<<6)))
	{
		pre = val;
		val = nor_dat(addr>>1);		
	}
}

void do_erase_nor_flash(void)
{
	unsigned int addr;
	
	/* 获得地址 */
	printf("Enter the address of sector to erase: ");
	addr = get_uint();

	printf("erasing ...\n\r");
	nor_cmd(0x555, 0xaa);    /* 解锁 */
	nor_cmd(0x2aa, 0x55); 
	nor_cmd(0x555, 0x80);	 /* erase sector */
	
	nor_cmd(0x555, 0xaa);    /* 解锁 */
	nor_cmd(0x2aa, 0x55); 
	nor_cmd(addr>>1, 0x30);	 /* 发出扇区地址 */
	wait_ready(addr);
}

3.norflash写操作

norflash写只能把1写成0,也就是写之前必须把扇区擦除才能写,所以这点看来,flash永远是flash,不能顶替内存。

norflash 分析_第8张图片

void do_write_nor_flash(void)
{
	unsigned int addr;
	unsigned char str[100];
	int i, j;
	unsigned int val;
	
	/* 获得地址 */
	printf("Enter the address of sector to write: ");
	addr = get_uint();

	printf("Enter the string to write: ");
	gets(str);

	printf("writing ...\n\r");

	/* str[0],str[1]==>16bit 
	 * str[2],str[3]==>16bit 
	 */
	i = 0;
	j = 1;
	while (str[i] && str[j])
	{
		val = str[i] + (str[j]<<8);
		
		/* 烧写 */
		nor_cmd(0x555, 0xaa);	 /* 解锁 */
		nor_cmd(0x2aa, 0x55); 
		nor_cmd(0x555, 0xa0);	 /* program */
		nor_cmd(addr>>1, val);
		/* 等待烧写完成 : 读数据, Q6无变化时表示结束 */
		wait_ready(addr);

		i += 2;
		j += 2;
		addr += 2;
	}

	val = str[i];
	/* 烧写 */
	nor_cmd(0x555, 0xaa);	 /* 解锁 */
	nor_cmd(0x2aa, 0x55); 
	nor_cmd(0x555, 0xa0);	 /* program */
	nor_cmd(addr>>1, val);
	/* 等待烧写完成 : 读数据, Q6无变化时表示结束 */
	wait_ready(addr);
}

部分参考:

http://www.cnblogs.com/jason-lu/archive/2013/03/13/2957399.html

 

你可能感兴趣的:(uboot)