UBOOT中可以對NOR FLASH進行操作,預設情況下是開啟了CONFIG_CMD_FLASH這個宏的。這個宏支援flinfo(列印flash資訊)、erase(擦除資料)和protect(保護)這幾個指令,cp指令的NOR FLASH操作部分也會得到支援(将資料從記憶體複制到NOR FLASH)。UBOOT中各個闆子的NOR FLASH的操作都是自己實作的。不過TQ2440和SMDK2410在這方面差距不大,SMDK2410的flash.c可以直接被TQ2440使用,隻需要修改一些宏參數即可。
首先來看看如何在配置頭檔案中支援NOR FLASH的相關宏參數。
CONFIG_SYS_MAX_FLASH_BANKS——這個參數指明系統中有幾個FLASH,TQ2440隻有1個。
CONFIG_SYS_MAX_FLASH_SECT——這個參數指明該FLASH中有好多個段,需要自己在晶片資料中查找,TQ2440用的NOR FLASH一共有19個段。
CONFIG_SYS_FLASH_ERASE_TOUT——指定擦除操作逾時限制。
CONFIG_SYS_FLASH_WRITE_TOUT——指定寫操作逾時限制。
PHYS_FLASH_SIZE——指定NOR FLASH的尺寸
上面的宏,基本上包含描述一個NOR FLASH所必須的參數。當然,不同的闆子對其的定義還會有一些差别,在TQ2440中是夠用了。如果以後需要自己寫相關的支援代碼還是需要按照上面提供的思路來。
下面這些是用于配置NOR FLASH中帶有環境變量的情況下所用的宏。如果配置了環境變量在NOR FLASH中,需要加上這個宏(不過SMDK2410對NOR FLASH的初始化函數實作中預設是要使用這些宏來初始化一個隻讀空間的,如果不添加上這些宏,編譯的時候會報錯,這個在熟悉了相關代碼後可以做一定的修改,現在就先保留這個配置)。
CONFIG_ENV_ADDR——指明環境變量存儲的位址(如果配置了環境變量儲存在某個)。
CONFIG_ENV_SIZE——指明環境變量存儲所占用的空間大小(記憶體開辟環境變量存儲緩沖區的時候也需要這個宏)。
對于此次移植,關于NOR FLASH部分确定晶片為 同時對flash的初始化函數做一些修改,確定其代碼編譯能更完善的被宏控制進而達到精簡的目的。
先還是來看看基于SMDK2410基礎上對NOR FLASH的宏配置進行的修改:
225
228 #if 0
229 #define CONFIG_AMD_LV400 1
230 #endif
231 #if 1
232 #define CONFIG_AMD_LV800 1
233 #endif
234
235 #define CONFIG_SYS_MAX_FLASH_BANKS 1
236 #ifdef CONFIG_AMD_LV800
237 #define PHYS_FLASH_SIZE 0x00200000
238 #define CONFIG_SYS_MAX_FLASH_SECT (19)
239 #ifdef CONFIG_ENV_IS_IN_FLASH
240 #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x1F0000)
241 #endif
242 #endif
243 #ifdef CONFIG_AMD_LV400
244 #define PHYS_FLASH_SIZE 0x00080000
245 #define CONFIG_SYS_MAX_FLASH_SECT (11)
246 #ifdef CONFIG_ENV_IS_IN_FLASH
247 #define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000)
248 #endif
249 #endif
250
251
252 #define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ)
253 #define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ)
254
255 //#define CONFIG_ENV_IS_IN_FLASH 1
256 #define CONFIG_ENV_IS_NOWHERE 1
257 #define CONFIG_ENV_SIZE 0x10000
再來看看UBOOT中對NOR FLASH的初始化函數flash_init(),這個函數的運作流程如下:
01 ulong flash_init (void)
02 {
03 int i, j;
04 ulong size = 0;
05
06 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++)
07 {
08 ulong flashbase = 0;
09
10 flash_info[i].flash_id =
11 #if defined(CONFIG_AMD_LV400)
12 (AMD_MANUFACT & FLASH_VENDMASK) |
13 (AMD_ID_LV400B & FLASH_TYPEMASK);
14 #elif defined(CONFIG_AMD_LV800)
15 (AMD_MANUFACT & FLASH_VENDMASK) |
16 (AMD_ID_LV800B & FLASH_TYPEMASK);
17 #else
18 #error "Unknown flash configured"
19 #endif
20 flash_info[i].size = FLASH_BANK_SIZE;
21 flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
22 memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
23 if (i == 0)
24 flashbase = PHYS_FLASH_1;
25 else
26 panic ("configured too many flash banks!\n");
27 for (j = 0; j < flash_info[i].sector_count; j++)
28 {
29 if (j <= 3)
30 {
31
32 if (j == 0)
33 {
34 flash_info[i].start[j] =
35 flashbase + 0;
36 }
37
38
39 if ((j == 1) || (j == 2))
40 {
41 flash_info[i].start[j] =
42 flashbase + 0x4000 + (j -
43 1) *
44 0x2000;
45 }
46
47
48 if (j == 3)
49 {
50 flash_info[i].start[j] =
51 flashbase + 0x8000;
52 }
53 }
54 else
55 {
56 flash_info[i].start[j] =
57 flashbase + (j - 3) * MAIN_SECT_SIZE;
58 }
59 }
60 size += flash_info[i].size;
61 }
62
63 flash_protect (FLAG_PROTECT_SET,
64 CONFIG_SYS_FLASH_BASE,
65 CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
66 &flash_info[0]);
67 #ifdef CONFIG_ENV_IS_IN_FLASH
68 flash_protect (FLAG_PROTECT_SET,
69 CONFIG_ENV_ADDR,
70 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
71 #endif
72
73 return size;
74 }
75
首先UBOOT确定了所使用的NOR FLASH的ID,這裡不是自動擷取,而是要自己手動。SMDK2410闆子中也就支援兩款NOR FLASH。
10 flash_info[i].flash_id =
11 #if defined(CONFIG_AMD_LV400)
12 (AMD_MANUFACT & FLASH_VENDMASK) |
13 (AMD_ID_LV400B & FLASH_TYPEMASK);
14 #elif defined(CONFIG_AMD_LV800)
15 (AMD_MANUFACT & FLASH_VENDMASK) |
16 (AMD_ID_LV800B & FLASH_TYPEMASK);
17 #else
18 #error "Unknown flash configured"
19 #endif
這裡确定了NOR FLASH的尺寸,可以看到這裡使用了宏定義。
20 flash_info[i].size = FLASH_BANK_SIZE;
這裡确定了NOR FLASH的段。
21 flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
初始化了NOR FLASH晶片的段保護辨別數組。後面可以利用這個數組來辨別哪個段是隻讀的。
22 memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
接下來要确定NOR FLASH的基位址,這裡隻允許一個NOR FLASH存在。
23 if (i == 0)
24 flashbase = PHYS_FLASH_1;
25 else
26 panic ("configured too many flash banks!\n");
然後程式進入一個循環中,手動配置設定了各個段的大小。第一段為16KB、第二三段為8KB、第四段為32KB餘下的段都為64KB,其起始位址的計算方法是flashbase + (j - 3) * MAIN_SECT_SIZE。
27 for (j = 0; j < flash_info[i].sector_count; j++)
28 {
29 if (j <= 3)
30 {
31
32 if (j == 0)
33 {
34 flash_info[i].start[j] =
35 flashbase + 0;
36 }
37
38
39 if ((j == 1) || (j == 2))
40 {
41 flash_info[i].start[j] =
42 flashbase + 0x4000 + (j -
43 1) *
44 0x2000;
45 }
46
47
48 if (j == 3)
49 {
50 flash_info[i].start[j] =
51 flashbase + 0x8000;
52 }
53 }
54 else
55 {
56 flash_info[i].start[j] =
57 flashbase + (j - 3) * MAIN_SECT_SIZE;
58 }
59 }
現在初始化流程進入了尾聲,下面就是将某些用作特殊用途的段保護起來。這樣在UBOOT中就無法擦除它們了。
首先是保護UBOOT代碼的存儲位置,該區域起始位址由CONFIG_SYS_FLASH_BASE來決定,尺寸大小monitor_flash_len = _bss_start - _armboot_start。
63 flash_protect (FLAG_PROTECT_SET,
64 CONFIG_SYS_FLASH_BASE,
65 CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
66 &flash_info[0]);
這裡做了一些修改,浏覽代碼發現這段代碼是當配置了CONFIG_ENV_IS_IN_FLASH的時候才會有意義的代碼,這個函數的調用将會把以CONFIG_FLASH_BASE起始的NOR FLASH段保護起來。防止在UBOOT中對環境變量進行修改。修改成配置了CONFIG_ENV_IS_IN_FLASH宏的時候才會起作用的結構,這樣可使UBOOT更加準确,精簡。
67 #ifdef CONFIG_ENV_IS_IN_FLASH
68 flash_protect (FLAG_PROTECT_SET,
69 CONFIG_ENV_ADDR,
70 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
71 #endif
如果NOR FLASH得到正确的初始化過後,就會列印出類似這樣的資訊:
接下來再指令行中驗證一下和NOR FLASH操作相關的幾個指令:
顯示NOR FLASH資訊
擦除NOR FLASH(可能會經常用到)
下面兩個指令為擦除整塊的操作,如果NOR FLASH中還有段處于被保護狀态,這兩個指令運作不會成功。
指定擦除某一塊NOR FLASH(如果有多個)
擦除所有的NOR FLASH(有好多擦好多)
NOR FLASH段保護
用法太多,不一一展示了,主要用途一般是解除UBOOT存儲區域的保護,将新的UBOOT代碼燒錄到裡面去(類似固件更新之類的功能)。
cp指令的示範(将記憶體的資料複制到NOR FLASH中)
需要注意的是由于NOR FLASH的接口為32位的,是以一次資料傳輸是4個位元組,下面指令傳輸的資料量最終大小是0x800位元組。
這樣,NOR FLASH也在本次UBOOT中得到了支援。不過可以看到,UBOOT現在還不是十分的規範,很多宏定義并不是通用的宏定義,随意性還是比較強(一些宏的名稱不規範,但是負責了重要的流程控制)。一些流程控制沒有考慮到通用性。還需要進一步的打磨才行。