一、 步驟說明:
U-Boot源代碼下載地址 http://www.linuxidc.com/Linux/2011-07/38897.htm
二、 啟動流程簡介
步驟一:建立u-boot下的 unsp2440開發板目錄結構
在u-boot的目錄樹中默認沒有S3C2440芯片的支持,但是其同S3C2410相差不多,我們根據S3C2410的一些配置修改得到對2440芯片的支持,u-boot默認僅支持Nor啟動,我們第一步完成U-boot在NORFLASH上的啟動。
目前u-boot對很多CPU直接支持,可以查看board目錄的一些子目錄,如:board/samsung/目錄下就是對三星一些ARM處理器的支持,有smdk2400、smdk2410和smdk6400,但沒有2440,所以我們就在這裡建立自己的開發板項目。
(1) 因2440和2410的資源差不多,主頻和外設有點差別,所以就在board/samsung/下建立自己開發板的項目,取名叫unsp2440
(2) #tar jxvf u-boot-2010.06.tar.bz2 //解壓源碼
(3) #cd u-boot-2010.06/board/samsung/ //進入目錄
(4) #cp smdk2410/ unsp2440/ -R //將2410目錄復制一份並重命名為unsp2440
#cd unsp2440 //進入unsp2440目錄
#mv smdk2410.c unsp2440.c //將unsp2440下的smdk2410.c改名為unsp2440.c
#vi board/samsung/unsp2440/Makefile //修改unsp2440下Makefile的編譯項,如下:
COBJS := unsp2440.o flash.o //因在unsp2440下我們將smdk2410.c改名為unsp2440.c
(5) #cp include/configs/smdk2410.h include/configs/unsp2440.h //建立2440頭文件
(6) 修改u-boot跟目錄下的Makefile文件
查找到smdk2410_config的地方,在他下面按照smdk2410_config的格式建立unsp2440_config的編譯選項,另外還要指定交叉編譯器
smdk2410_config :unconfig //2410編譯選項格式
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0
unsp2440_config :unconfig //2440編譯選項格式
@$(MKCONFIG) $(@:_config=) arm arm920t unsp2440 samsung s3c24x0
CROSS_COMPILE ?= arm-linux- //指定交叉編譯器為arm-linux-gcc
*說明:
*注意:編譯選項格式的第二行要用Tab鍵開始,否則編譯會出錯
(7) 測試編譯新建的unsp2440開發板項目
到此為止,u-boot對自己的unsp2440開發板還沒有任何用處,以上的移植只是搭建了一個unsp2440開發板u-boot的框架,要使其功能實現,還要根據unsp2440開發板的具體資源情況來對u-boot源碼進行修改。
步驟二:u-boot支持s3C2440 NOR啟動
根據u-boot啟動流程圖的步驟來分析或者修改添加u-boot源碼,使之適合unsp2440開發板(注:修改或添加的地方都用紅色表示)。
(1) unsp2440開發板u-boot的stage1入口點分析
前面我們知道了程序的入口點是arch/arm/arm920t/start.S,那麼我們就打開unsp2440開發板u-boot第一個要運行的程序arch/arm/arm920t/start.S(即u-boot的stage1部分),查找到_start的位置如下:
.globl _start
_start: b start_code //將程序的執行跳轉到start_code處
從這個匯編代碼可以看到程序又跳轉到start_code處開始執行,那麼再查找到start_code處的代碼如下:
/*
* the actual start code
*/
start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
/******dec by dengwei************/
/*bl coloured_LED_init*/
/*bl red_LED_on*/
//此處兩行是對AT91RM9200DK開發板上的LED進行初始化的,作為測試使用,我們這裡用不到,所以注釋掉
(2) unsp2440開發板u-boot的stage1階段的硬件設備初始化。
在include/configs/unsp2440.h頭文件中添加CONFIG_S3C2440宏
#vi include/configs/unsp2440.h
#define CONFIG_ARM920T 1 /* This is an ARM920T Core */
#define CONFIG_S3C24X0 1 /* in a SAMSUNG S3C24x0-type SoC */
#define CONFIG_S3C2410 1 /* specifically a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK2410 1 /* on a SAMSUNG SMDK2410 Board */
#define CONFIG_S3C2440 1 /* specifically a SAMSUNG S3C2440 SoC */
(3) 在u-boot中添加對S3C2440一些寄存器的支持、添加中斷禁止部分和時鐘設置部分。
1)中斷寄存器
由於2410和2440的寄存器及地址大部分是一致的,所以這裡就直接在2410的基礎上再加上對2440的支持即可,代碼如下:
#vi cpu/arm920t/start.S
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/************add by dengwei**********/
//關閉子中斷屏蔽寄存器
# if defined(CONFIG_S3C2440)
ldr r1, =0x7ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
2)時鐘管理:
/*******add by dengwei*************************************/
# if defined(CONFIG_S3C2440) //添加s3c2440的時鐘部分
#define MPLLCON 0x4C000004 //系統主頻配置寄存器基地址
#define UPLLCON 0x4C000008 //USB時鐘頻率配置寄存器基地址
ldr r0, =CLKDIVN //設置分頻系數FCLK:HCLKCLK = 1:4:8
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON //設置系統主頻為405MHz
ldr r1, =0x7F021
str r1, [r0]
ldr r0, =UPLLCON //設置USB時鐘頻率為48MHz
ldr r1, =0x38022
str r1, [r0]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
以上方法是在匯編中直接改變系統的時鐘頻率,為了實現u-boot���改方便同時實現同時支持2410,2440啟動,我們也可以把時鐘的初始化放在一個C文件中,做更加復雜的操作
/時鐘初始化
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl clock_init
#endif
S3C2440在start.S中修改以上信息,只是修改了第一階段的時鐘,u-boot在第二階段會重新初始化系統時鐘,還要分別在board/samsung/unsp2440/unsp2440.c和arch/arm/cpu/arm920t/s3c24x0/speed.c中修改或添加部分代碼,如下:
因為2410跟2440的的時鐘控制稍有不同,因此需要根據具體硬件選擇不同的參數
/* support both of S3C2410 and S3C2440, by dengwei */
extern const char *mtdparts_default;
if ((gpio->GSTATUS1 == 0x32410000) || (gpio->GSTATUS1 == 0x32410002))
{
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
//2410 MTD分區表信息
//mtdparts_default = MTDPARTS_DEFAULT2410;
//2410啟動引導參數
//setenv("bootargs", CONFIG_BOOTARGS2410);
}
else
{
/* arch number of UNSP2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
/*2440MTD分區表信息*/
//mtdparts_default = MTDPARTS_DEFAULT2440;
//*2440啟動引導參數
//setenv("bootargs", CONFIG_BOOTARGS2440);
}
#vi board/samsung/unsp2440/unsp2440.c
//設置主頻和USB時鐘頻率參數與start.S中的一致
#define FCLK_SPEED 2
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
#define M_MDIV 0xA1
#define M_PDIV 0x3
#define M_SDIV 0x1
#elif FCLK_SPEED==2 //即默認HCLK等於405M
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
#endif
#define USB_CLOCK 2 //USB默認為48M
#if USB_CLOCK==0
#define U_M_MDIV 0xA1
#define U_M_PDIV 0x3
#define U_M_SDIV 0x1
#elif USB_CLOCK==1
#define U_M_MDIV 0x48
#define U_M_PDIV 0x3
#define U_M_SDIV 0x2
#elif USB_CLOCK==2
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
#endif
#vi arch/arm/cpu/arm920t/s3c24x0/speed.c
//根據設置的分頻系數FCLK:HCLK:CLK = 1:4:8修改獲取時鐘頻率的函數
static ulong get_PLLCLK(int pllreg)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
ulong r, m, p, s;
if (pllreg == MPLL)
r = readl(&clk_power->MPLLCON);
else if (pllreg == UPLL)
r = readl(&clk_power->UPLLCON);
else
hang();
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
/******add by dengwei**********/
#if defined(CONFIG_S3C2440)
if(pllreg == MPLL)
{
//參考S3C2440芯片手冊上的公式:PLL=(2 * m * Fin)/(p * 2s)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
}
#endif
return (CONFIG_SYS_CLK_FREQ * m) / (p << s);
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
/*******add by dengwei******/
#if defined(CONFIG_S3C2440)
return(get_FCLK()/4);
#endif
return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK();
}
好了!修改完畢,我們重新編譯並將u-boot.bin使用H-JTAG下載到開發板的NOR FLASH中,觀察是否會打印啟動信息。