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现在还不是十分的规范,很多宏定义并不是通用的宏定义,随意性还是比较强(一些宏的名称不规范,但是负责了重要的流程控制)。一些流程控制没有考虑到通用性。还需要进一步的打磨才行。