/* * $Log: V:/Flite/archives/TrueFFS5/Src/FLFLASH.C_V $ * * Rev 1.12 Apr 15 2002 07:36:38 oris * Bug fix - do not initialize access routines in case of user defined routines - as a result docsys must be included. * * Rev 1.11 Jan 28 2002 21:24:38 oris * Changed memWinowSize to memWindowSize. * * Rev 1.10 Jan 17 2002 23:09:30 oris * Added flFlashOf() routine to allow the use of a single FLFlash record per socket . * Added memory access routines initialization for FLFlash. * Bug fix - if M+ device was registered after 8-bit DiskOnChip and the M+ had a bad download problem , the error would not be reported, but only flUnknown media. * * Rev 1.9 Sep 15 2001 23:46:00 oris * Changed erase routine to support up to 64K erase blocks. * * Rev 1.8 Jul 13 2001 01:04:38 oris * Added new field initialization in FLFlash record - Max Erase Cycles of the flash. * * Rev 1.7 May 16 2001 21:18:24 oris * Removed warnings. * * Rev 1.6 May 02 2001 06:41:26 oris * Removed the lastUsableBlock variable. * * Rev 1.5 Apr 24 2001 17:07:52 oris * Bug fix - missing NULL initialization for several compilation flags. * Added lastUsableBlock field defualt initialization. * * Rev 1.4 Apr 16 2001 13:39:14 oris * Bug fix read and write default routines were not initialized. * Initialize the firstUsableBlock. * Removed warrnings. * * Rev 1.3 Apr 12 2001 06:50:22 oris * Added initialization of download routine pointer. * * Rev 1.2 Apr 09 2001 15:09:04 oris * End with an empty line. * * Rev 1.1 Apr 01 2001 07:54:08 oris * copywrite notice. * Changed prototype of :flashRead. * Removed interface b initialization (experimental MTD interface for mdocp). * Spelling mistake "changableProtectedAreas". * Added check for bad download in flash recognition. * * Rev 1.0 Feb 04 2001 11:21:16 oris * Initial revision. * */ /***********************************************************************************/ /* M-Systems Confidential */ /* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 */ /* All Rights Reserved */ /***********************************************************************************/ /* NOTICE OF M-SYSTEMS OEM */ /* SOFTWARE LICENSE AGREEMENT */ /* */ /* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE */ /* AGREEMENT BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT */ /* FOR THE SPECIFIC TERMS AND CONDITIONS OF USE, */ /* OR CONTACT M-SYSTEMS FOR LICENSE ASSISTANCE: */ /* E-MAIL = info@m-sys.com */ /***********************************************************************************/ #include "flflash.h" #include "docsys.h" #define READ_ID 0x90 #define INTEL_READ_ARRAY 0xff #define AMD_READ_ARRAY 0xf0 /* MTD registration information */ int noOfMTDs = 0; MTDidentifyRoutine mtdTable[MTDS]; static FLFlash vols[SOCKETS]; FLStatus dataErrorObject; /*----------------------------------------------------------------------*/ /* f l F l a s h O f */ /* */ /* Gets the flash connected to a volume no. */ /* */ /* Parameters: */ /* volNo : Volume no. for which to get flash */ /* */ /* Returns: */ /* flash of volume no. */ /*----------------------------------------------------------------------*/ FLFlash *flFlashOf(unsigned volNo) { return &vols[volNo]; } /*----------------------------------------------------------------------*/ /* f l a s h M a p */ /* */ /* Default flash map method: Map through socket window. */ /* This method is applicable for all NOR Flash */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Card address to map */ /* length : Length to map (irrelevant here) */ /* */ /* Returns: */ /* Pointer to required card address */ /*----------------------------------------------------------------------*/ static void FAR0 *flashMap(FLFlash vol, CardAddress address, int length) { return flMap(vol.socket,address); } /*----------------------------------------------------------------------*/ /* f l a s h R e a d */ /* */ /* Default flash read method: Read by copying from mapped address */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Card address to read */ /* buffer : Area to read into */ /* length : Length to read */ /* */ /*----------------------------------------------------------------------*/ static FLStatus flashRead(FLFlash vol, CardAddress address, void FAR1 *buffer, dword length, word mode) { tffscpy(buffer,vol.map(&vol,address,(word)length),(word)length); return flOK; } /*----------------------------------------------------------------------*/ /* f l a s h N o W r i t e */ /* */ /* Default flash write method: Write not allowed (read-only mode) */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* address : Card address to write */ /* buffer : Area to write from */ /* length : Length to write */ /* */ /* Returns: */ /* Write-protect error */ /*----------------------------------------------------------------------*/ static FLStatus flashNoWrite(FLFlash vol, CardAddress address, const void FAR1 *from, dword length, word mode) { return flWriteProtect; } /*----------------------------------------------------------------------*/ /* f l a s h N o E r a s e */ /* */ /* Default flash erase method: Erase not allowed (read-only mode) */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* firstBlock : No. of first erase block */ /* noOfBlocks : No. of contiguous blocks to erase */ /* */ /* Returns: */ /* Write-protect error */ /*----------------------------------------------------------------------*/ static FLStatus flashNoErase(FLFlash vol, word firstBlock, word noOfBlocks) { return flWriteProtect; } /*----------------------------------------------------------------------*/ /* s e t N o C a l l b a c k */ /* */ /* Register power on callback routine. Default: no routine is */ /* registered. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* */ /*----------------------------------------------------------------------*/ static void setNoCallback(FLFlash vol) { flSetPowerOnCallback(vol.socket,NULL,NULL); } /*----------------------------------------------------------------------*/ /* f l I n t e l I d e n t i f y */ /* */ /* Identify the Flash type and interleaving for Intel-style Flash. */ /* Sets the value of vol.type (JEDEC id) & vol.interleaving. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* amdCmdRoutine : Routine to read-id AMD/Fujitsu style at */ /* a specific location. If null, Intel procedure */ /* is used. */ /* idOffset : Chip offset to use for identification */ /* */ /* Returns: */ /* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/ /*----------------------------------------------------------------------*/ void flIntelIdentify(FLFlash vol, void (*amdCmdRoutine)(FLFlash vol, CardAddress, unsigned char, FlashPTR), CardAddress idOffset) { int inlv; unsigned char vendorId = 0; FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,idOffset); unsigned char firstByte = 0; unsigned char resetCmd = amdCmdRoutine ? AMD_READ_ARRAY : INTEL_READ_ARRAY; for (inlv = 0; inlv < 15; inlv++) { /* Increase interleaving until failure */ flashPtr[inlv] = resetCmd; /* Reset the chip */ flashPtr[inlv] = resetCmd; /* Once again for luck */ if (inlv == 0) firstByte = flashPtr[0]; /* Remember byte on 1st chip */ if (amdCmdRoutine) /* AMD: use unlock sequence */ amdCmdRoutine(&vol,idOffset + inlv, READ_ID, flashPtr); else flashPtr[inlv] = READ_ID; /* Read chip id */ if (inlv == 0) vendorId = flashPtr[0]; /* Assume first chip responded */ else if (flashPtr[inlv] != vendorId || firstByte != flashPtr[0]) { /* All chips should respond in the same way. We know interleaving = n */ /* when writing to chip n affects chip 0. */ /* Get full JEDEC id signature */ vol.type = (FlashType) ((vendorId << 8) | flashPtr[inlv]); flashPtr[inlv] = resetCmd; break; } flashPtr[inlv] = resetCmd; } if (inlv & (inlv - 1)) vol.type = NOT_FLASH; /* not a power of 2, no way ! */ else #ifndef NT5PORT vol.interleaving = inlv; #else vol.interleaving = (Sword)inlv; #endif /*NT5PORT*/ } /*----------------------------------------------------------------------*/ /* i n t e l S i z e */ /* */ /* Identify the card size for Intel-style Flash. */ /* Sets the value of vol.noOfChips. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* amdCmdRoutine : Routine to read-id AMD/Fujitsu style at */ /* a specific location. If null, Intel procedure */ /* is used. */ /* idOffset : Chip offset to use for identification */ /* */ /* Returns: */ /* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/ /*----------------------------------------------------------------------*/ FLStatus flIntelSize(FLFlash vol, void (*amdCmdRoutine)(FLFlash vol, CardAddress, unsigned char, FlashPTR), CardAddress idOffset) { unsigned char resetCmd = amdCmdRoutine ? AMD_READ_ARRAY : INTEL_READ_ARRAY; FlashPTR flashPtr = (FlashPTR) vol.map(&vol,idOffset,0); if (amdCmdRoutine) /* AMD: use unlock sequence */ amdCmdRoutine(&vol,0,READ_ID, flashPtr); else flashPtr[0] = READ_ID; /* We leave the first chip in Read ID mode, so that we can */ /* discover an address wraparound. */ for (vol.noOfChips = 0; /* Scan the chips */ vol.noOfChips < 2000; /* Big enough ? */ vol.noOfChips += vol.interleaving) { int i; flashPtr = (FlashPTR) vol.map(&vol,vol.noOfChips * vol.chipSize + idOffset,0); /* Check for address wraparound to the first chip */ if (vol.noOfChips > 0 && (FlashType) ((flashPtr[0] << 8) | flashPtr[vol.interleaving]) == vol.type) goto noMoreChips; /* wraparound */ /* Check if chip displays the same JEDEC id and interleaving */ for (i = (vol.noOfChips ? 0 : 1); i < vol.interleaving; i++) { if (amdCmdRoutine) /* AMD: use unlock sequence */ amdCmdRoutine(&vol,vol.noOfChips * vol.chipSize + idOffset + i, READ_ID, flashPtr); else flashPtr[i] = READ_ID; if ((FlashType) ((flashPtr[i] << 8) | flashPtr[i + vol.interleaving]) != vol.type) goto noMoreChips; /* This "chip" doesn't respond correctly, so we're done */ flashPtr[i] = resetCmd; } } noMoreChips: flashPtr = (FlashPTR) vol.map(&vol,idOffset,0); flashPtr[0] = resetCmd; /* reset the original chip */ return (vol.noOfChips == 0) ? flUnknownMedia : flOK; } /*----------------------------------------------------------------------*/ /* i s R A M */ /* */ /* Checks if the card memory behaves like RAM */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* */ /* Returns: */ /* 0 = not RAM-like, other = memory is apparently RAM */ /*----------------------------------------------------------------------*/ static FLBoolean isRAM(FLFlash vol) { #ifndef NT5PORT FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,0); unsigned char firstByte = flashPtr[0]; char writeChar = (firstByte != 0) ? 0 : 0xff; volatile int zero=0; #else FlashPTR flashPtr = (FlashPTR) flMap(vol.socket,0); unsigned char firstByte; char writeChar; volatile int zero=0; if(flashPtr == NULL){ DEBUG_PRINT(("Debug:isRAM(): NULL Pointer.\n")); } firstByte = flashPtr[0]; writeChar = (firstByte != 0) ? 0 : 0xff; #endif //NT5PORT flashPtr[zero] = writeChar; /* Write something different */ if (flashPtr[zero] == writeChar) { /* Was it written ? */ flashPtr[zero] = firstByte; /* must be RAM, undo the damage */ DEBUG_PRINT(("Debug: error, socket window looks like RAM.\r\n")); return TRUE; } return FALSE; } /*----------------------------------------------------------------------*/ /* f l I d e n t i f y F l a s h */ /* */ /* Identify the current Flash medium and select an MTD for it */ /* */ /* Parameters: */ /* socket : Socket of flash */ /* vol : New volume pointer */ /* */ /* Returns: */ /* FLStatus : 0 = Flash was identified */ /* other = identification failed */ /*----------------------------------------------------------------------*/ FLStatus flIdentifyFlash(FLSocket *socket, FLFlash vol) { FLStatus status = flUnknownMedia; int iMTD; dword blockSize; vol.socket = socket; #ifndef FIXED_MEDIA /* Check that we have a media */ flResetCardChanged(vol.socket); /* we're mounting anyway */ checkStatus(flMediaCheck(vol.socket)); #endif #ifdef ENVIRONMENT_VARS if(flUseisRAM==1) { #endif if ( isRAM(&vol)) return flUnknownMedia; /* if it looks like RAM, leave immediately */ #ifdef ENVIRONMENT_VARS } #endif /* Install default methods */ vol.type = NOT_FLASH; vol.mediaType = NOT_DOC_TYPE; vol.pageSize = 0; vol.flags = 0; vol.map = flashMap; vol.read = flashRead; vol.setPowerOnCallback = setNoCallback; vol.erase = flashNoErase; vol.write = flashNoWrite; vol.readBBT = NULL; vol.writeIPL = NULL; vol.readIPL = NULL; #ifdef HW_OTP vol.otpSize = NULL; vol.readOTP = NULL; vol.writeOTP = NULL; vol.getUniqueId = NULL; #endif /* HW_OTP */ #ifdef HW_PROTECTION vol.protectionBoundries = NULL; vol.protectionKeyInsert = NULL; vol.protectionKeyRemove = NULL; vol.protectionType = NULL; vol.protectionSet = NULL; #endif /* HW_PROTECTION */ vol.download = NULL; vol.enterDeepPowerDownMode = NULL; #ifndef FL_NO_USE_FUNC if(flBusConfig[flSocketNoOf(socket)] != FL_ACCESS_USER_DEFINED); { vol.memRead = NULL; vol.memWrite = NULL; vol.memSet = NULL; vol.memRead8bit = NULL; vol.memWrite8bit = NULL; vol.memRead16bit = NULL; vol.memWrite16bit = NULL; vol.memWindowSize = NULL; } #endif /* FL_NO_USE_FUNC */ /* Setup arbitrary parameters for read-only mount */ vol.chipSize = 0x100000L; vol.erasableBlockSize = 0x1000L; vol.noOfChips = 1; vol.interleaving = 1; vol.noOfFloors = 1; vol.totalProtectedAreas = 0; vol.changeableProtectedAreas = 0; vol.ppp = 5; vol.firstUsableBlock = 0; vol.maxEraseCycles = 100000L; /* Defaul for NOR */ #ifdef NT5PORT vol.readBufferSize = 0; vol.readBuffer = NULL; #endif /*NT5PORT*/ /* Attempt all MTD's */ for (iMTD = 0; (iMTD < noOfMTDs) && (status != flOK) && (status != flBadDownload); iMTD++) status = mtdTable[iMTD](&vol); if (status == flBadDownload) { DEBUG_PRINT(("Debug: Flash media reported bad download error.\r\n")); return flBadDownload; } if (status != flOK) /* No MTD recognition */ { DEBUG_PRINT(("Debug: did not identify flash media.\r\n")); return flUnknownMedia; } /* Calculate erasable Block Size Bits */ for(blockSize = vol.erasableBlockSize>>1,vol.erasableBlockSizeBits = 0; blockSize>0; vol.erasableBlockSizeBits++,blockSize = blockSize >> 1); return flOK; } #ifdef NT5PORT VOID * mapThroughBuffer(FLFlash vol, CardAddress address, LONG length) { if ((ULONG) length > vol.readBufferSize) { vol.readBufferSize = 0; if (vol.readBuffer) { FREE(vol.readBuffer); } vol.readBuffer = MALLOC(length); if (vol.readBuffer == NULL) { return vol.readBuffer; } vol.readBufferSize = length; } vol.read(&vol,address,vol.readBuffer,length,0); return vol.readBuffer; } #endif /* NT5PORT */