/*************************************************************************** * cfiscsIdentify - Identification routine for devices conforming to CFI/SC * * Identifies media based on CFI and the AMD/Fujitsu command set and registers * as an MTD for such. This routine should be placed on the MTD list in * flcustom.h. It must be an extern routine. On successful identification, the * Flash structure is filled out and the write and erase routines registered. * * RETURNS: * FLStatus : 0 on positive identification, failed otherwise * * ERRNO * * http://www.amd.com/us-en/FlashMemory/ProductInformation/0,,37_1447_1451_1780%5E1834%5E1955,00.html * * \NOMANUAL */ FLStatus cfiAmdIdentify ( FLFlash vol /* Pointer identifying drive */ ) { FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0); FlashWPTR flashWPtr = (FlashWPTR) flashPtr; unsigned primaryTable, secondaryTable; FLBoolean eightBitMode = FALSE; int thisSector = 0; /* running count of sectors for this CFI */ CardAddress sectorBaseAdrs = 0; /* base address of this sector */ int ix = 0; #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: entering CFIAMD identification routine.\n"); DEBUG_PRINT("Debug: flash base addr = 0x%x\n", (UINT32)flashPtr); #endif flSetWindowBusWidth(vol.socket, 16);/* use 16-bits */ flSetWindowSpeed(vol.socket, 120); /* 120 nsec. */ flSetWindowSize(vol.socket, 2); /* 8 KBytes */ vol.mtdVars = &mtdVars[flSocketNoOf(vol.socket)]; thisCFI->bootBlockSectors = 0; /* Is this an 8 bit device */ flashPtr[0x55] = AMD_READ_ARRAY; flashPtr[0x55] = QUERY; if (flashPtr[0x10] == 0x51 && /* 'Q' */ flashPtr[0x11] == 0x52 && /* 'R' */ flashPtr[0x12] == 0x59) /* 'Y' */ { #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected single 8 bit device\n"); #endif thisCFI->multiplier = 1; thisCFI->interleaveWidth = 1; vol.interleaving = 1; eightBitMode = TRUE; goto getCFI; } /* Reset to READ_ARRAY and retry. Maybe 16 bit addressing */ flashPtr[0x55] = AMD_READ_ARRAY; flashWPtr[0x55] = (USHORT) ((QUERY << 8) | QUERY); /* Check for two interleaved 8 bit parts */ if (flashPtr[0x20] == 0x51 && /* 'Q' */ flashPtr[0x21] == 0x51 && /* 'Q' */ flashPtr[0x22] == 0x52 && /* 'R' */ flashPtr[0x23] == 0x52 && /* 'R' */ flashPtr[0x24] == 0x59 && /* 'Y' */ flashPtr[0x25] == 0x59) /* 'Y' */ { /* Let's try turning one off */ CFI_WORD_WRITE((FlashWPTR)(&flashPtr[0x55]), AMD_READ_ARRAY); if (flashPtr[0x20] != 0x51) /* Turned off successfully */ { thisCFI->multiplier = 2; thisCFI->interleaveWidth = 1; vol.interleaving =2; #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected two 8 bit devices\n"); #endif eightBitMode = TRUE; goto getCFI; } } /* a 16 bit device in 16 bit mode */ if (flashWPtr[0x10] == 'Q' && flashWPtr[0x11] == 'R' && flashWPtr[0x12] == 'Y') { thisCFI->multiplier = 2; thisCFI->interleaveWidth = 1; vol.interleaving = 1; #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected one 16 bit device\n"); #endif goto getCFI; } #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: No flash media detected!\n"); #endif return flUnknownMedia; getCFI: if (!eightBitMode) { thisCFI->wordMode = TRUE; /* limiting ourselves to 8 an 16 bit devs */ thisCFI->unlockAddr1 = AMD_WW_UNLOCK_ADDR1; thisCFI->unlockAddr2 = AMD_WW_UNLOCK_ADDR2; #ifdef DEBUG_PRINT DEBUG_PRINT("WORD MODE !!\n"); #endif } else { thisCFI->wordMode = FALSE; thisCFI->unlockAddr1 = AMD_BW_UNLOCK_ADDR1; thisCFI->unlockAddr2 = AMD_BW_UNLOCK_ADDR2; #ifdef DEBUG_PRINT DEBUG_PRINT("WORD MODE !!\n"); #endif } /* check the command set ID */ /* NOTE: Not swapped */ thisCFI->commandSetId = *(USHORT *)(&flashPtr[0x13 * thisCFI->multiplier]); #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: Commandset ID is 0x%x\n", thisCFI->commandSetId); #endif /* Only support the AMD/Fujitsu Command set */ if ( thisCFI->commandSetId != AMDFUJ_COMMAND_SET) { #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: did not recognize command set.\n"); #endif return flUnknownMedia; } /* get address for primary algorithm extended table. */ primaryTable = CFI_WORD_READ(&flashPtr[0x15 * thisCFI->multiplier]); /* check alternate command set ID. */ /* NOTE: not swapped */ thisCFI->altCommandSetId = *(USHORT *) (&flashPtr[0x17 * thisCFI->multiplier]); if (thisCFI->altCommandSetId != AMDFUJ_ALT_COMMAND_SET && thisCFI->altCommandSetId != ALT_NOT_SUPPORTED) return flUnknownMedia; /* get address for secondary algorithm extended table. */ secondaryTable = CFI_WORD_READ(&flashPtr[0x19 * thisCFI->multiplier]); thisCFI->vpp = flashPtr[0x1d * thisCFI->multiplier]; /*Get the number of erase block descriptions for the CFI*/ if (eightBitMode) thisCFI->sectorDefs = (int) (*(UCHAR *) (&flashPtr[0x2c * thisCFI->multiplier])); else thisCFI->sectorDefs = (int) (*(USHORT *) (&flashPtr[0x2c * thisCFI->multiplier])); /* We should bail out if this is greater than 8 */ #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: Number of erase block descriptions is 0x%x\n", thisCFI->sectorDefs); #endif vol.erasableBlockSize = 0; thisCFI->sectorsInCFI = 0; for ( ix = 0; ix < thisCFI->sectorDefs; ix++) { thisCFI->secDesc[ix].numSecs = (int) (*(USHORT *) (&flashPtr[(0x2d + (ix * 4)) * thisCFI->multiplier])); thisCFI->secDesc[ix].numSecs++; #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: Num sectors in %d - %d\n", ix, thisCFI->secDesc[ix].numSecs); #endif thisCFI->secDesc[ix].secSize = (long) ((*(USHORT *) (&flashPtr[(0x2f + (ix * 4)) * thisCFI->multiplier])) + (*(USHORT *)(&flashPtr[(0x30 + (ix * 4)) * thisCFI->multiplier])) * 0x100L); #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: Sector size is 0x%x\n", (UINT32) thisCFI->secDesc[ix].secSize); #endif /* TrueFFS does not support the flexible sector architecture so we * take the largest sector size to be the erase block size. */ if (vol.erasableBlockSize < thisCFI->secDesc[ix].secSize) vol.erasableBlockSize = thisCFI->secDesc[ix].secSize; /* Also track the number of sector on this device */ thisCFI->sectorsInCFI += thisCFI->secDesc[ix].numSecs; } if (vol.erasableBlockSize == 0x00) vol.erasableBlockSize = 0x80L; else vol.erasableBlockSize *= 256; /* Get Device Size */ if (eightBitMode) vol.chipSize = (1L << flashPtr[0x27 * thisCFI->multiplier]); else vol.chipSize = (1L << *(USHORT*)(&flashPtr[0x27 * thisCFI->multiplier])); vol.erasableBlockSize *= vol.interleaving; vol.chipSize -= CDS85XX_FLASH_RESERVED_SIZE; #ifdef SAVE_NVRAM_REGION /* Top boot block devices will loose their entire boot block to NVRAM. Since * TrueFFS cares not about the subdivisions we reserve an entire erase block * on each of the interleaved devices. */ vol.chipSize -= vol.erasableBlockSize; #endif #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: %d sectors on device\n", thisCFI->sectorsInCFI); DEBUG_PRINT("Debug: Erasable block size is 0x%lx\n", vol.erasableBlockSize); DEBUG_PRINT("Debug: Chip size is 0x%lx\n", vol.chipSize); #endif thisCFI->bootBlockType = BOOTBLOCK_NONE; /* Simplest case is the uniform sector device. Has only one * sector desc. */ for (; thisSector < thisCFI->secDesc[0].numSecs; thisSector++) { thisCFI->secInfo[thisSector].sectorSize = vol.erasableBlockSize; thisCFI->secInfo[thisSector].sectorBaseAdrs = sectorBaseAdrs; sectorBaseAdrs += (CardAddress) vol.erasableBlockSize; } #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: Number of boot block sectors is %d\n", thisCFI->bootBlockSectors); #endif /* Make sure this comes at the end since the device is set to READ_ARRAY * mode prior to the return */ if (cfiAmdChipCountGet(&vol) != flOK) return flUnknownMedia; #ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: No of chips detected is %d\n", vol.noOfChips); #if 0 for (ix = 0; ix < thisCFI->sectorsInCFI; ix++) DEBUG_PRINT ("%2d:0x%x --- 0x%lx\n", ix, thisCFI->secInfo[ix].sectorBaseAdrs, thisCFI->secInfo[ix].sectorSize); #endif #endif vol.erase = cfiAmdErase; vol.write = cfiAmdWrite; /* Might have to do this on a bus width basis but for now it seems to * work with Intel devices. */ flashPtr[0] = AMD_READ_ARRAY; flashPtr[1] = AMD_READ_ARRAY; flashPtr[2] = AMD_READ_ARRAY; flashPtr[3] = AMD_READ_ARRAY; return flOK; }
FLStatus check43Format(FLFlash *flash) { FLStatus status; byte FAR1* buf; /* If this is an alon */ if (flash->mediaType != DOC2000TSOP_TYPE) return flOK; buf = (flBufferOf(flSocketNoOf(flash->socket))->flData); if(flash->readBBT == NULL) { DFORMAT_PRINT(("ERROR : MTD read BBT routine was not initialized\r\n")); return flFeatureNotSupported; } status = flash->readBBT(flash,0,1,0,buf,FALSE); if (status == flBadBBT) { dword mediaSize = ((dword)flash->noOfChips*flash->chipSize); dword blockSize = 1<<flash->erasableBlockSizeBits; dword addr = 0; dword offset; word mediaHeaderBlock; /* ANAND unit number */ byte blocksPerUnit; /* Blocks per virtual unit */ byte blockShift; /* Bits to shift from block to unit */ CHECK_UNIT_WITH_ANAND: /* Either virgin or formated wih TrueFFS 4.3 */ for( ; addr < mediaSize ; addr += blockSize) { checkStatus(flash->read(flash,addr,buf,5,0)); if(tffscmp(buf,"ANAND",5) == 0) break; } if (addr == mediaSize) /* virgin card */ return flOK; DFORMAT_PRINT(("This DiskOnChip was formated with an NFTL format.\r\n")); /* Calculate block multiplier bits */ for (offset = addr + SECTOR_SIZE , status = flOK; (offset < addr + blockSize) && (status == flOK) ; offset += SECTOR_SIZE) { status = flash->read(flash,addr+offset,buf,512,EDC); } if(offset == addr + (SECTOR_SIZE<<1)) /* Bad EDC for NFTL unit header */ { DFORMAT_PRINT(("ERROR - Unit with ANAND was found, but the BBT has bad EDC.\r\n")); addr += blockSize; goto CHECK_UNIT_WITH_ANAND; /* Keep searching */ } offset = (offset - addr - (SECTOR_SIZE<<1)) << flash->erasableBlockSizeBits; for(blockShift = 0 ; offset < mediaSize ; blockShift++) { offset <<= 1; } blocksPerUnit = 1 << blockShift; mediaHeaderBlock = (word)(addr >> (flash->erasableBlockSizeBits + blockShift)); DFORMAT_PRINT(("Please wait while unformating is in progress...\r\n")); /* Read and write 512 blocks of the BBT (start from the end) */ for (offset = 0; offset < mediaSize>>(flash->erasableBlockSizeBits + blockShift); offset += SECTOR_SIZE) { word i; checkStatus(flash->read(flash,addr+offset+SECTOR_SIZE,buf,SECTOR_SIZE,EDC)); for(i=0;i<SECTOR_SIZE;i++) { if (i+offset == mediaHeaderBlock) continue; if (buf[i]==BBT_BAD_UNIT) /* A bad block */ { markUnitBad(flash , i+offset); } else /* A good block */ { status = flash->erase(flash,(word)(i+offset),blocksPerUnit); if (status != flOK) markUnitBad(flash , i+offset); } } } status = flash->erase(flash,mediaHeaderBlock,blocksPerUnit); if (status != flOK) markUnitBad(flash , mediaHeaderBlock); DFORMAT_PRINT(("Unformating of DiskOnChip 2000 tsop complete.\r\n")); }
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 !defined(FL_IDE_DOC) && !defined(FL_IDE_MDOCP) if ( isRAM(&vol)) return flUnknownMedia; /* if it looks like RAM, leave immediately */ #endif /* !FL_IDE_DOC && !FL_IDE_MDOCP */ #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; vol.memSetGetMode = 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 */ /* 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; }