?? fmd.cpp
字號(hào):
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include <fmd.h>
#include <s3c2443_nand.h>
#include <args.h>
#include <ethdbg.h>
#include "Cfnand.h"
#if MAGNETO
#include "args.h"
#include <image_cfg.h>
#endif
#define CHECK_SPAREECC 1
#define NAND_BASE 0xB1400000 // PA:0x4e00_0000
#if MAGNETO
#define MAX_REGIONS 16
#define BAD_BLOCKS_MAS 20 // 2% of total block size
BSP_ARGS *pBSPArgs;
#endif
static volatile S3C2443_NAND_REG *s2443NAND = (S3C2443_NAND_REG *)NAND_BASE;
extern "C" void RdPage512(unsigned char *bufPt);
extern "C" void RdPage2048(unsigned char *bufPt);
extern "C" void RdPage512Unalign(unsigned char *bufPt);
extern "C" void WrPage512(unsigned char *bufPt);
extern "C" void WrPage512Unalign(unsigned char *bufPt);
extern "C" void WrPageInfo(PBYTE pBuff);
extern "C" void RdPageInfo(PBYTE pBuff);
extern "C" void RdPageSpare(PBYTE pBuff);
#if MAGNETO
static BOOL DefineLayout();
static FlashRegion g_pRegionTable[MAX_REGIONS];
static DWORD g_dwNumRegions;
static FlashInfo g_flashInfo;
// TODO: Make sector size generic
static BYTE g_pFLSBuffer[NAND_SECTOR_SIZE];
#define DEFAULT_COMPACTION_BLOCKS 4
#endif
NANDDeviceInfo GetNandInfo(void) { return stDeviceInfo; }
/*
@func DWORD | ReadFlashID | Reads the flash manufacturer and device codes.
@rdesc Manufacturer and device codes.
@comm
@xref
*/
static DWORD ReadFlashID(void)
{
BYTE Mfg, Dev;
NF_nFCE_L(); // Deselect the flash chip.
NF_CMD(CMD_READID); // Send flash ID read command.
NF_ADDR(0); //
Mfg = NF_RDDATA_BYTE(); //
Dev = NF_RDDATA_BYTE(); //
NF_nFCE_H(); // Deselect the flash chip.
return ((DWORD)(Mfg<<8)+Dev);
}
/*
@func PVOID | FMD_Init | Initializes the Smart Media NAND flash controller.
@rdesc Pointer to S3C2443 NAND controller registers.
@comm
@xref
*/
PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
// Caller should have specified NAND controller address.
//
BOOL bLastMode = SetKMode(TRUE);
volatile DWORD nNandID;
UINT8 nMID, nDID;
UINT32 nCnt;
BOOL bNandExt = FALSE;
RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_INIT \r\n")));
#if MAGNETO
pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);
#endif
if (pRegIn && pRegIn->MemBase.Num && pRegIn->MemBase.Reg[0])
s2443NAND = (S3C2443_NAND_REG *)(pRegIn->MemBase.Reg[0]);
else
s2443NAND = (S3C2443_NAND_REG *)NAND_BASE;
// Set up initial flash controller configuration.
//
s2443NAND->NFCONF = (TACLS << 12) | /* CLE & ALE = HCLK * (TACLS + 1) */
(TWRPH0 << 8) | /* TWRPH0 = HCLK * (TWRPH0 + 1) */
(TWRPH1 << 4);
s2443NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
s2443NAND->NFSTAT = (1<<4);
// Get manufacturer and device codes.
nNandID = ReadFlashID();
RETAILMSG(1, (TEXT(" (NAND ID:0x%x) --> "), nNandID));
nMID = (UINT8)(nNandID >> 8);
nDID = (UINT8)(nNandID & 0xff);
for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
{
if (nDID == astNandSpec[nCnt].nDID)
{
bNandExt = TRUE;
break;
}
}
if (!bNandExt)
{
RETAILMSG(1, (TEXT("Error!!!\n")));
SetKMode (bLastMode);
return(NULL);
}
else
{
RETAILMSG(1, (TEXT("OK.\n")));
}
NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;
PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk;
SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg;
RETAILMSG(1, (TEXT(" NUM_OF_BLOCKS = %d \r\n"), NUM_OF_BLOCKS));
RETAILMSG(1, (TEXT(" PAGES_PER_BLOCK = %d \r\n"), PAGES_PER_BLOCK));
RETAILMSG(1, (TEXT(" SECTORS_PER_PAGE = %d \r\n"), SECTORS_PER_PAGE));
#if MAGNETO
DefineLayout();
#endif
SetKMode (bLastMode);
return((PVOID)s2443NAND);
}
/*
@func BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
BOOL bRet;
// RETAILMSG(1, (TEXT("FMD::FMD_ReadSector 0x%x \r\n"), startSectorAddr));
if ( IS_LB )
bRet = FMD_LB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
else
bRet = FMD_SB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
return bRet;
}
/*
@func BOOL | FMD_WriteSector | Writes the specified sector(s) to NAND flash.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,
DWORD dwNumSectors)
{
BOOL bRet = TRUE;
// RETAILMSG(1, (TEXT("FMD::FMD_WriteSector 0x%x \r\n"), startSectorAddr));
if ( IS_LB )
bRet = FMD_LB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
else
bRet = FMD_SB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
return bRet;
}
/*
@func BOOL | FMD_EraseBlock | Erases the specified flash block.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL FMD_EraseBlock(BLOCK_ID blockID)
{
BOOL bRet = TRUE;
// RETAILMSG(1, (TEXT("FMD::FMD_EraseBlock 0x%x \r\n")));
if ( IS_LB )
bRet = FMD_LB_EraseBlock(blockID, USE_NFCE);
else
bRet = FMD_SB_EraseBlock(blockID, USE_NFCE);
return bRet;
}
// FMD_PowerUp
//
// Performs any necessary powerup procedures...
//
VOID FMD_PowerUp(VOID)
{
// Set up initial flash controller configuration.
//
s2443NAND->NFCONF = (TACLS << 12) | /* CLE & ALE = HCLK * (TACLS + 1) */
(TWRPH0 << 8) | /* TWRPH0 = HCLK * (TWRPH0 + 1) */
(TWRPH1 << 4);
s2443NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
s2443NAND->NFSTAT = (1<<4);
}
// FMD_PowerDown
//
// Performs any necessary powerdown procedures...
//
VOID FMD_PowerDown(VOID)
{
}
// We don't have to build the following interface functions for the
// bootloader.
//
// FMD_OEMIoControl
//
// Used for any OEM defined IOCTL operations
//
BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
#if MAGNETO
BSP_ARGS *pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);
#endif
RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_OEMIoControl \r\n")));
switch(dwIoControlCode)
{
case IOCTL_FMD_GET_INTERFACE:
{
RETAILMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE \r\n")));
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
RETAILMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).\r\n")));
return(FALSE);
}
PFMDInterface pInterface = (PFMDInterface)pOutBuf;
pInterface->cbSize = sizeof(FMDInterface);
pInterface->pInit = FMD_Init;
pInterface->pDeInit = FMD_Deinit;
pInterface->pGetInfo = FMD_GetInfo;
#if MAGNETO
pInterface->pGetInfoEx = FMD_GetInfoEx;
#endif
pInterface->pGetBlockStatus = FMD_GetBlockStatus;
pInterface->pSetBlockStatus = FMD_SetBlockStatus;
pInterface->pReadSector = FMD_ReadSector;
pInterface->pWriteSector = FMD_WriteSector;
pInterface->pEraseBlock = FMD_EraseBlock;
pInterface->pPowerUp = FMD_PowerUp;
pInterface->pPowerDown = FMD_PowerDown;
pInterface->pGetPhysSectorAddr = NULL;
break;
}
#if 0
case IOCTL_FMD_LOCK_BLOCKS:
// LOCK is not supported.!!!!
BlockLockInfo * pLockInfo;
pLockInfo = (BlockLockInfo *)pInBuf;
RETAILMSG(1, (TEXT("IOCTL_FMD_LOCK_BLOCKS!!!!(0x%x,0x%x) \r\n"), pLockInfo->StartBlock, pLockInfo->NumBlocks));
if ( IS_LB ) // Large Block
{
if ( READ_REGISTER_BYTE(pNFSBLK) >> 6 < (ULONG)(pLockInfo->StartBlock + pLockInfo->NumBlocks) )
WRITE_REGISTER_USHORT(pNFSBLK, (pLockInfo->StartBlock + pLockInfo->NumBlocks)<<6);
}
else // Small Block
{
if ( READ_REGISTER_BYTE(pNFSBLK) >> 5 < (ULONG)(pLockInfo->StartBlock + pLockInfo->NumBlocks)*8 )
{
// RETAILMSG(1, (TEXT("Write value (0x%x) \r\n"), ((ULONG)(pLockInfo->StartBlock + pLockInfo->NumBlocks)*8)<<5));
WRITE_REGISTER_ULONG(pNFSBLK, ((ULONG)(pLockInfo->StartBlock + pLockInfo->NumBlocks)*8)<<5);
// RETAILMSG(1, (TEXT("Read value (0x%x) \r\n"), READ_REGISTER_ULONG(pNFSBLK)));
}
}
pBSPArgs->nfsblk = pLockInfo->StartBlock + pLockInfo->NumBlocks;
break;
case IOCTL_FMD_UNLOCK_BLOCKS:
RETAILMSG(1, (TEXT("IOCTL_FMD_UNLOCK_BLOCKS!!!!(0x%x,0x%x) \r\n"), pLockInfo->StartBlock, pLockInfo->NumBlocks));
RETAILMSG(1, (TEXT("S3C2443 Does not support IOCTL_FMD_UNLOCK_BLOCKS !!!! \r\n")));
return(FALSE);
break;
case IOCTL_FMD_READ_RESERVED:
RETAILMSG(1,(TEXT("IOCTL_FMD_READ_RESERVED\r\n")));
return(FALSE);
break;
case IOCTL_FMD_WRITE_RESERVED:
RETAILMSG(1,(TEXT("IOCTL_FMD_WRITE_RESERVED\r\n")));
return(FALSE);
break;
case IOCTL_FMD_GET_RESERVED_TABLE:
RETAILMSG(1,(TEXT("IOCTL_FMD_GET_RESERVED_TABLE\r\n")));
return(FALSE);
break;
case IOCTL_FMD_SET_REGION_TABLE:
RETAILMSG(1,(TEXT("IOCTL_FMD_SET_REGION_TABLE\r\n")));
return(FALSE);
break;
case IOCTL_FMD_SET_SECTORSIZE:
RETAILMSG(1,(TEXT("IOCTL_FMD_SET_SECTORSIZE\r\n")));
return(FALSE);
break;
case IOCTL_FMD_RAW_WRITE_BLOCKS:
RETAILMSG(1,(TEXT("IOCTL_FMD_RAW_WRITE_BLOCKS\r\n")));
return(FALSE);
break;
case IOCTL_FMD_GET_RAW_BLOCK_SIZE:
RETAILMSG(1,(TEXT("IOCTL_FMD_GET_RAW_BLOCK_SIZE\r\n")));
return(FALSE);
break;
case IOCTL_FMD_GET_INFO:
RETAILMSG(1,(TEXT("IOCTL_FMD_GET_INFO\r\n")));
return(FALSE);
break;
#endif
default:
RETAILMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x).\r\n"), dwIoControlCode));
return(FALSE);
}
return TRUE;
}
BOOL FMD_Deinit(PVOID hFMD)
{
return(TRUE);
}
/*
@func BOOL | FMD_GetInfo | Provides information on the NAND flash.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL FMD_GetInfo(PFlashInfo pFlashInfo)
{
UINT32 nCnt;
UINT32 nNandID;
UINT8 nMID, nDID;
if (!pFlashInfo)
return(FALSE);
BOOL bLastMode = SetKMode(TRUE); // for READFlashID();
pFlashInfo->flashType = NAND;
nNandID = ReadFlashID();
nMID = nNandID >> 8;
nDID = nNandID & 0xff;
for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
{
if (nDID == astNandSpec[nCnt].nDID)
{
break;
}
}
// OK, instead of reading it from the chip, we use the hardcoded
// numbers here.
pFlashInfo->dwNumBlocks = NUM_OF_BLOCKS;
pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK;
pFlashInfo->wDataBytesPerSector = NAND_SECTOR_SIZE;
pFlashInfo->dwBytesPerBlock = (PAGES_PER_BLOCK * NAND_SECTOR_SIZE);
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));
SetKMode(bLastMode);
return TRUE;
}
static BOOL IsBlockBad(BLOCK_ID blockID)
{
BOOL bRet = FALSE;
if ( IS_LB )
bRet = LB_IsBlockBad(blockID, USE_NFCE);
else
bRet = SB_IsBlockBad(blockID, USE_NFCE);
return bRet;
}
/*
@func DWORD | FMD_GetBlockStatus | Returns the status of the specified block.
@rdesc Block status (see fmd.h).
@comm
@xref
*/
DWORD FMD_GetBlockStatus(BLOCK_ID blockID)
{
DWORD dwResult = 0;
if ( IS_LB )
dwResult = FMD_LB_GetBlockStatus(blockID, USE_NFCE);
else
dwResult = FMD_SB_GetBlockStatus(blockID, USE_NFCE);
return dwResult;
}
/*
@func BOOL | MarkBlockBad | Marks the specified block as bad.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
static BOOL MarkBlockBad(BLOCK_ID blockID)
{
BOOL bRet = TRUE;
if ( IS_LB )
bRet = LB_MarkBlockBad(blockID, USE_NFCE);
else
bRet = SB_MarkBlockBad(blockID, USE_NFCE);
return bRet;
}
/*
@func BOOL | FMD_SetBlockStatus | Marks the block with the specified block status.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
*/
BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
BOOL bRet = TRUE;
if ( IS_LB )
bRet = FMD_LB_SetBlockStatus(blockID, dwStatus, USE_NFCE);
else
bRet = FMD_SB_SetBlockStatus(blockID, dwStatus, USE_NFCE);
return bRet;
}
typedef enum {
ECC_CORRECT_MAIN = 0, // correct Main ECC
ECC_CORRECT_SPARE = 1, // correct Main ECC
} ECC_CORRECT_TYPE;
BOOL ECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc, ECC_CORRECT_TYPE nType)
{
DWORD nErrStatus;
DWORD nErrDataNo;
DWORD nErrBitNo;
UINT32 nErrDataMask;
UINT32 nErrBitMask = 0x7;
BOOL bRet = TRUE;
//RETAILMSG(1, (TEXT("#### FMD_DRIVER:::ECC_CorrectData %x, %x, %x\r\n"), sectoraddr, nRetEcc, nType));
if (nType == ECC_CORRECT_MAIN)
{
nErrStatus = 0;
nErrDataNo = 7;
nErrBitNo = 4;
nErrDataMask = 0x7ff;
}
else if (nType == ECC_CORRECT_SPARE)
{
nErrStatus = 2;
nErrDataNo = 21;
nErrBitNo = 18;
nErrDataMask = 0xf;
}
else
{
return FALSE;
}
switch((nRetEcc>>nErrStatus) & 0x3)
{
case 0: // No Error
bRet = TRUE;
break;
case 1: // 1-bit Error(Correctable)
RETAILMSG(1,(TEXT("%cECC correctable error(0x%x). Byte:%d, bit:%d\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr, (nRetEcc>>nErrDataNo)&nErrDataMask, (nRetEcc>>nErrBitNo)&nErrBitMask));
(pData)[(nRetEcc>>nErrDataNo)&nErrDataMask] ^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
bRet = TRUE;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -