1、u-boot移植前期準備
1.1建立開發闆目錄結構
我建立了fl2440這個檔案夾,除了bootloader的u-boot之外,以後需要制作的Linux核心,根檔案系統,相關的驅動,第三方應用,自己寫的程式等,都放入對應目錄下,便于管理。
[[email protected] ~]$ cd fl2440/
[[email protected] fl2440]$ ls
3rdparty bootloader driver kernel mkdir program rootfs
[[email protected] fl2440]$ ll
total 28
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 3rdparty
drwxrwxr-x 4 tangbin tangbin 4096Mar 9 19:57 bootloader
drwxrwxr-x 3 tangbin tangbin 4096 Mar 1620:22 driver
drwxrwxr-x 3 tangbin tangbin 4096 Mar 1620:10 kernel
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 mkdir
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 program
drwxrwxr-x 2 tangbin tangbin 4096 Oct 1615:28 rootfs
1.2準備好u-boot源碼包
可以到u-boot的FTP上直接下載下傳(ftp://ftp.denx.de/pub/u-boot/u-boot-2010.09.tar.bz2),下載下傳完成後得到一個壓縮包。
将其解壓,得到如下檔案:
[[email protected] bootloader]$ tar -xjf u-boot-2010.09.tar.bz2
[[email protected] bootloader]$ ls
u-boot-2010.09 u-boot-2010.09.tar.bz2
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN0LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90TUhFXOXlVNsdlWzYUbZZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TOwcjNxEjMwIDMyMDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
2、開發闆建立與編譯測試
2.1u-boot 源碼中添加 fl2440 開發闆
依次執行:cd board
mkdir -p lingyun/fl2440 #建立以後我們要用的檔案夾,-p是指一次性建立多層次的目錄
# FL2440開發闆移植u-boot以smdk2410為主機闆進行移植,是以用smdk2410建立配置檔案。
cp samsung/smdk2410/* lingyun/fl2440/
cd lingyun/fl2440/
mv smdk2410.c fl2440.c
修改Makefile
vim Makefile
-COBJS :=smdk2410.o flash.o
+COBJS := fl2440.o flash.o #将原來的smdk2410.o改成fl2440.o
cd ../../../
cp include/configs/smdk2410.hinclude/configs/fl2440.h
[[email protected] u-boot-2010.09bk]$ vim boards.cfg
在smdk2410下添加一條代碼:
這一行中的小“-”代表u-boot下的board目錄,是以,如果你是在board下建立fl2440檔案夾,就用“-”,如果你在board下建立了其他的檔案下,再建立的fl2440目錄,就要填寫那個目錄名
[[email protected] u-boot-2010.09bk]$ vim Makefile
添加交叉編譯器。
接下來執行:
make fl2440_config
make
這時候編譯出來的 u-boot.bin 就是要燒到開發闆上的 u-boot 檔案,但這個代碼是基于smdk2410 開發闆的,我們并沒有對這個代碼作任何的修改,是以這個 bin 檔案隻能在smdk2410 這個開發闆上跑。
如果想運作在 FL2440 這個開發闆上,接下來我們就要開始對源代碼進行修改。
注:make fl2440_config(make xxx_config)這個指令的作用。因為在執行make之前,先要執行make $(board)_config 對工程進行配置,以确定特定于目标闆的各個子目錄和頭檔案。
$(board)_config:是makefile 中的一個僞目标,它傳入指定的CPU,ARCH,BOARD,SOC參數去執行mkconfig腳本。
這個腳本的主要功能在于連接配接目标闆平台相關的頭檔案夾,生成config.h檔案包含闆子的配置頭檔案。
使得makefile能根據目标闆的這些參數去編譯正确的平台相關的子目錄。
以fl2440闆為例,執行 make fl2410_config
3、u-boot移植
3.1概述
我們的u-boot是從Nand flash啟動的,以此做分析。
前面已經提到了前期準備工作,下面就是對u-boot啟動代碼的修改了。
主要修改start.S、lowlevel_init.S,硬體初始化:設定異常向量—>cpu進入SVC模式—>設定控制寄存器位址—>關看門狗—>關中斷—>設定時鐘寄存器—>執行cpu_init_crit關閉MMU和cache。
接着添加DM9000網卡的支援,最後是Nand flash啟動代碼修改,支援nandflash啟動。
3.2Start.S分析
Start.S的執行流程大緻為:
1.硬體初始化:
進入svc模式;關閉watch dog;屏蔽所有IRQ掩碼;設定時鐘頻率FCLK、HCLK、PCLK;清I/D cache;禁止MMU和CACHE;配置memory control;
2.重定位:
如果目前代碼不在連接配接指定的位址上(對于s3c2440是0x33f80000)則需要把u-boot從目前位置拷貝到RAM指定位置中;
3.建立堆棧,堆棧是進入C函數前必須初始化的。
4.清.bss區。
5.跳到start_armboot函數中執行。(lib_arm/board.c)
3.3 Start.S的修改
1.将用于LED跳轉的兩行代碼注釋,我們不在這裡做程式跳轉:
2.删除從120行到169行,這些代碼是用于定義特殊寄存器和屏蔽中斷的,我們在後面統一定義:
vim arch/arm/cpu/arm920t/start.S
打開star.S後添加如下代碼:以下宏定義設定了s3c2440中斷、時鐘、nandflash控制器、看門狗、GPIO的基位址,具體詳見s3c2440開發闆的晶片手冊。
#define S3C24X0_INTERRUPT_BASE 0x4A000000
#define S3C24X0_CLOCK_POWER_BASE 0x4C000000
#define S3C2410_NAND_BASE 0x4E000000
#define S3C24X0_WATCHDOG_BASE 0x53000000
#define S3C24X0_GPIO_BASE 0x56000000
#define INTMSK_OFFSET 0x08
#define INTSUBMSK_OFFSET 0x1c
#define MPLLCON_OFFSET 0x04
#define CLKDIVN_OFFSET 0x14
#define NFCONF_OFFSET 0x00
#define NFCONT_OFFSET 0x04
#define NFCMD_OFFSET 0x08
#define NFSTAT_OFFSET 0x20
#define MDIV_405 0x7f << 12
#define PSDIV_405 0x21
#define MDIV_200 0xa1 << 12
#define PSDIV_200 0x31
接着上面的宏定義下,繼續添加關閉看門狗、屏蔽中斷、設定時鐘、初始化nandflash控制器代碼:
/****** Disable Watchdog ******/
ldr r0, =S3C24X0_WATCHDOG_BASE
mov r1, #0
str r1, [r0]
/****** Disable interrupt by mask all IRQmask ******/
ldr r0, =S3C24X0_INTERRUPT_BASE
mvn r1, #0x0
str r1, [r0, #INTMSK_OFFSET]
str r1, [r0, #INTSUBMSK_OFFSET]
/****** Initialize System Clock,FCLK:HCLK:PCLK = 1:4:8,default FCLK is 120MHz ******/
ldr r0, =S3C24X0_CLOCK_POWER_BASE
mov r1, #5
str r1, [r0, #CLKDIVN_OFFSET]
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
mov r2, #MDIV_405
add r2, r2, #PSDIV_405
str r2, [r0, #MPLLCON_OFFSET]
/***** Initialize Nandflash controller******/
mov r1, #S3C2410_NAND_BASE
ldr r2, =((7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #NFCONF_OFFSET]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE controller
str r2, [r1, #NFCONT_OFFSET]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #NFSTAT_OFFSET]
mov r2, #0xff @ Reset Nandflash
strb r2, [r1, #NFCMD_OFFSET]
mov r3, #0 @ Delay for awhile
delay:
add r3, r3, #0x1
cmp r3, #0xa
blt delay
wait:
ldr r2, [r1, #NFSTAT_OFFSET] @wait ready
tst r2, #0x4
beq wait
然後執行cpu_init_crit,關閉MMU和CACHE,再跳轉到board/fl2440/lowlevel_init.S中初始化RAM控制器:
3.4lowlevel_init.S的修改
修改RAM控制每個BANK的位址宏定義和參數設定,修改如下代碼,粗體部分為在原先代碼基礎上修改後的:
#define BWSCON 0x48000000
/* BWSCON */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
#define B1_BWSCON (DW16)
#define B2_BWSCON (DW16) #define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16)
#define B5_BWSCON (DW16)
#define B6_BWSCON (DW32)
#define B7_BWSCON (DW32)
/*BANK0CON */
#define B0_Tacs 0x0 /* 0clk */
#define B0_Tcos 0x0 /* 0clk */
#define B0_Tacc 0x7 /* 14clk */
#define B0_Tcoh 0x0 /* 0clk */
#define B0_Tah 0x0 /* 0clk */
#define B0_Tacp 0x0
#define B0_PMC 0x0 /* normal */
/*BANK1CON */
#define B1_Tacs 0x0 /* 0clk */
#define B1_Tcos 0x0 /* 0clk */
#define B1_Tacc 0x7 /* 14clk */
#define B1_Tcoh 0x0 /* 0clk */
#define B1_Tah 0x0 /* 0clk */
#define B1_Tacp 0x0
#define B1_PMC 0x0
#define B2_Tacs 0x0
#define B2_Tcos 0x0
#define B2_Tacc 0x7
#define B2_Tcoh 0x0
#define B2_Tah 0x0
#define B2_Tacp 0x0
#define B2_PMC 0x0
#define B3_Tacs 0xc /* 0clk */
#define B3_Tcos 0x7 /* 4clk */
#define B3_Tacc 0xf /* 14clk */
#define B3_Tcoh 0x1 /* 1clk */
#define B3_Tah 0x0 /* 0clk */
#define B3_Tacp 0x0 /* 6clk */
#define B3_PMC 0x0 /* normal */
#define B4_Tacs 0x0 /* 0clk */
#define B4_Tcos 0x0 /* 0clk */
#define B4_Tacc 0x7 /* 14clk */
#define B4_Tcoh 0x0 /* 0clk */
#define B4_Tah 0x0 /* 0clk */
#define B4_Tacp 0x0
#define B4_PMC 0x0 /* normal */
#define B5_Tacs 0xc /* 0clk */
#define B5_Tcos 0x7 /* 0clk */
#define B5_Tacc 0xf /* 14clk */
#define B5_Tcoh 0x1 /* 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 B7_MT 0x3 /* SDRAM */
#define B7_Trcd 0x1 /* 3clk */
#define B7_SCAN 0x1 /* 9bit */
修改初始化參數:
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Autorefresh */
#define Trp 0x2 /* 4clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#define REFCNT 1012 /* period=15.6us, HCLK=60Mhz,(2048+1-15.6*60) */
修改166行左右:
SMRDATA:(這部分定義的是BWSCON的13個寄存器的值)
.word 0x32 .word 0x32改為: .word 0xb2
.word 0x30
.word 0x30
3.5 修改配置支援s3c2440
修改include/asm/arch-s3c24x0/s3c24x0.h
#if defined(CONFIG_S3C2410)修改為#ifdefined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
修改nandflash的寄存器定義,修改s3c2410_nand結構體為如下:
#if defined (CONFIG_S3C2440)
/* NAND FLASH (see S3C2440 manual chapter 6) */
struct s3c2410_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};#endif
修改s3c24x0_clock_power結構體
struct s3c24x0_clock_power {
u32 LOCKTIME;
u32 MPLLCON;
u32 UPLLCON;
u32 CLKCON;
u32 CLKSLOW;
u32 CLKDIVN;
#if defined (CONFIG_S3C2440)
u32 CAMDIVN;
#endif
}
修改include/asm/arch/s3c24x0_cpu.h,補充對s3c2440的支援
檔案23行,修改#elif defined (CONFIG_S3C2410)為
#elif defined (CONFIG_S3C2410) ||(CONFIG_S3C2440)
修改arch/arm/cpu/arm920t/s3c24x0/timer.c檔案
184行添加支援s3c2440
defined(CONFIG_S3C2440) || \
修改arch/arm/cpu/arm920t/s3c24x0/speed.c
66行添加
#if defined(CONFIG_S3C2440)
if(pllreg == MPLL)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
else if(pllreg == UPLL)
#endif
修改get_HCLK()函數如下:
ulong get_HCLK(void)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
//return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 :get_FCLK();
#if defined(CONFIG_S3C2440) /* Modify byhurryliu*/
if (readl(&clk_power->CLKDIVN) & 0x6)
{
if((readl(&clk_power->CLKDIVN) & 0x6)==2)
return(get_FCLK()/2);
if ((readl(&clk_power->CLKDIVN) & 0x6)==6)
return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 :get_FCLK()/3);
if ((readl(&clk_power->CLKDIVN) & 0x6)==4)
return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 :get_FCLK()/4);
return(get_FCLK());
}
else
return(get_FCLK());
#else
return((readl(&clk_power->CLKDIVN)& 0x2) ? get_FCLK()/2 : get_FCLK());
#endif /* Modify end*/
}
修改include/configs/fl2440.h
38行添加#define CONFIG_S3C2440 1
4、添加支援從nandflash啟動代碼
4.1nandflash啟動代碼添加
vim arch/arm/cpu/arm920t/start.S
添加支援nandflash啟動代碼:
NANDFLASH_BOOT:
/*Get ready to call C functions fornand_read_ll() */
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
/* Read u-boot from Nandflash to SDRAMaddress $TEXT_BASE */
ldr r0, =TEXT_BASE /*nand_read_ll() 1st argument*/
mov r1, #0x0 /*nand_read_ll() 2nd argument*/
mov r2, #CONFIG_UBOOT_LENGTH /*nand_read_ll() 3rd argument*/
bl nand_read_ll
tst r0, #0x0 /*Check nand_read_ll() returnvalue*/
bne infinite_loop /*nand_read_ll() not return 0, then gotodead loop*/
nand_read_ok:
/*Then verify the read data validation*/
mov r0, #0 /*The first 4K data in internalSRAM*/
ldr r1, =TEXT_BASE /*The first 4K data read from Nandflash inSDRAM*/
mov r2, #0x400 /*The compare data length*/
compare_next_byte:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne infinite_loop
subs r2, r2, #4
beq stack_setup
bne compare_next_byte
infinite_loop:
b infinite_loop
注意:nandflash啟動代碼中的nand_read_ll()函數,nand_read_ll函數的作用是在NAND Flash中搬運U-Boot到RAM,該函數在board/samsung/mini2440/nand_read.c中定義。
4.2board/fl2440目錄下添加nand_read.c
添加C語言從NAND Flash搬移代碼部分,剛剛我們看到了彙編部分會調用一個C函數nand_read_ll,這個函數就在nand_read.c檔案中,要在board/fl2440目錄下建立一個名為nand_read.c的檔案.
/*
* 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 mustmake sure 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<[email protected]>
* Date : $Date: 2004/07/14 10:37:37 $
*
* u-boot integration and bad-block skipping(C) 2006 by OpenMoko, Inc.
* Author: Harald Welte<[email protected]>
*
*
*/
#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
#ifdefined(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)
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
#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))
#define nand_deselect() (NFCONT |= (1 <<1))
#defin enand_clear_RnB() (NFSTAT |= (1 << 2))
#endif
static inline void nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}
struct boot_nand_t {
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};
#if0
#ifdefined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
/*configuration for 2410 with 512byte sized flash */
#define NAND_PAGE_SIZE 512
#define BAD_BLOCK_OFFSET 5
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE 0x4000
#else
/*configuration for 2440 with 2048byte sized flash */
#define NAND_5_ADDR_CYCLE
#define NAND_PAGE_SIZE 2048
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
#endif
/*compile time failure in case of an invalid configuration */
#ifdefined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
#error"S3C2410 does not support nand page size != 512"
#endif
#endif
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 */
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 int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsignedlong addr)
{
unsigned short *ptr16 = (unsignedshort *)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();
#ifdefined(CONFIG_S3C2410)
for (i = 0; i < nand->page_size;i++) {
*buf = (NFDATA & 0xff);
buf++;
}
#elifdefined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
for (i = 0; i <(nand->page_size>>1); i++) {
*ptr16 = NFDATA16;
ptr16++;
}
#endif
return nand->page_size;
}
static unsigned short nand_read_id()
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res << 8) | NFDATA;
return res;
}
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();
if (0) { /* dirty little hack todetect if nand id is misread */
unsigned short * nid =(unsigned short *)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76 || /* Samsung K91208 on SD2410 board */
nand_id == 0xad76 ) { /*Hynix HY27US08121A*/
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
// nand.size = 0x4000000;
} else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
nand_id == 0xadda || /* Hynix HY27UF082G2B on FL2440 board */
nand_id == 0xecda || /* Samsung K9F2G08U0B on FL2440 board */
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);) {
#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)) {
/* Badblock */
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.3将nand_read.c檔案連結到u-boot.bin檔案的前4K代碼
vim board/fl2440/Makefile
添加nand_read.o使得nand_read.c能被編譯到u-boot.bin中
COBJS := fl2440.o nand_read.o
修改檔案arch/arm/cpu/arm920t/u-boot.lds,将u-boot從nandflash搬運的代碼連結到前4K的u-boot.bin中:
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
arch/arm/cpu/arm920t/start.o (.text)
board/fl2440/lowlevel_init.o (.text)(粗體部分為要添加的部分)
board/fl2440/nand_read.o (.text)
*(.text)
}
. = ALIGN(4);
4.4添加u-boot支援nandflash序列槽操作
vim include/configs/fl2440.h
/*
* NAND flash settings
*/
#ifdefined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Maxnumber of NAND devices */
#define CONFIG_SYS_NAND_BASE 0x4E000000
#define SECTORSIZE 512
#define SECTORSIZE_2K 2048
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_SECTOR_SIZE_2K SECTORSIZE_2K
#define NAND_BLOCK_MASK 511
#define NAND_BLOCK_MASK_2K 2047
#define NAND_MAX_CHIPS 1
#define CONFIG_MTD_NAND_VERIFY_WRITE
#define CONFIG_SYS_64BIT_VSPRINTF /* neededfor nand_util.c */
#endif /* CONFIG_CMD_NAND */
vim drivers/mtd/nand/s3c2410_nand.c 支援s3c2440開發闆對nandflash的讀寫:
#define NF_BASE 0x4e000000
#ifdefined(CONFIG_S3C2410)
#define S3C2410_NFCONF_EN (1<<15)
#define S3C2410_NFCONF_512BYTE (1<<14)
#define S3C2410_NFCONF_4STEP (1<<13)
#define S3C2410_NFCONF_INITECC (1<<12)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
#endif
添加S3C2440開發闆的nandflash各功能寄存器定義
#ifdefined(CONFIG_S3C2440)
#define S3C2410_NFCONT_EN (1<<0)
#define S3C2410_NFCONT_INITECC (1<<4)
#define S3C2410_NFCONT_nFCE (1<<1)
#define S3C2410_NFCONT_MAINECCLOCK (1<<5)
#define S3C2410_NFCONF_TACLS(x) ((x)<<12)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)
#define S3C2410_ADDR_NALE 0x08
#define S3C2410_ADDR_NCLE 0x0c
#endif
修改這個全局變量
ulongIO_ADDR_W = NF_BASE;
#ifdef CONFIG_NAND_SPL
修改s3c2410_hwcontrol函數:
staticvoid s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
// struct nand_chip *chip = mtd->priv;
struct s3c2410_nand *nand =s3c2410_get_base_nand();
debugX(1, "hwcontrol(): 0x%02x0x%02x\n", cmd, ctrl);
if (ctrl & NAND_CTRL_CHANGE) {
//ulong IO_ADDR_W = (ulong)nand;
IO_ADDR_W = (ulong)nand;
if (!(ctrl & NAND_CLE))
IO_ADDR_W |= S3C2410_ADDR_NCLE;
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S3C2410_ADDR_NALE;
// chip->IO_ADDR_W = (void *)IO_ADDR_W;
if (ctrl & NAND_NCE)
#ifdefined(CONFIG_S3C2410)
writel(readl(&nand->NFCONF)& ~S3C2410_NFCONF_nFCE,&nand->NFCONF);
#elifdefined(CONFIG_S3C2440)
writel(readl(&nand->NFCONT)& ~S3C2410_NFCONT_nFCE,&nand->NFCONT);
#endif
else
#ifdefined(CONFIG_S3C2410)
writel(readl(&nand->NFCONF)| S3C2410_NFCONF_nFCE,&nand->NFCONF);
#elifdefined(CONFIG_S3C2440)
writel(readl(&nand->NFCONT)| S3C2410_NFCONT_nFCE,&nand->NFCONT);
#endif
}
if (cmd != NAND_CMD_NONE)
//writeb(cmd, chip->IO_ADDR_W);
writeb(cmd, (void *)IO_ADDR_W);
}
修改s3c2410_nand_enable_hwecc函數:
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand *nand =s3c2410_get_base_nand();
debugX(1, "s3c2410_nand_enable_hwecc(%p,%d)\n", mtd, mode);
#ifdefined(CONFIG_S3C2410)
writel(readl(&nand->NFCONF) |S3C2410_NFCONF_INITECC, &nand->NFCONF);
#elifdefined(CONFIG_S3C2440)
writel(readl(&nand->NFCONT) |S3C2410_NFCONT_INITECC, &nand->NFCONT);
#endif
}
修改board_nand_init函數如下:
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
struct s3c24x0_clock_power *clk_power =s3c24x0_get_base_clock_power();
struct s3c2410_nand *nand_reg =s3c2410_get_base_nand();
debugX(1, "board_nand_init()\n");
writel(readl(&clk_power->CLKCON) |(1 << 4), &clk_power->CLKCON);
#ifdefined(CONFIG_S3C2410)
/* initialize hardware */
twrph0 = 3;
twrph1 = 0;
tacls = 0;
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->NFCONF);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W =(void *)&nand_reg->NFDATA;
#elifdefined(CONFIG_S3C2440)
/* initialize hardware */
tacls = 0;
twrph0 = 4;
twrph1 = 2;
cfg = 0;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 -1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 -1);
writel(cfg, &nand_reg->NFCONF);
cfg =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
writel(cfg, &nand_reg->NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W= (void *)&nand_reg->NFDATA;
#endif
nand->select_chip = NULL;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
nand->read_buf = nand_read_buf;
#endif
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl =s3c2410_nand_enable_hwecc;
nand->ecc.calculate =s3c2410_nand_calculate_ecc;
nand->ecc.correct =s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size =CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes =CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
debugX(1, "end of nand_init\n");
return 0;
}
修改arch/arm/include/asm/arch-s3c24x0/s3c24x0.h中nandflash控制寄存器的結構體:
struct s3c24x0_interrupt {
u32 SRCPND;
u32 INTMOD;
u32 INTMSK;
u32 PRIORITY;
u32 INTPND;
u32 INTOFFSET;
…………
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 SUBSRCPND;
u32 INTSUBMSK;
#endif
};
…………
struct s3c24x0_dma {
u32 DISRC;
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 DISRCC;
#endif
u32 DIDST;
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 DIDSTC;
#endif
u32 DCON;
u32 DSTAT;
u32 DCSRC;
u32 DCDST;
u32 DMASKTRIG;
#ifdef CONFIG_S3C2400
u32 res[1];
#endif
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 res[7];
#endif
};
…………
struct s3c24x0_clock_power {
u32 LOCKTIME;
u32 MPLLCON;
u32 UPLLCON;
u32 CLKCON;
u32 CLKSLOW;
u32 CLKDIVN;
#if defined (CONFIG_S3C2440)
u32 CAMDIVN;
#endif
};
…………
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 LCDINTPND;
u32 LCDSRCPND;
u32 LCDINTMSK;
u32 LPCSEL;
#endif
};
#if defined(CONFIG_S3C2410)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFSTAT;
u32 NFECC;
};
#elif defined (CONFIG_S3C2440)
struct s3c2410_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};
#endif
…………
#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440)
u32 GPACON;
u32 GPADAT;
u32 res1[2];
u32 GPBCON;
…………
#if defined (CONFIG_S3C2440)
u32 res9[3];
u32 MSLCON;
u32 GPJCON;
u32 GPJDAT;
u32 GPJUP;
#endif
#endif
};
5、添加DM9000網絡支援
vim include/configs/fl2440.h
…………
#if 0 //禁用 CS89000 網卡
#define CONFIG_NET_MULTI
#define CONFIG_CS8900 /* we have a CS8900on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driverdoes accesses as shorts */
#else //添加 DM9000 網卡
#define CONFIG_NET_MULTI 1
#define CONFIG_NET_RETRY_COUNT 20
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE0x20000300 /* nGCS4 */
#define DM9000_IOCONFIG_DM9000_BASE
#define DM9000_DATA(CONFIG_DM9000_BASE+4)#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_NO_SROM 1
#undef CONFIG_DM9000_DEBUG
#endif
…………
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_PING 添加 ping指令支援
我們可以在這裡修改 CONFIG_BOOTDELAY 來改變啟動時按任意鍵進入 debug 模式的延時時間
#define CONFIG_BOOTDELAY 5
/*#define CONFIG_BOOTARGS "root=ramfsdevfs=mount console=ttySA0,9600" */
#define CONFIG_ETHADDR 11:22:33:44:55:66 //配置網卡的 MAC位址
#define CONFIG_NETMASK255.255.255.0 //配置網絡子網路遮罩
#define CONFIG_IPADDR 192.168.199.200 //配置網卡 IP位址
#define CONFIG_SERVERIP 192.168.199.2 //配置 TFTP伺服器 IP 位址
/*#define CONFIG_BOOTFILE"elinos-lart" */
/*#define CONFIG_BOOTCOMMAND "tftp;bootm" */
…………
我們可以在這裡通過修改 CONFIG_SYS_PROMPT 來修改 u-boot 的指令提示符
#define CONFIG_SYS_PROMPT"[[email protected]]# " /* Monitor Command Prompt */
修改 board/lingyun/fl2440/fl2440.c,添加 dm9000 網卡的初始化
vim board/lingyun/fl2440/fl2440.c
…………
#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_CS8900
rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
return rc;
}
#endif
…………
對 DM9000 網卡驅動作一些小的修改
vim drivers/net/dm9000x.c
…………
static int dm9000_init(struct eth_device *dev,bd_t *bd)
{
…………
while (!(phy_read(1) & 0x20)) { /*autonegation complete bit */
udelay(1000);
i++;
if(i == 2000) {
printf("couldnot establish link\n");
break;
}
}
}
以上代碼的修改後,我們可以編譯測試 u-boot 代碼進行網絡測試了。