分类: 嵌入式
2010-09-16 09:31:31
将u-boot-1.1.6.tar.bz2解压,得到文件夹u-boot-1.1.6
采用交叉编译器arm-linux-gcc 3.4.1。
1)、在u-boot-1.1.6/board下找个与QQ2440相似的开发板,这里选smdk2410。
2)、将u-boot-1.1.6/board/smdk2410目录复制到board目录下,并改名为QQ2440。
3)、把smdk2410.c改名为QQ2440.c,修改Makefile中的 COBJS := QQ2440.o flash.o,保存。
4)、将u-boot-1.1.6/include/configs/smdk2410.h,复制到include/configs目录,并改名为QQ2440.h。
6)、在u-boot-1.1.6/Makefile中添加
2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t QQ2440 NULL s3c24x0
7)、打开超级终端,切换到u-boot-1.1.6目录,敲入命令
# make QQ2440_config
Configuring for 2440 board...
8)、之后就可以# make了,如正常编译通过,表明环境搭建好。
接下来进入移植当中最为繁琐也最考验一个人耐心的阶段,修改文件。
(这里没有定义config_s3c2440,用的是config_s3c2410,但实际上是s3c2440的配置)
第126行添加中断模式寄存器的定义:
# define INTMOD 0X4A000004
第146行
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
改为:
# if defined(CONFIG_S3C2410)
ldr r1, =0x7fff /*15位的中断*/
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
第150行注释掉时钟设置(因为在下面我们调用子函数完成)
#if 0
/* FCLK:HCLK:PCLK = 1:4:8 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
第168行将堆栈设置提到前面以便后面C函数clock_init的调用。
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
sub sp, r0, #12 /* leave 3 words for abort-stack */
bl clock_init /*初始化系统时钟,自己添加的函数*/
第185行(因为堆栈在前面已经设置)
beq stack_setup
改为
beq clear_bss
第190行
add r2, r0, r2 /* r2 <- source end address */
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
改为:(CopyCode2Ram函数在board/QQ2440\boot_init下。boot_init文件自己添加)
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
#else
add r2, r0, r2 /* r2 <- source end address */
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
第208行注释掉堆栈设置
/* Set up the stack */
/*stack_setup:*/
/* ldr r0, _TEXT_BASE // upper 128 KiB: relocated uboot */
/* sub r0, r0, #CFG_MALLOC_LEN // malloc area */
/* sub r0, r0, #CFG_GBL_DATA_SIZE // bdinfo */
/* #ifdef CONFIG_USE_IRQ */
/* sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) */
/* #endif */
/* sub sp, r0, #12 // leave 3 words for abort-stack */
第54行(bank1接IDE,Nor Flash为32位,nand Flash为16位)
#define B1_BWSCON (DW32)
改为:
#define B1_BWSCON (DW16)
第126行(修改存储器刷新计数值)
#define REFCNT 1113 /* period="15".6us, HCLK="60Mhz", (2048+1-15.6*60) */
改为:
#define REFCNT 0x4f4 /* period=7.8125us, HCLK=100Mhz, (2048+1-7.8125*100) */
第74行添加(调用内核使用到)
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_CMDLINE_TAG 1
第81行添加三条命令
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
/*************lihuistart********/\
CFG_CMD_PING | \
CFG_CMD_JFFS2 | \
CFG_CMD_NAND | \
/* End: *lihui************/ \
/*CFG_CMD_NAND |*/ \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
第98行修改网口配置
#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" *
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b *
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 10.0.0.110
#define CONFIG_SERVERIP 10.0.0.1
#define CONFIG_BOOTFILE "elinos-lart" *
#define CONFIG_BOOTCOMMAND "tftp; bootm"
/*****************************************lihui*****/
#define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.17
#define CONFIG_SERVERIP 192.168.1.106
/*#define CONFIG_BOOTFILE "elinos-lart" */
#define CONFIG_BOOTCOMMAND "nboot 0x320000000 0x50000; bootm 0x32000000"
第182行修改输出文字
#define CFG_PROMPT "sdmk2410#" /* Monitor Command Prompt */
改为:
#define CFG_PROMPT "QQ2440> " /* Monitor Command Prompt */
第180行修改flash选择
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#if 0
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#endif
改为
#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#endif
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
在最后添加Nand Flash设置
/*NAND flash settings */
#define CFG_NAND_BASE 0 //随便设
#define CFG_MAX_NAND_DEVICE 1 //设备数1
#define NAND_MAX_CHIPS 1 //片数1
第23行有关时钟定义修改为:
#define S3C2440_MPLL_400MHZ 0x7f021
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_100MHZ ((0x5c<<12)|(0x01<<4)|(0x03))
#define S3C2440_UPLL_48MHZ ((0x38<<12)|(0x02<<4)|(0x02))
#define S3C2440_CLKDIV 0x05 /* FCLK:HCLK:PCLK = 1:4:8, UCLK = UPLL */
#define S3C2440_CLKDIV188 0x04 /* FCLK:HCLK:PCLK = 1:8:8 */
#define S3C2440_CAMDIVN188 ((0<<8)|(1<<9)) /* FCLK:HCLK:PCLK = 1:8:8 */
/* S3C2410: Mpll,Upll = (m * Fin) / (p * 2^s)
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
*/
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2410_UPLL_48MHZ ((0x28<<12)|(0x01<<4)|(0x02))
#define S3C2410_CLKDIV 0x03 /* FCLK:HCLK:PCLK = 1:2:4 */
第66行在board_init函数中注释掉原有的时钟配置
/* to reduce PLL lock time, adjust the LOCKTIME register */
/* clk_power->LOCKTIME = 0xFFFFFF;*/
/* configure MPLL */
/* clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);*/
/* some delay between MPLL and UPLL */
/* delay (4000);*/
/* configure UPLL */
/* clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);*/
/* some delay between MPLL and UPLL */
添加:
/* support both of S3C2410 and S3C2440, by */
if ((gpio->GSTATUS1 == 0x32410000) || (gpio->GSTATUS1 == 0x32410002))
{
/* FCLK:HCLK:PCLK = 1:2:4 */
clk_power->CLKDIVN = S3C2410_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
}
else
{
#if 1
/* FCLK:HCLK:PCLK = 1:4:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV;
#else
/* FCLK:HCLK:PCLK = 1:8:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV188;
clk_power->CAMDIVN = S3C2440_CAMDIVN188;
#endif
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
/* arch number of QQ2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
}
第129行在结构体s3c24x0_clock_power中添加CAMDIVN(分频用)
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
改为:
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
S3C24X0_REG32 CAMDIVN; /* for s3c2440 */
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
第170添加Nand结构体的定义
/* NAND FLASH (see S3C2440 manual chapter 6, ) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSBLK;
S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;
第100行添加获取s3c2440_NAND基址的函数
/* for s3c2440*/
static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
{
return (S3C2440_NAND * const)S3C2410_NAND_BASE;
}
1) cpu/arm920t/s3c24x0/speed.c
第41行添加全局变量声明
DECLARE_GLOBAL_DATA_PTR;
第70行注释掉
/* return((CONFIG_SYS_CLK_FREQ * m) / (p << s));*/
改为
/* support both of S3C2410 and S3C2440 */
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
else
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s)); /* S3C2440 */
第87行添加s3c2440_clkdivn的配置定义
/* for s3c2440 */
#define S3C2440_CLKDIVN_PDIVN (1<<0)
#define S3C2440_CLKDIVN_HDIVN_MASK (3<<1)
#define S3C2440_CLKDIVN_HDIVN_1 (0<<1)
#define S3C2440_CLKDIVN_HDIVN_2 (1<<1)
#define S3C2440_CLKDIVN_HDIVN_4_8 (2<<1)
#define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1)
#define S3C2440_CLKDIVN_UCLK (1<<3)
#define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0)
#define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4)
#define S3C2440_CAMDIVN_HCLK3_HALF (1<<8)
#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9)
#define S3C2440_CAMDIVN_DVSEN (1<<12)
第105行函数get_HCLK修改为:
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
/* support both of S3C2410 and S3C2440*/
unsigned long clkdiv;
unsigned long camdiv;
int hdiv = 1;
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
else
{
clkdiv = clk_power->CLKDIVN;
camdiv = clk_power->CAMDIVN;
/* work out clock scalings */
switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
case S3C2440_CLKDIVN_HDIVN_1:
hdiv = 1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv = 2;
break;
case S3C2440_CLKDIVN_HDIVN_4_8:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
break;
}
return get_FCLK() / hdiv;
}
}
第149行get_PCLK函数修改为:
ulong get_PCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
unsigned long clkdiv;
unsigned long camdiv;
int hdiv = 1;
/* support both of S3C2410 and S3C2440,*/
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
return((clk_power->CLKDIVN & 0x1) ? get_HCLK()/2 : get_HCLK());
else
{
clkdiv = clk_power->CLKDIVN;
camdiv = clk_power->CAMDIVN;
/* work out clock scalings */
switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
case S3C2440_CLKDIVN_HDIVN_1:
hdiv = 1;
break;
case S3C2440_CLKDIVN_HDIVN_2:
hdiv = 2;
break;
case S3C2440_CLKDIVN_HDIVN_4_8:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
break;
case S3C2440_CLKDIVN_HDIVN_3_6:
hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
break;
}
return get_FCLK() / hdiv / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
}
}
并修改当前目录下的Makefile中的 COBJS := QQ2440.o flash.o,
为COBJS := QQ2440.o flash.o boot_init.o
内容如下:
#include
#include
#define GSTATUS1 (*(volatile unsigned int *)0x560000B0)
#define BUSY 1
/* 供外部调用的函数 */
void nand_init_ll(void);
void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);
/* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */
static void nand_reset(void);
static void wait_idle(void);
static void nand_select_chip(void);
static void nand_deselect_chip(void);
static void write_cmd(int cmd);
static void write_addr(unsigned int addr);
static unsigned char read_data(void);
/* S3C2410的NAND Flash处理函数 */
static void s3c2410_nand_reset(void);
static void s3c2410_wait_idle(void);
static void s3c2410_nand_select_chip(void);
static void s3c2410_nand_deselect_chip(void);
static void s3c2410_write_cmd(int cmd);
static void s3c2410_write_addr(unsigned int addr);
static unsigned char s3c2410_read_data(void);
/* S3C2440的NAND Flash处理函数 */
static void s3c2440_nand_reset(void);
static void s3c2440_wait_idle(void);
static void s3c2440_nand_select_chip(void);
static void s3c2440_nand_deselect_chip(void);
static void s3c2440_write_cmd(int cmd);
static void s3c2440_write_addr(unsigned int addr);
static unsigned char s3c2440_read_data(void);
/* S3C2410的NAND Flash操作函数 */
/* 复位 */
static void s3c2410_nand_reset(void)
{
s3c2410_nand_select_chip();
s3c2410_write_cmd(0xff); // 复位命令
s3c2410_wait_idle();
s3c2410_nand_deselect_chip();
}
/* 等待NAND Flash就绪 */
static void s3c2410_wait_idle(void)
{
int i;
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
}
/* 发出片选信号 */
static void s3c2410_nand_select_chip(void)
{
int i;
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
s3c2410nand->NFCONF &= ~(1<<11);
for(i=0; i<10; i++);
}
/* 取消片选信号 */
static void s3c2410_nand_deselect_chip(void)
{
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
s3c2410nand->NFCONF |= (1<<11);
}
/* 发出命令 */
static void s3c2410_write_cmd(int cmd)
{
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD;
*p = cmd;
}
/* 发出地址 */
static void s3c2410_write_addr(unsigned int addr)
{
int i;
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFADDR;
*p = addr & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 9) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 17) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 25) & 0xff;
for(i=0; i<10; i++);
}
/* 读取数据 */
static unsigned char s3c2410_read_data(void)
{
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA;
return *p;
}
/* S3C2440的NAND Flash操作函数 */
/* 复位 */
static void s3c2440_nand_reset(void)
{
s3c2440_nand_select_chip();
s3c2440_write_cmd(0xff); // 复位命令
s3c2440_wait_idle();
s3c2440_nand_deselect_chip();
}
/* 等待NAND Flash就绪 */
static void s3c2440_wait_idle(void)
{
int i;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
}
/* 发出片选信号 */
static void s3c2440_nand_select_chip(void)
{
int i;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
s3c2440nand->NFCONT &= ~(1<<1);
for(i=0; i<10; i++);
}
/* 取消片选信号 */
static void s3c2440_nand_deselect_chip(void)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
s3c2440nand->NFCONT |= (1<<1);
}
/* 发出命令 */
static void s3c2440_write_cmd(int cmd)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
*p = cmd;
}
/* 发出地址 */
static void s3c2440_write_addr(unsigned int addr)
{
int i;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
*p = addr & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 9) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 17) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 25) & 0xff;
for(i=0; i<10; i++);
}
/* 读取数据 */
static unsigned char s3c2440_read_data(void)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
return *p;
}
/* 在第一次使用NAND Flash前,复位一下NAND Flash */
static void nand_reset(void)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_nand_reset();
}
else
{
s3c2440_nand_reset();
}
}
static void wait_idle(void)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_wait_idle();
}
else
{
s3c2440_wait_idle();
}
}
static void nand_select_chip(void)
{
int i;
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_nand_select_chip();
}
else
{
s3c2440_nand_select_chip();
}
for(i=0; i<10; i++);
}
static void nand_deselect_chip(void)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_nand_deselect_chip();
}
else
{
s3c2440_nand_deselect_chip();
}
}
static void write_cmd(int cmd)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_write_cmd(cmd);
}
else
{
s3c2440_write_cmd(cmd);
}
}
static void write_addr(unsigned int addr)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
s3c2410_write_addr(addr);
}
else
{
s3c2440_write_addr(addr);
}
}
static unsigned char read_data(void)
{
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
return s3c2410_read_data();
}
else
{
return s3c2440_read_data();
}
}
/* 初始化NAND Flash */
void nand_init_ll(void)
{
S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
/* 判断是S3C2410还是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */
s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else
{
/* 设置时序 */
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
}
/* 复位NAND Flash */
nand_reset();
}
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* 读函数 */
void nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ; /* 地址或长度不对齐 */
}
/* 选中芯片 */
nand_select_chip();
for(i=start_addr; i < (start_addr + size);) {
/* 发出READ0命令 */
write_cmd(0);
/* Write Address */
write_addr(i);
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = read_data();
buf++;
}
}
/* 取消片选信号 */
nand_deselect_chip();
return ;
}
int bBootFrmNORFlash(void)
{
volatile unsigned int *pdw = (volatile unsigned int *)0;
unsigned int dwVal;
/*
* 无论是从NOR Flash还是从NAND Flash启动,
* 地址0处为指令"b Reset", 机器码为0xEA00000B,
* 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中,
* 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。
* 对于NOR Flash,必须通过一定的命令序列才能写数据,
* 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:
* 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash
*/
dwVal = *pdw;
*pdw = 0x12345678;
if (*pdw != 0x12345678)
{
return 1;
}
else
{
*pdw = dwVal;
return 0;
}
}
int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
unsigned int *pdwDest;
unsigned int *pdwSrc;
int i;
if (bBootFrmNORFlash())
{
pdwDest = (unsigned int *)buf;
pdwSrc = (unsigned int *)start_addr;
/* 从 NOR Flash启动 */
for (i = 0; i < size / 4; i++)
{
pdwDest[i] = pdwSrc[i];
}
return 0;
}
else
{
/* 初始化NAND Flash */
nand_init_ll();
/* 从 NAND Flash启动 */
nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
return 0;
}
}
static inline void delay (unsigned long loops)
{
__asm__ volatile ("1:\n"
"subs %0, %1, #1\n"
"bne 1b":"=r" (loops):"0" (loops));
}
/* S3C2440: Mpll = (2*m * Fin) / (p * 2^s), UPLL = (m * Fin) / (p * 2^s)
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
*/
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
#define S3C2440_MPLL_100MHZ ((0x5c<<12)|(0x01<<4)|(0x03))
#define S3C2440_UPLL_48MHZ ((0x38<<12)|(0x02<<4)|(0x02))
#define S3C2440_CLKDIV 0x05 /* FCLK:HCLK:PCLK = 1:4:8, UCLK = UPLL */
#define S3C2440_CLKDIV188 0x04 /* FCLK:HCLK:PCLK = 1:8:8 */
#define S3C2440_CAMDIVN188 ((0<<8)|(1<<9)) /* FCLK:HCLK:PCLK = 1:8:8 */
/* S3C2410: Mpll,Upll = (m * Fin) / (p * 2^s)
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
*/
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2410_UPLL_48MHZ ((0x28<<12)|(0x01<<4)|(0x02))
#define S3C2410_CLKDIV 0x03 /* FCLK:HCLK:PCLK = 1:2:4 */
void clock_init(void)
{
S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;
/* support both of S3C2410 and S3C2440, by */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
/* FCLK:HCLK:PCLK = 1:2:4 */
clk_power->CLKDIVN = S3C2410_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
else
{
/* FCLK:HCLK:PCLK = 1:4:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
}
并在当前目录下的Makefile中的 COBJS 下添加上nand_flash.o
内容如下:
/*
* Nand flash interface of s3c2410/s3c2440, by
* Changed from drivers/mtd/nand/s3c2410.c of kernel 2.6.13
*/
#include
#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include
#include
DECLARE_GLOBAL_DATA_PTR;
#define S3C2410_NFSTAT_READY (1<<0)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2440_NFSTAT_READY (1<<0)
#define S3C2440_NFCONT_nFCE (1<<1)
/* select chip, for s3c2410 */
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
if (chip == -1) {
s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
} else {
s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
}
}
/* command and control functions, for s3c2410
*
* Note, these all use tglx's method of changing the IO_ADDR_W field
* to make the code simpler, and use the nand layer's code to issue the
* command and address sequences via the proper IO ports.
*
*/
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
break;
}
}
/* s3c2410_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
*/
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
}
/* select chip, for s3c2440 */
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
if (chip == -1) {
s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
} else {
s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
}
}
/* command and control functions */
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
break;
}
}
/* s3c2440_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
*/
static int s3c2440_nand_devready(struct mtd_info *mtd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
}
/*
* Nand flash hardware initialization:
* Set the timing, enable NAND flash controller
*/
static void s3c24x0_nand_inithw(void)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)
{
/* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else
{
/* Set flash memory timing */
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* Initialize ECC, enable chip select, NAND flash controller enable */
s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
}
}
/*
* Called by drivers/nand/nand.c, initialize the interface of nand flash
*/
void board_nand_init(struct nand_chip *chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
s3c24x0_nand_inithw();
if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410) {
chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->select_chip = s3c2410_nand_select_chip;
chip->options = 0;
} else {
chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
chip->hwcontrol = s3c2440_nand_hwcontrol;
chip->dev_ready = s3c2440_nand_devready;
chip->select_chip = s3c2440_nand_select_chip;
chip->options = 0;
}
chip->eccmode = NAND_ECC_SOFT;
}
#endif
第36行添加(显示用)
Board/QQ2440/boot_init.o(.text)
在u-boot-1.1.6目录下
#make QQ2440_config
# make all
此时在u-boot-1.1.6目录下生成u-boot.bin文件
要烧写U-Boot,必须确定Nor Flash中的BIOS为Supervivi2.0,把开发板设置为Nor lash启动,连接好串口和USB线,打开超级终端,打开电源,串口显示如图:
打开DNW,确认USB 连接正常 OK,点UsbPortTransmit/Restore,选择刚才所编译的u-boot.bin,下载和烧写很快就会结束。把QQ2440启动模式跳线改为Nand Flash启动,重新复位或者重启开机电源开关,在串口终端可以看到如图信息:
至此U-Boot已经编译并下载到开发板中运行了,这时你需要完全抛弃 Nor Flash中supervivi的那些功能命令,使用U-Boot本身的功能来下载和烧写内核,以及文件系统。