538 lines
15 KiB
C
538 lines
15 KiB
C
/*
|
|
* $Log: V:/i28f008.c_v $
|
|
*
|
|
* Rev 1.16 06 Oct 1997 18:37:30 ANDRY
|
|
* no COBUX
|
|
*
|
|
* Rev 1.15 05 Oct 1997 19:11:08 ANDRY
|
|
* COBUX (Motorola M68360 16-bit only board)
|
|
*
|
|
* Rev 1.14 05 Oct 1997 14:35:36 ANDRY
|
|
* flNeedVpp() and flDontNeedVpp() are under #ifdef SOCKET_12_VOLTS
|
|
*
|
|
* Rev 1.13 10 Sep 1997 16:18:10 danig
|
|
* Got rid of generic names
|
|
*
|
|
* Rev 1.12 04 Sep 1997 18:47:20 danig
|
|
* Debug messages
|
|
*
|
|
* Rev 1.11 31 Aug 1997 15:06:40 danig
|
|
* Registration routine return status
|
|
*
|
|
* Rev 1.10 24 Jul 1997 17:52:30 amirban
|
|
* FAR to FAR0
|
|
*
|
|
* Rev 1.9 21 Jul 1997 14:44:06 danig
|
|
* No parallelLimit
|
|
*
|
|
* Rev 1.8 20 Jul 1997 17:17:00 amirban
|
|
* No watchDogTimer
|
|
*
|
|
* Rev 1.7 07 Jul 1997 15:22:06 amirban
|
|
* Ver 2.0
|
|
*
|
|
* Rev 1.6 15 Apr 1997 19:16:40 danig
|
|
* Pointer conversions.
|
|
*
|
|
* Rev 1.5 29 Aug 1996 14:17:48 amirban
|
|
* Warnings
|
|
*
|
|
* Rev 1.4 18 Aug 1996 13:48:44 amirban
|
|
* Comments
|
|
*
|
|
* Rev 1.3 31 Jul 1996 14:31:10 amirban
|
|
* Background stuff
|
|
*
|
|
* Rev 1.2 04 Jul 1996 18:20:06 amirban
|
|
* New flag field
|
|
*
|
|
* Rev 1.1 03 Jun 1996 16:28:58 amirban
|
|
* Cobra additions
|
|
*
|
|
* Rev 1.0 20 Mar 1996 13:33:06 amirban
|
|
* Initial revision.
|
|
*/
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* FAT-FTL Lite Software Development Kit */
|
|
/* Copyright (C) M-Systems Ltd. 1995-1996 */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* This MTD supports the following Flash technologies: */
|
|
/* */
|
|
/* - Intel 28F008/Cobra 8-mbit devices */
|
|
/* - Intel 28F016SA/28016SV/Cobra 16-mbit devices (byte-mode operation) */
|
|
/* */
|
|
/* And (among else), the following Flash media and cards: */
|
|
/* */
|
|
/* - Intel Series-2 PCMCIA cards */
|
|
/* - Intel Series-2+ PCMCIA cards */
|
|
/* - M-Systems ISA/Tiny/PC-104 Flash Disks */
|
|
/* - M-Systems NOR PCMCIA cards */
|
|
/* - Intel Value-100 cards */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
#include "flflash.h"
|
|
#ifdef FL_BACKGROUND
|
|
#include "backgrnd.h"
|
|
#endif
|
|
|
|
#define flash (*pFlash)
|
|
|
|
#define SETUP_ERASE 0x20
|
|
#define SETUP_WRITE 0x40
|
|
#define CLEAR_STATUS 0x50
|
|
#define READ_STATUS 0x70
|
|
#define READ_ID 0x90
|
|
#define SUSPEND_ERASE 0xb0
|
|
#define CONFIRM_ERASE 0xd0
|
|
#define RESUME_ERASE 0xd0
|
|
#define READ_ARRAY 0xff
|
|
|
|
#define WSM_ERROR 0x38
|
|
#define WSM_VPP_ERROR 0x08
|
|
#define WSM_SUSPENDED 0x40
|
|
#define WSM_READY 0x80
|
|
|
|
/* JEDEC ids for this MTD */
|
|
#define I28F008_FLASH 0x89a2
|
|
#define I28F016_FLASH 0x89a0
|
|
#define COBRA004_FLASH 0x89a7
|
|
#define COBRA008_FLASH 0x89a6
|
|
#define COBRA016_FLASH 0x89aa
|
|
|
|
#define MOBILE_MAX_INLV_4 0x8989
|
|
#define LDP_1MB_IN_16BIT_MODE 0x89ff
|
|
|
|
/* Definition of MTD specific vol.flags bits: */
|
|
|
|
#define NO_12VOLTS 0x100 /* Card does not need 12 Volts Vpp */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 0 8 W r i t e */
|
|
/* */
|
|
/* Write a block of bytes to Flash */
|
|
/* */
|
|
/* This routine will be registered as the MTD vol.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 i28f008Write(FLFlash vol,
|
|
CardAddress address,
|
|
const VOID FAR1 *buffer,
|
|
dword length,
|
|
word overwrite)
|
|
{
|
|
/* Set timeout ot 5 seconds from now */
|
|
ULONG writeTimeout = flMsecCounter + 5000;
|
|
|
|
FLStatus status;
|
|
ULONG i, cLength;
|
|
FlashPTR flashPtr;
|
|
|
|
|
|
if (flWriteProtected(vol.socket))
|
|
return flWriteProtect;
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
if (!(vol.flags & NO_12VOLTS))
|
|
checkStatus(flNeedVpp(vol.socket));
|
|
#endif
|
|
|
|
flashPtr = (FlashPTR) flMap(vol.socket,address);
|
|
cLength = length;
|
|
|
|
if (vol.interleaving == 1) {
|
|
lastByte:
|
|
#ifdef __cplusplus
|
|
#define bFlashPtr flashPtr
|
|
#define bBuffer ((const UCHAR FAR1 * &) buffer)
|
|
#else
|
|
#define bFlashPtr flashPtr
|
|
#define bBuffer ((const UCHAR FAR1 *) buffer)
|
|
#endif
|
|
while (cLength >= 1) {
|
|
tffsWriteByteFlash(bFlashPtr, SETUP_WRITE);
|
|
tffsWriteByteFlash(bFlashPtr, *bBuffer);
|
|
cLength--;
|
|
bBuffer++;
|
|
bFlashPtr++;
|
|
while (!(tffsReadByteFlash(bFlashPtr-1) & WSM_READY) && flMsecCounter < writeTimeout)
|
|
;
|
|
}
|
|
}
|
|
else if (vol.interleaving == 2) {
|
|
lastWord:
|
|
#ifdef __cplusplus
|
|
#define wFlashPtr ((FlashWPTR &) flashPtr)
|
|
#define wBuffer ((const USHORT FAR1 * &) buffer)
|
|
#else
|
|
#define wFlashPtr ((FlashWPTR) flashPtr)
|
|
#define wBuffer ((const USHORT FAR1 *) buffer)
|
|
#endif
|
|
while (cLength >= 2) {
|
|
tffsWriteWordFlash(wFlashPtr, SETUP_WRITE * 0x101);
|
|
tffsWriteWordFlash(wFlashPtr, *wBuffer);
|
|
cLength -= 2;
|
|
wBuffer++;
|
|
wFlashPtr++;
|
|
while ((~(tffsReadWordFlash(wFlashPtr-1)) & (WSM_READY * 0x101)) && flMsecCounter < writeTimeout)
|
|
;
|
|
}
|
|
if (cLength > 0)
|
|
goto lastByte;
|
|
}
|
|
else /* if (vol.interleaving >= 4) */ {
|
|
#ifdef __cplusplus
|
|
#define dFlashPtr ((FlashDPTR &) flashPtr)
|
|
#define dBuffer ((const ULONG FAR1 * &) buffer)
|
|
#else
|
|
#define dFlashPtr ((FlashDPTR) flashPtr)
|
|
#define dBuffer ((const ULONG FAR1 *) buffer)
|
|
#endif
|
|
while (cLength >= 4) {
|
|
tffsWriteDwordFlash(dFlashPtr, SETUP_WRITE * 0x1010101l);
|
|
tffsWriteDwordFlash(dFlashPtr, *dBuffer);
|
|
cLength -= 4;
|
|
dBuffer++;
|
|
dFlashPtr++;
|
|
while ((~(tffsReadDwordFlash(dFlashPtr-1)) & (WSM_READY * 0x1010101lu)) && flMsecCounter < writeTimeout)
|
|
;
|
|
}
|
|
if (cLength > 0)
|
|
goto lastWord;
|
|
}
|
|
|
|
flashPtr -= length;
|
|
bBuffer -= length;
|
|
|
|
status = flOK;
|
|
for (i = 0; i < (ULONG)vol.interleaving && i < length; i++) {
|
|
if (tffsReadByteFlash(flashPtr + i) & WSM_ERROR) {
|
|
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media.\n"));
|
|
status = (tffsReadByteFlash(flashPtr + i) & WSM_VPP_ERROR) ? flVppFailure : flWriteFault;
|
|
tffsWriteByteFlash(flashPtr + i, CLEAR_STATUS);
|
|
}
|
|
tffsWriteByteFlash(flashPtr + i, READ_ARRAY);
|
|
}
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
if (!(vol.flags & NO_12VOLTS))
|
|
flDontNeedVpp(vol.socket);
|
|
#endif
|
|
|
|
/* verify the data */
|
|
if (status == flOK) {
|
|
/* compare double words */
|
|
for (;length >= 4; length -= 4, dFlashPtr++, dBuffer++) {
|
|
if (tffsReadDwordFlash(dFlashPtr) != *dBuffer) {
|
|
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media in verification.\n"));
|
|
return flWriteFault;
|
|
}
|
|
}
|
|
|
|
/* compare the last bytes */
|
|
for (; length; length--, bFlashPtr++, bBuffer++) {
|
|
if (tffsReadByteFlash(bFlashPtr) != *bBuffer) {
|
|
DEBUG_PRINT(("Debug: write failed for 8-bit Intel media in verification.\n"));
|
|
return flWriteFault;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 0 8 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 i28f008Erase(FLFlash vol,
|
|
word firstErasableBlock,
|
|
word numOfErasableBlocks)
|
|
{
|
|
LONG iBlock;
|
|
|
|
FLStatus status = flOK; /* unless proven otherwise */
|
|
|
|
if (flWriteProtected(vol.socket))
|
|
return flWriteProtect;
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
if (!(vol.flags & NO_12VOLTS))
|
|
checkStatus(flNeedVpp(vol.socket));
|
|
#endif
|
|
|
|
for (iBlock = 0; iBlock < numOfErasableBlocks && status == flOK; iBlock++) {
|
|
LONG j;
|
|
FLBoolean finished;
|
|
|
|
FlashPTR flashPtr = (FlashPTR)
|
|
flMap(vol.socket,
|
|
(firstErasableBlock + iBlock) * vol.erasableBlockSize);
|
|
|
|
for (j = 0; j < vol.interleaving; j++) {
|
|
tffsWriteByteFlash(flashPtr + j, SETUP_ERASE);
|
|
tffsWriteByteFlash(flashPtr + j, CONFIRM_ERASE);
|
|
}
|
|
|
|
do {
|
|
#ifdef FL_BACKGROUND
|
|
while (flForeground(1) == BG_SUSPEND) { /* suspend */
|
|
for (j = 0; j < vol.interleaving; j++) {
|
|
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
|
|
if (!(tffsReadByteFlash(flashPtr + j) & WSM_READY)) {
|
|
tffsWriteByteFlash(flashPtr + j, SUSPEND_ERASE);
|
|
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
|
|
while (!(tffsReadByteFlash(flashPtr + j) & WSM_READY))
|
|
;
|
|
}
|
|
tffsWriteByteFlash(flashPtr + j, READ_ARRAY);
|
|
}
|
|
}
|
|
#endif
|
|
finished = TRUE;
|
|
for (j = 0; j < vol.interleaving; j++) {
|
|
tffsWriteByteFlash(flashPtr + j, READ_STATUS);
|
|
if (tffsReadByteFlash(flashPtr + j) & WSM_SUSPENDED) {
|
|
tffsWriteByteFlash(flashPtr + j, RESUME_ERASE);
|
|
finished = FALSE;
|
|
}
|
|
else if (!(tffsReadByteFlash(flashPtr + j) & WSM_READY))
|
|
finished = FALSE;
|
|
else {
|
|
if (tffsReadByteFlash(flashPtr + j) & WSM_ERROR) {
|
|
DEBUG_PRINT(("Debug: erase failed for 8-bit Intel media.\n"));
|
|
status = (tffsReadByteFlash(flashPtr + j) & WSM_VPP_ERROR) ? flVppFailure : flWriteFault;
|
|
tffsWriteByteFlash(flashPtr + j, CLEAR_STATUS);
|
|
}
|
|
tffsWriteByteFlash(flashPtr + j, READ_ARRAY);
|
|
}
|
|
flDelayMsecs(10);
|
|
}
|
|
} while (!finished);
|
|
} /* block loop */
|
|
|
|
#ifdef SOCKET_12_VOLTS
|
|
if (!(vol.flags & NO_12VOLTS))
|
|
flDontNeedVpp(vol.socket);
|
|
#endif
|
|
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 0 8 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 *i28f008Map (FLFlash vol, CardAddress address, int length)
|
|
{
|
|
vol.socket->remapped = TRUE;
|
|
return mapThroughBuffer(&vol,address,length);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 0 8 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 i28f008Read(FLFlash vol,
|
|
CardAddress address,
|
|
VOID FAR1 *buffer,
|
|
dword length,
|
|
word modes)
|
|
{
|
|
ULONG i;
|
|
UCHAR * byteBuffer;
|
|
FlashPTR byteFlashPtr;
|
|
ULONG * dwordBuffer = (ULONG *)buffer;
|
|
FlashDPTR dwordFlashPtr = (FlashDPTR)flMap(vol.socket, address);
|
|
|
|
for (i = 0; i < length - 4; i += 4, dwordBuffer++, dwordFlashPtr++) {
|
|
*dwordBuffer = tffsReadDwordFlash(dwordFlashPtr);
|
|
}
|
|
byteBuffer = (UCHAR *)dwordBuffer;
|
|
byteFlashPtr = (FlashPTR)dwordFlashPtr;
|
|
for(; i < length; i++, byteBuffer++, byteFlashPtr++) {
|
|
*byteBuffer = tffsReadByteFlash(byteFlashPtr);
|
|
}
|
|
return flOK ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* i 2 8 f 0 0 8 I d e n t i f y */
|
|
/* */
|
|
/* Identifies media based on Intel 28F008 and 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 i28f008Identify(FLFlash vol)
|
|
{
|
|
LONG iChip;
|
|
|
|
CardAddress idOffset = 0;
|
|
|
|
DEBUG_PRINT(("Debug: i28f008Identify :entering 8-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 */
|
|
|
|
flIntelIdentify(&vol, NULL,0);
|
|
|
|
if (vol.type == NOT_FLASH) {
|
|
/* The flash may be write-protected at offset 0. Try another offset */
|
|
idOffset = 0x80000l;
|
|
flIntelIdentify(&vol, NULL,idOffset);
|
|
}
|
|
|
|
if (vol.type == LDP_1MB_IN_16BIT_MODE) {
|
|
flSetWindowBusWidth(vol.socket, 8); /* use 8-bits */
|
|
flIntelIdentify(&vol, NULL,idOffset); /* and try to get a valid id */
|
|
}
|
|
|
|
switch (vol.type) {
|
|
case COBRA004_FLASH:
|
|
vol.chipSize = 0x80000l;
|
|
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
|
|
break;
|
|
|
|
case COBRA008_FLASH:
|
|
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
|
|
/* no break */
|
|
|
|
case MOBILE_MAX_INLV_4:
|
|
case I28F008_FLASH:
|
|
vol.chipSize = 0x100000l;
|
|
break;
|
|
|
|
case COBRA016_FLASH:
|
|
vol.flags |= SUSPEND_FOR_WRITE | NO_12VOLTS;
|
|
/* no break */
|
|
|
|
case I28F016_FLASH:
|
|
vol.chipSize = 0x200000l;
|
|
break;
|
|
|
|
default:
|
|
DEBUG_PRINT(("Debug: failed to identify 8-bit Intel media.\n"));
|
|
return flUnknownMedia; /* not ours */
|
|
}
|
|
|
|
vol.erasableBlockSize = 0x10000l * vol.interleaving;
|
|
|
|
checkStatus(flIntelSize(&vol, NULL,idOffset));
|
|
|
|
if (vol.type == MOBILE_MAX_INLV_4)
|
|
vol.type = I28F008_FLASH;
|
|
|
|
for (iChip = 0; iChip < vol.noOfChips; iChip += vol.interleaving) {
|
|
LONG i;
|
|
|
|
FlashPTR flashPtr = (FlashPTR)
|
|
flMap(vol.socket,iChip * vol.chipSize);
|
|
|
|
for (i = 0; i < vol.interleaving; i++)
|
|
tffsWriteByteFlash(flashPtr + i, CLEAR_STATUS);
|
|
}
|
|
|
|
/* Register our flash handlers */
|
|
vol.write = i28f008Write;
|
|
vol.erase = i28f008Erase;
|
|
vol.read = i28f008Read;
|
|
vol.map = i28f008Map;
|
|
|
|
DEBUG_PRINT(("Debug: i28f008Identify :identified 8-bit Intel media.\n"));
|
|
|
|
return flOK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* f l R e g i s t e r I 2 8 F 0 0 8 */
|
|
/* */
|
|
/* Registers this MTD for use */
|
|
/* */
|
|
/* Parameters: */
|
|
/* None */
|
|
/* */
|
|
/* Returns: */
|
|
/* FLStatus : 0 on success, otherwise failure */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
FLStatus flRegisterI28F008(VOID)
|
|
{
|
|
if (noOfMTDs >= MTDS)
|
|
return flTooManyComponents;
|
|
|
|
mtdTable[noOfMTDs++] = i28f008Identify;
|
|
|
|
return flOK;
|
|
}
|
|
|