Chinaunix首页 | 论坛 | 博客
  • 博客访问: 113295
  • 博文数量: 23
  • 博客积分: 471
  • 博客等级: 一等列兵
  • 技术积分: 251
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-21 15:21
文章分类
文章存档

2017年(1)

2013年(2)

2011年(20)

分类: 嵌入式

2011-01-10 20:31:52

前述

Nand flash芯片:K9F1G08U0B128M

在前面移植nor文档的基础上,我们来移植nand flash上的uboot,这样过程就简单许多了,为什么要针对两种flash做移植呢?

原因:我认为一个原因是有些板上是没有nor 芯片的,相对于nand价格贵了点吧(^_^),所以需要针对nand移植,而且现在的uboot也是不直接支持nand启动的。

详细移植步骤 NO1

1.主要还是需要修改start.S文件,主要在修改在代码拷贝处,从nand拷贝时,不能向操作nor那样通过总线访问硬件,必须通过相应的控制器来访问,所以拷贝uboot代码到sdram的操作需要用一个函数nand_read_II()来实现,这个函数放在board/mini2440/nand_read.c中这个文件中。

/********************************************************************************/

start.S:

删除以前的nor的重定向代码,替换为

#ifdef CONFIG_S3C2440_NAND_BOOT

               @ reset NAND

 

       mov r1, #NAND_CTL_BASE       //0x4E000000

       ldr   r2, =( (7<<12) | (7<<8) | (7<<4) | (3<<2)) | (0<<0) )

       str    r2, [r1, #oNFCONF]      //根据手册设置NAND

       ldr   r2, [r1, #oNFCONF]

 

       ldr   r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control

       str    r2, [r1, #oNFCONT]     //允许片选,允许NAND Flash控制寄存器

       ldr   r2, [r1, #oNFCONT]

 

       ldr   r2, =(0x6)             @ RnB Clear

       str    r2, [r1, #oNFSTAT]   //清除忙标志,Rnb_TransDetect位写“1即可清楚忙标志

       ldr   r2, [r1, #oNFSTAT]

      

       mov r2, #0xff        @ RESET command     //发送复位命令

       strb  r2, [r1, #oNFCMD]

       mov r3, #0                    @ wait

     

nand1:   

       add  r3, r3, #0x1

        cmp r3, #0xa

        blt   nand1

       

nand2:   

       ldr   r2, [r1, #oNFSTAT]       @ wait ready         

//等待前一次操作完成,通过判断Rnb_TransDetect位实现

        tst    r2, #0x4

        beq  nand2

 

       ldr   r2, [r1, #oNFCONT]

       orr   r2, r2, #0x2           @ Flash Memory Chip Disable

       str    r2, [r1, #oNFCONT]            // 关闭片选,到这里只是完成了NAND初始化。

 

       @ get read to call C functions (for nand_read())         //C准备堆栈

       ldr   sp, DW_STACK_START       @ setup stack pointer

       mov fp, #0                    @ no previous frame, so fp="0"

  @ copy uboot to sdRAM

//r0,r1,r2为传递给C的参数

       ldr          r0,=TEXT_BASE   //数据存放位置,即要拷贝到哪里

       mov     r1, #0x0               //拷贝的起始地址

       mov r2, #0x30000                //拷贝长度

       bl    nand_read_ll                 //跳到C语言中

       tst    r0, #0x0         //nand_read_ll返回0则读取成功

       beq  ok_nand_read     

bad_nand_read:

       1:    b     1b           @ infinite loop     

//为什么读取错误时设一个无限循?这样不是启动不来了么?为什么不重新读取    

ok_nand_read:

       @ verify

       mov r0, #0

       ldr   r1, =TEXT_BASE

       mov r2, #0x400      @ 4 bytes * 1024 = 4K-bytes

go_next:

       ldr   r3, [r0], #4

       ldr   r4, [r1], #4

       teq   r3, r4

       bne  notmatch        //比较前4K的内容是否拷贝正确

       subs r2, r2, #4

       beq  stack_setup

       bne  go_next   

notmatch:

loop3:

       b     loop3

#endif    // CONFIG_S3C2440_NAND_BOOT

 

/********************************************************************************/

 

/board/mini2440中添加nand_read.c文件,并且修改makefile

/********************************************************************************/

nand_read.c:

#include

#define __REGb(x) (*(volatile unsigned char *)(x))

#define __REGi(x) (*(volatile unsigned int *)(x))

#define NF_BASE 0x4e000000

 

#define NFCONF __REGi(NF_BASE + 0x0)

#define NFCONT __REGi(NF_BASE + 0x4)

#define NFCMD __REGb(NF_BASE + 0x8)

#define NFADDR __REGb(NF_BASE + 0xC)

#define NFDATA __REGb(NF_BASE + 0x10)

#define NFSTAT __REGb(NF_BASE + 0x20)

 

#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1))

#define NAND_CHIP_DISABLE (NFCONT |= (1<<1))

#define NAND_CLEAR_RB (NFSTAT |= (1<<2))

#define NAND_DETECT_RB { while(! (NFSTAT&(1<<2)));}

 

#define BUSY 4

inline void wait_idle(void)

{

    while(!(NFSTAT & BUSY));

    NFSTAT |= BUSY;

}

 

#define NAND_SECTOR_SIZE 2048

#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)

 

/* low level nand read function */

int

nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

{

    int i, j;

  

    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))

   {

                  return -1;    //invalid alignment

    }

 

    NAND_CHIP_ENABLE;

       

    for(i=start_addr; i < (start_addr + size);)

{

    /* READ0 */

        NAND_CLEAR_RB;   

        NFCMD = 0;   

        /* Write Address */

 

       /*  start comment

        NFADDR = i & 0xff;

        NFADDR = (i >> 9) & 0xff;

        NFADDR = (i >> 17) & 0xff;

        NFADDR = (i >> 25) & 0xff;

   */

    /*page 2k,so [10..0]=00000000000 this must pay attention*/

        NFADDR = 0x0;

        NFADDR = 0x0;

        NFADDR = (i >> 11) & 0xff;

        NFADDR = (i >> 19) & 0xff;

        NFCMD = 0x30;

               

        NAND_DETECT_RB;

   

        for(j=0; j < NAND_SECTOR_SIZE; j++, i++)

          {

               *buf = (NFDATA & 0xff);

                 buf++;

        }

    }

    NAND_CHIP_DISABLE;

    return 0;

}

/***************************************************************************/

 

2.第二个需要修改的文件呢?当然是include/configs/mini2440.h文件咯,大家看看怎么修改?

① 首先,不需要nor flash了,注释掉前面文章中涉及到的nor的宏,自己改吧..

② 添加CMD相关命令,以及nand flash paramnand flash setting

 

 

     //nand Flash param

#define CONFIG_CMDLINE_EDITING

#ifdef CONFIG_CMDLINE_EDITING

#undef CONFIG_AUTO_COMPLETE

#else

#define CONFIG_AUTO_COMPLETE

#endif

 

//#define CONFIG_NAND_LEGACY

 

#define CONFIG_CMD_NAND

/*

 * NAND flash settings

 */

#if defined(CONFIG_CMD_NAND)

#define CONFIG_S3C2440_NAND_BOOT 1

#define CFG_NAND_BASE 0x4E000000

/* NandFlash控制器在SFR区起始寄存器地址 */

#define CFG_MAX_NAND_DEVICE    1      

/* Max number of NAND devices         */

#define CONFIG_MTD_NAND_VERIFY_WRITE 1 //使能flash写校验

/* #undef CONFIG_MTD_NAND_VERIFY_WRITE */

#define CONFIG_SYS_NAND_BASE 0x4E000000

#define CONFIG_SYS_MAX_NAND_DEVICE 1

#define CONFIG_MAX_NAND_DEVICE 1

#define NAND_MAX_CHIPS 1

#endif  /* CONFIG_CMD_NAND */

 

/* NAND Flash Controller */

#define NAND_CTL_BASE 0x4E000000

#define bINT_CTL(Nb) __REG(INT_CTL_BASE + (Nb))

③ 相关nand控制器的地址以及偏移

/* Offset */

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD 0x08

#define oNFADDR 0x0c

#define oNFDATA 0x10

#define oNFSTAT 0x20

#define oNFECC 0x2c

#define rNFCONF (*(volatile unsigned int *)0x4e000000)

#define rNFCONT (*(volatile unsigned int *)0x4e000004)

#define rNFCMD (*(volatile unsigned char *)0x4e000008)

#define rNFADDR (*(volatile unsigned char *)0x4e00000c)

#define rNFDATA (*(volatile unsigned char *)0x4e000010)

#define rNFSTAT (*(volatile unsigned int *)0x4e000020)

#define rNFECC (*(volatile unsigned int *)0x4e00002c)

④ ENV设置

#define CFG_NO_FLASH              1

#define CONFIG_ENV_IS_IN_NAND     1

#define CONFIG_ENV_OFFSET         0x40000

#define CONFIG_ENV_SIZE               0x20000     /* Total Size of Environment

       Sector */

 

3.这里我们不使用nand_legacy方式,所以还需要修改nand.c

添加:

#if defined(CONFIG_S3C2440)

#define NF_BASE        0x4e000000

#define NFCONF         __REGi(NF_BASE + 0x0)

#define NFCONT         __REGi(NF_BASE + 0x4)

#define NFCMD          __REGb(NF_BASE + 0x8)

#define NFADDR         __REGb(NF_BASE + 0xc)

#define NFDATA         __REGb(NF_BASE + 0x10)

#define NFMECCD0       __REGi(NF_BASE + 0x14)

#define NFMECCD1       __REGi(NF_BASE + 0x18)

#define NFSECCD        __REGi(NF_BASE + 0x1C)

#define NFSTAT         __REGb(NF_BASE + 0x20)

#define NFSTAT0        __REGi(NF_BASE + 0x24)

#define NFSTAT1        __REGi(NF_BASE + 0x28)

#define NFMECC0        __REGi(NF_BASE + 0x2C)

#define NFMECC1        __REGi(NF_BASE + 0x30)

#define NFSECC         __REGi(NF_BASE + 0x34)

#define NFSBLK         __REGi(NF_BASE + 0x38)

#define NFEBLK         __REGi(NF_BASE + 0x3c)

#define S3C2440_NFCONT_nCE     (1<<1)

#define S3C2440_ADDR_NALE 0x0c

#define S3C2440_ADDR_NCLE 0x08

#endif

 

#define S3C2410_NFCONF_EN          (1<<15)

#define S3C2410_NFCONF_512BYTE     (1<<14)

#define S3C2410_NFCONF_4STEP       (1<<13)

#define S3C2410_NFCONF_INITECC     (1<<12)

#define S3C2410_NFCONF_nFCE        (1<<11)

#define S3C2410_NFCONF_TACLS(x)    ((x)<<8)

#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<4)

#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<0)

 

#define S3C2410_ADDR_NALE 4

#define S3C2410_ADDR_NCLE 8

 

ulong IO_ADDR_W = NF_BASE;

 

static void s3c2410_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 defined(CONFIG_S3C2410)

       if (ctrl & NAND_CTRL_CHANGE) {

              //ulong IO_ADDR_W = NF_BASE;

              IO_ADDR_W = NF_BASE;

              if (!(ctrl & NAND_CLE))

                     IO_ADDR_W |= S3C2410_ADDR_NCLE;

              if (!(ctrl & NAND_ALE))

                     IO_ADDR_W |= S3C2410_ADDR_NALE;

 

              //chip->IO_ADDR_W = (void *)IO_ADDR_W;

 

              if (ctrl & NAND_NCE)

                     NFCONF &= ~S3C2410_NFCONF_nFCE;

              else

                     NFCONF |= S3C2410_NFCONF_nFCE;

       }

 

       if (cmd != NAND_CMD_NONE)

       //     writeb(cmd, chip->IO_ADDR_W);

              writeb(cmd,(void *)IO_ADDR_W);

#endif

       #if defined(CONFIG_S3C2440)

        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;}

                        //chip->IO_ADDR_W = (void *)IO_ADDR_W;

               if (ctrl & NAND_NCE)  

                       {

                        NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash

                       //DEBUGN("NFCONT is 0x%x ",NFCONT);

                       //DEBUGN("nand Enable ");

                       }

               else

                       {

                         NFCONT |= S3C2440_NFCONT_nCE;  //禁止nand flash

                       //DEBUGN("nand disable ");

                       }

 

        }

        if (cmd != NAND_CMD_NONE)

               writeb(cmd,(void *)IO_ADDR_W);

               //writeb(cmd, chip->IO_ADDR_W);

#endif

}

修改nand_init函数:

int board_nand_init(struct nand_chip *nand)

{

       u_int32_t cfg;

       u_int8_t tacls, twrph0, twrph1;

       S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

 

       DEBUGN("board_nand_init()\n");

 

       clk_power->CLKCON |= (1 << 4);

#if  defined(CONFIG_S3C2410)

           DEBUGN("CONFIG_S3C2410\n");

       /* initialize hardware */

       twrph0 = 3; twrph1 = 0; tacls = 0;

 

       cfg = S3C2410_NFCONF_EN;

       cfg |= S3C2410_NFCONF_TACLS(tacls - 1);

       cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);

       cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

 

       NFCONF = cfg;

 

       /* initialize nand_chip data structure */

       nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;

 

       /* read_buf and write_buf are default */

       /* read_byte and write_byte are default */

 

       /* hwcontrol always must be implemented */

       nand->cmd_ctrl = s3c2410_hwcontrol;

 

       nand->dev_ready = s3c2410_dev_ready;

#endif

#if defined(CONFIG_S3C2440)

        DEBUGN("CONFIG_S3C2440\n");

        twrph0 = 4; twrph1 = 2; tacls = 0;

        cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);

        NFCONF = cfg;

        //DEBUGN("cfg is %x\n",cfg);

        //DEBUGN("NFCONF is %lx\n",NFCONF);

        cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);

        NFCONT = cfg;

        //DEBUGN("cfg is %lx\n",cfg);

        //DEBUGN("NFCONT is %x\n",NFCONT);

/* 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 = s3c2410_hwcontrol;

        nand->dev_ready = s3c2410_dev_ready;

#endif

 

#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_HW3_512;

#else

       nand->ecc.mode = NAND_ECC_SOFT;

#endif

 

#ifdef CONFIG_S3C2410_NAND_BBT

       nand->options = NAND_USE_FLASH_BBT;

#else

       nand->options = 0;

#endif

 

       DEBUGN("end of nand_init\n");

       return 0;

}

NO2.

至此,基本修改完成,大家make一下,烧写试试!

注意:该nand flash 芯片不能在win下通过sjf2440.exe进行烧写,可以到网上下载最新的H-JTAG来进行烧写,速度快,很好用!(免费的O(_)O

输出效果图如下:

阅读(3307) | 评论(1) | 转发(3) |
0

上一篇:没有了

下一篇:五、U-boot源码简要分析(一)

给主人留下些什么吧!~~

yuweixian42302011-01-11 15:10:33

又高又硬