📄 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>
#ifdef CEDAR_ONLY
#include "utldrv.h"
#include <nkintr.h>
#include "oalintr.h"
#endif // CEDAR_ONLY
#ifdef NOBINFS
#include "utldrv.h" // Still needed for driver->driver fast method calling in 4.x
#endif
#include <s24A0.h>
#include "cfnand.h"
#include "loader.h"
#ifdef NOBINFS
//#ifdef CEDAR_ONLY // Still needed in 4.x
// Globals
HANDLE g_hUTLObject = NULL;
UTL_FASTCALL g_tblFastCall;
//#endif // CEDAR_ONLY
#endif
// Globals needed for updatexip
HANDLE g_hMutex = NULL;
// BUGBUG: For now, we always will take the mutex
BOOL g_bTakeMutex = TRUE;
void GRABMUTEX();
void RELEASEMUTEX();
#ifdef NOSYSCALL
#ifndef BOOT_LOADER
// function prototypes for kernel functions
extern "C"
{
HANDLE SC_CreateMutex(LPSECURITY_ATTRIBUTES lpsa, BOOL bInitialOwner, LPCTSTR lpName);
DWORD SC_WaitForMultiple(DWORD cObjects, CONST HANDLE *lphObjects, BOOL fWaitAll, DWORD dwTimeout);
BOOL SC_ReleaseMutex(HANDLE hMutex);
BOOL SC_CloseHandle(HANDLE hObj);
}
#endif
#endif
// Use Macros here to avoid extra over head for c function calls
#define READ_REGISTER_BYTE(p) (*(volatile PBYTE) (p))
#define WRITE_REGISTER_BYTE(p, v) (*(volatile PBYTE)(p)) = (v)
#define READ_REGISTER_USHORT(p) (*(volatile PUSHORT) (p))
#define WRITE_REGISTER_USHORT(p, v) (*(volatile PUSHORT)(p)) = (v)
#define WRITE_REGISTER_ULONG(p, v) (*(volatile PULONG)(p)) = (v)
#define READ_REGISTER_ULONG(p) (*(volatile PULONG) (p))
// Registers
volatile PULONG pNFReg;
volatile PULONG pNFCONF;
volatile PULONG pNFCONT;
volatile PUSHORT pNFCMD;
volatile PULONG pNFADDR;
volatile PUSHORT pNFDATA;
volatile PUSHORT pNFMECCData0;
volatile PUSHORT pNFMECCData1;
volatile PUSHORT pNFMECCData2;
volatile PUSHORT pNFMECCData3;
volatile PULONG pNFSTAT;
volatile PULONG pNFESTAT0;
volatile PULONG pNFESTAT1;
volatile PULONG pNFMECC0;
volatile PULONG pNFMECC1;
volatile IOPreg *s24A0IOP;
volatile SROMreg *s24A0SROM;
// Status bit pattern
#define STATUS_READY 0x40
#define STATUS_ERROR 0x01
// HCLK=133Mhz
#define TACLS 0
#define TECH 0x3f
#define TWRPH0 6
#define TWRPH1 0
// MACROS
#define NF_DISABLE_HWCE() WRITE_REGISTER_ULONG(pNFCONF, (ULONG) (READ_REGISTER_ULONG(pNFCONF) & ~ (1<<3))) //$Disable HW CE
#define NF_LDSTR_ADD(addr) WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) | (addr<<16)))
#define NF_LDSTR_SIZE(size) WRITE_REGISTER_ULONG(pNFCONT, ((ULONG) (READ_REGISTER_ULONG(pNFCONT) &(~(7<<4)) |( (size-1)<<4))))
#define NF_SW_MODE() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & (~ (3<<0)) | (3<<0))) //$Softwaremode
#define NF_DISABLE_ALLMODE() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & ~ (3<<0))) //$Disable all mode
#define NF_LD_START() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & (~ (3<<0)) | (1<<0))) //$Autoload mode
#define NF_LDDONE_CHECK() {while(!(NF_STAT() & (1<<15))) ;}
#define NF_LDDONE_CLEAR() WRITE_REGISTER_ULONG(pNFSTAT, (ULONG) (READ_REGISTER_ULONG(pNFSTAT) | (1<<15)))
#define NF_ST_START() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & (~ (3<<0)) | (2<<0))) //$Autostore mode
#define NF_STDONE_CHECK() {while(!(NF_STAT() & (1<<14))) ;}
#define NF_STDONE_CLEAR() WRITE_REGISTER_ULONG(pNFSTAT, (ULONG) (READ_REGISTER_ULONG(pNFSTAT) | (1<<14)))
#define NF_LOCK_DISABLE() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & ~(1<<2)))
#define NF_CE_L() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & ~(1<<7)))//$nand flash chip enable.
#define NF_CE_H() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) | (1<<7))) //$nand flash chip disable.
#define NF_CMD(cmd) WRITE_REGISTER_USHORT(pNFCMD, (USHORT) (cmd))
#define NF_ADDR(addr) WRITE_REGISTER_USHORT(pNFADDR, (USHORT) (addr))
#define NF_ADDR_(addr) WRITE_REGISTER_ULONG(pNFADDR, (ULONG) (addr))
#define NF_DATA_R() READ_REGISTER_BYTE(pNFDATA)
#define NF_DATA_R2() READ_REGISTER_USHORT(pNFDATA)
#define NF_DATA_W2(val) WRITE_REGISTER_USHORT(pNFDATA, (USHORT) (val))
#define NF_STAT() READ_REGISTER_ULONG(pNFSTAT)
#define NF_MECC_UnLock() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) & ~(1<<9)))//$unlock main data area
#define NF_MECC_Lock() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) | (1<<9)))
#define NF_RSTECC() WRITE_REGISTER_ULONG(pNFCONT, (ULONG) (READ_REGISTER_ULONG(pNFCONT) | (1<<8)))//$ initialise ECC decoder
#define NF_CLEAR_RB() WRITE_REGISTER_ULONG(pNFSTAT, (ULONG) (READ_REGISTER_ULONG(pNFSTAT) | (1<<13)))
#define NF_DETECT_RB() {while(!(NF_STAT() & (1<<13)));}
// External function
extern "C" {
BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);
}
// Flags and pointers
#define BADBLOCKMARK 0x00
// VALIDADDR is 5 << 8
//
// Explain: 5 means the 6th byte in spare area (517 byte in the sector)
// Shift 8 bit to the left to form the correct address for 16bit port
//
#define VALIDADDR 0x05
#define OEMADDR 0x04 // 5th byte in spare area
#ifdef CEDAR_ONLY
void PowerOnCallback()
{
DEBUGMSG(1, (TEXT("FlashDrv::FMD:: Come back form Power Off!\n")));
}
#endif // CEDAR_ONLY
// Reset the chip
//
void NF_Reset()
{
int i;
GRABMUTEX();
NF_SW_MODE();
NF_CE_L();
NF_CLEAR_RB();
NF_CMD(CMD_RESET);
for(i=0;i<10;i++); //tWB = 100ns. //??????
//NF_DETECT_RB();
NF_CE_H();
RELEASEMUTEX();
}
/*
Here is the statement from SamSung's K9F2808U0B datasheet:
All device locations are erased (FFh) except location where the invalid block(s)
information is written prior to shipping. The invalid block(s) status is defined
by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd
page of every invalid block has non-FFh data at the column address of 517. Since
the invalid block information is also erasable in most cases, it is impossible to
recover the information once it has been erased.
Here is the logic we are taking:
If the block is invalid, non-FFh value in column address of 517, we don't use that
block anyway. Otherwise, the whole spare area is subject to use by our program. If
we found additional bad block later on, we don't necessary have to use column 517
to represent invalid block. We could use any of the 16 byte spare area.
But for simplicity, in our current implementation, we avoid to touch column 517. So
the we allocate SectorInfo as following:
- - - - - - - - - - - - - - - -
|R|R|R|R|O|V|R|R|E|E|E|E|E|E|E|E|
- - - - - - - - - - - - - - - -
Where Rs are reserved bytes used by the FAL
O is a byte for use by the OEM
V is a byte indicating if the block is valid (a.k.a. bad)
Es are bytes used for ECC
*/
/*
* 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)
{
volatile DWORD rddata;
int NewSpareAddr = (512+16)/sizeof(WORD)*(sectorAddr%4) + 512/sizeof(WORD);
int NewSectorAddr = sectorAddr/4;
DEBUGMSG(1, (TEXT("NAND_ReadSectorInfo_IN %x!\n"), sectorAddr));
#ifdef BOOT_LOADER
// EdbgOutputDebugString("NAND_ReadSectorInfo 0x%x \r\n", sectorAddr);
#endif
DEBUGMSG(1, (TEXT("FlashDrv!FMD!NAND_ReadSectorInfo: \r\n")));
GRABMUTEX();
// Chip enable
NF_CE_L();
NF_CLEAR_RB();
// Write the command
NF_CMD(CMD_READ);
// Write the address
NF_ADDR((NewSpareAddr)&0xff);
NF_ADDR((NewSpareAddr>>8)&0xff);
NF_ADDR((NewSectorAddr)&0xff);
NF_ADDR((NewSectorAddr>>8) & 0xff);
if (NEED_EXT_ADDR) {
NF_ADDR((NewSectorAddr >> 16) & 0xff);
}
NF_CMD(0x30);
// Wait for the Ready bit
NF_DETECT_RB(); // Wait tR(max 12us)
// Read the SectorInfo data (we only need to read first 8 bytes)
pInfo->dwReserved1 = (DWORD) (NF_DATA_R2());
pInfo->dwReserved1 |= (DWORD) (((DWORD) NF_DATA_R2()) << 16);
rddata = NF_DATA_R2();
// OEM byte
pInfo->bOEMReserved = (BYTE) (rddata & 0xff);
// Read the bad block mark
pInfo->bBadBlock = (BYTE) ((rddata>>8) & 0xff);
// Second reserved field (WORD)
pInfo->wReserved2 = (WORD) NF_DATA_R2();
NF_CE_H();
RELEASEMUTEX();
DEBUGMSG(1, (TEXT("NAND_ReadSectorInfo_OUT %x!\n"), sectorAddr));
}
/*
* 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)
{
volatile DWORD wrdata;
BOOL bRet = TRUE;
int NewSpareAddr = (512+16)/sizeof(WORD)*(sectorAddr%4) + 512/sizeof(WORD);
int NewSectorAddr = sectorAddr/4;
DEBUGMSG(1, (TEXT("NAND_WriteSectorInfo_IN %x!\n"), sectorAddr));
#ifdef BOOT_LOADER
// EdbgOutputDebugString("NAND_WriteSectorInfo 0x%x \r\n", sectorAddr);
#endif
// RETAILMSG(1, (TEXT("FlashDrv!FMD!NAND_WriteSectorInfo: \r\n")));
GRABMUTEX();
// Chip enable
NF_CE_L();
NF_CLEAR_RB();
// Write the command
// First, let's point to the spare area
// NF_CMD(CMD_READ2);
NF_CMD(CMD_WRITE);
// Write the address
NF_ADDR((NewSpareAddr)&0xff);
NF_ADDR((NewSpareAddr>>8)&0xff);
NF_ADDR(NewSectorAddr & 0xff);
NF_ADDR((NewSectorAddr >> 8) & 0xff);
if (NEED_EXT_ADDR) {
NF_ADDR((NewSectorAddr >> 16) & 0xff);
}
// Now let's write the SectorInfo data
//
// Write the first reserved field (DWORD)
NF_DATA_W2( (pInfo->dwReserved1) & 0xffff );
NF_DATA_W2( (pInfo->dwReserved1 >> 16) & 0xffff );
wrdata = (WORD)(pInfo->bOEMReserved) | (((WORD)(pInfo->bBadBlock) << 8)&0xff00);
NF_DATA_W2( wrdata );
NF_DATA_W2( pInfo->wReserved2 );
// Issue the write complete command
NF_CMD(CMD_WRITE2);
// Check ready bit
NF_DETECT_RB(); // Wait tR(max 12us)
// Check the status of program
NF_CMD(CMD_STATUS);
if(NF_DATA_R2() & STATUS_ERROR) {
RETAILMSG(1, (TEXT("NAND_WriteSectorInfo() ######## Error Programming page %d!\n"), sectorAddr));
bRet = FALSE;
}
NF_CE_H();
RELEASEMUTEX();
DEBUGMSG(1, (TEXT("NAND_WriteSectorInfo_OUT %x!\n"), sectorAddr));
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)
{
int i;
unsigned char id1,id2,id3,id4;
DEBUGMSG(1, (TEXT("FMD::FMD_Init\r\n")));
// 0. Create the Mutex for shared access between the kernel and MSFLASH
#ifndef BOOT_LOADER
if (g_hMutex == NULL)
{
#ifdef NOSYSCALL
#ifndef BOOT_LOADER
g_hMutex = SC_CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
#endif
#else
g_hMutex = CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
#endif
// was mutex creation successful?
if (g_hMutex == NULL)
{
RETAILMSG(1,(TEXT("FlashDrv!FMD!FMD_Init: Unable to create mutex\r\n")));
goto ErrExit;
}
}
#endif
#ifndef NOSYSCALL
#ifdef NOBINFS
DWORD dwBytes;
// Initialize the FASTCALL structure to 0
memset(&g_tblFastCall, 0, sizeof(UTL_FASTCALL));//$put 0 at all memory location of UTL_FASTCALL struct.
// 1. CreateFile to get the access to UTLDRV.
//
g_hUTLObject = CreateFile(TEXT("UTL0:"), GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, 0);
if(INVALID_HANDLE_VALUE == g_hUTLObject) {
RETAILMSG(1, (TEXT("Failed CreateFile -- error = 0x%x\n"), GetLastError()));
goto ErrExit;
}
// 2. Call IOCTL to get the FAST CALL function pointer.
//
if(!DeviceIoControl(g_hUTLObject,
IOCTL_UTL_GET_FASTCALL,
NULL, 0,
&g_tblFastCall, sizeof(g_tblFastCall),
&dwBytes, NULL)) { //g_tblfastcall contain the output data from UTLDRV.
RETAILMSG(1, (TEXT("Failed DeviceIoControl -- error = 0x%x\n"), GetLastError()));
goto ErrExit;
}
// 3. Call the fast call to get the PVA for the registers
//
// 3.1 Get the register for NAND controller
if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, NFC_BASE,
32, FALSE, (DWORD *)&pNFReg) ) { //$pNFReg has driver reg virtual address.
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(NFC_BASE) call!\n")));
goto ErrExit;
}
// 3.2 Get the register for the CLKPWR register
if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, CLKPWR_BASE,
32, FALSE, (DWORD *)&v_s24A0CLKPWR) ) {
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(CLKPWR_BASE) call!\n")));
goto ErrExit;
}
#ifdef CEDAR_ONLY
// ++ CE 3.0 Specific Code. Not needed for 4.x +
// 4. Register the Block driver to the Power On Monitor
//
if (ERROR_SUCCESS != g_tblFastCall.RegisterBlockDrv(g_tblFastCall.pContext,
PowerOnCallback)) {
RETAILMSG(1, (TEXT("Failed RegisterStorageDrv -- error = 0x%x\n"), GetLastError()));
goto ErrExit;
}
// -- CE 3.0 Specific Code. Not needed for 4.x +
#endif // CEDAR_ONLY
#else //binfs
//RETAILMSG(1, (TEXT("else block\n")));
pNFReg = (PULONG) VirtualAlloc(0, 0x1000, MEM_RESERVE, PAGE_NOACCESS);//$4KB mamory reserved
if(!pNFReg) {
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualAlloc ... Bailing out!\n")));
goto ErrExit;
}
if(!VirtualCopy(pNFReg, (LPVOID) NFC_BASE, 0x1000,
PAGE_READWRITE|PAGE_NOCACHE)) {
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualCopy for MemCtrl!\n")));
goto ErrExit;
}
//Allocate IOPreg
s24A0IOP = (IOPreg *)VirtualAlloc(NULL, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
ASSERT(s24A0IOP);
if (!VirtualCopy((LPVOID) s24A0IOP, (LPVOID) IOP_BASE, sizeof(IOPreg),
PAGE_READWRITE | PAGE_NOCACHE)) {
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: VirtualCopy (s24A0IOP) failed!\r\n")));
goto ErrExit;
}
//Allocate SROMreg
s24A0SROM = (SROMreg *)VirtualAlloc(NULL, sizeof(SROMreg), MEM_RESERVE, PAGE_NOACCESS);
ASSERT(s24A0SROM);
if (!VirtualCopy((LPVOID) s24A0SROM, (LPVOID) SROMCTRL_BASE, sizeof(SROMreg),
PAGE_READWRITE | PAGE_NOCACHE)) {
RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: VirtualCopy (s24A0SROM) failed!\r\n")));
goto ErrExit;
}
#endif
#else
pNFReg = (PULONG) (NFC_BASE | 0x20000000);
s24A0IOP = (IOPreg *) ( IOP_BASE | 0x20000000 );
s24A0SROM = (SROMreg *) ( SROMCTRL_BASE | 0x20000000 );
#endif
pNFCONF = pNFReg;
pNFCONT = (PULONG) ((PBYTE) pNFReg + 0x04);
pNFCMD = (PUSHORT) ((PBYTE) pNFReg + 0x08);
pNFADDR = (PULONG) ((PBYTE) pNFReg + 0x0C);
pNFDATA = (PUSHORT) ((PBYTE) pNFReg + 0x10);
pNFMECCData0 = (PUSHORT) ((PBYTE) pNFReg + 0x14);
pNFMECCData1 = (PUSHORT) ((PBYTE) pNFReg + 0x18);
pNFMECCData2 = (PUSHORT) ((PBYTE) pNFReg + 0x1c);
pNFMECCData3 = (PUSHORT) ((PBYTE) pNFReg + 0x20);
pNFSTAT = (PULONG) ((PBYTE) pNFReg + 0x2c);
pNFESTAT0 = (PULONG) ((PBYTE) pNFReg + 0x30);
pNFESTAT1 = (PULONG) ((PBYTE) pNFReg + 0x34);
pNFMECC0 = (PULONG) ((PBYTE) pNFReg + 0x38);
pNFMECC1 = (PULONG) ((PBYTE) pNFReg + 0x3c);
// Now we need enable the NAND Flash controller
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -