前言:這是本人在學習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.移植准備工作
1).下載u-boot-1.1.6源碼,並解壓;
2).建立u-boot的source insight工程,方便查找及分析;
3).安裝arm-Linux交叉編譯器,版本3.4.5;
2.修改頂層Makefile
1).打開 /Makefile ,找到smdk2410板配置選項:
- smdk2410_config : unconfig
- @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
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
mini2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t mini2440 NULL s3c24x0
3.建立主代碼
1).找到 /board/smdk2410 目錄,將此目錄復制為 /board/mini2440 ,打開mini2440目錄,將smdk2410.c文件重命名為mini2440.c。打開同目錄下Makefile文件,修改代碼
- COBJS := smdk2410.o flash.o
COBJS := smdk2410.o flash.o
為
- COBJS := mini2440.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 */
#define CONFIG_S3C2440 1 /* in a SAMSUNG S3C2440 SoC */
4.修改CPU頻率設置
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
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
#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;
- }
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) / (p << s));
改為
- return((CONFIG_SYS_CLK_FREQ * m * 2) / (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 );
- }
/* return HCLK frequency */
ulong get_HCLK(void)
{
return(get_FCLK()/4 );
}
/* return PCLK frequency */
ulong get_PCLK(void)
{
return(get_HCLK()/2 );
}
再次進行編譯測試,出現打印信息:
- U-Boot 1.1.6 (Jan 26 2017 - 17:10:05)
-
- DRAM: 64 MB
- Flash: 512 kB
- *** Warning - bad CRC, using default environment
-
- In: serial
- Out: serial
- Err: serial
- SMDK2410 #
5.支持Nor Flash AM29lv160DB
打開 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
/*-----------------------------------------------------------------------
* 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_FLASH_CFI_DRIVER 1
修改代碼
- #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 */
- #endif
- #ifdef 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 */
- #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 */
- #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 */
#endif
2) 在 /board/mini2440/makefile 中COBJS := mini2440.o flash.o去掉flash.o ,再次編譯測試,出現錯誤:
- cfi_flash.c:411: error: `CFG_MONITOR_BASE' undeclared (first use in this function)
在mini2440.h中加入宏定義
- #define CFG_MONITOR_BASE 0
- #define CFG_FLASH_CFI 1
再次編譯,通過!燒寫至開發板,打印出信息:
- Flash: 2 MB
Flash: 2 MB
輸入命令 flinfo
得到信息:
- SMDK2410 # flinfo
-
- Bank # 1: CFI conformant FLASH (16 x 16) Size: 2 MB in 35 Sectors
- Erase timeout 8192 ms, write timeout 1 ms, buffer write timeout 1 ms, buffer size 1
- Sector Start Addresses:
- 00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO)
- 00020000 00030000 00040000 00050000 00060000
- 00070000 00080000 00090000 000A0000 000B0000
- 000C0000 000D0000 000E0000 000F0000 00100000
- 00110000 00120000 00130000 00140000 00150000
- 00160000 00170000 00180000 00190000 001A0000
- 001B0000 001C0000 001D0000 001E0000 001F0000 (RO)
- SMDK2410 #
至此nor flash支持移植成功。
6.支持DM9000網卡
smdk2410支持cs8900網卡,本開發板使用DM9000網卡,/drivers/dm9000x.c 是對應的網卡驅動。
1) 在mini2440.h中,將以下關於cs8900的宏注釋掉,並添加DM9000宏定義:
- /*
- * Hardware drivers
- */
- #if 0
- #define CONFIG_DRIVER_CS8900 1 /* we have a CS8900 on-board */
- #define CS8900_BASE 0x19000300
- #define CS8900_BUS16 1 /* the Linux driver does accesses as shorts */
- #endif
- #define CONFIG_DRIVER_DM9000 1
編譯,出現錯誤提示:
- dm9000x.c:374: error: `DM9000_IO' undeclared (first use in this function)
- dm9000x.c:445: error: `DM9000_DATA' undeclared (first use in this function)
- dm9000x.c:144: error: `CONFIG_DM9000_BASE' undeclared
以此繼續增加宏定義:
- #define CONFIG_DM9000_BASE 0x20000000
- #define DM9000_IO 0x20000000
- #define DM9000_DATA (DM9000_IO + 0x4)
- #define CONFIG_DM9000_USE_16BIT 1
查看原理圖可得本開發板網卡片選線接在BANK4,故基地址為0x20000000,IO為基地址,DATA與基地址偏移0x04,此外定義16BIT表示網卡使用16BIT模式。
2) 修改默認網絡參數,mini2440.h 中修改代碼:
- #define CONFIG_NETMASK 255.255.255.0
- #define CONFIG_IPADDR 192.168.31.111
- #define CONFIG_SERVERIP 192.168.31.245
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.31.111
#define CONFIG_SERVERIP 192.168.31.245
還有取消屏蔽:
- #define CONFIG_ETHADDR 08:00:3e:26:0a:5b
再次編譯,通過!下載至開發板,運行測試ping和tftp命令:發現ping無效,tftp可用。原因是未添加PING命令宏定義,故在mini2440.h中添加相關宏:
- #define CONFIG_COMMANDS \
- (CONFIG_CMD_DFL | \
- CFG_CMD_CACHE | \
- /*CFG_CMD_NAND |*/ \
- /*CFG_CMD_EEPROM |*/ \
- /*CFG_CMD_I2C |*/ \
- /*CFG_CMD_USB |*/ \
- CFG_CMD_REGINFO | \
- CFG_CMD_DATE | \
- CFG_CMD_PING | \
再次測試,得到打印結果:
- SMDK2410 # ping 192.168.31.245
- dm9000 。。。。。
- host 192.168.31.245 is alive
SMDK2410 # ping 192.168.31.245
dm9000 。。。。。
host 192.168.31.245 is alive
至此,dm9000支持移植成功。
7.支持NAND FLASH
nand的驅動代碼在 /drivers/nand 目錄下面,打開此目錄下的nand.c文件,看到如下代碼
- #include <common.h>
-
- #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
-
- #include <nand.h>
所以判斷使用nand驅動的宏開關為CFG_CMD_NAND。
1) 在mini2440.h中的CONFIG_COMMANDS中加入宏定義 CFG_CMD_NAND
- #define CONFIG_COMMANDS \
- (CONFIG_CMD_DFL | \
- CFG_CMD_CACHE | \
- CFG_CMD_NAND | \
- /*CFG_CMD_EEPROM |*/ \
- /*CFG_CMD_I2C |*/ \
然後啟動編譯,錯誤如下:
- nand.c:35: error: `CFG_MAX_NAND_DEVICE' undeclared here (not in a function)
- nand.c:38: error: `CFG_NAND_BASE' undeclared here (not in a function)
- home/book/Desktop/u-boot-1.1.6/include/linux/mtd/nand.h:412: error: `NAND_MAX_CHIPS' undeclared here (not in a function)
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 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芯片;
再次編譯,出現錯誤為:
- drivers/nand/libnand.a(nand.o)(.text+0x24): In function `nand_init':
- /home/book/Desktop/u-boot-1.1.6/drivers/nand/nand.c:50: undefined reference to `board_nand_init'
意思是board_nand_init函數未定義。上電後nand的初始化過程為:start_armboot函數調用nand_init,nand_init函數在 /drivers/nand/nand.c中實現,nand_init函數調用同文件中nand_init_chip函數,nand_init_chip函數會首先調用board_nand_init函數來初始化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
/*
* 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;
/* 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;
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 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;
- }
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
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 256MiB 3.3V 8-bit, sector size 128 KiB
至此,NAND flash支持移植成功!
U-Boot源代碼下載地址 http://www.linuxidc.com/Linux/2011-07/38897.htm