在U-Boot-2009-03移植笔记(点亮第一展灯)中,我们初始化好了sdram,点亮了第一盏灯。在本文中,我们将移植好nandflash启动的驱动代码。
对于S3C2440,有一个steppingston,在CPU上电的时候,由硬件将Nandflash的前4KB代码拷贝到片内的SRAM中,并且内部SRAM被映射到地址0x0,于是我们的代码才能被cpu执行。
但问题是我们的代码肯定不止4KB,所以我们必须自己写代码,把nandflash中的剩余代码拷贝到内存中,然后让CPU跳转到对应的内存地址执行。
设置堆栈指针,为C语言准备运行环境
1 /*设置堆栈*/
2 ldr sp, DW_STACK_START
3 mov fp,#0
注意第二行引用了DW_STACK_START标号,我们定义在标号_start_armboot后面
1 _start_armboot: .word start_armboot
2 DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
第二行的STACK_BASE和STACK_SIZE都定义在include/configs/xinna2440.h中
1 #define STACK_BASE 0x33f00000 //定义堆栈的地址
2 #define STACK_SIZE 0x8000 //堆栈的长度大小
设置好了堆栈指针,下面我们只需要初始化好Nandflash之后,就可以读取数据,存到sdram中了。
初始化NandFlash
我们在board/xinna2440/文件夹下,增加nand_op.c文件,然后修改board/xinna2440/Makefile,添加对nand_op.c的编译
1 COBJS := xinna2440.o flash.o nand_op.o
编辑board/xinna2440/nand_op.c,添加以下文件,我们的板子上用的是K9F2G08U0A,2KB一页,共64MB大小。 1 /*
2 * board/samsung/reille2440/nand_read.c
3 *
4 * (C) Copyright 2011
5 * reille
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 */
13 #include
14 #define NF_BASE 0x4E000000 //Nand Flash配置寄存器基地址
15 #define __REGb(x) (*(volatile unsigned char *)(x))
16 #define __REGi(x) (*(volatile unsigned int *)(x))
17 #if 0
18 #define NFCONF __REGi(NF_BASE + 0x0 ) //通过偏移量还是得到配置寄存器基地址
19 #define NFCONT __REGi(NF_BASE + 0x4 ) //通过偏移量得到控制寄存器基地址
20 #define NFCMD __REGb(NF_BASE + 0x8 ) //通过偏移量得到指令寄存器基地址
21 #define NFADDR __REGb(NF_BASE + 0xC ) //通过偏移量得到地址寄存器基地址
22 #define NFDATA __REGb(NF_BASE + 0x10) //通过偏移量得到数据寄存器基地址
23 #define NFSTAT __REGb(NF_BASE + 0x20) //通过偏移量得到状态寄存器基地址
24 #endif
25
26 #define NFCONF (*(volatile unsigned int *)(NF_BASE + 0X0))
27 #define NFCONT (*(volatile unsigned short *)(NF_BASE + 0x4))
28 #define NFCMD (*(volatile unsigned short *)(NF_BASE + 0X8))
29 #define NFADDR (*(volatile unsigned short *)(NF_BASE + 0xc))
30 #define NFDATA (*(volatile unsigned char *)(NF_BASE + 0x10))
31 #define NFSTAT (*(volatile unsigned char *)(NF_BASE + 0x20))
32
33
34 #define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1)) //Nand片选使能
35 #define NAND_CHIP_DISABLE (NFCONT |= (1<<1)) //取消Nand片选
36 #define NAND_CLEAR_RB (NFSTAT |= (1<<2));
37 #define NAND_DETECT_RB { while(! (NFSTAT&(1<<2)) );}
38 #define NAND_SECTOR_SIZE 2048
39 #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
40 #if 0
41 #define DEBUGN printf
42 #else
43 #define DEBUGN(x, args ...) {}
44 #endif
45
46 /* low level nand read function */
47 #define GPBCON (*(volatile unsigned long *)0x56000010)
48 #define GPBDAT (*(volatile unsigned long *)0x56000014)
49
50 #define GPACON (*(volatile unsigned long *)0x56000000)
51
52 void nand_wait_ll(void)
53 {
54 int k;
55 while(!(NFSTAT & 1))
56 for(k = 0; k < 20; k++);
57 return;
58 // NAND_DETECT_RB
59 }
60
61 void nand_reset_ll(void)
62 {
63 NAND_CHIP_ENABLE; //选中Nand片选
64 // NAND_CLEAR_RB
65 NFCMD = 0xff;
66 nand_wait_ll();
67 // NAND_CLEAR_RB
68 NAND_CHIP_DISABLE; //取消片选信号
69 }
70
71
72 unsigned char nand_read_id(unsigned char*mc,unsigned char *dc,unsigned char *pc)
73 {
74 int i=0;
75 unsigned char res;
76 NAND_CHIP_ENABLE; //选中Nand片选
77 NFCMD = 0x90;
78 for(i = 0;i < 100;i++);
79 NFADDR = 0 & 0xFF;
80 NFADDR = (0 >> 9) & 0xFF;
81 NFADDR = (0 >> 17) & 0xFF;
82 NFADDR = (0 >> 25) & 0xFF;
83 for(i = 0;i < 100;i++);
84 nand_wait_ll();
85 *mc = NFDATA;
86 *dc = NFDATA;
87 res = NFDATA;
88 *pc = NFDATA;
89 NAND_CHIP_DISABLE; //取消片选信号
90 return *mc;
91 }
92
93 void nand_init_ll(void)
94 {
95 int TACLS = 3;
96 int TWRPH0 = 7;
97 int TWRPH1 = 7;
98 int i = 0;
99 //配置gpio
100 // GPACON = (GPACON &~(0x3f << 17)) | ( 0x3f << 17);
101 GPACON = GPACON | (0x3f << 17);
102 NFCONF = (TACLS << 12) | (TWRPH0 << 8) | (TWRPH1 << 4) | (0 << 0);
103
104 NFCONT = (0 << 13) | (0 << 12) | ( 0 << 10) | (0 << 9) | (0 << 8) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 1) | (1 << 0);
105
106 nand_reset_ll();
107 }
108
109 #if 0
110 int nand_write_ll(void)
111 {
112 int i = 0x90000;
113 unsigned char j = 0;
114 NAND_CHIP_ENABLE; //选中Nand片选
115 NFCMD = 0x80;
116
117 NFADDR = 0x00;
118 NFADDR = 0x00;
119 NFADDR = i & 0xFF;
120 NFADDR = (i >> 8) & 0xFF;
121 NFADDR = (i >> 16) & 0xFF;
122 for(j = 0; j < 100;j++);
123
124
125 NFCMD = 0x10;
126 nand_wait_ll();
127
128 for(j = 0 ; j < 100; j++)
129 {
130 NFDATA = j;
131 }
132 NFCMD = 0x10;
133 nand_wait_ll();
134
135 NAND_CHIP_DISABLE; //取消片选信号
136 return 0;
137 }
138 #endif
139
140 static void write_addr(unsigned int addr)
141 {
142 int col,page,i;
143 col = addr & NAND_BLOCK_MASK;
144 page = addr & NAND_SECTOR_SIZE;
145
146 NFADDR = col & 0xff;
147 for(i = 0; i < 10; i++);
148 NFADDR = (col >> 8) & 0x0f;
149 for(i = 0; i < 10; i++);
150
151
152 NFADDR = page & 0xFF;
153 for(i = 0; i < 10; i++);
154 NFADDR = (page >> 8) & 0xFF;
155 for(i = 0; i < 10; i++);
156
157 NFADDR = (page >> 16) & 0x01;
158 for(i = 0; i < 10; i++);
159 }
160
161 static nand_read_page_ll(unsigned char *buf,unsigned long pageaddr)
162 {
163 int i = 0;
164 NAND_CHIP_ENABLE; //选中Nand片选
165
166 //发出READ0指令
167 NFCMD = 0;
168
169 //对Nand进行寻址
170 NFADDR = 0x00;
171 NFADDR = 0x00;
172 NFADDR = pageaddr & 0xff;
173 NFADDR = (pageaddr >> 8) & 0xff;
174 NFADDR = (pageaddr >> 16) & 0xff;
175
176 NFCMD = 0x30;
177 nand_wait_ll();
178
179 for(i=0; i < NAND_SECTOR_SIZE; i++)
180 buf[i] = NFDATA;
181
182 NAND_CHIP_DISABLE; //取消片选信号
183 }
184
185 int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
186 {
187 int pageaddr = 0;
188 for(pageaddr = 0; pageaddr < 100;pageaddr++)
189 {
190 nand_read_page_ll(buf,pageaddr);
191 buf += NAND_SECTOR_SIZE;
192 }
193 return 0;
194 }
195
写好了nand_flash驱动之后,我们在start.S中调用,将u-boot自身,从nandflash读到sdram中。
1 bl nand_init_ll /*调用nandflash初始化函数*/
2
3 ldr r0, =TEXT_BASE /*指定uboot在内存中的地址,这个宏定义在board/xinna2440/config.mk中,默认是0x33f80000*/
4 mov r1, #0x0 /*从nandflash的0地址读取*/
5 mov r2, #0x30000 /*读取长度*/
6
7 bl nand_read_ll /*开始循环读取*/
8 tst r0, #0x0 /*判断函数返回值*/
9 beq ok_nand_read
10
11 bad_nand_read:
12 loop2: b loop2 /*读取出错,死循环*/
13
14 ok_nand_read:
15 mov r0,#0
16 ldr r1,=TEXT_BASE
17 mov r2,#0x400
18 /*读取成功,以下代码用于校验内存数据和sram中的数据是否一样*/
19
20 go_next:
21 ldr r3, [r0], #4
22 ldr r4, [r1], #4
23 teq r3, r4
24 bne notmatch
25 subs r2, r2, #4
26 beq stack_setup
27 bne go_next
28
29 notmatch: /*数据不一致,死循环*/