前言:這是本人在學習u-boot期間的初級移植筆記,故功能較簡陋、代碼較粗略,後續會有高級篇完善。
u-boot版本:1.1.6
交叉編譯器:3.4.5
開發板:友善之臂mini2440
開發板配置:SoC s3c2440 、網卡 DM9000 、 Nor Flash AM29LV160DB (2M) 、NAND FLash (256M) 、SDRAM (64M)
以源文件已存在的 smdk2410項目為基礎進行移植工作
1).下載u-boot-1.1.6源碼,並解壓;
2).建立u-boot的source insight工程,方便查找及分析;
3).安裝arm-Linux交叉編譯器,版本3.4.5;
1).打開 /Makefile ,找到smdk2410板配置選項:
smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
各項參數意義:
arm:CPU架構
arm920t:CPU型號
smdk2410:開發板名稱
NULL:開發者
s3c24x0:片上系統
類比此項添加配置選項:
mini2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t mini2440 NULL s3c24x0
1).找到 /board/smdk2410 目錄,將此目錄復制為 /board/mini2440 ,打開mini2440目錄,將smdk2410.c文件重命名為mini2440.c。打開同目錄下Makefile文件,修改代碼
COBJS := smdk2410.o flash.o
為
COBJS := mini2440.o flash.o
2).建立開發板配置頭文件。將 /include/configs/smdk2410.h 復制為 /include/configs/mini2440.h ,打開此文件,添加
#define CONFIG_S3C2440 1 /* in a SAMSUNG S3C2440 SoC */
1).將以上步驟建立的代碼編譯測試:
root@book-desktop:/home/book/Desktop/u-boot-1.1.6# make mini2440_config Configuring for mini2440 board... root@book-desktop:/home/book/Desktop/u-boot-1.1.6# make
生成u-boot.bin 下載至開發板運行,發現並未打印出任何信息。原因是2410和2440在頻率設置方面有所不同。
2). 打開 /board/mini2440/mini2440.c ,屏蔽下列代碼
#if 0 #define FCLK_SPEED 1 #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 #endif #define USB_CLOCK 1 #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 #endif #endif
然後修改board_init函數
int board_init (void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
clk_power->CLKDIVN = 0x05; /* 1 : 4 : 8 */
__asm__( "mrc p15,0,r1,c1,c0,0\n"
"orr r1,r1,#0xc0000000\n"
"mcr p15,0,r1,c1,c0,0\n"
:::"r1"
);//異步總線
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = ((0x5c << 12) + (0x01 << 4) + 0x01); //400MHz
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = ((0x38 << 12) + (0x02 << 4) + 0x02); //48MHz
/* some delay between MPLL and UPLL */
delay (8000);
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
gpio->GPBCON = 0x00044555;
gpio->GPBUP = 0x000007FF;
gpio->GPCCON = 0xAAAAAAAA;
gpio->GPCUP = 0x0000FFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0x0000FFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FFBA;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x002AFAAA;
gpio->GPHUP = 0x000007FF;
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
icache_enable();
dcache_enable();
return 0;
}
3).串口初始化時需要獲取系統時鐘,這裡修改 /cpu/arm920t/s3c24x0/speed.c ,
get_PLLCLK()中
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
改為
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
這是因為2410和2440主頻計算公式的差異。
其他修改:
/* return HCLK frequency */
ulong get_HCLK(void)
{
return(get_FCLK()/4 );
}
/* return PCLK frequency */
ulong get_PCLK(void)
{
return(get_HCLK()/2 );
}
再次進行編譯測試,出現打印信息:
打開 mini2440.h 頭文件,發現flash配置項只有CONFIG_AMD_LV400和CONFIG_AMD_LV800,沒有本型號,因為AM29lv160DB符合CFI接口標准,故使用 /drivers/cfi_flash.c 中的接口函數。進行下列修改:
1).屏蔽代碼/*----------------------------------------------------------------------- * FLASH and environment organization */ #if 0 #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ #endif增加宏定義
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */ #ifdef CONFIG_AMD_LV800 #define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ #define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */ #elif defined CONFIG_AMD_LV400 #define PHYS_FLASH_SIZE 0x00080000 /* 512KB */ #define CFG_MAX_FLASH_SECT (11) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x070000) /* addr of environment */ #else #define PHYS_FLASH_SIZE 0x00200000 /* 2MB */ #define CFG_MAX_FLASH_SECT (99) /* max number of sectors on one chip */ #define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x1F0000) /* addr of environment */ #endif2) 在 /board/mini2440/makefile 中COBJS := mini2440.o flash.o去掉flash.o ,再次編譯測試,出現錯誤:
Flash: 2 MB輸入命令 flinfo 得到信息:
smdk2410支持cs8900網卡,本開發板使用DM9000網卡,/drivers/dm9000x.c 是對應的網卡驅動。
1) 在mini2440.h中,將以下關於cs8900的宏注釋掉,並添加DM9000宏定義:
以此繼續增加宏定義:
2) 修改默認網絡參數,mini2440.h 中修改代碼:
#define CONFIG_NETMASK 255.255.255.0 #define CONFIG_IPADDR 192.168.31.111 #define CONFIG_SERVERIP 192.168.31.245
還有取消屏蔽:
SMDK2410 # ping 192.168.31.245 dm9000 。。。。。 host 192.168.31.245 is alive
至此,dm9000支持移植成功。
nand的驅動代碼在 /drivers/nand 目錄下面,打開此目錄下的nand.c文件,看到如下代碼
1) 在mini2440.h中的CONFIG_COMMANDS中加入宏定義 CFG_CMD_NAND
home/book/Desktop/u-boot-1.1.6/include/linux/mtd/nand.h:412: error: `NAND_MAX_CHIPS' undeclared here (not in a function)
在mini2440.h中添加以上宏定義:
/*NAND FLASH*/ #define CFG_MAX_NAND_DEVICE 1 #define CFG_NAND_BASE 0x0 #define NAND_MAX_CHIPS 1
三者分別表示:
nand設備數量;
nand基地址,無實際意義,在board_nand_init函數中會被重新指定;
每個nand設備有1個nand芯片;
再次編譯,出現錯誤為:
2) 實現board_nand_init函數。
在 /cpu/arm920t/s3c24x0/ 目錄下建立文件nand_flash.c,文件內容為:
/*
* Nand flash interface of s3c2410/s3c2440
*/
#include <common.h>
#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
#include <s3c2410.h>
#include <nand.h>
DECLARE_GLOBAL_DATA_PTR;
#define S3C2410_NFSTAT_READY (1<<0)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2440_NFSTAT_READY (1<<0)
#define S3C2440_NFCONT_nFCE (1<<1)
/* select chip, for s3c2410 */
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
if (chip == -1) {
s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
} else {
s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
}
}
/* command and control functions, for s3c2410
*
* Note, these all use tglx's method of changing the IO_ADDR_W field
* to make the code simpler, and use the nand layer's code to issue the
* command and address sequences via the proper IO ports.
*
*/
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
break;
}
}
/* s3c2410_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
*/
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
}
/* select chip, for s3c2440 */
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
if (chip == -1) {
s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
} else {
s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
}
}
/* command and control functions */
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
case NAND_CTL_CLRNCE:
printf("%s: called for NCE\n", __FUNCTION__);
break;
case NAND_CTL_SETCLE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
break;
}
}
/* s3c2440_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
*/
static int s3c2440_nand_devready(struct mtd_info *mtd)
{
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
}
/*
* Nand flash hardware initialization:
* Set the timing, enable NAND flash controller
*/
static void s3c24x0_nand_inithw(void)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
if (0)
{
/* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else
{
/* Set flash memory timing */
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* Initialize ECC, enable chip select, NAND flash controller enable */
s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
}
}
/*
* Called by drivers/nand/nand.c, initialize the interface of nand flash
*/
void board_nand_init(struct nand_chip *chip)
{
S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
s3c24x0_nand_inithw();
if (0) {
chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->select_chip = s3c2410_nand_select_chip;
chip->options = 0;
} else {
chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;
chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
chip->hwcontrol = s3c2440_nand_hwcontrol;
chip->dev_ready = s3c2440_nand_devready;
chip->select_chip = s3c2440_nand_select_chip;
chip->options = 0;
}
chip->eccmode = NAND_ECC_SOFT;
}
#endif
還要在 /include/s3c24x0.h文件中增加本文件中使用到的S3C2440_NAND數據結構,在s3c2410_nand的下面,
/* NAND FLASH (see S3C2410 manual chapter 6) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFECC;
} /*__attribute__((__packed__))*/ S3C2410_NAND;
增添2440nand的結構體:
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSBLK;
S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;
然後打開同目錄下的s3c2410.h,找到
static inline S3C2410_NAND * const S3C2410_GetBase_NAND(void)
{
return (S3C2410_NAND * const)S3C2410_NAND_BASE;
}
在其下面添加
static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
{
return (S3C2440_NAND * const)S3C2410_NAND_BASE;
}
最後將新建的nand_flash.c文件編入u-boot之中。打開 /cpu/arm920t/s3c24x0/Makefile ,在COBJS中增加nand_flash.o:
COBJS = i2c.o interrupts.o serial.o speed.o \ usb_ohci.o nand_flash.o
編譯,通過!下載至開發板運行,控制台打印出:NAND : 256MiB,輸入命令nand info,打印信息:
NAND 256MiB 3.3V 8-bit, sector size 128 KiB
至此,NAND flash支持移植成功!
U-Boot源代碼下載地址 http://www.linuxidc.com/Linux/2011-07/38897.htm