三、 UBOOT移植
1、注意问题
了解了大概uboot的运行过程,现在开始移植,移植前,说明几个问题
由于uboot-1.3.4较于较早的版本,就是Makefile有一定的变化,使得对于24x0处理器从nand启动会有问题,就是有人说的无法运行过lowlevel_init。这个问题产生的原因是因为编译器将笔者自己添加的用于nandboot的子函数放到了4K之后(为什么说是4K,uboot从nand启动原理,前面说过),解决办法:
1、顶层Makefile文件中:
#__LIBS := $(subst $(obj),,$(LIBS)) $(subst$(obj),,$(LIBBOARD))
__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
这样修改之后查看map文件可以发现,lowlevel_init函数链接到了前面.
2、在不修改Makefile的情况下,可以通过修改目标板下的链接文件u-boot.lds来使lowlevel_init放在4K之内: cpu/arm920t/start.o (.text)board/net2410e/lowlevel_init.o (.text) 把之放到start.o的后面.
这相当于修改链接脚本,未做验证,笔者使用第一种方法!
3、 开始移植/*其中,蓝色为修改内容,红色为添加内容,参考《移植u-boot-1.3.4到s3c2440》*/
下载源码,网址:
1) 解压uboot
#tar –xjvf u-boot-1.3.4.tar.gz2
2) 修改Makefile
#cd u-boot-1.3.4
#vi Makefile或者直接在图形界面打开Makefile,可能这种方法更好用
修改内容如下:
__LIBS := $(subst$(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为:
__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst$(obj),,$(LIBS))
添加开发板信息
sbc2410x_config: unconfig @$(MKCONFIG)$(@:_config=) arm arm920t sbc2410x NULL s3c24x0
gt2440_config : unconfig @$(MKCONFIG) $(@:_config=) armarm920t gt2440 NULL s3c24x0
/*
各项的意思如下:
gt2440_config : 这个名字是将来你配置板子时候用到的名字,参见make gt2440_config命令。
arm: CPU的架构(ARCH)
arm920t: CPU的类型(CPU),其对应于cpu/arm920t子目录。
gt2440: 开发板的型号(BOARD),对应于board/ gt2440目录。
NULL: 开发者/或经销商(vender)。s3c24x0: 片上系统(SOC)。
*/
3) 在/board/下建立自己的开发板目录
由于笔者开发者那填了NULL,所以直接创建,如果有填,则要再建一个子目录,因为笔者是以sbc2410x这板为基础移植的,所以还要将它的内容复制到开发板文件夹上。
[root@localhost u-boot-1.3.4]#mkdir /board/gt2440
[root@localhost u-boot-1.3.4]#cp –arfsbc2410x/* gt2440/
[root@localhost u-boot-1.3.4]#cd gt2440
[root@localhost u-boot-1.3.4]#mv sbc2410x.cgt2440.c
[root@localhost u-boot-1.3.4]#ls可以看到下面这些文件
config.mk flash.c lowlevel_init.s Makefile GT2440.c u-boot.lds
[root@localhost u-boot-1.3.4]#vi Makefile
COBJS:= gt2440.o flash.o
4) 在include/configs/中建立开发板所需要的配置头文件
[root@localhost u-boot-1.3.4]#cp../../include/configs/sbc2410x.h ../../include/configs/gt2440.h
5) 测试交叉编译能否成功
这里提醒一下,移植uboot是需要交叉编译有浮点运算功能的,安装arm-linux时,应该选用有浮点运算的,而不是最新的,因为最新的未必是最好的,uboot也是一样,新的只是移植简单了,对于交叉编译工具,笔者选用的是arm-linux-gcc-3.4.1
(1) 配置
[root@localhost u-boot-1.3.4]#makegt2440_config
Configure for gt2440 board
(2) 测试编译
[root@localhost u-boot-1.3.4]#make
编译信息最后两行
arm-linux-objcopy --gap-fill=0xff -O srec u-bootu-boot.srec
arm-linux-objcopy --gap-fill=0xff -O binaryu-boot u-boot.bin
6) 开始针对自己的开发板移植
1. 修改/cpu/arm920t/start.S
1.1 修改寄存器地址定义
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
/*turn offthe watchdog*/
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clockdivisor register */
#else
# define pWTCON 0x53000000 /*该地址用来屏蔽看门狗*/
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses 该地址用来屏蔽中断*/
# define INTSUBMSK 0x4A00001C /*该地址用来屏蔽子中断*/
# define CLKDIVN 0x4C000014 /* clockdivisor register 该地址用来决定FCLK、HCLK、PCLK的比例*/
#define CLK_CTL_BASE 0x4c000000 /* 从S3C2440A.pdf中可以看出该寄存器是存放Mpll和Upll的P254 */
#if defined(CONFIG_S3C2440)
#define MDIV_405 0x7f << 12 /* 参见P255表,同时要知道本开发板的Fin是12MHz,需要的Fclk(也就是Mpll)是405MHz*/
#define PSDIV_405 0x21 /* 同上,同时设定PDIV和SDIV的值,PDIV和SDIV参见S3C2440A.pdf*/
#endif
#endif
1.2 修改中断禁止部分
# ifdefined(CONFIG_S3C2410)
//ldr r1,0x3ff
ldr r1, =0x7ff //根据2410芯片手册,INTSUBMSK有11位可用,
//vivi也是0x7ff,不知为什么U-Boot一直没改过来。但是由于芯片复位默认
//所有的终端都是被屏蔽的,所以这个不影响工
ldr r0,=INTSUBMSK
str r1, [r0]
# endif
# if defined(CONFIG_S3C2440)
ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK有15位可用
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
1.3 修改时钟设置
/*时钟控制逻辑单元能够产生s3c2440需要的时钟信号,包括CPU使用的主频FCLK,AHB总线使用的HCLK,APB总线设备使用的PCLK,2440里面的两个锁相环(PLL),其中一个对应FCLK、HCLK、PCLK,另外一个对应UCLK(48MHz)*/
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
/*协处理器操作
CP15 —系统控制协处理器 (the system control coprocessor)他通过协处理器指令MCR和MRC提供具体的寄存器来配置和控制caches、MMU、保护系统、配置时钟模式(在bootloader时钟初始化用到),详情可看《ARM体系结构与编程》或者笔者的一个浅谈,也是参考那本书的
*/
mcr p15,0,r1,c1,c0,0 /*读协处理器p15 c1寄存器的值到r1*/
orr r1,r1,#0xc0000000
mcr p15,0,r1,c1,c0,0 /*把r1的内容写到c1中去,禁止MMU、禁止地址对齐检查功能、禁止caches、禁止写入缓冲、异常中断处理程序进入32位地址模式、禁止26位地址异常检查、选择时期中止模型、选择little-endian。。。。。。详情可以看《ARM体系结构与编程》的5.2节*/
#ifdefined(CONFIG_S3C2440)
/*now, CPU clock is 405.00 Mhz qljt*/
mov r1, #CLK_CTL_BASE
mov r2, #MDIV_405 /* mpll_405mhz */
add r2, r2, #PSDIV_405 /* mpll_405mhz */
str r2, [r1,#0x04] /* MPLLCON实际上是设置寄存器CLK_CTL_BASE+0x04=0x4c000004的值 */
#endif
#endif /*CONFIG_S3C2400 || CONFIG_S3C2410|| CONFIG_S3C2440 */
1.4 将Flash启动改成从NANDFlash启动(这里网上还有一个小程序,是判别现在是nor还是nand启动的,原理可参考,
其实就是利用start.S里的魔方数以及nand和nor的写特性,然后可以同时烧进nor和nand中,主要区别在于,nor可以直接运��uboot。笔者这里没加)
将u-boot重定向语句段屏蔽
@#if ndef CONFIG_AT91RM9200
#if 0
#ifndefCONFIG_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 ofarmboot */
add r2, r0, r2 /* r2 <- source endaddress */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee[r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif/*#if 0*/
#endif /*CONFIG_AT91RM9200 */
然后添加(参考VIVI):
#ifdef CONFIG_S3C2440_NAND_BOOT
/*往下四段内容都是针对S3C2440的关于NAND-FLASH的寄存器的设置*/
mov r1, #NAND_CTL_BASE
ldr r2, =((7<<12)|(7<<8)|(7<<4)|(0<<0) ) /*总线宽为8
Bit,设定TWRPH1,TWRPH0(nWE高低电平持续时间)*/
str r2, [r1, #oNFCONF] /*这些宏是在include/configs/GT2440.h中被定义的*/
ldr r2, [r1, #oNFCONF]
ldr r2, =((1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
/*delay一段时间*/
mov r3,#0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
/*等待nand-flash的复位完毕信号*/
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2,#0x2 @ Flash Memory ChipDisable /*在这里先Display fansh CE先,在C函数中再enable*/
str r2, [r1, #oNFCONT]
/*下面这段用来初始化栈指针sp和帧指针fp,至于它们的定义和作用参考文件夹” 栈指针sp和帧指针fp”里面的内容
记住它们都是与函数调用时候相关的。简单来讲就是子函数被调用以后是通过指针的相对位置来查找调用参数和局部变量的,但是由于sp经常变化,所以需要fp来协助。*/
@ get ready to call C functions (for nand_read())
ldr sp,DW_STACK_START @ setup stack pointer /*sp 是指堆栈指针*/
mov fp,#0 @ no previous frame, so fp=0
@ copy U-Boot toRAM /*注意:现在是运行在4k 的SRAM里,现在要把nand flash的内容拷贝到SDRAM中!vivi里面应该是有一段是针对gpio的程序,也许使用来debug用的信号灯,这里省略了*/
/*TEXT_BASE 是uboot自己的入口地址,在u-boot-1.3.4-board/gt2440的config.mk中定义
有趣的是外国人的逆向思维很厉害,它们很灵活地把它放在SDRAM的最后0x80000地方,也就是0x33F80000
*/
ldr r0, =TEXT_BASE /*r0 : 把u-boot复制到ram的那个位置*/
mov r1, #0x0 /*r1 : 从falsh的那个位置开始复制*/
mov r2, #0x20000 /*r2 : 复制多大的内容*/
bl nand_read_ll /*跳到执行uboot复制的程序入口,这个函数从哪里来?自己在后面写的,也可以参考vivi的*/
tst r0, #0x0 /*这里特别注意r0的值是指nand_read_ll 执行完以后的返回值,而不是上面ldr r0, =TEXT_BASE 的值,可以查看uboot反汇编文件,跟踪到nand_read_ll可得mov r0,#0*/
beq ok_nand_read
bad_nand_read: /*如果读nand_read失败的话,那么死循环*/
loop2: b loop2 @ infinite loop
ok_nand_read:
@ verify
/*下面这段程序的作用就是用开始执行的4Kbytes程序跟笔者复制到SRAM中的uboot的前4K程序进行比较,从而校验,现在运行在SRAM里*/
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3: b loop3 @ infinite loop
#endif @ CONFIG_S3C2440_NAND_BOOT
1.5 跳转到C函数之前,即跳出start.S进入第二阶段之前,加个led控制,点灯大法,具体参照读者的硬件配置
ble clbss_l
ldr pc,_start_armboot
#ifdefined(CONFIG_S3C2440)
/*LED1 onu-boot stage 1 is ok!,gt2440.h*/
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_B
ldr r2,=0x3D57FC
str r2, [r1, #oGPIO_CON]
ldr r2, =0x7ff
str r2, [r1, #oGPIO_UP]
ldr r2, =0x7fce
str r2, [r1, #oGPIO_DAT]
#endif/*s3c2440*/
_start_armboot: .word start_armboot
1.6在“_start_armboot: .word start_armboot”后加入
#ifdefined(CONFIG_S3C2440_NAND_BOOT)
.align 2 /*四字节对齐*/
DW_STACK_START:.wordSTACK_BASE+STACK_SIZE-4/*这里的STACK_BASE和 STACK_SIZE 将在gt2440.h中定义*/
#endif
2. 修改include/configs/gt2440.h文件,因为参考的s3c2410与s3c2440的nandflash控制器寄存器不同,其他相同的可以不改
/*
* Nandflash Boot
*/
#define CONFIG_S3C2440_NAND_BOOT 1
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x8000
/* NAND Flash Controller */
#define NAND_CTL_BASE 0x4E000000
/* Offset */
#define oNFCONF 0x00 /*这些宏是在start.S中被调用的*/
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFADDR 0x0c
#define oNFDATA 0x10
#define oNFSTAT 0x20
#define oNFECC 0x2c
/* GPIO */
#define GPIO_CTL_BASE 0x56000000
#define oGPIO_F 0x50
#define oGPIO_CON 0x0 /* R/W,Configures the pins of the port */
#define oGPIO_DAT 0x4 /*R/W, Data register for port */
#define oGPIO_UP 0x8 /*R/W, Pull-up disable register */
#endif /* __CONFIG_H */
3. 在board/gt2440中加入NAND FLASH读函数文件同(参考的是《GT2440之 U-boot使用及移植详细手册》,可实现不同大小的nand读操作)
/*
* nand_read.c: Simple NAND read functions forbooting from NAND
*
* This is used by cpu/arm920/start.S assemblercode,
* and the board-specific linker script must makesure this
* file is linked within the first 4kB of NANDflash.
*
* Taken from GPLv2 licensed vivi bootloader,
* Copyright (C) 2002 MIZI Research, Inc.
*
* Author: Hwang, Chideok<hwang@mizi.com>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping(C) 2006 by OpenMoko, Inc
* Author: Harald Welte<laforge@openmoko.org>
*/
#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))
#defineNF_BASE 0x4e000000
#ifdefined(CONFIG_S3C2410)
#defineNFCONF __REGi(NF_BASE + 0x0)
#defineNFCMD __REGb(NF_BASE + 0x4)
#defineNFADDR __REGb(NF_BASE + 0x8)
#defineNFDATA __REGb(NF_BASE + 0xc)
#defineNFSTAT __REGb(NF_BASE + 0x10)
#defineNFSTAT_BUSY 1
#definenand_select() (NFCONF &= ~0x800)
#definenand_deselect() (NFCONF |= 0x800)
#definenand_clear_RnB() do {} while (0)
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
#defineNFCONF __REGi(NF_BASE + 0x0)
#defineNFCONT __REGi(NF_BASE + 0x4)
#defineNFCMD __REGb(NF_BASE + 0x8)
#defineNFADDR __REGb(NF_BASE + 0xc)
#defineNFDATA __REGb(NF_BASE + 0x10)
#defineNFDATA16 __REGw(NF_BASE + 0x10)
#defineNFSTAT __REGb(NF_BASE + 0x20)
#defineNFSTAT_BUSY 1
#definenand_select() (NFCONT &= ~(1 << 1))
#definenand_deselect() (NFCONT |= (1 << 1))
#definenand_clear_RnB() (NFSTAT |= (1 << 2))
#endif
static inlinevoid nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}
structboot_nand_t { /*用来贮存芯片的参数*/
int page_size;
int block_size;
int bad_block_offset;
// unsignedlong size;
};
#if 0
#ifdefined(CONFIG_S3C2410) || defined(CONFIG_GT2440)
/*configuration for 2410 with 512byte sized flash */
#defineNAND_PAGE_SIZE 512
#defineBAD_BLOCK_OFFSET 5
#defineNAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#defineNAND_BLOCK_SIZE 0x4000
#else
/*configuration for 2440 with 2048byte sized flash */
#defineNAND_5_ADDR_CYCLE
#defineNAND_PAGE_SIZE 2048
#defineBAD_BLOCK_OFFSET NAND_PAGE_SIZE
#defineNAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#defineNAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
#endif /*defined(CONFIG_S3C2410) || defined(CONFIG_GT2440)*/
/* compile timefailure in case of an invalid configuration */
#ifdefined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
#error"S3C2410 does not support nand page size != 512"
#endif /*defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)*/
#endif /*IF 0*/
static intis_bad_block(struct boot_nand_t * nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;
nand_clear_RnB();
/*page_size的不同主要是读的时候写地址不一样,2K的为5次,2次Colmn 3次row address
而512的是1次Colmn和3次row address具体怎么安排,可看芯片手册
还有一些宏,例如NAND_CMD_READ0定义在include/linux/mtd/nand.h里*/
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 */
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;
return 0;
}
static intnand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned longaddr)
{
unsigned short *ptr16 = (unsigned short *)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; /*0x30*/
}
else
{
return -1;
}
nand_wait();
#ifdefined(CONFIG_S3C2410)
for (i = 0; i < nand->page_size; i++) {
*buf = (NFDATA & 0xff); /*8位线宽*/
buf++;
}
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
for (i = 0; i <(nand->page_size>>1); i++) {
*ptr16 = NFDATA16; /*16位线宽*/
ptr16++;
}
#endif /* defined(CONFIG_S3C2410)*/
return nand->page_size;
}
static unsignedshort nand_read_id()
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res << 8) | NFDATA;
return res;
}
extern unsignedint dynpart_size[];
/* low levelnand read function */
intnand_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();
if (0) { /* dirty little hack to detect ifnand id is misread */
unsigned short * nid = (unsigned short*)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76 || /* Samsung K91208 */
nand_id == 0xad76 ) { /*HynixHY27US08121A*/
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
// nand.size = 0x4000000;
} else if (nand_id == 0xecf1 || /* SamsungK9F1G08U0B */
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;
// nand.size = 0x8000000;
} else {
return -1; // hang
}
if ((start_addr & (nand.block_size-1)) ||(size & ((nand.block_size-1))))
return-1; /* invalid alignment */
for (i=start_addr; i < (start_addr +size);) {
#ifndefCONFIG_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;
}
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/
4. 修改board/gt2440/lowlevel_init.S文件
由于这个是底层的初始化文件,所以要根据读者的开发板情况来配置或者修改/board/gt2440/lowlevel_init.S文件
/* REFRESH parameter 下面这6个配置都可以参考s3c2440A datasheet P210的REFRESH寄存器 */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp 0x01 /* 3clk 这个值可以参考本版子上的SDRAM的datasheet*/
#defineTrc 0x3 /* 也就是SDRAM datasheet里面的Tsrc 7clk 本来这个地方是Trc,但从lowlevel_init.S里面的调用来看,应该是s3c2440的寄存器REFRESH的Tsrc才对,好多地方都没有改过来,只是个名字而已,不影响结果
注意:如果这里改了,那么下面这句中的Trc也要改为相应的
Tsrc:
.word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)*/
#define Tchr 0x2 /* 3clk,这个从lowlevel_init.S里面的调用来看是属于REFRESH的保留位,不知道为什么还要给他赋值*/
#defineREFCNT 1259 /*这个值的算法参考s3c2440A datasheet P210的Refresh Counter
Refresh count = 2^11 + 1- HCLK * period */
/*下面不厌其烦地解析一下lowlevel_init.S这个原文件*/
#define BWSCON 0x48000000
……
#define Tchr 0x2 /* 3clk */
#define REFCNT 0x0459
/**************************************/
/*1.要知道上面这些配置的最终会被用到下面SMRDATA 这个数据池里面,所以必须要明白SMRDATA 这个数据池是用
来干什么的,SMRDATA 后面每一个.word 后面放置的数据都是将要写入BWSCON 开始的寄存器的,总共有13个.word ,它们后面放置的值将会分别写入0x48000000、0x48000004、0x48000008…一直到0x48000030共13个寄存器。 */
/*2.上面那些配置的值是怎样决定的呢,详细请参考s3c2440A和你所用SDRAM的datasheet。细心找总是能找到的。*/
/*3.而上面的那些配置值最终是通过下面lowlevel_init后面的这段函数写到寄存器里面的,下面对该段函数逐一分析:*/
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* memory controlconfiguration */
/* make r0 relative thecurrent location so that it */
/* reads SMRDATA out of FLASHrather than memory ! */
ldr r0, =SMRDATA
ldr r1, _TEXT_BASE
sub r0, r0, r1 /*其实明白了前三条语句这段程序就不难懂了,归根到底就是为什么将SMRDATA 的值减去_TEXT_BASE的值?
原因如下:
当笔者编译出uboot的时候,编译器会给uboot这程序定一个初始地址作为基地址,其它就以它为基准,这个地址就是在config.mk里指定的TEXT_BASE,笔者的定为0x33f80000。
笔者使用的是从nandflashboot的方式,目前程序仍然在4K-bytes ‘Steppingstone’(即开始的4K SRAM)上面运行。
现在代码还没有搬运到内存中,什么时候搬?就是下一段代码要做的。所以如果调用这个label的话,找不到数据的,因为那个位置没东西,那数据在哪?在flash中!!那怎么找?其实flash是安排在0x0地址中的,所以真正的数据也是在相对于0x0的位置,那怎么找?就是用你相对于text_base的位置减去text_base的不就可以吗?事实笔者也是这样做的。*/
ldr r1, =BWSCON /* Bus Width StatusController */
add r2, r0, #13*4 /*总共13个寄存器*/
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
/* everything is fine now */
mov pc, lr
.ltorg /*数据缓冲池,上网可以查得资料*/
/* the literal pools origin */
SMRDATA:
……
.word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0xb2
.word 0x30 /*需要注意的是CASLatency的值在这里直接配置*/
.word 0x30
/***********************************************************
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
************************************************************/
5. 修改board/gt2440/gt2440.c
这个文件主要板级初始化的任务(如:GPIO初始化,lcd、网卡初始化类,PLL),修改的地方主要包括:修改PLL、增加LCD初始化函数(暂时没加)、修改GPIO设置、如果网上不是CS8900还要添加网卡芯片的初始化函数。
这里主要修改GPIO设置和PLL设置
#elif FCLK_SPEED==1 /* Fout =405MHz */
//#define M_MDIV 0x5c
//#define M_PDIV 0x4
//#define M_SDIV 0x0
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
#elif USB_CLOCK==1
//#define U_M_MDIV 0x48
//#define U_M_PDIV 0x3
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
/*对于PLL时钟问题,笔者把参考《ARM79出口-u-boot移植手册》,将UPLLCON的配置和MPLLCON的配置顺序颠倒一下(不颠倒也是可以工作的,但是S3c2440 datasheet文档中明确规定,笔者就按它说的去做吧)*/
/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV <<12) + (U_M_PDIV << 4) +
U_M_SDIV);
/* some delaybetween MPLL and UPLL */
delay(0xffff);
delay(0xffff);
delay(0xffff);
/*configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12
/*some delay between MPLL and UPLL */
delay(0xffff);
delay(0xffff);
delay(0xffff);
......
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
// gpio->GPBCON = 0x00044556;
gpio->GPBCON =0x3D57FC; /*for LED*/
......
/* arch number of S3C2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
/* adress of boot parameters */
gd->bd->bi_boot_params =0x30000100;
icache_enable();
dcache_enable();
gpio->GPBDAT = 0x7f8e; /*for LED*/
//int board_init (void)设置完成后,LED1和LED2会亮起!
return 0;
}
这里说明一下,gt2440.c完成的板级初始化函数在哪里调用。其实它是被定义在
init_fnc_t *init_sequence[]
这个初始化函数指针集里的,很熟悉吧?就是在前面介绍流程board.c里面,它从汇编跳到这执行start_armboot()函数,在函数里一一执行。
/*===========================================================
到这里,应该是可以编译通过的,否则就是编辑的时候出现了错误
===========================================================*/