启动u-boot后发现提示“NAND: 0 MiB”,说明uboot现在还不能识别出NAND FLASH,所以现在我们来修改代码:
a.在smdk2440.h(路径为:include\configs\smdk2440.h)文件中,将
#define CONFIG_SYS_TEXT_BASE 0x0
修改为:
#define CONFIG_SYS_TEXT_BASE0x33f80000
因为nand flash地址为30000000~34000000,所以这里为uboot留出512k的空间
b. 注释掉:
jump_to_copy
这是跳转函数,先注释掉,这里由我们自己实现。
c.添加init.c(这个文件待会我会上传)文件到board/samsung/smdk2440文件夹下
d. 修改board/samsung/smdk2440下的Makefile文件,把
obj-y:= smdk2440.o
修改为:
obj-y:= init.o smdk2440.o
这里涉及到Makefile的语法,意为编译init和smdk2440文件。
e.在arch/arm/cpu目录下修改u-boot.lds文件下,在:
CPUDIR/start.o(.text*)
这一行语句下添加一句:
board/samsung/smdk2440/built-in.o (.text)
f.在文件:arch/arm/lib/crt0.s的include之后添加如下代码:
.globl _TEXT_BASE _TEXT_BASE: .word CONFIG_SYS_TEXT_BASE
其中,_TEXT_BASE作为此刻代码段的位置,把代码从NAND FLASH复制到SDRAM时要用到
g.在汇编函数_main(路径:arch/arm/lib/crt0.s)里,找到这句代码:
bicsp, sp, #7/* 8-byte alignment for ABI compliance */
这条是8字节对齐指令,而且在这个_main函数里,设置了堆栈指针,所以我们现在可以调用C函数了。
所以在#endif之后添加如下代码:
bl nand_init_ll mov r0, #0 ldr r1, _TEXT_BASE ldr r2, =__bss_start sub r2, r2, r1 bl copy_code_to_sdram bl clear_bss ldr pc, =call_board_init_f call_board_init_f:
h.在c函数reserve_uboot(路径:common/board_f)里,把:
gd->relocaddr -= gd->mon_len; gd->relocaddr &= ~(4096 - 1);这两句和重定位有关,先注释掉,并且在:gd->start_addr_sp = gd->relocaddr;这一句代码之前添加一句:gd->relocaddr = CONFIG_SYS_TEXT_BASE;这里由我们自己定位地址。
i.至此,NAND也可以启动uboot了. 附上init.c文件:
/* NAND FLASH控制器 */ #define NFCONF (*((volatile unsigned long *)0x4E000000)) #define NFCONT (*((volatile unsigned long *)0x4E000004)) #define NFCMMD (*((volatile unsigned char *)0x4E000008)) #define NFADDR (*((volatile unsigned char *)0x4E00000C)) #define NFDATA (*((volatile unsigned char *)0x4E000010)) #define NFSTAT (*((volatile unsigned char *)0x4E000020)) /* GPIO */ #define GPHCON (*(volatile unsigned long *)0x56000070) #define GPHUP (*(volatile unsigned long *)0x56000078) /* UART registers*/ #define ULCON0 (*(volatile unsigned long *)0x50000000) #define UCON0 (*(volatile unsigned long *)0x50000004) #define UFCON0 (*(volatile unsigned long *)0x50000008) #define UMCON0 (*(volatile unsigned long *)0x5000000c) #define UTRSTAT0 (*(volatile unsigned long *)0x50000010) #define UTXH0 (*(volatile unsigned char *)0x50000020) #define URXH0 (*(volatile unsigned char *)0x50000024) #define UBRDIV0 (*(volatile unsigned long *)0x50000028) #define TXD0READY (1<<2) void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len); static int isBootFromNorFlash(void) { volatile int *p = (volatile int *)0; int val; val = *p; *p = 0x12345678; if (*p == 0x12345678) { /* 写成功, 是nand启动 */ *p = val; return 0; } else { /* NOR不能像内存一样写 */ return 1; } } void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len) { int i = 0; /* 如果是NOR启动 */ if (isBootFromNorFlash()) { while (i < len) { dest[i] = src[i]; i++; } } else { //nand_init(); nand_read_ll((unsigned int)src, dest, len); } } void clear_bss(void) { extern int __bss_start, __bss_end; int *p = &__bss_start; for (; p < &__bss_end; p++) *p = 0; } void nand_init_ll(void) { #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 /* 设置时序 */ NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ NFCONT = (1<<4)|(1<<1)|(1<<0); } static void nand_select(void) { NFCONT &= ~(1<<1); } static void nand_deselect(void) { NFCONT |= (1<<1); } static void nand_cmd(unsigned char cmd) { volatile int i; NFCMMD = cmd; for (i = 0; i < 10; i++); } static void nand_addr(unsigned int addr) { unsigned int col = addr % 2048; unsigned int page = addr / 2048; volatile int i; NFADDR = col & 0xff; for (i = 0; i < 10; i++); NFADDR = (col >> 8) & 0xff; for (i = 0; i < 10; i++); NFADDR = page & 0xff; for (i = 0; i < 10; i++); NFADDR = (page >> 8) & 0xff; for (i = 0; i < 10; i++); NFADDR = (page >> 16) & 0xff; for (i = 0; i < 10; i++); } static void nand_wait_ready(void) { while (!(NFSTAT & 1)); } static unsigned char nand_data(void) { return NFDATA; } void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len) { int col = addr % 2048; int i = 0; /* 1. 选中 */ nand_select(); while (i < len) { /* 2. 发出读命令00h */ nand_cmd(0x00); /* 3. 发出地址(分5步发出) */ nand_addr(addr); /* 4. 发出读命令30h */ nand_cmd(0x30); /* 5. 判断状态 */ nand_wait_ready(); /* 6. 读数据 */ for (; (col < 2048) && (i < len); col++) { buf[i] = nand_data(); i++; addr++; } col = 0; } /* 7. 取消选中 */ nand_deselect(); }