一、 uboot 1.2.0移植
移植環境:VMware5.5.2+redhat9
開發闆:SKY_2440B_V5.0或者V3.0
編譯器:cross3.2(下載下傳位址ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.2.tar.gz)
Uboot:u-boot-1.2.0(下載下傳位址:ftp://ftp.denx.de/pub/u-boot/)
先說明一下,移植過程按照tekkaman的blog移植的。
部落格位址http://blog.chinaunix.net/u1/34474/index.html。
其中uboot的移植參照http://blog.chinaunix.net/u1/34474/showart.php?id=397315做的。
所下面寫的移植過程,很多都是從blog上copy過來的,有不同的地方,我會另外指出。
1.用dk登入linux主機,在dk下建立一個myboard檔案夾
2.解壓cross3.2:解壓到/usr/local/arm/檔案夾下
最好在/usr/local/arm/下建立一個3.2檔案夾,把解壓在arm檔案夾下的檔案(夾)全部移到3.2下,因為後面可能還會用到3.4.1的交叉編譯器。
3.解壓uboot:将uboot解壓到myboard檔案夾下
tar xzvf u-boot-1.2.0.tar.bz2–C /home/dk/myboard/
4.進入uboot目錄,修改Makefile
cd u-boot-1.2.0
vi Makefile
(1) 建立我的編譯項
在1923行,即smdk2410_config編譯項之後增加我的編譯項
tekkaman2440_config : unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t tekkaman2440tekkaman s3c24x0
各項的意思如下:
arm: CPU的架構(ARCH)
arm920t: CPU的類型(CPU),其對應于cpu/arm920t子目錄。
tekkaman2440: 開發闆的型号(BOARD),對應于board/tekkaman/tekkaman2440目錄。
tekkaman: 開發者/或經銷商(vender)。
s3c24x0: 片上系統(SOC)。
(2) 修改交叉編譯器路徑,我用的cross3.2是在/usr/local/arm/
修改128行
CROSS_COMPILE=/usr/local/arm/3.2/bin/arm-linux-
5.在/board子目錄中建立自己的開發闆tekkaman2440目錄
由于我在上一步闆子的開發者/或經銷商(vender)中填了tekkaman,是以開發闆tekkaman2440目錄一定要建在/board子目錄中的tekkaman目錄下,否則編譯會出錯。
$cdboard
$mkdir tekkaman tekkaman/tekkaman2440
$cp -arf sbc2410x
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
# define pWTCON 0x53000000這個定義了看門狗的寄存器位址
# define INTMSK 0x4A000008 中斷掩碼的寄存器位址
# define INTSUBMSK 0x4A00001C中斷掩碼的寄存器位址
# define CLKDIVN 0x4C000014 完成時鐘分份的寄存器
#endif
(1)修改中斷禁止部分
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
ldr r0, =pWTCON把看門狗寄存器位址給了r0
mov r1, #0x0 r1等于0
str r1, [r0] 看門狗寄存器等于0因為在啟動時要關閉看門狗,不能讓他産生中斷影響啟動,此時也根本不需要任何中斷
mov r1, #0xffffffff 關閉所有中斷
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
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
(2)修改時鐘設定(2440的主頻可達533MHz,但是我設到533MHz時系統很不穩定,不知是不是SDRAM和總線配置的影響,是以現在先設到405MHz,以後在改進。)
ldr r0, =CLKDIVN
這個值決定了FCLK HCLK PCLK的頻率
FCLK是供給CPU的是主頻
HCLK是供給AHB總線(主要用于高性能子產品(如CPU、DMA和DSP等)之間的連接配接,作為SoC的片上系統總線)上的外圍裝置
PCLK是供給APB總線(APB主要用于低帶寬的周邊外設之間的連接配接,例如UART、1284等)上的外圍裝置
UCLK是兩路PLL中一路供給USB的頻率
ARM總線技術在這裡我不多介紹了,對硬體感興趣的同學建議多多了解,我有一回面試人家就問我這個了,405MHZ已經很高了,基本都夠了,2410的200MHZ就能播放Mplayer視訊,據說很流暢。
mov r1, #5
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0,0
他是用到了協處理器P15,此處理器主要設定mmu,時鐘模式,caches,保護模式的。先把C0 C1的值讀出到r1,設定後再寫回。 FCLK:HCLK:PCLK的比例由CLKDIVN決定的,CLKDIVN寄存器的HDIVN和PDIVN決定比例的大小。因為此時的HDIVH不為0,将快速總線模式改為異步總線模式,操作協處理器P15改變模式即可,如果HDIVH不為0,而且是快速總線模式的話,那麼CPU的主頻由hclk控制,這樣可以實作不改變HCLK和PCLCK的同時就能使CPU的主頻減半或更多。網上的大蝦說沒有以上幾句主頻會是12MHZ,我的觀點不同。這是資料手冊原文
If HDIVN is not 0 and the CPU bus mode is the fast busmode, the CPU will operate by the HCLK.This feature can be used to change theCPU frequency as a half or more without affecting the HCLKand PCLK
#ifdefined(CONFIG_S3C2440)
mov r1, #CLK_CTL_BASE 這是時鐘寄存器的基位址
mov r2, #MDIV_405
add r2, r2, #PSDIV_405
str r2, [r1,#0x04] 設定 MPLLCON
#endif
#if defined(CONFIG_S3C2410)
mov r1, #CLK_CTL_BASE
mov r2,#MDIV_200
add r2, r2,#PSDIV_200
str r2, [r1,#0x04]
#endif
#endif
紅色部分是我添加的,利用vivi的代碼,将其設為405.00MHz并在前面加上:
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014
#defineCLK_CTL_BASE 0x4C000000
#if defined(CONFIG_S3C2440)
#define MDIV_405 0x7f << 12
#define PSDIV_405 0x21
#endif
#if defined(CONFIG_S3C2410)
#define MDIV_200 0xa1 <<12
#define PSDIV_200 0x31
#endif
#endif〕
(3)将從Flash啟動改成從NAND Flash啟動。(特别注意:這和2410的程式有不同,不可混用!!!是拷貝vivi的代碼。)
将以下U-Boot的重定向語句段:
這段代碼将uboot搬運到ram中,這個是沒有存放在nand的情況,下面咱們來看一下不在nand啟動和在nand啟動時此處的差別。
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:
adr r0, _start nor中的起始位址給了r0
ldr r1, _TEXT_BASE ram中的uboot代碼的起始位址(這裡關于uboot搬運這塊在記憶體位址的部分,分了很多段,每一段空間具有不同功能,這是你了解uboot必須掌握的,非常關鍵,解釋後續會提到些)
cmp r0,r1 比較兩個位址是否相同,不同則進行下面的搬運工作
beq stack_setup
在這裡你會發現搬運了全部uboot,有的uboot把uboot的c部分搬運到記憶體_TEXT_BASE裡面所放的位址處。
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 _bss_start-_armboot_start= armboot 因為_armboot_end的結束位置就是bss區的開始位置是以能計算出uboot代碼的大小
add r2, r0, r2
以下就是把整個代碼搬運到_TEXT_BASE裡面所放的位址處,記住是記憶體位址,哈哈!!
copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
#endif
替換成:因為nand和nor的啟動是有差別的,NOR Flash儲存器較貴,而NAND Flash則相對便宜,是以很多使用者選擇在NAND Flash中執行啟動代碼,在SDRAM中執行主程式。為支援NAND Flash的BootLader,S3C2440有一個内部SRAM緩沖,稱為‘Steppingstone’,啟動時,NAND Flash的最先4K位元組将被裝載到Steppingstone中,裝載到Steppingstone中的啟動代碼将執行。這都是硬體自動完成的不需要咱們軟體參與。一般來說,啟動代碼将把NAND Flash的内容拷貝到SDRAM中,ECC将檢測NAND的合法性,當拷貝完成時,主程式将在SDRAM中執行電源開啟後,或系統重新開機後,NAND Flash控制器将自動裝載4KB的BootLoader代碼,載入代碼後将執行。注意在自啟動時,ECC不檢測,是以,NAND Flash的頭4KB要保證無錯,下面我來帶你分析它的源代碼喽,嘿嘿!!!!忽然想家了,對了nand的硬體連接配接簡單有興趣的看一下了(NCON-Adv Flash,GPG13-Page size,GPG14-Address cycle,GPG15-總線寬度)
#ifdef CONFIG_S3C2440_NAND_BOOT @tekkaman@在以後會定義它的,不要忘了
@ reset NAND
mov r1, #NAND_CTL_BASE nand的寄存器基位址
ldr r2, =((7<<12)|(7<<8)|(7<<4)|(0<<0) ) CLE & ALE期間設定值|TWRPH0期間設定值|TWRPH0期間設定值|8位總線
str r2, [r1, #oNFCONF] 設定NFCONF寄存器,初始化作用
ldr r2, [r1, #oNFCONF]
ldr r2, =((1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control初始化ECC解碼/編碼器(隻寫)|強制拉低nFCE(允許片選)|允許NAND控制器
str r2, [r1, #oNFCONT] 設定 NFCONT
ldr r2, [r1,#oNFCONT]
ldr r2, =(0x6) @ RnB Clear和nand isbusy
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3,#0 @ wait就是一下段延時
nand1:
add r3, r3, #0x1
cmp r3, #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初始化frame的起始位置
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE 設定第1個參數: UBOOT在RAM中的起始位址
mov r1, #0x0 設定第2個參數:NandFlash的起始位址
mov r2, #0x20000 設定第3個參數: UBOOT的長度(128KB)
bl nand_read_ll 在board/tekkaman/tekkaman2440/nand_read.c我會解析這個函數的作用
tst r0, #0x0 如果函數的傳回值為0,表示執行成功.
beq ok_nand_read 執行記憶體比較,比較什麼呢?他比較搬運到記憶體中的代碼和在内部ram的前4kb是否一樣
bad_nand_read:
loop2: b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0 内部RAM的起始位址
ldr r1, =TEXT_BASE UBOOT在RAM中的起始位址
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:
記憶體中的代碼和在内部ram的前4kb如果不一樣,就無限的循環在這了,如果你不努力的去體會每一句,你的功力就像他一樣了,哈哈!
loop3: b loop3 @ infinite loop
#endif @CONFIG_S3C2440_NAND_BOOT @tekkaman@@
在 “ _start_armboot: .wordstart_armboot ” 後加入:
.align 2 二的平方也就是字對齊了存儲了
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
9.在board/tekkaman/tekkaman2440加入NAND Flash讀函數檔案,拷貝vivi中的nand_read.c檔案到此檔案夾即可:
#include<config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#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 NFSTAT __REGb(NF_BASE + 0x20)
//#define GPDAT __REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1)) 允許片選
#define NAND_CHIP_DISABLE(NFCONT |= (1<<1))禁止片選
#define NAND_CLEAR_RB (NFSTAT |= (1<<2))
#define NAND_DETECT_RB { while(!(NFSTAT&(1<<2)) );}
#define BUSY 4
inline void wait_idle(void) {
while(!(NFSTAT & BUSY));等待是否nand忙于上次的操作
NFSTAT |= BUSY;
}
#define NAND_SECTOR_SIZE 512 一頁大小,我們的nand是這樣分的
1裝置(Device) = 4096塊(Blocks)
1塊(Block) = 32頁/行(Pages/rows) ;頁與行是相同的意思,叫法不一樣
1(Page) = 528位元組(Bytes) =資料塊大小(512Bytes) + OOB塊大小(16Bytes)
在每一頁中,最後16個位元組(又稱OOB)用于Nand Flash指令執行完後設定狀态用,剩餘512個位元組又
分為前半部分和後半部分。可以通過Nand Flash指令00h/01h/50h分别對前半部、後半部、OOB進行定位,通過OOB部分的第六位元組(即517位元組)标志是否是壞塊,OOB第六位元組外,通常至少把OOB的前3個位元組存放Nand Flash硬體ECC碼,這個我就不多說了,你要想真正看懂這些代碼,必須了解nand的架構啊
Nand Flash内置的指針指向各自的首位址。
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE- 1)
int
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 -1; 檢驗開始位址和程式大小是否為512的整數
}
NAND_CHIP_ENABLE; 允許NAND
for(i=start_addr; i < (start_addr + size);) {直到讀取整個uboot代碼為止
NAND_CLEAR_RB;
NFCMD = 0;
Nand Flash片内尋址采用26位位址形式。從第0位開始分四次通過I/O0-I/O7進行
傳送,并進行片内尋址。具體含義如下:
0-7位:位元組在上半部、下半部及OOB内的偏移位址
8位:值為0代表對一頁内前256個位元組進行尋址
值為1代表對一頁内後256個位元組進行尋址
9-13位:對頁進行尋址
14-25位:對塊進行尋址
當傳送位址時,從位0開始
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
NAND_DETECT_RB;
for(j=0; j < NAND_SECTOR_SIZE; j++,i++) {
*buf = (NFDATA &0xff);
buf++;
}
}
NAND_CHIP_DISABLE;禁止片選
return 0;
}
注意:s3c2410與s3c2440的Nand Flash控制器寄存器不同,不能混用!!
10. 修改board/tekkaman/tekkaman2440/Makefile檔案
OBJS := tekkaman2440.o nand_read.o flash.o
11.修改include/configs/tekkaman2440.h檔案,添加如下内容(注意:s3c2410與s3c2440的Nand Flash控制器寄存器不同,不能混用!!):
......
#define CONFIG_S3C2440_NAND_BOOT1 這處告訴從nand啟動
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x8000
//#define UBOOT_RAM_BASE 0x33f80000
#define NAND_CTL_BASE 0x4E000000
#define bINT_CTL(Nb) __REG(INT_CTL_BASE +(Nb))
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFADDR 0x0c
#define oNFDATA 0x10
#define oNFSTAT 0x20
#define oNFECC 0x2c
#define GPIO_CTL_BASE 0x56000000
#define oGPIO_B 0x10
#define oGPIO_CON 0x0
#define oGPIO_DAT 0x4
#define oGPIO_UP 0x8
#endif
12. 修改board/tekkaman/tekkaman2440/lowlevel_init.S檔案
......
#define REFEN 0x1
#define TREFMD 0x0
#defineTrp 0x2
#define Trc 0x3
#define Tchr 0x2
#defineREFCNT 1012
......
注:參數的值按照SKY提供的對應檔案的參數修改過來。
13. 修改/board/tekkaman/tekkaman2440/tekkaman2440.c
因為SKY2440和smdk2410的GPIO連接配接有所不同,修改其對GPIO和PLL的配置(請參閱SKY2440的硬體說明、2440晶片手冊和提供的uboot相對應的檔案):這個函數我想不用我解釋了吧!其實有些IO口在驅動裡可以重新設定,但有時沒有必要單單寫一個IO驅動,例如序列槽的端口設定需要将他設定為rx或tx用那就可以直接改這了。
......
#elifFCLK_SPEED==1
//#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
//#defineU_M_MDIV 0x48
//#define U_M_PDIV 0x3
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
......
gpio->GPACON= 0x007FFFFF;
//gpio->GPBCON = 0x00044556;
gpio->GPBCON = 0x00055556;
......
gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ;
機碼ID号必須和核心的機碼對上,我們的是168,你找到他不要另加一個,因為我就犯過這個錯誤,他本身裡面就有一個,你得覆寫他,要不然他還會認他以前的那個号,别忘了他的配置檔案,是按照行讀的,一旦讀到比對的參數就會跳出循環,導緻你在後面加的根本就沒起上作用。
gd->bd->bi_boot_params= 0x30000100;
這個是核心的參數的起始位址,我們的闆子核心是在0x30008000位址處,在從0x30000000到0x30008000的32kb之間存放的是核心頁表和核心的啟動參數,
icache_enable();
dcache_enable();
gpio->GPBDAT= 0x180; //tekkamanninja
//intboard_init (void)設定完成後,LED1和LED2會亮起!
return0;
}
14. 為了實作NAND Flash的讀寫,再次修改/include/configs/tekkaman2440.h
(請格外注意:如果編譯時報錯,在Linux下用KWrite等有高亮顯示的文本編輯器看看檔案的注釋是不是為注釋應有的顔色(KWrite中為灰色),如果不是,則将注釋删除。因為#define後面的注釋被認為是程式的一部分。建議注釋和#define分行寫)
......
#define CONFIG_ARM920T 1
#define CONFIG_S3C2440 1
#define CONFIG_tekkaman2440 1
......
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
CFG_CMD_NET | \
\
\
\
CFG_CMD_PING | \
CFG_CMD_ENV | \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_DHCP | \
CFG_CMD_ELF)
#include <cmd_confdefs.h>
#define CFG_LONGHELP
#define CFG_PROMPT "[Tekkaman2440]#"
#define CFG_CBSIZE 256
......
#define CFG_LOAD_ADDR 0x30008000
......
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0X20000
//#define ENV_IS_EMBEDDED 1
#define CFG_NAND_LEGACY 定義後便調用我們的board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函數進行nand初始化
#defineCFG_ENV_SIZE 0x10000
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000
#define CFG_MAX_NAND_DEVICE 1
#define SECTORSIZE 512
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_BLOCK_MASK 511
#define ADDR_COLUMN 1
#define ADDR_PAGE 3
#defineADDR_COLUMN_PAGE 4
#defineNAND_ChipID_UNKNOWN 0x00
#defineNAND_MAX_FLOORS 1
#defineNAND_MAX_CHIPS 1
這些前面基本已經提到
#defineWRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}
#defineWRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;}
#define WRITE_NAND(d, adr){rNFDATA = d;}
#define READ_NAND(adr)(rNFDATA)
#defineNAND_WAIT_READY(nand) {while(!(rNFSTAT&(1<<0)));}
#defineNAND_DISABLE_CE(nand) {rNFCONT |= (1<<1);}
#defineNAND_ENABLE_CE(nand) {rNFCONT &= ~(1<<1);}
#defineWRITE_NAND_COMMANDW(d, adr) NF_CmdW(d)
#define NAND_CTL_CLRALE(nandptr)
#defineNAND_CTL_SETALE(nandptr)
#defineNAND_CTL_CLRCLE(nandptr)
#defineNAND_CTL_SETCLE(nandptr)
#defineCONFIG_MTD_NAND_VERIFY_WRITE 1
......
定義了各個寄存器
#define rNFCONF (*(volatileunsigned int *)0x4e000000)
#define rNFCONT (*(volatileunsigned int *)0x4e000004)
#define rNFCMD (*(volatileunsigned char *)0x4e000008)
#define rNFADDR (*(volatileunsigned char *)0x4e00000c)
#define rNFDATA (*(volatileunsigned char *)0x4e000010)
#define rNFSTAT (*(volatileunsigned int *)0x4e000020)
#define rNFECC (*(volatileunsigned int *)0x4e00002c)
#endif
注:下面的這些定義是SKY提供的uboot參數,請按照這個參數把/include/configs/tekkaman2440.h修改過來
#define CONFIG_BOOTDELAY 1 模式選折延時時間
#define CONFIG_BOOTARGS "noinitrdroot=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
這裡設定的都是傳遞給核心的參數,
initrd的最初的目的是為了把kernel的啟動分成兩個階段:在kernel中保留最少最基本的啟動代碼,然後把對各種各樣硬體裝置的支援以子產品的方式放在initrd中,這樣就在啟動過程中可以從initrd所mount的根檔案系統中裝載需要的子產品。這樣的一個好處就是在保持kernel不變的情況下,通過修改initrd中的内容就可以靈活的支援不同的硬體。在啟動完成的最後階段,根檔案系統可以重新mount到其他裝置上。如果把需要的功能全都編譯到核心中(非子產品方式),隻需要一個核心檔案即可,我們這裡就沒有用到它,
root=/dev/mtdblock2 是指定檔案系統路徑,在dev/的第二個分區了
init=/linuxrc他是個腳本,放在檔案系統的根目錄下,裡面是檔案系統啟動時要挂載所要執行的準備console=ttySAC0用哪個序列槽
#define CONFIG_ETHADDR 0a:1b:2c:3d:4e:5f 網卡mac位址I ,全國獨一個啊
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.6
#define CONFIG_SERVERIP 192.168.1.8
#define CONFIG_BOOTCOMMAND "nboot 0x32000000 0 0x4C000; bootm 0x32000000" 0x4C000是變動的值
nbootInAddr dev FlAddr
InAddr:需要裝載到的記憶體的位址。
FlAddr:在nand flash上uImage存放的位址
dev:裝置号
需要提前設定環境變量,否則nboot不會調用bootm
Tekkaman2440#setenv autostart yes
0x4C000是核心在nand中起始的位址,看nand分區那就可以了解它的由來,在這裡我們将核心搬運到0x32000000處,跳到此處執行什麼呢?此時把壓縮的核心進行解壓,解壓代碼在核心的頭部,解壓到0x30008000處,這就是核心的解壓後的位址。我們的核心最終是從這裡開始執行的。
15.在個檔案中添加“CONFIG_S3C2440”,使得原來s3c2410的代碼可以編譯進來。
(1)/include/common.h檔案的第454行:
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_LH7A40X) ||defined(CONFIG_S3C2440)
(2)/include/s3c24x0.h檔案的第85、95、99、110、148、404行:
#if defined(CONFIG_S3C2410)|| defined (CONFIG_S3C2440)
(3)/cpu/arm920t/s3c24x0/interrupts.c檔案的第33行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB)||defined (CONFIG_S3C2440)
第38行:#elifdefined(CONFIG_S3C2410)|| defined (CONFIG_S3C2440)
(4)/cpu/arm920t/s3c24x0/serial.c檔案的第22行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB)||defined (CONFIG_S3C2440)
第26行:#elifdefined(CONFIG_S3C2410)|| defined (CONFIG_S3C2440)
void serial_setbrg (void)
{
S3C24X0_UART * const uart= S3C24X0_GetBase_UART(UART_NR);
int i;
unsigned int reg = 0;
reg = get_PCLK() / (16 * gd->baudrate) - 1;
uart->UFCON = 0x00;
uart->UMCON = 0x0;
uart->ULCON = 0x3;
......
}
(5)/cpu/arm920t/s3c24x0/speed.c檔案的第33行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) || defined (CONFIG_S3C2440)
第37行:#elifdefined(CONFIG_S3C2410)||defined (CONFIG_S3C2440)
順便修改源代碼,以比對s3c2440:
static ulong get_PLLCLK(int pllreg)
{
......
m =((r & 0xFF000) >> 12) + 8;
p =((r & 0x003F0)>> 4) + 2;
s =r & 0x3;
//tekkaman
#if defined(CONFIG_S3C2440)
if (pllreg== MPLL)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
elseif (pllreg == UPLL)
#endif
//tekkaman
return((CONFIG_SYS_CLK_FREQ * m) / (p <<s));
}
......
ulong get_FCLK(void)
{
return(get_PLLCLK(MPLL));
}
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
if (clk_power->CLKDIVN &0x6)
{
if ((clk_power->CLKDIVN &0x6)==2) return(get_FCLK()/2);
if ((clk_power->CLKDIVN &0x6)==6) return((clk_power->CAMDIVN & 0x100) ? get_FCLK()/6 :get_FCLK()/3);
if ((clk_power->CLKDIVN &0x6)==4) return((clk_power->CAMDIVN& 0x200) ? get_FCLK()/8 :get_FCLK()/4);
return(get_FCLK());
}
else {
return(get_FCLK());
}
}
......
(6)/cpu/arm920t/s3c24x0/usb_ohci.c檔案的第45行:
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
(i2c的檔案還沒修改,因為沒用到)
(7)/rtc/s3c24x0_rtc.c檔案的第35行:
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
在個檔案中添加“defined(CONFIG_tekkaman2440)”,使得原來SBC2410X的代碼可以編譯進來。
(1)/cpu/arm920t/s3c24x0/interrupts.c檔案的第181行:
defined(CONFIG_VCMA9)|| defined(CONFIG_tekkaman2440)
16.在include/linux/mtd/nand_ids.h的結構體nand_flash_ids加入
static structnand_flash_dev nand_flash_ids[] = {
......
{"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},
{"Samsung K9F1208U0B", NAND_MFR_SAMSUNG, 0x76, 26, 0,3, 0x4000, 0},
{"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},
......
};
注:可參照SKY提供的uboot對應檔案修改。
17.修改common/env_nand.c
......
#ifdef CONFIG_INFERNO
#error CONFIG_INFERNO not supported yet
#endif
int nand_legacy_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
extern struct nand_chipnand_dev_desc[CFG_MAX_NAND_DEVICE];
extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_tlen, int clean);
extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
......
env 将從永久性存儲媒體中搬到RAM裡面,以後對env的操作,比如修改環境變量的值,删除環境變量的值都是對這個 env在RAM中的拷貝進行操作,由于RAM的特性,下次啟動時所做的修改将全部消失,u-boot提供了将env寫回永久性存儲媒體的指令支援 : saveenv,不同版本的 env( nand flash, flash …)實作方式不同,以Nand Flash的實作(未定義CFG_ENV_OFFSET_REDUND)為例,見下面的saveenv函數了,Nand Flash的 saveenv 指令實作很簡單,調用nand_erase 和nand_write進行Nand Flash的 erase,write。nand_write/erase使用的是u-boot的nand驅動架構,我在做開發的過程中使用的是nand_legacy驅動,是以可以把nand_erase和nand_write改成nand_legacy_erase和nand_legacy_rw就可實作nand_legacy驅動的儲存環境變量版本,這就是為什麼注釋掉nand_erase和 nand_write的原因了,哈哈,其實我也是才知道的,以前這塊也有點糊塗
#else完成對環境變量的存儲
int saveenv(void)
{
ulong total;
int ret = 0;
puts("Erasing Nand...");
UBOOT對NAND進行讀寫操作調用的函數在drivers/nand_legacy/nand_legacy。C函數裡面的nand_legacy_erase先擦除要寫的nand區,再調用nand_legacy_rw進行讀寫,不是調用nand_erase和 nand_write
//if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
if (nand_legacy_erase(nand_dev_desc +0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
return 1;
puts("Writing to Nand... ");
total =CFG_ENV_SIZE;
//ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total,(u_char*)env_ptr);
ret = nand_legacy_rw(nand_dev_desc + 0,
0x00 | 0x02, CFG_ENV_OFFSET, CFG_ENV_SIZE,
&total, (u_char*)env_ptr);
if (ret || total!= CFG_ENV_SIZE)
return 1;
puts ("done\n");
return ret;
......
#else
void env_relocate_spec (void) 完成環境變量的重新定位,把它從nand搬運到sdram裡面
{
#if !defined(ENV_IS_EMBEDDED) env 是否存在于 u-boot TEXT段中
ulong total;
int ret;
total = CFG_ENV_SIZE; env 塊的大小
u-boot 在啟動的時候會将存儲在永久性存儲媒體中的 env重新定位到 RAM 中,這樣可以快速通路,同時可以通過saveenv将 RAM 中的env 儲存到永久性存儲媒體中。實際上還需要幾個宏來控制u-boot對環境變量的處理。CFG_ENV_OFFSET: env塊在 Flash 中偏移位址。env_ptr:最終完成将環境變量搬移到記憶體位址。
//ret =nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret = nand_legacy_rw(nand_dev_desc + 0, 0x01 | 0x02,CFG_ENV_OFFSET, CFG_ENV_SIZE, &total, (u_char*)env_ptr);
......
上面的代碼很清楚的表明了 env_relocate_spec的意圖,調用 nand_read将環境變量從CFG_ENV_OFFSET處讀出,環境變量的大小為 CFG_ENV_SIZE注意CFG_ENV_OFFSET和 CFG_ENV_SIZE要和Nand Flash的塊/頁邊界對齊。讀出資料後再調用crc32對env_ptr->data進行校驗并與儲存在 env_ptr->crc的校驗碼對比,看資料是否出錯,從這裡也可以看出在系統第一次啟動時,Nand Flash裡面沒有存儲任何環境變量,crc校驗肯定回出錯,當我們儲存環境變量後,接下來再啟動闆子u-boot就不會再報crc32出錯了。
18.在/board/tekkaman/tekkaman2440/tekkaman2440.c檔案的末尾添加對Nand Flash的初始化函數(在後面Nand Flash的操作都要用到)
u-boot運作至第二階段進入start_armboot()函數。其中nand_init()函數是對nand flash的最初初始化函數。Nand_init()函數在兩個檔案中實作。其調用與CFG_NAND_LEGACY宏有關,如果沒有定義這個宏,系統調用 drivers/nand/nand.c中的nand_init();否則調用自己在board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函數。這裡我選擇第二種方式。
這些代碼很簡單的都是操作他的實體位址,對照資料手冊就會很清楚他的用意,它主要就是完成對nand的初始化,設定好nand的寄存器。為了便于大家了解他,我把我的參考資料貼在這,看了便知道了!!!!!
Nand flash主要内設指令詳細介紹
Nand Flash指令執行是通過将指令字送到Nand Flash控制器的指令寄存器來執行。
Nand Flash的指令是分周期執行的,每條指令都有一個或多個執行周期,每個執行周期都有相映代碼表示該周
期将要執行的動作。
主要指令有:Read 1、Read 2、Read ID、Reset、Page Program、Block Erase、Read Status。
詳細介紹如下:
1. Read 1:
功能:表示将要讀取Nand flash存儲空間中一個頁的前半部分,并且将内置指針定位到前半部分的第一個位元組。
指令代碼:00h
2. Read 2:
功能:表示将要讀取Nand flash存儲空間中一個頁的後半部分,并且将内置指針定位到後半部分的第一個位元組。
指令代碼:01h
3. Read ID:
功能:讀取Nand flash晶片的ID号
指令代碼:90h
4. Reset:
功能:重新開機晶片。
指令代碼:FFh
5. Page Program:
功能:對頁進行程式設計指令,用于寫操作。
指令代碼:首先寫入00h(A區)/01h(B區)/05h(C區),表示寫入那個區; 再寫入80h開始程式設計模式(寫入模式),接
下來寫入位址和資料;最後寫入10h表示程式設計結束.
6. Block Erase
功能:塊擦除指令。
指令代碼:首先寫入60h進入擦寫模式,然後輸入塊位址;接下來寫入D0h, 表示擦寫結束.
7. Read Status
功能:讀取内部狀态寄存器值指令。
指令代碼:70h
Nand Flash 控制器工作原理
對Nand Flash存儲晶片進行操作,必須通過Nand Flash控制器的專用寄存器才能完成。是以,不能對Nand
Flash進行總線操作。而Nand Flash的寫操作也必須塊方式進行。對Nand Flash的讀操作可以按位元組讀取。
Nand Flash控制器特性
1. 支援對Nand Flash晶片的讀、檢驗、程式設計控制
2. 如果支援從Nand Flash啟動,在每次重新開機後自動将前Nand Flash的前4KB資料搬運到ARM的内部RAM中
3. 支援ECC校驗
Nand Flash控制器工作原理
Nand Flash控制器在其專用寄存器區(SFR)位址空間中映射有屬于自己的特殊功能寄存器,就是通過将Nand
Flash晶片的内設指令寫到其特殊功能寄存器中,進而實作對Nand flash晶片讀、檢驗和程式設計控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存詳細說明見下一節。
Nand flash 控制器中特殊功能寄存器詳細介紹
1. 配置寄存器(NFCONF)
功能:用于對Nand Flash控制器的配置狀态進行控制。
在位址空間中位址:0x4E000000,其中:
Bit15:Nand Flash控制器使能位,置0代表禁止Nand Flash控制器,置1代表激活Nand Flash控制器;
要想通路Nand Flash晶片上存儲空間,必須激活Nand Flash控制器。在複位後該位自動置0,是以在初始化時
必須将該位置為1。
Bit12:初始化ECC位,置1為初始化ECC;置0為不初始化ECC。
Bit11:Nand Flash晶片存儲空間使能位,置0代表可以對存儲空間進行操作;置1代表禁止對存儲空
間進行操作。在複位後,該位自動為1。
Bit10-8:TACLS位。根據此設定CLE&ALE的周期。TACLS的值範圍在0-7之間。
Bit6-4、2-0分别為:TWRPH0、TWRPH1位。設定寫操作的通路周期。其值在0-7之間。
2. 指令寄存器(NFCMD)
功能:用于存放Nand flash晶片内設的操作指令。
在位址空間中位址:0x4E000004,其中:
Bit0-7:存放具體Nand flash晶片内設的指令值。其餘位保留以後用。
3. 位址寄存器(NFADDR)
功能:用于存放用于對Nand flash晶片存儲單元尋址的位址值。
在位址空間中位址:0x4E000008,其中:
Bit0-7:用于存放位址值。因為本款Nand flash晶片隻有I/O0-7的位址/資料複用引腳且位址是四周
期每次8位送入的,是以這裡隻用到8位。其餘位保留待用。
4. 資料寄存器(NFDATA)
功能:Nand flash晶片所有内設指令執行後都會将其值放到該寄存器中。同時,讀出、寫入Nand flash
存儲空間的值也是放到該寄存器。
在位址空間中位址:0x4E00000C,其中:
Bit0-7:用于存放需要讀出和寫入的資料。其餘位保留代用。
5. 狀态寄存器(NFSTAT)
功能:用于檢測Nand flash晶片上次對其存儲空間的操作是否完成。
在位址空間中位址:0x4E000010,其中:
Bit0:置0表示Nand flash晶片正忙于上次對存儲空間的操作;置1表示Nand flash晶片準備好接收新
的對存儲空間操作的請求。
6. ECC校驗寄存器(NFECC)
功能:ECC校驗寄存器
在位址空間中位址:0x4E000014,其中:
Bit0Bit7:
ECC0
Bit8Bit15:
ECC1
Bit16Bit23:
ECC2
操作的函數實作
1. 發送指令
#define NF_CMD(cmd){rNFCMD=cmd;}
2. 寫入位址
#define NF_ADDR(addr) {rNFADDR=addr;}
3. Nand Flash晶片選中
#define NF_nFCE_L(){rNFCONF&=~(1<<11);}
4. Nand Flash晶片不選中
#define NF_nFCE_H(){rNFCONF|=(1<<11);}
5. 初始化ECC
#define NF_RSTECC(){rNFCONF|=(1<<12);}
6. 讀資料
#define NF_RDDATA() (rNFDATA)
7. 寫資料
#define NF_WRDATA(data) {rNFDATA=data;}
8. 擷取Nand Flash晶片狀态
#define NF_WAITRB(){while(!(rNFSTAT&(1<<0)));}
0/假:表示Nand Flash晶片忙狀态
1/真:表示Nand Flash已經準備好
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
typedef enum {
NFCE_LOW,
NFCE_HIGH
} NFCE_STATE;
static inline void NF_Conf(u16 conf)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCONF = conf;
}
static inline voidNF_Cont(u16 cont)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONT = cont;
}
static inline voidNF_Cmd(u8 cmd)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCMD = cmd;
}
static inline voidNF_CmdW(u8 cmd)
{
NF_Cmd(cmd);
udelay(1);
}
static inline voidNF_Addr(u8 addr)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFADDR = addr;
}
static inline voidNF_SetCE(NFCE_STATE s)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
switch (s) {
case NFCE_LOW:
nand->NFCONT &= ~(1<<1);
break;
case NFCE_HIGH:
nand->NFCONT |= (1<<1);
break;
}
}
static inline voidNF_WaitRB(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
while(!(nand->NFSTAT & (1<<0)));
}
static inline voidNF_Write(u8 data)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFDATA = data;
}
static inline u8NF_Read(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
return(nand->NFDATA);
}
static inline voidNF_Init_ECC(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCONT |=(1<<4);
}
static inline u32NF_Read_ECC(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
return(nand->NFECC);
}
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe(ulong physadr);
static inline void NF_Reset(void)
{
int i;
NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF);
for(i = 0; i < 10; i++);
NF_WaitRB();
NF_SetCE(NFCE_HIGH);
}
static inline void NF_Init(void)
{
#if 0
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#else
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
#endif
NF_Conf((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
NF_Cont((1<<6)|(1<<4)|(1<<1)|(1<<0));
NF_Reset();
}
void
nand_init(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
NF_Init();
#ifdef DEBUG
printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
#endif
printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
}
#endif
19.在/include/s3c24x0.h中加入2440 的NAND FLASH 寄存器定義和CAMDIVN定義:
......
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
S3C24X0_REG32 CAMDIVN;
} S3C24X0_CLOCK_POWER;
......
#if defined(CONFIG_S3C2410)
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFECC;
} S3C2410_NAND;
#endif
#if defined (CONFIG_S3C2440)
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFECC;
} S3C2410_NAND;
#endif
20.移植DM9000網卡
在/include/configs/tekkaman2440.h檔案中修改添加對DM9000的支援,屏蔽CS8900:
//#defineCONFIG_DRIVER_CS8900 1
//#define CS8900_BASE 0x19000300
//#define CS8900_BUS16 1
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
#define CONFIG_DM9000_USE_16BIT
在這裡#define CONFIG_DM9000_BASE的定義最為重要。不同的闆子隻要修改這個參數即可。
我是按照SKY提供的Uboot代碼的對應檔案的參數修改的。
修正BUG(修改/drivers/dm9000.c檔案)
(1)網卡MAC位址錯誤的解決方法:
int
eth_init(bd_t * bd)
{
......
//tekkamanninja
char *tmp = getenv ("ethaddr");
char *end;
for (i=0; i<6; i++) {
bd->bi_enetaddr[i] = tmp ?simple_strtoul(tmp, &end, 16) : 0;
if (tmp)
tmp = (*end) ? end+1 :end;
}
//tekkamanninja
printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",bd->bi_enetaddr[0],
bd->bi_enetaddr[1],bd->bi_enetaddr[2], bd->bi_enetaddr[3],
bd->bi_enetaddr[4],bd->bi_enetaddr[5]);
......
紅色的字元是要做的修改:功能是屏蔽原有擷取MAC位址的語句,替換成從U-Boot的參數區讀取資料并存到bd->bi_enetaddr[i]中。
(2)“could not establish link” 提示和慢響應的解決方法:
int
eth_init(bd_t * bd)
{
......
DM9000_iow(DM9000_RCR, RCR_DIS_LONG |RCR_DIS_CRC | RCR_RXEN);
DM9000_iow(DM9000_IMR, IMR_PAR);
#if 0
i = 0;
while (!(phy_read(1) & 0x20)) {
udelay(1000);
i++;
if (i == 10000) {
printf("could notestablish link\n");
return 0;
}
printf(" link=%d\n",i);
}
lnk = phy_read(17) >> 12;
printf("operating at ");
switch (lnk) {
case 1:
printf("10M half duplex ");
break;
case 2:
printf("10M full duplex ");
break;
case 4:
printf("100M half duplex ");
break;
case 8:
printf("100M full duplex ");
break;
default:
printf("unknown: %d ", lnk);
break;
}
printf("mode\n");
#endif
return 0;
}
紅色的字元是要做的修改:功能是屏蔽無用的語句。其實被屏蔽的語句是MII接口用的,放在這顯然是錯誤的,無端的浪費了10秒鐘。
21.編譯修改好的代碼:
maketekkaman2440_config; make;
在uboot的根目錄下你就可以看到uboot的鏡像檔案了,燒到flash中就可以了。
以上生成的uboot鏡像,網絡似乎不大行,ping主機ping不通。SKY提供的uboot也是一樣的問題,ping不通。
還有一點需要說明的是:UBOOT在啟動核心的時候,還需要識别ID,需要UBOOT的ID和核心的ID相同,這個可以通過uboot的bdinfo指令看到UBOOT裡設定的ID。SKY提供的UBOOT的ID和核心的ID是經過修改的。是以前面生成的UBOOT鏡像會啟動不了SKY提供的核心。
你打開SKY提供的UBOOT代碼,include\asm-arm\mach-types.h,你将會發現第183行和377行的改動。
是以如果你想用前面生成的UBOOT啟動SKY提供的核心的話,那麼include\asm-arm\mach-types.h的377行也要修改成#define MACH_TYPE_S3C2440 168,這樣就可以啟動了。
現在的uboot隻有一些基本的功能,最近從網上(http://www.100ask.net/showtopic-544.aspx)弄了個uboot1.1.6,支援S3C24x0/yaffs/USB/CS8900/DM9000/OpenJTAG/Nor,Nand啟動的u-boot,回頭再試一試。
二、 linux2.6.24.4移植
移植環境:VMware5.5.2+redhat9
開發闆:SKY_2440B_V5.0
編譯器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
核心:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
先說明一下,移植過程按照tekkaman的blog移植的。
部落格位址http://blog.chinaunix.net/u1/34474/index.html
另外也參考了http://blog.csdn.net/yang_dk/archive/2008/04/17/2300712.aspx和
http://blog.chinaunix.net/u2/63560/showart_511924.html部落格的内容。
所下面寫的移植過程,很多都是從blog上copy過來的,有不同的地方,我會另外指出。
1.解壓linux-2.6.24.4,和arm-linux-gcc-3.4.1
2.進入linux-2.6.24.4根目錄,修改makefile檔案
vi makefile
第193行改為:
ARCH =arm
CROSS_COMPILE = /usr/local/arm/3.4.1/bin/arm-linux- 告訴交叉編譯器的路徑
CROSS_COMPILE根據你自己arm-linux-gcc-3.4.1安裝的路徑設定.
3.修改arch/arm/plat-s3c24xx/common-smdk.c檔案,修改NAND_FLASH分區資訊和硬體資訊.
根據SKY的闆子,我設定如下:
這個結構體是設定nand的分區情況的
static struct mtd_partitionsmdk_default_nand_part[]={
[0]= {
.name = “UBOOT”,
.size = SZ_64K*4, //0x0~0x40000,256K
.offset = 0,
},
[1] = {
.name = “kernel 2.6.24.4”,
.size = SZ_2M, //0x4c000~0x200000+0x4c000,2M
.offset = SZ_64K*4+SZ_16K*3,
},
[2] = {
.name = “rootfs”,
.size = SZ_64K*987, //0x0024c000~0x03db0000+ 0x0024c000
.offset = SZ_2M+SZ_64K*4+SZ_16K*3,
}
};
另外修改smdk_nand_info,如下:
static struct s3c2410_platform_nand smdk_nand_info = {
.tacls = 0,
.twrph0 = 30,
.twrph1 = 0,
.nr_sets = ARRAY_SIZE(smdk_nand_sets), 應該為初始化nand的設定結構體
.sets = smdk_nand_sets, 應該為初始化nand的設定結構體
};
4.修改時鐘: arch/arm/mach-s3c2440/mach-smdk2440.c
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000); 外部的晶振的頻率是12MHz
s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));
}
開發闆的mapio的初始化。首先我來講解一下我對io記憶體映射的了解,io記憶體是具有實體位址的
關于IO與記憶體空間:
在X86處理器中存在着I/O空間的概念,I/O空間是相對于記憶體空間而言的,它通過特定的指令in、out來通路。端口号辨別了外設的寄存器位址。Intel文法的in、out指令格式為:
IN 累加器, {端口号│DX}
OUT {端口号│DX},累加器
目前,大多數嵌入式微控制器如ARM、PowerPC等中并不提供I/O空間,而僅存在記憶體空間。記憶體空間可以直接通過位址、指針來通路,程式和程式運作中使用的變量和其他資料都存在于記憶體空間中。
即便是在X86處理器中,雖然提供了I/O空間,如果由我們自己設計電路闆,外設仍然可以隻挂接在記憶體空間。此時,CPU可以像通路一個記憶體單元那樣通路外設I/O端口,而不需要設立專門的I/O指令。是以,記憶體空間是必須的,而I/O空間是可選的。
是以你現在應該明白了大多數嵌入式處理器為什麼都采用io記憶體映射,這樣會使操作io口像操作記憶體一樣,并不需要特殊的指令,我們将io的實體位址也就是資料手冊上寫的寄存器的位址将他進行記憶體映射,這就是所謂的io記憶體映射,映射後的位址當然是虛拟位址了,這樣我們操作這個虛拟位址就等于操作io。
在Linux裝置驅動中,宜使用Linux核心提供的函數來通路定位于I/O空間的端口,這些函數包括:
· 讀寫位元組端口(8位寬)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
· 讀寫字端口(16位寬)
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
· 讀寫長字端口(32位寬)
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
· 讀寫一串位元組
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
· insb()從端口port開始讀count個位元組端口,并将讀取結果寫入addr指向的記憶體;outsb()将addr指向的記憶體的count個位元組連續地寫入port開始的端口。
· 讀寫一串字
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);
· 讀寫一串長字
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);
上述各函數中I/O端口号port的類型高度依賴于具體的硬體平台,是以,隻是寫出了unsigned。
(3)readb和writeb:
在裝置的實體位址被映射到虛拟位址之後,盡管可以直接通過指針通路這些位址,但是工程師宜使用Linux核心的如下一組函數來完成裝置記憶體映射的虛拟位址的讀寫,這些函數包括:
· 讀I/O記憶體
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
與上述函數對應的較早版本的函數為(這些函數在Linux 2.6中仍然被支援):
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);
· 寫I/O記憶體
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
與上述函數對應的較早版本的函數為(這些函數在Linux 2.6中仍然被支援):
void writeb(unsigned value, address);
void writew(unsigned value, address);
void writel(unsigned value, address);
(4)把I/O端口映射到“記憶體空間”:
void *ioport_map(unsigned long port, unsigned int count);
通過這個函數,可以把port開始的count個連續的I/O端口重映射為一段“記憶體空間”。然後就可以在其傳回的位址上像通路I/O記憶體一樣通路這些I/O端口。當不再需要這種映射時,需要調用下面的函數來撤消:
void ioport_unmap(void *addr);
實際上,分析ioport_map()的源代碼可發現,所謂的映射到記憶體空間行為實際上是給開發人員制造的一個“假象”,并沒有映射到核心虛拟位址,僅僅是為了讓工程師可使用統一的I/O記憶體通路接口通路I/O端口。
在S3C2410的Linux裡面,全部都會做phy->virt的映射。映射方式中的一種是靜态映射,ioremap是動态映射。在靜态映射之後,仍然可以通過ioremap動态映射,也就是一個IO實體位址可以映射到多個虛拟位址。
其實所謂的記憶體映射,也不要想的那麼複雜,你可以看看上面的從實體位址到虛拟位址的映射,其實就是一個位址變化。建立一個對應關系,那你會納悶為什麼建立這個對應關系,首先你要知道我們這些操作都是在核心裡的,核心操作的也是虛拟位址,我們這塊用的虛拟位址和實體位址隻存在簡單的線性關系,在這裡我就不多解釋了,嘿嘿,懶着寫,記住google是你的最好老師!!!
smdk2440_map_io函數中會調用:
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
而開發闆相關的記憶體映射在smdk2440_iodesc,有ISA,聲霸卡,網卡等。
定義如下:
static struct map_desc smdk2440_iodesc[] __initdata = {
{ (u32)S3C24XX_VA_ISA_WORD,S3C2410_CS2, SZ_16M, MT_DEVICE },
{ (u32)S3C24XX_VA_ISA_BYTE,S3C2410_CS2, SZ_16M, MT_DEVICE },
};
2.s3c24xx_init_io函數會調用:iotable_init(s3c_iodesc,ARRAY_SIZE(s3c_iodesc));
而s3c_iodesc定義如下:
static struct map_desc s3c_iodesc[]__initdata = {
IODESC_ENT(GPIO),
IODESC_ENT(IRQ),
IODESC_ENT(MEMCTRL),
IODESC_ENT(UART)
};
這個部分是系統啟動必須的映射。
後續會調用(cpu->map_io)(mach_desc,size);來完成其他映射。
這個函數會調用iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
定義如下:
static struct map_desc s3c2440_iodesc[] __initdata = {
IODESC_ENT(USBHOST),
IODESC_ENT(USBDEV),
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
綜合上述發現,如果一個新加驅動,首先要看是否完成了IO映射,如果沒有的話,就在開發闆部分加入。
5.修改nand flash的校驗方式,去掉ECC校驗
在drivers/mtd/nand/s3c2410.c的第699行
将chip->ecc.mode = NAND_ECC_SOFT;
改為chip->ecc.mode = NAND_ECC_NONE;
網上有的blog上不用去掉也可以,編譯不會出錯,但是我沒有試驗過,我是把ECC校驗去掉的了.(經測試,這個不用改也可以)
6.增加Yaffs2檔案系統的支援
下載下傳Yaffs2: http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/
解壓yaffs2并将其加入linux核心(打更新檔的方式):
cd yaffs2
./patch-ker.shc /home/dk/myboard/linux-2.6.24.4/
./patch-ker.shc 後面跟的是你linux解壓所在的路徑.打完包後,在核心fs檔案夾下将會多了yaffs檔案夾,同僚makefile檔案也自動修改了.
7.為了核心支援devfs以及在啟動是并在/sbin/init運作之前自動挂載/dev為devfs檔案系統,編輯fs/Kconfig:
在906行menu “Pseudo filesystems”下面添加如下代碼:
config DEVFS_FS
bool “/dev file system support(OBSOLETE)”
default y
config DEVFS_MOUNT
bool “Automatically mount atboot”
default y
depends on DEVFS_FS
有的blog說不需要增加這一段,因為2.6.24.4已經把devfs的相關代碼删除了,即使添加了也沒有用.我在移植核心的時候還是加上了這段代碼,不加的編譯情況還沒有試.(經測試,這段現在不加也可以)
8.複制編譯配置檔案到2.6.24.4核心根目錄下.
cparch/arm/configs/s3c2410_defconfig.config
将config覆寫掉,他是核心的配置,我們在圖形界面下配置核心後的最終儲存結果就是變成了config檔案,我們用s3c2410_defconfig的配置,是因為他接近我們的2440的配置,再此基礎上修改核心配置。
9.編譯核心選項:make menuconfig
[*] Enable loadable module support --->
[*] Module unloading
[*] Automatic kernelmodule loading
選擇這兩個,剩下的可以去掉
System Type ---->
[*] S3C2410 DMA support
[*] Support ARM920T processor
S3C2410 Machines --->
[*] SMDK2410/A9M2410
S3C2440 Machines --->
[*] SMDK2440
[*] SMDK2440 with S3C2440CPU module
System Type這部分,隻選這些,其他可以全部去掉。另外,網上一些文章都說隻選上SMDK2440就可以了,其他的都去掉,我沒有試,不知道行不行.(經過測試,必須SMDK2410的選項)
Boot option ----->
修改啟動參數為:
noinitrd root=/dev/mtdblock2init=/linuxrc console=ttySAC0,115200
可能根據個人闆子的設定會不一樣,我的是從Nand Flash中加載檔案系統,其中mtdblock2是存放我的Linux檔案系統的分區。不過,在bootloader可以傳遞核心參數的情況下這個設定是無效的。
Userspace binary formats --->
< > Kernel support for a.out andECOFF binaries (去除該選項,a.out和ECOFF是兩種可執行檔案的格式,在ARM-Linux下一般都用ELF,是以這兩種基本用不上。)
Device Drivers --->
<*> Memory Technology Device(MTD) support --->
[*] MTD partitioning support
<*> NAND Device Support --->
<*> NAND Flash support for S3C2410/S3C2440SoC
[ ] S3C2410 NAND Hardware ECC //這個要去掉
[*] Network devicesupport --->
[*] Ethernet (10 or 100Mbit) --->
<*> DM9000 support
<*> Real TimeClock --->
“N”掉 [] Set system time from RTC on startup and resume
去掉紅字的兩個部分,黑子部分選上,其他的選擇預設就可以了。
File systems -->
< > Second extended fs support #去除對ext2的支援
< > Ext3 journalling file systemsupport #去除對ext3的支援
<*> Kernel automounter support
<*> Kernel automounter version 4support (also supports v3)
<*> Filesystem in Userspace support
Pseudo filesystems -->
[*] Virtual memory filesystem support (former shm fs)
<*>Userspace-driven configuration filesystem (EXPERIMENTAL)
Miscellaneous filesystems-->
<*> YAFFS2file system support
“N”掉[ ]Autoselect yaffs2 format和
[ ]Cache short names in RAM ,因為這是給每頁大于1024B的NAND Flash設計的
<*> Journalling Flash File System v2 (JFFS2)support
(0) JFFS2 debuggingverbosity (0 = quiet, 2 = noisy)
[*] JFFS2 write-bufferingsupport
[ ] JFFS2 summary support(EXPERIMENTAL)
[ ] JFFS2 XATTR support(EXPERIMENTAL)
[*] Advanced compressionoptions for JFFS2
[*] JFFS2 ZLIBcompression support
[*] JFFS2RTIME compression support
[*] JFFS2RUBIN compression support
JFFS2 default compression mode(priority) --->
Network File Systems -->
<*> NFS file system support
--以下最好選上,因為在挂載NFS時可能出現protocol不支援的情況--
[*]Provide NFSv3 client support
[*]Provide client support for the NFSv3 ACL protocol extension
[*] Provide NFSv4 client support (EXPERIMENTAL)
[*] Allow direct I/O on NFS files
-------------------------------------------------------------------------
<*> NFS serversupport
[*] Provide NFSv3 server support
[*]Provide serversupport for the NFSv3 ACL protocol extension
[*] Provide NFSv4 server support(EXPERIMENTAL)
--- Provide NFS server over TCPsupport
[*] Root file systemon NFS
注:我後面用到的根檔案系統是cramfs或yaffs.
10.ok,先編譯一下核心,make zIamge.編譯完在arch/arm/boot下将會有一個zImage檔案.
11.生成uboot用的uImage.
Uboot使用的鏡像和zImage有點差別,具體可以網上搜一下.
先把Uboot編譯後生成的tools/mkImage檔案copy到主機的/bin下,然後進入到linux-2.6.24.4核心的根目錄下,在執行一下make uImage指令,等上一會就會在arch/arm/boot下将會有一個uImage檔案.
最後下載下傳到開發闆上試試吧.目前的核心網卡、液晶等驅動都還沒有移植。
需要說明的,這個新的核心和SKY提供的yaffs檔案不比對,相比于以前的2.6.13之類,核心中修改了oob的使用,主要就是ECC較驗碼的位置。但是,yaffs那幫人沒有同步修改mkyaffsimg,這需要自己做。好在我在網上(http://www.100ask.net/showtopic-177.aspx)找到了mkyaffsimg的更新檔.
另外一個問題就是uboot移植中說到的ID不比對的問題,如果你用的uboot是SKY提供的,那麼需要将arch\arm\tools\mach-types檔案中的一行s3c2440 ARCH_S3C2440 S3C2440 362
改成s3c2440 ARCH_S3C2440 S3C2440 168即可.
三、 根檔案系統的設計(帶使用者登入)
移植環境:VMware5.5.2+redhat9(非root登入,需要切換到root下執行的另外指出)
開發闆:SKY_2440B_V5.0
編譯器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
Busybox:busybox-1.9.2.tar.bz2(http://busybox.net/downloads/)
Tinylogin:tinylogin-snapshot.tar.bz2(http://tinylogin.busybox.net/)
Cramfs制作工具: cramfs-1.1.tar.gz(http://sourceforge.net/projects/cramfs/)
先說明一下,移植過程按照tekkaman的blog移植的。
部落格位址http://blog.chinaunix.net/u1/34474/index.html
其中參照http://blog.chinaunix.net/u1/34474/showart_485837.html做的。
所下面寫的移植過程,很多都是從blog上copy過來的,有不同的地方,我會另外指出。
1.建立根檔案系統的基本目錄結構。
我把這個過程做成了shell腳本(檔案名為mkroot) ,很友善!
#! /bin/sh
echo "creatint rootfs dir......"
mkdir rootfs
cd rootfs
echo "making dir : bin dev etc lib proc sbin sysusr"
mkdir bin dev etc lib proc sbin sys usr #必備的8個目錄
mkdir usr/bin usr/lib usr/sbin lib/modules
# Don't use mknod ,unless you run this Script as root
# mknod -m 600 dev/console c 5 1
# mknod -m 666 dev/null c 1 3
echo "making dir : mnt tmp var"
mkdir mnt tmp var
chmod 1777 tmp
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/log var/run var/tmp
chmod 1777 var/tmp
echo "making dir : home root boot"
mkdir home root boot
echo "done"
有一點需要注意,在windows下的回車和linux下的回車不一樣,如果你是在windows下把這個腳本編輯好的,那麼在linux下運作會有點問題。
在你想要建立根檔案系統的地方,運作:
./mkroot
2.進入到dev檔案夾建立兩個裝置檔案,需要用root登入建立
Mknod –m 600 console c 5 1;mknod –m 666 null c 1 3;
3.配置、編譯、安裝busybox-1.9.2
(1)解壓busybox-1.9.2
(2)修改makefile檔案(在174行附近)
ARCH =arm
CROSS_COMPILE =/usr/local/arm/3.4.1/bin/arm-linux-
(3)配置busybox:make menuconfig
在原有的基礎上修改如下:
Busybox Settings --->
Installation Options --->
[*] Don't use /usr
(前面建立的rootfs所在路徑) BusyBox installation prefix
Busybox Library Tuning --->
[*]Support for /etc/networks
[*] Additional editing keys
[*] vi-style line editing commands
(15) History size
[*] History saving
[*] Tab completion
[*] Username completion
[*] Fancy shell prompts
Login/Password Management Utilities --->選項全部N掉,後面單獨使用TinyLogin。(因為內建的好像不是很好用,我自己的經驗是這樣)
Linux Module Utilities --->
[N]Support version 2.2.x to 2.4.x Linux kernels
Shells --->
--- Ash Shell Options 下的選項全選
(4)編譯、安裝
執行make;make install
執行之後,将會在你的rootfs的bin,sbin下建立一些檔案,同時在rootfs下生成一個linuxrc檔案。
4.修改必要的檔案
(1)将busybox-1.9.2下的examples/bootfloppy/etc/下的檔案copy到rootfs/etc下
cp –a .../ examples/bootfloppy/etc後增加自己的液晶驅動代碼,參考sky提供的液晶驅動\arch\arm\mach-s3c2410\sky2440.c中的#elif defined(CONFIG_FB_S3C24X0_S320240)
staticstruct s3c2410fb_mach_info smdk2440_lcdcfg__initdata = {。。。。}處的整個結構體的内容替換為:
static struct s3c2410fb_displaysky2440_lcd_cfg __initdata = {
{
.lcdcon5 =S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE|
S3C2410_LCDCON5_INVVFRAME|
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,
.width = 320,
.height = 240,
.pixclock = 100000,
.xres = 320,
.yres = 240,
.bpp = 16,
.left_margin = 16,
.right_margin = 6,
.hsync_len = 9,
.upper_margin = 4,
.lower_margin = 6,
.vsync_len = 16,
}
};
static struct s3c2410fb_mach_infosmdk2440_fb_info__initdata = {
。。。。。。。。。}處的整個結構體的内容替換為:
static struct s3c2410fb_mach_infosky2440_fb_info __initdata = {
.displays =&sky2440_lcd_cfg,
.num_displays = 1,
.default_display= 0,
.gpccon = 0xaa955699,
.gpccon_mask = 0xffc003cc,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa95aaa1,
.gpdcon_mask = 0xffc0fff0,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
.lpcsel = 0xf82,
};
在函數smdk2410_init()中加入
s3c24xx_fb_set_platdata(&sky2440_fb_info);
2.配置核心
DeviceDrivers --->
Graphics support --->
Display device support --->
<*> Displaypanel/monitor support
<*> Support for frame bufferdevices
<*> S3C2410 LCD framebuffer support
Console display driver support --->
<*> FramebufferConsole support
[*] Framebuffer Console Rotation
[*] Select compiled-infonts
[*] VGA8x8 font
[*] VGA8x16 font
[*] Mini4x6 font
[*] Sparc console 8x16font
[*] Bootup logo --->
--- Bootup logo
[*] Standard 224-color Linux logo
3.重新編譯核心,下載下傳,運作,你就會看到液晶上的那個小企鵝了,對應的圖檔為/drivers/video/logo/logo_linux_clut224.ppm.
另外這時可以把LCD當作一個控制台來使用了,例如執行:echo hello > /dev/tty0
将會在LCD的小企鵝下輸出hello字元.
六、 DM9000網卡驅動移植
移植環境:VMware5.5.2+redhat9
開發闆:SKY_2440B_V5.0
編譯器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
核心:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
DM9000的CS是接在nGCS4上的,INT接到EINT7,CMD接到ADDR2上.
1.增加DM9000平台裝置,修改arch/arm/plat-s3c24xx/common-smdk.c
(1)添加要包含的頭檔案
在47行處添加
#if defined (CONFIG_DM9000) ||defined(CONFIG_DM9000_MODULE)
#include <linux/dm9000.h>
#endif
(2)添加DM9000平台裝置結構
緊接着前面的地方,添加平台裝置結構
#if defined (CONFIG_DM9000) ||defined(CONFIG_DM9000_MODULE)
static struct resource s3c_dm9k_resource[] = {
[0]= {
.start= S3C2410_CS4,
.end= S3C2410_CS4 + 3,
.flags= IORESOURCE_MEM,
},
[1]= {
.start= S3C2410_CS4 + 4,
.end= S3C2410_CS4 + 4 + 3,
.flags= IORESOURCE_MEM,
},
[2]= {
.start= IRQ_EINT7,
.end= IRQ_EINT7,
.flags= IORESOURCE_IRQ,
}
};
static struct dm9000_plat_data s3c_dm9k_platdata = {
.flags= DM9000_PLATF_16BITONLY,
};
static struct platform_device s3c_device_dm9k = {
.name= "dm9000",
.id= 0,
.num_resources= ARRAY_SIZE(s3c_dm9k_resource),
.resource= s3c_dm9k_resource,
.dev= {
.platform_data= &s3c_dm9k_platdata,
}
};
#endif
(3)加入到核心裝置清單中
static struct platform_device __initdata *smdk_devs[] ={
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
};
2.修改drivers/net/dm9000.c
(1)增加包括頭檔案代碼
在74行附近
#if defined(CONFIG_ARCH_S3C2410)
#include <asm/arch-s3c2410/regs-mem.h>
#endif
(2)設定存儲器控制器BANK4使用,設定預設MAC位址
在dm9000_probe()函數中先增加兩個變量定義(大概412行)
#ifdefined(CONFIG_ARCH_S3C2410)
unsignedint oldval_bwscon;
unsignedint oldval_bankcon4;
#endif
再增加Bank4的設定(大概427行)
……
PRINTK2("dm9000_probe()");
#if defined(CONFIG_ARCH_S3C2410)
oldval_bwscon= *((volatile unsigned int *)S3C2410_BWSCON);
*((volatileunsigned int *)S3C2410_BWSCON)= (oldval_bwscon & ~(3<<16)) \
|S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
oldval_bankcon4= *((volatile unsigned int *)S3C2410_BANKCON4);
*((volatileunsigned int *)S3C2410_BANKCON4)= 0x1f7c;
#endif
設定預設MAC位址(大概612行)
…..
if(!is_valid_ether_addr(ndev->dev_addr))
printk("%s: Invalidethernet MAC address. Please "
"set using ifconfig\n",ndev->name);
#if defined(CONFIG_ARCH_S3C2410)
printk("nowuse the default MAC address:08:90:90:90:90:90\n");
ndev->dev_addr[0]= 0x08;
ndev->dev_addr[1]= 0x90;
ndev->dev_addr[2]= 0x90;
ndev->dev_addr[3]= 0x90;
ndev->dev_addr[4]= 0x90;
ndev->dev_addr[5]= 0x90;
#endif
………
out:
printk("%s:not found (%d).\n", CARDNAME, ret);
#if defined(CONFIG_ARCH_S3C2410)
*((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;
*((volatile unsigned int *)S3C2410_BANKCON4) = oldval_bankcon4;
#endif
……..
(3)注冊終端市,指定觸發方式,在dm9000_open()中
static int
dm9000_open(struct net_device *dev)
{
board_info_t*db = (board_info_t *) dev->priv;
PRINTK2("enteringdm9000_open\n");
#if defined(CONFIG_ARCH_S3C2410)
if(request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED |IRQF_TRIGGER_RISING, dev->name, dev))
#else
if(request_irq(dev->irq, &dm9000_interrupt, DM9000_IRQ_FLAGS,dev->name, dev))
#endif
return-EAGAIN;
…….
3.修改核心配置
Make menuconfig之後,将DM9000編譯入核心,或者配置成子產品.
Device Drivers --à
Networkdevice support --à
[*]Networkdevice support
Ethernet(10 or 100Mbit) -à
<*>DM9000support
4.重新編譯核心:make uImage
七、 USB驅動
移植環境:VMware5.5.2+redhat9
開發闆:SKY_2440B_V5.0
編譯器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
核心:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
沒有修改什麼檔案,隻是在核心編譯的時候,加入了一些有關usb的選項
Device drives ---à
SCSI device support ---à
<*>SCSI device support
[*]legacy /proc/scsi/ support
<*>SCSI disk support
USB support ->
<*> support for Host-side USB
[*] USB device filesystem
<*>OHCI HCD support
<*>USB Mass storage support
HID device --à
<*>USB Human Interface device(full HID) support
[*] /dev/hiddev raw HID device support
重新編譯核心,下載下傳.
啟動後,如果将usb滑鼠插入疊在一起的那個usb接口的下面那個接口,你将會看到提示
[@(none) /dev]#usb 1-1: newlow speed USB device using s3c2410-ohciand address3
usb 1-1: configuration #1chosen from 1 choice
input: USB Mouse as/class/input/input1
input: USB HID v1.00 Mouse[USB Mouse] on usb-s3c24xx-1
并且在dev下增加了幾個檔案: usbdev1.2, usbdev1.2_ep00, usbdev1.2_ep81
當拔下的時候: [@(none)/dev]#usb 1-1: USB disconnect, address 3
另外拿了塊u盤,挂載在上面可以看到内容(需要核心支援相應的檔案系統).
八、 Qtopia移植(qtopia-2.2.0版本)
移植環境:VMware5.5.2+redhat9
開發闆:SKY_2440B_V5.0
編譯器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
核心:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
前面已經移植的核心和檔案系統可以在終端下正常操作(除了網絡ping的時候還有丢包的問題),下面要在前面的基礎上移植qtopia.
首先是一些壓縮包的下載下傳:
1.得到本機運作版本uic 工具: http://vanille.de/tools/uic-qt2
下載下傳後改變權限 chmod u+rx uic-qt2
2.qtopia-free-src-2.2.0.tar.gz下載下傳位址:
ftp://ftp.trolltech.com/pub/qt/source/qtopia-free-src-2.2.0.tar.gz
3.e2fsprogs-1.39.tar.gz 下載下傳位址:
http://nchc.dl.sourceforge.net/sourceforge/e2fsprogs/e2fsprogs-1.39.tar.gz
4.jpegsrc.v6b.tar.gz 下載下傳位址:
http://superb-east.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.14.tar.bz2
5.libpng-1.2.14.tar.bz2下載下傳位址:
http://superb-east.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.14.tar.bz2
6.tslib-1.3.tar.bz2(觸摸屏校正工具:也可以用QT自帶的,這樣就不必下載下傳) 下載下傳位址:
http://mail.pdaxrom.org/download/1.1.0beta4/src/tslib-1.3.tar.bz2
7.zlib-1.2.3.tar.bz2下載下傳位址:
http://www.zlib.net/zlib-1.2.3.tar.gz
移植步驟:
在開始之前需要修改交叉編譯器的一個頭檔案,為/…../3.4.1/armlinux/include/linux/fd.h,在該檔案中增加一行:#include<linux/compiler.h>
1.導出編譯工具安裝路徑
export PATH=$PATH:/...../3.4.1/bin/
source/etc/profile
2.建立qt的檔案夾
mkdir /..../myboard/qtopia-arm-home
exportMYHOME=/..../myboard/qtopia-arm-home
3.建立幾個檔案夾
cd $MYHOME
mkdir arm
cd arm
mkdir libinclude
4.解壓有關庫檔案
e2fsprogs-1.39.tar.gz.tar.gz,jpegsrc.v6b.tar.gz,libpng-1.2.14.tar.bz2,zlib-1.2.3.tar.bz2解壓至$MYHOME/arm目錄,并相應更名目錄為 e2fs,jpeg,libpng,zlib。
5.編譯相關庫
(1) e2fs
cd $MYHOME/arm/e2fs
./configure --host=arm-linux--enable-elf-shlibs --with-cc=arm-linux-gcc -with-linker=arm-linux-ld--prefix=/..../3.4.1/arm-linux
Make
将lib檔案夾下的uuid檔案夾複制到../include把libuuid.so*複制到../lib
cp -r lib/uuid ../include
cp lib/libuuid.so* ../lib
再同樣複制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(2) jpeg
cd $MYHOME/arm/jpeg
./config --enable-shared --prefix=/…./3.4.1/arm-linux
gedit Makefile
修改
CC= arm-linux-gcc
AR= arm-linux-ar rc
AR2=arm-linux-ranlib
Make
Make install-lib
将會在/…./3.4.1/arm-linux/lib和/…./3.4.1/arm-linux/include中生成有關庫檔案(libjpeg.so*,libjpeg.a,libjpeg.la)和頭檔案(jpeglib.h)
再同樣上面那些檔案複制一份到$MYHOME/arm/include 和$MYHOME/arm/lib下
(3) zlib
cd $MYHOME/arm/zlib
./configure -shared
gedit Makefile
修改
[begin]
......
CC=arm-linux-gcc
......
LDSHARED=arm-linux-gcc -shared-Wl,-soname,libz.so.1
CPP=arm-linux-gcc -E
......
AR=arm-linux-ar rc
RANLIB=arm-linux-ranlib
......
prefix =/.../3.4.1/arm-linux
......
[end]
make
cp libz.so* ../lib/
cp *.h ../include/
再同樣複制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(4)libpng
cd $MYHOME/arm/libpng
cp scripts/makefile.linux ./Makefile
gedit Makefile
修改:
[begin]
.....
AR_RC=arm-linux-ar rc
CC=arm-linux-gcc
.....
RANLIB=arm-linux-ranlib
....
prefix=/.../3.4.1/arm-linux
.....
[end]
make
cp libpng.a ../lib/
cp libpng12.so* ../lib/
cp libpng12.so ../lib/libpng.so
cp *.h ../include/
再同樣複制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
6.建立檔案夾nfs
cd $MYHOME
mkdir nfs
7.解壓qtopia-free-2.2.0.tar.bz2到nfs檔案夾
8.編譯qtopia
(1)建立安裝目錄
mkdir $MYHOME/nfs/qtopia
(2)複制uci-qt2檔案
cp uic-qt2 $MYHOME/nfs/qtopia-free-2.2.0/qt2/bin/uic
(3)修改檔案
vi $MYHOME/nfs/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++/qmake.conf
将此行
QMAKE_LIBS_QT = -lqte
修改為
QMAKE_LIBS_QT= -lqte -lpng -lz -luuid -ljpeg
(4)支援usb鍵盤和滑鼠
修改$QPEDIR/src/qt/qconfig-qpe.h檔案
注釋如下部分:
(5)準備配置檔案:
cp $MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/qt/qconfig-qpe.h$MYHOME/nfs/qtopia-free-2.2.0/qt2/src/tools
cd $MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/libraries/qtopia
cp custom-linux-ipaq-g++.cppcustom-linux-arm-g++.cpp
cp custom-linux-ipaq-g++.hcustom-linux-arm-g++.h
(6) 開始配置
./configure -qte '-embedded -xplatformlinux-arm-g++ -qconfig qpe -no-qvfb -depths 16,32 -system-jpeg -system-libpng-system-zlib -gif -thread -no-xft -release -I$MYHOME/arm/include-L$MYHOME/arm/lib -lpng -lz -luuid -ljpeg' -qpe '-xplatform linux-arm-g++-edition pda -displaysize 320x240 -I$MYHOME/arm/include -L$MYHOME/arm/lib-prefix=$MYHOME/nfs/qtopia'
. ./setQpeEnv(兩個點号之間有空格)
其中的320*240是對應我的觸摸屏的長和寬
(7)make
make過程中可能會有一些錯誤,根據提示進行修改,但我make時沒有出現錯誤
(8)make install
至此将在$MYHOME/nfs/qtopia中生成一些qt移植所需的檔案
9.複制在第四節中得到的檔案系統目錄(mini_rootfs),改名成qt_rootfs
10.将Qtopia所依賴的庫複制到qt_rootfs/lib中
cd $MYHOME/arm
cp lib/* ……/qt_rootfs/lib
11.複制字庫(字庫在$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts/中)
cp –rf$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts $MYHOME/nfs/qtopia
12.将qtopia檔案夾複制到qt_rootfs中
先在qt_rootfs中建立一個opt檔案夾:cd ……./qt_rootfs;mkdir opt;
再将$MYHOME/nfs中的qtopia檔案夾複制到qt_rootfs/opt中
13.建立時區檔案
cd ……./qt_rootfs
mkdir –pusr/share/zoneinfo
cp –rf/usr/share/zoneinfo/America usr/share/zoninfo/
cp/usr/share/zoneinfo/zone.tab usr/share/zoneinfo/
也可以将$MYHOME/nfs/qtopia-free-2.2.0/qtopia/etc/下的zoneinfo檔案夾全部copy到usr/share/
14.僞造觸摸屏校驗檔案
Qtopia第一次啟動的時候會運作觸摸屏校驗程式,由于現在還沒移植觸摸屏驅動,會導緻校驗失敗,無法進入系統,可以在根檔案系統中建立一個觸摸校驗檔案etc/pointercal,内容為1 0 1 0 1 1 65536
15.建立一個腳本檔案,用來運作qtopia
在……qt_rootfs/bin下建立一個qpe.sh檔案
#!/bin/sh
exportHOME=/root
exportQTDIR=/opt/qtopia
exportQPEDIR=/opt/qtopia
exportQWS_DISPLAY=LinuxFb:/dev/fb0
exportQWS_KEYBOARD=”TTY:/dev/tty1”
exportQWS_MOUSE_PROTO=”USB:/dev/mouse0”
exportPATH=$QPEDIR/bin:$PATH
exportLD_LIBRARY_PATH=$QPEDIR/lib:$LD_LIBRARY_PATH
$QPEDIR/bin/qpe&
将qpe.sh設定成可執行.另外如果qt_rootfs/下沒有root檔案夾,要建立一個.HOME變量要用到.
16.修改根檔案系統的啟動腳本
(1) 在qt_rootfs下建立一個tmp目錄(如果已經有這麼一個目錄則跳過這一步)
(2) 在etc/fstab中加入這麼一行(如果已經有這麼一行則跳過這一步)
tmpfs /tmp tmpfs defaults 0 0
(3)修改etc/init.d/rcS,在最後加入這麼一行
/bin/qpe.sh&
16.重新制作yaffs檔案系統
./mkyaffsimage………/qt_rootfs qt_rootfs.yaffs
17.重新将qt_rootfs.yaffs燒寫進開發闆,啟動即可
注:目前還不支援觸摸屏,可能要用到qtopia自帶的tslib或者要用到tslib.1.3.tar.bz2.
九、
十、
十一、
十二、
十三、
十四、
十五、