uboot-2012-4.1移植 (2)修改uboot程式碼
3 修改程式碼
a 修改start.s中時鐘設定部分。
/*修改這裡,時鐘設定不正確*/
/* FCLK:HCLK:PCLK = 1:4:8 */
/*設定時鐘*/
ldr r0,=0x4c000014
mov r1,#0x05
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))
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
ldr pc,=call_board_init_f //這條彙編是絕對跳轉指令
call_board_init_f: //這兩句程式實現了 程式從nor跳轉到sdram中執行。
ldr r0,=0x00000000
bl board_init_f
/*呼叫board_init_f函式返回值id,存在r0中,作為board_init_r的引數*/
ldr r1, _TEXT_BASE
ldr sp,base_sp //棧要重新設定,base_sp為定義的一個全域性變數 :.globl base_sp base_sp: .long 0
bl board_init_r //base_sp 在board_init_f函式中base_sp = addr_sp;被賦值。
/*呼叫第二階段程式碼*/
bl board_init_r
程式剛開始時的堆疊指標被定義為ldr sp,=(CONFIG_SYS_INIT_SP_ADDR) bic sp,sp,#7
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE)
修改smdk2440/smdk2410.c的 board_early_init_f 函式,去掉其對MPLL的設定。
b 修改sdram配置暫存器值
.long 0x22011110 @BWSCON
.long 0x00000700 @BANKCON0
.long 0x00000700 @BANKCON1
.long 0x00000700 @BANKCON2
.long 0x00000700 @BANKCON3
.long 0x00000700 @BANKCON4
.long 0x00000700 @BANKCON5
.long 0x00018005 @BANKCON6
.long 0x00018005 @BANKCON7
.long 0x008c07a3 @REFRESH
.long 0x000000b1 @BANKSIZE
.long 0x00000030 @MRSRB6
.long 0x00000030 @MRSRB7
也可以不用修改!
.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
3.1 修改了以後,編譯,下載,發現串列埠輸出的東西是亂些亂碼,初步認為是波特率沒有設定好
檢視串列埠波特率的設定,發現在get_HCLK裡沒有定義CONFIG_S3C2440
c 修改程式碼:include/configs/smdk2440.h:
去掉CONFIG_S3C2410 加上#define CONFIG_S3C2440
編譯,s3c2410_nand.c:72 行出錯。。去掉這個巨集 CONFIG_NAND_S3C2410 暫時不把nand flash加進來
把CONFIG_CMD_NAND去掉也就把nand 所有巨集都去掉了
編譯後,出錯:fs/yaffs2/libyaffs2.o: In function `yaffs_StartUp':
/home/zz/my-uboot-2012.4.01/fs/yaffs2/yaffscfg.c:210: undefined reference to `nand_info'
d 修改程式碼:include/configs/smdk2440.h: 註釋掉:#define CONFIG_YAFFS2。
再次編譯,make distclean make smdk2440_config make。能通過。
修改重定位程式碼後,發現不能從nor啟動了。查了半天,原因是:isBootFromNorFlash 函式中定義的指標沒有使用 volatile 關鍵字修飾
修改加上volatile 就Ok了。
e 修改start.S加上 .global base_sp base_sp: .long 0
修改board.c board_init_f 函式中 加上 extern ulong base_sp 在return 前加上base_sp = addr_sp;
f 修改程式碼使其支援nor flash
board_init_r
flash_init
flash_detect_legacy
flash_get_size
分析除錯資訊,開啟DEBUG巨集。在cfi_flash.c中新增#define DEBUG 1 #define _DEBUG 1
在jedec_flash.c中的 static const struct amd_flash_info jedec_table[] 陣列中新增:
/*GQ2440使用的nor flash : S29AL016MB*/
{
.mfr_id = (u16)AMD_MANUFACT, /*廠家ID*/
.dev_id = 0x2249, /*裝置ID*/
.name = "S29AL016MB",
.uaddr = { /*nor flash看到的解鎖地址*/
[1] = MTD_UADDR_0x0555_0x02AA /* x16 */
},
.DevSize = SIZE_2MiB, /*總大小*/
.CmdSet = CFI_CMDSET_AMD_LEGACY,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(16*1024, 1),
ERASEINFO(8*1024, 2),
ERASEINFO(32*1024,1),
ERASEINFO(64*1024, 31),
}
},
編譯、燒寫後,執行出現 ERROR: too many flash sectors
修改配置標頭檔案smdk2440.h
修改 #define CONFIG_SYS_MAX_FLASH_SECT (19)為(128)
去掉cfi_flash.c中新增#define DEBUG 1 #define _DEBUG 1
至此,uboot就能在Nor啟動和運行了!!但是還不能使用網路,使用nand flash來引導核心
g 修改網絡卡程式 使它支援DM9000
加入對DM9000支援的配置巨集
#if 0
#define CONFIG_CS8900 /* we have a CS8900 on-board */
#define CONFIG_CS8900_BASE 0x19000300
#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */
#else
#define CONFIG_DRIVER_DM9000
#define CONFIG_DM9000_BASE 0x20000000 //由網絡卡接到CPU的BANK地址來決定的
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE + 4) //這個由網絡卡上的CMD引腳接的位置來決定,LDDR2位+4 LDDR1+2 LDDR0+0
#endif
修改記憶體配置暫存器組的值,這裡只用修改
.long 0x00000740 @BANKCON4/*為了支援網絡卡而修改成740,原值為700*/
編譯還是出錯: Net: No ethernet found.
搜尋程式碼找到這句:
在 board_init_r
puts("Net: ");
eth_initialize(gd->bd);
board_eth_init
#ifdef CONFIG_CS8900
rc = cs8900_initialize(0, CONFIG_CS8900_BASE);
#endif
發現這裡只調用了cs8900_initialize,所以新增如下程式碼
#ifdef CONFIG_DRIVER_DM9000
rc=dm9000_initialize(bis);
#endif
make通過。插上網線, set ipaddr 192.168.0.6 ping 192.168.0.1
出錯: *** ERROR: `ethaddr' not set
原因沒有設定網絡卡MAC地址
set ethaddr 00:11:22:33:44:55
set ipaddr 192.168.0.2
set serverip 192.168.0.1
測試OK。。網絡卡移植到此結束。
移植的uboot還不能引導linux核心。
原因是,uboot傳遞的機器碼不對。對於國嵌的Linux核心,傳遞的機器碼為MINI2440 也就1999
可能在uboot裡 set machid 7cf 來設定。
set machid 7cf
set ethaddr 08:08:11:18:12:27
set bootargs noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
tftp 32000000 uimage
bootm 32000000
終於看到另人興奮的字元飄動的介面了。。。。。吼吼
3.2 修改程式碼,支援nand flash。
a 開啟巨集 #define CONFIG_CMD_NAND
make ,出錯,逐個修改錯誤
b s3c2410_nand.c:72:出錯 s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
這是因為配置檔案中開啟巨集 CONFIG_S3C2440 關閉巨集 CONFIG_S3C2410 而
#ifdef CONFIG_S3C2410
/* NAND FLASH (see S3C2410 manual chapter 6) */
struct s3c2410_nand { //2410的nand flash控制器暫存器
u32 nfconf;
u32 nfcmd;
u32 nfaddr;
u32 nfdata;
u32 nfstat;
u32 nfecc;
};
#endif
#ifdef CONFIG_S3C2440
/* NAND FLASH (see S3C2440 manual chapter 6) */
struct s3c2440_nand { //2440的nand flash控制器暫存器
u32 nfconf;
u32 nfcont;
u32 nfcmd;
u32 nfaddr;
u32 nfdata;
u32 nfeccd0;
u32 nfeccd1;
u32 nfeccd;
u32 nfstat;
u32 nfstat0;
u32 nfstat1;
};
#endif
所以struct s3c2410_nand *nand 結構體未定義,出錯
c 複製driver/mtd/nand/s3c2410_nand.c為 s3c2440_nand.c
把s3c2440_nand.c 裡所有函式名中的2410改為2440 在s3c2440_hwcontrol函式中
把原來的 struct s3c2410_nand *nand = s3c2410_get_base_nand();
修改成 struct s3c2440_nand *nand = s3c2440_get_base_nand();
修改smdk2440.h配置標頭檔案,開啟巨集CONFIG_NAND_S3C2440,關閉巨集CONFIG_NAND_S3C2410
/*
* NAND configuration
*/
#ifdef CONFIG_CMD_NAND
#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440 //修改加上,使Makefile裡會編譯s3c2440_nand.o
#define CONFIG_SYS_S3C2440_NAND_HWECC //
#endif
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0x4E000000
#endif
修改Makefile 加上COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
d uboot第二階段程式碼,nand分析過程
board_init_r
puts("NAND: ");
nand_init(); /* go init the NAND */
nand_init_chip(0) CONFIG_SYS_MAX_NAND_DEVICE==1
board_nand_init
設定nand_chip 結構體,提供底層操作函式
修改struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();為
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
#if 0 //這段程式碼是對2410的NFCONF暫存器設定數值的,和2440的設定值不同,註釋掉
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
#endif
/*初始化nand控制器*/
cfg = ((tacls-1)<<12) | ((twrph0-1)<<8) | ((twrph1-1)<<4);
writel(cfg, &nand_reg->nfconf);
/*使能Nand Flash控制器,初始化ECC,禁止片選*/
writel( (1<<4) | (1<<1) | (1<<0) ,&nand_reg->nfcont);
nand->select_chip = s3c2440_nand_select;//片選函式自己寫
nand_scan
nand_scan_ident
nand_set_defaults //設定裝置的操作的預設函式
chip->select_chip = nand_select_chip;
chip->cmdfunc = nand_command;
nand_get_flash_type //讀裝置型別
chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
nand_command(struct mtd_info *mtd, unsigned int command,int column, int page_addr)
//即可以用來發命令,也可以用來發地址:行地址和列地址
chip->cmd_ctrl(mtd, readcmd, ctrl);
nand->cmd_ctrl = s3c2440_hwcontrol;
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
*maf_id = chip->read_byte(mtd); //讀廠家ID
*dev_id = chip->read_byte(mtd); //讀裝置ID
nand 協議層:知道傳送什麼命令
單板相關函式:知道怎麼發關這資料:
選中/取消選中
發命令
發地址
R/W資料
判斷狀態
刪除掉ECC相關的函式,因為ECC比較複雜
修改s3c2440_nand.c中所有s3c2410_hwcontrol 為 s3c2440_hwcontrol
/* ctrl : 表示發命令還是發資料
* dat:表示命令值或資料值
*/
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
// struct nand_chip *chip = mtd->priv;
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(ctrl & NAND_CLE)/*發命令*/
{
writeb(dat,&nand->nfcmd);
}
else if(ctrl &NAND_ALE)/*發地址*/
{
writeb(dat,&nand->nfaddr);
}
}
//這裡的writeb(當然用writel也可以,因為這兩個暫存器有效資料都是8位)時,
//第二個引數加上&;這個函式在移植的過程中,少寫了,這個函式的功能就是發命令或發地址
static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(chipnr==0)/*選中*/
{
nand->nfcont &= ~(1<<1);
}
else if(chipnr==-1)/*取消選中*/
{
nand->nfcont |= (1<<1);
}
else
BUG();
}
這裡我共修改了include/configs/smdk2440.h drivers/mtd/nand/s3c2440_nand.c
drivers/mtd/nand/Makefile 三個檔案
可以開啟巨集 #define CONFIG_YAFFS2,make distclean make smdk2440_config make
E:\u-boot.bin
D:\u-boot.bin
loady 30000000
protect off all
erase 0 7ffff
cp.b 30000000 0 80000
3.3 修改uboot支援環境引數的儲存
在uboot啟動時*** Warning - bad CRC, using default environment
a 在原始碼中搜索 using default environment
common/env_common.c中 set_default_env 函式打印出這些資訊
檢視 set_default_env 中的default_environment
這個數組裡面很多的開關巨集,依次修改之
加上這三個巨集
#define CONFIG_BOOTARGS "noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M"
#define CONFIG_BOOTCOMMAND "bootm 32000000"
#define CONFIG_ETHADDR "08:08:11:22:af"
修改這個三巨集的IP地址,為了和開發用的主機一致
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.0.2
#define CONFIG_SERVERIP 192.168.0.1
#define CONFIG_SYS_PROMPT "SMDK2410 # " //用於修改在開發板上顯示使用者登入名
#if 0 /*the env save in nor flash*/
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000)
#define CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_SIZE 0x10000
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#endif
/*設定環境變數在nand中的儲存位置擦出長度*/
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00040000 //環境變數儲存的起始 nand 地址
#define CONFIG_ENV_SIZE 0x20000 /*128K正好是一個塊,nand擦出是按塊進行的*/
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE //
0x00000000-0x00040000 bootloader //nand 中的分割槽如下
0x00040000-0x00060000 params
0x00060000-0x00260000 kernel
0x00260000-0x10000000 root
b 裁減程式碼,去掉不常用的功能和命令
1去掉USB相關的巨集
//#define CONFIG_USB_OHCI
//#define CONFIG_USB_KEYBOARD
//#define CONFIG_USB_STORAGE
//#define CONFIG_DOS_PARTITION
2去掉RTC時鐘
//#define CONFIG_RTC_S3C24X0
3去掉一些命令列
//#define CONFIG_CMD_DATE
//#define CONFIG_CMD_DHCP
//#define CONFIG_CMD_USB
4關閉檔案系統相關巨集
/*
* File system
*/
#if 0
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
#define CONFIG_YAFFS2
#define CONFIG_RBTREE
#endif
c saveenv命令
儲存到 nand flash 上saveenv()在env_nand.c中
把env_nand.c編譯到程式中,檢視common/Makefile
由 COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o 可知
要開啟 開關巨集 CONFIG_ENV_IS_IN_NAND
nand erase [nand的起始地址] [nand的擦出大小]
nand write [欲讀的記憶體起始地址] [寫nand的起始地址] [大小]
nand read [欲寫的記憶體起始地址] [讀nand的起始地址] [大小]
d 在board.c中呼叫 mtdparts_init
/*mtdparts config配置nand 分割槽*/
#define CONFIG_MTD_DEVICE
#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=sust2440-0"
#define MTDPARTS_DEFAULT "mtdparts=sust2440-0:256k(u-boot)," \
"128k(params)," \
"2m(kernel)," \
"-(rootfs)"
修改arch/arm/lib/board.c,在 board_init_r函式中的 for(;;){main_loop();}前
加上 run_command("mtdparts default", 0); 對mtdparts分割槽進行初始化
設定環境變數
bootargs=noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/common/rootfs ip=192.168.0.2:192.168.0.255::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
bootcmd=nand read 32000000 kernel ; bootm 32000000
set machid 7cf //設定機器碼為1999也就是MINI2440的機器碼,怎麼在程式碼中寫死,沒有找到方法
nand erase.part kernel
nand write 30000000 kernel
3.4 修改支援yaffs檔案系統下載
修改smdk2440開啟天關巨集
/*支援yaffs檔案系統下載*/
#define CONFIG_CMD_NAND_YAFFS
追蹤程式碼cmd_nand.c 中的 nand_write_skip_bad函式
nand_write_skip_bad函式位於driver/mtd/nand/nand_util.c中
//ops.mode = MTD_OOB_AUTO;/*此處修改為MTD_OOB_RAW*/
ops.mode = MTD_OOB_RAW;
再修改
// if (!rval) /*此處寫錯了,根據韋東山視訊修改;這處是原始碼的錯誤*/
make distclean;make smdk2440_config;make
tftp 31000000 u-boot.bin ;protect off all ;erase 0 3ffff ;cp.b 31000000 0 40000
tftp 31000000 u-boot-last-yaffs.bin ;nand erase.part u-boot ;nand write 31000000 u-boot
3.5 製作補丁檔案和打補丁
make distclean
rm u-boot.dis -f
tar -xjf u-boot-2012.04.01.tar.bz2
製作補丁檔案
diff -urN u-boot-2012.04.01 my-uboot-2012.4.01_zhaigch > my-uboot-2012.4.01_zhaigch.patch
原始碼的uboot 修改過的uboot 重定向輸出到 補丁檔案
打補丁
cd u-boot-2012.04.01 進入原始碼資料夾下
patch -p1 < ../my-uboot-2012.4.01_zhaigch.patch
補丁共修改這以下這些檔案
patching file arch/arm/config.mk
patching file arch/arm/cpu/arm920t/start.S
patching file arch/arm/cpu/u-boot.lds
patching file arch/arm/include/asm/mach-types.h
patching file arch/arm/lib/board.c
patching file board/samsung/smdk2440/init.c
patching file board/samsung/smdk2440/lowlevel_init.S
patching file board/samsung/smdk2440/Makefile
patching file board/samsung/smdk2440/smdk2410.c
patching file boards.cfg
patching file common/cmd_bdinfo.c
patching file drivers/mtd/cfi_flash.c
patching file drivers/mtd/jedec_flash.c
patching file drivers/mtd/nand/Makefile
patching file drivers/mtd/nand/nand_base.c
patching file drivers/mtd/nand/nand_util.c
patching file drivers/mtd/nand/s3c2440_nand.c
patching file include/common.h
patching file include/configs/smdk2440.h
patching file arch/arm/config.mk
patching file arch/arm/cpu/arm920t/start.S
patching file arch/arm/cpu/u-boot.lds
patching file arch/arm/include/asm/mach-types.h
patching file arch/arm/lib/board.c
patching file board/samsung/smdk2440/init.c
patching file board/samsung/smdk2440/lowlevel_init.S
patching file board/samsung/smdk2440/Makefile
patching file board/samsung/smdk2440/smdk2410.c
patching file boards.cfg
patching file common/cmd_bdinfo.c
patching file drivers/mtd/cfi_flash.c
patching file drivers/mtd/jedec_flash.c
patching file drivers/mtd/nand/Makefile
patching file drivers/mtd/nand/nand_base.c
patching file drivers/mtd/nand/nand_util.c
patching file drivers/mtd/nand/s3c2440_nand.c
patching file include/common.h
patching file include/configs/smdk2440.h
4 關於機器碼machid
在以上的程式碼移植過程中,燒寫的uboot都要手動去設定 set machid 7cf
才能引導linux (因為我所用的linux識別的機器碼為mini2440 的1999:0x7cf)
後來找到問題的所在了:
在 board/samsung/smdk2440/smdk2410.c 中的 board_init 函式中對板子進行設定
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
修改為: /* MINI2440-Board 的機器碼在 arch/arm/include/asm/mach-types.h 檔案中定義*/
gd->bd->bi_arch_number = MACH_TYPE_MINI2440;