📄 fmd.cpp
字号:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2002 Microsoft Corporation
Module Name: FMD.CPP
Abstract: FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
on AT-Rise development board.
Notes: Currently, *only* the CE 3.0 (and earlier) power management logic
is implemented (i.e. the PowerUp() and PowerDown() APIs).
Environment: As noted, this media driver works on behalf of the FAL to directly
access the underlying FLASH hardware. Consquently, this module
needs to be linked with FAL.LIB to produce the device driver
named FLASHDRV.DLL.
-----------------------------------------------------------------------------*/
#include <fmd.h>
#include <s3c2440x.h>
#include "cfnand.h"
#include "args.h"
#include "image_cfg.h"
#define NAND_BASE 0xB0E00000
#define IOP_BASE 0xB1600000
#define BADBLOCKMARK 0x00
#define MAX_REGIONS 16
static FlashRegion g_pRegionTable[MAX_REGIONS];
static DWORD g_dwNumRegions;
static FlashInfo g_flashInfo;
// TODO: Make sector size generic
static BYTE g_pFLSBuffer[SECTOR_SIZE];
#define DEFAULT_COMPACTION_BLOCKS 4
// Registers
volatile PUSHORT pNFReg;
volatile PUSHORT pNFCONF;
volatile PUSHORT pNFCONT;
volatile PUSHORT pNFCMD;
volatile PUSHORT pNFADDR;
volatile PULONG pNFDATA;
volatile PUSHORT pNFSTAT;
volatile PULONG pNFMECCD0;
volatile PULONG pNFMECCD1;
volatile PULONG pNFESTAT0;
volatile PULONG pNFESTAT1;
volatile PULONG pNFMECC0;
volatile PULONG pNFMECC1;
volatile PULONG pNFECC;
volatile PULONG pNFSBLK;
volatile PULONG pNFEBLK;
#define NFDATA 0x4E000010
S3C2440X_IOPORT_REG *v_pIOPregs;
static BOOL DefineLayout();
//void NANDTest();
// External function
extern "C" {
BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);
}
#define LOW 0
#define HIGH 1
void SetChipSelect(int mode, int status)
{
if ( status == LOW )
NF_CE_L();
else // if ( status == HIGH )
NF_CE_H();
}
// Reset the chip
//
void NF_Reset()
{
BOOL bLastMode = SetKMode(TRUE);
// Do not anything...
// if ()
// {
// LB_NF_Reset(USE_NFCE);
// SB_NF_Reset(USE_GPIO);
// }
// else
// {
// LB_NF_Reset(USE_GPIO);
// SB_NF_Reset(USE_NFCE);
// }
SetKMode(bLastMode);
}
/*
* NAND_ReadSectorInfo
*
* Read SectorInfo out of the spare area. The current implementation only handles
* one sector at a time.
*/
void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
RETAILMSG(1, (TEXT("FMD::NAND_ReadSectorInfo ++ \r\n")));
if ( sectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
NAND_LB_ReadSectorInfo(sectorAddr, pInfo, USE_NFCE);
else
NAND_SB_ReadSectorInfo(sectorAddr, pInfo, USE_NFCE);
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
NAND_LB_ReadSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
else
NAND_SB_ReadSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
}
RETAILMSG(1, (TEXT("FMD::NAND_ReadSectorInfo -- \r\n")));
}
/*
* NAND_WriteSectorInfo
*
* Write SectorInfo out to the spare area. The current implementation only handles
* one sector at a time.
*/
BOOL NAND_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
BOOL bRet = TRUE;
if ( sectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
bRet = NAND_LB_WriteSectorInfo(sectorAddr, pInfo, USE_NFCE);
else
bRet = NAND_SB_WriteSectorInfo(sectorAddr, pInfo, USE_NFCE);
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
bRet = NAND_LB_WriteSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
else
bRet = NAND_SB_WriteSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
}
return bRet;
}
/*-----------------------------------------------------------------------------
* FMD Interface functions
*
*----------------------------------------------------------------------------*/
// FMD_Init
//
// Initialize the flash chip
//
// Note: Presently, the Flash size characteristics are hardcoded in CFNAND.H
// and are NOT stored in the registry. Refer to the StratFlash FMD in
// %WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\BLOCK\... for an example of how
// to use the registry for storing this information.
//
PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
BSP_ARGS *pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);
RETAILMSG(1, (TEXT("FMD::FMD_Init\r\n")));
// 0. Create the Mutex for shared access between the kernel and MSFLASH
// RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: pNFReg = %x \r\n"), pNFReg));
pNFReg = (PUSHORT) (NAND_BASE);
//#if defined SMALLBLOCK_FIRST || defined LARGEBLOCK_FIRST
v_pIOPregs = (S3C2440X_IOPORT_REG*)(IOP_BASE);
//#endif
pNFCONF = pNFReg;
pNFCONT = (PUSHORT) ((PBYTE) pNFReg + 0x04);
pNFCMD = (PUSHORT) ((PBYTE) pNFReg + 0x08);
pNFADDR = (PUSHORT) ((PBYTE) pNFReg + 0x0C);
pNFDATA = (PULONG) ((PBYTE) pNFReg + 0x10);
pNFMECCD0 = (PULONG) ((PBYTE) pNFReg + 0x14);
pNFMECCD1 = (PULONG) ((PBYTE) pNFReg + 0x18);
pNFSTAT = (PUSHORT) ((PBYTE) pNFReg + 0x20);
pNFESTAT0 = (PULONG) ((PBYTE) pNFReg + 0x24);
pNFESTAT1 = (PULONG) ((PBYTE) pNFReg + 0x28);
pNFMECC0 = (PULONG) ((PBYTE) pNFReg + 0x2C);
pNFMECC1 = (PULONG) ((PBYTE) pNFReg + 0x30);
pNFECC = (PULONG) ((PBYTE) pNFReg + 0x2C);
pNFSBLK = (PULONG) ((PBYTE) pNFReg + 0x38);
pNFEBLK = (PULONG) ((PBYTE) pNFReg + 0x3C);
// Now we need enable the NAND Flash controller
BOOL bLastMode = SetKMode(TRUE);
WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
WRITE_REGISTER_USHORT(pNFSTAT, 0);
DefineLayout();
WRITE_REGISTER_ULONG(pNFEBLK, 0xFFFFE0); // Maximum Number
#ifdef ULDR
WRITE_REGISTER_ULONG(pNFSBLK, 0x0); // Minimum Number
#else
RETAILMSG(1, (TEXT("FMD::FMD_Init - pBSPArgs->nfsblk = 0x%x \r\n"), pBSPArgs->nfsblk));
RETAILMSG(1, (TEXT("FMD::FMD_Init - READ_REGISTER_BYTE(pNFSBLK) = 0x%x \r\n"), READ_REGISTER_ULONG(pNFSBLK)));
if ( (READ_REGISTER_ULONG(pNFSBLK) >> 5) == 0 ) // soft reset or IPL
{
if ( pBSPArgs->nfsblk == 0 ) // IPL
{
RETAILMSG(1, (TEXT("FMD::FMD_Init IPL ..... \r\n")));
}
else
{
RETAILMSG(1, (TEXT("FMD::FMD_Init Softreset ..... \r\n")));
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 ) // Large Block
{
WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 6); // Minimum Number
}
else
{
WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5); // Minimum Number
}
WRITE_REGISTER_USHORT(pNFCONT, READ_REGISTER_USHORT(pNFCONT) | (1<<13));
}
}
else
{
RETAILMSG(1, (TEXT("FMD::FMD_Init First Booting IN OS .... \r\n")));
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 ) // Large Block
{
WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 6); // Minimum Number
}
else
{
WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5); // Minimum Number
}
// WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5); // Minimum Number
WRITE_REGISTER_USHORT(pNFCONT, READ_REGISTER_USHORT(pNFCONT) | (1<<13));
}
#endif
//#if defined SMALLBLOCK_FIRST || defined LARGEBLOCK_FIRST
//v_pIOPregs->GPACON &= ~(1<<16);
//v_pIOPregs->GPADAT |= (1<<16);
//#endif
SetKMode(bLastMode);
RETAILMSG(1, (TEXT("FMD::FMD_Init Done\r\n")));
// NANDTest();
return (PVOID)pNFCONF;
}
// FMD_Deinit
//
// De-initialize the flash chip
//
BOOL FMD_Deinit(PVOID hFMD)
{
return TRUE;
}
/*****************************************************************************/
/* */
/* NAME */
/* _ReadXID */
/* DESCRIPTION */
/* This function reads ManufavturerID and DeviceID. */
/* PARAMETERS */
/* pMID */
/* NAND Flash Manufacturer ID */
/* NOW, only detect SAMSUNG (0xEC) */
/* pDID */
/* NAND Flash device ID */
/* RETURN VALUES */
/* FAIL */
/* In case of ID Finding Failure */
/* TRUE */
/* Operation success */
/* NOTES */
/* */
/*****************************************************************************/
INT32
_ReadXID(UINT8* pMID, UINT8* pDID, int mode)
{
UINT32 nCnt, nRet;
UINT8 n4thcycle, nBuff;
int i;
// RETAILMSG(1, (TEXT("[S2440: IN] ++_ReadXID()\r\n")));
n4thcycle = nBuff = 0;
BOOL bLastMode = SetKMode(TRUE);
SetChipSelect(mode, LOW);
NF_CLEAR_RB();
NF_CMD (CMD_READ_ID);
NF_ADDR (0x00);
for ( i = 0; i < 100; i++ );
/* tREA is necessary to Get a MID. */
for (nCnt = 0; nCnt < 5; nCnt++)
{
*pMID = (BYTE) NF_DATA_R();
if (0xEC == *pMID)
break;
}
*pDID = (BYTE) NF_DATA_R();
nBuff = (BYTE) NF_DATA_R();
n4thcycle = (BYTE) NF_DATA_R();
SetChipSelect(mode, HIGH);
SetKMode(bLastMode);
if (*pMID != (UINT8)0xEC)
{
RETAILMSG(1, (TEXT("[S2440 : ERR] ID Finding Failure\r\n")));
nRet = FALSE;
}
else
{
RETAILMSG(1, (TEXT("MID = 0x%x, DID = 0x%x 4th Cycle : 0x%x\n"),*pMID, *pDID, n4thcycle));
nRet = TRUE;
}
// RETAILMSG(1, (TEXT("[S2440 : OUT] --_ReadXID()\r\n")));
return (nRet);
}
// FMD_GetInfo
//
// Return the Flash information
//
BOOL FMD_GetInfo(PFlashInfo pFlashInfo)
{
UINT32 nCnt;
UINT8 nMID, nDID;
if (!pFlashInfo)
return(FALSE);
pFlashInfo->flashType = NAND;
if (_ReadXID(&nMID, &nDID, USE_NFCE) != TRUE)
{
RETAILMSG(1, (TEXT("[FMD_GetInfo : ERR] _ReadXID() Error\r\n")));
return (FALSE);
}
for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
{
if (nDID == astNandSpec[nCnt].nDID)
{
break;
}
}
dwPrimaryNandDevice = nCnt;
wPRIMARY_REAL_NAND_BLOCKS = astNandSpec[dwPrimaryNandDevice].nNumOfBlks;
wSECONDARY_NAND_BLOCKS = 0;
wSECONDARY_REAL_NAND_BLOCKS = 0;
// RETAILMSG(1, (TEXT("dwPrimaryNandDevice : %d(0x%x) \r\n"), dwPrimaryNandDevice, dwPrimaryNandDevice));
// RETAILMSG(1, (TEXT("astNandSpec[dwPrimaryNandDevice].nSctsPerPg: %d(0x%x) \r\n"), astNandSpec[dwPrimaryNandDevice].nSctsPerPg, astNandSpec[dwPrimaryNandDevice].nSctsPerPg));
// RETAILMSG(1, (TEXT("wPRIMARY_REAL_NAND_BLOCKS : %d(0x%x) \r\n"), wPRIMARY_REAL_NAND_BLOCKS, wPRIMARY_REAL_NAND_BLOCKS));
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 ) // Primary NAND is Large Block...
{
wPRIMARY_NAND_BLOCKS = wPRIMARY_REAL_NAND_BLOCKS;
}
else
{
wPRIMARY_NAND_BLOCKS = wPRIMARY_REAL_NAND_BLOCKS / 8;
}
wNUM_BLOCKS = wPRIMARY_NAND_BLOCKS + wSECONDARY_NAND_BLOCKS;
// OK, instead of reading it from the chip, we use the hardcoded
// numbers here.
pFlashInfo->dwNumBlocks = wNUM_BLOCKS;
pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK;
pFlashInfo->wDataBytesPerSector = SECTOR_SIZE;
pFlashInfo->dwBytesPerBlock = (pFlashInfo->wSectorsPerBlock * pFlashInfo->wDataBytesPerSector);
RETAILMSG(1, (TEXT("NUMBLOCKS : %d(0x%x), SECTORSPERBLOCK = %d(0x%x), BYTESPERSECTOR = %d(0x%x) \r\n"), pFlashInfo->dwNumBlocks, pFlashInfo->dwNumBlocks, pFlashInfo->wSectorsPerBlock, pFlashInfo->wSectorsPerBlock, pFlashInfo->wDataBytesPerSector, pFlashInfo->wDataBytesPerSector));
return TRUE;
}
BOOL FMD_GetInfoEx(PFlashInfoEx pFlashInfo, PDWORD pdwNumRegions)
{
// Temp
RETAILMSG(1, (L"FMD_GetInfoEx enter.\r\n"));
if (!pdwNumRegions)
{
return FALSE;
}
if (!pFlashInfo)
{
// Return required buffer size to caller
*pdwNumRegions = g_dwNumRegions;
return TRUE;
}
if (*pdwNumRegions < g_dwNumRegions)
{
*pdwNumRegions = g_dwNumRegions;
DEBUGMSG (1, (TEXT("FMD_GetInfoEx: Insufficient buffer for number of regions")));
return FALSE;
}
memcpy (pFlashInfo->region, g_pRegionTable, g_dwNumRegions * sizeof(FlashRegion));
// Temp
for (DWORD iRegion = 0; iRegion < g_dwNumRegions; iRegion++) {
RETAILMSG(1, (L"Type=%d, StartP=0x%x, NumP=0x%x, NumL=0x%x, Sec/Blk=0x%x, B/Blk=0x%x, Compact=%d.\r\n",
g_pRegionTable[iRegion].regionType,
g_pRegionTable[iRegion].dwStartPhysBlock,
g_pRegionTable[iRegion].dwNumPhysBlocks,
g_pRegionTable[iRegion].dwNumLogicalBlocks,
g_pRegionTable[iRegion].dwSectorsPerBlock,
g_pRegionTable[iRegion].dwBytesPerBlock,
g_pRegionTable[iRegion].dwCompactBlocks));
}
*pdwNumRegions = g_dwNumRegions;
pFlashInfo->cbSize = sizeof(FlashInfoEx);
pFlashInfo->flashType = NAND;
pFlashInfo->dwNumBlocks = wNUM_BLOCKS;
pFlashInfo->dwDataBytesPerSector = SECTOR_SIZE;
pFlashInfo->dwNumRegions = g_dwNumRegions;
return(TRUE);
}
static BOOL DefineLayout()
{
PFlashRegion pRegion = NULL;
DWORD dwBlock = 0;
if (!FMD_GetInfo (&g_flashInfo)) {
return FALSE;
}
// Find the MBR to determine if there is a flash layout sector
g_dwNumRegions = 0;
// Find the first usuable block
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -