nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
来源:互联网 发布:极乐宿舍使用软件 编辑:程序博客网 时间:2024/06/05 01:15
先初步了解下这块nand芯片:
解释:这张是该芯片结构图,4096个块,1块128页,1页4KB+218B;
片内寻址-5个周期 分列地址和行地址,自己看图
这块和另一块芯片K9GAG08U0E差不多,驱动方面几近相同,只是后者每页是8KB+436B
这里先讲一点
.至于4KB+218B中哪些是数据区 哪些是额外的,这得看ecc模块的设计者,从flash角度来看,这4K+218字节是完全等同的。而ecc模块早就被生产厂商做死,无需自行设计。
现在开始分析了。
一.s3c6410支持从SD卡启动,从SD卡启动后就可以把Uboot.bin文件写入NandFlash了,可以认真的看一下Uboot 里面 的 nand write.uboot 命令是如何把数据写入NandFlash前4页 的。写入成功后就可以从NandFlash启动Uboot。
nand write.uboot 的关键代码 位于uboot1.1.6/common/cmd_nand.c文件中:
size=4096;
nand_write(nand, off, &size, (u_char *)addr);
off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr);
off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr);
off+=4096;
addr+=2048;
nand_write(nand, off, &size, (u_char *)addr);
off+=4096;
addr+=2048;
//写剩余的页面,这里的Uboot占用1M的NandFlash地址空间,在U0D里面占用256个页面(256Page=1M),上面已经写了四个页面了,这里写剩余的252个页,252个页面足够存放Uboot的有效数据了。
size=1024*1024-4*4096;
ret = nand_write(nand, off, &size, (u_char *)addr);
}
//6410支持4K每页 只不过在nand启动时默认把前8K程序当作2K每页存取,故在nand上前16K(4个页)实际上是以每页2K存取8K的程序,其余都是4K每页存取的,上述代码就是这个意思。
二.uboot1.1.6/cpu/s3c64xx/nand_cp.c 文件
#include <common.h>
#ifdef CONFIG_S3C64XX
#include <asm/io.h>
#include <linux/mtd/nand.h>
#include <regs.h>
/*
* address format地址格式
* 17 16 9 8 0
* --------------------------------------------
* | block(12bit) | page(5bit) | offset(9bit) |
* --------------------------------------------
*/
static int nandll_read_page (uchar *buf, ulong addr, int large_block)
{
int i;
int page_size = 512;
if (large_block==1)
page_size = 2048;
if (large_block==2)
page_size = 4096;//这个类型2
if(large_block==3)
page_size = 8192;
NAND_ENABLE_CE();
NFCMD_REG = NAND_CMD_READ0;
/* Write Address */5 个寻址周期,参看第一张图
NFADDR_REG = 0;
if (large_block)
NFADDR_REG = 0;
NFADDR_REG = (addr) & 0xff;
NFADDR_REG = (addr >> 8) & 0xff;
NFADDR_REG = (addr >> 16) & 0xff;
if (large_block)
NFCMD_REG = NAND_CMD_READSTART;
NF_TRANSRnB();
/* for compatibility(2460). u32 cannot be used. by scsuh */
for(i=0; i < page_size; i++) {
*buf++ = NFDATA8_REG;
}
NAND_DISABLE_CE();
return 0;
}
/*
* Read data from NAND.读数据
*/
static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
uchar *buf = (uchar *)dst_addr;
int i;
uint page_shift = 9;
if (large_block==1)
page_shift = 11;
if(large_block==2)
page_shift = 12;
/*
PAGE_SHIFT,页帧号
内核地址,无论是虚拟的还物理的,其都由两部分组成。往往是高N位是页号,低M位是页内的偏移量。
当我们将地址中的低M位偏移量抛弃不用,高N位的页号,移到右端,得到这个结果称页帧号。
宏PAGE_SHIFT, 告诉我们要右移多少位得到页帧号。至于为什么要右移12位,看第一张图。
*/
if(large_block==3)
page_shift =13;
if(large_block == 2)
{
/* Read pages */读前4页
for (i = 0; i < 4; i++, buf+=(1<<(page_shift-1))) {//buf=0xffe
nandll_read_page(buf, i, large_block);
}
/* Read pages */读后56页
for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) { //buf=0xfff,i<60
nandll_read_page(buf, i, large_block);
}
}else if(large_block == 3) //K9GAG08U0E
{
/* Read pages */
for (i = 0; i < 4; i++, buf+=(1<<(page_shift-2))) {
nandll_read_page(buf, i, large_block);
}
/* Read pages */
for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) {
nandll_read_page(buf, i, large_block);
}
}
else
{
for (i = 0; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) {
nandll_read_page(buf, i, large_block);
}
}
return 0;
}
int copy_uboot_to_ram (void)//把uboot代码写到ram中
{
int large_block = 0;
int i;
vu_char id;
NAND_ENABLE_CE();
NFCMD_REG=NAND_CMD_RESET;
NF_TRANSRnB();
NFCMD_REG = NAND_CMD_READID;
NFADDR_REG = 0x00;
NF_TRANSRnB();
/* wait for a while */
for (i=0; i<200; i++);
int factory = NFDATA8_REG;
id = NFDATA8_REG;
int cellinfo=NFDATA8_REG;
int tmp= NFDATA8_REG;
int childType=tmp & 0x03; //Page size
if (id > 0x80)
{
large_block = 1;
}
if(id == 0xd5 && childType==0x01 )
{
large_block = 2;
}else if(id == 0xd5 && childType==0x02 )
{
large_block = 3;
}
/* read NAND Block.
* 128KB ->240KB because of U-Boot size increase. by scsuh
* So, read 0x3c000 bytes not 0x20000(128KB).
*/
return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);
}
#if 1
#define REG_GPFCON (0x7F0080A0)
#define REG_GPFDAT (0x7F0080A4)
void beep(void)
{
uint reg_f_cfg=readl(REG_GPFCON) & 0x3FFFFFFF | (1<<30);
writel(reg_f_cfg,REG_GPFCON);
uint reg_f_on=readl(REG_GPFDAT) & 0xFFFF7FFF | (1<<15);
uint reg_f_off=readl(REG_GPFDAT) & 0xFFFF7FFF;
writel(reg_f_on,REG_GPFDAT);
}
#else
void beep(void)
{
}
#endif
#endif
三.现在来看nand驱动的流程 进入start.S看到这段
#ifdef CONFIG_BOOT_NAND//我们需要的
mov r0, #0x1000
bl copy_from_nand
#endif
关于copy_from_nand 具体如下:
.globl copy_from_nand
copy_from_nand:
mov r10, lr /* save return address */
mov r9, r0
/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
mov r9, #0x1000
bl copy_uboot_to_ram
3: tst r0, #0x0
bne copy_failed
ldr r0, =0x0c000000
ldr r1, _TEXT_PHY_BASE
1: ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne compare_failed /* not matched */
subs r9, r9, #4
bne 1b
4: mov lr, r10 /* all is OK */
mov pc, lr
copy_failed:
nop /* copy from nand failed */
b copy_failed
compare_failed:
nop /* compare failed */
b compare_failed
其中copy_uboot_to_ram的实现在nand_cp.c中
int copy_uboot_to_ram (void)//把uboot代码写到ram中
{
int large_block = 0;
int i;
vu_char id;
NAND_ENABLE_CE();
NFCMD_REG=NAND_CMD_RESET;
NF_TRANSRnB();
NFCMD_REG = NAND_CMD_READID;
NFADDR_REG = 0x00;
NF_TRANSRnB();
/* wait for a while */
for (i=0; i<200; i++);
int factory = NFDATA8_REG;
id = NFDATA8_REG;
int cellinfo=NFDATA8_REG;
int tmp= NFDATA8_REG;
int childType=tmp & 0x03; //Page size
if (id > 0x80)
{
large_block = 1;
}
if(id == 0xd5 && childType==0x01 )
{
large_block = 2;
}else if(id == 0xd5 && childType==0x02 )
{
large_block = 3;
}
/* read NAND Block.
* 128KB ->240KB because of U-Boot size increase. by scsuh
* So, read 0x3c000 bytes not 0x20000(128KB).
*/
return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);
}
进入board.c,arm_start中有nand_init具体实现在smdk6410.c中
void nand_init(void)
{
nand_probe(CFG_NAND_BASE);//检测芯片型号
if (nand_dev_desc[0].ChipID != NAND_ChipID_UNKNOWN)
{
print_size(nand_dev_desc[0].totlen, "\n");
}
}
#endif
四.uboot加载运行后接下来分析nand命令,我感觉这才是重点
1.先认识下主要数据结构
struct nand_flash_dev 数据结构,在/include/linux/MTD/nand.h 中
struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;
};
struct nand_chip 数据结构
该数据结构在 include/linux/mtd/nand.h 中定义
struct platform_nand_chip {
int nr_chips;
int chip_offset;
int nr_partitions;
struct mtd_partition *partitions;
struct nand_ecclayout *ecclayout;
int chip_delay;
unsigned int options;
void *priv;
};
2.查看common/cmd_nand.c 咱们来看看都有哪些命令还有这些命令怎么执行的
erase擦除操作
if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
nand_erase_options_t opts;
/* "clean" at index 2 means request to write cleanmarker */
int clean = argc > 2 && !strcmp("clean", argv[2]);
int o = clean ? 3 : 2;
int scrub = !strcmp(cmd, "scrub");
printf("\nNAND %s: ", scrub ? "scrub" : "erase");
/* skip first two or three arguments, look for offset and size */
if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
return 1;
memset(&opts, 0, sizeof(opts));
opts.offset = off;
opts.length = size;
opts.jffs2 = clean;
opts.quiet = quiet;
if (scrub) {
puts("Warning: "
"scrub option will erase all factory set "
"bad blocks!\n"
" "
"There is no reliable way to recover them.\n"
" "
"Use this command only for testing purposes "
"if you\n"
" "
"are sure of what you are doing!\n"
"\nReally scrub this NAND flash? <y/N>\n");
if (getc() == 'y' && getc() == '\r') {
opts.scrub = 1;
} else {
puts("scrub aborted\n");
return -1;
}
}
ret = nand_erase_opts(nand, &opts);
printf("%s\n", ret ? "ERROR" : "OK");
return ret == 0 ? 0 : 1;
}
重点看对yaffs2文件系统的写支持
#ifdef CFG_NAND_YAFFS_WRITE
} else if (!read && s != NULL && + (!strcmp(s, ".yaffs2") || !strcmp(s, ".yaffs1"))) {
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
opts.pad = 0;
opts.blockalign = 1;
opts.quiet = quiet;
opts.writeoob = 1;
opts.autoplace = 1;
/* jsgood */
/* if (s[6] == '1')
opts.forceyaffs = 1; */
ret = nand_write_opts(nand, &opts);
#endif
}
现在针对其中的调用处理进行详细跟踪
关于nand_write_options_t opts ;在nand.h和nand_util.c有定义
struct nand_write_options {
u_char *buffer; /* memory block containing image to write用于写镜像的内存块 */
ulong length; /* number of bytes to write描述多少字节 */
ulong offset; /* start address in NAND 烧写开始地址*/
int quiet; /* don't display progress messages 不显示烧写进度*/
int autoplace; /* if true use auto oob layout 采用自动(默认)obb布局*/
int forcejffs2; /* force jffs2 oob layout采用jffs2obb布局 */
int forceyaffs; /* force yaffs oob layout 采用yaffs布局*/
int noecc; /* write without ecc烧写时不写ecc */
int writeoob; /* image contains oob data烧写时包含obb区的数据 */
int pad; /* pad to page size 页大小*/
int blockalign; /* 1|2|4 set multiple of eraseblocks 设置擦写对齐方式
* to align to */
};
typedef struct nand_write_options nand_write_options_t;
在nand_util.c里的具体实现,好长啊。。。。//我感觉英文注释已经很给力了 我就不注释了
/**
* nand_write_opts: - write image to NAND flash with support for various options
*
* @param meminfo NAND device to erase
* @param opts write options (@see nand_write_options)
* @return 0 in case of success
*
* This code is ported from nandwrite.c from Linux mtd utils by
* Steven J. Hill and Thomas Gleixner.
*/
int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
{
int imglen = 0;
int pagelen;
int baderaseblock;
int blockstart = -1;
loff_t offs;
int readlen;
int oobinfochanged = 0;
int percent_complete = -1;
/* org: struct nand_oobinfo old_oobinfo; */
struct nand_ecclayout old_oobinfo;
ulong mtdoffset = opts->offset;
ulong erasesize_blockalign;
u_char *buffer = opts->buffer;
size_t written;
int result;
/* jsgood */
struct mtd_oob_ops oob_ops;
if (opts->pad && opts->writeoob) {
printf("Can't pad when oob data is present.\n");
return -1;
}
/* set erasesize to specified number of blocks - to match
* jffs2 (virtual) block size */
if (opts->blockalign == 0) {
erasesize_blockalign = meminfo->erasesize;
} else {
erasesize_blockalign = meminfo->erasesize * opts->blockalign;
}
/* make sure device page sizes are valid */
if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
&& !(meminfo->oobsize == 8 && meminfo->writesize == 256)
&& !(meminfo->oobsize == 64 && meminfo->writesize == 2048)
&& !(meminfo->oobsize == 128 && meminfo->writesize == 4096)
&& !(meminfo->oobsize == 232 && meminfo->writesize == 8192))
{
printf("meminfo->oobsize == %d && meminfo->writesize == %d",meminfo->oobsize,meminfo->writesize);
printf("Unknown flash (not normal NAND)\n");
return -1;
}
/* read the current oob info */
/* org: memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo)); */
memcpy(&old_oobinfo, meminfo->ecclayout, sizeof(struct nand_ecclayout));
/* write without ecc? */
if (opts->noecc) {
/* org: memcpy(&meminfo->oobinfo, &none_oobinfo,
sizeof(meminfo->oobinfo)); */
memcpy(meminfo->ecclayout, &none_oobinfo,
sizeof(struct nand_ecclayout));
oobinfochanged = 1;
printf("opts->noecc***************************\n");
}
/* autoplace ECC? */
if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
/* org: memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
sizeof(meminfo->oobinfo)); */
memcpy(meminfo->ecclayout, &autoplace_oobinfo, sizeof(struct nand_ecclayout));
oobinfochanged = 1;
printf("opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)***************************\n");
}
/* force OOB layout for jffs2 or yaffs? */
if (opts->forcejffs2 || opts->forceyaffs) {
/* org: struct nand_oobinfo *oobsel =
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; */
struct nand_ecclayout *oobsel =
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
if (meminfo->oobsize == 8) {
if (opts->forceyaffs) {
printf("YAFSS cannot operate on "
"256 Byte page size\n");
goto restoreoob;
}
/* Adjust number of ecc bytes */
jffs2_oobinfo.eccbytes = 3;
}
/* org: memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo)); */
memcpy(meminfo->ecclayout, oobsel, sizeof(struct nand_ecclayout));
printf("opts->forcejffs2 || opts->forceyaffs");
}
/* get image length */
imglen = opts->length;
pagelen = meminfo->writesize
+ ((opts->writeoob != 0) ? meminfo->oobsize : 0);
// printf("opts->writeoob=%d,meminfo->oobsize=%d.................. \n",opts->writeoob,meminfo->oobsize);
/* check, if file is pagealigned */
if ((!opts->pad) && ((imglen % pagelen) != 0)) {
printf("Input block length is not page aligned\n");
goto restoreoob;
}
/* check, if length fits into device */
if (((imglen / pagelen) * meminfo->writesize)
> (meminfo->size - opts->offset)) {
printf("Image %d bytes, NAND page %d bytes, "
"OOB area %u bytes, device size %u bytes\n",
imglen, pagelen, meminfo->writesize, meminfo->size);
printf("Input block does not fit into device\n");
goto restoreoob;
}
if (!opts->quiet)
printf("\n");
/* get data from input and write to the device */
while (imglen && (mtdoffset < meminfo->size)) {
WATCHDOG_RESET ();
/*
* new eraseblock, check for bad block(s). Stay in the
* loop to be sure if the offset changes because of
* a bad block, that the next block that will be
* written to is also checked. Thus avoiding errors if
* the block(s) after the skipped block(s) is also bad
* (number of blocks depending on the blockalign
*/
while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
blockstart = mtdoffset & (~erasesize_blockalign+1);
offs = blockstart;
baderaseblock = 0;
/* check all the blocks in an erase block for
* bad blocks */
do {
int ret = meminfo->block_isbad(meminfo, offs);
if (ret < 0) {
printf("Bad block check failed\n");
goto restoreoob;
}
if (ret == 1) {
baderaseblock = 1;
if (!opts->quiet)
printf("\rBad block at 0x%lx "
"in erase block from "
"0x%x will be skipped\n",
(long) offs,
blockstart);
}
if (baderaseblock) {
mtdoffset = blockstart
+ erasesize_blockalign;
}
offs += erasesize_blockalign
/ opts->blockalign;
} while (offs < blockstart + erasesize_blockalign);
}
readlen = meminfo->writesize;
if (opts->pad && (imglen < readlen)) {
readlen = imglen;
memset(data_buf + readlen, 0xff,
meminfo->writesize - readlen);
}
/* read page data from input memory buffer */
memcpy(data_buf, buffer, readlen);
buffer += readlen;
/* This is yaffs2 writing if opts->writeoob == 1,
* and the other case is jffs2 writing in S3C NAND by jsgood.
*/
if (opts->writeoob) {
/* read OOB data from input memory block, exit
* on failure */
memcpy(oob_buf, buffer, meminfo->oobsize);
buffer += meminfo->oobsize;
////debug
/*
int k=0;
for(k=0;k<meminfo->oobsize;k++)
{
if((k+1)%6==0)
{
printf("%x ",oob_buf[k]);
printf("\n");
}else
{
printf("%x ",oob_buf[k]);
}
}
printf("........................\n");
*/
/* write OOB data first, as ecc will be placed
* in there*/
/* org: result = meminfo->write_oob(meminfo,
mtdoffset,
meminfo->oobsize,
&written,
(unsigned char *)
&oob_buf); */
oob_ops.mode = MTD_OOB_AUTO;
oob_ops.len = meminfo->writesize;
oob_ops.ooboffs = 0;
oob_ops.ooblen = meminfo->oobsize;
oob_ops.oobbuf = (unsigned char *)&oob_buf;
oob_ops.datbuf = (unsigned char *)&data_buf;
result = meminfo->write_oob(meminfo, mtdoffset, &oob_ops);
if (result != 0) {
printf("\nMTD writeoob failure: %d\n",
result);
goto restoreoob;
}
imglen -= meminfo->oobsize;
} else {
/* write out the page data */
result = meminfo->write(meminfo,
mtdoffset,
meminfo->writesize,
&written,
(unsigned char *) &data_buf);
if (result != 0) {
printf("writing NAND page at offset 0x%lx failed\n",
mtdoffset);
goto restoreoob;
}
}
imglen -= readlen;
if (!opts->quiet) {
unsigned long long n = (unsigned long long)
(opts->length-imglen) * 100;
int percent;
do_div(n, opts->length);
percent = (int)n;
/* output progress message only at whole percent
* steps to reduce the number of messages printed
* on (slow) serial consoles
*/
if (percent != percent_complete) {
printf("\rWriting data at 0x%x "
"-- %3d%% complete.",
mtdoffset, percent);
percent_complete = percent;
}
}
mtdoffset += meminfo->writesize;
}
if (!opts->quiet)
printf("\n");
restoreoob:
if (oobinfochanged) {
/* org: memcpy(&meminfo->oobinfo, &old_oobinfo,
sizeof(meminfo->oobinfo)); */
memcpy(meminfo->ecclayout, &old_oobinfo,
sizeof(struct nand_ecclayout));
}
if (imglen > 0) {
printf("Data did not fit into device, due to bad blocks\n");
return -1;
}
/* return happy */
return 0;
}
关于menset即分配空间
下面那些参数已经在struct nand_write_options中说明了,详见上面。
五.现在开始分析nand驱动构架,所有驱动代码均位于nand中
//如果是K9GAG08U0D就用下面的obb区结构
static struct nand_ecclayout s3c_nand_oob_mlc_128_8bit = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 104,
.eccpos = {
24,25,26,27,28,29,30,31,32,33,
34,35,36,37,38,39,40,41,42,43,
44,45,46,47,48,49,50,51,52,53,
54,55,56,57,58,59,60,61,62,63,
64,65,66,67,68,69,70,71,72,73,
74,75,76,77,78,79,80,81,82,83,
84,85,86,87,88,89,90,91,92,93,
94,95,96,97,98,99,100,101,102,103,
104,105,106,107,108,109,110,111,112,113,
114,115,116,117,118,119,120,121,122,123,
124,125,126,127},
.oobfree = {
{.offset = 2,
.length = 22}}
};
//初始化代码
/*
* Board-specific NAND initialization. The following members of the
* argument are board-specific (per include/linux/mtd/nand.h):
* - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
* - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
* - hwcontrol: hardwarespecific function for accesing control-lines
* - dev_ready: hardwarespecific function for accesing device ready/busy line
* - enable_hwecc?: function to enable (reset) hardware ecc generator. Must
* only be provided if a hardware ECC is available
* - eccmode: mode of ecc, see defines
* - chip_delay: chip dependent delay for transfering data from array to
* read regs (tR)
* - options: various chip options. They can partly be set to inform
* nand_scan about special functionality. See the defines for further
* explanation
* Members with a "?" were not set in the merged testing-NAND branch,
* so they are not set here either.
*/
void board_nand_init(struct nand_chip *nand)
{
#if defined(CFG_NAND_HWECC)
int i;
u_char tmp;
u_char dev_id;
struct nand_flash_dev *type = NULL;
#endif
if (NFCONF_REG & 0x80000000)
boot_nand = 1;
else
boot_nand = 0;
NFCONT_REG &= ~NFCONT_WP;
nand->IO_ADDR_R = (void __iomem *)(NFDATA);
nand->IO_ADDR_W = (void __iomem *)(NFDATA);
nand->cmd_ctrl = s3c_nand_hwcontrol;
nand->dev_ready = s3c_nand_device_ready;
nand->scan_bbt = s3c_nand_scan_bbt;
nand->options = 0;
#if defined(CFG_NAND_FLASH_BBT)
nand->options |= NAND_USE_FLASH_BBT;
#else
nand->options |= NAND_SKIP_BBTSCAN;
#endif
#if defined(CFG_NAND_HWECC)
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.hwctl = s3c_nand_enable_hwecc;
nand->ecc.calculate = s3c_nand_calculate_ecc;
nand->ecc.correct = s3c_nand_correct_data;
// K9GAG08U0E must add below codes
{
s3c_nand_hwcontrol(0, NAND_CMD_RESET, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
}
s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
tmp = readb(nand->IO_ADDR_R); /* Maf. ID */
// printf("Manufactor ID:%x\n",tmp);
tmp = dev_id = readb(nand->IO_ADDR_R); /* Device ID */
//printf("dev_id ID:%x \n",dev_id);
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (tmp == nand_flash_ids[i].id) {
type = &nand_flash_ids[i];
break;
}
}
nand->cellinfo = readb(nand->IO_ADDR_R); /* 3rd byte */
tmp = readb(nand->IO_ADDR_R); /* 4th byte */
// printf("tmp = %x\n",tmp);
if (!type->pagesize)
{
if (((nand->cellinfo >> 2) & 0x3) == 0)
{
#if 0
nand_type = S3C_NAND_TYPE_MLC;
nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */
nand->ecc.read_page = s3c_nand_read_page_4bit;
nand->ecc.write_page = s3c_nand_write_page_4bit;
nand->ecc.size = 512;
nand->ecc.bytes = 8; /* really 7 bytes */
if ((1024 << (tmp & 0x3)) > 512)
{
nand->ecc.layout = &s3c_nand_oob_mlc_64;
#ifdef FORLINX_DEBUG
printf("Nandflash:Type=MLC ChipName:samsung-K9F2G08U0B or hynix-HY27UF082G2B \n");
#endif
}else
{
nand->ecc.layout = &s3c_nand_oob_16;
#ifdef FORLINX_DEBUG
printf("*************nand->ecc.layout = &s3c_nand_oob_mlc_16 \n");
#endif
}
#endif
nand_type = S3C_NAND_TYPE_SLC;
nand->ecc.size = 512;
nand->ecc.bytes = 4;
if ((1024 << (tmp & 0x3)) > 512)
{
nand->ecc.read_page = s3c_nand_read_page_1bit;
nand->ecc.write_page = s3c_nand_write_page_1bit;
nand->ecc.read_oob = s3c_nand_read_oob_1bit;
nand->ecc.write_oob = s3c_nand_write_oob_1bit;
nand->ecc.layout = &s3c_nand_oob_64;
#ifdef FORLINX_DEBUG
printk("Nandflash:Type=SLC ChipName:samsung-K9F2G08U0B or hynix-HY27UF082G2B \n");
#endif
} else
{
nand->ecc.layout = &s3c_nand_oob_16;
}
} else
{
nand_type = S3C_NAND_TYPE_MLC;
nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */
nand->ecc.read_page = s3c_nand_read_page_4bit;
nand->ecc.write_page = s3c_nand_write_page_4bit;
nand->ecc.size = 512;
nand->ecc.bytes = 8; /* really 7 bytes */
nand->ecc.layout = &s3c_nand_oob_mlc_64;
printf("Nandflash:ChipType=MLC ChipName=samsung-K9G8G08U0A \n");
}
} else
{
nand_type = S3C_NAND_TYPE_MLC;
nand->options |= NAND_NO_SUBPAGE_WRITE; /* NOP = 1 if MLC */
nand->ecc.read_page = s3c_nand_read_page_4bit;
nand->ecc.write_page = s3c_nand_write_page_4bit;
nand->ecc.size = 512;
nand->ecc.bytes = 8; /* really 7 bytes */
nand->ecc.layout = &s3c_nand_oob_mlc_64;
int childType=tmp & 0x03; //Page size
// printf("dev_id=%x,childType=%x \n",dev_id,childType);
if(dev_id == 0xd5 && childType==0x01)
{
//K9GAG08U0D size=2GB type=MLC Page=4K
#ifdef FORLINX_DEBUG
printf("Nandflash:ChipType= MLC ChipName=samsung-K9GAG08U0D \n");
#endif
// dg add #if 2011-11-09
#if defined(CONFIG_NAND_BL1_8BIT_ECC) && (defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430))
nand->ecc.read_page = s3c_nand_read_page_8bit;
nand->ecc.write_page = s3c_nand_write_page_8bit;
nand->ecc.size = 512;
nand->ecc.bytes = 13;
nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;//这个芯片就用这个,和内核中的分布一样
}
else if(dev_id == 0xd5 && childType==0x02)
{
//K9GAG08U0E size=2GB type=MLC Page=8K
#ifdef FORLINX_DEBUG
printf("Nandflash:ChipType= MLC ChipName=samsung-K9GAG08U0E \n");
#endif
// dg add #if 2012-03-30
#if defined(CONFIG_NAND_BL1_8BIT_ECC) && (defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430))
nand->ecc.read_page = s3c_nand_read_page_8bit;
nand->ecc.write_page = s3c_nand_write_page_8bit;
nand->ecc.size = 512;
nand->ecc.bytes = 13;
nand->ecc.layout = &s3c_nand_oob_mlc_232_8bit;
#endif
}
else
{
#ifdef FORLINX_DEBUG
printf("select s3c_nand_oob_mlc_64\n");
#endif
}
}
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
- nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
- nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(下)
- Nandflash 驱动深度分析(基于S3C2410)
- Nandflash 驱动深度分析(基于S3C2410)
- NandFlash驱动分析
- NandFlash驱动分析
- NandFlash驱动分析
- nandflash 驱动分析
- 读nandflash---根据数据手册K9GAG08U0D
- OK6410上uboot1.1.6的dm9000AE移植(续)
- NandFlash驱动超详细分析
- NandFlash驱动源码详细分析
- NandFlash驱动超详细分析
- NandFlash驱动超详细分析
- jz2440平台nandflash驱动分析
- NandFlash驱动超详细分析
- uboot1.1.6移植SDHC驱动、Fat支持
- nandflash驱动分析以及与norflash的比较 (转)
- Activity生命周期理解之一 启动一个Activity
- 常见Js复制代码
- Spring 声明式事务,propagation属性列表
- request.getParameter()和request.getAttribute()
- flex 鼠标变成手型
- nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
- thinkPHP不为人知的函数
- xsd验证xml的两种方法
- DOS命令——fc
- Android layout xml总结(2)
- 最新的超棒免费图标字体(icon font)收集
- js中innerHTML与innerText的用法与区别
- 11g R2 RAC 环境下启动闪回区域的方法
- Parameter Sniffing