3.6 修改UBOOT支持NAND FLASH
3.6.1 修改:include/configs/smdk2440.h: #define CONFIG_CMD_NAND
3.6.2 把drivers/mtd/nand/s3c2410_nand.c複製為s3c2440_nand.c
3.6.3 修改drivers/mtd/nand/目錄下的Makefile檔:
COBJS-$(CONFIG_NAND_NDFC) += ndfc.o
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
3.6.3 修改drivers/mtd/nand/目錄下的Makefile檔:
......
COBJS-$(CONFIG_NAND_NDFC) += ndfc.o
COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o // 添加這句話
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
......
3.6.4 CONFIG_NAND_S3C2440 在設定檔 includes/configs/smdk2440.h 中定義
......
/*
* NAND configuration
*/
#ifdef CONFIG_CMD_NAND
#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#endif
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0x4E000000
#endif
......
3.6.5
修改driver\mtd\nand\s3c2440_nand.c
// ctrl : 硬體動作, enable chip/disable chip, send command or send address
// cmd : command or address
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(ctrl & NAND_CLE)
{
// send command
writeb(dat, &nand->nfcmd);
}
else if(ctrl & NAND_ALE)
{
// send address
writeb(dat, &nand->nfaddr);
}
}
static int s3c2440_dev_ready(struct mtd_info *mtd)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debug("dev_ready\n");
return readl(&nand->nfstat) & 0x01;
}
static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
switch (chipnr) {
case -1: // disable chip
nand->nfcont |= (1<<1);
break;
case 0: // enable chip
nand->nfcont &= ~(1<<1);
break;
default:
BUG();
}
}
//#ifdef CONFIG_S3C2410_NAND_HWECC
//void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
//{
// struct s3c2410_nand *nand = s3c2410_get_base_nand();
// debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
// writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
//}
//static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
// u_char *ecc_code)
//{
// struct s3c2410_nand *nand = s3c2410_get_base_nand();
// ecc_code[0] = readb(&nand->nfecc);
// ecc_code[1] = readb(&nand->nfecc + 1);
// ecc_code[2] = readb(&nand->nfecc + 2);
// debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
// mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
// return 0;
//}
//static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
// u_char *read_ecc, u_char *calc_ecc)
//{
// if (read_ecc[0] == calc_ecc[0] &&
// read_ecc[1] == calc_ecc[1] &&
// read_ecc[2] == calc_ecc[2])
// return 0;
// printf("s3c2410_nand_correct_data: not implemented\n");
// return -1;
//}
//#endif
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debug("board_nand_init()\n");
writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);
/* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
tacls = CONFIG_S3C24XX_TACLS;
twrph0 = CONFIG_S3C24XX_TWRPH0;
twrph1 = CONFIG_S3C24XX_TWRPH1;
#else
tacls = 4;
twrph0 = 8;
twrph1 = 8;
#endif
#if 0
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->nfconf);
#endif
// 設置時序
cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);
writel(cfg, &nand_reg->nfconf);
// enable nand flash controller, initial ECC, disable chip select
writel((1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
nand->IO_ADDR_W = (void *)&nand_reg->nfdata;
// nand->select_chip = NULL;
nand->select_chip = s3c2440_nand_select;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
nand->read_buf = nand_read_buf;
#endif
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode = NAND_ECC_SOFT; // 採軟體實現ECC
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
debug("end of nand_init\n");
return 0;
}
3.6.6
分析過程:
3.6.4 CONFIG_NAND_S3C2440 在設定檔 includes/configs/smdk2440.h 中定義
......
/*
* NAND configuration
*/
#ifdef CONFIG_CMD_NAND
#ifdef CONFIG_S3C2410
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC
#else
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#endif
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_SYS_NAND_BASE 0x4E000000
#endif
......
3.6.5
修改driver\mtd\nand\s3c2440_nand.c
// ctrl : 硬體動作, enable chip/disable chip, send command or send address
// cmd : command or address
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
if(ctrl & NAND_CLE)
{
// send command
writeb(dat, &nand->nfcmd);
}
else if(ctrl & NAND_ALE)
{
// send address
writeb(dat, &nand->nfaddr);
}
}
static int s3c2440_dev_ready(struct mtd_info *mtd)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
debug("dev_ready\n");
return readl(&nand->nfstat) & 0x01;
}
static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
{
struct s3c2440_nand *nand = s3c2440_get_base_nand();
switch (chipnr) {
case -1: // disable chip
nand->nfcont |= (1<<1);
break;
case 0: // enable chip
nand->nfcont &= ~(1<<1);
break;
default:
BUG();
}
}
//#ifdef CONFIG_S3C2410_NAND_HWECC
//void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
//{
// struct s3c2410_nand *nand = s3c2410_get_base_nand();
// debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
// writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
//}
//static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
// u_char *ecc_code)
//{
// struct s3c2410_nand *nand = s3c2410_get_base_nand();
// ecc_code[0] = readb(&nand->nfecc);
// ecc_code[1] = readb(&nand->nfecc + 1);
// ecc_code[2] = readb(&nand->nfecc + 2);
// debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
// mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
// return 0;
//}
//static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
// u_char *read_ecc, u_char *calc_ecc)
//{
// if (read_ecc[0] == calc_ecc[0] &&
// read_ecc[1] == calc_ecc[1] &&
// read_ecc[2] == calc_ecc[2])
// return 0;
// printf("s3c2410_nand_correct_data: not implemented\n");
// return -1;
//}
//#endif
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
debug("board_nand_init()\n");
writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);
/* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
tacls = CONFIG_S3C24XX_TACLS;
twrph0 = CONFIG_S3C24XX_TWRPH0;
twrph1 = CONFIG_S3C24XX_TWRPH1;
#else
tacls = 4;
twrph0 = 8;
twrph1 = 8;
#endif
#if 0
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
writel(cfg, &nand_reg->nfconf);
#endif
// 設置時序
cfg = ((tacls-1)<<12)|((twrph0-1)<<8)|((twrph1-1)<<4);
writel(cfg, &nand_reg->nfconf);
// enable nand flash controller, initial ECC, disable chip select
writel((1<<4)|(1<<1)|(1<<0), &nand_reg->nfcont);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
nand->IO_ADDR_W = (void *)&nand_reg->nfdata;
// nand->select_chip = NULL;
nand->select_chip = s3c2440_nand_select;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
nand->read_buf = nand_read_buf;
#endif
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
#else
nand->ecc.mode = NAND_ECC_SOFT; // 採軟體實現ECC
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
debug("end of nand_init\n");
return 0;
}
3.6.6
分析過程:
nand_init(arch/arm/lib/board.c)
nand_init_chip (driver/mtd/nand.c)
board_nand_init
設置nand_chip結構體, 提供底層的操作函數
nand_scan( driver/mtd/nand.c)
nand_scan_ident
nand_set_defaults
chip->select_chip = nand_select_chip;
chip->cmdfunc = nand_command;
chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
nand_get_flash_type
chip->select_chip // 調用s3c2440_nand_selcet函數, select or diselect
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
nand_command() // 即可以用來發命令,也可以用來發列位址(頁內位
// 址)、行地址(哪一頁)
// 址)、行地址(哪一頁)
chip->cmd_ctrl // nand_cmdfunc()調用
s3c2440_hwcontrol // 底層發command 函數,
// chip->cmd_ctrl調用
// chip->cmd_ctrl調用
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); // 讀操作,與時序圖一致
*maf_id = chip->read_byte(mtd); // 讀manufactor ID
*dev_id = chip->read_byte(mtd); // 讀device ID
重新燒寫
3.6.7
驗證:
U-Boot 2012.04.01 (Sep 15 2015 - 17:04:40)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 2 MiB
NAND: 256 MiB <--ok
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 # nand erase 0 80000
NAND erase: device 0 offset 0x0, size 0x80000
Erasing at 0x60000 -- 100% complete.
OK
SMDK2410 # nand write 0 0 80000
NAND write: device 0 offset 0x0, size 0x80000
524288 bytes written: OK
SMDK2410 # nand read 30000000 0 80000
NAND read: device 0 offset 0x0, size 0x80000
524288 bytes read: OK
SMDK2410 # cmp.b 0 30000000 80000
Total of 524288 bytes were the same <-- 比較內存與nand flash 內容相同, 驗證ok
SMDK2410 #
NAND FLASH 啟動 U-BOOT
U-Boot 2012.04.01 (Sep 15 2015 - 17:04:40)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 0 kb <--- NOR FLASH,
NAND: 256 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
重新燒寫
nand flash OK |
驗證:
U-Boot 2012.04.01 (Sep 15 2015 - 17:04:40)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 2 MiB
NAND: 256 MiB <--ok
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 # nand erase 0 80000
NAND erase: device 0 offset 0x0, size 0x80000
Erasing at 0x60000 -- 100% complete.
OK
SMDK2410 # nand write 0 0 80000
NAND write: device 0 offset 0x0, size 0x80000
524288 bytes written: OK
SMDK2410 # nand read 30000000 0 80000
NAND read: device 0 offset 0x0, size 0x80000
524288 bytes read: OK
SMDK2410 # cmp.b 0 30000000 80000
Total of 524288 bytes were the same <-- 比較內存與nand flash 內容相同, 驗證ok
SMDK2410 #
NAND FLASH 啟動 U-BOOT
U-Boot 2012.04.01 (Sep 15 2015 - 17:04:40)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 0 kb <--- NOR FLASH,
NAND: 256 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: CS8900-0
SMDK2410 #
=============================================
No comments:
Post a Comment