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 /* x16 */

                         },

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

/*-----------------------------------------------------------------------

* FLASH and environment organization

*/


#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(); /*在board/samsung/micro2440/nand.c中实现*/

#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, "");

           /*

            * Compute and print flash CRC if flashchecksum is set to 'y'

            *

            * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX

            */

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

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

            }

            putc('\n');

# else/* !CONFIG_SYS_FLASH_CHECKSUM */

            print_size(flash_size, "\n");

# endif /* CONFIG_SYS_FLASH_CHECKSUM */

        } else {

           puts(failed);

           hang();

       }

#ifdef CONFIG_MICRO2440

}

#endif

#endif

#if defined(CONFIG_CMD_NAND)

    puts("NAND:  ");

nand_init();/* go init the NAND */

#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

/* NAND FLASH (see S3C2440 manual chapter 6) */

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

你可能感兴趣的:(嵌入式系统,flash,c,平台,struct,cmd,io)