📄 cfiamd.c
字号:
/* cfiamd.c - MTD for AMD parts that comply with CFI */ /* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/* FAT-FTL Lite Software Development Kit * Copyright (C) M-Systems Ltd. 1995-2001 *//*modification history--------------------01l,24jun02,nrv fixing the condition where flashPtr[0x24] is checked twice01k,30apr02,nrv cleaned up the code by removing local var gif01j,09apr02,yp fixed SPR 75069. reworked write routines so status chek would work.01i,28mar02,nrv vol.mtdVars is dereferenced before the pointer is set in cfiAmdIdentify01h,12feb02,yp Written based on cfiscs.c*//*DESCRIPTIONThis library provides an MTD for devices that conform to the Common Flash Interface (CFI) and the AMD/Fujitsu command set. The library provides identification, erase and write routines for 8 and 16 bit devices in native or byte mode. Support is also added for word width devices interleaved word wide where bytes 0 and 1 would be on device one and bytes 2 and 3 would be on device two, and so on. Support is also present for configurations that only permit double word width writes.The identification process supports byte, word, and double word width devices as specified by the CFI query process. Vendr specific extentions are made available from an instance specific data structure, referred to in this file as thisCFI. In addition to supporting a boot code region through the format process thisdriver is also able to reserve the last erase block of each device in the arrayso the vxWorks may use this region as NVRAM if the macro SAVE_NVRAM_REGION is defined.The low voltage devices that support boot blocks get no special treatment in this driver. The asymmetric regions are regocgnized from the erase block regioninformation retreaved during CFI identification. They can, therefore be used by the the file system just like any other sector, if they are not used for boot purposes. Since TrueFFS does not support uneven sector distribution, the size of the largest sector is taken as the erase block size. When an erase request corresponds to the boot block region, all sectors in the boot block are erased.As such, the NVRAM area saved on a top boot device is the entire boot block and not just the last sector as one might expect.Based on the observation that CFI data on the sector distribution on AMD devicesalways describes bottom boot devices, this driver does an "autoselect" to determine the boot block type for proper interpretation of the device geometry data. The erase process assumes that bottom boot devices have the boot block located in sector zero. The first erase block encountered in an erase request that has a sector size other than vol.erasableBlockSize on top boot devices is assumed to be the boot block anchor on top boot devices.NOMANUAL*/#include <stdio.h>#include "tffs/flflash.h"#include "tffs/backgrnd.h"#define MAXSECTORS 128 /* should work with any value */typedef enum { BOOTBLOCK_NONE, BOOTBLOCK_TOP, BOOTBLOCK_BOTTOM }BOOTBLOCK;typedef union { UCHAR uchar[4]; UINT32 uint32; } CFI_DWORD;typedef union { UCHAR uchar[2]; USHORT ushort; } CFI_WORD; /* Instance specific CFI data so that a system may have more than one CFI * device. */typedef struct { unsigned commandSetId; /* id of a specific command set. */ unsigned altCommandSetId; /* id of alternate command set. */ FLBoolean wordMode; /* TRUE - word mode. */ /* FALSE - byte mode. */ int multiplier; /* the number of bytes between */ /* 1st Q and 1st R in query */ int interleaveWidth; /* 1 - byte 2 - word interleaved */ unsigned maxBytesWrite; /* maximum number of bytes */ /* in multi-byte write. */ FLBoolean vpp; /* if = TRUE, need vpp. */ long optionalCommands; /* optional commands supported */ /* (1 = yes, 0 = no): */ /* bit 0 - chip erase. */ /* bit 1 - suspend erase. */ /* bit 2 - suspend write */ /* bit 3 - lock/unlock. */ /* bit 4 - queued erase. */ unsigned afterSuspend; /* functions supported after */ /* suspend (1 = yes, 0 = no): */ /* bit 0 - write after erase */ /* suspend. */ int sectorDefs; /* Number of sector definitions */ struct { /* sector descriptions as found */ long secSize; /* in CFI query. */ int numSecs; /* */ }secDesc[8]; /* assume 8 is enough */ struct { /* */ long sectorSize; /* sector size */ UINT32 sectorBaseAdrs; /* base address of sector */ } secInfo[MAXSECTORS]; /* per sector info */ UINT32 unlockAddr1; /* offset for first unlock */ UINT32 unlockAddr2; /* offset for 2nd unlock */ int sectorsInCFI; /* sector count for device */ int bootBlockSectors; /* sectors that makeup boot block*/ BOOTBLOCK bootBlockType; /* Top, Bottom or None */ } CFI;LOCAL CFI mtdVars[DRIVES];/* defines *//* Save the last erase block on each device discovered in the array * for NVRAM */#define SAVE_NVRAM_REGION/* disable debugging */#undef CFI_DEBUG#ifdef CFI_DEBUG#define DEBUG_PRINT printf#else#undef DEBUG_PRINT#endif#ifndef _BYTE_ORDER#error "Error: _BYTE_ORDER needs to be #define'd. Try #include \"vxWorks.h\" "#endif#if (_BYTE_ORDER == _BIG_ENDIAN)#define CFI_LONGSWAP(x) LONGSWAP(x) /* swap everything in a long word */#define CFI_WORDSWAP(x) WORDSWAP(x) /* swap the shorts in a long */#define CFI_BYTESWAP(x) ( ( (x & 0xff) << 8) | ( (x >> 8) & 0xff) ) /* Swap bytes in a short */#else#define CFI_LONGSWAP(x) (x) /* pass it as is */#define CFI_WORDSWAP(x) (x) /* pass it as is */#define CFI_BYTESWAP(x) (x) /* pass it as is */#endif /* _BYTE_ORDER == _BIG_ENDIAN */#define CFI_LONG_WRITE(addr, data) (*(ULONG *)addr = (ULONG)(CFI_WORDSWAP(data)))#define CFI_WORD_WRITE(addr, data) (*(USHORT *)addr = (USHORT)(CFI_BYTESWAP(data)))#define CFI_WORD_READ(addr) (CFI_BYTESWAP(*(USHORT *)addr))#define CFI_LONG_READ(addr) (CFI_WORDSWAP(*(ULONG *)addr))/* command set IDs */#define INTEL_COMMAND_SET 0x0001#define AMDFUJ_COMMAND_SET 0x0002#define INTEL_ALT_COMMAND_SET 0x0001#define AMDFUJ_ALT_COMMAND_SET 0x0004#define ALT_NOT_SUPPORTED 0x0000/* CFI identification strings */#define ID_STR_LENGTH 3#define QUERY_ID_STR "QRY"#define PRIMARY_ID_STR "PRI"#define ALTERNATE_ID_STR "ALT"/* commands */#define AMD_SETUP_ERASE 0x80#define AMD_SETUP_WRITE 0xa0#define AMD_READ_ID 0x90#define AMD_SUSPEND_ERASE 0xb0#define AMD_SECTOR_ERASE 0x30#define AMD_RESUME_ERASE 0x30#define AMD_READ_ARRAY 0xf0#define AMD_NO_UNLOCK_ADDR 0xffffffffL#define AMD_UNLOCK_1 0xaa#define AMD_UNLOCK_2 0x55#define AMD_WW_UNLOCK_ADDR1 0x555u /* Word wide devices */#define AMD_WW_UNLOCK_ADDR2 0x2aau /* Word wide devices */#define AMD_BW_UNLOCK_ADDR1 0xaaau /* Byte wide devices */#define AMD_BW_UNLOCK_ADDR2 0x555u /* Byte wide devices */#define AMD_D2 4 /* Toggles when erase suspended */#define AMD_D5 0x20 /* Set when programming timeout */#define AMD_D6 0x40 /* Toggles when programming *//* optional commands support */#define CHIP_ERASE_SUPPORT 0x0001#define SUSPEND_ERASE_SUPPORT 0x0002#define SUSPEND_WRITE_SUPPORT 0x0004#define LOCK_SUPPORT 0x0008#define QUEUED_ERASE_SUPPORT 0x0010#define QUERY 0x98/* supported functions after suspend */#define WRITE_AFTER_SUSPEND_SUPPORT 0x0001#define thisCFI ((CFI *)vol.mtdVars)/* JEDEC IDs *//* 1.8 volt devices */#if 0/* Leaving out this one since it will complicate driver */#define Am39BDS643G_FLASH 0x017e /* top boot only 95 64KB, 4 16KB, 31 64KB, and 4 16KB sectors*/#endif #define Am29DS163DT_FLASH 0x0195 /* 8 8KB, and 31 64KB sectors */#define Am29DS163DB_FLASH 0x0196 /* 8 8KB, and 31 64KB sectors */#define Am29DS323DT_FLASH 0x01b7 /* 8 8KB, and 63 64KB sectors */#define Am29DS323DB_FLASH 0x01b8 /* 8 8KB, and 63 64KB sectors */#define Am29PDS322DT_FLASH 0x0101 /* 8 8KB, and 63 64KB sectors */#define Am29PDS322DB_FLASH 0x0100 /* 8 8KB, and 63 64KB sectors */#define Am29SL160CT_FLASH 0x01e4 /* 8 8KB, and 31 64KB sectors */#define Am29SL160CB_FLASH 0x01e7 /* 8 8KB, and 31 64KB sectors *//* 3.0 volt devices */#define Am29LV160BT_FLASH 0x01c4 /* 31 64KB, 1 32KB, 2 8KB, and 1 16KB sectors */#define Am29LV160BB_FLASH 0x0149 /* 1 16KB, 2 8KB, 1 32KB, and 31 64KB sectors */#define Am29DL161DT_FLASH 0x0136 /* 8 8KB, and 31 64KB sectors */#define Am29DL161DB_FLASH 0x0139 /* 8 8KB, and 31 64KB sectors */#define Am29DL162DT_FLASH 0x012d /* 8 8KB, and 31 64KB sectors */#define Am29DL162DB_FLASH 0x012e /* 8 8KB, and 31 64KB sectors */#define Am29DL163DT_FLASH 0x0128 /* 8 8KB, and 31 64KB sectors */#define Am29DL163DB_FLASH 0x012b /* 8 8KB, and 31 64KB sectors */#define Am29DL164DT_FLASH 0x0133 /* 8 8KB, and 31 64KB sectors */#define Am29DL164DB_FLASH 0x0135 /* 8 8KB, and 31 64KB sectors *//* The DL32xG series has the same JEDEC IDs and sector architecture */#define Am29LV320DT_FLASH 0x01f6 /* 8 8KB, and 63 64KB sectors */#define Am29LV320DB_FLASH 0x01f9 /* 8 8KB, and 63 64KB sectors */#define Am29DL322DT_FLASH 0x0155 /* 8 8KB, and 63 64KB sectors */#define Am29DL322DB_FLASH 0x0156 /* 8 8KB, and 63 64KB sectors */#define Am29DL323DT_FLASH 0x0150 /* 8 8KB, and 63 64KB sectors */#define Am29DL323DB_FLASH 0x0153 /* 8 8KB, and 63 64KB sectors */#define Am29DL324DT_FLASH 0x015c /* 8 8KB, and 63 64KB sectors */#define Am29DL324DB_FLASH 0x015f /* 8 8KB, and 63 64KB sectors */#define Am29LV017D_FLASH 0x01c8 /* 32 64KB sectors */#define Am29LV033C_FLASH 0x01a3 /* 64 64KB sectors */#define Am29LV065D_FLASH 0x0193 /* 128 64KB sectors */#define Am29LV116DT_FLASH 0x01c7 /* 31 64KB, 1 32KB, 2 8KB, and 1 16KB sectors */#define Am29LV116DB_FLASH 0x014c /* 1 16KB, 2 8KB, 1 32KB, and 31 64KB sectors */#define Am29LV640D_FLASH 0x01d7 /* 128 64KB sectors *//* left out PDL series because of the double CE# lines and left out PDL * series since they are quite impractical WRT TrueFFS. Should add support * for mirror bit devices as soon as data sheets become available. *//* 5.0 volt devices */#define Am29F016D_FLASH 0x01ad /* 32 64KB uniform sectors */#define Am29F017D_FLASH 0x013d /* 32 64KB uniform sectors */#define Am29F160DT_FLASH 0x01d2 /* 31 64KB, 1 32KB, 2 8KB, and 1 16KB sectors */#define Am29F160DB_FLASH 0x01d8 /* 1 16KB, 2 8KB, 1 32KB, and 31 64KB sectors */#define Fuj29LV160TE_FLASH 0x04c4 /* 31 64KB, 1 32KB, 2 8KB, and 1 16KB sectors */#define Fuj29LV160BE_FLASH 0x0449 /* 1 16KB, 2 8KB, 1 32KB, and 31 64KB sectors *//****************************************************************************** * cfiAmdChipCountGet - return the number of chips in this array * * Leave the first chip (or set of interleaved chips) in READ_ARRAY * mode and move forward by chip size (or interleaved chip size) until * address wrap around is detected. The chip count is updated in * vol.noOfChips. * * NOMANUAL * */LOCAL FLStatus cfiAmdChipCountGet ( FLFlash vol ) { UINT32 cmdBuffer; int ix; char queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR; FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0); /* Switch first (interleaved) chip set to QUERY mode */ cmdBuffer = 0x0; for (ix = 0; ix < thisCFI->multiplier; ix++) cmdBuffer |= QUERY << (8 * ix); flashPtr[0x55 * thisCFI->multiplier] = cmdBuffer; /* NOTE: The address wrap around technique used here works only if the flash * size was declared correctly in the socket driver. At some point the MTD * should be discovering flash size and exporting it to the socket driver. */ for (vol.noOfChips = 1 * vol.interleaving; /* Scan the chips */ vol.noOfChips < 2000; /* Big enough ? */ vol.noOfChips += vol.interleaving) {#ifdef SAVE_NVRAM_REGION /* Reinstate the NVRAM region */ flashPtr = (FlashPTR) flMap(vol.socket, vol.noOfChips * (vol.chipSize + (vol.erasableBlockSize / vol.interleaving)));#else flashPtr = (FlashPTR) flMap(vol.socket, vol.noOfChips * vol.chipSize);#endif#ifdef DEBUG_PRINT DEBUG_PRINT("Debug: Looking for Flash device at base 0x%x\n", (UINT32) flashPtr);#endif if ((flashPtr[0x10 * thisCFI->multiplier]) == (unsigned char)queryIdStr[0] && (flashPtr[0x11 * thisCFI->multiplier]) == (unsigned char)queryIdStr[1] && (flashPtr[0x12 * thisCFI->multiplier]) == (unsigned char)queryIdStr[2]) { goto noMoreChips; /* Wrapped around */ } /* Confirm this is also a CFI part */ *(UCHAR *)(flashPtr + (0x55 * thisCFI->multiplier)) = (UCHAR)(QUERY); if (flashPtr[0x10 * thisCFI->multiplier] != (unsigned char)queryIdStr[0] || flashPtr[0x11 * thisCFI->multiplier] != (unsigned char)queryIdStr[1] || flashPtr[0x12 * thisCFI->multiplier] != (unsigned char)queryIdStr[2]) { /* Should not happen !! */ goto noMoreChips; /* Not a CFI Flash part */ } flashPtr[0x55 * thisCFI->multiplier] = (UCHAR)(AMD_READ_ARRAY); } /* We should never get here. */#ifdef DEBUG_PRINT DEBUG_PRINT("Debug: Device count overflow\n");#endif /* DEBUG_PRINT */ return flGeneralFailure; noMoreChips: flashPtr = (FlashPTR) flMap(vol.socket, 0); /* Switch to READ_ARRAY mode */ cmdBuffer = 0x0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -