资源描述
uboot-2010-03移植tq2440记录
(by fengyong(vonbrave@))
一.移植环境
(1) Vmware6.5---Ubuntu8.04
(2) 使用的开发板是TQ2440,配有Nor Flash大小为2MB; NandFlash 256MB。型号是三星的K9F2GU08A。页的大小是2KB.
我们的开发板NandFlash是64MB的,三星的型号是K9F1208。页的大小是512K。
(3) 交叉编译器的版本是EABI-4.3.3_EmbedSky_20100610.tar.bz2。
编译器的选择我们选择4.3.3
(4) 移植的U-Boot版本号为u-boot-2010-03。其官方下载地址 ftp://ftp.denx.de/pub/u-boot/。
在该版本中,仍然不支持s3c2440的处理器,因此必须以smdk2410为原型,在此基础上进行U-Boot的移植工作。
二.建立自己的开发板目录并测试编译环境
(1) 新建一个开发板的相应目录和文件(检测配置问题,看能不能编译出u-boot.bin)
为了不破坏原来的结构目录和代码,在board目录下建立一个目录embedsky,将samsung/smdk2410目录复制到embedsky目录下,并将文件夹改名smdk2440。
(2) 将smdk2440/smdk2410.c改名为smdk2440.c。
(3) 在include/configs目录下,将smdk2410.h直接复制为smdk2440.h
(4) 修改顶层的Makefile文件,在其中添加如下的两行:
smdk2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2440 embedsky s3c24x0
上面第二行一定要记得加TAB键,这是Makefile的规则
说明:arm :CPU的架构(ARCH)
arm920t:CPU的类型
smdk2440 :对应在board目录下建立新的开发板项目的目录
embedsky:新开发板项目目录的上级目录,如直接在board下建立新的开发板项目的目录,则这里就为NULL
s3c24x0:CPU型号
注意:编译选项格式的第二行要用Tab键开始,否则编译会出错,这是Makefile文件的规则.当Make出错的时候就应该查看是不是,这里写错!
(5)修改board/embedsky/smdk2440目录下的Makefile文件,因为前面将smdk2410.c文件改名为smdk2440.c:
COBJS := smdk2410.o flash.o
改为
COBJS := smdk2440.o flash.o
(6) 修改根目录下Makefile
将__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
或修改cpu/arm920t/u-boot.lds文件的
.text :
{
cpu/arm920t/start.o (.text)
board/embedsky/smdk2440/lowlevel_init.o (.text)
board/embedsky/smdk2440/nand_read.o (.text)
*(.text)
}
(7)进入u-boot-2010.03目录,验证环境
先 #make distclean 清理所有以前的编译生成项
然后# make smdk2440_config
Configuring for smdk2440 board... 生成一个适合smdk2440的config
#make
到此,就已经建立了自己的目录,还有测试了编译的环境,如果都正确的话,就可以进行下面的移植工作了。
三、修改u-boot-2010.03中的文件,以便支持smdk2440
1.修改/cpu/arm920t/start.S文件,使U-BOOT可以从NandFlash启动
(1)删除掉LED的代码
#include <common.h>
#include <config.h>
start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
@ bl coloured_LED_init
@ bl red_LED_on
(2) 修改寄存器的地址
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
后增加:
#define CLK_CTL_BASE 0x4C000000
#define MDIV_405 (0x7f << 12)
#define PSDIV_405 (0x21)
#define MDIV_200 (0xa1 <<12)
#define PSDIV_200 (0x31)
#endif
(3)修改中断禁止
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x7ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
#if defined(CONFIG_S3C2440)
ldr r1,=0x7fff //2440的位宽多点
ldr r0,=INTSUBMSK
str r1,[r0]
#endif
(4) 修改时钟设置(2440的主频为405MHz。)
#if defined(CONFIG_S3C2440)
ldr r0,=CLKDIVN
mov r1,#5
str r1,[r0]
mrc p15,0,r1,c1,c0,0
orr r1,r1,#0xc0000000
mcr p15,0,r1,c1,c0,0
mov r1,#CLK_CTL_BASE
mov r2,#MDIV_405
add r2,r2,#PSDIV_405
str r2,[r1,#0x04]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
mrc p15,0,r1,c1,c0,0
orr r1,r1,#0xc0000000
mcr p15,0,r1,c1,c0,0
mov r1,#CLK_CTL_BASE
mov r2,#MDIV_200
addr r2,r2,#PSDIV_200
str r2,[r2,#0x04]
#endif
#endif /* CONFIG_S3C24x0 */
(5)将原来的从NorFlash启动,转换为从NandFlash 启动
#ifndef CONFIG_AT91RM9200
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia {r3-r10} /* copy from source address [r0] */
stmia {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
在上述代码后面增加下面的代码:
//下面添加对 Nand Flash的支持,下面的这段代码主要实现的功能就把u-boot的程序可以复制的RAM中,该汇编代码调用了用C语言写的函数nand_read_ll()
/****** NAND_BOOT ********/
#define LENGTH_UBOOT 0x60000
#define NAND_CTL_BASE 0x4E000000
#ifdef CONFIG_S3C2440
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
初始化nand控制寄存器
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait 设置延迟
nand1:
add r3, r3, #0x1
cmp r3, #0xa 延迟10次 0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE 编译时的链接地址
mov r1, #0x0
mov r2, #LENGTH_UBOOT 长度 0x60000
bl nand_read_ll 调用nand_read.c函数的处理
tst r0, #0x0
beq ok_nand_read 检查返回值,如果返回0,走bad_nand_read,死循环
bad_nand_read:
loop2:
b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4 将nand的前4K数据放入r3
ldr r4, [r1], #4 将TEXT_BASE的前4K数据放入r4
teq r3, r4 比较
bne notmatch 跳转到死循环
subs r2, r2, #4 将r2-4进行比较
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3 @ infinite loop
#endif
在ldr pc, _start_armboot
_start_armboot: .word start_armboot之后添加
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START:.word STACK_BASE+STACK_SIZE - 4
2 在board/embedsky/smdk2440/目录下加入NAND Flash读取函数(start.S中需要的nand_read_ll函数)文件nand_read.c,
新建nand_read.c,支持2K/512字节Page size 的Nand Flash读操作
#include <common.h>
#include <linux/mtd/nand.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGw(x) (*(volatile unsigned short *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#if defined(CONFIG_S3C2410)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
#define NFADDR __REGb(NF_BASE + 0x8)
#define NFDATA __REGb(NF_BASE + 0xc)
#define NFSTAT __REGb(NF_BASE + 0x10)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONF &= ~0x800)
#define nand_deselect() (NFCONF |= 0x800)
#define nand_clear_RnB() do {} while (0)
#elif defined(CONFIG_S3C2440)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGi(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFDATA16 __REGw(NF_BASE + 0x10)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONT &= ~(1 << 1)) 第一位清0
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB() (NFSTAT |= (1 << 2))清RNB 信号
#endif
static inline void nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY)) 等待RnB信号
for (i=0; i<10; i++);
}
struct boot_nand_t {
int page_size; 页的大小
int block_size;
int bad_block_offset; 坏块的偏移
};
static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;
nand_clear_RnB();
if (nand->page_size == 512) {
NFCMD = NAND_CMD_READOOB; /* 0x50 */
NFADDR = nand->bad_block_offset & 0xf;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = i >> 11; /* addr / 2048 */ 除2048从第三个周期对齐
NFCMD = NAND_CMD_READ0;
NFADDR = nand->bad_block_offset & 0xff;
NFADDR = (nand->bad_block_offset >> 8) & 0xff;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART; 读命令
} else {
return -1;
}
nand_wait();
data = (NFDATA & 0xff);
if (data != 0xff) 判断是否是坏块
return 1; 返回1表示是坏块
return 0;
}
static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr) 读一个页的buf的数据
{
unsigned short *ptr16 = (unsigned short *)buf; buf指针
unsigned int i, page_num;
nand_clear_RnB();
NFCMD = NAND_CMD_READ0; 读命令
if (nand->page_size == 512) {
/* Write Address */
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = addr >> 11; /* addr / 2048 */
/* Write Address */
NFADDR = 0;
NFADDR = 0;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();
#if defined(CONFIG_S3C2410)
for (i = 0; i < nand->page_size; i++) {
*buf = (NFDATA & 0xff);
buf++;
}
//2440
#elif defined(CONFIG_S3C2440)
for (i = 0; i < (nand->page_size>>1); i++) {
*ptr16 = NFDATA16; 16位总线读方式
ptr16++;
}
#endif
return nand->page_size; 返回读的大小
}
static unsigned short nand_read_id() 返回读的ID
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA; 第一个字节
res = (res << 8) | NFDATA; 第二个字节
return res; 合并为16字节的 返回
}
extern unsigned int dynpart_size[];
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
unsigned short nand_id;
struct boot_nand_t nand;
/* chip Enable */
nand_select();
nand_clear_RnB();
for (i = 0; i < 10; i++)
;
nand_id = nand_read_id(); 16位的id
if (0) { /* dirty little hack to detect if nand id is misread */
unsigned short * nid = (unsigned short *)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76) { /* Samsung K9F1208 */芯片寄存器设置数据发送指令的返回值,在芯片图里面
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
} else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
nand_id == 0xecda || /* Samsung K9F2G08U0B */
nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
nand.page_size = 2048;
nand.block_size = 128 * 1024;
nand.bad_block_offset = nand.page_size;
} else { return -1;
}
if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
return -1; /* invalid alignment */ 判断块对齐
for (i=start_addr; i < (start_addr + size);) { 开始读数据
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD 检查是否是坏块
if (i & (nand.block_size-1)== 0) {
if (is_bad_block(&nand, i) ||
is_bad_block(&nand, i + nand.page_size)) {
/* Bad block */
i += nand.block_size;
size += nand.block_size;
continue;
}
}
#endif
j = nand_read_page_ll(&nand, buf, i); 读的最小单位按页读
i += j;
buf += j;
}
/* chip Disable */
nand_deselect();
return 0;
}
在添加完nand_read.c文件后,记得修改board/smdk2440/Makefile文件,将nand_read.c编译进u-boot。
COBJS := smdk2440.o nand_read.o flash.o
3 修改board/smdk2440/lowlevel_init.S文件
将:对bank的设置
#define B3_Tacs 0x0 /* 0clk */
#define B3_Tcos 0x3 /* 4clk */
#define B3_Tacc 0x7 /* 14clk */
#define B3_Tcoh 0x1 /* 1clk */
#define B3_Tah 0x0 /* 0clk */
#define B3_Tacp 0x3 /* 6clk */
#define B3_PMC 0x0 /* normal */
=>
改为:
#define B3_Tacs 0xc
#define B3_Tcos 0x7
#define B3_Tacc 0xf
#define B3_Tcoh 0x1
#define B3_Tah 0x0
#define B3_Tacp 0x0
#define B3_PMC 0x0
将:
#define B5_Tacs 0x0 /* 0clk */
#define B5_Tcos 0x0 /* 0clk */
#define B5_Tacc 0x7 /* 14clk */
#define B5_Tcoh 0x0 /* 0clk */
#define B5_Tah 0x0 /* 0clk */
#define B5_Tacp 0x0
#define B5_PMC 0x0 /* normal */
#define B6_MT 0x3 /* SDRAM */
#define B6_Trcd 0x1
#define B6_SCAN 0x1 /* 9bit */
=>
改为:
#define B5_Tacs 0xc
#define B5_Tcos 0x7
#define B5_Tacc 0xf
#define B5_Tcoh 0x1
#define B5_Tah 0x0
#define B5_Tacp 0x0
#define B5_PMC 0x0
#define B6_MT 0x3 /* SDRAM */
#define B6_Trcd 0x2 /* 0x1*/
#define B6_SCAN 0x1 /* 9bit */
将:
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp 0x0 /* 2clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
=>
改为:
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#if defined(CONFIG_S3C2440)
#define Trp 0x2 /* 4clk */
#define REFCNT 1012
#else
#define Trp 0x0 /* 2clk */
#define REFCNT 0x0459
#endif
4、修改/board/smdk2440/smdk2440.c 如下:
#include <common.h>
#include <netdev.h>
#include <asm/arch/s3c24x0_cpu.h>
#if defined(CONFIG_CMD_NAND)
#include <linux/mtd/nand.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
#define FCLK_SPEED 1
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#if defined(CONFIG_S3C2410)
/* Fout = 202.8MHz */
#define M_MDIV 0xA1
#define M_PDIV 0x3
#define M_SDIV 0x1
#endif
#if defined(CONFIG_S3C2440)
/* Fout = 405MHz */
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
#endif
#endif
#define USB_CLOCK 1
#if USB_CLOCK==0
#define U_M_MDIV 0xA1
#define U_M_PDIV 0x3
#define U_M_SDIV 0x1
#elif USB_CLOCK==1
#if defined(CONFIG_S3C2410)
#define U_M_MDIV 0x48
#define U_M_PDIV 0x3
#endif
#if defined(CONFIG_S3C2440)
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#endif
#define U_M_SDIV 0x2 2440的分频
#endif
static inline void delay (unsigned long loops)
{
__asm__ volatile ("1:\n"
"subs %0, %1, #1\n"
"bne 1b":"=r" (loops):"0" (loops));
}
/*
* Miscellaneous platform dependent initialisations
*/
int board_init (void)
{
struct s3c24x0_clock_power * const clk_power =
s3c24x0_get_base_clock_power();
struct
展开阅读全文