flash的dma操作
nand_init()
{
writel(FIO_DMACTR_REG,(readl(FIO_DMACTR_REG) & 0xcfffffff);
writel(NAND_CTR_REG,readl(NAND_CTR_REG)|NAND_CTR_I4);
nand_wait_cmd_done(NAND_CMD_RESET);
nand_wait_cmd_done(NAND_CMD_READID);
id = readl(NAND_ID_REG);
}
void nand_wait_cmd_done(u32 cmd)
{
writel(NAND_CMD_REG,cmd);
rct_timer2_reset_count();
while(1)
{
if(readl(NAND_INT_REG) & NAND_INT_DI)
{
break;
}
if(rct_timer2_get_count() >= NAND_CMD_TIMEOUT)
{
putstr("nand cmd timeout:");
puthex(cmd);
putstr("
");
while(1);
}
}
writel(NAND_INT_REG,0x0);
}
nand_reset()
{
setbitsl(FIO_CTR_REG,FIO_CTR_RR);
rct_timer2_dly_ms(1);
clrbitsl(FIO_CTR_REG,FIO_CTR_RR);
writel(FIO_DMASTA_REG,0x0);
writel(FIO_DMACTR_REG,FIO_DMACTR_FL | FIO_DMACTR_TS4B);
writel(NAND_CTR_REG,flnand.control);
writel(NAND_INT_REG,0x0);
writel(NAND_TIM0_REG,flnand.timing0);
........
return 0;
}
#define NAND_TCLS 12
#define NAND_TALS 12
#define NAND_TCS 20
#define NAND_TDS 12
#define NAND_TCLH 5
#define NAND_TALH 5
#define NAND_TCH 5
#define NAND_TDH 5
#define NAND_TWP 12
#define NAND_TWH 10
#define NAND_TWB 100
#define NAND_TRR 20
#define NAND_TRP 12
#define NAND_TREH 10
#define NAND_TRB 100 /*not defined in datasheet*/
#define NAND_TCEH 40 /*trhz - tchz = 60 - 20 = 40*/
#define NAND_TRDELAY 20 /*trea*/
#define NAND_TCLR 10
#define NAND_TWHR 60
#define NAND_TIR 0
#define NAND_TWW 100
#define NAND_TRHZ 60
#define NAND_TAR 10
#define NAND_TRHW 30
#define NAND_TADL 100 /*not defined in datasheet*/
#define NAND_TCRL 5 /*tcea - trea = 2*/
nand_control寄存器需要指定的功能位:
C2:列地址周期为2 2048-bytes pages
I4:ID读取需4个cycle
RC:read-confirm
CC:copy-confirm
IE:interrupt-enable
SZ:flash chip size 1G bit
EB:External banks 表面外部一共挂载的nandflash个数
WD:data bus width 8bit
/**
*Read data from NAND flash to memory
*dst - address in dram
*src - address in nand device
*len - length to be read from nand
*return - length of read data
*/
int nand_read_data(u8 *dst, u8 *src, int len)
{
val = src;
block = val / flnand.block_size;
val -= block * flnand.block_size;
page = val / flnand.main_size;
pos = val % flnand.main_size;
pages = len / flnand.main_size;
if(pos == 0)
{
first_ppage_size = 0;
}
else
{
first_ppage_size = flnand.main_size - pos;
}
if(len >= first_ppage_size)
{
pages = (len - first_ppage_size) / flnand.main_size;
last_ppage_size = (len - first_ppage_size) % flnand.main_size;
}
else
{
first_ppage_size = len;
pages = 0;
last_ppage_seze = 0;
}
if(len != first_ppage_size + pages * flnand.main_size + last_ppage_size)
{
return -1;
}
len = 0;
if(first_ppage_size)
{
rval = nand_read(block,page,1,buffer);
if(rval < 0)
{
return len;
}
memcpy(dst, (void *)(buffer + pos), first_ppage_size);
dst += first_ppage_size;
len += first_ppage_size;
nand_get_affset_adr(&block, &page, 1, rval);
}
if(pages > 0)
{
rval = nand_read(block, page, pages, dst);
if(rval < 0)
{
return len;
}
dst += pages * flnand.main_size;
len += pages * flnand.main_size;
nand_get_offset_adr(&block, &page, pages, rval);
}
if(last_ppage_size > 0)
{
rval = nand_read(block, page, 1, buffer);
if(rval < 0)
{
return len;
}
memcpy(dst, (void *)buffer, last_ppage_size);
len += last_ppage_size;
}
return len;
}
void nand_get_offset_adr(u32 *block, u32 *page, u32 pages, u32 bad_blks)
{
u32 blocks;
blocks = pages / flnand.pages_per_block;
pages = pages % flnand.pages_per_block;
*block = *block + blocks;
*page += pages;
if(*page >= flnand.pages_per_block)
{
*page -= flnand.pages_per_block;
*block += 1;
}
*block += bad_blks;
}
static int nand_read(u32 block, u32 page, u32 pages, u8 *buf)
{
first_blk_pages = flnand.pages_per_block - page;
if(pages > first_blk_pages)
{
pages -= first_blk_pages;
blocks = pages / flnand.pages_per_block;
last_blk_pages = pages % flnand.pages_per_block;
}
else
{
first_blk_pages = pages;
blocks = 0;
last_blk_pages = 0;
}
if(first_blk_pages)
{
while(nand_is_bad_block(block))
{
block++;
bad_blks++;
}
rval = nand_read_pages(block, page, first_blk_pages, buf, NULL, 1);
if(rval < 0)
{
return -1;
}
block++;
buf += first_blk_pages * flnand.main_size;
}
while(blocks > 0)
{
while(nand_is_bad_block(block))
{
block++;
bad_blks++;
}
rval = nand_read_pages(block,0,flnand.pages_per_block,buf,NULL,1);
if(rval < 0)
{
return -1;
}
block++;
blocks--;
buf += flnand.block_size;
}
if(last_blk_pages)
{
while(nand_is_bad_block(block))
{
block++;
bad_blks++;
}
rval = nand_read_pages(block,0,last_blk_pages,buf,NULL,1);
if(rval < 0)
{
return -1;
}
}
return bad_blks;
}
坏块检测这里不打算展开讲,由于其实现相对简单,这里只简述下它的管理思路。
1、创建BBT(bad block table)
2、将BBT存储在flash的最后一个block的第一页(防止最后一个block为坏块,一共预留了4个block)
3、坏块分类:
1)出厂坏块,在该block的第一页的OOB区域第6个字节标记为非0xff。
2)使用中产生的坏块,可以效仿出厂坏块进行标记,但这里为了区分,在第三页和第四页的OOB区域的第6个字节进行了标记。
4、BBT和坏块之间的映射。
1)出厂坏块
bbt[block >> 2] &= ~(0x03 << ((block << 1) % 8));
2)使用中产生坏块
bbt[block >> 2] &= ~(0x01 << ((block << 1) % 8));
3)从表中找出该block是否为坏块(逆操作)
bb = (bbt[block >> 2] >> ((block << 1)
if(bb == 0x03)
{
好块
}
else if(bb == 0x02 || bb == 0x01)
{
使用中产生坏块
}
else if(bb == 0x0)
{
出厂坏块
}
DMA操作相关:
地址:0xE000_0000 - 0xE000_0FFF Flash 4-KB DMA Data FIFO
读操作时0xE000_0000作为DMA传输的源地址,buffer作为目的地址
写操作时0xE000_0000作为DMA传输的目的地址,buffer作为源地址
看完关于DMA的操作,觉得乏善可陈,按着安霸SDK提供的代码进行操作即可,没有自己可操作的需要。