天天看點

U-boot移植 (v2012.04.1 S3C2440平台) (三) Nor flash Nand flash 驅動支援

7  NOR Flash(SSTVF1601) 支援

在u-boot中添加對Nor flash的支援比較簡單,大多數Nor flash都支援CFI接口,而u-boot有對cfi flash的驅動支援。對于SSTVF1601,并不支援标準的CFI接口,是以得使用JEDEC接口。但jedec_flash.c中并沒有SSTVF1601的配置資訊,是以得手動添加上:

drivers/mtd/jedec_flash.c:

static const struct amd_flash_info jedec_table[] = {

    …

#ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16

{

    .mfr_id= (u16)SST_MANUFACT,

    .dev_id     = SST39VF1601,

    .name       = "SST 39VF1601",

    .uaddr      = {

                           [1] = MTD_UADDR_0x5555_0x2AAA

                         },

    .DevSize    = SIZE_2MiB,

    .CmdSet     = P_ID_AMD_STD,

    .NumEraseRegions= 4,

    .regions    = {

                          ERASEINFO(0x1000,96),

                          ERASEINFO(0x1000,160),

                          ERASEINFO(0x1000,240),

                          ERASEINFO(0x1000,16),

                          }

},

#endif

};

修改micro2440.h:

#define CONFIG_SYS_FLASH_CFI

#define CONFIG_FLASH_CFI_DRIVER

#define CONFIG_FLASH_CFI_LEGACY

#define CONFIG_SYS_FLASH_LEGACY_1024Kx16

#define CONFIG_FLASH_SHOW_PROGRESS45

#define CONFIG_SYS_MAX_FLASH_BANKS1

#define CONFIG_SYS_FLASH_BANKS_LIST     { CONFIG_SYS_FLASH_BASE }

#define CONFIG_SYS_MAX_FLASH_SECT(512)

#define CONFIG_ENV_ADDR(CONFIG_SYS_FLASH_BASE + 0x1f0000)

#define CONFIG_ENV_IS_IN_FLASH

#define CONFIG_ENV_SIZE0x10000

7  NAND Flash支援

u-boot的driver/mtd/nand下有s3c2410 nand控制器的驅動,并沒有s3c2440的。但2410和2440的nand控制器差别并不大,我們可以在2410的基礎上進行移植。具體代碼可以在我的github(https://github.com/novawl/u-boot-v2010.4.1)下的drivers/mtd/nand/s3c2440_nand.c中檢視。需要注意的是,hwcontrol函數中,當cmd不為指令時,得将IO_ADDR_W指派為nfdata位址,不然資料将無法寫入到nand flash中。

static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)

{

    struct nand_chip *chip = mtd->priv;

    struct s3c2440_nand *nand = s3c2440_get_base_nand();

    debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

    if (ctrl & NAND_CTRL_CHANGE) {

        ulong IO_ADDR_W = (ulong)nand;

        if (!(ctrl & NAND_CLE))

            IO_ADDR_W |= S3C2440_ADDR_NCLE;

        if (!(ctrl & NAND_ALE))

           IO_ADDR_W |= S3C2440_ADDR_NALE;

        if (cmd == NAND_CMD_NONE)

           IO_ADDR_W = &nand->nfdata;

        chip->IO_ADDR_W = (void *)IO_ADDR_W;

        if (ctrl & NAND_NCE)

            writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nFCE, &nand->nfcont);

        else

            writel(readl(&nand->nfcont) | S3C2440_NFCONT_nFCE, &nand->nfcont);

    }

    if (cmd != NAND_CMD_NONE)

        writeb(cmd, chip->IO_ADDR_W);

}

修改arch/arm/lib/board.c,當從Nor flash啟動時才初始化nor flash,否則隻初始化nand flash:

#if !defined(CONFIG_SYS_NO_FLASH)

    static char *failed = "*** failed ***\n";

#ifdef CONFIG_MICRO2440

    extern int BootFrmNORFlash();

#endif

#endif

void board_init_r(gd_t *id, ulong dest_addr)

#if !defined(CONFIG_SYS_NO_FLASH)

#ifdef CONFIG_MICRO2440

    if (BootFrmNORFlash()) {

#endif

        puts("Flash: ");

        flash_size = flash_init();

        if (flash_size > 0) {

# ifdef CONFIG_SYS_FLASH_CHECKSUM

            char *s = getenv("flashchecksum");

            print_size(flash_size, "");

            if (s && (*s == 'y')) {

                printf("  CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size));

            }

            putc('\n');

# else

            print_size(flash_size, "\n");

# endif

        } else {

           puts(failed);

           hang();

       }

#ifdef CONFIG_MICRO2440

}

#endif

#endif

#if defined(CONFIG_CMD_NAND)

    puts("NAND:  ");

nand_init();

#endif

ECC校驗:

s3c2410和s3c2440 Nand flash控制器ECC校驗子產品有很大差别,是以基于s3c2440_nand.c的ecc校驗函數和s3c2410_nand.c有較大差别。下面是與ECC校驗相關的三個函數的實作:

#ifdef CONFIG_S3C2440_NAND_HWECC

void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)

{

    struct s3c2440_nand *nand = s3c2440_get_base_nand();

    debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);

    writel(readl(&nand->nfcont) | S3C2440_NFCONT_INITECC, &nand->nfcont);

}

static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)

{

    struct s3c2440_nand *nand = s3c2440_get_base_nand();

    unsigned long ecc = readl(&nand->nfecc0);

    ecc_code[0] = ecc;

    ecc_code[1] = ecc >> 8;

    ecc_code[2] = ecc >> 16;

    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 s3c2440_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("s3c2440_nand_correct_data: not implemented\n");

    return -1;

}

#endif

micro2440.h中與ECC相關的配置:

#define CONFIG_S3C2440_NAND_HWECC

#define CONFIG_SYS_NAND_ECCSIZE512

#define CONFIG_SYS_NAND_ECCBYTES3

還有一個需要注意的地方是新版的u-boot中s3c24x0.h中定義的struct s3c2440_nand結構體定義并不全面,并沒有nfmecc0 和nfmecc1等寄存器的實作,這裡需要添加上:

#ifdef CONFIG_S3C2440

struct s3c2440_nand {

    u32  nfconf;

    u32  nfcont;

    u32  nfcmd;

    u32  nfaddr;

    u32  nfdata;

    u32  nfeccd0;

    u32  nfeccd1;

    u32  nfeccd;

    u32  nfstat;

    u32  nfstat0;

    u32  nfstat1;

  u32  nfecc0;

    u32  nfecc1;

    u32  nfecc;

};

#endif

繼續閱讀