551 lines
16 KiB
C
551 lines
16 KiB
C
/*
|
|
* $Log: P:/user/amir/lite/vcs/i28f016.c_v $
|
|
*
|
|
* Rev 1.10 06 Oct 1997 9:45:48 danig
|
|
* VPP functions under #ifdef
|
|
*
|
|
* Rev 1.9 10 Sep 1997 16:48:24 danig
|
|
* Debug messages & got rid of generic names
|
|
*
|
|
* Rev 1.8 31 Aug 1997 15:09:20 danig
|
|
* Registration routine return status
|
|
*
|
|
* Rev 1.7 24 Jul 1997 17:52:58 amirban
|
|
* FAR to FAR0
|
|
*
|
|
* Rev 1.6 20 Jul 1997 17:17:06 amirban
|
|
* No watchDogTimer
|
|
*
|
|
* Rev 1.5 07 Jul 1997 15:22:08 amirban
|
|
* Ver 2.0
|
|
*
|
|
* Rev 1.4 04 Mar 1997 16:44:22 amirban
|
|
* Page buffer bug fix
|
|
*
|
|
* Rev 1.3 18 Aug 1996 13:48:24 amirban
|
|
* Comments
|
|
*
|
|
* Rev 1.2 12 Aug 1996 15:49:04 amirban
|
|
* Added suspend/resume
|
|
*
|
|
* Rev 1.1 31 Jul 1996 14:30:50 amirban
|
|
* Background stuff
|
|
*
|
|
* Rev 1.0 18 Jun 1996 16:34:30 amirban
|
|
* Initial revision.
|
|
*/
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FAT-FTL Lite Software Development Kit */
|
|
/* Copyright (C) M-Systems Ltd. 1995-1996 */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* This MTD supports the following Flash technologies: */
|
|
/* */
|
|
/* - Intel 28F016SA/28016SV/Cobra 16-mbit devices */
|
|
/* */
|
|
/* And (among else), the following Flash media and cards: */
|
|
/* */
|
|
/* - Intel Series-2+ PCMCIA cards */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
#include "flflash.h"
|
|
#ifdef FL_BACKGROUND
|
|
#include "backgrnd.h"
|
|
#endif
|
|
|
|
/* JEDEC ids for this MTD */
|
|
#define I28F016_FLASH 0x89a0
|
|
#define LH28F016SU_FLASH 0xB088
|
|
|
|
#define SETUP_ERASE 0x2020
|
|
#define SETUP_WRITE 0x4040
|
|
#define CLEAR_STATUS 0x5050
|
|
#define READ_STATUS 0x7070
|
|
#define READ_ID 0x9090
|
|
#define SUSPEND_ERASE 0xb0b0
|
|
#define CONFIRM_ERASE 0xd0d0
|
|
#define RESUME_ERASE 0xd0d0
|
|
#define READ_ARRAY 0xffff
|
|
|
|
#define LOAD_PAGE_BUFFER 0xe0e0
|
|
#define WRITE_PAGE_BUFFER 0x0c0c
|
|
#define READ_EXTENDED_REGS 0x7171
|
|
|
|
#define WSM_VPP_ERROR 0x08
|
|
#define WSM_ERROR 0x38
|
|
#define WSM_SUSPENDED 0x40
|
|
#define WSM_READY 0x80
|
|
|
|
#define GSR_ERROR 0x20
|
|
|
|
#define both(word) (vol.interleaving == 1 ? tffsReadWordFlash(word) : tffsReadWordFlash(word) & (tffsReadWordFlash(word) >> 8))
|
|
#define any(word) (tffsReadWordFlash(word) | (tffsReadWordFlash(word) >> 8))
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 W o r d S i z e */
|
|
/* */
|
|
/* Identify the card size for an Intel 28F016 word-mode Flash array. */
|
|
/* Sets the value of vol.noOfChips. */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus i28f016WordSize(FLFlash vol)
|
|
{
|
|
FlashWPTR flashPtr = (FlashWPTR) flMap(vol.socket,0);
|
|
unsigned short id0, id1;
|
|
|
|
tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
|
|
tffsWriteWordFlash(flashPtr, READ_ID);
|
|
/* We leave the first chip in Read ID mode, so that we can */
|
|
/* discover an address wraparound. */
|
|
if( vol.type == I28F016_FLASH ) {
|
|
id0 = 0x0089;
|
|
id1 = 0x66a0;
|
|
}
|
|
else if( vol.type == LH28F016SU_FLASH ) {
|
|
id0 = 0x00B0;
|
|
id1 = 0x6688;
|
|
}
|
|
|
|
for (vol.noOfChips = 1; /* Scan the chips */
|
|
vol.noOfChips < 2000; /* Big enough ? */
|
|
vol.noOfChips++) {
|
|
flashPtr = (FlashWPTR) flMap(vol.socket,vol.noOfChips * vol.chipSize);
|
|
|
|
if (tffsReadWordFlash(flashPtr) == id0 && tffsReadWordFlash(flashPtr + 1) == id1)
|
|
break; /* We've wrapped around to the first chip ! */
|
|
|
|
tffsWriteWordFlash(flashPtr, READ_ID);
|
|
if (!(tffsReadWordFlash(flashPtr) == id0 && tffsReadWordFlash(flashPtr + 1) == id1))
|
|
break;
|
|
tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
|
|
tffsWriteWordFlash(flashPtr, READ_ARRAY);
|
|
}
|
|
|
|
flashPtr = (FlashWPTR) flMap(vol.socket,0);
|
|
tffsWriteWordFlash(flashPtr, READ_ARRAY);
|
|
|
|
return flOK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 W r i t e */
|
|
/* */
|
|
/* Write a block of bytes to Flash */
|
|
/* */
|
|
/* This routine will be registered as the MTD flash.write routine */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* address : Card address to write to */
|
|
/* buffer : Address of data to write */
|
|
/* length : Number of bytes to write */
|
|
/* overwrite : TRUE if overwriting old Flash contents */
|
|
/* FALSE if old contents are known to be erased */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on success, failed otherwise */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus i28f016Write(FLFlash vol,
|
|
CardAddress address,
|
|
const VOID FAR1 *buffer,
|
|
dword length,
|
|
word overwrite)
|
|
{
|
|
/* Set timeout of 5 seconds from now */
|
|
ULONG writeTimeout = flMsecCounter + 5000;
|
|
|
|
FLStatus status = flOK;
|
|
FlashWPTR flashPtr;
|
|
ULONG maxLength, i, from;
|
|
UCHAR * bBuffer = (UCHAR *) buffer;
|
|
FlashPTR bFlashPtr;
|
|
ULONG * dBuffer = (ULONG *) buffer;
|
|
FlashDPTR dFlashPtr;
|
|
|
|
if (flWriteProtected(vol.socket))
|
|
return flWriteProtect;
|
|
|
|
if ((length & 1) || (address & 1)) /* Only write words on word-boundary */
|
|
return flBadParameter;
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
checkStatus(flNeedVpp(vol.socket));
|
|
#endif
|
|
|
|
maxLength = 256 * vol.interleaving;
|
|
for (from = 0; from < length && status == flOK; from += maxLength) {
|
|
FlashWPTR currPtr;
|
|
ULONG lengthWord;
|
|
ULONG tailBytes;
|
|
ULONG thisLength = length - from;
|
|
|
|
if (thisLength > maxLength)
|
|
thisLength = maxLength;
|
|
lengthWord = (thisLength + vol.interleaving - 1) /
|
|
(vol.interleaving == 1 ? 2 : vol.interleaving) - 1;
|
|
if (vol.interleaving != 1)
|
|
lengthWord |= (lengthWord << 8);
|
|
flashPtr = (FlashWPTR) flMap(vol.socket,address + from);
|
|
|
|
tailBytes = ((thisLength - 1) & (vol.interleaving - 1)) + 1;
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < (ULONG)vol.interleaving && i < thisLength;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, LOAD_PAGE_BUFFER);
|
|
if (i < tailBytes) {
|
|
tffsWriteWordFlash(currPtr, (USHORT) lengthWord);
|
|
}
|
|
else {
|
|
tffsWriteWordFlash(currPtr, (USHORT) (lengthWord - 1));
|
|
}
|
|
tffsWriteWordFlash(currPtr, 0);
|
|
}
|
|
|
|
dFlashPtr = (FlashDPTR) flashPtr;
|
|
bFlashPtr = (FlashPTR) flashPtr;
|
|
for (i = 0; i < thisLength - 4; i += 4) {
|
|
tffsWriteDwordFlash(dFlashPtr + i, *(dBuffer + from + i));
|
|
}
|
|
for(; i < thisLength; i++) {
|
|
tffsWriteByteFlash(bFlashPtr + i, *(bBuffer + from + i));
|
|
}
|
|
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < (ULONG)vol.interleaving && i < thisLength;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, WRITE_PAGE_BUFFER);
|
|
if (!((address + from + i) & vol.interleaving)) {
|
|
/* Even address */
|
|
tffsWriteWordFlash(currPtr, (USHORT) lengthWord);
|
|
tffsWriteWordFlash(currPtr, 0);
|
|
}
|
|
else {
|
|
/* Odd address */
|
|
tffsWriteWordFlash(currPtr, 0);
|
|
tffsWriteWordFlash(currPtr, (USHORT) lengthWord);
|
|
}
|
|
|
|
}
|
|
|
|
/* map to the GSR & BSR */
|
|
flashPtr = (FlashWPTR) flMap(vol.socket,
|
|
(CardAddress)( (address + from & -(int)vol.erasableBlockSize) +
|
|
4 * vol.interleaving));
|
|
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < (ULONG)vol.interleaving && i < thisLength;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, READ_EXTENDED_REGS);
|
|
while (!(both(currPtr) & WSM_READY) && flMsecCounter < writeTimeout)
|
|
;
|
|
if ((any(currPtr) & GSR_ERROR) || !(both(currPtr) & WSM_READY)) {
|
|
DEBUG_PRINT(("Debug: write failed for 16-bit Intel media.\n"));
|
|
status = flWriteFault;
|
|
tffsWriteWordFlash(currPtr, CLEAR_STATUS);
|
|
}
|
|
tffsWriteWordFlash(currPtr, READ_ARRAY);
|
|
}
|
|
}
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
flDontNeedVpp(vol.socket);
|
|
#endif
|
|
|
|
/* verify the data */
|
|
dFlashPtr = (FlashDPTR) flMap(vol.socket, address);
|
|
dBuffer = (ULONG *) buffer;
|
|
|
|
if (status == flOK) {
|
|
/* compare double words */
|
|
for (;length >= 4; length -= 4, dFlashPtr++, dBuffer++) {
|
|
if (tffsReadDwordFlash(dFlashPtr) != *dBuffer) {
|
|
DEBUG_PRINT(("Debug: write failed for 16-bit Intel media in verification.\n"));
|
|
return flWriteFault;
|
|
}
|
|
}
|
|
|
|
/* compare the last bytes */
|
|
bFlashPtr = (FlashPTR) dFlashPtr;
|
|
bBuffer = (UCHAR *)dBuffer;
|
|
for (; length; length--, bFlashPtr++, bBuffer++) {
|
|
if (tffsReadByteFlash(bFlashPtr) != *bBuffer) {
|
|
DEBUG_PRINT(("Debug: write failed for 16-bit Intel media in verification.\n"));
|
|
return flWriteFault;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 E r a s e */
|
|
/* */
|
|
/* Erase one or more contiguous Flash erasable blocks */
|
|
/* */
|
|
/* This routine will be registered as the MTD vol.erase routine */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* firstErasableBlock : Number of first block to erase */
|
|
/* numOfErasableBlocks: Number of blocks to erase */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on success, failed otherwise */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus i28f016Erase(FLFlash vol,
|
|
word firstErasableBlock,
|
|
word numOfErasableBlocks)
|
|
{
|
|
FLStatus status = flOK; /* unless proven otherwise */
|
|
LONG iBlock;
|
|
|
|
if (flWriteProtected(vol.socket))
|
|
return flWriteProtect;
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
checkStatus(flNeedVpp(vol.socket));
|
|
#endif
|
|
|
|
for (iBlock = 0; iBlock < numOfErasableBlocks && status == flOK; iBlock++) {
|
|
FlashWPTR currPtr;
|
|
LONG i;
|
|
FLBoolean finished;
|
|
|
|
FlashWPTR flashPtr = (FlashWPTR)
|
|
flMap(vol.socket,(firstErasableBlock + iBlock) * vol.erasableBlockSize);
|
|
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < vol.interleaving;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, SETUP_ERASE);
|
|
tffsWriteWordFlash(currPtr, CONFIRM_ERASE);
|
|
}
|
|
|
|
do {
|
|
#ifdef FL_BACKGROUND
|
|
while (flForeground(1) == BG_SUSPEND) { /* suspend */
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < vol.interleaving;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, READ_STATUS);
|
|
if (!(both(currPtr) & WSM_READY)) {
|
|
tffsWriteWordFlash(currPtr, SUSPEND_ERASE);
|
|
tffsWriteWordFlash(currPtr, READ_STATUS);
|
|
while (!(both(currPtr) & WSM_READY))
|
|
;
|
|
}
|
|
tffsWriteWordFlash(currPtr, READ_ARRAY);
|
|
}
|
|
}
|
|
#endif
|
|
finished = TRUE;
|
|
for (i = 0, currPtr = flashPtr;
|
|
i < vol.interleaving;
|
|
i += 2, currPtr++) {
|
|
tffsWriteWordFlash(currPtr, READ_STATUS);
|
|
|
|
if (any(currPtr) & WSM_SUSPENDED) {
|
|
tffsWriteWordFlash(currPtr, RESUME_ERASE);
|
|
finished = FALSE;
|
|
}
|
|
else if (!(both(currPtr) & WSM_READY))
|
|
finished = FALSE;
|
|
else {
|
|
if (any(currPtr) & WSM_ERROR) {
|
|
DEBUG_PRINT(("Debug: erase failed for 16-bit Intel media.\n"));
|
|
status = (any(currPtr) & WSM_VPP_ERROR) ? flVppFailure : flWriteFault;
|
|
tffsWriteWordFlash(currPtr, CLEAR_STATUS);
|
|
}
|
|
tffsWriteWordFlash(currPtr, READ_ARRAY);
|
|
}
|
|
}
|
|
flDelayMsecs(10);
|
|
} while (!finished);
|
|
|
|
}
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
flDontNeedVpp(vol.socket);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 M a p */
|
|
/* */
|
|
/* Map through buffer. This routine will be registered as the map */
|
|
/* routine for this MTD. */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* address : Flash address to be mapped. */
|
|
/* length : number of bytes to map. */
|
|
/* */
|
|
/* Returns: */
|
|
/* Pointer to the buffer data was mapped to. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
VOID FAR0 *i28f016Map (FLFlash vol, CardAddress address, int length)
|
|
{
|
|
vol.socket->remapped = TRUE;
|
|
return mapThroughBuffer(&vol,address,length);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 R e a d */
|
|
/* */
|
|
/* Read some data from the flash. This routine will be registered as */
|
|
/* the read routine for this MTD. */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* address : Address to read from. */
|
|
/* buffer : buffer to read to. */
|
|
/* length : number of bytes to read (up to sector size). */
|
|
/* modes : EDC flag etc. */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on success, otherwise failed. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus i28f016Read(FLFlash vol,
|
|
CardAddress address,
|
|
VOID FAR1 *buffer,
|
|
dword length,
|
|
word modes)
|
|
{
|
|
ULONG i;
|
|
UCHAR * bBuffer;
|
|
FlashPTR bFlashPtr;
|
|
ULONG * dBuffer = (ULONG *)buffer;
|
|
FlashDPTR dFlashPtr = (FlashDPTR)flMap(vol.socket, address);
|
|
|
|
for (i = 0; i < length - 4; i += 4, dBuffer++, dFlashPtr++) {
|
|
*dBuffer = tffsReadDwordFlash(dFlashPtr);
|
|
}
|
|
bBuffer = (UCHAR *)dBuffer;
|
|
bFlashPtr = (FlashPTR)dFlashPtr;
|
|
for(; i < length; i++, bBuffer++, bFlashPtr++) {
|
|
*bBuffer = tffsReadByteFlash(bFlashPtr);
|
|
}
|
|
return flOK ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 1 6 I d e n t i f y */
|
|
/* */
|
|
/* Identifies media based on Intel 28F016 and registers as an MTD for */
|
|
/* such. */
|
|
/* */
|
|
/* This routine will be placed on the MTD list in custom.h. It must be */
|
|
/* an extern routine. */
|
|
/* */
|
|
/* On successful identification, the Flash structure is filled out and */
|
|
/* the write and erase routines registered. */
|
|
/* */
|
|
/* Parameters: */
|
|
/* vol : Pointer identifying drive */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on positive identificaion, failed otherwise */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus i28f016Identify(FLFlash vol)
|
|
{
|
|
FlashWPTR flashPtr;
|
|
|
|
DEBUG_PRINT(("Debug: entering 16-bit Intel media identification routine.\n"));
|
|
|
|
flSetWindowBusWidth(vol.socket,16);/* use 16-bits */
|
|
flSetWindowSpeed(vol.socket,150); /* 120 nsec. */
|
|
flSetWindowSize(vol.socket,2); /* 8 KBytes */
|
|
|
|
flashPtr = (FlashWPTR) flMap(vol.socket,0);
|
|
|
|
vol.noOfChips = 0;
|
|
tffsWriteWordFlash(flashPtr, READ_ID);
|
|
if (tffsReadWordFlash(flashPtr) == 0x0089 && tffsReadWordFlash(flashPtr + 1) == 0x66a0) {
|
|
/* Word mode */
|
|
vol.type = I28F016_FLASH;
|
|
vol.interleaving = 1;
|
|
tffsWriteWordFlash(flashPtr, READ_ARRAY);
|
|
}
|
|
else if (tffsReadWordFlash(flashPtr) == 0x00B0 && tffsReadWordFlash(flashPtr + 1) == 0x6688) {
|
|
/* Word mode */
|
|
vol.type = LH28F016SU_FLASH;
|
|
vol.interleaving = 1;
|
|
tffsWriteWordFlash(flashPtr, READ_ARRAY);
|
|
}
|
|
else {
|
|
/* Use standard identification routine to detect byte-mode */
|
|
flIntelIdentify(&vol, NULL,0);
|
|
if (vol.interleaving == 1)
|
|
vol.type = NOT_FLASH; /* We cannot handle byte-mode interleaving-1 */
|
|
}
|
|
|
|
if( (vol.type == I28F016_FLASH) || (vol.type == LH28F016SU_FLASH) ) {
|
|
vol.chipSize = 0x200000L;
|
|
vol.erasableBlockSize = 0x10000L * vol.interleaving;
|
|
checkStatus(vol.interleaving == 1 ?
|
|
i28f016WordSize(&vol) :
|
|
flIntelSize(&vol, NULL,0));
|
|
|
|
/* Register our flash handlers */
|
|
vol.write = i28f016Write;
|
|
vol.erase = i28f016Erase;
|
|
vol.read = i28f016Read;
|
|
vol.map = i28f016Map;
|
|
|
|
DEBUG_PRINT(("Debug: identified 16-bit Intel media.\n"));
|
|
return flOK;
|
|
}
|
|
else {
|
|
DEBUG_PRINT(("Debug: failed to identify 16-bit Intel media.\n"));
|
|
return flUnknownMedia; /* not ours */
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* f l R e g i s t e r I 2 8 F 0 1 6 */
|
|
/* */
|
|
/* Registers this MTD for use */
|
|
/* */
|
|
/* Parameters: */
|
|
/* None */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on success, otherwise failure */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus flRegisterI28F016(VOID)
|
|
{
|
|
if (noOfMTDs >= MTDS)
|
|
return flTooManyComponents;
|
|
|
|
mtdTable[noOfMTDs++] = i28f016Identify;
|
|
|
|
return flOK;
|
|
}
|
|
|