?? fmd_lb.cpp
字號:
//
// 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.
//
// Copyright (c) Samsung Electronics. Co. LTD. All rights reserved.
/*++
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.
Module Name:
fmd_lb.cpp
Abstract:
This module implements main functions of FMD PDD for Large Block(1024K, 2048KBytes Block Size)
Functions:
FMD_LB_*
Notes:
--*/
#include "precomp.h"
// SpareArea Map(Byte Addressing)
// 0~7 : SectorInfo
// 8~23 : MECC data(128bit)
// 24~27 : SECC1 Data(32bit)
// 28~31 : SECC2 Data[32bit]
void SubmitSpareAreaReadCmd(DWORD SectorStartAddr, DWORD SpareStartAddr)
{
NF_nFCE_L();
NF_CLEAR_RB();
NF_CMD(CMD_READ); // Send read command.
NF_ADDR((SpareStartAddr)&0xff);
NF_ADDR((SpareStartAddr>>8)&0xff);
NF_ADDR((SectorStartAddr) & 0xff);
NF_ADDR((SectorStartAddr >> 8) & 0xff);
if(g_bNeedExtAddr)
{
NF_ADDR((SectorStartAddr >> 16) & 0xff);
}
NF_CMD(CMD_READ3); // 2nd command
NF_DETECT_RB(); // Wait for command to complete.
}
// the 1st byte through ECC engine is badblock byte for SectorInfo structure in large block NAND flash
// the relationship between input through ECC engine and SectorInfo structure is like this
//
// ReadByte - ECC input byte ----------- SectorInfoLocation(if pSectorInfo = (LPBYTE)pData) (Little Endian)
// 1byte - bBadBlock - 6th byte (*pData[5])
// 4byte - dwReserved1 & 0xff - 1st byte (*pData[0])
// - (dwReserved1>>8) & 0xff - 2nd byte (*pData[1])
// - (dwReserved1>>16) & 0xff - 3rd byte (*pData[2])
// - (dwReserved1>>24) & 0xff - 4th byte (*pData[3])
// 1byte - bOEMReserved - 5th byte (*pData[4])
//
void RestructSectorInfo(PSectorInfo pSectorInfoBuff, PBYTE RawSectorInfo)
{
pSectorInfoBuff->bBadBlock = RawSectorInfo[0];
pSectorInfoBuff->dwReserved1 = RawSectorInfo[1];
pSectorInfoBuff->dwReserved1 |= RawSectorInfo[2]<<8;
pSectorInfoBuff->dwReserved1 |= RawSectorInfo[3]<<16;
pSectorInfoBuff->dwReserved1 |= RawSectorInfo[4]<<24;
pSectorInfoBuff->bOEMReserved = RawSectorInfo[5];
pSectorInfoBuff->wReserved2 = RawSectorInfo[6];
pSectorInfoBuff->wReserved2 |= (RawSectorInfo[7]<<8);
}
void ReadOneSectorInfo(PBYTE RawSectorInfoBuf) ///< Read One SectorInfo by sizeof(SectorInfo)
{
int i;
// Initialize MECC Module
NF_RSTECC();
NF_MECC_UnLock();
for(i =0 ; i< 6; i++){ // Except Reserved2. Reserved2 area can vary
RawSectorInfoBuf[i] = NF_RDDATA_BYTE();
}
NF_MECC_Lock();
RawSectorInfoBuf[6] = NF_RDDATA_BYTE();
RawSectorInfoBuf[7] = NF_RDDATA_BYTE();
}
BOOL FMD_LB_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
ULONG SectorAddr = (ULONG)startSectorAddr;
DWORD i;
volatile DWORD rddata;
UINT32 nRetEcc = 0;
DWORD MECCBuf[MAX_SECTORS_PER_PAGE];
UINT16 nSectorLoop;
int NewSpareAddr = NAND_PAGE_SIZE;
int NewDataAddr = 0;
int NewSectorAddr = startSectorAddr;
DWORD SECCBuf1; // 1st Spare ECC
DWORD SECCBuf2; // 2nd Spare ECC(cloned from 1st)
BYTE RawSectorInfo[8];
RETAILMSG(FMD_ZONE_FUNCTION,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR %x %x\r\n"),startSectorAddr,NewDataAddr));
if (!pSectorBuff && !pSectorInfoBuff)
{
return(FALSE);
}
if ( dwNumSectors > 1 )
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("######## FATAL ERROR => FMD::FMD_ReadSector->dwNumsectors is bigger than 1. \r\n")));
return FALSE;
}
if (!pSectorBuff)
{
return NAND_LB_ReadSectorInfo(startSectorAddr, pSectorInfoBuff);
}
SubmitSpareAreaReadCmd(NewSectorAddr, NewSpareAddr+NAND_SECC1_OFFSET); //< Spare Area Start Address, SECTOR_SIZE(512)*SECTOS_PER_PAGE(4)=2048 -> Physical Page Size
// Read SECC1, SECC2 from Spare area
SECCBuf1 = NF_RDDATA_WORD();
SECCBuf2 = NF_RDDATA_WORD();
// Set address for random access to read SectorInfo and MECC code from Spare Area
NF_CMD(CMD_RDO); // Send read random data output command
NF_ADDR((NewSpareAddr)&0xff);
NF_ADDR(((NewSpareAddr)>>8)&0xff);
NF_CMD(CMD_RDO2); // Command done
if (pSectorInfoBuff) /// Read SectorInfo doesn't check this
{
ReadOneSectorInfo(RawSectorInfo); ///< Read One SectorInfo by sizeof(SectorInfo)
// Check ECC abour SectorInfo
NF_WRMECCD0( ((SECCBuf1&0xff00)<<8)|(SECCBuf1&0xff) );
NF_WRMECCD1( ((SECCBuf1&0xff000000)>>8)|((SECCBuf1&0xff0000)>>16) );
nRetEcc = NF_ECC_ERR0;
if (!ECC_CorrectData(startSectorAddr, RawSectorInfo, nRetEcc, ECC_CORRECT_SPARE1)) // Use specific byte
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("#### SECC1 ECC correction failed\n")));
NF_nFCE_H();
return FALSE;
}
RestructSectorInfo(pSectorInfoBuff, RawSectorInfo);
}
else
{
for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)
{
rddata = (DWORD) NF_RDDATA_WORD(); // read and trash the data
}
}
// Initialize MECC module
NF_RSTECC();
NF_MECC_UnLock();
// Read MECC parity code from Spare Area
for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)
{
MECCBuf[nSectorLoop] = NF_RDDATA_WORD();
}
NF_MECC_Lock();
// Check ECC about MECC parity code
NF_WRMECCD0( ((SECCBuf2&0xff00)<<8)|(SECCBuf2&0xff) );
NF_WRMECCD1( ((SECCBuf2&0xff000000)>>8)|((SECCBuf2&0xff0000)>>16) );
nRetEcc = NF_ECC_ERR0;
if (!ECC_CorrectData(startSectorAddr, (LPBYTE)MECCBuf, nRetEcc, ECC_CORRECT_SPARE2))
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("#### SECC2 ECC correction failed\n")));
NF_nFCE_H();
return FALSE;
}
// Read each Sector in the Page. (using SECTORS_PER_PAGE)
for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)
{
NewDataAddr = nSectorLoop * SECTOR_SIZE;
NF_CMD(CMD_RDO); // Send read command.
NF_ADDR((NewDataAddr)&0xff);
NF_ADDR((NewDataAddr>>8)&0xff);
NF_CMD(CMD_RDO2); // 2nd command
NF_RSTECC();
NF_MECC_UnLock();
if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
{
RdPage512Unalign(pSectorBuff+nSectorLoop*SECTOR_SIZE);
}
else
{
// Usual case to handle 4byte aligned buffer pointer
RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE); // Read page/sector data.
}
NF_MECC_Lock();
// Check ECC about Main data with MECC parity code
NF_WRMECCD0( ((MECCBuf[nSectorLoop]&0xff00)<<8)|(MECCBuf[nSectorLoop]&0xff) );
NF_WRMECCD1( ((MECCBuf[nSectorLoop]&0xff000000)>>8)|((MECCBuf[nSectorLoop]&0xff0000)>>16) );
nRetEcc = NF_ECC_ERR0;
if (!ECC_CorrectData(startSectorAddr, pSectorBuff+nSectorLoop*SECTOR_SIZE, nRetEcc, ECC_CORRECT_MAIN))
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("#### MECC ECC correction failed\n")));
NF_nFCE_H();
return FALSE;
}
}
NF_nFCE_H();
return TRUE;
}
BOOL NAND_LB_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
BOOL bRet = TRUE;
int NewSectorAddr = sectorAddr;
UINT32 nRetEcc = 0;
DWORD MECCBuf[MAX_SECTORS_PER_PAGE];
DWORD SECCBuf;
BYTE RawSectorInfo[8];
/* if(sectorAddr == 0)
{
// Bad Block must be treated as valid for steploader and eboot
pInfo->bOEMReserved = ~(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY);
pInfo->bBadBlock = BADBLOCKMARK;
pInfo->dwReserved1 = 0xffffffff;
pInfo->wReserved2 = 0xffff;
return TRUE;
}
*/
SubmitSpareAreaReadCmd(NewSectorAddr, NAND_PAGE_SIZE);
ReadOneSectorInfo(RawSectorInfo);
// Read MECC parity code from Spare area, actually don't use these data..
MECCBuf[0] = NF_RDDATA_WORD();
MECCBuf[1] = NF_RDDATA_WORD();
MECCBuf[2] = NF_RDDATA_WORD();
MECCBuf[3] = NF_RDDATA_WORD();
// Check ECC about SectorInfo with SECC1 parity code
SECCBuf = NF_RDDATA_WORD();
NF_WRMECCD0( ((SECCBuf&0xff00)<<8)|(SECCBuf&0xff) );
NF_WRMECCD1( ((SECCBuf&0xff000000)>>8)|((SECCBuf&0xff0000)>>16) );
nRetEcc = NF_ECC_ERR0;
bRet = ECC_CorrectData(sectorAddr, (LPBYTE)&RawSectorInfo, nRetEcc, ECC_CORRECT_SPARE1);
if(!bRet)
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("#### Warning:NAND_LB_ReadSectorInfo Spare ECC operation for SectorInfo failed\n")));
RETAILMSG(FMD_ZONE_READ, (TEXT("\n#### RawSectorInfo:bOEMReserved:0x%x, bBadBlock:0x%x, dwReserved1:0x%x, wReserved2:0x%x"),
((PSectorInfo)&RawSectorInfo)->bOEMReserved, ((PSectorInfo)&RawSectorInfo)->bBadBlock,
((PSectorInfo)&RawSectorInfo)->dwReserved1, ((PSectorInfo)&RawSectorInfo)->wReserved2));
RETAILMSG(FMD_ZONE_READ, (TEXT("\n#### SECCBuf : 0x%x"), SECCBuf));
// NF_nFCE_H();
/* Implementation 2
pInfo->bOEMReserved = ~(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY);
pInfo->bBadBlock = BADBLOCKMARK;
pInfo->dwReserved1 = 0xffffffff;
pInfo->wReserved2 = 0xffff;
*/
// return TRUE; // Bad Block must be treated as valid for steploader and eboot
// return bRet;
}
RestructSectorInfo(pInfo, RawSectorInfo);
NF_nFCE_H();
return bRet;
}
BOOL FMD_LB_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
DWORD i;
BOOL bRet = TRUE;
BYTE Status;
DWORD MECCBuf[MAX_SECTORS_PER_PAGE];
UINT16 nSectorLoop;
int NewSpareAddr = NAND_PAGE_SIZE;
int NewDataAddr = 0;
int NewSectorAddr = startSectorAddr;
DWORD SECCBuf1;
DWORD SECCBuf2;
RETAILMSG(FMD_ZONE_WRITE, (TEXT("FMD::FMD_LB_WriteSector 0x%x \r\n"), startSectorAddr));
if (!pSectorBuff && !pSectorInfoBuff)
return(FALSE);
if ( dwNumSectors > 1 )
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("######## FATAL ERROR => FMD::FMD_WriteSector->dwNumsectors is bigger than 1. \r\n")));
return FALSE;
}
if (!pSectorBuff)
{
NAND_LB_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
return TRUE;
}
// Enable Chip
NF_nFCE_L();
NF_CLEAR_RB();
// Issue command
NF_CMD(CMD_WRITE);
// Setup address
NF_ADDR((NewDataAddr)&0xff);
NF_ADDR((NewDataAddr>>8)&0xff);
NF_ADDR((NewSectorAddr)&0xff);
NF_ADDR((NewSectorAddr>>8)&0xff);
if(g_bNeedExtAddr)
{
NF_ADDR((NewSectorAddr>>16)&0xff);
}
for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)
{
// Initialize ECC register
NF_RSTECC();
NF_MECC_UnLock();
// Special case to handle un-aligned buffer pointer.
//
if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
{
// Write the data
WrPage512Unalign(pSectorBuff+nSectorLoop*SECTOR_SIZE);
}
else
{
WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
}
// Read out the ECC value generated by HW
NF_MECC_Lock();
MECCBuf[nSectorLoop] = NF_RDMECC0();
}
NF_CMD(CMD_RDI);
NF_ADDR((NewSpareAddr)&0xff);
NF_ADDR((NewSpareAddr>>8)&0xff);
// Write the SectorInfo data to the media
// NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the
// upper byte of a USHORT.
if(pSectorInfoBuff)
{
// Initialize MECC module
NF_RSTECC();
NF_MECC_UnLock();
// Write SectorInfo
NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);
NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);
NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);
NF_MECC_Lock();
// Store SECC parity code for SectorInfo
SECCBuf1 = NF_RDMECC0();
NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);
NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);
}
else
{
// Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)
{
NF_WRDATA_WORD(0xffffffff);
}
}
// Write the ECC value to the flash (16 btes for 4 sectors)
// Initialize MECC module
NF_RSTECC();
NF_MECC_UnLock();
// Store MECC parity code for main data
NF_WRDATA_WORD(MECCBuf[0]);
NF_WRDATA_WORD(MECCBuf[1]);
NF_WRDATA_WORD(MECCBuf[2]);
NF_WRDATA_WORD(MECCBuf[3]);
NF_MECC_Lock(); // get SECC
// Store MECC parity code for MECC parity code
SECCBuf2 = NF_RDMECC0();
if(pSectorInfoBuff)
{
// Store SECC1, SECC2
NF_WRDATA_WORD(SECCBuf1);
NF_WRDATA_WORD(SECCBuf2);
}
// Finish up the write operation
NF_CMD(CMD_WRITE2);
// Wait for RB
NF_DETECT_RB(); // Wait tR(max 12us)
if ( NF_RDSTAT & STATUS_ILLACC )
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("FMD_WriteSector() ######## Error Programming page (Illegal Access) %d!\n"), startSectorAddr));
g_pNFConReg->NFSTAT = STATUS_ILLACC; // Write 1 to clear.
bRet = FALSE;
}
else
{
// Check the status
do
{
NF_CMD(CMD_STATUS);
Status = NF_RDDATA_BYTE(); // Read command status.
}while(!(Status & STATUS_READY));
if(Status & STATUS_ERROR)
{
RETAILMSG(FMD_ZONE_ERROR, (TEXT("FMD_WriteSector() ######## Error Programming page %d!\n"), startSectorAddr));
bRet = FALSE;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -