歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

u-boot-1.1.6移植筆記(初級篇)

前言:這是本人在學習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板配置選項:

  1. smdk2410_config :   unconfig 
  2.     @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 
smdk2410_config	:	unconfig
	@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

各項參數意義:

    arm:CPU架構

     arm920t:CPU型號

    smdk2410:開發板名稱

    NULL:開發者

    s3c24x0:片上系統

類比此項添加配置選項:

  1. mini2440_config :   unconfig 
  2.     @$(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文件,修改代碼

  1. COBJS   := smdk2410.o flash.o 
COBJS	:= smdk2410.o flash.o

  1. COBJS   := mini2440.o flash.o 
COBJS	:= mini2440.o flash.o

2).建立開發板配置頭文件。將 /include/configs/smdk2410.h 復制為 /include/configs/mini2440.h ,打開此文件,添加

  1. #define CONFIG_S3C2440      1   /* in a SAMSUNG S3C2440 SoC     */ 
#define	CONFIG_S3C2440		1	/* in a SAMSUNG S3C2440 SoC     */


4.修改CPU頻率設置

1).將以上步驟建立的代碼編譯測試:

  1. root@book-desktop:/home/book/Desktop/u-boot-1.1.6# make mini2440_config 
  2. Configuring for mini2440 board... 
  3. 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 ,屏蔽下列代碼

  1. #if 0 
  2. #define FCLK_SPEED 1 
  3.  
  4. #if FCLK_SPEED==0       /* Fout = 203MHz, Fin = 12MHz for Audio */ 
  5. #define M_MDIV  0xC3 
  6. #define M_PDIV  0x4 
  7. #define M_SDIV  0x1 
  8. #elif FCLK_SPEED==1     /* Fout = 202.8MHz */ 
  9. #define M_MDIV  0xA1 
  10. #define M_PDIV  0x3 
  11. #define M_SDIV  0x1 
  12. #endif 
  13.  
  14. #define USB_CLOCK 1 
  15.  
  16. #if USB_CLOCK==0 
  17. #define U_M_MDIV    0xA1 
  18. #define U_M_PDIV    0x3 
  19. #define U_M_SDIV    0x1 
  20. #elif USB_CLOCK==1 
  21. #define U_M_MDIV    0x48 
  22. #define U_M_PDIV    0x3 
  23. #define U_M_SDIV    0x2 
  24. #endif 
  25. #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函數

  1. int board_init (void) 
  2.     S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); 
  3.     S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); 
  4.      
  5.     clk_power->CLKDIVN = 0x05; /* 1 : 4 : 8 */ 
  6.      
  7.     __asm__(    "mrc    p15,0,r1,c1,c0,0\n" 
  8.                 "orr    r1,r1,#0xc0000000\n" 
  9.                 "mcr    p15,0,r1,c1,c0,0\n" 
  10.                 :::"r1" 
  11.                 );//異步總線 
  12.      
  13.     /* to reduce PLL lock time, adjust the LOCKTIME register */ 
  14.     clk_power->LOCKTIME = 0xFFFFFF; 
  15.  
  16.     /* configure MPLL */ 
  17.     clk_power->MPLLCON = ((0x5c << 12) + (0x01 << 4) + 0x01); //400MHz 
  18.  
  19.     /* some delay between MPLL and UPLL */ 
  20.     delay (4000); 
  21.  
  22.     /* configure UPLL */ 
  23.     clk_power->UPLLCON = ((0x38 << 12) + (0x02 << 4) + 0x02); //48MHz 
  24.  
  25.     /* some delay between MPLL and UPLL */ 
  26.     delay (8000); 
  27.  
  28.     /* set up the I/O ports */ 
  29.     gpio->GPACON = 0x007FFFFF; 
  30.     gpio->GPBCON = 0x00044555; 
  31.     gpio->GPBUP = 0x000007FF; 
  32.     gpio->GPCCON = 0xAAAAAAAA; 
  33.     gpio->GPCUP = 0x0000FFFF; 
  34.     gpio->GPDCON = 0xAAAAAAAA; 
  35.     gpio->GPDUP = 0x0000FFFF; 
  36.     gpio->GPECON = 0xAAAAAAAA; 
  37.     gpio->GPEUP = 0x0000FFFF; 
  38.     gpio->GPFCON = 0x000055AA; 
  39.     gpio->GPFUP = 0x000000FF; 
  40.     gpio->GPGCON = 0xFF95FFBA; 
  41.     gpio->GPGUP = 0x0000FFFF; 
  42.     gpio->GPHCON = 0x002AFAAA; 
  43.     gpio->GPHUP = 0x000007FF; 
  44.  
  45.     /* arch number of SMDK2410-Board */ 
  46.     gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; 
  47.  
  48.     /* adress of boot parameters */ 
  49.     gd->bd->bi_boot_params = 0x30000100; 
  50.  
  51.     icache_enable(); 
  52.     dcache_enable(); 
  53.  
  54.     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()中

  1. return((CONFIG_SYS_CLK_FREQ * m) / (p << s)); 
    return((CONFIG_SYS_CLK_FREQ * m) / (p << s));

改為

  1. return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s)); 
    return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));

這是因為2410和2440主頻計算公式的差異。
其他修改:

  1. /* return HCLK frequency */ 
  2. ulong get_HCLK(void) 
  3.     return(get_FCLK()/4 ); 
  4.  
  5. /* return PCLK frequency */ 
  6. ulong get_PCLK(void) 
  7.     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 );
}

再次進行編譯測試,出現打印信息:

  1. U-Boot 1.1.6 (Jan 26 2017 - 17:10:05) 
  2.  
  3. DRAM:  64 MB 
  4. Flash: 512 kB 
  5. *** Warning - bad CRC, using default environment 
  6.  
  7. In:    serial 
  8. Out:   serial 
  9. Err:   serial 
  10. SMDK2410 #


5.支持Nor Flash AM29lv160DB

打開 mini2440.h 頭文件,發現flash配置項只有CONFIG_AMD_LV400和CONFIG_AMD_LV800,沒有本型號,因為AM29lv160DB符合CFI接口標准,故使用 /drivers/cfi_flash.c 中的接口函數。進行下列修改:

1).屏蔽代碼
  1. /*----------------------------------------------------------------------- 
  2.  * FLASH and environment organization 
  3.  */ 
  4. #if 0 
  5. #define CONFIG_AMD_LV400    1   /* uncomment this if you have a LV400 flash */ 
  6. #define CONFIG_AMD_LV800    1   /* uncomment this if you have a LV800 flash */ 
  7. #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
增加宏定義
  1. #define CFG_FLASH_CFI_DRIVER    1
修改代碼
  1. #define CFG_MAX_FLASH_BANKS 1   /* max number of memory banks */ 
  2. #ifdef CONFIG_AMD_LV800 
  3. #define PHYS_FLASH_SIZE     0x00100000 /* 1MB */ 
  4. #define CFG_MAX_FLASH_SECT  (19)    /* max number of sectors on one chip */ 
  5. #define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */ 
  6. #endif 
  7. #ifdef CONFIG_AMD_LV400 
  8. #define PHYS_FLASH_SIZE     0x00080000 /* 512KB */ 
  9. #define CFG_MAX_FLASH_SECT  (11)    /* max number of sectors on one chip */ 
  10. #define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x070000) /* addr of environment */ 
  11. #endif
  1. #define CFG_MAX_FLASH_BANKS 1   /* max number of memory banks */ 
  2. #ifdef CONFIG_AMD_LV800 
  3. #define PHYS_FLASH_SIZE     0x00100000 /* 1MB */ 
  4. #define CFG_MAX_FLASH_SECT  (19)    /* max number of sectors on one chip */ 
  5. #define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */ 
  6. #elif   defined CONFIG_AMD_LV400 
  7. #define PHYS_FLASH_SIZE     0x00080000 /* 512KB */ 
  8. #define CFG_MAX_FLASH_SECT  (11)    /* max number of sectors on one chip */ 
  9. #define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x070000) /* addr of environment */ 
  10. #else 
  11. #define PHYS_FLASH_SIZE     0x00200000 /* 2MB */ 
  12. #define CFG_MAX_FLASH_SECT  (99)    /* max number of sectors on one chip */ 
  13. #define CFG_ENV_ADDR        (CFG_FLASH_BASE + 0x1F0000) /* addr of environment */ 
  14. #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 ,再次編譯測試,出現錯誤:
  1. cfi_flash.c:411: error: `CFG_MONITOR_BASE' undeclared (first use in this function) 
在mini2440.h中加入宏定義
  1. #define CFG_MONITOR_BASE    0 
  1. #define CFG_FLASH_CFI   1 
再次編譯,通過!燒寫至開發板,打印出信息:
  1. Flash:  2 MB
Flash:  2 MB
輸入命令 flinfo 得到信息:
  1. SMDK2410 # flinfo 
  2.  
  3. Bank # 1: CFI conformant FLASH (16 x 16)  Size: 2 MB in 35 Sectors 
  4.  Erase timeout 8192 ms, write timeout 1 ms, buffer write timeout 1 ms, buffer size 1 
  5.   Sector Start Addresses: 
  6.     00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO) 
  7.     00020000      00030000      00040000      00050000      00060000       
  8.     00070000      00080000      00090000      000A0000      000B0000       
  9.     000C0000      000D0000      000E0000      000F0000      00100000       
  10.     00110000      00120000      00130000      00140000      00150000       
  11.     00160000      00170000      00180000      00190000      001A0000       
  12.     001B0000      001C0000      001D0000      001E0000      001F0000 (RO) 
  13. SMDK2410 #
至此nor flash支持移植成功。

6.支持DM9000網卡

smdk2410支持cs8900網卡,本開發板使用DM9000網卡,/drivers/dm9000x.c 是對應的網卡驅動。

1) 在mini2440.h中,將以下關於cs8900的宏注釋掉,並添加DM9000宏定義:

  1. /* 
  2.  * Hardware drivers 
  3.  */ 
  4. #if 0 
  5. #define CONFIG_DRIVER_CS8900    1   /* we have a CS8900 on-board */ 
  6. #define CS8900_BASE     0x19000300 
  7. #define CS8900_BUS16        1 /* the Linux driver does accesses as shorts */ 
  8. #endif 
  9. #define CONFIG_DRIVER_DM9000    1
    編譯,出現錯誤提示:
  1. dm9000x.c:374: error: `DM9000_IO' undeclared (first use in this function) 
  1. dm9000x.c:445: error: `DM9000_DATA' undeclared (first use in this function) 
  2. dm9000x.c:144: error: `CONFIG_DM9000_BASE' undeclared

以此繼續增加宏定義:

  1. #define CONFIG_DM9000_BASE      0x20000000 
  2. #define DM9000_IO               0x20000000 
  3. #define DM9000_DATA             (DM9000_IO + 0x4) 
  4. #define CONFIG_DM9000_USE_16BIT 1 
查看原理圖可得本開發板網卡片選線接在BANK4,故基地址為0x20000000,IO為基地址,DATA與基地址偏移0x04,此外定義16BIT表示網卡使用16BIT模式。

2) 修改默認網絡參數,mini2440.h 中修改代碼:

  1. #define CONFIG_NETMASK          255.255.255.0 
  2. #define CONFIG_IPADDR       192.168.31.111 
  3. #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

還有取消屏蔽:

  1. #define CONFIG_ETHADDR  08:00:3e:26:0a:5b 
再次編譯,通過!下載至開發板,運行測試ping和tftp命令:發現ping無效,tftp可用。原因是未添加PING命令宏定義,故在mini2440.h中添加相關宏:
  1. #define CONFIG_COMMANDS \ 
  2.             (CONFIG_CMD_DFL  | \ 
  3.             CFG_CMD_CACHE    | \ 
  4.             /*CFG_CMD_NAND   |*/ \ 
  5.             /*CFG_CMD_EEPROM |*/ \ 
  6.             /*CFG_CMD_I2C    |*/ \ 
  7.             /*CFG_CMD_USB    |*/ \ 
  8.             CFG_CMD_REGINFO  | \ 
  9.             CFG_CMD_DATE     | \ 
  10.             CFG_CMD_PING     | \ 
再次測試,得到打印結果:
  1. SMDK2410 # ping 192.168.31.245 
  2. dm9000 。。。。。 
  3. 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文件,看到如下代碼

  1. #include <common.h> 
  2.  
  3. #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) 
  4.  
  5. #include <nand.h> 
所以判斷使用nand驅動的宏開關為CFG_CMD_NAND。

1) 在mini2440.h中的CONFIG_COMMANDS中加入宏定義 CFG_CMD_NAND

  1. #define CONFIG_COMMANDS \ 
  2.             (CONFIG_CMD_DFL  | \ 
  3.             CFG_CMD_CACHE    | \ 
  4.             CFG_CMD_NAND     | \ 
  5.             /*CFG_CMD_EEPROM |*/ \ 
  6.             /*CFG_CMD_I2C    |*/ \ 
然後啟動編譯,錯誤如下:
  1. nand.c:35: error: `CFG_MAX_NAND_DEVICE' undeclared here (not in a function) 
  2. nand.c:38: error: `CFG_NAND_BASE' undeclared here (not in a function) 
  1. 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中添加以上宏定義:

  1. /*NAND FLASH*/ 
  2. #define CFG_MAX_NAND_DEVICE 1 
  3. #define CFG_NAND_BASE       0x0 
  4. #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芯片;

再次編譯,出現錯誤為:

  1. drivers/nand/libnand.a(nand.o)(.text+0x24): In function `nand_init': 
  2. /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,文件內容為:

  1. /* 
  2.  * Nand flash interface of s3c2410/s3c2440 
  3.  */ 
  4.  
  5. #include <common.h> 
  6.  
  7. #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) 
  8. #include <s3c2410.h> 
  9. #include <nand.h> 
  10.  
  11. DECLARE_GLOBAL_DATA_PTR; 
  12.  
  13. #define S3C2410_NFSTAT_READY    (1<<0) 
  14. #define S3C2410_NFCONF_nFCE     (1<<11) 
  15.  
  16. #define S3C2440_NFSTAT_READY    (1<<0) 
  17. #define S3C2440_NFCONT_nFCE     (1<<1) 
  18.  
  19.  
  20. /* select chip, for s3c2410 */ 
  21. static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) 
  22.     S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND(); 
  23.  
  24.     if (chip == -1) { 
  25.         s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE; 
  26.     } else { 
  27.         s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE; 
  28.     } 
  29.  
  30. /* command and control functions, for s3c2410  
  31.  * 
  32.  * Note, these all use tglx's method of changing the IO_ADDR_W field 
  33.  * to make the code simpler, and use the nand layer's code to issue the 
  34.  * command and address sequences via the proper IO ports. 
  35.  * 
  36. */ 
  37. static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) 
  38.     S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND(); 
  39.     struct nand_chip *chip = mtd->priv; 
  40.  
  41.     switch (cmd) { 
  42.     case NAND_CTL_SETNCE: 
  43.     case NAND_CTL_CLRNCE: 
  44.         printf("%s: called for NCE\n", __FUNCTION__); 
  45.         break; 
  46.  
  47.     case NAND_CTL_SETCLE: 
  48.         chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD; 
  49.         break; 
  50.  
  51.     case NAND_CTL_SETALE: 
  52.         chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR; 
  53.         break; 
  54.  
  55.         /* NAND_CTL_CLRCLE: */ 
  56.         /* NAND_CTL_CLRALE: */ 
  57.     default: 
  58.         chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA; 
  59.         break; 
  60.     } 
  61.  
  62. /* s3c2410_nand_devready() 
  63.  * 
  64.  * returns 0 if the nand is busy, 1 if it is ready 
  65.  */ 
  66. static int s3c2410_nand_devready(struct mtd_info *mtd) 
  67.     S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND(); 
  68.  
  69.     return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY); 
  70.  
  71.  
  72. /* select chip, for s3c2440 */ 
  73. static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip) 
  74.     S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND(); 
  75.  
  76.     if (chip == -1) { 
  77.         s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE; 
  78.     } else { 
  79.         s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE; 
  80.     } 
  81.  
  82. /* command and control functions */ 
  83. static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) 
  84.     S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND(); 
  85.     struct nand_chip *chip = mtd->priv; 
  86.  
  87.     switch (cmd) { 
  88.     case NAND_CTL_SETNCE: 
  89.     case NAND_CTL_CLRNCE: 
  90.         printf("%s: called for NCE\n", __FUNCTION__); 
  91.         break; 
  92.  
  93.     case NAND_CTL_SETCLE: 
  94.         chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD; 
  95.         break; 
  96.  
  97.     case NAND_CTL_SETALE: 
  98.         chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR; 
  99.         break; 
  100.  
  101.         /* NAND_CTL_CLRCLE: */ 
  102.         /* NAND_CTL_CLRALE: */ 
  103.     default: 
  104.         chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA; 
  105.         break; 
  106.     } 
  107.  
  108. /* s3c2440_nand_devready() 
  109.  * 
  110.  * returns 0 if the nand is busy, 1 if it is ready 
  111.  */ 
  112. static int s3c2440_nand_devready(struct mtd_info *mtd) 
  113.     S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND(); 
  114.  
  115.     return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY); 
  116.  
  117. /* 
  118.  * Nand flash hardware initialization: 
  119.  * Set the timing, enable NAND flash controller 
  120.  */ 
  121. static void s3c24x0_nand_inithw(void) 
  122.     S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND(); 
  123.     S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND(); 
  124.  
  125. #define TACLS   0 
  126. #define TWRPH0  4 
  127. #define TWRPH1  2 
  128.  
  129.     if (0) 
  130.     { 
  131.         /* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */ 
  132.         s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); 
  133.     } 
  134.     else 
  135.     { 
  136.         /* Set flash memory timing */ 
  137.         s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); 
  138.         /* Initialize ECC, enable chip select, NAND flash controller enable */ 
  139.         s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0); 
  140.     } 
  141.  
  142. /* 
  143.  * Called by drivers/nand/nand.c, initialize the interface of nand flash 
  144.  */ 
  145. void board_nand_init(struct nand_chip *chip) 
  146.     S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND(); 
  147.     S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND(); 
  148.  
  149.     s3c24x0_nand_inithw(); 
  150.  
  151.     if (0) { 
  152.         chip->IO_ADDR_R    = (void *)&s3c2410nand->NFDATA; 
  153.         chip->IO_ADDR_W    = (void *)&s3c2410nand->NFDATA; 
  154.         chip->hwcontrol    = s3c2410_nand_hwcontrol; 
  155.         chip->dev_ready    = s3c2410_nand_devready; 
  156.         chip->select_chip  = s3c2410_nand_select_chip; 
  157.         chip->options      = 0; 
  158.     } else { 
  159.         chip->IO_ADDR_R    = (void *)&s3c2440nand->NFDATA; 
  160.         chip->IO_ADDR_W    = (void *)&s3c2440nand->NFDATA; 
  161.         chip->hwcontrol    = s3c2440_nand_hwcontrol; 
  162.         chip->dev_ready    = s3c2440_nand_devready; 
  163.         chip->select_chip  = s3c2440_nand_select_chip; 
  164.         chip->options      = 0; 
  165.     } 
  166.  
  167.     chip->eccmode       = NAND_ECC_SOFT; 
  168.  
  169. #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的下面,

  1. /* NAND FLASH (see S3C2410 manual chapter 6) */ 
  2. typedef struct { 
  3.     S3C24X0_REG32   NFCONF; 
  4.     S3C24X0_REG32   NFCMD; 
  5.     S3C24X0_REG32   NFADDR; 
  6.     S3C24X0_REG32   NFDATA; 
  7.     S3C24X0_REG32   NFSTAT; 
  8.     S3C24X0_REG32   NFECC; 
  9. } /*__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的結構體:

  1. typedef struct { 
  2.     S3C24X0_REG32   NFCONF; 
  3.     S3C24X0_REG32   NFCONT; 
  4.     S3C24X0_REG32   NFCMD; 
  5.     S3C24X0_REG32   NFADDR; 
  6.     S3C24X0_REG32   NFDATA; 
  7.     S3C24X0_REG32   NFMECCD0; 
  8.     S3C24X0_REG32   NFMECCD1; 
  9.     S3C24X0_REG32   NFSECCD; 
  10.     S3C24X0_REG32   NFSTAT; 
  11.     S3C24X0_REG32   NFESTAT0; 
  12.     S3C24X0_REG32   NFESTAT1; 
  13.     S3C24X0_REG32   NFMECC0; 
  14.     S3C24X0_REG32   NFMECC1; 
  15.     S3C24X0_REG32   NFSECC; 
  16.     S3C24X0_REG32   NFSBLK; 
  17.     S3C24X0_REG32   NFEBLK; 
  18. } /*__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,找到

  1. static inline S3C2410_NAND * const S3C2410_GetBase_NAND(void) 
  2.     return (S3C2410_NAND * const)S3C2410_NAND_BASE; 
static inline S3C2410_NAND * const S3C2410_GetBase_NAND(void)
{
	return (S3C2410_NAND * const)S3C2410_NAND_BASE;
}

在其下面添加

  1. static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void) 
  2.     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:

  1. COBJS   = i2c.o interrupts.o serial.o speed.o \ 
  2.       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,打印信息:

  1. 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

Copyright © Linux教程網 All Rights Reserved