移植uboot第五步:支持NORFlash
寫在前面:
我的博客已遷移至自建服務器:博客傳送門,CSDN博客暫時停止,如有機器學習方面的興趣,歡迎來看一看。
此外目前我在gitHub上準備一些李航的《統計學習方法》的實現算法,目標將書內算法全部手打實現,歡迎參觀并打星。GitHib傳送門
正文
之前已經將板子設為NAND啟動了,但這只是能從NANDcopy代碼,不代表板子就支持了以后對NANDFlash的讀寫操作。
啟動板子以后輸出信息:
其中說明了Flash: *** failed ***,表示確實flash沒有支持。
一. 復制這個錯誤到到SI中搜索,結果如下:
#if !defined(CONFIG_SYS_NO_FLASH)puts("Flash: ");flash_size = flash_init();if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUMchar *s = getenv("flashchecksum");print_size(flash_size, "");/** Compute and print flash CRC if flashchecksum is set to 'y'** NOTE: Maybe we should add some WATCHDOG_RESET()? XXX*/if (s && (*s == 'y')) {printf(" CRC: %08X", crc32(0,(const unsigned char *) CONFIG_SYS_FLASH_BASE,flash_size));}putc('\n'); # else /* !CONFIG_SYS_FLASH_CHECKSUM */print_size(flash_size, "\n"); # endif /* CONFIG_SYS_FLASH_CHECKSUM */} else {puts("0 KB\n\r");puts(failed);hang();} #endif可以知道是if語句不成立,導致輸出failed,也就是說讀取flash大小的時候flash_size值為0。
先把這兩句話注釋掉
puts(failed); hang(); //表示阻塞中,程序到這里就死循環進入nand初始化函數flash_init();
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;這里可以看到Flash的大小是由size 這個變量決定的。
進入flash_get_size(),看到里面有一些debug
這些debug的開關是宏定義的,因此在文件上的上端
#define DEBUG #define _DEBUG 1因為不知道具體他們編寫的時候DEBUG是什么格式,因此兩種都寫了
編譯,燒寫。
Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit fwc addr 00005554 cmd 55 0055 16bit x 16 bit fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit fwc addr (null) cmd f0 00f0 16bit x 16 bit JEDEC PROBE: ID c2 2249 0 fwc addr (null) cmd ff 00ff 16bit x 16 bit fwc addr (null) cmd 90 0090 16bit x 16 bit fwc addr (null) cmd ff 00ff 16bit x 16 bit JEDEC PROBE: ID 13 ea00 0二. JEDEC PROBE: ID c2 2249 0 這句話其中的c2表示廠家ID,2249表示機器ID。查閱NORFlash手冊,發現這兩個ID是正確的,但是沒有檢測到,說明程序底層驅動是對的,但是板子沒支持這個NOR。搜索JEDEC PROBE:
flash_read_jedec_ids(info); 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; elseunmap_physmem((void *)info->start[0], MAP_NOCACHE);進入jedec_flash_match函數:
/*-----------------------------------------------------------------------* match jedec ids against table. If a match is found, fill flash_info entry*/ 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_table數組查看:
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 #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8{.mfr_id = (u16)AMD_MANUFACT,.dev_id = AM29LV040B,.name = "AMD AM29LV040B",.uaddr = {[0] = MTD_UADDR_0x0555_0x02AA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000,8),}},{.mfr_id = (u16)SST_MANUFACT,.dev_id = SST39LF040,.name = "SST 39LF040",.uaddr = {[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x01000,128),}},{.mfr_id = (u16)STM_MANUFACT,.dev_id = STM_ID_M29W040B,.name = "ST Micro M29W040B",.uaddr = {[0] = MTD_UADDR_0x0555_0x02AA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000,8),}},{.mfr_id = (u16)MX_MANUFACT,.dev_id = MX29LV040,.name = "MXIC MX29LV040",.uaddr = {[0] = MTD_UADDR_0x0555_0x02AA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000, 8),}},{.mfr_id = (u16)WINB_MANUFACT,.dev_id = W39L040A,.name = "WINBOND W39L040A",.uaddr = {[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000, 8),}},{.mfr_id = (u16)AMIC_MANUFACT,.dev_id = A29L040,.name = "AMIC A29L040",.uaddr = {[0] = MTD_UADDR_0x0555_0x02AA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000, 8),}},{.mfr_id = (u16)EON_MANUFACT,.dev_id = EN29LV040A,.name = "EON EN29LV040A",.uaddr = {[0] = MTD_UADDR_0x0555_0x02AA /* x8 */},.DevSize = SIZE_512KiB,.CmdSet = P_ID_AMD_STD,.NumEraseRegions= 1,.regions = {ERASEINFO(0x10000, 8),}}, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16{.mfr_id = (u16)AMD_MANUFACT,.dev_id = AM29F400BB,.name = "AMD AM29F400BB",.uaddr = {[1] = MTD_UADDR_0x0555_0x02AA /* x16 */},.DevSize = SIZE_512KiB,.CmdSet = CFI_CMDSET_AMD_LEGACY,.NumEraseRegions= 4,.regions = {ERASEINFO(0x04000, 1),ERASEINFO(0x02000, 2),ERASEINFO(0x08000, 1),ERASEINFO(0x10000, 7),}},{.mfr_id = (u16)AMD_MANUFACT,.dev_id = AM29LV400BB,.name = "AMD AM29LV400BB",.uaddr = {[1] = MTD_UADDR_0x0555_0x02AA /* x16 */},.DevSize = SIZE_512KiB,.CmdSet = CFI_CMDSET_AMD_LEGACY,.NumEraseRegions= 4,.regions = {ERASEINFO(0x04000,1),ERASEINFO(0x02000,2),ERASEINFO(0x08000,1),ERASEINFO(0x10000,7),}},{.mfr_id = (u16)AMD_MANUFACT,.dev_id = AM29LV800BB,.name = "AMD AM29LV800BB",.uaddr = {[1] = MTD_UADDR_0x0555_0x02AA /* x16 */},.DevSize = SIZE_1MiB,.CmdSet = CFI_CMDSET_AMD_LEGACY,.NumEraseRegions= 4,.regions = {ERASEINFO(0x04000, 1),ERASEINFO(0x02000, 2),ERASEINFO(0x08000, 1),ERASEINFO(0x10000, 15),}},{.mfr_id = (u16)STM_MANUFACT,.dev_id = STM29F400BB,.name = "ST Micro M29F400BB",.uaddr = {[1] = MTD_UADDR_0x0555_0x02AA /* x16 */},.DevSize = SIZE_512KiB,.CmdSet = CFI_CMDSET_AMD_LEGACY,.NumEraseRegions = 4,.regions = {ERASEINFO(0x04000, 1),ERASEINFO(0x02000, 2),ERASEINFO(0x08000, 1),ERASEINFO(0x10000, 7),}}, #endif };查詢以后發現,確實是這里面沒有我們所使用的NORFlash。
進入機器ID的宏定義代碼,里面找到了這個:
C2就是我們使用的NORFlash,說明uboot是能夠支持的,只是數組中沒有將其寫入。更改數組,加入我們自己的NORflash,使其能夠支持。
因為數組中有宏定義,我也不打算破壞它的結構了,隨便復制了一個將其粘貼到數組的最后端,#endif的下面。
a.將廠家ID:mfr_id修改為MX_MANUFACT,
b.機器ID:dev_id修改為0x2249,
c.名字:name修改為"MXIC MT29LV160DB"
uaddr解鎖地址改為[1] = MTD_UADDR_0x0555_0x02AA /* x16 */ /*NOR flash 解鎖地址 */
[0]表示NOR是8位的,我使用的是16位的,因此改為1。NORFlash使用的時候會鎖定,因此寫的時候要先解鎖,在一些地址中寫入值才能解鎖。解鎖地址可以查閱手冊。
d.大小:DevSize修改為SIZE_2MiB
e.NumEraseRegions改為4。
NOR的結構不同,擦除塊是不同的,例如一個flash可能分成了十塊,每塊128kb,也有可能一個flash前十塊是128kb,后十塊是256kb,可以查閱手冊,有多少種塊,就寫幾,我使用的NOR有4中,分別8字節2塊,16字節1塊,32字節1塊,64字節31塊。
f.
regions = {ERASEINFO(0x01000,64),}修改為:
.regions = {ERASEINFO(16 * 1024 , 1),ERASEINFO(8 * 1024 , 2),ERASEINFO(32 * 1024 , 1),ERASEINFO(64 * 1024 , 31), }這個就是說明擦除塊的分布情況,從上往下分別是NOR中地址從低到高排布。
make,燒寫,運行。
出現警告,說擦除塊太多。查看以后是宏定義值為19,值小于我們的擦除塊數量,將其修改為128。 其實這個值多少都可以,只要大于使用的擦除塊就行了。
三. 調試時出現一個bug,對移植來說關聯不大,但是很有可能在以后造成錯誤,這里就把它修改一下。
重定位的時候東西都移了,但是棧指針沒有修改,要重新設置棧,否則所有的東西都在0x33F00000,只有棧在0x30000000,在0x33F00000之前是考慮空出來了一塊區域給棧用的,現在沒有重新定位棧,導致都沒有用。程序能跑,但是這樣的話,要時刻小心不能使用0x30000000之后的這塊區域,否則修改到變量了,uboot很有可能會死。
在start.S中設置一個全局變量
board_init_f函數本質上是一個計算uboot存放位置的函數,在這里可以找到為棧設置的地址。
base_sp = addr_sp;在重定位代碼以后,將棧指針重新設置
ldr r1, _TEXT_BASE ldr sp, base_sp /* 重新設置棧 *//* 調用第二階段代碼 */ bl board_init_r編譯,燒寫,運行。
U-Boot 2012.04.01 (Aug 12 2016 - 00:17:17)CPUID: 32440001 FCLK: 400 MHz HCLK: 100 MHz PCLK: 50 MHz DRAM: 64 MiB WARNING: Caches not enabled Flash: fwc addr (null) cmd f0 00f0 16bit x 16 bit fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit fwc addr 00005554 cmd 55 0055 16bit x 16 bit fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit fwc addr (null) cmd f0 00f0 16bit x 16 bit JEDEC PROBE: ID c2 2249 0 2 MiB *** Warning - bad CRC, using default environmentIn: serial Out: serial Err: serial Net: CS8900-0 SMDK2410 #成功了
總結
以上是生活随笔為你收集整理的移植uboot第五步:支持NORFlash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移植uboot第四步:设置NAND启动
- 下一篇: 移植uboot第六步:支持NANDFla