NandDrv.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/*-----------------------------------------------------------------------------------*/
/* Nuvoton Technology Corporation confidential */
/* */
/* Copyright (c) 2008 by Nuvoton Technology Corporation */
/* All rights reserved */
/* */
/*-----------------------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "w55fa93_sic.h"
#include "wblib.h"
//#include "fmi.h"
//#include "gnand_global.h"
//#include "w55fa93_gnand.h"
#include "w55fa93_reg.h"
// define DATE CODE and show it when running to make maintaining easy.
#define NAND_DATE_CODE FMI_DATE_CODE
#define NAND_RESERVED_BLOCK 10
#define OPT_TWO_RB_PINS
#define OPT_FIRST_4BLOCKS_ECC4
#define OPT_SUPPORT_H27UAG8T2A
#ifdef OPT_SW_WP
#define SW_WP_DELAY_LOOP 3000
#endif
BOOL volatile _fmi_bIsNandFirstAccess = TRUE;
extern BOOL volatile _fmi_bIsSMDataReady;
INT fmiSMCheckBootHeader(INT chipSel, FMI_SM_INFO_T *pSM);
static int _nand_init0 = 0, _nand_init1 = 0;
__align(4096) UCHAR _fmi_ucSMBuffer[4096];
UINT8 *_fmi_pSMBuffer;
/* functions */
INT fmiSMCheckRB(FMI_SM_INFO_T *pSM)
{
#if 1 // no timer in it
UINT32 ii;
for (ii=0; ii<100; ii++);
while(1)
{
if(pSM == pSM0)
{
if (inpw(REG_SMISR) & SMISR_RB0_IF)
{
while(! (inpw(REG_SMISR) & SMISR_RB0) );
outpw(REG_SMISR, SMISR_RB0_IF);
return 1;
}
}
else
{
if (inpw(REG_SMISR) & SMISR_RB1_IF)
{
while(! (inpw(REG_SMISR) & SMISR_RB1) );
outpw(REG_SMISR, SMISR_RB1_IF);
return 1;
}
}
}
return 0;
#else
unsigned int volatile tick;
tick = sysGetTicks(TIMER0);
while(1)
{
if(pSM == pSM0)
{
if (inpw(REG_SMISR) & SMISR_RB0_IF)
{
while(! (inpw(REG_SMISR) & SMISR_RB0) );
outpw(REG_SMISR, SMISR_RB0_IF);
return 1;
}
}
else
{
if (inpw(REG_SMISR) & SMISR_RB1_IF)
{
while(! (inpw(REG_SMISR) & SMISR_RB1) );
outpw(REG_SMISR, SMISR_RB1_IF);
return 1;
}
}
if ((sysGetTicks(TIMER0) - tick) > 1000)
break;
}
return 0;
#endif
}
INT fmiSMCheckStatus(FMI_SM_INFO_T *pSM)
{
UINT32 status, ret;
ret = 0;
outpw(REG_SMCMD, 0x70); // Status Read command for NAND flash
status = inpw(REG_SMDATA);
if (status & BIT0) // BIT0: Chip status: 1:fail; 0:pass
{
#ifdef DEBUG
printf("NAND device status: FAIL!!\n");
#endif
sysprintf("ERROR: NAND device status: FAIL!!\n");
ret = FMI_SM_STATUS_ERR;
}
if ((status & BIT7) == 0) // BIT7: Write Protect: 1:unprotected; 0:protected
{
#ifdef DEBUG
printf("NAND device status: Write Protected!!\n");
#endif
sysprintf("WARNING: NAND device status: Write Protected!!\n");
ret = FMI_SM_STATUS_ERR;
}
return ret;
}
// SM functions
INT fmiSM_Reset(FMI_SM_INFO_T *pSM)
{
#ifdef OPT_TWO_RB_PINS
UINT32 volatile i;
if(pSM == pSM0)
outpw(REG_SMISR, SMISR_RB0_IF);
else
outpw(REG_SMISR, SMISR_RB1_IF);
outpw(REG_SMCMD, 0xff);
for (i=100; i>0; i--);
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
#else
UINT32 volatile i;
outpw(REG_SMISR, SMISR_RB0_IF);
outpw(REG_SMCMD, 0xff);
for (i=100; i>0; i--);
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
#endif // OPT_TWO_RB_PINS
}
VOID fmiSM_Initial(FMI_SM_INFO_T *pSM)
{
if (pSM->nPageSize == NAND_PAGE_8KB)
{
outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_8K);
}
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_4K);
}
else if (pSM->nPageSize == NAND_PAGE_2KB)
{
outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_2K);
}
else // pSM->nPageSize = NAND_PAGE_512B
{
outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_512);
}
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_EN); // enable ECC
if (pSM->bIsCheckECC)
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_CHK); // enable ECC check
else
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_ECC_CHK); // disable ECC check
#ifdef _SIC_USE_INT_
if ((_nand_init0 == 0) && (_nand_init1 == 0))
outpw(REG_SMIER, SMIER_DMA_IE);
#endif //_SIC_USE_INT_
// set BCH_Tx and redundant area size
outpw(REG_SMREAREA_CTL, inpw(REG_SMREAREA_CTL) & ~SMRE_MECC); // Redundant area size
if (pSM->nPageSize == NAND_PAGE_8KB)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_12 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 376); // Redundant area size
}
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
if (pSM->bIsNandECC12 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_12 is selected
#ifdef OPT_SUPPORT_H27UAG8T2A
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224);; // Redundant area size
#else
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 216);; // Redundant area size
#endif
}
else if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size
}
else
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size
}
}
else if (pSM->nPageSize == NAND_PAGE_2KB)
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
else
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
else
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 16); // Redundant area size
}
}
/*-----------------------------------------------------------------------------
* Read NAND chip ID from chip and then set pSM and NDISK by chip ID.
*---------------------------------------------------------------------------*/
INT fmiSM_ReadID(FMI_SM_INFO_T *pSM, NDISK_T *NDISK_info)
{
UINT32 tempID[5];
fmiSM_Reset(pSM);
outpw(REG_SMCMD, 0x90); // read ID command
outpw(REG_SMADDR, EOA_SM); // address 0x00
tempID[0] = inpw(REG_SMDATA);
tempID[1] = inpw(REG_SMDATA);
tempID[2] = inpw(REG_SMDATA);
tempID[3] = inpw(REG_SMDATA);
tempID[4] = inpw(REG_SMDATA);
NDISK_info->vendor_ID = tempID[0];
NDISK_info->device_ID = tempID[1];
if (tempID[0] == 0xC2)
pSM->bIsCheckECC = FALSE;
else
pSM->bIsCheckECC = TRUE;
pSM->bIsNandECC4 = FALSE;
pSM->bIsNandECC8 = FALSE;
pSM->bIsNandECC12 = FALSE;
pSM->bIsNandECC15 = FALSE;
switch (tempID[1])
{
/* page size 512B */
case 0x79: // 128M
pSM->uSectorPerFlash = 255744;
pSM->uBlockPerFlash = 8191;
pSM->uPagePerBlock = 32;
pSM->uSectorPerBlock = 32;
pSM->bIsMulticycle = TRUE;
pSM->nPageSize = NAND_PAGE_512B;
pSM->bIsNandECC4 = TRUE;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nBlockPerZone = 8192; /* blocks per zone */
NDISK_info->nPagePerBlock = 32; /* pages per block */
NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */
NDISK_info->nPageSize = 512;
break;
case 0x76: // 64M
case 0x5A: // 64M XtraROM
pSM->uSectorPerFlash = 127872;
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 32;
pSM->uSectorPerBlock = 32;
pSM->bIsMulticycle = TRUE;
pSM->nPageSize = NAND_PAGE_512B;
pSM->bIsNandECC4 = TRUE;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nPagePerBlock = 32; /* pages per block */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
NDISK_info->nPageSize = 512;
break;
case 0x75: // 32M
pSM->uSectorPerFlash = 63936;
pSM->uBlockPerFlash = 2047;
pSM->uPagePerBlock = 32;
pSM->uSectorPerBlock = 32;
pSM->bIsMulticycle = FALSE;
pSM->nPageSize = NAND_PAGE_512B;
pSM->bIsNandECC4 = TRUE;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nBlockPerZone = 2048; /* blocks per zone */
NDISK_info->nPagePerBlock = 32; /* pages per block */
NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */
NDISK_info->nPageSize = 512;
break;
case 0x73: // 16M
pSM->uSectorPerFlash = 31968; // max. sector no. = 999 * 32
pSM->uBlockPerFlash = 1023;
pSM->uPagePerBlock = 32;
pSM->uSectorPerBlock = 32;
pSM->bIsMulticycle = FALSE;
pSM->nPageSize = NAND_PAGE_512B;
pSM->bIsNandECC4 = TRUE;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nBlockPerZone = 1024; /* blocks per zone */
NDISK_info->nPagePerBlock = 32; /* pages per block */
NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */
NDISK_info->nPageSize = 512;
break;
/* page size 2KB */
case 0xf1: // 128M
case 0xd1:
pSM->uBlockPerFlash = 1023;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->uSectorPerFlash = 255744;
pSM->bIsMulticycle = FALSE;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsNandECC8 = TRUE;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nBlockPerZone = 1024; /* blocks per zone */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */
NDISK_info->nPageSize = 2048;
// 2013/10/22, support MXIC MX30LF1G08AA NAND flash
// 2015/06/22, support MXIC MX30LF1G18AC NAND flash
if ( ((tempID[0]==0xC2)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x1D)) ||
((tempID[0]==0xC2)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x95)&&(tempID[4]==0x02)) )
{
// The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only)
// So, we MUST modify the configuration of it
// 1. change pSM->bIsCheckECC to TRUE to enable ECC feature;
// 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk.
// (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2)
pSM->bIsCheckECC = TRUE;
NDISK_info->vendor_ID = 0xFF; // fake vendor_ID
}
// 2014/10/16, support Winbond W29N01GV NAND flash
if ((tempID[0]==0xEF)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x95))
{
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
}
break;
case 0xda: // 256M
if ((tempID[3] & 0x33) == 0x11)
{
pSM->uBlockPerFlash = 2047;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nBlockPerZone = 2048; /* blocks per zone */
NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x21)
{
pSM->uBlockPerFlash = 1023;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 512;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nBlockPerZone = 1024; /* blocks per zone */
NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */
}
pSM->uSectorPerFlash = 511488;
pSM->bIsMulticycle = TRUE;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsNandECC8 = TRUE;
NDISK_info->nPageSize = 2048;
break;
case 0xdc: // 512M
if ((tempID[3] & 0x33) == 0x11)
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x21)
{
pSM->uBlockPerFlash = 2047;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 512;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nBlockPerZone = 2048; /* blocks per zone */
NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */
}
pSM->uSectorPerFlash = 1022976;
pSM->bIsMulticycle = TRUE;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsNandECC8 = TRUE;
NDISK_info->nPageSize = 2048;
break;
case 0xd3:
// 2014/4/2, To support Samsung K9WAG08U1D 512MB NAND flash
if ((tempID[0]==0xEC)&&(tempID[2]==0x51)&&(tempID[3]==0x95)&&(tempID[4]==0x58))
{
pSM->uBlockPerFlash = 4095; // block index with 0-base. = physical blocks - 1
pSM->uPagePerBlock = 64;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock;
pSM->bIsMLCNand = FALSE;
pSM->bIsMulticycle = TRUE;
pSM->bIsNandECC8 = TRUE;
pSM->uSectorPerFlash = 1022976;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; // number of zones
NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone
NDISK_info->nPagePerBlock = pSM->uPagePerBlock;
NDISK_info->nPageSize = pSM->nPageSize;
NDISK_info->nLBPerZone = 4000; // logical blocks per zone
break;
}
// 2016/9/29, support MXIC MX60LF8G18AC NAND flash
if ((tempID[0]==0xC2)&&(tempID[1]==0xD3)&&(tempID[2]==0xD1)&&(tempID[3]==0x95)&&(tempID[4]==0x5A))
{
// The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only)
// So, we MUST modify the configuration of it
// 1. change pSM->bIsCheckECC to TRUE to enable ECC feature;
// 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk.
// (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2)
pSM->bIsCheckECC = TRUE;
NDISK_info->vendor_ID = 0xFF; // fake vendor_ID
}
if ((tempID[3] & 0x33) == 0x32)
{
pSM->uBlockPerFlash = 2047;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 1024; /* 128x8 */
pSM->nPageSize = NAND_PAGE_4KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 4096;
NDISK_info->nBlockPerZone = 2048; /* blocks per zone */
NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x11)
{
pSM->uBlockPerFlash = 8191;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 8192; /* blocks per zone */
NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x21)
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 512;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x22)
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 512; /* 64x8 */
pSM->nPageSize = NAND_PAGE_4KB;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nPageSize = 4096;
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
}
pSM->uSectorPerFlash = 2045952;
pSM->bIsMulticycle = TRUE;
pSM->bIsNandECC8 = TRUE;
break;
case 0xd5: // 2048M
#ifdef OPT_SUPPORT_H27UAG8T2A
if ((tempID[0]==0xAD)&&(tempID[2] == 0x94)&&(tempID[3] == 0x25))
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 1024; /* 128x8 */
pSM->nPageSize = NAND_PAGE_4KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 4096;
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
pSM->uSectorPerFlash = 4091904;
pSM->bIsMulticycle = TRUE;
pSM->bIsNandECC12 = TRUE;
break;
}
else
{
if ((tempID[3] & 0x33) == 0x32)
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 1024; /* 128x8 */
pSM->nPageSize = NAND_PAGE_4KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 4096;
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x11)
{
pSM->uBlockPerFlash = 16383;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 16384; /* blocks per zone */
NDISK_info->nLBPerZone = 16000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x21)
{
pSM->uBlockPerFlash = 8191;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 512;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 8192; /* blocks per zone */
NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */
}
pSM->uSectorPerFlash = 4091904;
pSM->bIsMulticycle = TRUE;
pSM->bIsNandECC8 = TRUE;
break;
}
#else
if ((tempID[3] & 0x33) == 0x32)
{
pSM->uBlockPerFlash = 4095;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 1024; /* 128x8 */
pSM->nPageSize = NAND_PAGE_4KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 4096;
NDISK_info->nBlockPerZone = 4096; /* blocks per zone */
NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x11)
{
pSM->uBlockPerFlash = 16383;
pSM->uPagePerBlock = 64;
pSM->uSectorPerBlock = 256;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = FALSE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 64; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 16384; /* blocks per zone */
NDISK_info->nLBPerZone = 16000; /* logical blocks per zone */
}
else if ((tempID[3] & 0x33) == 0x21)
{
pSM->uBlockPerFlash = 8191;
pSM->uPagePerBlock = 128;
pSM->uSectorPerBlock = 512;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->bIsMLCNand = TRUE;
NDISK_info->NAND_type = NAND_TYPE_MLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ;
NDISK_info->nZone = 1; /* number of zones */
NDISK_info->nPagePerBlock = 128; /* pages per block */
NDISK_info->nPageSize = 2048;
NDISK_info->nBlockPerZone = 8192; /* blocks per zone */
NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */
}
pSM->uSectorPerFlash = 4091904;
pSM->bIsMulticycle = TRUE;
pSM->bIsNandECC8 = TRUE;
break;
#endif
default:
// 2013/9/25, support MXIC MX30LF1208AA NAND flash
if ((tempID[0]==0xC2)&&(tempID[1]==0xF0)&&(tempID[2]==0x80)&&(tempID[3]==0x1D))
{
pSM->uBlockPerFlash = 511; // block index with 0-base. = physical blocks - 1
pSM->uPagePerBlock = 64;
pSM->nPageSize = NAND_PAGE_2KB;
pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock;
pSM->bIsMLCNand = FALSE;
pSM->bIsMulticycle = FALSE;
pSM->bIsNandECC8 = TRUE;
NDISK_info->NAND_type = NAND_TYPE_SLC;
NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ;
NDISK_info->nZone = 1; // number of zones
NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone
NDISK_info->nPagePerBlock = pSM->uPagePerBlock;
NDISK_info->nPageSize = pSM->nPageSize;
// why nLBPerZone is not 512 ? sicSMInit() had reserved %2 blocks for bad block base on this value.
NDISK_info->nLBPerZone = 500; // logical blocks per zone
pSM->uSectorPerFlash = pSM->uSectorPerBlock * NDISK_info->nLBPerZone / 1000 * 999;
// The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only)
// So, we MUST modify the configuration of it
// 1. change pSM->bIsCheckECC to TRUE to enable ECC feature;
// 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk.
// (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2)
pSM->bIsCheckECC = TRUE;
NDISK_info->vendor_ID = 0xFF; // fake vendor_ID
break;
}
sysprintf("ERROR: SM ID not support!! [%02x][%02x][%02x][%02x][%02x]\n", tempID[0], tempID[1], tempID[2], tempID[3], tempID[4]);
return FMI_SM_ID_ERR;
}
sysprintf("NAND: Found %s NAND, ID [%02x][%02x][%02x][%02x][%02x], page size %d, BCH T%d\n",
pSM->bIsMLCNand ? "MLC" : "SLC",
tempID[0], tempID[1], tempID[2], tempID[3], tempID[4],
pSM->nPageSize,
pSM->bIsNandECC4*4 + pSM->bIsNandECC8*8 + pSM->bIsNandECC12*12 + pSM->bIsNandECC15*15
);
return 0;
}
INT fmiSM2BufferM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCMD, 0x00); // read command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
}
INT fmiSM2BufferM_RA(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCMD, 0x50); // read command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
}
INT fmiSMECCErrCount(UINT32 ErrSt, BOOL bIsECC8)
{
unsigned int volatile errCount;
if ((ErrSt & 0x02) || (ErrSt & 0x200) || (ErrSt & 0x20000) || (ErrSt & 0x2000000))
{
#ifdef DEBUG
printf("uncorrectable!![0x%x]\n", ErrSt);
#endif
return FMI_SM_ECC_ERROR;
}
if (ErrSt & 0x01)
{
errCount = (ErrSt >> 2) & 0xf;
#ifdef DEBUG
if (bIsECC8)
printf("Field 5 have %d error!!\n", errCount);
else
printf("Field 1 have %d error!!\n", errCount);
#endif
}
if (ErrSt & 0x100)
{
errCount = (ErrSt >> 10) & 0xf;
#ifdef DEBUG
if (bIsECC8)
printf("Field 6 have %d error!!\n", errCount);
else
printf("Field 2 have %d error!!\n", errCount);
#endif
}
if (ErrSt & 0x10000)
{
errCount = (ErrSt >> 18) & 0xf;
#ifdef DEBUG
if (bIsECC8)
printf("Field 7 have %d error!!\n", errCount);
else
printf("Field 3 have %d error!!\n", errCount);
#endif
}
if (ErrSt & 0x1000000)
{
errCount = (ErrSt >> 26) & 0xf;
#ifdef DEBUG
if (bIsECC8)
printf("Field 8 have %d error!!\n", errCount);
else
printf("Field 4 have %d error!!\n", errCount);
#endif
}
return errCount;
}
static VOID fmiSM_CorrectData_BCH(UINT8 ucFieidIndex, UINT8 ucErrorCnt, UINT8* pDAddr)
{
// ECC is based on 512+32, when ECC code error is encountered, we must coorect it by this base
UINT32 uaData[16], uaAddr[16];
UINT32 uaErrorData[4];
UINT8 ii, jj;
UINT32 uPageSize, spareSize;
uPageSize = inpw(REG_SMCSR) & SMCR_PSIZE;
jj = ucErrorCnt/4;
jj ++;
if (jj > 4) jj = 4;
for(ii=0; ii<jj; ii++)
{
uaErrorData[ii] = inpw(REG_BCH_ECC_DATA0 + ii*4);
}
for(ii=0; ii<jj; ii++)
{
uaData[ii*4+0] = uaErrorData[ii] & 0xff;
uaData[ii*4+1] = (uaErrorData[ii]>>8) & 0xff;
uaData[ii*4+2] = (uaErrorData[ii]>>16) & 0xff;
uaData[ii*4+3] = (uaErrorData[ii]>>24) & 0xff;
}
jj = ucErrorCnt/2;
jj ++;
if (jj > 8) jj = 8;
for(ii=0; ii<jj; ii++)
{
uaAddr[ii*2+0] = inpw(REG_BCH_ECC_ADDR0 + ii*4) & 0x1fff;
uaAddr[ii*2+1] = (inpw(REG_BCH_ECC_ADDR0 + ii*4)>>16) & 0x1fff;
}
pDAddr += (ucFieidIndex-1)*0x200;
for(ii=0; ii<ucErrorCnt; ii++)
{
if (uPageSize == PSIZE_8K)
{
switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL)
{
case BCH_T4: // 8K+256
default:
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 7 - uaAddr[ii];
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_32+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T8: // 8K+256
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 14 - uaAddr[ii];
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_4+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T12: // 8K+376
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 23*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 22 - uaAddr[ii];
uaAddr[ii] += 23*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T15:
break;
}
}
else if (uPageSize == PSIZE_4K)
{
switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL)
{
case BCH_T4: // 4K+128
default:
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 7 - uaAddr[ii];
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_16+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T8: // 4K+128
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 14 - uaAddr[ii];
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T12: // 4K+216
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 23*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 22 - uaAddr[ii];
uaAddr[ii] += 23*(ucFieidIndex-1); // field offset
#ifdef OPT_SUPPORT_H27UAG8T2A
// 4K+224
spareSize = inpw(REG_SMREAREA_CTL) & SMRE_REA128_EXT;
// *((UINT8*)REG_SMRA_10+uaAddr[ii]) ^= uaData[ii];
*((UINT8*)REG_SMRA_0+(spareSize-184)+uaAddr[ii]) ^= uaData[ii];
#else
// 4K+216
*((UINT8*)REG_SMRA_8+uaAddr[ii]) ^= uaData[ii];
#endif
}
}
break;
}
}
else if (uPageSize == PSIZE_2K)
{
switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL)
{
case BCH_T4:
default:
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 7 - uaAddr[ii];
uaAddr[ii] += 8*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_8+uaAddr[ii]) ^= uaData[ii];
}
}
break;
case BCH_T8:
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 14 - uaAddr[ii];
uaAddr[ii] += 15*(ucFieidIndex-1); // field offset
*((UINT8*)REG_SMRA_1+uaAddr[ii]) ^= uaData[ii];
}
}
break;
}
}
else
{
if (uaAddr[ii] < 512)
*(pDAddr+uaAddr[ii]) ^= uaData[ii];
else
{
if (uaAddr[ii] < 515)
{
uaAddr[ii] -= 512;
*((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii];
}
else
{
uaAddr[ii] = 543 - uaAddr[ii];
uaAddr[ii] = 7 - uaAddr[ii];
*((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii];
}
}
}
}
}
INT fmiSM_Read_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uDAddr)
{
int volatile ret=0;
UINT32 uStatus;
UINT32 uErrorCnt;
volatile UINT32 uError = 0;
outpw(REG_DMACSAR, uDAddr);
ret = fmiSM2BufferM(pSM, uSector, 0);
if (ret < 0)
return ret;
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif //_SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN);
#ifdef _SIC_USE_INT_
while(!_fmi_bIsSMDataReady);
#else
while(1)
{
if (!(inpw(REG_SMCSR) & SMCR_DRD_EN))
break;
}
#endif
if (pSM->bIsCheckECC)
{
while(1)
{
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF)
{
if (inpw(REG_SMCSR) & BCH_T4) // BCH_ECC selected
{
uStatus = inpw(REG_SM_ECC_ST0);
uStatus &= 0x3f;
if ((uStatus & 0x03)==0x01) // correctable error in 1st field
{
uErrorCnt = uStatus >> 2;
fmiSM_CorrectData_BCH(1, uErrorCnt, (UINT8*)uDAddr);
#ifdef DEBUG
printf("Field 1 have %d error!!\n", uErrorCnt);
#endif
}
else if (((uStatus & 0x03)==0x02)
||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error
{
#ifdef DEBUG
printf("SM uncorrectable error is encountered, %4x !!\n", uStatus);
#endif
uError = 1;
}
}
else
{
#ifdef DEBUG
printf("Wrong BCH setting for page-512 NAND !!\n");
#endif
uError = 2;
}
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error
}
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
{
if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) )
break;
}
}
}
else
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
if (uError)
return -1;
return 0;
}
VOID fmiBuffer2SMM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr)
{
// set the spare area configuration
/* write byte 514, 515 as used page */
outpw(REG_SMRA_0, 0x0000FFFF);
outpw(REG_SMRA_1, 0xFFFFFFFF);
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
}
INT fmiSM_Write_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uSAddr)
{
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN);
outpw(REG_DMACSAR, uSAddr);
fmiBuffer2SMM(pSM, uSector, 0);
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif // _SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN);
while(1)
{
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
#endif //_SIC_USE_INT_
break;
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMCMD, 0x10); // auto program command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("fmiSM_Write_512: data error!!\n");
#endif
return FMI_SM_STATE_ERROR;
}
return 0;
}
INT fmiSM_Read_2K(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uDAddr)
{
UINT32 uStatus;
UINT32 uErrorCnt, ii;
volatile UINT32 uError = 0;
// fmiSM_Reset(pSM);
while(inpw(REG_DMACCSR) & FMI_BUSY); // wait DMAC FMI ready;
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN);
outpw(REG_DMACSAR, uDAddr); // set DMA transfer starting address
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */
{
//printf("read: ECC error!!\n");
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
}
outpw(REG_SMCMD, 0x00); // read command
outpw(REG_SMADDR, 0); // CA0 - CA7
outpw(REG_SMADDR, 0); // CA8 - CA11
outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMCMD, 0x30); // read command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif //_SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN);
// if ((pSM->bIsCheckECC) || (inpw(REG_SMCSR)&SMCR_ECC_CHK) )
if (pSM->bIsCheckECC)
{
while(1)
{
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF)
{
uStatus = inpw(REG_SM_ECC_ST0);
for (ii=1; ii<5; ii++)
{
#if 0
if (!(uStatus & 0x03))
{
uStatus >>= 8;
continue;
}
#endif
if ((uStatus & 0x03)==0x01) // correctable error in 1st field
{
uErrorCnt = uStatus >> 2;
fmiSM_CorrectData_BCH(ii, uErrorCnt, (UINT8*)uDAddr);
#ifdef DEBUG
printf("Field %d have %d error!!\n", ii, uErrorCnt);
#endif
break;
}
else if (((uStatus & 0x03)==0x02)
||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error in 1st field
{
#ifdef DEBUG
printf("SM uncorrectable error is encountered, %4x !!\n", uStatus);
#endif
uError = 1;
break;
}
uStatus >>= 8;
}
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error
}
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
{
if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) )
break;
}
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
{
if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) )
break;
}
#endif //_SIC_USE_INT_
}
}
else
{
while(1)
{
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
if (inpw(REG_SMISR) & SMISR_DMA_IF)
{
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
break;
}
}
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
if (uError)
return -1;
return 0;
}
INT fmiSM_Read_RA(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 ucColAddr)
{
/* clear R/B flag */
// fmiSM_Reset(pSM);
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCMD, 0x00); // read command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
// outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12
outpw(REG_SMADDR, (ucColAddr >> 8) & 0xFF); // CA8 - CA12
outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMCMD, 0x30); // read command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
}
INT fmiSM_Read_RA_512(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uColumm)
{
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCMD, 0x50); // read command
outpw(REG_SMADDR, uColumm);
outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
return 0;
}
INT fmiSM_Write_2K(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
// fmiSM_Reset(pSM);
/* enable DMAC */
while(inpw(REG_DMACCSR) & FMI_BUSY); // wait DMAC FMI ready;
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN);
outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address
// set the spare area configuration
/* write byte 2050, 2051 as used page */
outpw(REG_SMRA_0, 0x0000FFFF);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN);
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */
{
//printf("error sector !!\n");
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
// outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f); // CA8 - CA11
outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif //_SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN);
while(1)
{
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
#endif //_SIC_USE_INT_
break;
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMCMD, 0x10); // auto program command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("fmiSM_Write_2K: data error!!\n");
#endif
sysprintf("ERROR: fmiSM_Write_2K() write data error on page %d since NAND status.\n", uSector);
return FMI_SM_STATE_ERROR;
}
#if 1
if (inpw(REG_SMRA_0) != 0x0000FFFF)
while(1);
#endif
return 0;
}
INT fmiSM_Write_2K_ALC(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address
// set the spare area configuration
/* write byte 2050, 2051 as used page */
outpw(REG_SMRA_0, 0x0000FFFF);
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN);
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f); // CA8 - CA11
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000); // PA16 - PA17
}
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif // _SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN);
while(1)
{
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
#endif //_SIC_USE_INT_
break;
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
{
int i;
UINT8 *u8pData;
u8pData = (UINT8 *)REG_SMRA_0;
for (i=0; i<64; i++)
outpw(REG_SMDATA, *u8pData++);
}
outpw(REG_SMCMD, 0x10); // auto program command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("fmiSM_Write_2K: data error!!\n");
#endif
return FMI_SM_STATE_ERROR;
}
return 0;
}
INT fmiSM_Read_4K(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uDAddr)
{
UINT32 uStatus;
UINT32 uErrorCnt, ii, jj;
volatile UINT32 uError = 0;
outpw(REG_DMACSAR, uDAddr); // set DMA transfer starting address
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
outpw(REG_SMCMD, 0x00); // read command
outpw(REG_SMADDR, 0); // CA0 - CA7
outpw(REG_SMADDR, 0); // CA8 - CA11
outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMCMD, 0x30); // read command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif //_SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN);
if ((pSM->bIsCheckECC) || (inpw(REG_SMCSR)&SMCR_ECC_CHK) )
{
while(1)
{
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF)
{
for (jj=0; jj<2; jj++)
{
uStatus = inpw(REG_SM_ECC_ST0+jj*4);
if (!uStatus)
continue;
for (ii=1; ii<5; ii++)
{
if (!(uStatus & 0x03))
{
uStatus >>= 8;
continue;
}
if ((uStatus & 0x03)==0x01) // correctable error in 1st field
{
uErrorCnt = uStatus >> 2;
fmiSM_CorrectData_BCH(jj*4+ii, uErrorCnt, (UINT8*)uDAddr);
#ifdef DEBUG
printf("Field %d have %d error!!\n", jj*4+ii, uErrorCnt);
#endif
break;
}
else if (((uStatus & 0x03)==0x02)
||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error in 1st field
{
#ifdef _DEBUG
printf("SM uncorrectable BCH error is encountered !!\n");
#endif
uError = 1;
break;
}
uStatus >>= 8;
}
}
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error
}
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
{
if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) )
break;
}
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
{
if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) )
break;
}
#endif //_SIC_USE_INT_
}
}
else
{
while(1)
{
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
if (inpw(REG_SMISR) & SMISR_DMA_IF)
{
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
break;
}
}
}
if (uError)
return -1;
return 0;
}
INT fmiSM_Write_4K(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address
// set the spare area configuration
/* write byte 2050, 2051 as used page */
outpw(REG_SMRA_0, 0x0000FFFF);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN);
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
// outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12
outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA12
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif //_SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN);
while(1)
{
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
#endif //_SIC_USE_INT_
break;
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMCMD, 0x10); // auto program command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("fmiSM_Write_4K: data error!!\n");
#endif
return FMI_SM_STATE_ERROR;
}
return 0;
}
INT fmiSM_Write_4K_ALC(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr)
{
outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address
// set the spare area configuration
/* write byte 2050, 2051 as used page */
outpw(REG_SMRA_0, 0x0000FFFF);
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN);
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
#ifdef _SIC_USE_INT_
_fmi_bIsSMDataReady = FALSE;
#endif // _SIC_USE_INT_
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN);
while(1)
{
#ifdef _SIC_USE_INT_
if (_fmi_bIsSMDataReady)
#else
if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer.
#endif //_SIC_USE_INT_
break;
}
outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag
{
int i;
UINT8 *u8pData;
u8pData = (UINT8 *)REG_SMRA_0;
for (i=0; i<218; i++)
outpw(REG_SMDATA, *u8pData++);
}
outpw(REG_SMCMD, 0x10); // auto program command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("fmiSM_Write_2K: data error!!\n");
#endif
return FMI_SM_STATE_ERROR;
}
return 0;
}
// mhkuo
INT fmiCheckInvalidBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo)
{
int volatile status=0;
unsigned int volatile sector;
unsigned char volatile data512=0xff, data517=0xff, blockStatus=0xff;
if (BlockNo == 0)
return 0;
sector = BlockNo * pSM->uPagePerBlock;
if (pSM->nPageSize == NAND_PAGE_512B)
status = fmiSM2BufferM_RA(pSM, sector, 0);
else
status = fmiSM_Read_RA(pSM, sector, pSM->nPageSize);
if (status < 0)
{
#ifdef DEBUG
printf("fmiCheckInvalidBlock 0x%x\n", status);
#endif
return 1;
}
if (pSM->nPageSize == NAND_PAGE_512B)
{
data512 = inpw(REG_SMDATA) & 0xff;
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA) & 0xff;
// if ((data512 != 0xFF) || (data517 != 0xFF))
if ((data512 == 0xFF) && (data517 == 0xFF))
{
fmiSM_Reset(pSM);
status = fmiSM2BufferM_RA(pSM, sector+1, 0);
if (status < 0)
{
#ifdef DEBUG
printf("fmiCheckInvalidBlock 0x%x\n", status);
#endif
return 1;
}
data512 = inpw(REG_SMDATA) & 0xff;
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA) & 0xff;
if ((data512 != 0xFF) || (data517 != 0xFF))
{
fmiSM_Reset(pSM);
return 1; // invalid block
}
}
else
{
fmiSM_Reset(pSM);
return 1; // invalid block
}
}
else
{
blockStatus = inpw(REG_SMDATA) & 0xff;
if (blockStatus == 0xFF)
{
fmiSM_Reset(pSM);
if (pSM->bIsMLCNand == TRUE)
sector = (BlockNo+1) * pSM->uPagePerBlock - 1;
else
sector++;
status = fmiSM_Read_RA(pSM, sector, pSM->nPageSize);
if (status < 0)
{
#ifdef DEBUG
printf("fmiCheckInvalidBlock 0x%x\n", status);
#endif
return 1;
}
blockStatus = inpw(REG_SMDATA) & 0xff;
if (blockStatus != 0xFF)
{
fmiSM_Reset(pSM);
return 1; // invalid block
}
}
else
{
fmiSM_Reset(pSM);
return 1; // invalid block
}
}
fmiSM_Reset(pSM);
return 0;
}
static void sicSMselect(INT chipSel)
{
if (chipSel == 0)
{
outpw(REG_GPDFUN, inpw(REG_GPDFUN) | 0x0003CC00); // enable NAND NWR/NRD/RB0 pins
outpw(REG_GPEFUN, inpw(REG_GPEFUN) | 0x00F30000); // enable NAND ALE/CLE/CS0 pins
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_CS0);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_CS1);
}
else
{
outpw(REG_GPDFUN, inpw(REG_GPDFUN) | 0x0003F000); // enable NAND NWR/NRD/RB1 pins
outpw(REG_GPEFUN, inpw(REG_GPEFUN) | 0x00FC0000); // enable NAND ALE/CLE/CS1 pins
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_CS1);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_CS0);
}
//--- 2014/2/26, Reset SD controller and DMAC to keep clean status for next access.
// Reset DMAC engine and interrupt satus
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_SWRST | DMAC_EN);
while(inpw(REG_DMACCSR) & DMAC_SWRST);
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN);
outpw(REG_DMACISR, WEOT_IF | TABORT_IF); // clear all interrupt flag
// Reset FMI engine and interrupt status
outpw(REG_FMICR, FMI_SWRST);
while(inpw(REG_FMICR) & FMI_SWRST);
outpw(REG_FMIISR, FMI_DAT_IF); // clear all interrupt flag
// Reset NAND engine and interrupt status
outpw(REG_FMICR, FMI_SM_EN);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_SM_SWRST);
while(inpw(REG_SMCSR) & SDCR_SWRST);
outpw(REG_SMISR, 0xFFFFFFFF); // clear all interrupt flag
}
static INT fmiNormalCheckBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo)
{
int volatile status=0;
unsigned int volatile sector;
unsigned char data, data517;
_fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);
/* MLC check the 2048 byte of last page per block */
if (pSM->bIsMLCNand == TRUE)
{
if (pSM->nPageSize == NAND_PAGE_2KB)
{
sector = (BlockNo+1) * pSM->uPagePerBlock - 1;
/* Read 2048 byte */
status = fmiSM_Read_RA(pSM, sector, 2048);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data != 0xFF)
return 1; // invalid block
}
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
sector = (BlockNo+1) * pSM->uPagePerBlock - 1;
/* Read 4096 byte */
status = fmiSM_Read_RA(pSM, sector, 4096);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data != 0xFF)
return 1; // invalid block
}
}
/* SLC check the 2048 byte of 1st or 2nd page per block */
else // SLC
{
sector = BlockNo * pSM->uPagePerBlock;
if (pSM->nPageSize == NAND_PAGE_4KB)
{
status = fmiSM_Read_RA(pSM, sector, 4096);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data == 0xFF)
{
#ifdef DEBUG
// printf("find bad block, check next page to confirm it.\n");
#endif
status = fmiSM_Read_RA(pSM, sector+1, 4096);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data != 0xFF)
{
#ifdef DEBUG
printf("find bad block is conformed.\n");
#endif
return 1; // invalid block
}
}
else
{
#ifdef DEBUG
printf("find bad block is conformed.\n");
#endif
return 1; // invalid block
}
}
else if (pSM->nPageSize == NAND_PAGE_2KB)
{
status = fmiSM_Read_RA(pSM, sector, 2048);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data == 0xFF)
{
#ifdef DEBUG
// printf("find bad block, check next page to confirm it.\n");
#endif
status = fmiSM_Read_RA(pSM, sector+1, 2048);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
if (data != 0xFF)
{
#ifdef DEBUG
printf("find bad block is conformed.\n");
#endif
return 1; // invalid block
}
}
else
{
#ifdef DEBUG
printf("find bad block is conformed.\n");
#endif
return 1; // invalid block
}
}
else /* page size 512B */
{
status = fmiSM2BufferM_RA(pSM, sector, 0);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA) & 0xff;
// if ((data != 0xFF) || (data517 != 0xFF))
if ((data == 0xFF) && (data517 == 0xFF))
{
fmiSM_Reset(pSM);
status = fmiSM2BufferM_RA(pSM, sector+1, 0);
if (status < 0)
{
#ifdef DEBUG
printf("fmiNormalCheckBlock 0x%x\n", status);
#endif
return 1;
}
data = inpw(REG_SMDATA) & 0xff;
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA);
data517 = inpw(REG_SMDATA) & 0xff;
if ((data != 0xFF) || (data517 != 0xFF))
{
fmiSM_Reset(pSM);
return 1; // invalid block
}
}
else
{
#ifdef DEBUG
printf("find bad block is conformed.\n");
#endif
fmiSM_Reset(pSM);
return 1; // invalid block
}
fmiSM_Reset(pSM);
}
}
return 0;
}
/* function pointer */
FMI_SM_INFO_T *pSM0=0, *pSM1=0;
static INT sicSMInit(INT chipSel, NDISK_T *NDISK_info)
{
int status=0, count;
outpw(REG_AHBCLK, inp32(REG_AHBCLK) | SIC_CKE | NAND_CKE);
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN);
outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_SWRST);
while(inpw(REG_DMACCSR) & DMAC_SWRST);
outpw(REG_FMICR, FMI_SM_EN);
if ((_nand_init0 == 0) && (_nand_init1 == 0))
{
// enable SM
/* select NAND control pin used */
// outpw(REG_SMTCR, 0x20304);
// outpw(REG_SMTCR, 0x10205);
outpw(REG_SMTCR, 0x20305);
outpw(REG_SMCSR, (inpw(REG_SMCSR) & ~SMCR_PSIZE) | PSIZE_512);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_3B_PROTECT);
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_CHK);
/* init SM interface */
#ifdef _NAND_PAR_ALC_
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN);
#ifdef DEBUG
printf("Parity only written to SM registers but not NAND !!\n");
#endif
#else
outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN);
#ifdef DEBUG
printf("Parity written to SM registers and NAND !!\n");
#endif
#endif // _NAND_PAR_ALC_
}
sicSMselect(chipSel);
if (chipSel == 0)
{
if (_nand_init0)
return 0;
pSM0 = malloc(sizeof(FMI_SM_INFO_T));
if (pSM0 == NULL)
return FMI_NO_MEMORY;
memset((char *)pSM0, 0, sizeof(FMI_SM_INFO_T));
if ((status = fmiSM_ReadID(pSM0, NDISK_info)) < 0)
{
if (pSM0 != NULL)
{
free(pSM0);
pSM0 = 0;
}
return status;
}
fmiSM_Initial(pSM0);
#ifdef OPT_SW_WP
outpw(REG_GPAFUN, inpw(REG_GPAFUN) & ~MF_GPA7); // port A7 low (WP)
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~0x0080); // port A7 low (WP)
outpw(REG_GPIOA_OMD, inpw(REG_GPIOA_OMD) | 0x0080); // port A7 output
#endif
// check NAND boot header
fmiSMCheckBootHeader(0, pSM0);
while(1)
{
if (!fmiNormalCheckBlock(pSM0, pSM0->uLibStartBlock))
break;
else
{
#ifdef DEBUG
printf("invalid start block %d\n", pSM0->uLibStartBlock);
#endif
pSM0->uLibStartBlock++;
}
}
if (pSM0->bIsCheckECC)
if (pSM0->uLibStartBlock == 0)
pSM0->uLibStartBlock++;
NDISK_info->nStartBlock = pSM0->uLibStartBlock; /* available start block */
pSM0->uBlockPerFlash -= pSM0->uLibStartBlock;
count = NDISK_info->nBlockPerZone * 2 / 100 + NAND_RESERVED_BLOCK;
NDISK_info->nBlockPerZone = (NDISK_info->nBlockPerZone * NDISK_info->nZone - NDISK_info->nStartBlock) / NDISK_info->nZone;
NDISK_info->nLBPerZone = NDISK_info->nBlockPerZone - count;
NDISK_info->nNandNo = chipSel;
_nand_init0 = 1;
}
else if (chipSel == 1)
{
if (_nand_init1)
return 0;
pSM1 = malloc(sizeof(FMI_SM_INFO_T));
if (pSM1 == NULL)
return FMI_NO_MEMORY;
memset((char *)pSM1, 0, sizeof(FMI_SM_INFO_T));
if ((status = fmiSM_ReadID(pSM1, NDISK_info)) < 0)
{
if (pSM1 != NULL)
{
free(pSM1);
pSM1 = 0;
}
return status;
}
fmiSM_Initial(pSM1);
#ifdef OPT_SW_WP
outpw(REG_GPAFUN, inpw(REG_GPAFUN) & ~MF_GPA7); // port A7 low (WP)
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~0x0080); // port A7 low (WP)
outpw(REG_GPIOA_OMD, inpw(REG_GPIOA_OMD) | 0x0080); // port A7 output
#endif
// check NAND boot header
fmiSMCheckBootHeader(1, pSM1);
while(1)
{
if (!fmiNormalCheckBlock(pSM1, pSM1->uLibStartBlock))
break;
else
{
#ifdef DEBUG
printf("invalid start block %d\n", pSM1->uLibStartBlock);
#endif
pSM1->uLibStartBlock++;
}
}
if (pSM1->bIsCheckECC)
if (pSM1->uLibStartBlock == 0)
pSM1->uLibStartBlock++;
NDISK_info->nStartBlock = pSM1->uLibStartBlock; /* available start block */
pSM1->uBlockPerFlash -= pSM1->uLibStartBlock;
count = NDISK_info->nBlockPerZone * 2 / 100 + NAND_RESERVED_BLOCK;
NDISK_info->nBlockPerZone = (NDISK_info->nBlockPerZone * NDISK_info->nZone - NDISK_info->nStartBlock) / NDISK_info->nZone;
NDISK_info->nLBPerZone = NDISK_info->nBlockPerZone - count;
NDISK_info->nNandNo = chipSel;
_nand_init1 = 1;
}
else
return FMI_SM_INIT_ERROR;
return 0;
}
//static INT sicSMpread(INT chipSel, INT PBA, INT page, UINT8 *buff)
INT sicSMpread(INT chipSel, INT PBA, INT page, UINT8 *buff)
{
FMI_SM_INFO_T *pSM;
int pageNo;
int status=0;
int i;
char *ptr;
#ifdef OPT_SUPPORT_H27UAG8T2A
int spareSize;
#endif
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM); //removed by mhuko
PBA += pSM->uLibStartBlock;
pageNo = PBA * pSM->uPagePerBlock + page;
#ifdef OPT_FIRST_4BLOCKS_ECC4
if (PBA <= 3)
{
#ifdef OPT_SUPPORT_H27UAG8T2A
// set to ECC8 for Block 0-3
if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */
{
if (pSM->bIsNandECC12 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size
}
}
// set to ECC4 for Block 0-3
else if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#else
// set to ECC4 for Block 0-3
if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#endif
}
#endif
if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */
{
ptr = (char *)REG_SMRA_0;
fmiSM_Read_RA(pSM, pageNo, 2048);
for (i=0; i<64; i++)
*ptr++ = inpw(REG_SMDATA) & 0xff;
status = fmiSM_Read_2K(pSM, pageNo, (UINT32)buff);
}
else if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */
{
#ifdef OPT_SUPPORT_H27UAG8T2A
spareSize = inpw(REG_SMREAREA_CTL) & SMRE_REA128_EXT;
ptr = (char *)REG_SMRA_0;
fmiSM_Read_RA(pSM, pageNo, 4096);
for (i=0; i<spareSize; i++)
*ptr++ = inpw(REG_SMDATA) & 0xff;
#else
ptr = (char *)REG_SMRA_0;
fmiSM_Read_RA(pSM, pageNo, 4096);
// for (i=0; i<216; i++)
for (i=0; i<128; i++)
*ptr++ = inpw(REG_SMDATA) & 0xff;
#endif
status = fmiSM_Read_4K(pSM, pageNo, (UINT32)buff);
}
else /* 512B */
{
ptr = (char *)REG_SMRA_0;
fmiSM_Read_RA_512(pSM, pageNo, 0);
for (i=0; i<16; i++)
*ptr++ = inpw(REG_SMDATA) & 0xff;
status = fmiSM_Read_512(pSM, pageNo, (UINT32)buff);
}
#ifdef DEBUG
if (status)
printf("read NAND page fail !!!\n");
#endif
#ifdef OPT_FIRST_4BLOCKS_ECC4
if (PBA <= 3)
{
#ifdef OPT_SUPPORT_H27UAG8T2A
// restore to ECC12
if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */
{
if (pSM->bIsNandECC12 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224); // Redundant area size
}
}
// restore to ECC8
else if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#else
if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#endif
}
#endif
// sysFlushCache(I_D_CACHE);
// sysInvalidCache();
return status;
}
//static INT sicSMpwrite(INT chipSel, INT PBA, INT page, UINT8 *buff)
INT sicSMpwrite(INT chipSel, INT PBA, INT page, UINT8 *buff)
{
FMI_SM_INFO_T *pSM;
int pageNo;
int status=0;
// sysFlushCache(D_CACHE);
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM); //removed by mhuko
PBA += pSM->uLibStartBlock;
pageNo = PBA * pSM->uPagePerBlock + page;
#ifdef OPT_FIRST_4BLOCKS_ECC4
if (PBA <= 3)
{
#ifdef OPT_SUPPORT_H27UAG8T2A
// set to ECC8 for Block 0-3
if (pSM->nPageSize == NAND_PAGE_4KB)
{
if (pSM->bIsNandECC12 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size
}
}
// set to ECC4 for Block 0-3
else if (pSM->nPageSize == NAND_PAGE_2KB)
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#else
// set to ECC4 for Block 0-3
if (pSM->nPageSize == NAND_PAGE_2KB)
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#endif
}
#endif
if (pSM->nPageSize == NAND_PAGE_2KB)
#ifdef _NAND_PAR_ALC_
status = fmiSM_Write_2K_ALC(pSM, pageNo, 0, (UINT32)buff);
#else
status = fmiSM_Write_2K(pSM, pageNo, 0, (UINT32)buff);
#endif
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
#ifdef _NAND_PAR_ALC_
status = fmiSM_Write_4K_ALC(pSM, pageNo, 0, (UINT32)buff);
#else
status = fmiSM_Write_4K(pSM, pageNo, 0, (UINT32)buff);
#endif
}
else /* 512B */
status = fmiSM_Write_512(pSM, pageNo, (UINT32)buff);
#ifdef DEBUG
if (status)
printf("write NAND page fail !!!\n");
#endif
#ifdef OPT_FIRST_4BLOCKS_ECC4
if (PBA <= 3)
{
#ifdef OPT_SUPPORT_H27UAG8T2A
// restore to ECC12
if (pSM->nPageSize == NAND_PAGE_4KB)
{
if (pSM->bIsNandECC12 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224); // Redundant area size
}
}
// restore to ECC8
else if (pSM->nPageSize == NAND_PAGE_2KB)
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#else
// restore to ECC8
if (pSM->nPageSize == NAND_PAGE_2KB)
{
if (pSM->bIsNandECC8 == TRUE)
{
outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL);
outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8);
outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size
}
}
#endif
}
#endif
return status;
}
static INT sicSM_is_page_dirty(INT chipSel, INT PBA, INT page)
{
FMI_SM_INFO_T *pSM;
int pageNo;
UINT8 data0, data1;
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM); //removed by mhuko
PBA += pSM->uLibStartBlock;
pageNo = PBA * pSM->uPagePerBlock + page;
if (pSM->nPageSize == NAND_PAGE_2KB)
fmiSM_Read_RA(pSM, pageNo, 2050);
else if (pSM->nPageSize == NAND_PAGE_4KB)
fmiSM_Read_RA(pSM, pageNo, 4098);
else if (pSM->nPageSize == NAND_PAGE_8KB)
fmiSM_Read_RA(pSM, pageNo, 8194);
else /* 512B */
fmiSM_Read_RA_512(pSM, pageNo, 2);
data0 = inpw(REG_SMDATA);
data1 = inpw(REG_SMDATA);
data1 = data1; // avoid compile warning message
if (pSM->nPageSize == NAND_PAGE_512B)
fmiSM_Reset(pSM);
if (data0 == 0x00)
return 1; // used page
else if (data0 != 0xff)
return 1; // used page
return 0; // un-used page
}
static INT sicSM_is_valid_block(INT chipSel, INT PBA)
{
FMI_SM_INFO_T *pSM;
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
PBA += pSM->uLibStartBlock;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM);
if (fmiCheckInvalidBlock(pSM, PBA) == 1) // invalid block
{
#ifdef DEBUG
printf("invalid block %d\n", PBA);
#endif
return 0;
}
else
return 1; // valid block
}
#ifdef OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL
static INT sicSMMarkBadBlock_WhileEraseFail(FMI_SM_INFO_T *pSM, UINT32 BlockNo)
{
UINT32 uSector, ucColAddr;
/* check if MLC NAND */
if (pSM->bIsMLCNand == TRUE)
{
uSector = (BlockNo+1) * pSM->uPagePerBlock - 1; // write last page
if (pSM->nPageSize == NAND_PAGE_2KB)
{
ucColAddr = 2048; // write 2048th byte
}
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
ucColAddr = 4096; // write 4096th byte
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMDATA, 0xf0); // mark bad block (use 0xf0 instead of 0x00 to differ from Old (Factory) Bad Blcok Mark)
outpw(REG_SMCMD, 0x10);
if (! fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
fmiSM_Reset(pSM);
return 0;
}
/* SLC check the 2048 byte of 1st or 2nd page per block */
else // SLC
{
uSector = BlockNo * pSM->uPagePerBlock; // write lst page
if (pSM->nPageSize == NAND_PAGE_2KB)
{
ucColAddr = 2048; // write 2048th byte
}
else if (pSM->nPageSize == NAND_PAGE_4KB)
{
ucColAddr = 4096; // write 4096th byte
}
else if (pSM->nPageSize == NAND_PAGE_512B)
{
ucColAddr = 0;
goto _mark_512;
}
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMDATA, 0xf0); // mark bad block (use 0xf0 instead of 0x00 to differ from Old (Factory) Bad Blcok Mark)
outpw(REG_SMCMD, 0x10);
if (! fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
fmiSM_Reset(pSM);
return 0;
_mark_512:
outpw(REG_SMCMD, 0x50); // point to redundant area
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, ucColAddr); // CA0 - CA7
outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMDATA, 0xf0); // 512
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xf0); // 516
outpw(REG_SMDATA, 0xf0); // 517
outpw(REG_SMCMD, 0x10);
if (! fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
fmiSM_Reset(pSM);
return 0;
}
}
#endif // OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL
INT sicSMMarkBadBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo)
{
UINT32 sector, column;
/* page 0 */
sector = BlockNo * pSM->uPagePerBlock;
column = pSM->nPageSize; // set address to begin of spare area
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, column); // CA0 - CA7
outpw(REG_SMADDR, (column >> 8) & 0x3f); // CA8 - CA12
outpw(REG_SMADDR, sector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((sector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (sector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((sector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMDATA, 0xf0); // 1st byte of spare area
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xf0);
outpw(REG_SMDATA, 0xf0); // 6th byte of spare area
outpw(REG_SMCMD, 0x10);
if (! fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
fmiSM_Reset(pSM);
/* page 1 */
sector++;
// send command
outpw(REG_SMCMD, 0x80); // serial data input command
outpw(REG_SMADDR, column); // CA0 - CA7
outpw(REG_SMADDR, (column >> 8) & 0x3f); // CA8 - CA12
outpw(REG_SMADDR, sector & 0xff); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((sector >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, (sector >> 8) & 0xff); // PA8 - PA15
outpw(REG_SMADDR, ((sector >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMDATA, 0xf0); // 512
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xff);
outpw(REG_SMDATA, 0xf0); // 516
outpw(REG_SMDATA, 0xf0); // 517
outpw(REG_SMCMD, 0x10);
if (! fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
fmiSM_Reset(pSM);
return 0;
}
static INT sicSMChangeBadBlockMark(INT chipSel)
{
int status=0;
FMI_SM_INFO_T *pSM;
_fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, 0x08);
fmiSM_Initial(pSM);
#ifndef OPT_FA93
// scan all nand chip
for (i=1; i<=pSM->uBlockPerFlash; i++)
{
if (fmiNormalCheckBlock(pSM, i)) // bad block
{
if (sicSMMarkBadBlock(pSM, i) < 0)
return FMI_SM_MARK_BAD_BLOCK_ERR;
}
}
#endif
/* read physical block 0 - image information */
status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer);
if (status < 0)
return status;
/* write specific mark */
_fmi_ucSMBuffer[pSM->nPageSize-6] = '5';
_fmi_ucSMBuffer[pSM->nPageSize-5] = '5';
_fmi_ucSMBuffer[pSM->nPageSize-4] = '0';
_fmi_ucSMBuffer[pSM->nPageSize-3] = '0';
_fmi_ucSMBuffer[pSM->nPageSize-2] = '9';
_fmi_ucSMBuffer[pSM->nPageSize-1] = '1';
// remove write "550091" in FA93
// sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_ucSMBuffer);
// status = sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_ucSMBuffer); //mhkuo@20100730
// status = sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer); //mhkuo@20100730
return status;
}
//static INT sicSMblock_erase(INT chipSel, INT PBA)
INT sicSMblock_erase(INT chipSel, INT PBA)
{
FMI_SM_INFO_T *pSM;
UINT32 page_no;
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
PBA += pSM->uLibStartBlock;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM);
if (fmiCheckInvalidBlock(pSM, PBA) != 1)
{
page_no = PBA * pSM->uPagePerBlock; // get page address
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */
{
#ifdef DEBUG
printf("erase: error sector !!\n");
#endif
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
}
outpw(REG_SMCMD, 0x60); // erase setup command
outpw(REG_SMADDR, (page_no & 0xff)); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((page_no >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, ((page_no >> 8) & 0xff)); // PA8 - PA15
outpw(REG_SMADDR, ((page_no >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMCMD, 0xd0); // erase command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("sicSMblock_erase error!!\n");
#endif
#ifdef OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL
sicSMMarkBadBlock_WhileEraseFail(pSM,PBA);
#endif
return FMI_SM_STATUS_ERR;
}
}
else
{
sysprintf("Don't erase block PBA %d since it is bad block.\n", PBA);
return FMI_SM_INVALID_BLOCK;
}
return 0;
}
/*-----------------------------------------------------------------------------
* Force to erase a block even if it is a bad block.
* INPUT:
* chipSel: 0 for NAND0 port; 1 for NAND1 port.
* PBA: physical block address include reserve area.
* OUTPUT:
* None.
* RETURN:
* 0 : erase successfully
* -1: erase fail and return error code
*---------------------------------------------------------------------------*/
INT sicSMblock_erase_test(INT chipSel, INT PBA)
{
FMI_SM_INFO_T *pSM;
UINT32 page_no;
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, 0x08);
fmiSM_Initial(pSM);
page_no = PBA * pSM->uPagePerBlock; // get page address
/* clear R/B flag */
if (pSM == pSM0)
{
while(!(inpw(REG_SMISR) & SMISR_RB0));
outpw(REG_SMISR, SMISR_RB0_IF);
}
else
{
while(!(inpw(REG_SMISR) & SMISR_RB1));
outpw(REG_SMISR, SMISR_RB1_IF);
}
if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */
{
#ifdef DEBUG
printf("erase: error sector !!\n");
#endif
outpw(REG_SMISR, SMISR_ECC_FIELD_IF);
}
outpw(REG_SMCMD, 0x60); // erase setup command
outpw(REG_SMADDR, (page_no & 0xff)); // PA0 - PA7
if (!pSM->bIsMulticycle)
outpw(REG_SMADDR, ((page_no >> 8) & 0xff)|EOA_SM); // PA8 - PA15
else
{
outpw(REG_SMADDR, ((page_no >> 8) & 0xff)); // PA8 - PA15
outpw(REG_SMADDR, ((page_no >> 16) & 0xff)|EOA_SM); // PA16 - PA17
}
outpw(REG_SMCMD, 0xd0); // erase command
if (!fmiSMCheckRB(pSM))
return FMI_SM_RB_ERR;
if (fmiSMCheckStatus(pSM) != 0)
{
#ifdef DEBUG
printf("sicSMblock_erase error!!\n");
#endif
return FMI_SM_STATUS_ERR;
}
return 0;
}
static INT sicSMchip_erase(INT chipSel)
{
int i, status=0;
FMI_SM_INFO_T *pSM;
sicSMselect(chipSel);
if (chipSel == 0)
pSM = pSM0;
else
pSM = pSM1;
// enable SM
outpw(REG_FMICR, FMI_SM_EN);
fmiSM_Initial(pSM);
// erase all chip
for (i=0; i<=pSM->uBlockPerFlash; i++)
{
status = sicSMblock_erase(chipSel, i);
if (status < 0)
sysprintf("SM block erase fail <%d>!!\n", i);
}
return 0;
}
/* driver function */
INT nandInit0(NDISK_T *NDISK_info)
{
return (sicSMInit(0, NDISK_info));
}
INT nandpread0(INT PBA, INT page, UINT8 *buff)
{
return (sicSMpread(0, PBA, page, buff));
}
INT nandpwrite0(INT PBA, INT page, UINT8 *buff)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
status = sicSMpwrite(0, PBA, page, buff);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMpwrite(0, PBA, page, buff));
#endif
}
INT nand_is_page_dirty0(INT PBA, INT page)
{
return (sicSM_is_page_dirty(0, PBA, page));
}
INT nand_is_valid_block0(INT PBA)
{
return (sicSM_is_valid_block(0, PBA));
}
INT nand_block_erase0(INT PBA)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
#if 0
sicSMselect(0);
outpw(REG_SMCMD, 0x70); // status read command
while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected
{
outpw(REG_SMCMD, 0x70); // status read command
}
#endif
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
status = sicSMblock_erase(0, PBA);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMblock_erase(0, PBA));
#endif
}
INT nand_chip_erase0(void)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
status = sicSMchip_erase(0);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMchip_erase(0));
#endif
}
INT nand_ioctl(INT param1, INT param2, INT param3, INT param4)
{
return 0;
}
INT fmiSMCheckBootHeader(INT chipSel, FMI_SM_INFO_T *pSM)
{
int fmiNandSysArea=0;
int volatile status, imageCount, i, block;
unsigned int *pImageList;
volatile int ii;
#define OPT_FOUR_BOOT_IMAGE
_fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);
pImageList = (UINT32 *)((UINT32)_fmi_ucSMBuffer | 0x80000000);
/* read physical block 0 - image information */
#ifdef OPT_FOUR_BOOT_IMAGE
for (ii=0; ii<4; ii++)
{
status = sicSMpread(chipSel, ii, pSM->uPagePerBlock-1, _fmi_pSMBuffer);
if (!status)
{
if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963))
break;
}
}
#else
status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer);
#endif
if (status < 0)
return status;
/* check specific mark */
if (pSM->nPageSize != NAND_PAGE_512B)
{
if (((_fmi_ucSMBuffer[pSM->nPageSize-6]) == '5') && ((_fmi_ucSMBuffer[pSM->nPageSize-5]) == '5') &&
((_fmi_ucSMBuffer[pSM->nPageSize-4]) == '0') && ((_fmi_ucSMBuffer[pSM->nPageSize-3]) == '0') &&
((_fmi_ucSMBuffer[pSM->nPageSize-2]) == '9') && ((_fmi_ucSMBuffer[pSM->nPageSize-1]) == '1'))
{
_fmi_bIsNandFirstAccess = FALSE;
}
else
{
sicSMChangeBadBlockMark(chipSel);
}
}
if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963))
{
fmiNandSysArea = *(pImageList+1);
}
if ((fmiNandSysArea != 0xFFFFFFFF) && (fmiNandSysArea != 0))
{
pSM->uLibStartBlock = (fmiNandSysArea / pSM->uSectorPerBlock) + 1;
}
else
{
/* read physical block 0 - image information */
#ifdef OPT_FOUR_BOOT_IMAGE
for (ii=0; ii<4; ii++)
{
status = sicSMpread(chipSel, ii, pSM->uPagePerBlock-2, _fmi_pSMBuffer);
if (!status)
{
if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963))
break;
}
}
#else
status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-2, _fmi_pSMBuffer);
#endif
if (status < 0)
return status;
if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963))
{
imageCount = *(pImageList+1);
/* pointer to image information */
pImageList = pImageList+4;
for (i=0; i<imageCount; i++)
{
block = (*(pImageList + 1) & 0xFFFF0000) >> 16;
if (block > pSM->uLibStartBlock)
pSM->uLibStartBlock = block;
/* pointer to next image */
pImageList = pImageList+12;
}
pSM->uLibStartBlock++;
}
}
return 0;
}
VOID fmiSMClose(INT chipSel)
{
if (chipSel == 0)
{
_nand_init0 = 0;
if (pSM0 != 0)
{
free(pSM0);
pSM0 = 0;
}
}
else
{
_nand_init1 = 0;
if (pSM1 != 0)
{
free(pSM1);
pSM1 = 0;
}
}
if ((_nand_init0 == 0) && (_nand_init1 == 0))
{
outpw(REG_SMCSR, inpw(REG_SMCSR)|0x06000000); // CS-0/CS-1 -> HIGH
outpw(REG_SMISR, 0xfff);
outpw(REG_FMICR, 0x00);
outpw(REG_GPDFUN, inpw(REG_GPDFUN) & ~0x0003FC00); // enable NAND NWR/NRD/RB0/RB1 pins
outpw(REG_GPEFUN, inpw(REG_GPEFUN) & ~0x00FF0000); // enable NAND ALE/CLE/CS0/CS1 pins
}
}
INT nandInit1(NDISK_T *NDISK_info)
{
return (sicSMInit(1, NDISK_info));
}
INT nandpread1(INT PBA, INT page, UINT8 *buff)
{
return (sicSMpread(1, PBA, page, buff));
}
INT nandpwrite1(INT PBA, INT page, UINT8 *buff)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
#if 0
sicSMselect(1);
outpw(REG_SMCMD, 0x70); // status read command
while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected
{
outpw(REG_SMCMD, 0x70); // status read command
}
#endif
status = sicSMpwrite(1, PBA, page, buff);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMpwrite(1, PBA, page, buff));
#endif
}
INT nand_is_page_dirty1(INT PBA, INT page)
{
return (sicSM_is_page_dirty(1, PBA, page));
}
INT nand_is_valid_block1(INT PBA)
{
return (sicSM_is_valid_block(1, PBA));
}
INT nand_block_erase1(INT PBA)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
#if 0
sicSMselect(1);
outpw(REG_SMCMD, 0x70); // status read command
while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected
{
outpw(REG_SMCMD, 0x70); // status read command
}
#endif
status = sicSMblock_erase(1, PBA);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMblock_erase(1, PBA));
#endif
}
INT nand_chip_erase1(void)
{
#ifdef OPT_SW_WP
int status;
UINT32 ii;
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP)
for (ii=0; ii<SW_WP_DELAY_LOOP; ii++);
status = sicSMchip_erase(1);
outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP)
return status;
#else
return (sicSMchip_erase(1));
#endif
}
nvtfat.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/*************************************************************************
* Nuvoton Electronics Corporation confidential
*
* Copyright (c) 2008 by Nuvoton Electronics Corporation
* All rights reserved
*
* FILENAME
* nvtfat.h
*
* REMARK
* None
**************************************************************************/
#ifndef _NVTFAT_H_
#define _NVTFAT_H_
#define MAX_PATH_LEN 520 /* maximum length of full path, counted by
character, note that one character may be
compsoed of two bytes */
#define MAX_FILE_NAME_LEN 514
/*
* Declared for pre-referenced data strucutres
*/
struct storage_driver_S;
struct physical_disk_S;
struct partition_S;
struct logical_disk_S;
struct fs_op_S;
struct file_op_S;
struct file_S;
struct file_find_S;
struct file_stat_S;
#define STORAGE_DRIVER_T struct storage_driver_S
#define PDISK_T struct physical_disk_S
#define PARTITION_T struct partition_S
#define LDISK_T struct logical_disk_S
#define DISK_OP_T struct disk_op_S
#define FILE_OP_T struct file_op_S
#define FILE_T struct file_S
#define FILE_FIND_T struct file_find_S
#define FILE_STAT_T struct file_stat_S
/*
* Include other header files
*/
#include "nvtfat_fat.h"
/*================================================= Error Code Definitions ==*/
/*--- ERROR CODEs ---*/
#define FS_OK 0
/* GENERAL ERRORs */
#define ERR_FILE_EOF 0xFFFF8200 /* end of file */
#define ERR_GENERAL_FILE_ERROR 0xFFFF8202 /* general file error */
#define ERR_NO_FREE_MEMORY 0xFFFF8204 /* no free memory */
#define ERR_NO_FREE_BUFFER 0xFFFF8206 /* no available sector buffers */
#define ERR_NOT_SUPPORTED 0xFFFF8208 /* feature or function was not supported */
#define ERR_UNKNOWN_OP_CODE 0xFFFF820A /* unrecognized operation code */
#define ERR_INTERNAL_ERROR 0xFFFF820C /* file system internal error */
#define ERR_SYSTEM_LOCK 0xFFFF820E /* file system locked by ScanDisk or Defragment */
/* FILE ERRORs */
#define ERR_FILE_NOT_FOUND 0xFFFF8220 /* file not found */
#define ERR_FILE_INVALID_NAME 0xFFFF8222 /* invalid file name */
#define ERR_FILE_INVLAID_HANDLE 0xFFFF8224 /* invalid file hFile */
#define ERR_FILE_IS_DIRECTORY 0xFFFF8226 /* try to open a directory file */
#define ERR_FILE_IS_NOT_DIRECTORY 0xFFFF8228 /* is not a directory file */
#define ERR_FILE_CREATE_NEW 0xFFFF822A /* can not create new entry */
#define ERR_FILE_OPEN_MAX_LIMIT 0xFFFF822C /* has opened too many files */
#define ERR_FILE_EXIST 0xFFFF822E /* file already exist */
#define ERR_FILE_INVALID_OP 0xFFFF8230 /* invalid file operation */
#define ERR_FILE_INVALID_ATTR 0xFFFF8232 /* invalid file attribute */
#define ERR_FILE_INVALID_TIME 0xFFFF8234 /* invalid time specified */
#define ERR_FILE_TRUNC_UNDER 0xFFFF8236 /* truncate file underflow, size < pos */
#define ERR_FILE_NO_MORE 0xFFFF8238 /* No really an error, used to identify end of file enumeration of a directory */
#define ERR_FILE_IS_CORRUPT 0xFFFF823A /* file is corrupt */
/* PATH ERRORs */
#define ERR_PATH_INVALID 0xFFFF8260 /* path name was invalid */
#define ERR_PATH_TOO_LONG 0xFFFF8262 /* path too long */
#define ERR_PATH_NOT_FOUND 0xFFFF8264 /* path not found */
/* DRIVE ERRORs */
#define ERR_DRIVE_NOT_FOUND 0xFFFF8270 /* drive not found, the disk may have been unmounted */
#define ERR_DRIVE_INVALID_NUMBER 0xFFFF8272 /* invalid drive number */
#define ERR_DRIVE_NO_FREE_SLOT 0xFFFF8274 /* can not mount more drive */
/* DIRECTORY ERRORS */
#define ERR_DIR_BUILD_EXIST 0xFFFF8290 /* try to build an already exist directory */
#define ERR_DIR_REMOVE_MISS 0xFFFF8292 /* try to remove a nonexistent directory */
#define ERR_DIR_REMOVE_ROOT 0xFFFF8294 /* try to remoe root directory */
#define ERR_DIR_REMOVE_NOT_EMPTY 0xFFFF8296 /* try to remove a non-empty directory */
#define ERR_DIR_DIFFERENT_DRIVE 0xFFFF8298 /* specified files on different drive */
#define ERR_DIR_ROOT_FULL 0xFFFF829A /* root directory full */
#define ERR_DIR_SET_SIZE 0xFFFF829C /* try to set file size of a directory */
#define ERR_DIR_MOVE_DISK 0xFFFF829E /* cannot move the whole directory from disk to another disk */
/* ACCESS ERRORs */
#define ERR_READ_VIOLATE 0xFFFF82C0 /* user has no read privilege */
#define ERR_WRITE_VIOLATE 0xFFFF82C2 /* user has no write privilege */
#define ERR_ACCESS_VIOLATE 0xFFFF82C4 /* can not access */
#define ERR_READ_ONLY 0xFFFF82C6 /* try to write a read-only file */
#define ERR_WRITE_CAP 0xFFFF82C8 /* try to write file which was opened with read-only */
#define ERR_OPEN_WRITE_OPENED 0xFFFF82CA /* try to open-write a file, which has been opened */
#define ERR_DEL_OPENED 0xFFFF82CC /* try to delete a file, which has been opened */
/* DISK ERRORs */
#define ERR_NO_DISK_MOUNT 0xFFFF8300 /* there's no any disk mounted */
#define ERR_DISK_CHANGE_DIRTY 0xFFFF8302 /* disk change, buffer is dirty */
#define ERR_DISK_REMOVED 0xFFFF8304 /* portable disk has been removed */
#define ERR_DISK_WRITE_PROTECT 0xFFFF8306 /* disk is write-protected */
#define ERR_DISK_FULL 0xFFFF8308 /* disk is full */
#define ERR_DISK_BAD_PARTITION 0xFFFF830A /* bad partition */
#define ERR_DISK_UNKNOWN_PARTITION 0xFFFF830C /* unknow or not supported partition type */
#define ERR_DISK_UNFORMAT 0xFFFF830E /* partition was not formatted */
#define ERR_DISK_UNKNOWN_FORMAT 0xFFFF8310 /* unknown disk format */
#define ERR_DISK_SECTOR_SIZE 0xFFFF8311 /* secotr size too large, not supported */
#define ERR_DISK_BAD_BPB 0xFFFF8312 /* bad BPB, disk may not be formatted */
#define ERR_DISK_IO 0xFFFF8314 /* disk I/O failure */
#define ERR_DISK_IO_TIMEOUT 0xFFFF8316 /* disk I/O time-out */
#define ERR_DISK_FAT_BAD_CLUS 0xFFFF8318 /* bad cluster number in FAT table */
#define ERR_DISK_IO_BUSY 0xFFFF831A /* I/O device is busy writing, must retry. direct-write mode only */
#define ERR_DISK_INVALID_PARM 0xFFFF831C /* invalid parameter */
#define ERR_DISK_CANNOT_LOCK 0xFFFF831E /* cannot lock disk, the disk was in-use or locked by other one */
#define ERR_DISK_PDISK_REMOVE 0xFFFF8320 /* physical disk disconnect error */
#define ERR_DISK_LDISK_REMOVE 0xFFFF8322 /* logical disk disconnect error */
/* FILE SEEK ERRORs */
#define ERR_SEEK_SET_EXCEED 0xFFFF8350 /* file seek set exceed end-of-file */
#define ERR_ACCESS_SEEK_WRITE 0xFFFF8352 /* try to seek a file which was opened for written */
/* OTHER ERRORs */
#define ERR_FILE_SYSTEM_NOT_INIT 0xFFFF83A0 /* file system was not initialized */
#define ERR_ILLEGAL_ATTR_CHANGE 0xFFFF83A2 /* illegal file attribute change */
#define ERR_CHECKDISK_FILE_OPENED 0xFFFF83A4 /* there's file opened, cannot do scandisk operation */
#define ERR_CHECKDISK_LOCK 0xFFFF83A6 /* service locked by check disk operation */
/*============================================= disk and file system types ==*/
#define FILE_SYSTEM_FAT12 12
#define FILE_SYSTEM_FAT16 16
#define FILE_SYSTEM_FAT32 32
#define FILE_SYSTEM_NTFS 64
#define FILE_SYSTEM_ISO9660 99
#define DISK_TYPE_MASK 0x00FFFFFF
#define DISK_TYPE_HARD_DISK 0x00000001
#define DISK_TYPE_RAM_DISK 0x00000002
#define DISK_TYPE_CDR 0x00000004
#define DISK_TYPE_SMART_MEDIA 0x00000008
#define DISK_TYPE_CF 0x00000010
#define DISK_TYPE_SD_MMC 0x00000020
#define DISK_TYPE_FM_CARD 0x00002000 /* A bit OR */
#define DISK_TYPE_USB_DEVICE 0x00004000 /* A bit OR */
#define DISK_TYPE_DMA_MODE 0x00008000 /* A bit OR */
#define DISK_TYPE_READ_ONLY 0x00010000
#define DISK_TYPE_SET_INSTANCE(n) (n << 24)
#define DISK_INSTANCE_IS(n) ((n >> 24) & 0xff)
#define PARTITION_TYPE_UNKNOWN 0x00
#define PARTITION_TYPE_FAT12 0x01
#define PARTITION_TYPE_FAT16_OLD 0x04
#define PARTITION_TYPE_EXTENDED_DOS 0x05
#define PARTITION_TYPE_FAT16 0x06
#define PARTITION_TYPE_NTFS 0x07
#define PARTITION_TYPE_FAT32 0x0B
#define PARTITION_TYPE_FAT32_LBA 0x0C
#define PARTITION_TYPE_FAT16_LBA 0x0E
#define PARTITION_TYPE_DOS_LBA 0x0F
#define PARTITION_TYPE_LINUX_NATIVE 0x83
/*
* Storage driver structure - Each type of media should support its own storage
* driver. The storage driver control the physical I/O access to a storage device.
*/
#undef STORAGE_DRIVER_T
STORAGE_DRIVER_T;
#define BLOCKING_WRITE 0
#define NON_BLOCKING_WRITE 1
/*
* Storage I/O control
*/
#define STORAGE_IOCTL_EJECT_DOOR 1 /* eject door */
#define STORAGE_IOCTL_CLOSE_DOOR 2 /* close door */
#define STORAGE_IOCTL_LOCK_DOOR 3 /* lock door */
#define STORAGE_IOCTL_FORMAT 11 /* format disk */
#define STORAGE_IOCTL_SPEED 21 /* speed control */
#define STORAGE_IOCTL_POWER_MODE 31 /* power saving control */
typedef struct pt_rec /* partition record */
{
UINT8 ucState; /* Current state of partition */
UINT8 uStartHead; /* Beginning of partition head */
UINT8 ucStartSector; /* Beginning of partition sector */
UINT8 ucStartCylinder; /* Beginning of partition cylinder */
UINT8 ucPartitionType; /* Partition type, refer to the subsequent definitions */
UINT8 ucEndHead; /* End of partition - head */
UINT8 ucEndSector; /* End of partition - sector */
UINT8 ucEndCylinder; /* End of partition - cylinder */
UINT32 uFirstSec; /* Number of Sectors Between the MBR and the First Sector in the Partition */
UINT32 uNumOfSecs; /* Number of Sectors in the Partition */
} PT_REC_T;
#undef PDISK_T
PDISK_T;
typedef struct partition_S
{
/* The following 16 bytes are a direct mapping of paration record */
UINT8 ucState; /* Current state of partition */
UINT8 ucStartHead; /* Beginning of partition head */
UINT8 ucStartSector; /* Beginning of partition sector */
UINT8 ucStartCylinder; /* Beginning of partition cylinder */
UINT8 ucPartitionType; /* Partition type, refer to the subsequent definitions */
UINT8 ucEndHead; /* End of partition - head */
UINT8 ucEndSector; /* End of partition - sector */
UINT8 ucEndCylinder; /* End of partition - cylinder */
UINT32 uFirstSec; /* Number of Sectors Between the MBR and the First Sector in the Partition */
UINT32 uNumOfSecs; /* Number of Sectors in the Partition */
/* Please use the followings */
INT nSectorN; /* sectors per track, -1 means unknown */
INT nHeadN; /* number of heads, -1 means unknown */
INT nCylinderN; /* number of cylinders, -1 means unknown */
UINT32 uPartRecSecN; /* logical sector number of the sector where partition record resides */
UINT32 uStartSecN; /* Beginning logical sector number of this partition */
UINT32 uTotalSecN; /* Total number of sectors in this partition */
INT nErrorCode; /* error on this partition */
LDISK_T *ptLDisk; /* the only on logical disk on this partition, if exist */
PARTITION_T *ptNextPart; /* link to the next partition */
}
#undef PARTITION_T
PARTITION_T;
/* Here the disk drive is a logical disk drive */
typedef struct logical_disk_S
{
PDISK_T *ptPDisk; /* the physical disk it was located */
INT nDriveNo; /* 'A', 'B', ... 'Z' */
UINT8 ucFileSysType;
BOOL bIsDiskRemoved; /* set is this disk has been removed but not unmounted */
CHAR szVolLabel[16];
UINT32 uDiskSize; /* disk size counted by sectors */
UINT32 uFreeSpace; /* free space counted by sectors */
FAT_INFO_T tFatInfo;
DISK_OP_T *ptDiskOP; /* disk operations */
FILE_OP_T *ptFileOP; /* file operations */
FILE_T *ptFileList; /* files opened on this disk */
LDISK_T *ptLinkForAllLDisk; /* link used for all logical disk chain */
VOID *os_mutex; /* for OS */
VOID *os_priv; /* for OS */
}
#undef LDISK_T
LDISK_T;
typedef struct fdrv_t
{
INT nDiskType;
INT nDiskInstance;
INT nDriveNo;
INT nPartitionNo;
PDISK_T *ptPDisk;
} FDRV_T;
/*
* File system operqations
* These service routines are provided by a specific file system. They are used
* to fulfill operations on a specific file system. They are system level
* operations, instead of file level operations.
*/
typedef struct disk_op_S
{
INT (*delfile)(LDISK_T *, CHAR *, CHAR *); /* delete a file */
INT (*mkdir)(LDISK_T *, CHAR *, CHAR *); /* create a new directory */
INT (*rmdir)(LDISK_T *, CHAR *, CHAR *); /* remove a existent directory */
INT (*rename)(LDISK_T *, CHAR *, CHAR *, CHAR *, CHAR *, BOOL); /* rename file/directory */
INT (*move)(LDISK_T *, CHAR *, CHAR *, CHAR *, CHAR *, BOOL); /* move file/directory */
INT (*volume_label)(LDISK_T *, CHAR *, CHAR *); /* get/change disk volume label */
//INT (*format)(LDISK_T *); /* format this disk */
//INT (*scan_disk)(LDISK_T *); /* scan this disk */
//INT (*defragment)(LDISK_T *); /* defragment this disk */
}
#undef DISK_OP_T
DISK_OP_T;
/*
* File operations
* These service routines are provided by a specific file system. They are used
* to fulfill operations on a specific file opened on a file system. They are
* file level operations, instead of system level operations.
*/
typedef struct file_op_S
{
INT (*fopen)(FILE_T *, CHAR *, CHAR *); /* open a file */
INT (*fread)(FILE_T *, UINT8 *, INT, INT *);/* read data from file */
INT (*fwrite)(FILE_T *, UINT8 *, INT, INT*);/* write data to file */
INT (*fclose)(FILE_T *); /* close file */
INT (*fsizing)(FILE_T *, INT64); /* change file size */
INT64 (*fseek)(FILE_T *, INT64); /* setting the file position pointer */
INT (*fget_stat)(FILE_T *, FILE_STAT_T *); /* get file status */
INT (*fset_stat)(FILE_T *, FILE_STAT_T *); /* set file status */
INT (*find_first)(FILE_T *, FILE_FIND_T *);
INT (*find_next)(FILE_T *, FILE_FIND_T *);
INT (*find_close)(FILE_T *, FILE_FIND_T *);
INT (*fioctl)(FILE_T *, INT, VOID *); /* file system specific control */
}
#undef FILE_OP_T
FILE_OP_T;
typedef struct file_S
{
//CHAR suFileName[MAX_PATH_LEN+2]; /* full path file name */
CHAR szFnameAscii[MAX_FILE_NAME_LEN/2];
UINT32 uFlag;
LDISK_T *ptLDisk;
FAT_FCB_T tFatFcb; /* File Control Block used by FAT file system */
FILE_OP_T *ptFileOP; /* file operations */
FILE_T *ptFileAllLink; /* used for global file link */
FILE_T *ptFileDiskLink; /* used for file link on disk */
}
#undef FILE_T
FILE_T;
typedef enum file_sorting_t
{
NO_SORTING = 0, /* without any file sorting */
NAME_INCREASING, /* sorting by file name in increasing order */
NAME_DECREASING, /* sorting by file name in decreasing order */
CDATE_INCREASING, /* sorting by file creation date in increasing order */
CDATE_DECREASING, /* sorting by file creation date in decreasing order */
MDATE_INCREASING, /* sorting by file modification date in increasing order */
MDATE_DECREASING, /* sorting by file modification date in decreasing order */
SIZE_INCREASING, /* sorting by file size in increasing order */
SIZE_DECREASING /* sorting by file size in decreasing order */
} FILE_SORTING_T;
typedef struct file_find_S
{
INT hFile;
CHAR suLongName[MAX_FILE_NAME_LEN+2];
CHAR szShortName[14];
UINT8 ucAttrib;
UINT8 ucCTimeMS; /* create time minisecond */
UINT8 ucCTimeSec; /* create time */
UINT8 ucCTimeMin;
UINT8 ucCTimeHour;
UINT8 ucCDateDay; /* create date */
UINT8 ucCDateMonth;
UINT8 ucCDateYear;
UINT8 ucLDateDay; /* last access date */
UINT8 ucLDateMonth;
UINT8 ucLDateYear;
UINT8 ucWTimeSec; /* write time */
UINT8 ucWTimeMin;
UINT8 ucWTimeHour;
UINT8 ucWDateDay; /* write date */
UINT8 ucWDateMonth;
UINT8 ucWDateYear;
INT64 n64FileSize;
CHAR *suPattern[8];
BOOL bIsPatternExcludeDir; /* pattern rule did not apply to directory */
FILE_SORTING_T eFileSorting;
BOOL bIsDirFirst; /* only valid if eFileSorting != NO_SORTING */
/* TRUE: direcotry will be searched first */
/* The following members are library internal used, user MUST NOT modified them! */
BOOL bIsAllDirSearched;
BOOL bHasSearchPattern;
INT nCandidatePos;
INT nLastChoicePos;
struct file_find_S *ptCandidate;
struct file_find_S *ptLastChoice;
}
#undef FILE_FIND_T
FILE_FIND_T;
typedef struct file_stat_S
{
UINT32 uFlag; /* forwarded from FAL */
UINT8 ucAttrib; /* file attribute */
UINT8 ucDirNTRes;
UINT8 ucCTimeMs; /* create time minisecond */
UINT8 ucCTimeSec; /* create time */
UINT8 ucCTimeMin;
UINT8 ucCTimeHour;
UINT8 ucCDateDay; /* create date */
UINT8 ucCDateMonth;
UINT8 ucCDateYear;
UINT8 ucLDateDay; /* last access date */
UINT8 ucLDateMonth;
UINT8 ucLDateYear;
UINT8 ucWTimeSec; /* write time */
UINT8 ucWTimeMin;
UINT8 ucWTimeHour;
UINT8 ucWDateDay; /* write date */
UINT8 ucWDateMonth;
UINT8 ucWDateYear;
UINT32 uDev; /* ptLDisk value to fake Linux dev */
UINT32 uUnique; /* a unique value used to fake Linux inode number */
INT64 n64FilePos;
INT64 n64FileSize;
}
#undef FILE_STAT_T
FILE_STAT_T;
/*===================================================== file mode and flag ==*/
/* File open mode */
#define O_RDONLY 0x0001 /* Open for read only*/
#define O_WRONLY 0x0002 /* Open for write only*/
#define O_RDWR 0x0003 /* Read/write access allowed.*/
#define O_APPEND 0x0004 /* Seek to eof on each write*/
#define O_CREATE 0x0008 /* Create the file if it does not exist.*/
#define O_TRUNC 0x0010 /* Truncate the file if it already exists*/
#define O_EXCL 0x0020 /* Fail if creating and already exists */
#define O_DIR 0x0080 /* Open a directory file */
#define O_EXCLUSIVE 0x0200 /* Open a file with exclusive lock */
#define O_NODIRCHK 0x0400 /* no dir/file check */
#define O_FSEEK 0x1000 /* Open with cluster chain cache to enhance file seeking performance */
#define O_IOC_VER2 0x2000
#define O_INTERNAL 0x8000
/* operation */
#define OP_READ 0x0010000 /* can read */
#define OP_WRITE 0x0020000 /* can write */
#define OP_RDWR 0x0030000 /* can read/write */
#define OP_DELETE 0x0100000 /* file deletion */
#define OP_SETTIME 0x0200000 /* set file time used */
#define OP_DIRTY 0x0400000 /* file has ever been changed */
#define OP_ROOT 0x0800000 /* is root directory */
#define OP_NULL_RDONLY 0x1000000
#define OP_WAS_DEL 0x2000000 /* file has been deleted by other process */
#define OP_ERROR 0x8000000 /* file has been deleted by other process */
/* file attributes */
#define FA_RDONLY 0x01 /* Read only attribute */
#define FA_HIDDEN 0x02 /* Hidden file */
#define FA_SYSTEM 0x04 /* System file */
#define FA_LABEL 0x08 /* Volume label */
#define FA_DIR 0x10 /* Directory */
#define FA_ARCHIVE 0x20 /* Archive */
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
/* scan disk stage */
#define SDS_SCAN_FAT 1
#define SDS_BACKUP_FAT 2
#define SDS_SCAN_DIR 3
#define SDS_RECLAIM_CLUS 4
#define SDS_DUP_FAT 5
typedef INT (FS_DW_CB)(UINT8 *);
typedef INT (FS_SD_CB)(INT);
typedef VOID (FS_DEL_CB_T)(PDISK_T *, UINT32, INT);
typedef VOID (FS_MOUNT_CB_T)(LDISK_T *);
typedef VOID (FS_UNMOUNT_CB_T)(LDISK_T *);
/*===================================================== Exported Functions ==*/
/* NVTFAT File System APIs */
extern INT fsInitFileSystem(VOID);
extern INT fsAssignDriveNumber(INT nDriveNo, INT disk_type, INT instance, INT partition);
extern VOID fsInstallIoWriteCallBack(FS_DW_CB *cb_func);
extern VOID fsInstallFileDelCallBack(FS_DEL_CB_T *cb_func);
/* Disk operations */
extern INT fsUnmountPhysicalDisk(PDISK_T *ptPDisk);
extern INT fsMountLogicalDisk(LDISK_T *ptLDisk);
extern INT fsUnmountLogicalDisk(LDISK_T *ptLDisk);
extern INT fsDiskFreeSpace(INT nDriveNo, UINT32 *puBlockSize, UINT32 *puFreeSize, UINT32 *puDiskSize);
extern PDISK_T *fsGetFullDiskInfomation(VOID);
extern VOID fsReleaseDiskInformation(PDISK_T *ptPDiskList);
extern INT fsScanDisk(INT nDriveNo);
extern INT fsFormatFlashMemoryCard(PDISK_T *ptPDisk);
extern INT fsFormatFixedDrive(INT nDriveNo);
extern INT fsFormatDisk(INT disk_type, INT nand_part);
extern INT fsTwoPartAndFormatAll(PDISK_T *ptPDisk, INT firstPartSize, INT secondPartSize);
extern INT fsCreateDiskPartition(PDISK_T *ptPDisk, UINT32 *puSizeList, INT nCount); /* 2011-0621 add for multiple partition */
extern INT fsSetReservedArea(UINT32 uStartSecter); /* 2011-0624 add for reserved area */
extern VOID fsDiskWriteComplete(UINT8 *pucBuff);
extern INT fsGetLDiskVolID(INT nDriveNo, UINT32 *uVolID);
extern INT fsSetVolumeLabel(INT nDriveNo, CHAR *szLabel, INT nLen);
extern INT fsGetVolumeLabel(INT nDriveNo, CHAR *szLabel, INT nLen);
extern INT get_vdisk(INT nDriveNo, LDISK_T **plDisk);
/* File operations */
extern INT fsOpenFile(CHAR *suFileName, CHAR *szAsciiName, UINT32 uFlag);
extern INT fsCloseFile(INT hFile);
extern INT fsReadFile(INT hFile, UINT8 *pucPtr, INT nBytes, INT *pnReadCnt);
extern INT fsWriteFile(INT hFile, UINT8 *pucBuff, INT nBytes, INT *pnWriteCnt);
extern INT64 fsFileSeek(INT hFile, INT64 n64Offset, INT16 usWhence);
extern BOOL fsIsEOF(INT hFile);
extern INT fsSetFileSize(INT hFile, CHAR *suFileName, CHAR *szAsciiName, INT64 n64NewSize);
extern INT fsGetFilePosition(INT hFile, UINT32 *puPos);
extern INT64 fsGetFileSize(INT hFile);
extern INT fsGetFileStatus(INT hFile, CHAR *suFileName, CHAR *szAsciiName, FILE_STAT_T *ptFileStat);
extern INT fsSetFileStatus(INT hFile, CHAR *suFileName, CHAR *szAsciiName, FILE_STAT_T *ptFileStat);
extern INT fsSetFileAttribute(INT hFile, CHAR *suFileName, CHAR *szAsciiName, UINT8 ucAttrib, FILE_STAT_T *ptFileStat);
extern INT fsSetFileTime(INT hFile, CHAR *suFileName, CHAR *szAsciiName, UINT8 ucYear, UINT8 ucMonth, UINT8 ucDay, UINT8 ucHour, UINT8 unMin, UINT8 ucSec);
extern INT fsMergeFile(CHAR *suFileNameA, CHAR *szAsciiNameA, CHAR *suFileNameB, CHAR *szAsciiNameB);
extern INT fsDeleteFile(CHAR *suFileName, CHAR *szAsciiName);
extern INT fsRenameFile(CHAR *suOldName, CHAR *szOldAsciiName, CHAR *suNewName, CHAR *szNewAsciiName, BOOL bIsDirectory);
extern INT fsMoveFile(CHAR *suOldName, CHAR *szOldAsciiName, CHAR *suNewName, CHAR *szNewAsciiName, INT bIsDirectory);
extern INT fsCopyFile(CHAR *suSrcName, CHAR *szSrcAsciiName, CHAR *suDstName, CHAR *szDstAsciiName);
extern INT fsFindFirst(CHAR *suDirName, CHAR *szAsciiName, FILE_FIND_T *ptFindObj);
extern INT fsFindNext(FILE_FIND_T *ptFindObj);
extern INT fsFindClose(FILE_FIND_T *ptFindObj);
extern BOOL fsIsFileOpened(CHAR *suFileName);
/* Directory operations */
extern INT fsMakeDirectory(CHAR *suDirName, CHAR *szAsciiName);
extern INT fsRemoveDirectory(CHAR *suDirName, CHAR *szAsciiName);
extern INT fsDeleteDirTree(CHAR *suDirName, CHAR *szAsciiName);
extern INT fsGetDirectoryInfo(CHAR *suDirName, CHAR *szAsciiName,
INT *nFileCnt, INT *nDirCnt, UINT64 *u64TotalSize, BOOL bSearchSubDir);
extern INT fsGetDirectoryInfo2(CHAR *suDirName, CHAR *szAsciiName, CHAR **suPattern,
INT *pnFileCnt, INT *pnDirCnt, UINT64 *u64TotalSize, BOOL bSearchSubDir);
/* language support */
extern CHAR fsToUpperCase(CHAR chr);
extern INT fsUnicodeToAscii(VOID *pvUniStr, VOID *pvASCII, BOOL bIsNullTerm);
extern INT fsAsciiToUnicode(VOID *pvASCII, VOID *pvUniStr, BOOL bIsNullTerm);
extern VOID fsAsciiToUpperCase(VOID *pvASCII);
extern INT fsAsciiNonCaseCompare(VOID *pvASCII1, VOID *pvASCII2);
extern VOID fsUnicodeToUpperCase(VOID *pvUnicode);
extern VOID fsUnicodeToLowerCase(VOID *pvUnicode);
extern INT fsUnicodeStrLen(VOID *pvUnicode);
extern INT fsUnicodeNonCaseCompare(VOID *pvUnicode1, VOID *pvUnicode2);
extern INT fsUnicodeCopyStr(VOID *pvStrDst, VOID *pvStrSrc);
extern INT fsUnicodeStrCat(VOID *pvUniStrHead, VOID *pvUniStrTail);
extern VOID fsGetAsciiFileName(VOID *pvUniStr, VOID *pvAscii);
extern INT fsUnicodeWildCardCompare(CHAR *suStr1, CHAR *suStr2);
/* Driver supporting routines */
extern INT fsPhysicalDiskConnected(PDISK_T *ptPDisk);
extern INT fsPhysicalDiskDisconnected(PDISK_T *ptPDisk);
/* For debug and internal use, not exported funcions */
//extern CHAR *fsFindFirstSlash(CHAR *szFullName);
extern CHAR *fsFindLastSlash(CHAR *suFullName);
extern INT fsTruncatePath(CHAR *szPath, CHAR *szToken);
extern VOID fsTrimEndingSpace(CHAR *szStr);
extern FILE_T *fsHandleToDescriptor(INT hFile);
extern INT fsDescriptorToHandle(FILE_T *ptFile);
extern VOID fsDumpBufferHex(UINT8 *pucBuff, INT nSize);
extern VOID fsDumpSectorHex(INT uSectorNo, UINT8 *pucBuff, INT nSize);
extern INT fsDumpDiskSector(UINT32 uSectorNo, INT nSecNum);
extern LDISK_T *fsAllocateDisk(PDISK_T *ptPDisk, PARTITION_T *ptPartition);
extern UINT8 *fsAllocateSector(VOID);
extern INT fsFreeSector(UINT8 *pucSecAddr);
extern CHAR *fsDebugUniStr(CHAR *suStr);
//extern BOOL fsIsValidLongEntName(CHAR *szDirEntName);
//extern BOOL fsIsValidShortNameChar(CHAR cChar);
extern VOID lname_to_sname(CHAR *szAsciiName, INT nTildeNum, CHAR *szShortName);
extern INT fsFlushIOCache(VOID);
extern INT fsIOWrite(PDISK_T *ptPDisk, UINT32 uStartSecNo, INT nCount, UINT8 *pucOutBuff);
extern INT fsIORead(PDISK_T *ptPDisk, UINT32 uStartSecNo, INT nCount, UINT8 *in_buf);
extern VOID fs_enable_iow_cache(VOID);
extern INT fs_flush_iow_cache(VOID);
extern VOID *fsCheckDriverPointer(VOID *pvDrive);
#endif /* _NVTFAT_H_ */
nvtfat_fat.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/*************************************************************************
* Nuvoton Electronics Corporation confidential
*
* Copyright (c) 2008 by Nuvoton Electronics Corporation
* All rights reserved
*
* FILENAME
* nvtfat_fat.h
*
* REMARK
* None
**************************************************************************/
#ifndef _NVTFAT_FAT_H_
#define _NVTFAT_FAT_H_
/* Defined for long filenames */
#define LFN_MAX_FILENAME 514 /* maximum length of LFN in bytes */
/* Macro to convert Cluster number to logical sector number */
#define ClustNo2SecNo(n) ((UINT32)(n - 2) * ptLDisk->tFatInfo.uBpbSecPerClus + ptLDisk->tFatInfo.uDataSecStart)
#define SECTOR_TYPE_FILE 0
#define SECTOR_TYPE_DIR 1
#define SECTOR_TYPE_FAT 2
#define SECTOR_TYPE_PART 3
typedef struct sector_buf_S
{
UINT8 *pucData; /* cached sector contents */
LDISK_T *ptLDisk; /* LDISK_T * associated with this sector */
UINT32 uSectorNo; /* logical sector number */
BOOL bIsDirty; /* dirty or not */
INT nReaderCnt; /* how many threads are reading it */
UINT32 jiffy; /* access time stamp */
VOID *os_owner; /* for OS */
VOID *os_priv; /* for OS */
} SEC_BUFF_T;
/* For FAT and DATA sector check out */
#define READ_ACCESS 0
#define WRITE_ACCESS 1
/*======================================================== FAT information ==*/
typedef struct fat_info_S
{
/*- The followings are BPB fields commonly used by FAT16/FAT32 -*/
UINT32 uBpbBytesPerSec; /* BPB[11], size:2 */
UINT32 uBpbSecPerClus; /* BPB[13], size:1 */
UINT16 usBpbRsvdSecCnt; /* BPB[14], size:2 */
UINT8 ucBpbNumFATs; /* BPB[16], size:1 */
UINT16 usBpbRootEntCnt; /* BPB[17], size:2 */
UINT32 uBpbTotalSectors; /* FAT12/FAT16 - BPB[19], size:2 */
/* FAT32 - BPB[32], size: 4 */
UINT8 ucBpbMedia; /* BPB[21], size:1 */
UINT32 uBpbFatSize; /* FAT12/FAT16 - BPB[22], size:2 */
/* FAT32 - BPB[36], size:4 */
UINT16 usBpbSecPerTrk; /* BPB[24], size:2 */
UINT16 usBpbNumHeads; /* BPB[26], size:2 */
UINT32 uBpbHiddSec; /* BPB[28], size:4 */
UINT32 uBsVolID; /* FAT12/FAT16 - BPB[39], size:4 */
/* FAT32 - BPB[67], size:4 */
CHAR sBsVolLab[12]; /* FAT12/FAT16 - BPB[43], size:11 */
/* FAT32 - BPB[71], size:4 */
UINT32 uBpbRootClus; /* BPB[44], size:4 */
UINT16 usBpbFsInfo; /* BPB[48], size:2 */
/*- The following is FAT32 structure start from offset 36 -*/
/* UINT32 uBpbBytesPerSec; */ /* BPB[36], size:4 */
/* UINT16 usBsDrvNum; */ /* BPB[40], size:2 */
/* UINT16 usBpbFsVer; */ /* BPB[42], size:2 */
/* UINT16 usBpbBkBootSec; */ /* BPB[50], size:2 */
/* bpb_Reserved */ /* BPB[52], size:12 */
/* usBsDrvNum */ /* BPB[64], size:1 */
/* bs_Reserved1 */ /* BPB[65], size:1 */
/* bs_BootSig */ /* BPB[66], size:1 */
/*- The followings are proprietary used by our driver -*/
UINT32 uEndClusMark; /* FAT12 = 0xFF7, FAT16 = 0xFFF7, FAT32 = 0x0FFFFFF7 */
UINT8 ucFatType; /* TYPE_FAT12/TYPE_FAT16/TYPE_FAT32 */
UINT32 uSecSzMask; /* uBpbBytesPerSec - 1 */
UINT32 uBytesPerClus; /* uBpbBytesPerSec * uBpbSecPerClus */
UINT32 uLastSecNo; /* the last physical sector number on this partition */
UINT32 uLastClusNo; /* last cluster number on this partition */
UINT32 uFatSecStart; /* sector number of the first FAT sector */
UINT32 uDataSecStart; /* sector number of first data sector */
UINT32 uRootDirStartSec; /* FAT12/16 first sector number of the root directory */
UINT32 uFsInfoSecNo; /* FAT32 - the sector number of pucFSInfo sector */
UINT32 uFreeClusSearchIdx; /* the next start point to search a free cluster */
UINT32 uTotalFreeClus; /* total number of free clusters */
UINT8 pucFSInfo[512]; /* pucFSInfo sector */
} FAT_INFO_T;
#define FAT12_END_CLUS_MARK 0xFF8
#define FAT16_END_CLUS_MARK 0xFFF8
#define FAT32_END_CLUS_MARK 0x0FFFFFF8
#define FAT12_BAD_CLUS_MARK 0xFF7
#define FAT16_BAD_CLUS_MARK 0xFFF7
#define FAT32_BAD_CLUS_MARK 0x0FFFFFF7
#define TYPE_FAT12 12
#define TYPE_FAT16 16
#define TYPE_FAT32 32
/*================================================ FAT directory structure ==*/
/*
* A FAT directory entry size is 32 bytes and sector size is 512 bytes.
* So, it must be word-aligned.
*/
/* physical file name entry */
typedef struct dir_ent_S
{
UINT8 pucDirName[8]; /* Offset: 0, Size: 11 */
UINT8 pucDirExtName[3];
UINT8 ucDirAttrib; /* Offset: 11, Size: 1 */
UINT8 ucDirNTRes; /* Offset: 12, Size: 1 */
UINT8 ucDirCTimeTenth; /* Offset: 13, Size: 1 */
UINT8 pucDirCTime[2]; /* Offset: 14, Size: 2 */
UINT8 pucDirCDate[2]; /* Offset: 16, Size: 2 */
UINT8 pucDirLADate[2]; /* Offset: 18, Size: 2 */
UINT8 pucDirFirstClusHi[2];/* Offset: 20, Size: 2 */
UINT8 pucDirWTime[2]; /* Offset: 22, Size: 2 */
UINT8 pucDirWDate[2]; /* Offset: 24, Size: 2 */
UINT8 pucDirFirstClusLo[2];/* Offset: 26, Size: 2 */
UINT8 pucDirFileSize[4]; /* Offset: 28, Size: 4 */
} DIR_ENT_T;
/* physical long file name entry */
typedef struct lfn_ent_S
{
UINT8 ucLDirOrd; /* Offset: 0, Size: 1 */
UINT8 pucLDirName1[10]; /* Offset: 1, Size: 10, Unicode Chars 1~5 */
UINT8 ucLDirAttrib; /* Offset: 11, Size: 1, always 0x0F */
UINT8 ucLDirType; /* Offset: 12, Size: 1 */
UINT8 ucLDirChksum; /* Offset: 13, Size: 1, Checksum of 8.3 name */
UINT8 pucLDirName2[12]; /* Offset: 14, Size: 12, Unicode Chars 6-11 */
UINT8 pucLDirFirstClusLo[2]; /* Offset: 26, Size: 2, always 0 */
UINT8 pucLDirName3[4]; /* Offset: 28, Size: 4, Unicode Chars 12-13 */
} LFN_ENT_T;
/* FAT file attributes */
#define A_NORMAL 0x00 /* Normal file, no attributes */
#define A_RDONLY 0x01 /* Read only attribute */
#define A_HIDDEN 0x02 /* Hidden file */
#define A_SYSTEM 0x04 /* System file */
#define A_LABEL 0x08 /* Volume label */
#define A_DIR 0x10 /* Directory */
#define A_ARCHIVE 0x20 /* Archive */
#define A_LFN 0x0F /* (A_RDONLY | A_HIDDEN | A_SYSTEM | A_LABEL) */
#define A_LFN_MASK 0x3F /* (A_LFN | A_DIR | A_ARCHIVE) */
/*================================================ Run-time data structure ==*/
/*
* Each FILE_T has its own FAT configuration on a FAT file system. Refer to the
* FILE_T defined in nvtfat.h.
*/
typedef struct file_control_block_S
{
/* For directory entry */
//CHAR suLongName[LFN_MAX_FILENAME];
CHAR szShortName[14];
UINT8 ucDirAttrib; /* file attribute */
UINT8 ucDirNTRes;
UINT8 ucDirCTimeTenth; /* Millisecond stamp at file creation time */ UINT16 dirCtime; /* Time file was created */
UINT16 usDirCDate; /* Date file was created */
UINT16 usDirLDate; /* Last access date */
UINT16 usDirWTime; /* Time of last write. Note that file creation is considered a write. */
UINT16 usDirWDate; /* Date of last write. Note that file creation is considered a write. */
UINT32 uDirEntSecNo; /* Number of the sector where this directory entry is located. */
INT nDirEntInSecOffset; /* Directory entry offset of this file in <uDirEntSecNo> sector. */
/* for run-time file operation */
BOOL bIsFat16Root; /* is FAT12/FAT16 root directory */
BOOL bIsRWBuffDirty; /* read/write buffer is dirty or not */
UINT8 *pucRWBuff; /* file r/w buffer */
INT64 n64RWBuffMapPos; /* the file position of the r/w buffer mapped to */
UINT32 uRWBuffSecNo; /* the start sector number of r/w buffer */
INT nRWBuffSecCnt; /* the start sector number of r/w buffer */
INT nClusCnt; /* number of clusters cached in r/w buffer */
UINT32 uRWBuffSize; /* the size of read/write buffer */
UINT32 *pucCCBuff; /* cluster chain buffer */
UINT32 uCCBuffSize; /* cluster chain buffer size */
UINT32 uCCEntCnt; /* cluster chain entry count */
UINT32 uCCDoneFPos; /* cluster chain done file position */
UINT32 uFirstClusNo; /* first cluster number of this file */
UINT32 uLastClusNo;
UINT32 uCurClusNo; /* the number of the cluster currently used */
INT64 n64FileSize; /* The total length of this file */
INT64 n64FilePos; /* current position in file */
} FAT_FCB_T;
#ifdef ECOS
extern cyg_mutex_t _fat_mutex;
#define FAT_MUTEX_INIT() cyg_mutex_init(&_fat_mutex)
#define FAT_MUTEX_LOCK() cyg_mutex_lock(&_fat_mutex)
#define FAT_MUTEX_UNLOCK() cyg_mutex_unlock(&_fat_mutex)
#else /* Non-OS */
#define FAT_MUTEX_INIT()
#define FAT_MUTEX_LOCK()
#define FAT_MUTEX_UNLOCK()
#endif
/*====================================== External reference in library only ==*/
extern DISK_OP_T _fs_tFatDiskOperation;
extern FILE_OP_T _fs_tFatFileOperation;
extern BOOL _fs_bLockFileSystem;
extern INT fs_fat_parse_partition(PDISK_T *ptPDisk, PARTITION_T *ptPartition, UINT32 uBpbSecNo);
extern INT fs_fat_format_partition(PDISK_T *ptPDisk, PARTITION_T *ptPartition, INT nType);
extern INT fs_fat32_scan_disk(LDISK_T *ptLDisk);
extern INT fs_fat32_defragment_disk(LDISK_T *ptLDisk);
/* Cache */
extern VOID fs_fat_init_sector_cache(VOID);
extern VOID fs_fat_debug_sector_cache(VOID);
extern INT fs_fat_check_out_sec(LDISK_T *ptLDisk, UINT32 uSectorNo, INT nAccess, SEC_BUFF_T **ptSecBuff);
extern VOID fs_fat_check_in_sec(SEC_BUFF_T *ptSecBuff, INT nAccess, BOOL bIsDirty);
extern INT fs_fat_flush_sector_cache(LDISK_T *ptLDisk);
extern VOID fs_fat_clear_sector_cache(LDISK_T *ptLDisk);
/* FAT32 pucFSInfo sector */
//extern INT fs_fat_update_fs_info(LDISK_T *ptLDisk);
extern INT fsScanDisk(INT nDriveNo);
/* FAT table */
extern INT read_fs_info(LDISK_T *ptLDisk);
extern INT fs_read_fat_table(LDISK_T *ptLDisk, UINT32 uClusNo, UINT32 *puEntryValue);
extern INT fs_write_fat_table(LDISK_T *ptLDisk, UINT32 uClusNo, UINT32 uEntryValue);
extern INT fs_fat_reclaim_clusters(LDISK_T *ptLDisk, UINT32 uStartClusNo);
extern INT fs_fat_allocate_cluster(FILE_T *ptFile);
/* directory entry */
extern INT fs_fat_delete_file(LDISK_T *ptLDisk, CHAR *suFullName, CHAR *szAsciiName, BOOL bIsDirectory);
extern INT fs_fat_create_file(FILE_T *ptFile, CHAR *suFullName, CHAR *szAsciiName, UINT32 *uClusNoOfParent);
extern INT fs_fat_merge_file(LDISK_T *ptLDisk, CHAR *suFileNameA, CHAR *szAsciiNameA, CHAR *suFileNameB, CHAR *szAsciiNameB);
extern INT fs_fat_get_next_dir_entry(FILE_T *ptFile, UINT8 *pucBuff, CHAR **szLongName, DIR_ENT_T *ptDirEnt, UINT32 *uStartPos);
extern VOID fs_fat_set_dire_mtime(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire, INT bType);
extern VOID fs_fat_set_sdir_name(CHAR *szShortName, DIR_ENT_T *ptDire);
extern VOID fs_fat_get_sdir_name(CHAR *szShortName, DIR_ENT_T *ptDire);
extern UINT8 *fs_fat_get_ldir_name(UINT8 *pucNameBuff, LFN_ENT_T *ptLDire);
extern VOID fs_fat_set_dire_info(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire);
extern VOID fs_fat_get_dire_info(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire);
extern INT fs_fat_search_file(FILE_T *ptFile, CHAR *szFileName);
extern INT fs_fat_delete_tree(LDISK_T *ptLDisk, CHAR *suFullName, CHAR *szAsciiName);
extern INT fs_update_first_cluster(FILE_T *ptFile, UINT32 uClusNo);
extern VOID fs_fat_dump_fcb(FAT_FCB_T *ptFcb);
extern VOID fsDumpUniStr(UINT8 *suStr);
#endif /* _NVTFAT_FAT_H_ */
PWM.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright (c) Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------------------*/
/* Includes of system headers */
/*---------------------------------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "wblib.h"
#include "Common.h"
#include "PWM.h"
/*---------------------------------------------------------------------------------------------------------*/
/* Macro, type and constant definitions */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_GLOBALS
/*---------------------------------------------------------------------------------------------------------*/
/* Global file scope (static) variables */
/*---------------------------------------------------------------------------------------------------------*/
static PWM_CALLBACK_T pfnPWMHandler = {FALSE};
/*---------------------------------------------------------------------------------------------------------*/
/* Function: <PWM0_ISR> */
/* */
/* Parameter: */
/* VOID */
/* Returns: */
/* None */
/* Side effects: */
/* */
/* Description: */
/* ISR to handle PWM0 interrupt event */
/*---------------------------------------------------------------------------------------------------------*/
static VOID PWM_ISR (VOID)
{
UINT32 volatile u32RegPIIR,u32RegCCR0,u32RegCCR1;
u32RegPIIR = inp32(PIIR);
u32RegCCR0 = inp32(CCR0);
u32RegCCR1 = inp32(CCR1);
if (u32RegPIIR & 0xF )
{
if(u32RegPIIR & PIIR0);
{
outp32(PIIR, PIIR0);
if (pfnPWMHandler.pfnPWM0CallBack != NULL)
pfnPWMHandler.pfnPWM0CallBack();
}
if(u32RegPIIR & PIIR1);
{
outp32(PIIR, PIIR1);
if (pfnPWMHandler.pfnPWM1CallBack != NULL)
pfnPWMHandler.pfnPWM1CallBack();
}
if(u32RegPIIR & PIIR2);
{
outp32(PIIR, PIIR2);
if (pfnPWMHandler.pfnPWM2CallBack != NULL)
pfnPWMHandler.pfnPWM2CallBack();
}
if(u32RegPIIR & PIIR3);
{
outp32(PIIR, PIIR3);
if (pfnPWMHandler.pfnPWM3CallBack != NULL)
pfnPWMHandler.pfnPWM3CallBack();
}
}
if (u32RegCCR0 & CIIR0)
{
outp32(CCR0, inp32(CCR0) & ~CIIR0);
if (pfnPWMHandler.pfnCAP0CallBack != NULL)
{
pfnPWMHandler.pfnCAP0CallBack();
}
}
if (u32RegCCR0 & CIIR1)
{
outp32(CCR0, inp32(CCR0) & ~CIIR1);
if (pfnPWMHandler.pfnCAP1CallBack != NULL)
{
pfnPWMHandler.pfnCAP1CallBack();
}
}
if (u32RegCCR1 & CIIR2)
{
outp32(CCR1, inp32(CCR1) & ~CIIR2);
if (pfnPWMHandler.pfnCAP2CallBack != NULL)
{
pfnPWMHandler.pfnCAP2CallBack();
}
}
if (u32RegCCR1 & CIIR3)
{
outp32(CCR1, inp32(CCR1) & ~CIIR3);
if (pfnPWMHandler.pfnCAP3CallBack != NULL)
{
pfnPWMHandler.pfnCAP3CallBack();
}
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_IsTimerEnabled */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* */
/* Returns: */
/* 0 disable */
/* 1 enable */
/* Side effects: */
/* Description: */
/* This function is used to get PWM specified timer enable/disable state */
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_IsTimerEnabled(UINT8 u8Timer)
{
return ((inp32(PCR) & (1 << ((u8Timer & 0x7) << 3))) ? TRUE : FALSE);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerCounter */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* u16Counter - [in] Timer counter : 0~65535 */
/* Returns: */
/* 0 disable */
/* 1 enable */
/* Side effects: */
/* Description: */
/* This function is used to set the PWM specified timer counter */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_SetTimerCounter(UINT8 u8Timer, UINT16 u16Counter)
{
outp32(CNR0 + (u8Timer & 0x07) * 12, u16Counter);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetTimerCounter */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* */
/* Returns: */
/* The specified timer counter value */
/* */
/* Side effects: */
/* Description: */
/* This function is used to get the PWM specified timer counter value */
/*---------------------------------------------------------------------------------------------------------*/
UINT32 PWM_GetTimerCounter(UINT8 u8Timer)
{
return (inp32(PDR0 + 0x0C * (u8Timer & 0x07)) & 0xFFFF);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvPWM_InstallCallBack */
/* */
/* Parameters: */
/* u8Timer - [in] DRVPWM_TIMER0/DRVPWM_TIMER1/DRVPWM_TIMER2/DRVPWM_TIMER3 */
/* DRVPWM_CAP0/DRVPWM_CAP1/DRVPWM_CAP2/DRVPWM_CAP3 */
/* pfncallback - [in] The call back function for specified timer / capture */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to iNnstall the PWM timer/capture interrupt call back function */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_InstallCallBack(
UINT8 u8Timer,
PFN_PWM_CALLBACK pfncallback,
PFN_PWM_CALLBACK *pfnOldcallback
)
{
switch(u8Timer)
{
case PWM_TIMER0:
case PWM_CAP0:
if(pfncallback != NULL)
{
if(u8Timer & 0x10)
{
*pfnOldcallback = pfnPWMHandler.pfnCAP0CallBack;
pfnPWMHandler.pfnCAP0CallBack = pfncallback;
}
else
{
*pfnOldcallback = pfnPWMHandler.pfnPWM0CallBack;
pfnPWMHandler.pfnPWM0CallBack = pfncallback;
}
}
break;
case PWM_TIMER1:
case PWM_CAP1:
if(pfncallback != NULL)
{
if(u8Timer & 0x10)
{
*pfnOldcallback = pfnPWMHandler.pfnCAP1CallBack;
pfnPWMHandler.pfnCAP1CallBack = pfncallback;
}
else
{
*pfnOldcallback = pfnPWMHandler.pfnPWM1CallBack;
pfnPWMHandler.pfnPWM1CallBack = pfncallback;
}
}
break;
case PWM_TIMER2:
case PWM_CAP2:
if(pfncallback != NULL)
{
if(u8Timer & 0x10)
{
*pfnOldcallback = pfnPWMHandler.pfnCAP2CallBack;
pfnPWMHandler.pfnCAP2CallBack = pfncallback;
}
else
{
*pfnOldcallback = pfnPWMHandler.pfnPWM2CallBack;
pfnPWMHandler.pfnPWM2CallBack = pfncallback;
}
}
break;
case PWM_TIMER3:
case PWM_CAP3:
if(pfncallback != NULL)
{
if(u8Timer & 0x10)
{
*pfnOldcallback = pfnPWMHandler.pfnCAP3CallBack;
pfnPWMHandler.pfnCAP3CallBack = pfncallback;
}
else
{
*pfnOldcallback = pfnPWMHandler.pfnPWM3CallBack;
pfnPWMHandler.pfnPWM3CallBack = pfncallback;
}
}
break;
}
sysInstallISR(IRQ_LEVEL_7, IRQ_PWM, (PVOID)PWM_ISR);
sysSetLocalInterrupt(ENABLE_IRQ);
sysEnableInterrupt(IRQ_PWM);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_EnableInt */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* u8Int - [in] PWM_CAP_RISING_INT/PWM_CAP_FALLING_INT/PWM_CAP_ALL_INT */
/* (The parameter is valid only when capture function) */
/* pfncallback - [in] The call back function for specified timer / capture */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to Enable the PWM timer/capture interrupt */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_EnableInt(UINT8 u8Timer, UINT8 u8Int)
{
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
outp32(CCR1, (inp32(CCR1) & ~((0x06 << ((u8Timer & 0x01) << 4 )) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2))) | ((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));
else
outp32(CCR0, (inp32(CCR0) & ~((0x06 << ((u8Timer & 0x01) << 4 )) | (CFLRD1 | CRLRD1 | CIIR1 | CFLRD0 | CRLRD0 |CIIR0))) | ((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)));
}
else
outp32(PIER, inp32(PIER) | (1<<u8Timer));
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_DisableInt */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* u8Int - [in] PWM_CAP_RISING_INT/PWM_CAP_FALLING_INT/PWM_CAP_ALL_INT */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to clear the PWM timer/capture interrupt */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_DisableInt(UINT8 u8Timer, UINT8 u8Int)
{
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
outp32(CCR1, inp32(CCR1) & ~(((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)));
else
outp32(CCR0, inp32(CCR0) & ~(((u8Int & 0x03) << (((u8Timer & 0x01) <<4) + 1)) | (CFLRD1 | CRLRD1 | CIIR1 | CFLRD0 | CRLRD0 |CIIR0)));
}
else
{
outp32(PIER, inp32(PIER) & ~(1 << (u8Timer & 0x03)));
outp32(PIIR, inp32(PIIR) & ~(1 << (u8Timer & 0x03)));
}
switch(u8Timer)
{
case PWM_TIMER0:
case PWM_CAP0:
pfnPWMHandler.pfnCAP0CallBack = NULL;
pfnPWMHandler.pfnPWM0CallBack = NULL;
break;
case PWM_TIMER1:
case PWM_CAP1:
pfnPWMHandler.pfnCAP1CallBack = NULL;
pfnPWMHandler.pfnPWM1CallBack = NULL;
break;
case PWM_TIMER2:
case PWM_CAP2:
pfnPWMHandler.pfnCAP2CallBack = NULL;
pfnPWMHandler.pfnPWM2CallBack = NULL;
break;
case PWM_TIMER3:
case PWM_CAP3:
pfnPWMHandler.pfnCAP3CallBack = NULL;
pfnPWMHandler.pfnPWM3CallBack = NULL;
break;
}
if(((inp32(PIER) & 0xF) == 0) && ((inp32(CCR0) & 0x60006) == 0) && ((inp32(CCR1) & 0x60006) == 0))
sysDisableInterrupt(IRQ_PWM);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_ClearInt */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to clear the PWM timer/capture interrupt */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_ClearInt(UINT8 u8Timer)
{
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
outp32(CCR1, inp32(CCR1) & ~((1 << (((u8Timer & 0x01) << 4) + 4)) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)));
else
outp32(CCR0, inp32(CCR0) & ~((1 << (((u8Timer & 0x01) << 4) + 4)) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)));
}
else
outp32(PIIR, inp32(PIIR) & ~(1<<(u8Timer & 0x03)));
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetIntFlag */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* */
/* Returns: */
/* 0 FALSE */
/* 1 TRUE */
/* Side effects: */
/* Description: */
/* This function is used to get the PWM timer/capture interrupt flag */
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_GetIntFlag(UINT8 u8Timer)
{
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
{
if(inp32(CCR1) & (1 << (((u8Timer & 0x01) << 4) + 4)))
return TRUE;
else
return FALSE;
}
else
{
if(inp32(CCR0) & (1 << (((u8Timer & 0x01) << 4) + 4)))
return TRUE;
else
return FALSE;
}
}
else
{
if(inp32(PIIR) & (1<<(u8Timer & 0x03)))
return TRUE;
else
return FALSE;
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetRisingCounter */
/* */
/* Parameters: */
/* u8Capture - [in] PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* */
/* Returns: */
/* The value which latches the counter when thereˇs a rising transition */
/* */
/* Side effects: */
/* Description: */
/* This function is used to get value which latches the counter when thereˇs a rising */
/* transition */
/*---------------------------------------------------------------------------------------------------------*/
UINT16 PWM_GetRisingCounter(UINT8 u8Capture)
{
return inp32(CRLR0 + ((u8Capture & 0x7) << 3));
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetFallingCounter */
/* */
/* Parameters: */
/* u8Capture - [in] PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* */
/* Returns: */
/* The value which latches the counter when thereˇs a falling transition */
/* */
/* Side effects: */
/* Description: */
/* This function is used to get value which latches the counter when thereˇs a falling */
/* transition */
/*---------------------------------------------------------------------------------------------------------*/
UINT16 PWM_GetFallingCounter(UINT8 u8Capture)
{
return inp32(CFLR0 + ((u8Capture & 0x7)<< 3));
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_GetCaptureIntStatus */
/* */
/* Parameters: */
/* u8Capture - [in] PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* u8IntType - [in] PWM_CAP_RISING_FLAG/PWM_CAP_FALLING_FLAG */
/* */
/* Returns: */
/* Check if thereˇs a rising / falling transition */
/* */
/* Side effects: */
/* Description: */
/* This function is used to get the rising / falling transition interrupt flag */
/*---------------------------------------------------------------------------------------------------------*/
BOOL PWM_GetCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType)
{
if(u8Capture & 0x02)
{
if(inp32(CCR1) & (1 << (((u8Capture & 0x01) << 4) + u8IntType)))
return TRUE;
else
return FALSE;
}
else
{
if(inp32(CCR0) & (1 << (((u8Capture & 0x01) << 4) + u8IntType)))
return TRUE;
else
return FALSE;
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_ClearCaptureIntStatus */
/* */
/* Parameters: */
/* u8Capture - [in] PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* u8IntType - [in] PWM_CAP_RISING_FLAG/PWM_CAP_FALLING_FLAG */
/* */
/* Returns: */
/* Clear the rising / falling transition interrupt flag */
/* */
/* Side effects: */
/* Description: */
/* This function is used to clear the rising / falling transition interrupt flag */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_ClearCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType)
{
if(u8Capture & 0x02)
outp32(CCR1, (inp32(CCR1) & ~(CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)) | (1 << (((u8Capture & 0x01) << 4) + u8IntType)));
else
outp32(CCR0, (inp32(CCR0) & ~(CFLRD1 | CRLRD1 | CIIR1 | CFLRD0 | CRLRD0 |CIIR0)) | (1 << (((u8Capture & 0x01) << 4) + u8IntType)));
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Open */
/* */
/* Parameters: */
/* None */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* Enable PWM engine clock and reset PWM */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Open(VOID)
{
outp32(REG_APBCLK, inp32(REG_APBCLK)|PWM_CKE);
outp32(REG_APBIPRST, PWMRST);
outp32(REG_APBIPRST, inp32(REG_APBIPRST) & ~PWMRST);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Close */
/* */
/* Parameters: */
/* None */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* Disable PWM engine clock and the I/O enable */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Close(VOID)
{
outp32(POE, 0);
outp32(CAPENR,0x0);
sysDisableInterrupt(IRQ_PWM);
outp32(REG_APBCLK, inp32(REG_APBCLK) & ~PWM_CKE);
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_EnableDeadZone */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* u8Length - [in] Dead Zone Length : 0~255 */
/* bEnableDeadZone- [in] Enable DeadZone (TRUE) / Diasble DeadZone (FALSE) */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to set the dead zone length and enable/disable Dead Zone function */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_EnableDeadZone(UINT8 u8Timer, UINT8 u8Length,BOOL bEnableDeadZone)
{
if(u8Timer & 0x02)
{
outp32(PPR, (inp32(PPR) & ~DZI1) | ((u8Length & 0xFF) << 24));
outp32(PCR, (inp32(PCR) & ~DZEN1) | (bEnableDeadZone?DZEN1:0));
}
else
{
outp32(PPR, (inp32(PPR) & ~DZI0) | ((u8Length & 0xFF) << 16));
outp32(PCR, (inp32(PCR) & ~DZEN0) | (bEnableDeadZone?DZEN0:0));
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_Enable */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* bEnable - [in] Enable (TRUE) / Disable (FALSE) */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to enable PWM timer / capture function */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Enable(UINT8 u8Timer,BOOL bEnable)
{
outp32(PCR, (inp32(PCR)& ~(1 << ((u8Timer & 0x07) << 3) )) | (bEnable?(1 << ((u8Timer & 0x07) << 3) ):0) );
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
outp32(CCR1, (inp32(CCR1) & ~((1 << (((u8Timer & 0x01) << 4) + 3))) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)) | (bEnable?(1 << (((u8Timer & 0x01) << 4) + 3)):0));
else
outp32(CCR0, (inp32(CCR0) & ~((1 << (((u8Timer & 0x01) << 4) + 3))) | (CFLRD1 | CRLRD1 | CIIR1 | CFLRD0 | CRLRD0 |CIIR0)) | (bEnable?(1 << (((u8Timer & 0x01) << 4) + 3)):0));
}
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerClk */
/* */
/* Parameters: */
/* u8Timer PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* PWM_TIME_DATA_T *sPt */
/* u8Frequency Frequency */
/* u8HighPulseRatio High Pulse Ratio */
/* u8Mode PWM_ONE_SHOT_MODE / PWM_TOGGLE_MODE */
/* bInverter Inverter Enable (TRUE) / Inverter Disable (FALSE) */
/* u8ClockSelector Clock Selector */
/* PWM_CLOCK_DIV_1/PWM_CLOCK_DIV_2/PWM_CLOCK_DIV_4 */
/* PWM_CLOCK_DIV_8/PWM_CLOCK_DIV_16 */
/* (The parameter takes effect when u8Frequency = 0) */
/* u8PreScale Prescale (2 ~ 256) */
/* (The parameter takes effect when u8Frequency = 0) */
/* u32Duty Pulse duty */
/* (The parameter takes effect when u8Frequency = 0 or */
/* u8Timer = PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3) */
/* */
/* Returns: */
/* The actual frequency */
/* */
/* Side effects: */
/* Description: */
/* This function is used to configure the frequency/pulse/mode/inverter function */
/*---------------------------------------------------------------------------------------------------------*/
FLOAT PWM_SetTimerClk(UINT8 u8Timer, PWM_TIME_DATA_T *sPt)
{
FLOAT fFrequency;
UINT16 u16Duty;
UINT32 u32PllKHz, u32SysKHz, u32CpuKHz, u32HclkKHz, u32ApbKHz;
E_SYS_SRC_CLK eSrcClk;
sysGetSystemClock(&eSrcClk,
&u32PllKHz,
&u32SysKHz,
&u32CpuKHz,
&u32HclkKHz,
&u32ApbKHz);
u32ApbKHz = u32ApbKHz* 1000;
if(u8Timer & 0x10)
{
if(u8Timer & 0x02)
outp32(CCR1, (inp32(CCR1) & ~((1 << (((u8Timer & 0x01) << 4)))) | (CFLRD3 | CRLRD3 | CIIR3 | CFLRD2 | CRLRD2 |CIIR2)) | (sPt->bInverter?(1 << ((u8Timer & 0x01) << 4)):0));
else
outp32(CCR0, (inp32(CCR0) & ~((1 << (((u8Timer & 0x01) << 4)))) | (CFLRD1 | CRLRD1 | CIIR1 | CFLRD0 | CRLRD0 |CIIR0)) | (sPt->bInverter?(1 << ((u8Timer & 0x01) << 4)):0));
}
else
outp32(PCR, (inp32(PCR) & ~(1 << ((((u8Timer & 0x07)) << 3) + 2) )) |(sPt->bInverter?(1 << (((u8Timer & 0x07) << 3) + 2)):0));
outp32(PCR, (inp32(PCR) & ~(1 <<(((u8Timer & 0x07) << 3) + 3))) | ( sPt->u8Mode? (1 <<(((u8Timer & 0x07) << 3) + 3)):0));
if(sPt->fFrequency == 0)
{
UINT8 u8Divider;
if(u8Timer & 0x02)
outp32(PPR, (inp32(PPR) & ~CP1) | (((sPt->u8PreScale - 1) & 0xFF) << 8));
else
outp32(PPR, (inp32(PPR) & ~CP0) | ((sPt->u8PreScale - 1) & 0xFF));
u8Divider = 1;
switch(sPt->u8ClockSelector)
{
case PWM_CLOCK_DIV_1:
u8Divider = 4;
break;
case PWM_CLOCK_DIV_2:
u8Divider = 0;
break;
case PWM_CLOCK_DIV_4:
u8Divider = 1;
break;
case PWM_CLOCK_DIV_8:
u8Divider = 2;
break;
case PWM_CLOCK_DIV_16:
u8Divider = 3;
break;
}
outp32(PWM_CSR, (inp32(PWM_CSR) & ~(0x7 << ((u8Timer & 0x07)<<2) )) | ((u8Divider & 0x7) << ((u8Timer & 0x07)<<2)));
outp32(CNR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty - 1));
outp32(CMR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty * sPt->u8HighPulseRatio / 100 - 1));
fFrequency = (FLOAT)u32ApbKHz / sPt->u8PreScale / sPt->u8ClockSelector / sPt->u32Duty;
}
else
{
UINT8 u8Divider;
UINT16 u16PreScale;
fFrequency = (FLOAT) u32ApbKHz / sPt->fFrequency;
if(fFrequency > 0x10000000)
return 0;
u8Divider = 1;
if(fFrequency < 0x20000)
u16PreScale = 2;
else
{
u16PreScale = fFrequency / 65536;
if(fFrequency / u16PreScale > 65536)
u16PreScale++;
if(u16PreScale > 256)
{
UINT8 u8i;
u16PreScale = 256;
fFrequency = fFrequency / u16PreScale;
u8Divider = fFrequency / 65536;
if(fFrequency / u8Divider > 65536)
u8Divider++;
u8i = 0;
while(1)
{
if((1 << u8i++) > u8Divider)
break;
}
u8Divider = 1 << (u8i - 1);
if(u8Divider > 16)
return 0;
fFrequency = fFrequency * u16PreScale;
}
}
u16Duty = (UINT16 )(fFrequency/u16PreScale/u8Divider);
fFrequency = ((FLOAT) u32ApbKHz / u16PreScale / u8Divider) / u16Duty;
if(u8Timer & 0x02)
outp32(PPR, (inp32(PPR) & ~CP1) | (((u16PreScale - 1) & 0xFF) << 8));
else
outp32(PPR, (inp32(PPR) & ~CP0) | ((u16PreScale - 1) & 0xFF));
sPt->u8ClockSelector = u8Divider;
switch(u8Divider)
{
case 1:
u8Divider = 4;
break;
case 2:
u8Divider = 0;
break;
case 4:
u8Divider = 1;
break;
case 8:
u8Divider = 2;
break;
case 16:
u8Divider = 3;
break;
}
sPt->u8PreScale = u16PreScale;
outp32(PWM_CSR, (inp32(PWM_CSR) & ~(0x7 << ((u8Timer & 0x07)<<2) )) | ((u8Divider & 0x7) << ((u8Timer & 0x07)<<2)));
if(u8Timer & 0x10)
{
if(sPt->u32Duty != 0)
{
outp32(CNR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty - 1));
outp32(CMR0 + (u8Timer & 0x07) * 12, (sPt->u32Duty * sPt->u8HighPulseRatio / 100 - 1));
}
else
{
outp32(CNR0 + (u8Timer & 0x07) * 12, (u16Duty - 1));
outp32(CMR0 + (u8Timer & 0x07) * 12, (u16Duty * sPt->u8HighPulseRatio / 100 - 1));
}
}
else
{
outp32(CNR0 + (u8Timer & 0x07) * 12, (u16Duty - 1));
outp32(CMR0 + (u8Timer & 0x07) * 12, (u16Duty * sPt->u8HighPulseRatio / 100 - 1));
}
}
return fFrequency;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: PWM_SetTimerIO */
/* */
/* Parameters: */
/* u8Timer - [in] PWM_TIMER0/PWM_TIMER1/PWM_TIMER2/PWM_TIMER3 */
/* PWM_CAP0/PWM_CAP1/PWM_CAP2/PWM_CAP3 */
/* bEnable - [in] Enable (TRUE) / Diasble (FALSE) */
/* */
/* Returns: */
/* None */
/* */
/* Side effects: */
/* Description: */
/* This function is used to enable/disable PWM timer / capture I/O function */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_SetTimerIO(UINT8 u8Timer, BOOL bEnable)
{
if(bEnable)
{
if(u8Timer & 0x10)
outp32(CAPENR, inp32(CAPENR) | (1 << (u8Timer & 0x07)));
else
outp32(POE, inp32(POE) | (1 << (u8Timer & 0x07)));
outp32(REG_GPDFUN, (inp32(REG_GPDFUN) & ~(0x3 << ((u8Timer & 0x07) * 2))) | (0x2 << ((u8Timer & 0x07) * 2)));
}
else
{
if(u8Timer & 0x10)
outp32(CAPENR, inp32(CAPENR) & ~(1 << (u8Timer & 0x07)));
else
outp32(POE, inp32(POE) & ~(1 << (u8Timer & 0x07)));
outp32(REG_GPDFUN, (inp32(REG_GPDFUN) & ~(0x3 << ((u8Timer & 0x07) * 2))));
}
}
PWM.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/*---------------------------------------------------------------------------------------------------------*/
/* */
/* Copyright (c) Nuvoton Technology Corp. All rights reserved. */
/* */
/*---------------------------------------------------------------------------------------------------------*/
#ifndef __DRVPWM_H__
#define __DRVPWM_H__
/*---------------------------------------------------------------------------------------------------------*/
/* Includes of system headers */
/*---------------------------------------------------------------------------------------------------------*/
#include "wbio.h"
#include "w55fa93_reg.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*---------------------------------------------------------------------------------------------------------*/
/* Define Version number */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_MAJOR_NUM 1
#define PWM_MINOR_NUM 00
#define PWM_BUILD_NUM 1
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Timer */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_TIMER0 0x0
#define PWM_TIMER1 0x1
#define PWM_TIMER2 0x2
#define PWM_TIMER3 0x3
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Capture */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_CAP0 0x10
#define PWM_CAP1 0x11
#define PWM_CAP2 0x12
#define PWM_CAP3 0x13
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Capture Interrupt Enable/Disable Flag */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_CAP_RISING_INT 1
#define PWM_CAP_FALLING_INT 2
#define PWM_CAP_ALL_INT 0
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Capture Interrupt Flag */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_CAP_RISING_FLAG 6
#define PWM_CAP_FALLING_FLAG 7
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Clcok Selector */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_CLOCK_DIV_1 1
#define PWM_CLOCK_DIV_2 2
#define PWM_CLOCK_DIV_4 4
#define PWM_CLOCK_DIV_8 8
#define PWM_CLOCK_DIV_16 16
/*---------------------------------------------------------------------------------------------------------*/
/* PWM Mode Selector */
/*---------------------------------------------------------------------------------------------------------*/
#define PWM_TOGGLE_MODE TRUE
#define PWM_ONE_SHOT_MODE FALSE
/*---------------------------------------------------------------------------------------------------------*/
/* Define PWM Time Data Struct */
/*---------------------------------------------------------------------------------------------------------*/
typedef struct
{
UINT8 u8Mode;
FLOAT fFrequency;
UINT8 u8HighPulseRatio;
BOOL bInverter;
UINT8 u8ClockSelector;
UINT8 u8PreScale;
UINT32 u32Duty;
}PWM_TIME_DATA_T;
/*---------------------------------------------------------------------------------------------------------*/
/* Define PWM Call back funvtion Data Struct */
/*---------------------------------------------------------------------------------------------------------*/
typedef void (*PFN_PWM_CALLBACK)(void);
/*---------------------------------------------------------------------------------------------------------*/
/* Define PWM Call back function Data Struct */
/*---------------------------------------------------------------------------------------------------------*/
typedef struct
{
PFN_PWM_CALLBACK pfnPWM0CallBack;
PFN_PWM_CALLBACK pfnCAP0CallBack;
PFN_PWM_CALLBACK pfnPWM1CallBack;
PFN_PWM_CALLBACK pfnCAP1CallBack;
PFN_PWM_CALLBACK pfnPWM2CallBack;
PFN_PWM_CALLBACK pfnCAP2CallBack;
PFN_PWM_CALLBACK pfnPWM3CallBack;
PFN_PWM_CALLBACK pfnCAP3CallBack;
}PWM_CALLBACK_T;
/*---------------------------------------------------------------------------------------------------------*/
/* Define PWM functions prototype */
/*---------------------------------------------------------------------------------------------------------*/
VOID PWM_Open(VOID);
VOID PWM_Close(VOID);
VOID PWM_SetTimerCounter(UINT8 u8Timer, UINT16 u16Counter);
VOID PWM_EnableInt(UINT8 u8Timer, UINT8 u8Int);
VOID PWM_ClearInt(UINT8 u8Timer);
VOID PWM_DisableInt(UINT8 u8Timer, UINT8 u8Int);
VOID PWM_ClearCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType);
VOID PWM_EnableDeadZone(UINT8 u8Timer, UINT8 u8Length, BOOL bEnableDeadZone);
VOID PWM_SetTimerIO(UINT8 u8Timer, BOOL bEnable);
VOID PWM_Enable(UINT8 u8Timer, BOOL bEnable);
BOOL PWM_IsTimerEnabled(UINT8 u8Timer);
BOOL PWM_GetCaptureIntStatus(UINT8 u8Capture, UINT8 u8IntType);
BOOL PWM_GetIntFlag(UINT8 u8Timer);
UINT16 PWM_GetRisingCounter(UINT8 u8Capture);
UINT16 PWM_GetFallingCounter(UINT8 u8Capture);
UINT32 PWM_GetTimerCounter(UINT8 u8Timer);
FLOAT PWM_SetTimerClk(UINT8 u8Timer, PWM_TIME_DATA_T *sPt);
VOID PWM_InstallCallBack(UINT8 u8Timer, PFN_PWM_CALLBACK pfncallback, PFN_PWM_CALLBACK *pfnOldcallback);
#ifdef __cplusplus
}
#endif
#endif
T168_111\core\N32903文件:第15~19个文件
最新推荐文章于 2024-09-25 10:59:43 发布