Friday, October 9, 2015

U-boot porting JZ2440 - support NAND FLAHS

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_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
分析過程:
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->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);  // 讀操作,與時序圖一致
                                        *maf_id = chip->read_byte(mtd);  // 讀manufactor ID
                                        *dev_id = chip->read_byte(mtd);  // 讀device ID
重新燒寫
nand flash OK
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 #
 =============================================
3.6.8 nand 原理圖與讀操作時序圖
原理圖
時序圖

No comments:

Post a Comment