天嵌 ARM开发社区

 找回密码
 注册
查看: 4425|回复: 5

Nand Flash 移植问题 TQ2440板子 K9F1208U0B 64M

[复制链接]
xiang8000 发表于 2010-10-3 10:39:27 | 显示全部楼层 |阅读模式
本帖最后由 xiang8000 于 2010-10-3 10:44 编辑

目前板子已经能够从Nand Flash启动,并且终端有输出,其输出字样为:
U-Boot 2009.08 (10月 03 2010 - 04:08:59)

DRAM:  64 MB
Flash:  2 MB
NAND:  No NAND device found!!!
0 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
2440 #

然后键入nand help 命令,终端输出为:
2440 # nand help
nand - NAND sub-system

Usage:
nand info - show available NAND devices
nand device [dev] - show or set current device
nand read - addr off|partition size
nand write - addr off|partition size
    read/write 'size' bytes starting at offset 'off'
    to/from memory address 'addr', skipping bad blocks.
nand erase [clean] [off size] - erase 'size' bytes from
    offset 'off' (entire device if not specified)
nand bad - show bad blocks
nand dump[.oob] off - dump page
nand scrub - really clean NAND erasing bad blocks (UNSAFE)
nand markbad off [...] - mark bad block(s) at offset (UNSAFE)
nand biterr off - make a bit error at offset (UNSAFE)
2440 #

虽然能使用nand help命令,但是nand info命令却不能使用,键入后
2440 # nand info

2440 #
无任何显示,并返回等待输入
如果此时输入nand bad,会显示 没有驱动字样
2440 # nand bad
no devices available
2440 #
既然我的u-boot已经可以从nand flash启动并有了终端输出,那么板子应该已经识别到了nandflash了呀,为什么这些nand info等命令我却不能使用呢?另外环境变量也不能保存到NAND FLASH中,问题出在什么地方?望老师指教说明一下,是那部分代码存在问题,不胜感激!

这是我这里关于添加NAND FLASH启动相关的所有代码,根据别人blog一步一步进行而来,是否是有什么地方有所遗漏?已仔细检查数次,blog中所提到的地方已经都做了添加或修改,进度和blog一致无遗漏,是否blog有些步骤没有提及所以我这边也就有问题,老师费心了
blog如下(其也是 K9F1208U0B 64M nand flash + 2440)

首先,在include/configs/my2440.h头文件中定义Nand要用到的宏和寄存器,如下: #gedit include/configs/my2440.h  //在文件末尾加入以下Nand Flash相关定义
#define CONFIG_S3C2440_NAND_BOOT  1
#define NAND_CTL_BASE  0x4E000000  //Nand Flash配置寄存器基地址,查2440手册可得知
#define STACK_BASE  0x33F00000     //定义堆栈的地址
#define STACK_SIZE  0x8000         //堆栈的长度大小
#define oNFCONF  0x00 //相对Nand配置寄存器基地址的偏移量,还是配置寄存器的基地址
#define oNFCONT  0x04 //相对Nand配置寄存器基地址的偏移量,可得到控制寄存器的基地址(0x4E000004)
#define oNFADDR  0x0c //得到地址寄存器的基地址(0x4E00000c)
#define oNFDATA  0x10 //得到数据寄存器的基地址(0x4E000010)
#define oNFCMD   0x08 //可得到指令寄存器的基地址(0x4E000008)
#define oNFSTAT  0x20 //可得到状态寄存器的基地址(0x4E000020)
#define oNFECC   0x2c //可得到ECC寄存器的基地址(0x4E00002c)

其次,修改cpu/arm920t/start.S这个文件,使u-boot从Nand Flash启动,在上一节中提过,u-boot默认是从Nor Flash启动的。修改部分如下: #gedit cpu/arm920t/start.S
//注意:在上一篇Nor Flash启动中,我们为了把u-boot用supervivi下载到内存中运行而屏蔽掉这段有关CPU初始化的代码。而现在我们要把u-boot下载到Nand Flash中,从Nand Flash启动,所以现在要恢复这段代码。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl cpu_init_crit
#endif

#if 0 //屏蔽掉u-boot中的从Nor Flash启动部分
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:               /* relocate U-Boot to RAM */
    adr r0, _start      /* r0 <- current position of code */
    ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
    cmp r0, r1          /* don't reloc during debug */
    beq stack_setup

    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot */
    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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif

//下面添加2440中u-boot从Nand Flash启动
#ifdef CONFIG_S3C2440_NAND_BOOT
    mov r1, #NAND_CTL_BASE   //复位Nand Flash
    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
    str r2, [r1, #oNFCONF]   //设置配置寄存器的初始值,参考s3c2440手册
    ldr r2, [r1, #oNFCONF]

    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )
    str r2, [r1, #oNFCONT]   //设置控制寄存器
    ldr r2, [r1, #oNFCONT]

    ldr r2, =(0x6)           //RnB Clear
    str r2, [r1, #oNFSTAT]
    ldr r2, [r1, #oNFSTAT]
    mov r2, #0xff            //复位command
    strb r2, [r1, #oNFCMD]

    mov r3, #0               //等待
nand1:
    add r3, r3, #0x1
    cmp r3, #0xa
    blt nand1

nand2:
    ldr r2, [r1, #oNFSTAT]   //等待就绪
    tst r2, #0x4
    beq nand2

    ldr r2, [r1, #oNFCONT]
    orr r2, r2, #0x2         //取消片选
    str r2, [r1, #oNFCONT]

    //get read to call C functions (for nand_read())
    ldr sp, DW_STACK_START   //为C代码准备堆栈,DW_STACK_START定义在下面
    mov fp, #0               

    //copy U-Boot to RAM
    ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址
    mov r1, #0x0      //传递给C代码的第二个参数:Nand Flash的起始地址
    mov r2, #0x30000  //传递给C代码的第三个参数:u-boot的长度大小(128k)
    bl nand_read_ll   //此处调用C代码中读Nand的函数,现在还没有要自己编写实现
    tst r0, #0x0
    beq ok_nand_read

bad_nand_read:
    loop2: b loop2    //infinite loop

ok_nand_read:
    //检查搬移后的数据,如果前4k完全相同,表示搬移成功
    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
    subs r2, r2, #4
    beq stack_setup
    bne go_next

notmatch:
    loop3: b loop3           //infinite loop

#endif //CONFIG_S3C2440_NAND_BOOT

_start_armboot: .word start_armboot //在这一句的下面加上DW_STACK_START的定义

.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

再次,在board/samsung/my2440/目录下新建一个nand_read.c文件,在该文件中来实现上面汇编中要调用的nand_read_ll函数,代码如下: #gedit board/samsung/my2440/nand_read.c  //新建一个nand_read.c文件,记得保存
#include <config.h>
#define NF_BASE   0x4E000000  //Nand Flash配置寄存器基地址
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int  *)(x))
#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))  //Nand片选使能
#define NAND_CHIP_DISABLE (NFCONT |= (1<<1))   //取消Nand片选
#define NAND_CLEAR_RB     (NFSTAT |= (1<<2))
#define NAND_DETECT_RB    { while(! (NFSTAT&(1<<2)) );}

#define NAND_SECTOR_SIZE 512
#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; //地址或长度不对齐
   }
      NAND_CHIP_ENABLE; //选中Nand片选
    for(i=start_addr; i < (start_addr + size);)
    {
        //发出READ0指令
     NAND_CLEAR_RB;
        NFCMD = 0;
        //对Nand进行寻址
     NFADDR = i & 0xFF;
        NFADDR = (i >> 9) & 0xFF;
        NFADDR = (i >> 17) & 0xFF;
        NFADDR = (i >> 25) & 0xFF;
        NAND_DETECT_RB;
        for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
        {
            *buf = (NFDATA & 0xFF);
            buf++;
        }
    }
    NAND_CHIP_DISABLE; //取消片选信号
    return 0;
}

然后,在board/samsung/my2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下: COBJS    := my2440.o flash.o nand_read.o

修改cpu/arm920t/u-boot.lds
.text :
{
    cpu/arm920t/start.o    (.text)
    board/samsung/my2440/lowlevel_init.o (.text)   //添加
    board/samsung/my2440/nand_read.o (.text)  //添加
    *(.text)
}

移植到这里,nandflash终端会有输出,但是尚不能使用nand help命令
 楼主| xiang8000 发表于 2010-10-3 10:42:31 | 显示全部楼层
本帖最后由 xiang8000 于 2010-10-3 10:46 编辑

实现对nand的操作,应该就是添加能够使用nand help之类的命令
#gedit drivers/mtd/nand/s3c2440_nand.c   //新建s3c2440_nand.c文件

#include <common.h>
#if 0
#define DEBUGN    printf
#else
#define DEBUGN(x, args ...) {}
#endif

#include <nand.h>
#include <s3c2410.h>
#include <asm/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;
    S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_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_byte and write_byte are default */
    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c2440_hwcontrol;
    nand->dev_ready = s3c2440_dev_ready;
    return 0;
}

其次,在开发板配置文件include/configs/my2440.h文件中定义支持Nand操作的相关宏,如下: #gedit include/configs/my2440.h

/* Command line configuration. */
#define CONFIG_CMD_NAND
#define CONFIG_CMDLINE_EDITING

#ifdef CONFIG_CMDLINE_EDITING
#undef CONFIG_AUTO_COMPLETE
#else
#define CONFIG_AUTO_COMPLETE
#endif

/* NAND flash settings */
#if defined(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 NAND_SAMSUNG_LP_OPTIONS       1  //注意:我们这里是64M的Nand Flash,所以不用,如果是128M的大块Nand Flash,则需加上
#endif

在drivers/mtd/nand/Makefile文件中添加s3c2440_nand.c的编译项,如下: # gedit drivers/mtd/nand/Makefile

COBJS-y += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

命令支持添加完了,然后就是修改环境变量的保存
#gedit include/configs/my2440.h
//注释掉环境变量保存到Flash的宏(注意:如果你要使用上一篇中的从Nor启动的saveenv命令,则要恢复这些Flash宏定义)
//#define CONFIG_ENV_IS_IN_FLASH 1
//#define CONFIG_ENV_SIZE      0x10000 /* Total Size of Environment Sector */
//添加环境变量保存到Nand的宏(注意:如果你要使用上一篇中的从Nor启动的saveenv命令,则不要这些Nand宏定义)
#define CONFIG_ENV_IS_IN_NAND  1
#define CONFIG_ENV_OFFSET      0x30000 //将环境变量保存到nand中的0x30000位置
#define CONFIG_ENV_SIZE        0x10000 /* Total Size of Environment Sector */
所有移植结束,能使用nand help 命令,但其它却不行,保存环境变量也仍然是 norflash
 楼主| xiang8000 发表于 2010-10-3 10:48:02 | 显示全部楼层
这个问题困扰我很久了……望指教!万分感激!(QQ:19553580)
maylag 发表于 2010-10-12 14:18:14 | 显示全部楼层
2# xiang8000


不知道您的问题解决没有?您试试改改twrph0  twrph1   tacls  这三个参数的值,启动代码和board_nand_init函数中的都改改。
machoe 发表于 2010-10-12 18:53:08 | 显示全部楼层
你这种提问方法不太好,如果要描述的比较多,没关系,希望你最后总结一下,列出1.2.3.你想达到什么情况,而出现了什么情况,像你这么长的贴,我要读好久的。最后只看了你一句,saveenv的问题,这个函数你可以参考一下,天嵌的代码,里面写的很清楚。天嵌的就是保存是nandflash中的。
 楼主| xiang8000 发表于 2010-10-12 23:20:13 | 显示全部楼层
谢谢二位的指点,以后我会注意自己对问题的描述的,尽量不给大家带来阅读的麻烦,真诚的感谢二位的回复,我试试先
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-5-22 16:23 , Processed in 1.062500 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表