最新消息:

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

C/C++ admin 2834浏览 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
#include
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))

#define NF_BASE 0x4e000000 //Nand配置寄存器基地址
#define NFCONF __REGi(NF_BASE + 0×0) //偏移后还是得到配置寄存器基地址
#define NFCONT __REGi(NF_BASE + 0×4) //偏移后得到Nand控制寄存器基地址
#define NFCMD __REGb(NF_BASE + 0×8) //偏移后得到Nand指令寄存器基地址
#define NFADDR __REGb(NF_BASE + 0xc) //偏移后得到Nand地址寄存器基地址
#define NFDATA __REGb(NF_BASE + 0×10) //偏移后得到Nand数据寄存器基地址
#define NFMECCD0 __REGi(NF_BASE + 0×14) //偏移后得到Nand主数据区域ECC0寄存器基地址
#define NFMECCD1 __REGi(NF_BASE + 0×18) //偏移后得到Nand主数据区域ECC1寄存器基地址
#define NFSECCD __REGi(NF_BASE + 0x1C) //偏移后得到Nand空闲区域ECC寄存器基地址
#define NFSTAT __REGb(NF_BASE + 0×20) //偏移后得到Nand状态寄存器基地址
#define NFSTAT0 __REGi(NF_BASE + 0×24) //偏移后得到Nand ECC0状态寄存器基地址
#define NFSTAT1 __REGi(NF_BASE + 0×28) //偏移后得到Nand ECC1状态寄存器基地址
#define NFMECC0 __REGi(NF_BASE + 0x2C) //偏移后得到Nand主数据区域ECC0状态寄存器基地址
#define NFMECC1 __REGi(NF_BASE + 0×30) //偏移后得到Nand主数据区域ECC1状态寄存器基地址
#define NFSECC __REGi(NF_BASE + 0×34) //偏移后得到Nand空闲区域ECC状态寄存器基地址
#define NFSBLK __REGi(NF_BASE + 0×38) //偏移后得到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%02xn”, 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_readyn”);
return (NFSTAT & 0×01);
}

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 0×20000
#define CONFIG_ENV_OFFSET 0×40000
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) & 0×03; /* 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(0×90); // read id command
*p=0×00 & 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) & 0×03; /* Row Address A28~A29 */
for(j=0; j<10; j++);

write_cmd(0×30);
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(0×30);
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 = 0×12345678;
if (*pdw != 0×12345678)
{
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() == 0×76 )
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中,看看效果吧!

转载请注明:爱开源 » 移植u-boot-2010.09到tq2440(三)

您必须 登录 才能发表评论!