1. 程式人生 > >移植U-BOOT-2016.11到JZ2440詳細教程(5)

移植U-BOOT-2016.11到JZ2440詳細教程(5)

讓U-boot支援Nor Flash

這節的移植應該是最簡單的,修改程式碼量最少。但是我們還是要對原始碼進行一個簡單的分析。 在這裡插入圖片描述 首先緊接上一節最後的那張圖,我們已經讓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就行了。

修改完檔案,我們重新編譯並下載到開發板後可以在串列埠看到這個資訊: 在這裡插入圖片描述 查一下我們的晶片手冊,發現我們使用的晶片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已經識別出Nor Flash的大小了,再試一下是不是能用,使用flinfo,列印一下Nor Flash資訊。 在這裡插入圖片描述 取消防寫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傳送功能在這個地方: 在這裡插入圖片描述 把檔案下載到0x30000000開始的地址

loady 30000000		

然後馬上用ymodem傳送檔案,這個過程一定要快,不然容易失敗。 後面就跟之前的USB燒錄一樣,解除保護,擦除,拷貝:

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

後續

注意:這邊的補丁檔案只是相對於上一節的u-boot,直接下載下來的u-boot打這個補丁是沒有用的。