歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> u-boot-1.1.6移植筆記(初級篇)

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

日期:2017/3/1 9:06:02   编辑:Linux編程

前言:這是本人在學習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. #if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
  4. #define M_MDIV 0xC3
  5. #define M_PDIV 0x4
  6. #define M_SDIV 0x1
  7. #elif FCLK_SPEED==1 /* Fout = 202.8MHz */
  8. #define M_MDIV 0xA1
  9. #define M_PDIV 0x3
  10. #define M_SDIV 0x1
  11. #endif
  12. #define USB_CLOCK 1
  13. #if USB_CLOCK==0
  14. #define U_M_MDIV 0xA1
  15. #define U_M_PDIV 0x3
  16. #define U_M_SDIV 0x1
  17. #elif USB_CLOCK==1
  18. #define U_M_MDIV 0x48
  19. #define U_M_PDIV 0x3
  20. #define U_M_SDIV 0x2
  21. #endif
  22. #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. {
  3. S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
  4. S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
  5. clk_power->CLKDIVN = 0x05; /* 1 : 4 : 8 */
  6. __asm__( "mrc p15,0,r1,c1,c0,0\n"
  7. "orr r1,r1,#0xc0000000\n"
  8. "mcr p15,0,r1,c1,c0,0\n"
  9. :::"r1"
  10. );//異步總線
  11. /* to reduce PLL lock time, adjust the LOCKTIME register */
  12. clk_power->LOCKTIME = 0xFFFFFF;
  13. /* configure MPLL */
  14. clk_power->MPLLCON = ((0x5c << 12) + (0x01 << 4) + 0x01); //400MHz
  15. /* some delay between MPLL and UPLL */
  16. delay (4000);
  17. /* configure UPLL */
  18. clk_power->UPLLCON = ((0x38 << 12) + (0x02 << 4) + 0x02); //48MHz
  19. /* some delay between MPLL and UPLL */
  20. delay (8000);
  21. /* set up the I/O ports */
  22. gpio->GPACON = 0x007FFFFF;
  23. gpio->GPBCON = 0x00044555;
  24. gpio->GPBUP = 0x000007FF;
  25. gpio->GPCCON = 0xAAAAAAAA;
  26. gpio->GPCUP = 0x0000FFFF;
  27. gpio->GPDCON = 0xAAAAAAAA;
  28. gpio->GPDUP = 0x0000FFFF;
  29. gpio->GPECON = 0xAAAAAAAA;
  30. gpio->GPEUP = 0x0000FFFF;
  31. gpio->GPFCON = 0x000055AA;
  32. gpio->GPFUP = 0x000000FF;
  33. gpio->GPGCON = 0xFF95FFBA;
  34. gpio->GPGUP = 0x0000FFFF;
  35. gpio->GPHCON = 0x002AFAAA;
  36. gpio->GPHUP = 0x000007FF;
  37. /* arch number of SMDK2410-Board */
  38. gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
  39. /* adress of boot parameters */
  40. gd->bd->bi_boot_params = 0x30000100;
  41. icache_enable();
  42. dcache_enable();
  43. return 0;
  44. }
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. {
  4. return(get_FCLK()/4 );
  5. }
  6. /* return PCLK frequency */
  7. ulong get_PCLK(void)
  8. {
  9. return(get_HCLK()/2 );
  10. }
/* 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. DRAM: 64 MB
  3. Flash: 512 kB
  4. *** Warning - bad CRC, using default environment
  5. In: serial
  6. Out: serial
  7. Err: serial
  8. 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. Bank # 1: CFI conformant FLASH (16 x 16) Size: 2 MB in 35 Sectors
  3. Erase timeout 8192 ms, write timeout 1 ms, buffer write timeout 1 ms, buffer size 1
  4. Sector Start Addresses:
  5. 00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO)
  6. 00020000 00030000 00040000 00050000 00060000
  7. 00070000 00080000 00090000 000A0000 000B0000
  8. 000C0000 000D0000 000E0000 000F0000 00100000
  9. 00110000 00120000 00130000 00140000 00150000
  10. 00160000 00170000 00180000 00190000 001A0000
  11. 001B0000 001C0000 001D0000 001E0000 001F0000 (RO)
  12. 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. #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
  3. #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. #include <common.h>
  5. #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
  6. #include <s3c2410.h>
  7. #include <nand.h>
  8. DECLARE_GLOBAL_DATA_PTR;
  9. #define S3C2410_NFSTAT_READY (1<<0)
  10. #define S3C2410_NFCONF_nFCE (1<<11)
  11. #define S3C2440_NFSTAT_READY (1<<0)
  12. #define S3C2440_NFCONT_nFCE (1<<1)
  13. /* select chip, for s3c2410 */
  14. static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
  15. {
  16. S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
  17. if (chip == -1) {
  18. s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;
  19. } else {
  20. s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;
  21. }
  22. }
  23. /* command and control functions, for s3c2410
  24. *
  25. * Note, these all use tglx's method of changing the IO_ADDR_W field
  26. * to make the code simpler, and use the nand layer's code to issue the
  27. * command and address sequences via the proper IO ports.
  28. *
  29. */
  30. static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
  31. {
  32. S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
  33. struct nand_chip *chip = mtd->priv;
  34. switch (cmd) {
  35. case NAND_CTL_SETNCE:
  36. case NAND_CTL_CLRNCE:
  37. printf("%s: called for NCE\n", __FUNCTION__);
  38. break;
  39. case NAND_CTL_SETCLE:
  40. chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;
  41. break;
  42. case NAND_CTL_SETALE:
  43. chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;
  44. break;
  45. /* NAND_CTL_CLRCLE: */
  46. /* NAND_CTL_CLRALE: */
  47. default:
  48. chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
  49. break;
  50. }
  51. }
  52. /* s3c2410_nand_devready()
  53. *
  54. * returns 0 if the nand is busy, 1 if it is ready
  55. */
  56. static int s3c2410_nand_devready(struct mtd_info *mtd)
  57. {
  58. S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
  59. return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);
  60. }
  61. /* select chip, for s3c2440 */
  62. static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)
  63. {
  64. S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
  65. if (chip == -1) {
  66. s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;
  67. } else {
  68. s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;
  69. }
  70. }
  71. /* command and control functions */
  72. static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
  73. {
  74. S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
  75. struct nand_chip *chip = mtd->priv;
  76. switch (cmd) {
  77. case NAND_CTL_SETNCE:
  78. case NAND_CTL_CLRNCE:
  79. printf("%s: called for NCE\n", __FUNCTION__);
  80. break;
  81. case NAND_CTL_SETCLE:
  82. chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;
  83. break;
  84. case NAND_CTL_SETALE:
  85. chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;
  86. break;
  87. /* NAND_CTL_CLRCLE: */
  88. /* NAND_CTL_CLRALE: */
  89. default:
  90. chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
  91. break;
  92. }
  93. }
  94. /* s3c2440_nand_devready()
  95. *
  96. * returns 0 if the nand is busy, 1 if it is ready
  97. */
  98. static int s3c2440_nand_devready(struct mtd_info *mtd)
  99. {
  100. S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
  101. return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);
  102. }
  103. /*
  104. * Nand flash hardware initialization:
  105. * Set the timing, enable NAND flash controller
  106. */
  107. static void s3c24x0_nand_inithw(void)
  108. {
  109. S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
  110. S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
  111. #define TACLS 0
  112. #define TWRPH0 4
  113. #define TWRPH1 2
  114. if (0)
  115. {
  116. /* Enable NAND flash controller, Initialize ECC, enable chip select, Set flash memory timing */
  117. s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
  118. }
  119. else
  120. {
  121. /* Set flash memory timing */
  122. s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
  123. /* Initialize ECC, enable chip select, NAND flash controller enable */
  124. s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);
  125. }
  126. }
  127. /*
  128. * Called by drivers/nand/nand.c, initialize the interface of nand flash
  129. */
  130. void board_nand_init(struct nand_chip *chip)
  131. {
  132. S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();
  133. S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();
  134. s3c24x0_nand_inithw();
  135. if (0) {
  136. chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;
  137. chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;
  138. chip->hwcontrol = s3c2410_nand_hwcontrol;
  139. chip->dev_ready = s3c2410_nand_devready;
  140. chip->select_chip = s3c2410_nand_select_chip;
  141. chip->options = 0;
  142. } else {
  143. chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;
  144. chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;
  145. chip->hwcontrol = s3c2440_nand_hwcontrol;
  146. chip->dev_ready = s3c2440_nand_devready;
  147. chip->select_chip = s3c2440_nand_select_chip;
  148. chip->options = 0;
  149. }
  150. chip->eccmode = NAND_ECC_SOFT;
  151. }
  152. #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. {
  3. return (S3C2410_NAND * const)S3C2410_NAND_BASE;
  4. }
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. {
  3. return (S3C2440_NAND * const)S3C2410_NAND_BASE;
  4. }
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