fmd.cpp
来自「SAMSUNG S3C6410 CPU BSP for winmobile6」· C++ 代码 · 共 2,345 行 · 第 1/4 页
CPP
2,345 行
//
// 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 <bsp_cfg.h>
#include <fmd.h>
#include <s3c6410_nand.h>
#include <s3c6410_syscon.h>
#include <bsp_args.h>
#include <ethdbg.h>
#include "Cfnand.h"
#if MAGNETO
#include <image_cfg.h>
#endif
#define CHECK_SPAREECC (1)
#define NAND_DEBUG (0)
#define USE_LOCK_TIGHT (1) // CE does not use lock tight
#define NAND_BASE (0xB0200000) // PA:0x70200000
#define IOPORT_BASE (0xB2B08000) // PA:0x7F008000
#define SYSCON_BASE (0xB2A0F000) // PA:0x7E00F000
#if MAGNETO
#define MAX_REGIONS 16
#endif
BOOL NEED_EXT_ADDR = TRUE;
static volatile S3C6410_NAND_REG *s6410NAND = (S3C6410_NAND_REG *)NAND_BASE;
static volatile S3C6410_SYSCON_REG *s6410SYSCON = (S3C6410_SYSCON_REG *)SYSCON_BASE;
#if MAGNETO
BSP_ARGS *pBSPArgs;
#endif
extern "C"
{
void RdPage512(unsigned char *bufPt);
void RdPage512Unalign(unsigned char *bufPt);
void WrPage512(unsigned char *bufPt);
void WrPage512Unalign(unsigned char *bufPt);
void WrPageInfo(PBYTE pBuff);
void RdPageInfo(PBYTE pBuff);
}
NANDDeviceInfo GetNandInfo(void) { return stDeviceInfo; }
#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_LB_PAGE_SIZE];
#define DEFAULT_COMPACTION_BLOCKS 4
#endif
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;
break;
case 2: // Multiple Error
RETAILMSG(1,(TEXT("%cECC Uncorrectable error(0x%x)\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S'), sectoraddr));
bRet = FALSE;
break;
case 3: // ECC area Error
RETAILMSG(1,(TEXT("%cECC area error\r\n"), ((nType==ECC_CORRECT_MAIN)?'M':'S')));
default:
bRet = FALSE;
break;
}
return bRet;
}
/*
@func DWORD | ReadFlashID | Reads the flash manufacturer and device codes.
@rdesc Manufacturer and device codes.
@comm
@xref
*/
static DWORD ReadFlashID(void)
{
BYTE Mfg, Dev;
int i;
NF_nFCE_L(); // Deselect the flash chip.
NF_CMD(CMD_READID); // Send flash ID read command.
NF_ADDR(0);
for (i=0; i<10; i++)
{
Mfg = NF_RDDATA_BYTE();
if (Mfg == 0xEC || Mfg == 0x98) break;
}
Dev = NF_RDDATA_BYTE();
NF_nFCE_H();
return ((DWORD)(Mfg<<8)+Dev);
}
/*
@func PVOID | FMD_Init | Initializes the Smart Media NAND flash controller.
@rdesc Pointer to S3C6410 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 bNandExt = FALSE;
UINT8 nMID, nDID;
int nCnt;
BOOL bLastMode = SetKMode(TRUE);
volatile DWORD rdid;
RETAILMSG(1,(TEXT("[FMD] ++FMD_Init()\r\n")));
#if MAGNETO
pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);
#endif
if (pRegIn && pRegIn->MemBase.Num && pRegIn->MemBase.Reg[0])
s6410NAND = (S3C6410_NAND_REG *)(pRegIn->MemBase.Reg[0]);
else
s6410NAND = (S3C6410_NAND_REG *)NAND_BASE;
// Configure SMC Chip Select Mux for NAND
//
s6410SYSCON = (S3C6410_SYSCON_REG *)SYSCON_BASE;
s6410SYSCON->MEM_SYS_CFG = (s6410SYSCON->MEM_SYS_CFG & ~(0x1000)); // 8-bit data width
s6410SYSCON->MEM_SYS_CFG = (s6410SYSCON->MEM_SYS_CFG & ~(0x3F)) | (0x00); // Xm0CSn[2] = NFCON CS0
// Set up initial flash controller configuration.
//
s6410NAND->NFCONF = (NAND_TACLS << 12) | (NAND_TWRPH0 << 8) | (NAND_TWRPH1 << 4);
s6410NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
s6410NAND->NFSTAT = (1<<4);
// Get manufacturer and device codes.
rdid = ReadFlashID();
RETAILMSG(1, (TEXT("[FMD:INF] FMD_Init() : Read ID = 0x%x\n\r"), rdid));
nMID = (UINT8)(rdid >> 8);
nDID = (UINT8)(rdid & 0xff);
RETAILMSG(1, (TEXT("[FMD:INF] FMD_Init() : Read ID = 0x%08x\n\r"), rdid));
for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
{
if (nDID == astNandSpec[nCnt].nDID)
{
bNandExt = TRUE;
break;
}
}
if (!bNandExt)
{
RETAILMSG(1, (TEXT("[FMD:ERR] FMD_Init() : Unknown ID = 0x%08x\n\r"), rdid));
return NULL;
}
NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;
SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg;
PAGES_PER_BLOCK = (IS_LB)?astNandSpec[nCnt].nPgsPerBlk:NAND_PAGE_CNT;
RETAILMSG(1,(TEXT("SECTORS_PER_PAGE=%d\n"),SECTORS_PER_PAGE));
#if MAGNETO
DefineLayout();
#endif
SetKMode (bLastMode);
return((PVOID)s6410NAND);
}
/*
@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;
#if (NAND_DEBUG)
RETAILMSG(1, (TEXT("FMD::FMD_ReadSector 0x%x \r\n"), startSectorAddr));
#endif
if ( startSectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
else
bRet = FMD_SB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_ReadSector(startSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_GPIO);
else
bRet = FMD_SB_ReadSector(startSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_GPIO);
}
//RETAILMSG(1, (TEXT("FMD::FMD_ReadSector -- \r\n")));
return bRet;
}
BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,
DWORD dwNumSectors)
{
BOOL bRet = TRUE;
#if (NAND_DEBUG)
RETAILMSG(1, (TEXT("FMD::FMD_WriteSector 0x%x \r\n"), startSectorAddr));
#endif
if ( startSectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
else
bRet = FMD_SB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
}
else // if ( PRIMARY_NAND == SMALL_BLOCK_NAND )
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_WriteSector(startSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_GPIO);
else
bRet = FMD_SB_WriteSector(startSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_GPIO);
}
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;
int i;
#if (NAND_DEBUG)
//RETAILMSG(1, (TEXT("FMD::FMD_EraseBlock 0x%x \r\n")));
#endif
if ( blockID < wPRIMARY_NAND_BLOCKS )
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
{
for ( i = 0; i < LB_BLOCK_LOOP; i++ )
{
bRet = FMD_LB_EraseBlock(blockID*(LB_BLOCK_LOOP) + i, USE_NFCE);
if ( bRet == FALSE ) break;
}
}
else
{
for ( i = 0; i < SB_BLOCK_LOOP; i++ )
{
bRet = FMD_SB_EraseBlock(blockID*(SB_BLOCK_LOOP) + i, USE_NFCE);
if ( bRet == FALSE ) break;
}
}
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
{
for ( i = 0; i < LB_BLOCK_LOOP; i++ )
{
bRet = FMD_LB_EraseBlock((blockID-wPRIMARY_NAND_BLOCKS)*(LB_BLOCK_LOOP) + i, USE_GPIO);
if ( bRet == FALSE ) break;
}
}
else
{
for ( i = 0; i < SB_BLOCK_LOOP; i++ )
{
bRet = FMD_SB_EraseBlock(blockID*(SB_BLOCK_LOOP) + i, USE_GPIO);
if ( bRet == FALSE ) break;
}
}
}
return bRet;
}
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;
}
}
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 = NAND_PAGE_SIZE * astNandSpec[dwPrimaryNandDevice].nSctsPerPg;
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));
SetKMode(bLastMode);
return TRUE;
}
#if MAGNETO
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 = NAND_PAGE_SIZE * astNandSpec[dwPrimaryNandDevice].nSctsPerPg;
pFlashInfo->dwNumRegions = g_dwNumRegions;
return(TRUE);
}
BOOL FMD_GetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, PBYTE pOEMReserved)
{
if ( physicalSectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK ) // First NAND Flash
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
FMD_LB_GetOEMReservedByte( physicalSectorAddr, pOEMReserved, USE_NFCE);
else
FMD_SB_GetOEMReservedByte( physicalSectorAddr, pOEMReserved, USE_NFCE);
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
FMD_LB_GetOEMReservedByte( physicalSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pOEMReserved, USE_GPIO);
else
FMD_SB_GetOEMReservedByte( physicalSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pOEMReserved, USE_GPIO);
}
return TRUE;
}
// FMD_SetOEMReservedByte
//
// Sets the OEM reserved byte (for metadata) for the specified physical sector.
//
BOOL FMD_SetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, BYTE bOEMReserved)
{
BOOL bRet = TRUE;
if ( physicalSectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK ) // First NAND Flash
{
if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_SetOEMReservedByte(physicalSectorAddr, bOEMReserved, USE_NFCE);
else
bRet = FMD_SB_SetOEMReservedByte(physicalSectorAddr, bOEMReserved, USE_NFCE);
}
else
{
if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
bRet = FMD_LB_SetOEMReservedByte(physicalSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, bOEMReserved, USE_GPIO);
else
bRet = FMD_SB_SetOEMReservedByte(physicalSectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, bOEMReserved, USE_GPIO);
}
return bRet;
}
#ifndef NOSYSCALL
// We don't have to build the following interface functions for the
// bootloader.
//
// FMD_PowerUp
//
// Performs any necessary powerup procedures...
//
VOID FMD_PowerUp(VOID)
{
// Set up initial flash controller configuration.
s6410NAND->NFCONF = (NAND_TACLS << 12) | (NAND_TWRPH0 << 8) | (NAND_TWRPH1 << 4);
s6410NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
s6410NAND->NFSTAT = (1<<4);
}
// FMD_PowerDown
//
// Performs any necessary powerdown procedures...
//
VOID FMD_PowerDown(VOID)
{
}
// 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] FMD_OEMIoControl(0x%08x)\r\n"), dwIoControlCode));
switch(dwIoControlCode)
{
case IOCTL_FMD_GET_INTERFACE:
{
RETAILMSG(1, (TEXT("[FMD] FMD_OEMIoControl() : IOCTL_FMD_GET_INTERFACE\r\n")));
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : Invalid Parameter\r\n")));
return FALSE;
}
PFMDInterface pInterface = (PFMDInterface)pOutBuf;
pInterface->cbSize = sizeof(FMDInterface);
pInterface->pInit = FMD_Init;
pInterface->pDeInit = FMD_Deinit;
pInterface->pGetInfo = FMD_GetInfo;
pInterface->pGetInfoEx = FMD_GetInfoEx;
pInterface->pGetBlockStatus = FMD_GetBlockStatus;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?