📄 cfiamd.c
字号:
/* 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 (iBlock = firstErasableBlock; (iBlock - firstErasableBlock) < thisCFI->bootBlockSectors; iBlock++) { int i; FLBoolean finished; FlashPTR flashPtr; /* No need to call mapBase because we know we are on * a unit boundary */ flashPtr = (FlashPTR) vol.map(&vol, thisCFI->secInfo[iBlock].sectorBaseAdrs, 0); *(UINT32 *)(flashPtr + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = unlock1; *(UINT32 *)(flashPtr + (thisCFI->unlockAddr2 * thisCFI->multiplier)) = unlock2; *(UINT32 *)(flashPtr + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = erase_setup; *(UINT32 *)(flashPtr + (thisCFI->unlockAddr1 * thisCFI->multiplier)) = unlock1; *(UINT32 *)(flashPtr + (thisCFI->unlockAddr2 * thisCFI->multiplier)) = unlock2; *(UINT32 *)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) { flashPtr[i] = AMD_READ_ARRAY;#ifdef DEBUG_PRINT DEBUG_PRINT("Debug: erase failed in AMD MTD.\n");#endif return flWriteFault; } finished = FALSE; } } } while (!finished); } return flOK; }/******************************************************************************* * cfiAmdErase - Erase one or more contiguous Flash erasable blocks * * This routine will be registered as the MTD vol.erase routine. Sector zero is * assumed to be the boot block anchor of the boot block on bottom boot devices, * while the first sector of size not equal to vol.erasableBlockSize is assumed * to be the anchor for top boot devices. * * 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 */LOCAL FLStatus cfiAmdErase ( FLFlash vol, int firstErasableBlock, int numOfErasableBlocks ) { 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; if ((thisCFI->bootBlockType == BOOTBLOCK_BOTTOM) && (firstErasableBlock == 0)) {#ifdef DEBUG_PRINT DEBUG_PRINT("Debug: Erasing bottom boot block\n");#endif cfiAmdBootBlockErase(&vol, 0); thisSector += thisCFI->bootBlockSectors; } /* 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; /* Check if we have hit a boot block region on a top * boot device. If so lets clean it up and move on with * the others */ if ((thisCFI->bootBlockType == BOOTBLOCK_TOP) && (thisCFI->secInfo[thisSector].sectorSize != vol.erasableBlockSize)) {#ifdef DEBUG_PRINT DEBUG_PRINT("Debug: Erasing top boot block\n");#endif cfiAmdBootBlockErase(&vol, thisSector); break; }#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)); *unlockAddr1 = unlock1; *unlockAddr2 = unlock2; *unlockAddr1 = erase_setup; *unlockAddr1 = unlock1; *unlockAddr2 = unlock2; *(UINT32 *)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; }/*************************************************************************** * 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. * * Parameters: * vol : Pointer identifying drive * * Returns: * FLStatus : 0 on positive identificaion, failed otherwise * * http://www.amd.com/us-en/FlashMemory/ProductInformation/0,,37_1447_1451_1780%5E1834%5E1955,00.html * * * NOMANUAL * */FLStatus cfiAmdIdentify ( FLFlash vol ) { FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0); FlashWPTR flashWPtr = (FlashWPTR) flashPtr; FlashDPTR flashDPtr = (FlashDPTR) flashPtr; UINT32 unlock1 = 0; UINT32 unlock2 = 0; UINT32 readID = 0; UINT32 readArray = 0; int i; 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");#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; } /* If we have a 16 bit device in 8 bit mode it should ID correctly */ 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' */ { thisCFI->multiplier = 2;#ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected a 16 bit device in 8 bit mode\n");#endif vol.interleaving =1; thisCFI->interleaveWidth = 1; eightBitMode = TRUE; goto getCFI; } /* Reset to READ_ARRAY and retry. Maybe 32 bit addressing */ flashWPtr[0x55] = (USHORT) ((AMD_READ_ARRAY << 8) | AMD_READ_ARRAY); flashDPtr[0x55] = (ULONG) (QUERY << 24| QUERY <<16 | QUERY << 8 | QUERY); /* A 32 bit device in 8 bit mode and two 16 bit deivec in 8 bit mode will * appear the same to the querry process. The only way to make the * distinction is to try and set one device back to read array mode while * the other remains in query mode */ if (flashPtr[0x40] == 0x51 && /* 'Q' */ flashPtr[0x41] == 0x51 && /* 'Q' */ flashPtr[0x42] == 0x51 && /* 'Q' */ flashPtr[0x43] == 0x51 && /* 'Q' */ flashPtr[0x44] == 0x52 && /* 'R' */ flashPtr[0x45] == 0x52 && /* 'R' */ flashPtr[0x46] == 0x52 && /* 'R' */ flashPtr[0x47] == 0x52 && /* 'R' */ flashPtr[0x48] == 0x59 && /* 'Y' */ flashPtr[0x49] == 0x59 && /* 'Y' */ flashPtr[0x4a] == 0x59 && /* 'Y' */ flashPtr[0x4b] == 0x59) /* 'Y' */ { /* See if we can turn one off */ flashPtr[0x154] = AMD_READ_ARRAY; if ((flashPtr[0x40] != 0x51) && (flashPtr[0x41] == 0x51)) { /* Turned one device off successfully */ flashPtr[0x154] = QUERY; /* turn it back on to querry mode */ vol.interleaving = 2;#ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected two 16 bit device, 8 bit interleaved(2)\n");#endif } else { vol.interleaving =1;#ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected a 32 bit device in 8 bit mode\n");#endif } thisCFI->multiplier = 4; thisCFI->interleaveWidth = 1; eightBitMode = TRUE; goto getCFI; } /* Is it a single 32 bit device */ if (flashDPtr[0x10] == 'Q' && flashDPtr[0x11] == 'R' && flashDPtr[0x12] == 'Y') {#ifdef DEBUG_PRINT DEBUG_PRINT ("Debug: detected a 32 bit device in 32 bit mode\n");#endif thisCFI->multiplier = 4; thisCFI->interleaveWidth = 1; vol.interleaving = 1; goto getCFI; } /* Two 16 bit devices in 16 bit mode */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -