|
|
/*
* $Log: P:/user/amir/lite/vcs/nfdc2048.c_v $ * * Rev 1.28 19 Oct 1997 15:41:54 danig * Changed tffscpy16 and tffsset16 for far pointers & * cast to FAR0 in mapContInterface * * Rev 1.27 06 Oct 1997 18:37:34 ANDRY * no COBUX * * Rev 1.26 06 Oct 1997 18:04:34 ANDRY * 16-bit access only for interleave 2 cards, COBUX * * Rev 1.25 05 Oct 1997 12:02:32 danig * Support chip ID 0xEA * * Rev 1.24 10 Sep 1997 16:14:08 danig * Got rid of generic names * * Rev 1.23 08 Sep 1997 17:47:00 danig * fixed setAddress for big-endian * * Rev 1.22 04 Sep 1997 13:59:44 danig * Debug messages * * Rev 1.21 31 Aug 1997 15:18:04 danig * Registration routine return status * * Rev 1.20 28 Aug 1997 17:47:08 danig * Buffer\remapped per socket * * Rev 1.19 28 Jul 1997 15:10:36 danig * setPowerOnCallback & moved standard typedefs to flbase.h * * Rev 1.18 24 Jul 1997 18:04:12 amirban * FAR to FAR0 * * Rev 1.17 21 Jul 1997 18:56:00 danig * nandBuffer static * * Rev 1.16 20 Jul 1997 18:21:14 danig * Moved vendorID and chipID to Vars * * Rev 1.15 20 Jul 1997 17:15:06 amirban * Added Toshiba 8MB * * Rev 1.14 07 Jul 1997 15:22:26 amirban * Ver 2.0 * * Rev 1.13 02 Jul 1997 14:59:22 danig * More wait for socket to power up * * Rev 1.12 01 Jul 1997 13:39:54 danig * Wait for socket to power up * * Rev 1.11 22 Jun 1997 18:34:32 danig * Documentation * * Rev 1.10 12 Jun 1997 17:22:24 amirban * Allow LONG extra read/writes * * Rev 1.9 08 Jun 1997 19:18:06 danig * BIG_PAGE & FULL_PAGE moved to flash.h * * Rev 1.8 08 Jun 1997 17:03:40 amirban * Fast Toshiba and power on callback * * Rev 1.7 05 Jun 1997 12:31:38 amirban * Write corrections, and att reg changes * * Rev 1.6 03 Jun 1997 18:45:14 danig * powerUp() * * Rev 1.5 01 Jun 1997 13:42:52 amirban * Rewrite of read/write extra + major reduction * * Rev 1.4 25 May 1997 16:41:38 amirban * Bg-endian, Toshiba fix & simplifications * * Rev 1.3 18 May 1997 17:34:50 amirban * Use 'dataError' * * Rev 1.2 23 Apr 1997 11:02:14 danig * Update to TFFS revision 1.12 * * Rev 1.1 15 Apr 1997 18:48:02 danig * Fixed FAR pointer issues. * * Rev 1.0 08 Apr 1997 18:29:28 danig * Initial revision. */
/************************************************************************/ /* */ /* FAT-FTL Lite Software Development Kit */ /* Copyright (C) M-Systems Ltd. 1995-1997 */ /* */ /************************************************************************/
#include "ntddk.h"
#include "flflash.h"
#include "reedsol.h"
#define NFDC2048 /* Support NFDC2048 ASIC controller */
#define MAX_FLASH_DEVICES 16
#define PAGES_PER_BLOCK 16 /* 16 pages per block on a single chip*/
#define SYNDROM_BYTES 6 /* Number of syndrom bytes: 5 + 1 parity*/
/* Flash IDs*/ #define KM29N16000_FLASH 0xec64
#define KM29N32000_FLASH 0xece5
#define KM29V64000_FLASH 0xece6
#define KM29V128000_FLASH 0xec73
#define KM29V256000_FLASH 0xec75
#define NM29N16_FLASH 0x8f64
#define NM29N32_FLASH 0x8fe5
#define NM29N64_FLASH 0x8fe6
#define TC5816_FLASH 0x9864
#define TC5832_FLASH 0x98e5
#define TC5864_FLASH 0x98e6
#define TC58128_FLASH 0x9873
#define TC58256_FLASH 0x9875
/* Flash commands:*/ #define SERIAL_DATA_INPUT 0x80
#define READ_MODE 0x00
#define READ_MODE_2 0x50
#define RESET_FLASH 0xff
#define SETUP_WRITE 0x10
#define SETUP_ERASE 0x60
#define CONFIRM_ERASE 0xd0
#define READ_STATUS 0x70
#define READ_ID 0x90
#define SUSPEND_ERASE 0xb0
#define REGISTER_READ 0xe0
/* commands for moving flash pointer to areeas A,B or C of page*/ typedef enum { AREA_A = READ_MODE, AREA_B = 0x1, AREA_C = READ_MODE_2 } PointerOp;
typedef union { USHORT w ; UCHAR b ; } WordByte;
/*�������������������������������������������Ŀ
� Memory window to cards common memory � ���������������������������������������������*/
typedef struct { volatile WordByte signals; /* CDSN control register*/
#define CE 0x01
#define CLE 0x02
#define ALE 0x04
#define NOT_WP 0x08
#define RB 0x80
#define FAIL 0x01
#define SUSPENDED 0x20
#define READY 0x40
#define NOT_PROTECTED 0x80
UCHAR fillerA[1024 - sizeof(WordByte)]; volatile LEushort deviceSelector; volatile WordByte eccConfig; /* EDC configuration register*/
#define TOGGLE 0x04 /* Read*/
#ifdef NFDC2048
#define ECC_RST 0x04 /* Write*/
#define ECC_EN 0x08 /* Read / Write*/
#define PAR_DIS 0x10 /* Read / Write*/
#define ECC_RW 0x20 /* Read / Write*/
#define ECC_RDY 0x40 /* Read */
#define ECC_ERROR 0x80 /* Read*/
volatile USHORT syndrom[3]; UCHAR fillerC[1024-10]; /* 1kbytes minus 10 bytes*/ #else
UCHAR fillerC[1024-4]; /* 1kbytes minus 3 words */ #endif /* NFDC2048 */
volatile WordByte io[1024]; } ContComWin;
/* #defines for writing to ContComWin.eccConfig */ /* HOOK - added */ #define SET_ECC_CONFIG(win,val) tffsWriteByteFlash(&((win)->eccConfig.b), (UCHAR)(val))
#define CHK_ECC_ERROR(win) (tffsReadByteFlash(&((win)->eccConfig.b)) & (UCHAR)ECC_ERROR)
typedef ContComWin FAR0 * Interface;
#define DBL(x) ( (UCHAR)(x) * 0x101u )
#define SECOND_TRY 0x8000
#ifdef NFDC2048
/* Controller registers: Addresses & values */
#define ATTRIBUTE_MEM_START 0x8000000L /* Attribute memory starts at 128MB */
/* Controller configuration register */ #define CONFIG1 ATTRIBUTE_MEM_START + 0x3ffc
#define PWR_DN 0x01 /* Read / Write*/
#define PWR_DN2 0x02 /* Read / Write*/
#define STOP_CDSN 0x04 /* Read / Write*/
#define STOP_CDSNS 0x08 /* Read / Write*/
#define C_CDSN 0x10 /* Read / Write*/
#define R_CDSN 0x20 /* Read / Write*/
#define WP_C 0x40 /* Read / Write*/
#define WP_A 0x80 /* Read / Write*/
/* board's jumper settings*/ #define JUMPERS ATTRIBUTE_MEM_START + 0x3ffe
#define JMPER_INLV 0x08
#define JMPER_CDSNS 0x10
#define JMPER_EXT_CIS 0x20
#define JMPER_LDR_MASK 0x40
#define JMPER_MAX_MODE 0x80
/* PCMCIA register #0*/ #define CONFIG_OPTION ATTRIBUTE_MEM_START + 0x4000
#define CONFIGIDX 0x3F /* Read / Write*/
#define SREST 0x80 /* Read / Write*/
/* PCMCIA register #1*/ #define CARD_CONFIG ATTRIBUTE_MEM_START + 0x4002
#define PWRDWN 0x04 /* Read / Write*/
#else
#define INLV 2 /* Must define interleaving statically */
#endif /* NFDC2048 */
/* customization for this MTD*/ /*#define MULTI_ERASE */ /* use multiple block erase feature*/ #define USE_EDC /* use Error Detection /Correction Code */
/* #define VERIFY_AFTER_WRITE */
typedef struct { USHORT vendorID; USHORT chipID; USHORT pageSize ; /* all....................*/ USHORT pageMask ; /* ...these...............*/ USHORT pageAreaSize ; /* .......variables.......*/ USHORT tailSize ; /* .............interleave*/ USHORT noOfBlocks ; /* total erasable blocks in flash device*/ USHORT pagesPerBlock; /* number of pages per block */ FLBuffer *buffer; /* buffer for map through buffer */ } Vars;
Vars mtdVars_nfdc2048[SOCKETS];
#define thisVars ((Vars *) vol.mtdVars)
#define thisBuffer (thisVars->buffer->flData)
/*���������������������Ŀ
� Auxiliary methods � �����������������������*/
/*----------------------------------------------------------------------*/ /* t f f s c p y 1 6 */ /* */ /* Move data in 16-bit words. */ /* */ /* Parameters: */ /* dst : destination buffer */ /* src : source buffer */ /* len : bytes to move */ /* */ /*----------------------------------------------------------------------*/
VOID tffscpy16fromMedia (UCHAR FAR0 *dst, const UCHAR FAR0 *src, LONG len) { register LONG i; USHORT FAR0 *dstPtr = (USHORT FAR0 *) dst; const USHORT FAR0 *srcPtr = (USHORT FAR0 *) src;
/* move data in 16-bit words */ for (i = len; i > 0; i -= 2) *dstPtr++ = tffsReadWordFlash(srcPtr++); }
VOID tffscpy16toMedia (UCHAR FAR0 *dst, const UCHAR FAR0 *src, LONG len) { register LONG i; USHORT FAR0 *dstPtr = (USHORT FAR0 *) dst; const USHORT FAR0 *srcPtr = (USHORT FAR0 *) src;
/* move data in 16-bit words */ for (i = len; i > 0; i -= 2) tffsWriteWordFlash(dstPtr++,*srcPtr++); }
/*----------------------------------------------------------------------*/ /* t f f s s e t 1 6 */ /* */ /* Set data buffer in 16-bit words. */ /* */ /* Parameters: */ /* dst : destination buffer */ /* val : byte value tofill the buffer */ /* len : setination buffer size in bytes */ /* */ /*----------------------------------------------------------------------*/
VOID tffsset16 (UCHAR FAR0 *dst, UCHAR val, LONG len) { register USHORT wval = ((USHORT)val << 8) | val; register LONG i = 0; USHORT FAR0 *dstPtr;
/* set data in 16-bit words */ for (i = 0; i < len - 1; i += 2) { dstPtr = (USHORT FAR0 *)addToFarPointer(dst, i); tffsWriteWordFlash(dstPtr,wval); }
/* set last byte (if any) */ if (len & 1) { dstPtr = (USHORT FAR0 *)addToFarPointer(dst, len - 1); tffsWriteByteFlash(dstPtr,wval); } }
#ifdef NFDC2048
/*----------------------------------------------------------------------*/ /* r e a d S y n d r o m */ /* */ /* Read ECC syndrom and swap words to prepare it for writing to flash. */ /* */ /* Parameters: */ /* Interface : Pointer to window. */ /* to : buffer to read to. */ /* */ /*----------------------------------------------------------------------*/
VOID readSyndrom_nfdc2048( Interface interface, USHORT *to ) { to[0] = tffsReadWordFlash(&(interface->syndrom[2])); to[1] = tffsReadWordFlash(&(interface->syndrom[1])); to[2] = tffsReadWordFlash(&(interface->syndrom[0])); }
#ifdef USE_EDC
/*----------------------------------------------------------------------*/ /* r e a d S y n d r o m O n S y n d r o m */ /* */ /* Read ECC syndrom. */ /* */ /* Parameters: */ /* Interface : Pointer to window. */ /* to : buffer to read to. */ /* */ /*----------------------------------------------------------------------*/
VOID readSyndromOnSyndrom ( Interface interface, USHORT *to ) { to[0] = tffsReadWordFlash(&(interface->syndrom[0])); to[1] = tffsReadWordFlash(&(interface->syndrom[1])); to[2] = tffsReadWordFlash(&(interface->syndrom[2])); }
#endif /* USE_EDC */
/*���������������������������Ŀ
� Miscellaneous routines � �����������������������������*/
/*----------------------------------------------------------------------*/ /* g e t A t t R e g */ /* */ /* Get ASIC register residing in card's Attribute memory. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Address of register. */ /* */ /* Returns: */ /* Value of register. */ /* */ /*----------------------------------------------------------------------*/
UCHAR getAttReg(FLFlash vol, CardAddress reg) { return (UCHAR) (tffsReadByteFlash((USHORT FAR0 *) flMap(vol.socket,reg))); }
/*----------------------------------------------------------------------*/ /* s e t A t t R e g */ /* */ /* Set ASIC register residing in card's Attribute memory. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Address of register. */ /* value : Value to set */ /* */ /*----------------------------------------------------------------------*/
VOID setAttReg(FLFlash vol, CardAddress reg, UCHAR value) { tffsWriteWordFlash((USHORT FAR0 *) flMap(vol.socket,reg), DBL(value)); }
/*----------------------------------------------------------------------*/ /* p o w e r U p */ /* */ /* Power up the controller. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* */ /*----------------------------------------------------------------------*/
VOID powerUp(VOID *pVol) { flDelayMsecs(1); setAttReg ((FLFlash *) pVol, CONFIG1, WP_C); /* Power up the controller */ }
#endif /* NFDC2048 */
/*----------------------------------------------------------------------*/ /* m a p C o n t I n t e r f a c e */ /* */ /* Select flash device. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Address in flash. */ /* */ /* Returns: */ /* Pointer to the mapped window. */ /* */ /*----------------------------------------------------------------------*/
Interface mapContInterface(FLFlash vol, CardAddress address) { Interface interface = (Interface) flMap(vol.socket,(CardAddress)0); LEushort tmp;
toLE2(*((LEushort FAR0 *) &tmp), (USHORT)(address / (vol.chipSize * vol.interleaving)));
/* Select flash device with 16-bit write */ tffsWriteWordFlash(((USHORT FAR0 *) &interface->deviceSelector), *((USHORT *) &tmp));
return interface; }
/*----------------------------------------------------------------------*/ /* w a i t F o r R e a d y */ /* */ /* Wait for the selected device to be ready. */ /* */ /* Parameters: */ /* Interface : Pointer tot the window. */ /* */ /* Returns: */ /* TRUE if device is ready, FALSE if timeout error. */ /* */ /*----------------------------------------------------------------------*/
FLBoolean waitForReady_nfdc2048 (Interface interface) { LONG i;
for( i = 0; i < 20000; i++) { if( (~(tffsReadWordFlash(&(interface->signals.w))) & DBL(RB)) == 0) return TRUE ; /* ready at last..*/ flDelayMsecs(1); }
DEBUG_PRINT(("Debug: timeout error in NFDC 2048.\n"));
return FALSE; /* timeout error */ }
/*----------------------------------------------------------------------*/ /* m a k e C o m m a n d */ /* */ /* Set Page Pointer to Area A, B or C in page. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* cmd : receives command relevant to area */ /* addr : receives the address to the right area. */ /* modes : mode of operation (EXTRA ...) */ /* */ /*----------------------------------------------------------------------*/
VOID makeCommand_nfdc2048 (FLFlash vol, PointerOp *cmd, CardAddress *addr , LONG modes ) { USHORT offset;
if ( !(vol.flags & BIG_PAGE) ) { if (modes & EXTRA) { offset = (USHORT) (*addr & (SECTOR_SIZE - 1)); *cmd = AREA_C; if (vol.interleaving == 1) { if (offset < 8) /* First half of extra area */ *addr += 0x100; /* ... assigned to 2nd page */ else /* Second half of extra area */ *addr -= 8; /* ... assigned to 1st page */ } } else *cmd = AREA_A; } else { offset = (USHORT)(*addr) & thisVars->pageMask ; /* offset within device Page */
*addr -= offset; /* align at device Page*/
if (vol.interleaving == 2 && offset >= 512) offset += 16; /* leave room for 1st extra area */ if (modes & EXTRA) offset += SECTOR_SIZE;
if ( offset < thisVars->pageAreaSize ) /* starting in area A*/ *cmd = AREA_A ; else if ( offset < thisVars->pageSize ) /* starting in area B */ *cmd = AREA_B ; else /* got into area C*/ *cmd = AREA_C ;
offset &= (thisVars->pageAreaSize - 1) ; /* offset within area of device Page*/ *addr += offset ; } }
/*----------------------------------------------------------------------*/ /* c o m m a n d */ /* */ /* Latch command byte to selected flash device. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* Interface : Pointer to window. */ /* code : Command to set. */ /* */ /*----------------------------------------------------------------------*/
VOID command2048(FLFlash vol, Interface interface, UCHAR code) { tffsWriteWordFlash(&(interface->signals.w), DBL( CLE | NOT_WP | CE ));
if ( vol.interleaving == 1 ) { /* 8-bit */ tffsWriteByteFlash(&(interface->io[0].b), code); } else { /* 16-bit */ tffsWriteWordFlash(&(interface->io[0].w), DBL( code )); }
tffsWriteWordFlash(&(interface->signals.w), DBL( NOT_WP )); }
/*----------------------------------------------------------------------*/ /* s e t A d d r e s s */ /* */ /* Latch address to selected flash device. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* Interface : Pointer to window. */ /* address : address to set. */ /* */ /*----------------------------------------------------------------------*/
VOID setAddress2048(FLFlash vol, Interface interface, CardAddress address ) { address &= (vol.chipSize * vol.interleaving - 1) ; /* address within flash device*/ address /= vol.interleaving ; /* .................... chip */
if ( vol.flags & BIG_PAGE ) { /*
bits 0..7 stays as are bit 8 is thrown away from address bits 31..9 -> bits 30..8 */ address = ((address >> 9) << 8) | ((UCHAR)address) ; }
tffsWriteWordFlash(&(interface->signals.w), DBL(ALE | NOT_WP | CE));
/* send address to flash in the following sequence: */ /* bits 7...0 first */ /* bits 15...8 next */ /* bits 23..16 finally */ if ( vol.interleaving == 1 ) { tffsWriteByteFlash(&(interface->io[0].b), (UCHAR)address ); tffsWriteByteFlash(&(interface->io[0].b), (UCHAR)(address >> 8)); tffsWriteByteFlash(&(interface->io[0].b), (UCHAR)(address >> 16)); } else { tffsWriteWordFlash(&(interface->io[0].w), (USHORT)DBL(address)); tffsWriteWordFlash(&(interface->io[0].w), (USHORT)DBL(address >> 8)); tffsWriteWordFlash(&(interface->io[0].w), (USHORT)DBL(address >> 16)); }
tffsWriteWordFlash(&(interface->signals.w), DBL( NOT_WP | CE)); }
/*----------------------------------------------------------------------*/ /* r e a d C o m m a n d */ /* */ /* Issue read command. */ /* */ /* Parametes: */ /* vol : Pointer identifying drive */ /* Interface : Pointer to window. */ /* cmd : Command to issue (according to area). */ /* addr : address to read from. */ /* */ /*----------------------------------------------------------------------*/
VOID readCommand2048 (FLFlash vol, Interface interface, PointerOp cmd, CardAddress addr) { command2048 (&vol, interface, (UCHAR) cmd) ; /* move flash pointer to respective area of the page*/ setAddress2048 (&vol, interface, addr) ;
waitForReady_nfdc2048(interface) ; }
/*----------------------------------------------------------------------*/ /* w r i t e C o m m a n d */ /* */ /* Issue write command. */ /* */ /* Parametes: */ /* vol : Pointer identifying drive */ /* interface : Pointer to window. */ /* cmd : Command to issue (according to area). */ /* addr : address to write to. */ /* */ /*----------------------------------------------------------------------*/
VOID writeCommand2048 (FLFlash vol, Interface interface, PointerOp cmd, CardAddress addr) { if (vol.flags & FULL_PAGE) { command2048 (&vol, interface, RESET_FLASH); /* Clear page buffer */ waitForReady_nfdc2048(interface); } command2048 (&vol, interface, (UCHAR) cmd) ; /* move flash pointer to respective area of the page */ command2048 (&vol, interface, SERIAL_DATA_INPUT); /* start data loading for write */ setAddress2048 (&vol, interface, addr) ; }
/*----------------------------------------------------------------------*/ /* r e a d S t a t u s */ /* */ /* Read status of selected flash device. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* interface : Pointer to window. */ /* */ /* Returns: */ /* Chip status. */ /* */ /*----------------------------------------------------------------------*/
USHORT readStatus2048(FLFlash vol, Interface interface) { USHORT chipStatus ;
command2048(&vol, interface, READ_STATUS);
tffsWriteWordFlash(&(interface->signals.w), DBL( NOT_WP | CE ));
if ( vol.interleaving == 1 ) /* 8-bit*/ chipStatus = DBL(tffsReadByteFlash(&(interface->io[0].b))); else /* 16-bit */ chipStatus = tffsReadWordFlash(&(interface->io[0].w));
tffsWriteWordFlash(&(interface->signals.w), DBL( NOT_WP ));
return chipStatus; }
/*----------------------------------------------------------------------*/ /* w r i t e E x e c u t e */ /* */ /* Execute write. */ /* */ /* Parametes: */ /* vol : Pointer identifying drive */ /* interface : Pointer to window. */ /* Returns: */ /* FLStatus : 0 on success, otherwise failed. */ /* */ /*----------------------------------------------------------------------*/
FLStatus writeExecute2048 (FLFlash vol, Interface interface) { command2048 (&vol, interface, SETUP_WRITE); /* execute page program*/ if (!waitForReady_nfdc2048(interface)) { return flTimedOut; } if( readStatus2048(&vol, interface) & DBL(FAIL) ) return flWriteFault ;
return flOK ; }
/*----------------------------------------------------------------------*/ /* r e a d O n e S e c t o r */ /* */ /* Read up to one 512-byte block from flash. */ /* */ /* 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 readOneSector_nfdc2048 (FLFlash vol, CardAddress address, /* starting flash address*/ CHAR FAR1 *buffer, /* target buffer */ LONG length, /* bytes to read */ LONG modes) /* EDC flag etc.*/ { FLStatus status = flOK; PointerOp cmd; CardAddress addr = address ;
Interface interface = mapContInterface(&vol, address); /* select flash device */
/* move flash pointer to areas A,B or C of page*/
makeCommand_nfdc2048 (&vol, &cmd, &addr, modes) ;
readCommand2048 (&vol, interface, cmd, addr);
#ifdef NFDC2048
if(modes & EDC) { SET_ECC_CONFIG(interface, ECC_RST | ECC_EN); /*ECC reset and ON for read*/ } #endif /* NFDC2048 */
if ((vol.interleaving == 1) && !(vol.flags & BIG_PAGE) ) /* 8-bit */ { /* read up to two pages separately, starting page.. */
LONG toFirstPage, toSecondPage;
toFirstPage = (cmd == AREA_C ? 8 : 0x100) - ((USHORT)address & (cmd == AREA_C ? 7 : 0xff)); if (toFirstPage > length) toFirstPage = length; toSecondPage = length - toFirstPage ;
tffscpy16fromMedia ((UCHAR*)buffer, (const UCHAR FAR0 *) interface->io, toFirstPage ) ;
if ( toSecondPage > 0 ) { /* next page*/
readCommand2048 (&vol, interface, AREA_A, address + toFirstPage) ;
tffscpy16fromMedia( (UCHAR*)(buffer + toFirstPage), (const UCHAR FAR0 *) interface->io, toSecondPage ) ; } } else /* interleaving == 2 so 16-bit read*/ tffscpy16fromMedia( (UCHAR*)buffer, (const UCHAR FAR0 *) interface->io, length );
#ifdef NFDC2048
if( modes & EDC ) { UCHAR extraBytes[SYNDROM_BYTES]; /* read syndrom to let it through the ECC unit*/
SET_ECC_CONFIG(interface, ECC_EN | PAR_DIS); /* parity off in ECC*/
tffscpy16fromMedia( extraBytes, (const UCHAR FAR0 *) interface->io, SYNDROM_BYTES ) ;
if( CHK_ECC_ERROR(interface) ) /* ECC error*/ { if( (vol.interleaving == 1) && !(vol.flags & BIG_PAGE) ) { /* HOOK : make ECC working on 2M /INLV 1 */ } else { #ifdef USE_EDC
/* try to fix ECC error*/
if ( modes & SECOND_TRY ) /* 2nd try*/ { UCHAR syndrom[SYNDROM_BYTES];
/* read syndrom-on-syndrom from ASIC*/
readSyndromOnSyndrom(interface, (USHORT*)syndrom );
if (flCheckAndFixEDC(buffer, (CHAR FAR1 *)syndrom, vol.interleaving == 2) != NO_EDC_ERROR) { DEBUG_PRINT(("Debug: ECC error in NFDC 2048.\n")); status = flDataError; } } else /* 1st try - try once more*/ { SET_ECC_CONFIG(interface, PAR_DIS); /* reset ECC*/
return readOneSector_nfdc2048(&vol, address, buffer, length, modes | SECOND_TRY ) ; } #endif /* USE_EDC*/
} }
SET_ECC_CONFIG(interface, PAR_DIS); /* ECC off*/ } #endif /* NFDC2048 */
interface->signals.w = DBL(NOT_WP) ;
return status; }
/*----------------------------------------------------------------------*/ /* w r i t e O n e S e c t o r */ /* */ /* Write data in one 512-byte block to flash. */ /* Assuming that EDC mode never requested on partial block writes. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Address of sector to write to. */ /* buffer : buffer to write from. */ /* length : number of bytes to write (up to sector size). */ /* modes : OVERWRITE, EDC flags etc. */ /* */ /* Returns: */ /* FLStatus: 0 on success, otherwise failed. */ /* */ /*----------------------------------------------------------------------*/
FLStatus writeOneSector_nfdc2048(FLFlash vol, CardAddress address, /* target flash addres */ const CHAR FAR1 *buffer, /* source RAM buffer */ LONG length, /* bytes to write (up to BLOCK) */ LONG modes) /* OVERWRITE, EDC flags etc. */ { FLStatus status; PointerOp cmd;
Interface interface = mapContInterface(&vol, address); /* select flash device*/
if (flWriteProtected(vol.socket)) return flWriteProtect;
/* move flash pointer to areas A,B or C of page */
makeCommand_nfdc2048 (&vol, &cmd, &address, modes) ;
if ((vol.flags & FULL_PAGE) && cmd == AREA_B) { ULONG prePad = 2 + ((USHORT) address & thisVars->pageMask);
writeCommand2048(&vol, interface, AREA_A, address + thisVars->pageAreaSize - prePad); tffsset16( (UCHAR FAR0 *) interface->io, 0xff, prePad); } else writeCommand2048(&vol, interface, cmd, address);
#ifdef NFDC2048
if (modes & EDC) SET_ECC_CONFIG(interface, ECC_EN | ECC_RW); /* ECC ON for write*/ #endif
/* load data and syndrom*/
if( (vol.interleaving == 1) && !(vol.flags & BIG_PAGE) ) /* 8-bit*/ { LONG toFirstPage, toSecondPage ; /* write up to two pages separately*/
toFirstPage = (modes & EXTRA ? 8 : 0x100) - ((USHORT)address & (modes & EXTRA ? 7 : 0xff)); if (toFirstPage > length) toFirstPage = length; toSecondPage = length - toFirstPage ;
tffscpy16toMedia( (UCHAR FAR0 *) interface->io, /* user data */ (const UCHAR *)buffer, toFirstPage);
if ( toSecondPage > 0 ) { checkStatus( writeExecute2048(&vol, interface) ) ; /* done with 1st page */
writeCommand2048(&vol, interface, AREA_A, address + toFirstPage); /* user data*/ tffscpy16toMedia( (UCHAR FAR0 *) interface->io, (const UCHAR *)(buffer + toFirstPage), toSecondPage); } } else /* 16-bit*/ tffscpy16toMedia( (UCHAR FAR0 *) interface->io, /* user data*/ (const UCHAR *)buffer, length );
if(modes & EDC) { USHORT extraBytes[SYNDROM_BYTES / sizeof(USHORT) + 1]; /* Read the ECC syndrom*/
#ifdef NFDC2048
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP)); SET_ECC_CONFIG(interface, ECC_EN | PAR_DIS | ECC_RW); /* ECC parity off*/
readSyndrom_nfdc2048( interface, (USHORT*)extraBytes) ;
/* Write ECC syndrom and ANAND mark to the tail*/
SET_ECC_CONFIG(interface, PAR_DIS); /* ECC off*/ interface->signals.w = DBL(NOT_WP | CE); #else
extraBytes[0] = extraBytes[1] = extraBytes[2] = 0xffff; #endif /* NFDC2048 */
extraBytes[SYNDROM_BYTES / sizeof(USHORT)] = 0x5555; /* Anand mark */
tffscpy16toMedia((UCHAR FAR0 *) interface->io, (const UCHAR *)extraBytes, sizeof extraBytes); }
status = writeExecute2048(&vol, interface);
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP));
return status; }
/*��������������������������������������������Ŀ
� Core MTD methods - read, write and erase � ����������������������������������������������*/
/*----------------------------------------------------------------------*/ /* c d s n 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 cdsnRead( FLFlash vol, CardAddress address, /* target flash address */ VOID FAR1 *buffer, /* source RAM buffer */ dword length, /* bytes to write */ word modes) /* Overwrite, EDC flags etc. */ { CHAR FAR1 *temp; ULONG readNow;
/* read in sectors; first and last might be partial*/
ULONG block = modes & EXTRA ? 8 : SECTOR_SIZE;
readNow = block - ((USHORT)address & (block - 1)); temp = (CHAR FAR1 *)buffer; for ( ; length > 0 ; ) { if (readNow > length) readNow = length;
/* turn off EDC on partial block read*/ checkStatus( readOneSector_nfdc2048(&vol, address, temp, readNow, (readNow != SECTOR_SIZE ? (modes & ~EDC) : modes)) );
length -= readNow; address += readNow; temp += readNow;
/* align at sector */ readNow = block; }
return flOK ; }
/*----------------------------------------------------------------------*/ /* c d s n W r i t e */ /* */ /* Write some data to the flash. This routine will be registered as the */ /* write routine for this MTD. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Address of sector to write to. */ /* buffer : buffer to write from. */ /* length : number of bytes to write (up to sector size). */ /* modes : OVERWRITE, EDC flags etc. */ /* */ /* Returns: */ /* FLStatus: 0 on success, otherwise failed. */ /* */ /*----------------------------------------------------------------------*/
FLStatus cdsnWrite( FLFlash vol, CardAddress address, /* target flash address*/ const VOID FAR1 *buffer, /* source RAM buffer */ dword length, /* bytes to write */ word modes) /* Overwrite, EDC flags etc.*/ { ULONG writeNow; const CHAR FAR1 *temp; FLStatus status = flOK; #ifdef VERIFY_AFTER_WRITE
CardAddress saveAddress = address; USHORT flReadback[SECTOR_SIZE / sizeof(USHORT)]; #endif
/* write in sectors; first and last might be partial*/ LONG block = modes & EXTRA ? 8 : SECTOR_SIZE;
writeNow = block - ((USHORT)address & (block - 1)); temp = (const CHAR FAR1 *)buffer; for ( ; length > 0 ; ) { if (writeNow > length) writeNow = length;
/* turn off EDC on partial block write*/ status = writeOneSector_nfdc2048(&vol, address, temp, writeNow, writeNow != SECTOR_SIZE ? (modes & ~EDC) : modes);
if (status != flOK) break;
#ifdef VERIFY_AFTER_WRITE
status = readOneSector_nfdc2048 (&vol, address, (CHAR FAR1 *)flReadback, writeNow, (writeNow != SECTOR_SIZE ? (modes & ~EDC) : modes));
if((status != flOK) || (tffscmp(temp, flReadback, writeNow) != 0)) { status = flWriteFault; break; } #endif
length -= writeNow; address += writeNow; temp += writeNow;
/* align at sector */ writeNow = block; }
return flOK ; }
/*----------------------------------------------------------------------*/ /* c d s n E r a s e */ /* */ /* Erase number of blocks. This routine will be registered as the */ /* erase routine for this MTD. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* blockNo : First block to erase. */ /* blocksToErase : Number of blocks to erase. */ /* */ /* Returns: */ /* FLStatus : 0 on success, otherwise failed. */ /* */ /*----------------------------------------------------------------------*/
FLStatus cdsnErase( FLFlash vol, word blockNo, /* start' block (0 .. chipNoOfBlocks-1)*/ word blocksToErase) /* Number of blocks to be erased */ { LONG i; FLStatus status = flOK;
Interface interface = mapContInterface(&vol, (LONG)blockNo * vol.erasableBlockSize ) ; /* select device*/
if (flWriteProtected(vol.socket)) return flWriteProtect;
blockNo %= thisVars->noOfBlocks ; /* within flash device */
if ( blockNo + blocksToErase > thisVars->noOfBlocks ) /* accross device boundary */ return flBadParameter;
for ( i=0 ; i < blocksToErase ; i++, blockNo++ ) { USHORT pageNo = (USHORT) (blockNo * thisVars->pagesPerBlock);
command2048(&vol, interface, SETUP_ERASE);
tffsWriteWordFlash(&(interface->signals.w), DBL(ALE | NOT_WP | CE));
/* send 'pageNo' to the flash in the following sequence: */ /* bits 7..0 first */ /* bits 15..8 next */ if (vol.interleaving == 1) { tffsWriteByteFlash(&(interface->io[0].b),(UCHAR)pageNo); tffsWriteByteFlash(&(interface->io[0].b),(UCHAR)(pageNo >> 8)); } else { tffsWriteWordFlash(&(interface->io[0].w), DBL(pageNo)); tffsWriteWordFlash(&(interface->io[0].w), DBL(pageNo >> 8)); }
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP | CE));
/* if only one block may be erase at a time then do it
otherwise leave it for later*/
command2048(&vol, interface, CONFIRM_ERASE);
if (!waitForReady_nfdc2048(interface)) status = flTimedOut;
if ( readStatus2048(&vol, interface) & DBL(FAIL)) { /* erase operation failed*/ status = flWriteFault ; }
if (status != flOK) { /* reset flash device and abort */ DEBUG_PRINT(("Debug: erase failed in NFDC 2048.\n")); command2048(&vol, interface, RESET_FLASH ) ; waitForReady_nfdc2048(interface) ;
break ; } } /* block loop */
#ifdef MULTI_ERASE
/* do multiple block erase as was promised*/
command2048(&vol, interface, CONFIRM_ERASE); if (!waitForReady_nfdc2048(interface)) status = flTimedOut;
if ( readStatus2048(interface) & DBL(FAIL)) { /* erase operation failed*/ status = flWriteFault ; }
if (status != flOK) { /* reset flash device and abort*/ DEBUG_PRINT(("Debug: erase failed in NFDC 2048.\n")); command2048(&vol, interface, RESET_FLASH ) ; waitForReady_nfdc2048(interface) ; } #endif /* MULTI_ERASE*/
if(status == flOK) if ( readStatus2048(&vol, interface) & DBL(FAIL) ) { DEBUG_PRINT(("Debug: erase failed in NFDC 2048.\n")); status = flWriteFault; }
return status; }
/*----------------------------------------------------------------------*/ /* c d s n 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 * cdsnMap ( FLFlash vol, CardAddress address, int length ) { cdsnRead(&vol,address,thisBuffer,length, 0); vol.socket->remapped = TRUE; return (VOID FAR0 *)thisBuffer; }
#ifdef NFDC2048
/*----------------------------------------------------------------------*/ /* c d s n S e t C a l l b a c k */ /* */ /* Register a routine (powerUp()) for power on callback. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* */ /*----------------------------------------------------------------------*/
VOID cdsnSetCallback(FLFlash vol) { flSetPowerOnCallback(vol.socket, powerUp, &vol); } #endif /* NFDC2048 */
/*----------------------------------------------------------------------*/ /* i s K n o w n M e d i a */ /* */ /* Check if this flash media is supported. Initialize relevant fields */ /* in data structures. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* vendorId_P : vendor ID read from chip. */ /* chipId_p : chip ID read from chip. */ /* dev : dev chips were accessed before this one. */ /* */ /* Returns: */ /* TRUE if this media is supported, FALSE otherwise. */ /* */ /*----------------------------------------------------------------------*/
FLBoolean isKnownMedia_nfdc2048( FLFlash vol, USHORT vendorId_p, USHORT chipId_p, LONG dev ) { #ifdef NFDC2048
if ((chipId_p & 0xff00) == 0x6400) chipId_p = DBL(0x64); /* Workaround for TC5816/NFDC2048 problem */ #endif /* NFDC2048 */
if (dev == 0) { thisVars->vendorID = vendorId_p; /* remember for next chips */ thisVars->chipID = chipId_p; thisVars->pagesPerBlock = PAGES_PER_BLOCK;
if (vendorId_p == DBL(0xEC)) /* Samsung */ { switch (chipId_p) { case DBL(0x64): /* 2M */ case DBL(0xEA) : vol.type = KM29N16000_FLASH ; vol.chipSize = 0x200000L; return TRUE;
case DBL(0xE5): case DBL(0xE3): /* 4M */ vol.type = KM29N32000_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x400000L; return TRUE;
case DBL(0xE6): /* 8M */ vol.type = KM29V64000_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x800000L; return TRUE;
case DBL(0x73): /* 16 Mb */ vol.type = KM29V128000_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x1000000L; thisVars->pagesPerBlock *= 2; return TRUE;
case DBL(0x75): /* 32 Mb */ vol.type = KM29V256000_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x2000000L; thisVars->pagesPerBlock *= 2; return TRUE; } } else if (vendorId_p == DBL(0x8F)) /* National */ { switch (chipId_p) { case DBL(0x64): /* 2M */ vol.type = NM29N16_FLASH; vol.chipSize = 0x200000L; return TRUE; } } else if (vendorId_p == DBL(0x98)) /* Toshiba */ { vol.flags |= FULL_PAGE; /* no partial page programming */
switch (chipId_p) { case DBL(0x64): /* 2M */ case DBL(0xEA) : vol.type = TC5816_FLASH; vol.chipSize = 0x200000L; return TRUE;
case DBL(0x6B): /* 4M */ case DBL(0xE5): vol.type = TC5832_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x400000L; return TRUE;
case DBL(0xE6): /* 8M */ vol.type = TC5816_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x800000L; return TRUE;
case DBL(0x73): /* 16 Mb */ vol.type = TC58128_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x1000000L; thisVars->pagesPerBlock *= 2; return TRUE;
case DBL(0x75): /* 32 Mb */ vol.type = TC58256_FLASH; vol.flags |= BIG_PAGE; vol.chipSize = 0x2000000L; thisVars->pagesPerBlock *= 2; return TRUE; } } } else /* dev != 0*/ if( (vendorId_p == thisVars->vendorID) && (chipId_p == thisVars->chipID) ) return TRUE ;
return FALSE ; }
/*----------------------------------------------------------------------*/ /* r e a d F l a s h I D */ /* */ /* Read vendor and chip IDs, count flash devices. Initialize relevant */ /* fields in data structures. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* interface : Pointer to window. */ /* dev : dev chips were accessed before this one. */ /* */ /* Returns: */ /* TRUE if this media is supported, FALSE otherwise. */ /* */ /*----------------------------------------------------------------------*/
LONG readFlashID2048 (FLFlash vol, Interface interface, LONG dev) { USHORT vendorId_p, chipId_p ;
KeStallExecutionProcessor(250 * 1000); command2048(&vol, interface, RESET_FLASH ) ; flDelayMsecs(10); command2048(&vol, interface, READ_ID); tffsWriteWordFlash(&(interface->signals.w), DBL(ALE | NOT_WP | CE));
if (vol.interleaving == 1) { tffsWriteByteFlash(&(interface->io[0].b), 0); /* Read ID from*/ } else { /* address 0. */ tffsWriteWordFlash(&(interface->io[0].w), 0); }
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP | CE));
/* read vendor and chip IDs */
vendorId_p = (vol.interleaving == 1 ? DBL(tffsReadByteFlash(&(interface->io[0].b))) : tffsReadWordFlash(&(interface->io[0].w))) ; chipId_p = (vol.interleaving == 1 ? DBL(tffsReadByteFlash(&(interface->io[0].b))) : tffsReadWordFlash(&(interface->io[0].w)));
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP));
if ( isKnownMedia_nfdc2048(&vol, vendorId_p, chipId_p, dev) != TRUE ) /* no chip or diff.*/ return FALSE ; /* type of flash */
/* set flash parameters*/
if ( dev == 0 ) { thisVars->pageAreaSize = (USHORT) (0x100 * vol.interleaving); thisVars->pageSize = (USHORT) ((vol.flags & BIG_PAGE ? 0x200 : 0x100) * vol.interleaving); thisVars->tailSize = (USHORT) ((vol.flags & BIG_PAGE ? 16 : 8) * vol.interleaving); thisVars->pageMask = thisVars->pageSize - 1 ; vol.erasableBlockSize = thisVars->pagesPerBlock * thisVars->pageSize; thisVars->noOfBlocks = (USHORT)( (vol.chipSize * vol.interleaving) / vol.erasableBlockSize ) ; }
return TRUE ; }
/*----------------------------------------------------------------------*/ /* c d s n I d e n t i f y */ /* */ /* Identify flash. This routine will be registered as the */ /* identification routine for this MTD. */ /* */ /* Returns: */ /* FLStatus: 0 on success, otherwise failed. */ /* */ /*----------------------------------------------------------------------*/
FLStatus cdsnIdentify(FLFlash vol) { LONG addr = 0L ; Interface interface;
DEBUG_PRINT(("Debug: Entering NFDC 2048 identification routine\n"));
flDelayMsecs(10); /* wait for socket to power up */
flSetWindowBusWidth(vol.socket,16);/* use 16-bits */ flSetWindowSpeed(vol.socket,250); /* 250 nsec. */ flSetWindowSize(vol.socket,2); /* 4 KBytes */
vol.mtdVars = &mtdVars_nfdc2048[flSocketNoOf(vol.socket)]; /* get pointer to buffer (we assume SINGLE_BUFFER is not defined) */ thisVars->buffer = flBufferOf(flSocketNoOf(vol.socket));
/* detect card - identify bit toggles on consequitive reads*/
vol.chipSize = 0x200000L ; /* Assume something ... */ vol.interleaving = 1; /* unimportant for now */ interface = mapContInterface(&vol, 0); KeStallExecutionProcessor(250 * 1000);
if((tffsReadByteFlash(&(interface->eccConfig.b)) & TOGGLE) == (tffsReadByteFlash(&(interface->eccConfig.b)) & TOGGLE)) return flUnknownMedia;
/* read interleave from the card*/
#ifdef NFDC2048
vol.interleaving = ( (getAttReg(&vol, JUMPERS ) & JMPER_INLV) ? 1 : 2 );
powerUp((VOID *) &vol); interface = mapContInterface(&vol, 0); KeStallExecutionProcessor(250 * 1000);
if (vol.interleaving == 1) flSetWindowBusWidth(vol.socket, 8);
#else
vol.interleaving = INLV; #endif /* NFDC2048 */
/* reset all flash devices*/
tffsWriteWordFlash(&(interface->signals.w), DBL(NOT_WP));
/* identify and count flash chips, figure out flash parameters*/
for (vol.noOfChips = 0 ; vol.noOfChips < MAX_FLASH_DEVICES; vol.noOfChips += vol.interleaving, addr += vol.chipSize * vol.interleaving) { interface = mapContInterface(&vol, addr) ; if ( readFlashID2048(&vol, interface, vol.noOfChips) != TRUE ) /* no chip or different type of flash*/ break ; }
if ( vol.noOfChips == 0 ) /* no chips were found */ return flUnknownMedia;
/* ECC off*/
interface = mapContInterface(&vol, 0); KeStallExecutionProcessor(250 * 1000);
#ifdef NFDC2048
SET_ECC_CONFIG(interface, PAR_DIS); /* disable ECC and parity*/ setAttReg(&vol, CARD_CONFIG, PWRDWN); #endif /* NFDC2048 */
/* Register our flash handlers */ vol.write = cdsnWrite; vol.erase = cdsnErase; vol.read = cdsnRead; vol.map = cdsnMap; #ifdef NFDC2048
vol.setPowerOnCallback = cdsnSetCallback; #endif
vol.flags |= NFTL_ENABLED;
DEBUG_PRINT(("Debug: Identified NFDC 2048.\n"));
return flOK; }
/*----------------------------------------------------------------------*/ /* f l R e g i s t e r C D S N */ /* */ /* Registers this MTD for use */ /* */ /* Parameters: */ /* None */ /* */ /* Returns: */ /* FLStatus : 0 on success, otherwise failure */ /*----------------------------------------------------------------------*/
FLStatus flRegisterCDSN(VOID) { if (noOfMTDs >= MTDS) return flTooManyComponents;
mtdTable[noOfMTDs++] = cdsnIdentify;
return flOK; }
|