IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    移植u-boot-2010.09到tq2440(三)

    Qiang发表于 2011-02-08 13:01:12
    love 0

    五. Nand Flash驱动的移植
    Nand flash的移植还是很重要的,因为我们的u-boot和内核镜像都是烧在nand flash中的,必须要能操作nand flash,才能继续进行下去(stage2),nand flash的驱动代码主要是取自天嵌的u-boot。
    1. 建立文件drivers/mtd/nand/s3c2440_nand.c,添加如下内容:
    /*
    * Nand flash interface of s3c2440
    */
    #include
    #if 0
    #define DEBUGN printf
    #else
    #define DEBUGN(x, args …) {}
    #endif
    #include
    #include archs3c24x0_cpu.h>
    #include io.h>
    > #define __REGb(x) (*(volatile unsigned char *)(x))
    #define __REGi(x) (*(volatile unsigned int *)(x))

    #define NF_BASE 0x4e000000 //Nand配置寄存器基地址
    #define NFCONF __REGi(NF_BASE + 0x0) //偏移后还是得到配置寄存器基地址
    #define NFCONT __REGi(NF_BASE + 0x4) //偏移后得到Nand控制寄存器基地址
    #define NFCMD __REGb(NF_BASE + 0x8) //偏移后得到Nand指令寄存器基地址
    #define NFADDR __REGb(NF_BASE + 0xc) //偏移后得到Nand地址寄存器基地址
    #define NFDATA __REGb(NF_BASE + 0x10) //偏移后得到Nand数据寄存器基地址
    #define NFMECCD0 __REGi(NF_BASE + 0x14) //偏移后得到Nand主数据区域ECC0寄存器基地址
    #define NFMECCD1 __REGi(NF_BASE + 0x18) //偏移后得到Nand主数据区域ECC1寄存器基地址
    #define NFSECCD __REGi(NF_BASE + 0x1C) //偏移后得到Nand空闲区域ECC寄存器基地址
    #define NFSTAT __REGb(NF_BASE + 0x20) //偏移后得到Nand状态寄存器基地址
    #define NFSTAT0 __REGi(NF_BASE + 0x24) //偏移后得到Nand ECC0状态寄存器基地址
    #define NFSTAT1 __REGi(NF_BASE + 0x28) //偏移后得到Nand ECC1状态寄存器基地址
    #define NFMECC0 __REGi(NF_BASE + 0x2C) //偏移后得到Nand主数据区域ECC0状态寄存器基地址
    #define NFMECC1 __REGi(NF_BASE + 0x30) //偏移后得到Nand主数据区域ECC1状态寄存器基地址
    #define NFSECC __REGi(NF_BASE + 0x34) //偏移后得到Nand空闲区域ECC状态寄存器基地址
    #define NFSBLK __REGi(NF_BASE + 0x38) //偏移后得到Nand块开始地址
    #define NFEBLK __REGi(NF_BASE + 0x3c) //偏移后得到Nand块结束地址

    #define S3C2440_NFCONT_nCE (1<<1)
    #define S3C2440_ADDR_NALE 0x0c
    #define S3C2440_ADDR_NCLE 0x08
    ulong IO_ADDR_W = NF_BASE;
    static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
    {
    struct nand_chip *chip = mtd->priv;

    DEBUGN(“hwcontrol(): 0x%02x 0x%02x\n”, cmd, ctrl);

    if (ctrl & NAND_CTRL_CHANGE) {
    IO_ADDR_W = NF_BASE;

    if (!(ctrl & NAND_CLE)) //要写的是地址
    IO_ADDR_W |= S3C2440_ADDR_NALE;
    if (!(ctrl & NAND_ALE)) //要写的是命令
    IO_ADDR_W |= S3C2440_ADDR_NCLE;

    if (ctrl & NAND_NCE)
    NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash
    else
    NFCONT |= S3C2440_NFCONT_nCE; //禁止nand flash
    }

    if (cmd != NAND_CMD_NONE)
    writeb(cmd,(void *)IO_ADDR_W);
    }

    static int s3c2440_dev_ready(struct mtd_info *mtd)
    {
    DEBUGN(“dev_ready\n”);
    return (NFSTAT & 0x01);
    }

    int board_nand_init(struct nand_chip *nand)
    {
    u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    struct s3c24x0_clock_power * const clk_power = s3c24x0_get_base_clock_power();
    DEBUGN(“board_nand_init()\n”);
    clk_power->CLKCON |= (1 << 4);
    twrph0 = 4; twrph1 = 2; tacls = 0;
    cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);
    NFCONF = cfg;
    cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);
    NFCONT = cfg;

    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2440_hwcontrol;
    nand->dev_ready = s3c2440_dev_ready;
    nand->ecc.mode = NAND_ECC_SOFT;
    return 0;
    }
    2. 修改drivers/mtd/nand/Makefile,增加:
    COBJS-y += s3c2440_nand.o
    3. 修改include/config/tq2440.h,支持nand flash启动,随便把其他关于nand的设置一起做好:
    #define CONFIG_NAND_S3C2440 1
    #define CONFIG_CMD_NAND
    #define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址
    #define CONFIG_SYS_MAX_NAND_DEVICE 1
    #define CONFIG_MTD_NAND_VERIFY_WRITE 1
    #define CONFIG_ENV_IS_IN_NAND 1
    #define CONFIG_ENV_SIZE 0x20000
    #define CONFIG_ENV_OFFSET 0x40000
    4. 在arch/arm/include/asm/arch‐s3c24x0/s3c24x0.h中增加:
    struct s3c2440_nand {
    u32 NFCONF;
    u32 NFCONT;
    u32 NFCMD;
    u32 NFADDR;
    u32 NFDATA;
    u32 NFMECCD0;
    u32 NFMECCD1;
    u32 NFSECCD;
    u32 NFSTAT;
    u32 NFESTAT0;
    u32 NFESTAT1;
    u32 NFMECC0;
    u32 NFMECC1;
    u32 NFSECC;
    u32 NFSBLK;
    u32 NFEBLK;
    };
    5. 在board/samsung/tq2440/tq2440.c中增加nand读写的函数:
    #define GSTATUS1 (*(volatile unsigned int *)0x560000B0)
    #define BUSY 1

    #define NAND_SECTOR_SIZE 512
    #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE – 1)

    #define NAND_SECTOR_SIZE_LP 2048
    #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP – 1)

    char bLARGEBLOCK; //HJ_add 20090807
    char b128MB; //HJ_add 20090807

    /* 供外部调用的函数 */
    void nand_init_ll(void);
    int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size);
    int nand_read_ll_lp(unsigned char *buf, unsigned long start_addr, int size);

    static void nand_reset(void);
    static void wait_idle(void);
    static void nand_select_chip(void);
    static void nand_deselect_chip(void);
    static void write_cmd(int cmd);
    static void write_addr(unsigned int addr);
    static void write_addr_lp(unsigned int addr);
    static unsigned char read_data(void);
    int NF_ReadID(void); //HJ_add 20090807

    /* S3C2440的NAND Flash操作函数 */

    /* 复位 */
    static void nand_reset(void)
    {
    nand_select_chip();
    write_cmd(0xff); // 复位命令
    wait_idle();
    nand_deselect_chip();
    }

    /* 等待NAND Flash就绪 */
    static void wait_idle(void)
    {
    int i;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

    while(!(*p & BUSY))
    for(i=0; i<10; i++);
    }

    /* 发出片选信号 */
    static void nand_select_chip(void)
    {
    int i;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;

    s3c2440nand->NFCONT &= ~(1<<1);
    for(i=0; i<10; i++);
    }

    /* 取消片选信号 */
    static void nand_deselect_chip(void)
    {
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;

    s3c2440nand->NFCONT |= (1<<1);
    }

    /* 发出命令 */
    static void write_cmd(int cmd)
    {
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    *p = cmd;
    }

    /* 发出地址 */
    static void write_addr(unsigned int addr)
    {
    int i;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    *p = addr & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 9) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 17) & 0xff;
    for(i=0; i<10; i++);
    *p = (addr >> 25) & 0xff;
    for(i=0; i<10; i++);
    }

    /* 发出地址 */
    static void write_addr_lp(unsigned int addr)
    {
    int i;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    int col, page;

    col = addr & NAND_BLOCK_MASK_LP;
    page = addr / NAND_SECTOR_SIZE_LP;

    *p = col & 0xff; /* Column Address A0~A7 */
    for(i=0; i<10; i++);
    *p = (col >> 8) & 0x0f; /* Column Address A8~A11 */
    for(i=0; i<10; i++);
    *p = page & 0xff; /* Row Address A12~A19 */
    for(i=0; i<10; i++);
    *p = (page >> 8) & 0xff; /* Row Address A20~A27 */
    for(i=0; i<10; i++);
    if (b128MB == 0)
    *p = (page >> 16) & 0x03; /* Row Address A28~A29 */
    for(i=0; i<10; i++);
    }

    /* 读取数据 */
    static unsigned char read_data(void)
    {
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    return *p;
    }

    /* 初始化NAND Flash */
    void nand_init_ll(void)
    {
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;

    #define TACLS 0
    #define TWRPH0 3
    #define TWRPH1 0

    /* 设置时序 */
    s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
    s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

    /* 复位NAND Flash */
    nand_reset();
    }
    #if 1
    int NF_ReadID(void)
    {
    char pMID;
    char pDID;
    int nBuff;
    char n4thcycle;
    int i;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    b128MB = 1;
    n4thcycle = nBuff = 0;

    nand_init_ll();
    nand_select_chip();
    write_cmd(0x90); // read id command
    *p=0x00 & 0xff;
    for ( i = 0; i < 100; i++ );

    pMID = read_data();
    pDID = read_data();
    nBuff = read_data();
    n4thcycle = read_data();

    nand_deselect_chip();

    if (pDID >= 0xA0)
    {
    b128MB = 0;
    }

    return (pDID);
    }
    #endif

    /* 读函数 */
    int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
    {
    int i, j;
    char dat;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
    {
    return -1; /* 地址或长度不对齐 */
    }

    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);)
    {
    /* Check Bad Block */
    if(1){
    /* 发出READ0命令 */
    write_cmd(0x50);

    *p = 5;
    for(j=0; j<10; j++);
    *p = (i >> 9) & 0xff;
    for(j=0; j<10; j++);
    *p = (i >> 17) & 0xff;
    for(j=0; j<10; j++);
    *p = (i >> 25) & 0xff;
    for(j=0; j<10; j++);
    wait_idle();

    dat = read_data();
    write_cmd(0);

    /* 取消片选信号 */
    nand_deselect_chip();
    if(dat != 0xff)
    i += 16384; // 1 Block = 512*32= 16384
    /* Read Page */
    /* 选中芯片 */
    nand_select_chip();
    }
    /* 发出READ0命令 */
    write_cmd(0);

    /* Write Address */
    write_addr(i);
    wait_idle();

    for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
    {
    *buf = read_data();
    buf++;
    }
    }

    /* 取消片选信号 */
    nand_deselect_chip();

    return 0;
    }

    /* 读函数
    * Large Page
    */
    int nand_read_ll_lp(unsigned char *buf, unsigned long start_addr, int size)
    {
    int i, j;
    char dat;
    struct s3c2440_nand * s3c2440nand = (struct s3c2440_nand *)0x4e000000;
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP))
    {
    return -1; /* 地址或长度不对齐 */
    }

    /* 选中芯片 */
    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);)
    {
    /* Check Bad Block */
    if(1){
    int col, page;

    col = i & NAND_BLOCK_MASK_LP;
    page = i / NAND_SECTOR_SIZE_LP;
    /* 发出READ0命令 */
    write_cmd(0x00);

    *p = 5;
    for(j=0; j<10; j++);
    *p = 8;
    for(j=0; j<10; j++);
    *p = page & 0xff; /* Row Address A12~A19 */
    for(j=0; j<10; j++);
    *p = (page >> 8) & 0xff; /* Row Address A20~A27 */
    for(j=0; j<10; j++);
    if (b128MB == 0)
    *p = (page >> 16) & 0x03; /* Row Address A28~A29 */
    for(j=0; j<10; j++);

    write_cmd(0x30);
    wait_idle();

    dat = read_data();

    /* 取消片选信号 */
    nand_deselect_chip();
    if(dat != 0xff)
    i += 131072; // 1 Block = 2048*64= 131072
    /* Read Page */
    /* 选中芯片 */
    nand_select_chip();
    }
    /* 发出READ0命令 */
    write_cmd(0);

    /* Write Address */
    write_addr_lp(i);
    write_cmd(0x30);
    wait_idle();

    for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++)
    {
    *buf = read_data();
    buf++;
    }
    }

    /* 取消片选信号 */
    nand_deselect_chip();

    return 0;
    }

    int bBootFrmNORFlash(void)
    {
    volatile unsigned int *pdw = (volatile unsigned int *)0;
    unsigned int dwVal;

    /*
    * 无论是从NOR Flash还是从NAND Flash启动,
    * 地址0处为指令”b Reset”, 机器码为0xEA00000B,
    * 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中,
    * 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。
    * 对于NOR Flash,必须通过一定的命令序列才能写数据,
    * 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:
    * 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash
    */

    dwVal = *pdw;
    *pdw = 0x12345678;
    if (*pdw != 0x12345678)
    {
    return 1;
    }
    else
    {
    *pdw = dwVal;
    return 0;
    }
    }

    int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
    {
    unsigned int *pdwDest;
    unsigned int *pdwSrc;
    int i;

    if (bBootFrmNORFlash())
    {
    pdwDest = (unsigned int *)buf;
    pdwSrc = (unsigned int *)start_addr;
    /* 从 NOR Flash启动 */
    for (i = 0; i < size / 4; i++)
    {
    pdwDest[i] = pdwSrc[i];
    }
    return 0;
    }
    else
    {
    /* 初始化NAND Flash */
    nand_init_ll();

    /* 从 NAND Flash启动 */
    if (NF_ReadID() == 0x76 )
    nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
    else
    nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));
    return 0;
    }
    }
    6. 现在我们修改stage1的最后阶段:搬移u-boot代码到ram中,转到ram中继续执行。修改arch/arm/cpu/arm920t/start.S中代码搬运的部分:
    sub r2, r3, r2 /* r2 <- size of armboot */
    #if 1
    bl CopyCode2Ram
    #else
    add r2, r0, r2 /* r2<- source end address */

    copy_loop:
    ldmia r0!, {r3-r10} /* copy from source address [r0] */
    stmia r1!, {r3-r10} /* copy to target address [r1] */
    cmp r0, r2 /* until source end addreee [r2] */
    ble copy_loop
    7. 恢复之前为了测试做的修改,将start.S中的bl cpu_init_crit的注释去掉,即:
    bl cpu_init_crit
    同时修改board/samsung/tq2440/config.mk 中的25行为:
    TEXT_BASE = 0x33F80000
    编译后烧录到nand flash中,看看效果吧!



沪ICP备19023445号-2号
友情链接