📄 fmd.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.
//
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Module Name: FMD.CPP
Abstract: FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
Notes:
-----------------------------------------------------------------------------*/
#include <fmd.h>
#include <ceddk.h>
#include <wdm.h>
#include <ddkreg.h>
#include "nand.h"
#include "ecc.h" // Contains code for performing ECC
#include <PCIReg.h>
// 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
#define ECC_SIZE 8
static BYTE ECC[ECC_SIZE]; // Used to retrieve/store ECC information
DWORD IoAddr=0;
BOOL bIoMemMapped=FALSE;
DWORD dwDeviceId=0;
WORD g_wPagesPerBlock;
BOOL NEED_EXT_ADDR = TRUE;
/*
@func UCHAR | FMD_READ_PORT_UCHAR | READ_PORT_UCHAR wrapper - used to enforce flash access times.
@rdesc Data from read returned.
@comm
@xref
*/
UCHAR
FMD_READ_PORT_UCHAR(PUCHAR Port)
{
// NOTE: delay can be added here.
return(READ_PORT_UCHAR(Port));
}
/*
@func VOID | FMD_WRITE_PORT_UCHAR | WRITE_PORT_UCHAR wrapper - used to enforce flash access times.
@rdesc None.
@comm
@xref
*/
VOID
FMD_WRITE_PORT_UCHAR(PUCHAR Port, UCHAR Value)
{
// NOTE: delay can be added here.
WRITE_PORT_UCHAR(Port, Value);
}
// CheckStatus()
//
// Retrieve the status of the Chip. This function accept a loop number, which
// is used to do the loop if chip is not ready.
//
// dwLoops:
//
// 0: no loop
// 0xffffffff: loop forever
//
UCHAR CheckStatus(DWORD dwLoops)
{
BOOL bStop = (dwLoops != (DWORD) -1);
UCHAR usStatus;
// Twb=200ns wait. generate 20 * 30ns wait
for (volatile int i=0;i<20;i++)
FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
while(1) {
usStatus = FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
if( usStatus & STATUS_READY || // Status ready
(bStop && !dwLoops) ) // Non-infinite loop and
// we already pay our due
{
break;
}
dwLoops--;
}
// Trr= 20 ns. gernerate 2*30ns Wait.
FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
FMD_READ_PORT_UCHAR((PUCHAR)NAND_BUSY_PORT);
return usStatus;
}
// GetStatus()
//
// Retrieve the status of the Chip. This function accept a loop number, which
// is used to do the loop if chip is not ready.
//
// dwLoops:
//
// 0: no loop
// 0xffffffff: loop forever
//
UCHAR GetStatus(DWORD dwLoops)
{
BOOL bStop = (dwLoops != (DWORD) -1);
UCHAR usStatus;
CheckStatus(dwLoops);
// Issue read status command
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_STATUS);
while(1) {
usStatus = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
if( usStatus & STATUS_READY || // Status ready
(bStop && !dwLoops) ) // Non-infinite loop and
// we already pay our due
{
break;
}
dwLoops--;
}
// We need to reset the port back to read mode. Issuing a read (0x00)
// command
//FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READ);
return usStatus;
}
DWORD ReadFlashID()
{
BYTE data1,data2;
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)0); // enable chip
CheckStatus((DWORD) -1); // check ready
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READID);
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_ADDR_PORT, 0x0);
CheckStatus((DWORD) -1);
data1 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
data2 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
RETAILMSG(1,(TEXT("FMD:ReadID (Maker=%x,Device=%x)\r\n"),data1,data2));
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)1); // disable chip
return ((DWORD)data1*0x100+data2);
}
//
// Put Future Device enhancement here.
// Command 91h, address 0, Read following 3 bytes.
// Extended ID information.
// Character code:
// bit 1,0 00 single chip
// 01 2-chip module
// 10 4-chip module
// 11 8-chip module
// bit 3,2 01=MLC use 64 pages/block
// 00=Binary use 32 pages/block
// bit 6,5,4 010 device includes x4 multi-block mode
// bit 7 0 no 2ndary data cache
// Organization code:
// bit 3,2,1,0 0110 64MByte
// 0111 128MByte
// 1000 256MByte
// 1001 512MByte
// 1010 1GByte
// bit 5,4 00
// bit 7,6 01 x8-data-bus width
// Size code:
// bit 2,1,0 010 512Bytes-page size
// bit 4,3 11 extended page size=16Bytes
// bit 7,6,5 001 16KByte
// 010 32KByte
// 011 64KByte
// 100 128KByte
//
UCHAR ReadFlashID2()
{
BYTE data1,data2,data3;
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)0); // enable chip
CheckStatus((DWORD) -1); // check ready
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CMD_PORT, (UCHAR) CMD_READID2);
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_ADDR_PORT, 0x0);
CheckStatus((DWORD) -1);
data1 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
data2 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
data3 = FMD_READ_PORT_UCHAR((PUCHAR) NAND_DATA_PORT);
RETAILMSG(1,(TEXT("FMD:ReadID2 (Char=%x,Org=%x,Size=%x)\r\n"),data1,data2,data3));
FMD_WRITE_PORT_UCHAR((PUCHAR) NAND_CS_PORT,(UCHAR)1); // disable chip
return ((UCHAR)data1 & 0x04);
}
/*
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
*/
//
// Inline functions
//
//
// Read a DWORD from a device's configuration space
//
__inline static DWORD
PCIConfig_Read(
ULONG BusNumber,
ULONG Device,
ULONG Function,
ULONG Offset
)
{
ULONG RetVal = FALSE;
PCI_SLOT_NUMBER SlotNumber;
SlotNumber.u.AsULONG = 0;
SlotNumber.u.bits.DeviceNumber = Device;
SlotNumber.u.bits.FunctionNumber = Function;
HalGetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &RetVal, Offset, sizeof(RetVal));
return RetVal;
}
//
// Write a DWORD to a device's configuration space
//
__inline static void
PCIConfig_Write(
ULONG BusNumber,
ULONG Device,
ULONG Function,
ULONG Offset,
ULONG Value
)
{
PCI_SLOT_NUMBER SlotNumber;
SlotNumber.u.AsULONG = 0;
SlotNumber.u.bits.DeviceNumber = Device;
SlotNumber.u.bits.FunctionNumber = Function;
HalSetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &Value, Offset, sizeof(Value));
}
//
// Read Base Address Registers and size, populate Info struct with this information
//
BOOL
PCIReadBARs(
PPCI_REG_INFO pInfo
)
{
DWORD NumberOfRegs;
DWORD Offset;
DWORD i;
DWORD BaseAddress;
DWORD Size;
DWORD Reg;
DWORD IoIndex = 0;
DWORD MemIndex = 0;
// Determine number of BARs to examine from header type
switch (pInfo->Cfg.HeaderType & ~PCI_MULTIFUNCTION) {
case PCI_DEVICE_TYPE:
NumberOfRegs = PCI_TYPE0_ADDRESSES;
break;
case PCI_BRIDGE_TYPE:
NumberOfRegs = PCI_TYPE1_ADDRESSES;
break;
case PCI_CARDBUS_TYPE:
NumberOfRegs = PCI_TYPE2_ADDRESSES;
break;
default:
return FALSE;
}
for (i = 0, Offset = 0x10; i < NumberOfRegs; i++, Offset += 4) {
// Get base address register value
Reg = pInfo->Cfg.u.type0.BaseAddresses[i];
// Get size info
PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, 0xFFFFFFFF);
BaseAddress = PCIConfig_Read(pInfo->Bus, pInfo->Device, pInfo->Function, Offset);
PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, Reg);
// Re-adjust BaseAddress if upper 16-bits are 0 (this happens on some devices that don't follow
// the PCI spec, like the Intel UHCI controllers)
if (((BaseAddress & 0xFFFFFFFC) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -