📄 nanddrv.c
字号:
/*
* drivers/mtd/nand.c
*
* Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
*
* $Id: nand.c,v 1.12 2004/11/02 15:05:14 ASIC WUER
*
*
*
* Overview:
* ALL NAND operation.
*
*
*/
/*
* NAND low-level interface functions
*/
#include <stdio.h>
#include "pcdisk.h"
#include "HA_TypeDef.h"
#include "hardware.h"
#include "hardware_reg.h"
#include "lmalloc.h"
#include "stdio.h"
#include "M68328.h" //gfd
#include "nand.h"
/*
* Global variables
*/
U32 g_NIN = 0;
U32 g_NTN = 0;
//U32 g_flash_pagebuf[128]; //allocate for 512bytes
U32 g_Nand_ErrorInt;
U32 *g_flash_pagebuf=(U32 *)0x31800000;
U32 *g_flash_esrambuf = (U32 *)0x1fff3800;
/*
#define NAND_INTREP_ERROR -1;
#define NAND_WRITECHECK_ERROR -2;
#define NAND_TIMER_OUT -3;
#define NAND_OTHER_ERROR -4;
*/
///////////////////////////////////////041104 wuer
//int nor_rd_io(U16 driveno, U32 page, VOID *buffer, U16 count, int do_read);
int nand_rd_page(U32 page, U32*buffer, U32 do_read);
int nand_read_page_com (U32 page, U32 *buf);
int nand_write_page_com (U32 page, U32 *buf);
int nand_rd_block (U32 page, U32*buffer);
int nand_erase_block(U32 blockhead);
int nand_writenand_erase_block(U32 to, U32 len, U8 *buf);
int nand_read(U32 from, U32 len, U8 *buf);
void init_nand(void);
void int_serv_emi(void);
int clear(U32 tempadd, U32 num);
void ENT_INT_EMI( void );
void HA_DMA_DATADEFINE(U32 beginadd, U32 num);
unsigned long nand_psr_sysclk;
/*
* System EMI Interrupt
*/
void ENT_INT_EMI( void )
{
ent_int();
mask_irq(INT_EMI);
//ENABLE_INT;
int_serv_emi();
//DISABLE_INT;
unmask_irq(INT_EMI);
ret_int();
}
int nand_rd_page(U32 page, U32*buffer, U32 do_read)
{
U32 status,i;
U32 tempg_NIN,tempg_NTN;
U32 nand_addr = page<<9;
g_NIN = 0x0;
g_NTN = 0x0;
//printf("\tpage [%08d] [0x%08x] [%s]\n",page, (U32)buffer, do_read?"R":"Write");
while((g_NIN < 2) & (g_NTN < 3))
{
if(do_read&1)
nand_read_page_com(nand_addr,(U32*)g_flash_esrambuf);
else
{
for(i=0;i<128;i++)
{
g_flash_esrambuf[i] = buffer[i];
}
nand_write_page_com(nand_addr,(U32*)g_flash_esrambuf);
}
for(i=0;i<0x1000;i++);
if(g_NIN >= 2) return NO;
status = *(RP)GFD_NAND_IDLE;
if((status&0x1) == 0x1)
{
if(do_read&1)
{
for(i=0;i<128;i++)
{
buffer[i] = g_flash_esrambuf[i];
}
return YES; //read success!
}
else
{
tempg_NIN = g_NIN; //aviod g_var be changed!
tempg_NTN = g_NTN;
//for(i=0;i<128;i++) g_flash_pagebuf[i] = 0;
status = nand_rd_page(page,g_flash_pagebuf,0x1);
g_NIN = tempg_NIN;
g_NTN = tempg_NTN;
if( status == 1 )
{
for(i=0; i<128; i++)
{
if(g_flash_pagebuf[i] !=buffer[i])
{
printf("error address is NO 0x%x word in page 0x%x!\n",i,page);
printf("Value at g_flash_pagebuf[0x%08x] is 0x%x \n and at buffer[0x%08x] is 0x%x\n",g_flash_pagebuf[i],buffer[i]);
return 0;
}
}
return YES; //write success!
}
else
return NO; //write Ok, but reread fail!
}
}
else
{
for(i=0;i<0x1000;i++);
g_NTN ++;
}
}
if(g_NTN >= 3) return NO;
}
int nand_erase_block(U32 page)
{
U32 j,counter = 0x0;
/* Do not allow erase past end of device */
U32 blockhead = (U32)(page<<9);
//printf("E: p[%04d]\n",page);
//if(page == 2208)
//printf("E:\n");
g_NIN = 0x0;
g_NTN = 0x0;
while((g_NIN < 2) & (g_NTN < 3))
{
/*erase action now!*/
*(RP)(GFD_NAND_CONF) = 0x00100aaa; // 3 addresses modle
*(RP)GFD_NAND_ADDR = (U32)(blockhead >> 9);
*(RP)EMIADDR_NANDCOM = NAND_CMD_ERASE1;
for(j=0;j<0x1000;j++);
if(g_NIN >= 2) return NO;
j = *(RP)GFD_NAND_IDLE;
if((j&0x1) == 0x1) return YES;
else
{
j = *(volatile unsigned int *)GFD_NAND_IDLE;
counter++;
if(counter > 10000)
break;
}
g_NTN ++;
}
if(g_NTN >= 3) return NO;
return 0;
}
int nand_read_page_com (U32 from, U32 *buf)
{
*(RP)GFD_NAND_ADDR = ((U32)from) >> 1; //address config according to EMI refference
*(RP)GFD_NAND_CONF = 0x2200aaa; // Nand 4 address mode config
*(RP)DMACC0SrcAddr = GFD_NAND_DATA; //Nand data register is the source address of DMA
*(RP)DMACC0DestAddr = (U32)buf; //data buffer is the target address of DMA
*(RP)DMACC0Control = 0x20249b; //word-word burst=4 size=128words
*(RP)DMACC0Configuration = 0x31d; //enable DMA channel
*(RP)GFD_NAND_COM = (NAND_CMD_READ0 ); //send the read command, transportation begin now!!
return 0;
}
int nand_write_page_com(U32 to, U32 *buf)
{
*(RP)GFD_NAND_ADDR = ((U32)to) >> 1; //address config according to EMI refference
*(RP)GFD_NAND_CONF = 0x02200aaa; // Nand 4 address mode config
*(RP)DMACC0SrcAddr = (U32)buf ; //data buffer is the source address of DMA
*(RP)DMACC0DestAddr = GFD_NAND_DATA; //Nand data register is the target address of DMA
*(RP)DMACC0Control = 0x0020149B; //word-word burst=4 size=128words
*(RP)DMACC0Configuration = 0x301b; //enable DMA channel
*(RP)GFD_NAND_COM = (NAND_CMD_SEQIN); //send the write command, transportation begin now!!
return 0;
}
int nand_rd_block (U32 page, U32*buffer)
{
int i;
U32 tempaddr,status;
tempaddr = (U32)buffer;
for(i=0; i<32; i++){
//printf("%d\n", i);
status = nand_rd_page(page, (U32*)tempaddr, NO);
if(status != YES) return NO;
page ++;
tempaddr += 512;
}
//printf("nand_rd_block():page [%08d] [0x%08x] [%s]\n",page, (U32)buffer, do_read?"R":"W");
return YES;
}
void init_nand(void) //Ph5 set to "1"
{
U32 tempsel,tempdata,tempdir;
tempsel = *(RP)GPIO_PH5_SEL;
tempdata = *(RP)GPIO_PH5_DATA;
tempdir = *(RP)GPIO_PH5_DIR;
tempsel |= 0x20;
tempdata |= 0x20;
tempdir &= 0xffffffdf;
*(RP)GPIO_PH5_SEL = tempsel;
*(RP)GPIO_PH5_DATA = tempdata;
*(RP)GPIO_PH5_DIR = tempdir;
*(RP)0x10000000 |= 0x20000000; //open int of EMI
unmask_irq(INT_EMI);
}
void int_serv_emi(void)
{
*(RP)GFD_NAND_INTR = 0x0UL; //clear interrupt bit
g_NIN++;
}
int clear(U32 tempadd, U32 num)
{
U32 j;
for(j = 0x0; j < num; j = j+1 )
{
*(RP)tempadd = 0x0;
tempadd = tempadd + 4;
}
return 1;
}
int nand_write_page_format(U32 page, U32*buffer, U32 do_read)
{
do_read = NO;
return nand_rd_page(page, buffer, do_read);
}
int nand_rd_io(U16 driveno, U32 page, void FAR *buffer, U16 count, int do_read)
{
U32 *pbuffer = buffer;
U32 *pdatabuf = NULL;
U16 pageoffset = 0;
U32 status = YES;
U32 i=0;
do_read &= 0x01;
if(do_read == YES){
pbuffer = buffer;
for(i=0; i<count; i++)
{
status = nand_rd_page( page, (U32 *)pbuffer, YES);
if(status != YES) return NO;
page++; pbuffer += 0x80; //one page has 512BYTES for common
}
}
else
{
status = nand_erase_block(page);
if(status != YES) return NO;
status = nand_rd_block(page, (U32 *)pbuffer);
}
//printf("nand_rd_io():page [%08d] [0x%08x] [%s]\n",page, (U32)buffer, do_read?"R":"W");
return(status);
}
INT nand_rd_open(UINT16 driveno)
{
return(YES);
}
INT nand_rd_close(UINT16 driveno)
{
return(YES);
}
INT nand_rd_raw_open(UINT16 driveno)
{
return(YES);
}
INT nand_rd_ioctl(UINT16 driveno, UINT16 command, VOID *buffer)
{
return(YES);
}
void HA_DMA_DATADEFINE(U32 beginadd, U32 num) //define a source data area,prepare to be tranfered or compared
{
U32 i; //Write (num) WORD from the start address gvined
U32 *p = (U32 *)beginadd;
for(i = 0x0; i < num/4; i = i + 1 )
{
*p++ = (U32)i;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -