目錄
3. 修改源碼之實現從NOR啓動與NAND啓動
3.1 前言
3.2 實現從NOR啓動
3.2.1 修改設置時鐘
3.2.1.1 CLKDIVN寄存器
3.2.1.2 總線模式
3.2.1.3 MPLL寄存器
3.2.1.4 修改源碼
3.2.2 修改初始化存儲控制器參數
3.2.3 修改串口波特率相關內容
3.2.4 解決編譯錯誤
3.2.5 測試NOR Flash啓動
3.3 實現從NAND啓動
3.3.1 去掉 "-pie"選項
3.3.2 添加init.c文件
3.3.3 修改啓動流程
3.3.4 修改鏈接地址
3.3.5 修改重定位地址
3.3.6 修改鏈接腳本
3.3.7 測試NAND Flash啓動
3. 修改源碼之實現從NOR啓動與NAND啓動
3.1 前言
通過移植u-boot-2012.04.01到JZ2440(二:分析啓動流程)對uboot啓動流程的分析,我們知道源碼做了許多工作,回顧一下流程如下:
1. 設置異常向量表
2. 設置SVC管理模式、關看門狗、關中斷、設置時鐘頻率
3. 禁用Cache和MMU、初始化存儲控制器
4. 設置棧
5. 調用第一個C函數board_init_f
6. 重定位
6.1 拷貝代碼到SDRAM
6.2 修改動態鏈接地址數據
7. 清除bss段
8. 調用第二個C函數board_init_r(跳到SDRAM中運行)
修改代碼前,首先了解NOR啓動與NAND啓動的概念:
NOR啓動:上電後NOR Flash被映射到0x00000000地址(就是nGCS0,不需要片內SRAM輔助,片內SRAM的起始地址爲0x40000000),然後CPU從0x00000000開始運行(在NOR Flash上運行)。
NAND啓動:上電後CPU自動將NAND Flash中的前4K代碼拷貝到SRAM中,SRAM被映射爲0x00000000地址,CPU從0x00000000開始運行(在SRAM上運行)。
我們只需修改少量單板相關代碼就能將該uboot下載到NOR Flash上啓動,這是沒有問題的,但是想要在NAND Flash上運行,就會涉及一個嚴重問題:當uboot從NAND Flash啓動,CPU自動將uboot前4K代碼拷貝到片內RAM(此時片內RAM的基地址從0開始)中運行,前4步的代碼量很小,完全可以存放進這前4K的代碼裏,但是第5步調用第一個C函數board_init_f時,這部分的代碼基本不在前4K代碼以內,執行到這裏就會出錯(NOR Flash上能直接運行代碼,完全不用擔心該問題)。
所以想要在NAND Flash上啓動uboot,就需要在uboot前4K代碼裏將NAND Flash裏uboot的代碼拷貝到SDRAM中,也就是前4K代碼裏就要完成重定位(將NAND Flash內的uboot拷貝到SDRAM中)並跳轉到SDRAM中去執行剩餘代碼,而源碼重定位的信息又是通過調用第一個C函數board_init_f(暫且不考慮位置相關碼),但是我們又不能先調用board_init_f再重定位,爲了讓uboot能同時在NOR Flash也能在NAND Flash上啓動,所以啓動流程的後半部分我們基本自己來實現。
3.2 實現從NOR啓動
在移植u-boot-2012.04.01到JZ2440(一:創建單板)中我們已經創建好了單板相關文件,接下來按照啓動分析流程進行修改源碼實現從NOR Flash啓動uboot。
3.2.1 修改設置時鐘
3.2.1.1 CLKDIVN寄存器
在start.S文件中,uboot源碼只設置了CLKDIVN寄存器,查看S3C2440A芯片手冊第七章Clock & Power Management
有如下圖說明:
默認FCLK爲120MHz,則HDIVN和PDIVN都不爲0,這裏我們設置CLKDIVN寄存器的值爲5,也就是FCLK:HCLK:PCLK=1:4:8。
3.2.1.2 總線模式
同時手冊中還有如下說明:
表示S3C2440不支持同步總線模式,我們必須改爲異步模式,那麼我們必須在時鐘設置上加上那段代母,修改CPU的總線模式。
3.2.1.3 MPLL寄存器
datesheet中還有如下框圖:
我們CPU的啓動是在normal mode中,normal mode說明如下:
MPLL爲鎖相環輸出頻率 ,用來給MCU提供頻率,進而再給CPU的各個模塊供應頻率。具體可以看看datesheet中的Clock Generator Block Diagram框圖。儘管MPLL僅僅只是在一個reset後啓動,但是直到軟件對MPLLCON寄存器寫一個有效的設置之後,MPLL才作爲系統時鐘的輸出。在有效設置之前,從外部晶振源(XTlPll或EXTCLK)獲得的時候將直接用於系統時鐘。哪怕用戶不想要改變MPLLCON寄存器的值,用戶都應該寫一個相同的值進MPLLCON寄存器。
而我們的源碼中,在時鐘設置後,就直接跳到cpu_init_crit去執行,在其中又跳進lowlevel_init中執行SDRAM的初始化,並且註釋中HCLK的默認頻率爲60MHZ,此時的HCLK是依賴於FCLK也就是MPLL,因此我們必須添加上MPLL的設置。如下圖datesheet中的說明:
這裏我們設置MPLL爲400MHZ,所以MDIV設爲0x5c,PDIV設爲1,SDIV設爲1。
3.2.1.4 修改源碼
將以上3點修改到源碼,同時再啓動ICASHE。下面修改源碼,將以下內容(arch/arm/cpu/arm920t/start.S文件中):
改爲:
/* 設置時鐘 */
ldr r0, =0x4c000014
mov r1, #0x05; // FCLK:HCLK:PCLK=1:4:8
str r1, [r0]
/* 如果HDIVN非0,CPU的總線模式應該從“fast bus mode”變爲“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0 /* 讀出控制寄存器 */
orr r1, r1, #0xc0000000 /* 設置爲“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 寫入控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
/* MPLLCON = S3C2440_MPLL_400MHZ,FCLK=PLL=400MHZ */
ldr r0, =0x4c000004
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 啓動ICACHE */
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #(1<<12)
mcr p15, 0, r0, c1, c0, 0 @ write it back
由於後面會調用board_init_f()->board_early_init_f()裏面又設置了系統時鐘,這裏已經設置好了,所以屏蔽board_early_init_f()函數裏的時鐘設置,如下(board/samsung/jz2440/jz2440.c文件中):
3.2.2 修改初始化存儲控制器參數
修改內存控制寄存器默認參數,將以下內容(board/samsung/jz2440/lowlevel_init.S文件):
SMRDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30
改爲:
SMRDATA:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000740 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 // REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7
3.2.3 修改串口波特率相關內容
此時如果重新編譯燒寫uboot到NOR Flash運行會輸出亂碼,是由於串口設置問題,串口是在調用第一個C函數board_init_f()函數裏面調用init_sequence數組裏的serial_init()函數進行串口設置的,serial_init()函數如下(drivers/serial/serial.c中):
返回serial_init_dev()函數,參數爲UART_NR宏,該宏定義如下(drivers/serial/serial_s3c24x0.c中):
在include/configs/jz2440.h中默認定義了CONFIG_SERIAL1宏,也就是使用2440的串口0,S3C24X0_UART0是一個枚舉變量0,所以傳入參數爲0。serial_init_dev()函數如下(drivers/serial/serial_s3c24x0.c中):
static int serial_init_dev(const int dev_index)
{
/* 得到ULCON0控制寄存器基地址0x50000000 */
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
/* 使能FIFO, 清空Tx/Rx的FIFO緩衝區 */
writel(0x07, &uart->ufcon);
writel(0x0, &uart->umcon);
/* Normal,No parity,1 stop,8 bit */
writel(0x3, &uart->ulcon);
/*
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
*/
writel(0x245, &uart->ucon);
#ifdef CONFIG_HWFLOW
writel(0x1, &uart->umcon); /* rts up */
#endif
/* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
/* we need auto hw flow control on the gsm and gps port */
if (dev_index == 0 || dev_index == 1)
writel(0x10, &uart->umcon);
#endif
_serial_setbrg(dev_index); /*設置波特率*/
return (0);
}
該函數首先得到得到ULCON0控制寄存器基地址0x50000000,然後設置相關寄存器(配置FIFO、停止位、校驗位等),最後調用_serial_setbrg()函數,代碼如下(drivers/serial/serial_s3c24x0.c中):
void _serial_setbrg(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
unsigned int reg = 0;
int i;
/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
reg = get_PCLK() / (16 * gd->baudrate) - 1;
writel(reg, &uart->ubrdiv);
for (i = 0; i < 100; i++)
/* Delay */ ;
}
由於串口時鐘使用的是PLCK,其中通過get_PCLK()函數獲得PLCK時鐘,get_PCLK()函數如下:
由於之前設置的CLKDIVN寄存器爲5,所以get_PCLK()函數返回get_HCLK()/2,按照前面的CLKDIVN寄存器設置,get_HCLK()返回的應該是get_FCLK()/4,但是CONFIG_S3C2440宏卻沒有定義,執行的是else的代碼,所以需要我們添加CONFIG_S3C2440宏。
將以下內容(include/configs/jz2440.h文件中):
改爲:
3.2.4 解決編譯錯誤
此時重新編譯uboot會有如下錯誤:
可以找到drivers/mtd/nand/s3c2410_nand.c文件中多處使用s3c2410_nand這個結構體,之前將CONFIG_S3C2410宏改爲CONFIG_S3C2440後,就沒有定義s3c2410_nand這個結構體了,如下(include/configs/jz2440.h文件中):
所以暫時讓uboot不編譯s3c2410_nand.c文件,進入該文件的目錄下查看Makefile,如下:
CONFIG_NAND_S3C2410宏定義也在jz2440.h,如下:
直接來屏蔽CONFIG_CMD_NAND宏即可,因爲該宏下都是與2410相關的,所以修改如下(include/configs/jz2440.h文件中):
此時重新編譯(make distclean;make jz2440_config;make),還有如下錯誤:
同樣是s3c2410_nand這個結構體被調用了,查看fs/yaffs2/Makefile,有如下代碼:
屏蔽CONFIG_YAFFS2宏即可,修改如下(include/configs/jz2440.h文件中):
此時重新編譯(make distclean;make jz2440_config;make)成功。
3.2.5 測試NOR Flash啓動
燒寫試驗(使用韋東山老師的舊uboot進行燒寫快一點):
1. 使用韋東山老師的舊u-boot.bin,下載到norflash開發板撥置nor啓動,輸入q進入命令行;
2. 輸入 usb 1 30000000;(使用usb下載到SDRAM上,1表示一直下載,直到完成)
3. 使用dnw軟件下載編譯好的u-boot.bin;(傳輸新的uboot.bin給usb)
4. 輸入 protect off all;(關閉nor的寫保護)
5. 輸入 erase 0 7ffff;(擦除nor上的 0~7FFFF地址內容,擦除長度7FFF==512kb,要大於uboot.bin才行)
6. 輸入 cp.b 30000000 0 80000。(將SDRAM上的新的uboot.bin,拷貝到nor flash 0地址上)
重啓,此時串口輸出正確的報錯信息,如下所示:
PS:此時還不能修改jz2410.h中的指定鏈接地址的宏(CONFIG_SYS_TEXT_BASE,默認爲0),因爲調用第一個C函數board_init_f時調用init_sequence全局數組裏的函數,這是全局變量,裏面保存的是鏈接地址,而此時代碼又沒有拷貝到對應鏈接地址去(也就是重定位),跳到鏈接地址就會導致錯誤(此時宏CONFIG_SYS_TEXT_BASE=0時鏈接地址與運行地址才相同)。
3.3 實現從NAND啓動
3.3.1 去掉 "-pie"選項
uboot源碼在編譯執行arm-linux-ld時加了"-pie"選項,使得u-boot.bin裏多了"*(.rel*)", "*(.dynsym)",導致文件非常大;並且如果我們啓用了pie功能,那麼程序中的變量就會被抽出來放到代碼段後面的一些特殊段,而這些變量的地址肯定超過了4K,無法再訪問了。所以我們要去除這個pie選項,執行“grep "\-pie" * -nR”查找如下:
修改arch/arm/config.mk文件去掉pie選項如下:
3.3.2 添加init.c文件
添加init.c文件到board/samsung/jz2440目錄下,代碼如下:
/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))
void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
void nand_read0(unsigned int addr, unsigned char *buf, unsigned int len);
int isBootFromNorFlash(void)
{
volatile int *p = (volatile int *)0;
int val;
val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 寫成功, 是nand啓動 */
*p = val;
return 0;
}
else
{
/* NOR不能像內存一樣寫 */
return 1;
}
}
void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{
int i = 0;
/* 如果是NOR啓動 */
if (isBootFromNorFlash())
{
while (i < len)
{
dest[i] = src[i];
i++;
}
}
else
{
nand_read_ll((unsigned int)src, dest, len);
}
}
/* 清bss段 */
void clear_bss(void)
{
extern int __bss_start, __bss_end__; //bss段的開始地址與結束地址
int *p = &__bss_start;
for (; p < &__bss_end__; p++) /* 循環清0 */
*p = 0;
}
/* 初始化NAND Flash */
void nand_init_ll(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/* 設置時序 */
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */
NFCONT = (1<<4)|(1<<1)|(1<<0);
}
static void nand_select(void)
{
NFCONT &= ~(1<<1);
}
static void nand_deselect(void)
{
NFCONT |= (1<<1);
}
static void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD = cmd;
for (i = 0; i < 10; i++);
}
static void nand_addr(unsigned int addr)
{
unsigned int col = addr % 2048;
unsigned int page = addr / 2048;
volatile int i;
NFADDR = col & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (col >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = page & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for (i = 0; i < 10; i++);
}
static void nand_page(unsigned int page)
{
volatile int i;
NFADDR = page & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for (i = 0; i < 10; i++);
}
static void nand_col(unsigned int col)
{
volatile int i;
NFADDR = col & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (col >> 8) & 0xff;
for (i = 0; i < 10; i++);
}
static void nand_wait_ready(void)
{
while (!(NFSTAT & 1));
}
static unsigned char nand_data(void)
{
return NFDATA;
}
static int nand_bad(unsigned int addr)
{
unsigned int col = 2048;
unsigned int page = addr / 2048;
unsigned char val;
/* 1. 選中 */
nand_select();
/* 2. 發出讀命令00h */
nand_cmd(0x00);
/* 3. 發出地址(分5步發出) */
nand_col(col);
nand_page(page);
/* 4. 發出讀命令30h */
nand_cmd(0x30);
/* 5. 判斷狀態 */
nand_wait_ready();
/* 6. 讀數據 */
val = nand_data();
/* 7. 取消選中 */
nand_deselect();
if (val != 0xff)
return 1; /* bad blcok */
else
return 0;
}
void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;
while (i < len)
{
if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一個block只判斷一次 */
{
addr += (128*1024); /* 跳過當前block */
continue;
}
/* 1. 選中 */
nand_select();
/* 2. 發出讀命令00h */
nand_cmd(0x00);
/* 3. 發出地址(分5步發出) */
nand_addr(addr);
/* 4. 發出讀命令30h */
nand_cmd(0x30);
/* 5. 判斷狀態 */
nand_wait_ready();
/* 6. 讀數據 */
for (; (col < 2048) && (i < len); col++)
{
buf[i] = nand_data();
i++;
addr++;
}
col = 0;
/* 7. 取消選中 */
nand_deselect();
}
}
該文件函數說明如下:
1. isBootFromNorFlash()函數
1.1 對於從NAND Flash啓動的情況,其開始4KB的代碼會被自動複製到CPU內部4K RAM中,這4K RAM被映射爲0地址,此時讀寫0地址就是讀寫RAM,因此可以直接讀寫0地址。
1.2 對於從NOR Flash啓動的情況,NOR Flash的開始地址即爲0,此時讀寫0地址就是讀寫NOR Flash,因此必須通過一定的命令序列才能讀寫0地址。
所以可以根據這兩點來分辨是從NAND Flash還是NOR Flash啓動:向地址0寫入一個數據,然後讀出來,如果發現寫入失敗的就是NOR啓動,否則就是NAND啓動。
2. copy_code_to_sdram()函數
不使用源碼的重定位,使用該函數進行重定位,不需要進行修改動態鏈接地址,比較簡單,首先判斷boot啓動方式,然後將對應代碼拷貝到指定地址去(後面會通過指定相同的鏈接地址與重定位地址,然後調用該函數將u-boot代碼拷貝到重定位地址)。
3. clear_bss()函數
首先定義指針指向bss段的開始地址(鏈接地址)__bss_start,將該地址到bss段的結束地址(鏈接地址)__bss_end__全部清0。__bss_start與__bss_end__是在鏈接文件u-boot.lds中的標號。
4. NAND Flash相關函數
包含NAND Flash的設置、選中函數、發命令函數、發地址函數、判斷狀態函數、讀函數等。
再將該文件添加進board/samsung/jz2440目錄下的Makefile,修改如下:
3.3.3 修改啓動流程
在3.1 前言裏提到,不能按照源碼的啓動方式,在調用第一個C函數board_init_f之前要先重定位,所以修改start.S文件,將源碼調用board_init_f函數、重定位、清bss段、調用board_init_r函數代碼去掉或註釋,如下:
... ...
將該段代碼(上圖中203行~354行)替換成如下代碼:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
bl nand_init_ll /* 初始化NAND Flash */
mov r0, #0
ldr r1,_TEXT_BASE /* _TEXT_BASE存在前4k空間裏,若直接使用CONFIG_SYS_TEXT_BASE編譯
器可能會將這個宏定義放在SDRAM上,此時SDRAM上還沒有代碼 */
ldr r2, _bss_start_ofs
/* 重定位,參數1爲重定位前代碼存放的起始地址=0,參數2爲重定位地址,參數3爲代碼重定位的結束地址 */
bl copy_code_to_sdram
bl clear_bss /* 清bss段 */
ldr pc,=call_board_init_f /* 跳到SDRAM中執行call_board_init_f */
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f /* 調用board_init_f */
.globl call_board_init_r /* 定義爲全局標號,在board_init_f函數中調用 */
call_board_init_r: /* 從board_init_f中調用,得到參數r0=gd_t結構體指針,r1=重定位地址,r2=新的棧地址 */
mov sp, r2 /* 重新設置棧 */
bl board_init_r /* 調用board_init_r,參數爲r0,r1 */
對該段代碼說明如下:
1. 設置棧
調用C函數nand_init_ll之前需要先設置棧,這時的sp=0x30000F80。
2. 調用nand_init_ll函數
調用之前添加的init.c文件中的nand_init_ll函數,重定位之前調用該函數,因爲uboot可能存放在NAND Flash中。
3. 重定位
調用之前添加的init.c文件中的copy_code_to_sdram函數拷貝代碼到SDRAM中,傳入的參數1爲重定位前代碼存放的起始地址=0,參數2爲重定位地址,參數3爲代碼重定位的結束地址。
4. 清bss段
調用之前添加的init.c文件中的clear_bss函數。
5. 跳到SDRAM中執行uboot程序
6. 調用board_init_f函數
7. 重新設置棧
在board_init_f函數中得到新的棧地址r3,這裏設置新棧地址。
8. 調用board_init_r函數
從board_init_f函數中得到參數r0=gd_t結構體指針,r1=重定位地址。
3.3.4 修改鏈接地址
由於沒有使用源碼的動態修改鏈接地址代碼,所以在編譯U-Boot前修改鏈接地址,鏈接地址在start.S中定義如下:
所以修改宏CONFIG_SYS_TEXT_BASE即可,修改如下(include/configs/jz2440.h文件中):
3.3.5 修改重定位地址
源碼是通過在board_init_f函數中計算得到的重定位地址,我們這裏重定位地址必須與鏈接地址一樣,所以修改board_init_f()函數,將重定位地址設爲鏈接地址CONFIG_SYS_TEXT_BASE,修改如下(arch/arm/lib/board.c文件中):
同時去掉源碼board_init_f函數裏的重定位函數,替換爲調用call_board_init_r,修改如下(arch/arm/lib/board.c文件中):
3.3.6 修改鏈接腳本
把start.S、init.c(實現重定位、清bss等)、lowlevel_init.S(實現初始化SDRAM)等文件編譯時放在u-boot.bin的最前面,編譯時會在board/samsung/jz2440目錄下生成一個libsmdk2440.o文件,該文件是將jz2440單板目錄下的所有*.c、*S文件編譯後,連接成一個庫文件,只需要將該庫文件放在其他文件的代碼段之前即可,添加代碼“board/samsung/jz2440/libjz2440.o (.text)”到arch/arm/cpu/u-boot.lds文件(編譯後頂層目錄的u-boot.lds也會更新),修改如下:
此時重新編譯(make distclean;make jz2440_config;make)成功。
3.3.7 測試NAND Flash啓動
燒寫試驗(使用韋東山老師的舊uboot進行燒寫快一點):
1. 使用韋東山老師的舊u-boot.bin,下載到norflash開發板撥置nor啓動,輸入q進入命令行;
2. 輸入 usb 1 30000000;(使用usb下載到SDRAM的30000000上,1表示一直下載,直到完成)
3. 使用dnw軟件下載編譯好的u-boot.bin;(傳輸新的uboot.bin給usb)
4. 輸入 nand erase 0 80000;(擦除NAND Flash的0~80000地址)
5. 輸入 nand write 30000000 0 80000;(將SDRAM上的新的uboot.bin,拷貝到NAND Flash 0地址上)
開發板撥置NAND啓動,此時串口輸出正確的報錯信息,如下所示: