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; }
FLStatus v28F128J3Identify ( FLFlash vol ) { UINT32 * base = (UINT32 *)vol.map(&vol, 0, 0); UINT32 vendor, device; #ifdef DEBUG_PRINT DEBUG_PRINT("Entering v28F128J3Identify routine @ base address 0x%08x ...\n", (UINT32)base); #endif /* check the flash id */ V28F128J3_READ_ID(base); vendor = *(base + V28F128J3_VENDOR_OFFSET); device = *(base + V28F128J3_DEVICE_OFFSET); if ((vendor == VENDOR_ID_INTERLEAVED) && (device == DEVICE_ID_INTERLEAVED)) vol.type = V28F128J3_FLASH_ID; else { V28F128J3_RESET(base); return flUnknownMedia; } vol.chipSize = V28F128J3_FLASH_SIZE; vol.noOfChips = V28F128J3_FLASH_NUM; vol.interleaving = V28F128J3_FLASH_NUM; vol.erasableBlockSize = V28F128J3_SECTOR_SIZE * vol.interleaving; vol.write = v28F128J3Write; vol.erase = v28F128J3Erase; V28F128J3_RESET(base); return flOK; }
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; }
LOCAL FLStatus v28F128J3Erase ( FLFlash vol, int firstErasableBlock, int numOfErasableBlocks ) { UINT32 * block = NULL; UINT32 status = V28F128J3_STATUS_READY; UINT32 timeout = 0; int i; if (flWriteProtected(vol.socket)) return flWriteProtect; for (i = firstErasableBlock; i < firstErasableBlock + numOfErasableBlocks; i++) { block = (UINT32 *)vol.map(&vol, i * vol.erasableBlockSize, 0); #ifdef DEBUG_PRINT DEBUG_PRINT("Erasing block#%03d @ 0x%08x ...\r", i, block); #endif /* set timeout = 5s */ timeout = flMsecCounter + V28F128J3_OP_TIMEOUT; V28F128J3_READ_STATUS(block); do { status = *block; if (flMsecCounter >= timeout) break; } while ((status & V28F128J3_STATUS_READY_MASK) != V28F128J3_STATUS_READY); if ((status & V28F128J3_STATUS_ERR_MASK) != 0) V28F128J3_CLEAR_STATUS(block); V28F128J3_ERASE_BLOCK(block); V28F128J3_ERASE_CONFIRM(block); /* set timeout = 5s */ timeout = flMsecCounter + V28F128J3_OP_TIMEOUT; do { status = *block; if (flMsecCounter >= timeout) { V28F128J3_RESET(block); return flTimedOut; } } while ((status & V28F128J3_STATUS_READY_MASK) != V28F128J3_STATUS_READY); /* check erase error bit */ if (status & V28F128J3_STATUS_ERA_ERR_MASK) { V28F128J3_RESET(block); return flWriteFault; } } V28F128J3_RESET(block); return flOK; }
LOCAL FLStatus v28F128J3Write ( FLFlash vol, CardAddress address, const void FAR1 *buffer, int length, int overwrite ) { UINT8 *unaligned; UINT8 *buf = (UINT8 *)buffer; UINT32 left = length; UINT32 *aligned; UINT32 data, num; int i; if (flWriteProtected(vol.socket)) return flWriteProtect; /* calculate the program addr, make sure it's 32-bit aligned */ unaligned = (UINT8 *)vol.map (&vol, address, 0); num = (UINT32)unaligned & 0x3; aligned = (UINT32 *)((UINT32)unaligned - num); if (num != 0) { data = *aligned; for (i = num ; i < 4; i++) { data &= ~(0xFF << ((3 - i) * 8)); data |= ((*(buf + i - num)) << ((3 - i) * 8)); } if (v28F128J3Program(aligned, data) != flOK) return flWriteFault; buf += (4 - num); left -= (4 - num); aligned++; } while (left >= 4) { data = *(UINT32 *)buf; if (v28F128J3Program (aligned, data) != flOK) return flWriteFault; buf += 4; left -= 4; aligned++; } if (left > 0) { data = *aligned; for (i = 0 ; i < left; i++) { data &= ~(0xFF << ((3 - i) * 8)); data |= ((*(buf + i)) << ((3 - i) * 8)); } if (v28F128J3Program (aligned, data) != flOK) return flWriteFault; } if (tffscmp((void FAR0 *)unaligned, buffer, length)) { #ifdef DEBUG_PRINT DEBUG_PRINT("[v28F128J3Write]: data double check error @ 0x%08x ...\n", unaligned); #endif return flWriteFault; } return flOK; }
LOCAL FLStatus cfiAmdErase ( FLFlash vol, /* Pointer identifying drive */ int firstErasableBlock, /* Number of first block to erase */ int numOfErasableBlocks /* Number of blocks to erase */ ) { int i; UINT32 unlock1 = 0; UINT32 unlock2 = 0; UINT32 erase_setup = 0; UINT32 erase_sector = 0; int thisSector = firstErasableBlock; int sectorsToErase = numOfErasableBlocks; UINT32 * unlockAddr1; UINT32 * unlockAddr2; if (flWriteProtected(vol.socket)) return flWriteProtect; /* Setup the commands first */ for (i = 0; i < thisCFI->multiplier; i++) { unlock1 |= AMD_UNLOCK_1 << (i * 8); unlock2 |= AMD_UNLOCK_2 << (i * 8); erase_setup |= AMD_SETUP_ERASE << (i * 8); erase_sector |= AMD_SECTOR_ERASE << (i * 8); } for ( ; thisSector < firstErasableBlock + sectorsToErase; thisSector++) { int i; FLBoolean finished; FlashPTR flashPtr; #ifdef DEBUG_PRINT DEBUG_PRINT("Clearing sector %d\n", thisSector); #endif /* we know we are on a unit boundary so mapBase is not necessary */ flashPtr = (FlashPTR) vol.map(&vol, thisCFI->secInfo[thisSector].sectorBaseAdrs, 0); unlockAddr1 = (UINT32 *)((long)flashPtr + (thisCFI->unlockAddr1 *thisCFI->multiplier)); unlockAddr2 = (UINT32 *)((long)flashPtr + (thisCFI->unlockAddr2 *thisCFI->multiplier)); *(UINT16 *)unlockAddr1 = unlock1; *(UINT16 *)unlockAddr2 = unlock2; *(UINT16 *)unlockAddr1 = erase_setup; *(UINT16 *)unlockAddr1 = unlock1; *(UINT16 *)unlockAddr2 = unlock2; *(UINT16 *)flashPtr = erase_sector; do { finished = TRUE; for (i = 0;i < thisCFI->multiplier;i += thisCFI->interleaveWidth) { if (flashPtr[i] != 0xff) { if ((flashPtr[i] & AMD_D5) && flashPtr[i] != 0xff) { int x; UINT32 c; for (x = 0, c = 0; x < thisCFI->multiplier; x++) c |= AMD_READ_ARRAY << (x * 8); flashPtr[i] = c; #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: erase failed in AMD MTD.\n"); #endif return flWriteFault; } finished = FALSE; } } } while (!finished); } return flOK; }
LOCAL FLStatus cfiAmdWrite ( FLFlash vol, /* Pointer identifying drive */ CardAddress address, /* Card address to write to */ const void FAR1 *buffer, /* Address of data to write */ int length, /* Number of bytes to write */ FLBoolean overwrite /* Mode: TRUE overwrite;FALSE erased */ ) { /* Set timeout to 5 seconds from now */ unsigned long writeTimeout = flMsecCounter + 5000; int cLength; CardAddress cAddr = address; FlashPTR base; FlashPTR flashPtr; UINT32 unlock1 = 0; UINT32 unlock2 = 0; UINT32 setup_write = 0; UINT32 read_array = 0; int i; CFI_WORD tmpWord; #define bFlashPtr flashPtr #define bBuffer ((const unsigned char FAR1 *) buffer) #define wFlashPtr ((FlashWPTR) flashPtr) #define wBuffer ((const unsigned short FAR1 *) buffer) #define dFlashPtr ((FlashDPTR) flashPtr) #define dBuffer ((const unsigned long FAR1 *) buffer) /* Setup the commands first */ for (i = 0; i < thisCFI->multiplier; i++) { unlock1 |= AMD_UNLOCK_1 << (i * 8); unlock2 |= AMD_UNLOCK_2 << (i * 8); setup_write |= AMD_SETUP_WRITE << (i * 8); read_array |= AMD_READ_ARRAY << (i * 8); } if (flWriteProtected(vol.socket)) return flWriteProtect; i = 0; while ((thisCFI->secInfo[i].sectorBaseAdrs <= address) && (i < thisCFI->sectorsInCFI)) i++; i--; base = (FlashPTR) vol.map(&vol, thisCFI->secInfo[i].sectorBaseAdrs, vol.interleaving * thisCFI->interleaveWidth); flashPtr = (FlashPTR) vol.map(&vol, address, vol.interleaving * thisCFI->interleaveWidth); cLength = length; if (vol.interleaving * thisCFI->interleaveWidth == 1) { while (cLength >= 2) { *(USHORT *)(base + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = unlock1; *(USHORT *)(base + (thisCFI->unlockAddr2 * thisCFI->multiplier)) = unlock2; *(USHORT *)(base + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = setup_write; *wFlashPtr = *wBuffer; while ((wFlashPtr[0] != wBuffer[0]) && (flMsecCounter < writeTimeout)) { if (((wFlashPtr[0] & AMD_D5) && ((wFlashPtr[0] ^ wBuffer[0]) & 0xff))) { wFlashPtr[0] = read_array; #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: write failed in AMD MTD.\n"); #endif return flWriteFault; } } cLength -= 2; cAddr += 2; buffer = (const void FAR1 *)((UINT32)buffer+2); flashPtr += 2; } if (cLength > 0) { /* copy data from flash to tmpWord */ tmpWord.ushort = wFlashPtr[0]; /* now fill in the left over byte */ tmpWord.uchar[0] = *(char *)buffer; *(USHORT *)(base + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = unlock1; *(USHORT *)(base + (thisCFI->unlockAddr2 * thisCFI->multiplier)) = unlock2; *(USHORT *)(base + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = setup_write; *wFlashPtr = tmpWord.ushort; while ((wFlashPtr[0] != tmpWord.ushort) && (flMsecCounter < writeTimeout)) { if (((wFlashPtr[0] & AMD_D5) && ((wFlashPtr[0] ^ tmpWord.ushort) & 0xff))) { wFlashPtr[0] = read_array; #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: write failed in AMD MTD.\n"); #endif return flWriteFault; } } cAddr += cLength; buffer = (const void FAR1 *)((UINT32)buffer + cLength); flashPtr = flashPtr + cLength; cLength = 0; } /* cfiAmdLeftoverBytesWrite(&vol, buffer, flashPtr, cLength); */ } flashPtr -= length; buffer = (unsigned char *)buffer - length; /* bBuffer -= length; */ if (tffscmp((void FAR0 *) flashPtr,buffer,length)) { #ifdef DEBUG_PRINT DEBUG_PRINT("Debug: write failed in AMD MTD on verification.\n"); #endif return flWriteFault; } return flOK; }