📄 nand.c
字号:
//
// Copyright (c) Craftsman Software. All rights reserved.
//
// AUTHOR : junwei cheng
// E-MAIL : chjw_ch@yahoo.com
//
#include "nand.h"
#include "2440lib.h"
#ifdef __cplusplus
extern "C" {
#endif
//0 - no debug, 1 - debug command output
#define DEBUG_COMMAND 0
#ifdef DEBUG_COMMAND
#define DebugPrintf(x) {if(DEBUG_COMMAND) Uart_Printf x;}
#else
#define DebugPrintf(x)
#endif
//
//Advance NAND flash memory for auto-booting
//NAND_Normal, NAND_Advance
static int AdvFlash;
//NAND flash memory Address cycle for auto-booting AdvFlash AddrCycle.
//ADDR_CYCLE_3, ADDR_CYCLE_4
static int AddrCycle;
//Spare size
static int SpareSize; //16, 64
//pages per block bits count, used to convert data
static int PagesPerBlockBits;
//flash chip information
static FlashInfo g_ChipInfo;
//ChipID 2 NumBlocks
static DWORD ChipID2NumBlocks[][2] =
{
{0xECA1, 1024}, //K9F1G08Q0M
{0xECF1, 1024}, //K9F1G08U0M
{0xECB1, 1024}, //K9F1G16Q0M
{0xECC1, 1024}, //K9F1G16U0M
{0xECAA, 2048}, //K9F2G08Q0M
{0xECDA, 2048}, //K9F2G08U0M
{0xECBA, 2048}, //K9F2G16Q0M
{0xECCA, 2048}, //K9F2G16U0M
{0xECAC, 4096}, //K9K4G08Q0M
{0xECDC, 4096}, //K9K4G08U0M
{0xECBC, 4096}, //K9K4G16Q0M
{0xECCC, 4096}, //K9K4G16U0M
{0xECD3, 8192}, //K9K8G08U0M, K9WAG08U1M
};
//----------------------------------------------------------------------------------------
// NAND Flash Macros
//----------------------------------------------------------------------------------------
#define NF_ENABLE() {rNFCONT |= 1;}
#define NF_DISABLE() {rNFCONT &= ~1;}
#define NF_nFCE_L() {rNFCONT &= ~(1<<1);}
#define NF_nFCE_H() {rNFCONT |= (1<<1);}
#define NF_CMD(cmd) {rNFCMD = (BYTE)(cmd); DebugPrintf(("rNFCMD =0x%02x\n",cmd));}
#define NF_ADDR(addr) {rNFADDR = (BYTE)(addr);DebugPrintf(("rNFADDR=0x%02x\n",addr));}
#define NF_RDATA() (rNFDATA)
#define NF_WDATA(dat) {rNFDATA=(dat);}
#define NF_RDATA8() (rNFDATA8)
#define NF_WDATA8(dat) {rNFDATA8=(BYTE)(dat);}
//ready to operate?
#define NF_RnB() (rNFSTAT&1)
#define NF_WAIT_RnB() {while(!NF_RnB());DebugPrintf(("WaitRnB\n"));}
//ECC -----------------------------------------------------------------------------------
#define NF_InitECC() {rNFCONT |= (1<<4);}
#define NF_MainECCLock() {rNFCONT |= (1<<5);}
#define NF_MainECCUnlock() {rNFCONT &= ~(1<<5);}
//n= 0, 1, 2, 3
#define NF_MECCData8(n) ((rNFMECCD##(n>>1) << ((n&1) * 16) & 0xff)
#define NF_MECCData(n) ((rNFMECCD##(n>>1) << ((n&1) * 16) & 0xffff)
#define NF_SpareECCLock() {rNFCONT |= (1<<6);}
#define NF_SpareECCUnlock() {rNFCONT &= ~(1<<6);}
//n= 0, 1
#define NF_SECCData8(n) ((rNFSECCD << ((n&1) * 16) & 0xff)
#define NF_SECCData(n) ((rNFSECCD << ((n&1) * 16) & 0xffff)
//---------------------------------------------------------------------------------------
//status bits
#define NF_STATUS_FAILED(status) (status&(1<<0))
#define NF_STATUS_READY(status) (status&(1<<6))
#define NF_STATUS_NotProtected(status) (status&(1<<7))
//macros
#define BLOCK_TO_PAGE(block) (block << PagesPerBlockBits)
#define PAGE_TO_BLOCK(page) (page >> PagesPerBlockBits)
#define NF_ADDR_COL(col_addr) \
NF_ADDR(col_addr); \
if(AdvFlash == NAND_Advance) \
{ \
NF_ADDR(col_addr >> 8); \
} \
#define NF_ADDR_ROW(row_addr) \
NF_ADDR(row_addr); \
NF_ADDR(row_addr >> 8); \
if(AddrCycle == ADDR_CYCLE_4) \
{ \
NF_ADDR(row_addr >> 16); \
} \
#define NF_READ_STATUS(status_var) \
NF_CMD(CMD_ReadStatus); \
status_var = NF_RDATA8(); \
// Private method
// Normal mode (512)
static BOOL NF_Write(SECTOR_ADDR pages, DWORD offset_bytes, const void* pdata, DWORD len);
static BOOL NF_Read(SECTOR_ADDR pages, DWORD offset_bytes, void* pdata, DWORD len);
static BOOL NF_WriteSpare(SECTOR_ADDR pages, const void* pdata, DWORD len);
static BOOL NF_ReadSpare(SECTOR_ADDR pages, void* pdata, DWORD len);
// Advanced mode (2048)
static BOOL NF_WriteAdv(SECTOR_ADDR pages, DWORD offset_bytes, const void* pdata, DWORD len);
static BOOL NF_ReadAdv(SECTOR_ADDR pages, DWORD offset_bytes, void* pdata, DWORD len);
static BOOL NF_WriteSpareAdv(SECTOR_ADDR pages, const void* pdata, DWORD len);
static BOOL NF_ReadSpareAdv(SECTOR_ADDR pages, void* pdata, DWORD len);
static BOOL NF_ReadChipInfo(FlashInfo *pFlashInfo);
//others
#ifdef __cplusplus
extern "C" {
#endif
void __RdPageBytes(void* buffer, int count);
void __WrPageBytes(const void* buffer, int count);
#ifdef __cplusplus
}
#endif
//----------------------------------------------------------------------------------------
//
// HCLK=133Mhz
//----------------------------------------------------------------------------------------
#define TACLS 0
#define TWRPH0 6
#define TWRPH1 0
//----------------------------------------------------------------------------------------
// NAND Flash Intefaces
//----------------------------------------------------------------------------------------
DWORD Nand_BlockToPage(BLOCK_ID blockID)
{
return BLOCK_TO_PAGE(blockID);
}
DWORD Nand_PageToBlock(DWORD page)
{
return PAGE_TO_BLOCK(page);
}
/*
* Nand flash characterisc
*
* Return
* [0] 0 - 8-Bit bus width,1 - 16-Bit bus width
* [1] 0 - 3,4 cycles, 1 - 4,5 cycles
* [2] 0 - By word, 1 - By byte
* [3] 0 - Normal, 1 - Advance
* [4-31] Reserved.
*/
DWORD Nand_Characteristic(void)
{
return (rNFCONF & 0xF);
}
/*
* page size
*
* Return
* page size, 512, 2048
*/
DWORD Nand_PageSize(void)
{
return g_ChipInfo.wDataBytesPerSector;
}
/*
* pages of one block
*
* Return
* pages per block , 32, 64
*/
DWORD Nand_PagesPerBlock(void)
{
return g_ChipInfo.wSectorsPerBlock;
}
/*
* Init Nand Flash register
*/
BOOL Nand_Init(void)
{
DebugPrintf(("TACLS=%d,TWRPH0=%d,TWRPH1=%d\n", TACLS, TWRPH0, TWRPH1));
// for S3C2440
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
// TACLS [13:12] CLE&ALE duration = HCLK*TACLS.
// TWRPH0 [10:8] TWRPH0 duration = HCLK*(TWRPH0+1)
// TWRPH1 [6:4] TWRPH1 duration = HCLK*(TWRPH1+1)
// AdvFlash(R) [3] Advanced NAND, 0:256/512, 1:1024/2048
// PageSize(R) [2] NAND memory page size
// when [3]==0, 0:256, 1:512 bytes/page.
// when [3]==1, 0:1024, 1:2048 bytes/page.
// AddrCycle(R) [1] NAND flash addr size
// when [3]==0, 0:3-addr, 1:4-addr.
// when [3]==1, 0:4-addr, 1:5-addr.
// BusWidth(R/W) [0] NAND bus width. 0:8-bit, 1:16-bit.
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0);
// Lock-tight [13] 0:Disable lock, 1:Enable lock.
// Soft Lock [12] 0:Disable lock, 1:Enable lock.
// EnablillegalAcINT[10] Illegal access interupt control. 0:Disable, 1:Enable
// EnbRnBINT [9] RnB interrupt. 0:Disable, 1:Enable
// RnB_TrandMode[8] RnB transition detection config. 0:Low to High, 1:High to Low
// SpareECCLock [6] 0:Unlock, 1:Lock
// MainECCLock [5] 0:Unlock, 1:Lock
// InitECC(W) [4] 1:Init ECC decoder/encoder.
// Reg_nCE [1] 0:nFCE=0, 1:nFCE=1.
// NANDC Enable [0] operating mode. 0:Disable, 1:Enable.
rNFSTAT = 0;
//-------------------------------------------------------------------------------------------------------------
//Read Extended Information
AdvFlash = (rNFCONF >> 3) & 1;
AddrCycle = (rNFCONF >> 1) & 1;
// AdvFlash (Read only) [3] Advance NAND flash memory for auto-booting
// 0: Support 256 or 512 byte/page NAND flash memory
// 1: Support 1024 or 2048 byte/page NAND flash memory
// This bit is determined by NCON0 pin status during reset and wake-up from sleep mode
// PageSize (Read only) [2] NAND flash memory page size for auto-booting AdvFlash PageSize
// When AdvFlash is 0,
// 0: 256 Word/page, 1: 512 Bytes/page
// When AdvFlash is 1,
// 0: 1024 Word/page, 1: 2048 Bytes/page
// This bit is determined by GPG13 pin status during reset and wake-up from sleep mode.
// After reset, the GPG13 can be used as general I/O port or External interrupt.
//AddrCycle (Read only) [1] NAND flash memory Address cycle for auto-booting AdvFlash AddrCycle
// When AdvFlash is 0,
// 0: 3 address cycle 1: 4 address cycle
// When AdvFlash is 1,
// 0: 4 address cycle 1: 5 address cycle
// This bit is determined by GPG14pin status during reset and wake-up from sleep mode.
// After reset, the GPG14can be used as general I/O port or External interrupt.
g_ChipInfo.flashType = NAND;
//pre-calculate parameters
if(AdvFlash == NAND_Advance)
{
SpareSize = 64;
PagesPerBlockBits = 6;
g_ChipInfo.wDataBytesPerSector = 2048;
g_ChipInfo.wSectorsPerBlock = (1 << PagesPerBlockBits);
g_ChipInfo.dwBytesPerBlock = (g_ChipInfo.wDataBytesPerSector + SpareSize) * g_ChipInfo.wSectorsPerBlock;
}
else
{
SpareSize = 16;
PagesPerBlockBits = 5;
g_ChipInfo.wDataBytesPerSector = 512;
g_ChipInfo.wSectorsPerBlock = (1 << PagesPerBlockBits);
g_ChipInfo.dwBytesPerBlock = (g_ChipInfo.wDataBytesPerSector + SpareSize) * g_ChipInfo.wSectorsPerBlock;
}
if(!NF_ReadChipInfo(&g_ChipInfo))
{
return FALSE;
}
return TRUE;
}
/*
* Reset Nand Flash Chip
*/
void Nand_Reset(void)
{
NF_nFCE_L();
NF_CMD(CMD_Reset);
NF_WAIT_RnB();
NF_nFCE_H();
}
/*
* Read Nand Flash Chip ID
*
* Return
* Flash Chip ID
*/
U16 Nand_ReadID(void)
{
U16 id;
NF_nFCE_L();
NF_CMD(CMD_ReadID);
NF_ADDR(0x00);
id = NF_RDATA8() << 8;
id |= NF_RDATA8();
NF_nFCE_H();
return (id);
}
// Nand_GetInfo
//
// Return the Flash information
//
BOOL Nand_GetInfo(PFlashInfo pFlashInfo)
{
pFlashInfo->flashType = NAND;
// OK, instead of reading it from the chip, we use the hardcoded
// numbers here.
pFlashInfo->dwNumBlocks = NUM_BLOCKS;
pFlashInfo->wSectorsPerBlock = Nand_PagesPerBlock();
pFlashInfo->wDataBytesPerSector = Nand_PageSize();
return TRUE;
}
/*
* Read Nand Flash Operation Status
*
* Return
* status byte
*/
BYTE Nand_ReadStatus(void)
{
BYTE status;
NF_nFCE_L();
NF_READ_STATUS(status);
NF_nFCE_H();
return status;
}
/*
* Erase a block
*
* Parameter
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -