X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Flinux%2Fmtd%2Fcfi.h;h=123948b1454787401b63aefebb2dec1278f99a3f;hb=refs%2Fheads%2Fvserver;hp=a3efae0cd9a2df764c3d4277f850ce5b585ec12b;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index a3efae0cd..123948b14 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,14 +1,12 @@ -/* Common Flash Interface structures +/* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.45 2004/07/20 02:44:27 dwmw2 Exp $ + * $Id: cfi.h,v 1.57 2005/11/15 23:28:17 tpoynor Exp $ */ #ifndef __MTD_CFI_H__ #define __MTD_CFI_H__ -#include -#include #include #include #include @@ -82,8 +80,8 @@ static inline int cfi_interleave_supported(int i) } -/* NB: these values must represents the number of bytes needed to meet the - * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. +/* NB: these values must represents the number of bytes needed to meet the + * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. * These numbers are used in calculations. */ #define CFI_DEVICETYPE_X8 (8 / 8) @@ -145,6 +143,41 @@ struct cfi_pri_intelext { uint16_t ProtRegAddr; uint8_t FactProtRegSize; uint8_t UserProtRegSize; + uint8_t extra[0]; +} __attribute__((packed)); + +struct cfi_intelext_otpinfo { + uint32_t ProtRegAddr; + uint16_t FactGroups; + uint8_t FactProtRegSize; + uint16_t UserGroups; + uint8_t UserProtRegSize; +} __attribute__((packed)); + +struct cfi_intelext_blockinfo { + uint16_t NumIdentBlocks; + uint16_t BlockSize; + uint16_t MinBlockEraseCycles; + uint8_t BitsPerCell; + uint8_t BlockCap; +} __attribute__((packed)); + +struct cfi_intelext_regioninfo { + uint16_t NumIdentPartitions; + uint8_t NumOpAllowed; + uint8_t NumOpAllowedSimProgMode; + uint8_t NumOpAllowedSimEraMode; + uint8_t NumBlockTypes; + struct cfi_intelext_blockinfo BlockTypes[1]; +} __attribute__((packed)); + +struct cfi_intelext_programming_regioninfo { + uint8_t ProgRegShift; + uint8_t Reserved1; + uint8_t ControlValid; + uint8_t Reserved2; + uint8_t ControlInvalid; + uint8_t Reserved3; } __attribute__((packed)); /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ @@ -166,6 +199,18 @@ struct cfi_pri_amdstd { uint8_t TopBottom; } __attribute__((packed)); +/* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ + +struct cfi_pri_atmel { + uint8_t pri[3]; + uint8_t MajorVersion; + uint8_t MinorVersion; + uint8_t Features; + uint8_t BottomBoot; + uint8_t BurstMode; + uint8_t PageMode; +} __attribute__((packed)); + struct cfi_pri_query { uint8_t NumFields; uint32_t ProtField[1]; /* Not host ordered */ @@ -177,16 +222,19 @@ struct cfi_bri_query { uint32_t ConfField[1]; /* Not host ordered */ } __attribute__((packed)); -#define P_ID_NONE 0 -#define P_ID_INTEL_EXT 1 -#define P_ID_AMD_STD 2 -#define P_ID_INTEL_STD 3 -#define P_ID_AMD_EXT 4 -#define P_ID_ST_ADV 32 -#define P_ID_MITSUBISHI_STD 256 -#define P_ID_MITSUBISHI_EXT 257 -#define P_ID_SST_PAGE 258 -#define P_ID_RESERVED 65535 +#define P_ID_NONE 0x0000 +#define P_ID_INTEL_EXT 0x0001 +#define P_ID_AMD_STD 0x0002 +#define P_ID_INTEL_STD 0x0003 +#define P_ID_AMD_EXT 0x0004 +#define P_ID_WINBOND 0x0006 +#define P_ID_ST_ADV 0x0020 +#define P_ID_MITSUBISHI_STD 0x0100 +#define P_ID_MITSUBISHI_EXT 0x0101 +#define P_ID_SST_PAGE 0x0102 +#define P_ID_INTEL_PERFORMANCE 0x0200 +#define P_ID_INTEL_DATA 0x0210 +#define P_ID_RESERVED 0xffff #define CFI_MODE_CFI 1 @@ -221,16 +269,16 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int /* * Transforms the CFI command for the given geometry (bus width & interleave). * It looks too long to be inline, but in the common case it should almost all - * get optimised away. + * get optimised away. */ -static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) +static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) { map_word val = { {0} }; int wordwidth, words_per_bus, chip_mode, chips_per_word; unsigned long onecmd; int i; - /* We do it this way to give the compiler a fighting chance + /* We do it this way to give the compiler a fighting chance of optimising away all the crap for 'bankwidth' larger than an unsigned long, in the common case where that support is disabled */ @@ -241,7 +289,7 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf wordwidth = map_bankwidth(map); words_per_bus = 1; } - + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); @@ -260,7 +308,7 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf break; } - /* Now replicate it across the size of an unsigned long, or + /* Now replicate it across the size of an unsigned long, or just to the bus width as appropriate */ switch (chips_per_word) { default: BUG(); @@ -276,7 +324,7 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf ; } - /* And finally, for the multi-word case, replicate it + /* And finally, for the multi-word case, replicate it in all words in the structure */ for (i=0; i < words_per_bus; i++) { val.x[i] = onecmd; @@ -286,6 +334,69 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf } #define CMD(x) cfi_build_cmd((x), map, cfi) + +static inline unsigned long cfi_merge_status(map_word val, struct map_info *map, + struct cfi_private *cfi) +{ + int wordwidth, words_per_bus, chip_mode, chips_per_word; + unsigned long onestat, res = 0; + int i; + + /* We do it this way to give the compiler a fighting chance + of optimising away all the crap for 'bankwidth' larger than + an unsigned long, in the common case where that support is + disabled */ + if (map_bankwidth_is_large(map)) { + wordwidth = sizeof(unsigned long); + words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 + } else { + wordwidth = map_bankwidth(map); + words_per_bus = 1; + } + + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); + chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); + + onestat = val.x[0]; + /* Or all status words together */ + for (i=1; i < words_per_bus; i++) { + onestat |= val.x[i]; + } + + res = onestat; + switch(chips_per_word) { + default: BUG(); +#if BITS_PER_LONG >= 64 + case 8: + res |= (onestat >> (chip_mode * 32)); +#endif + case 4: + res |= (onestat >> (chip_mode * 16)); + case 2: + res |= (onestat >> (chip_mode * 8)); + case 1: + ; + } + + /* Last, determine what the bit-pattern should be for a single + device, according to chip mode and endianness... */ + switch (chip_mode) { + case 1: + break; + case 2: + res = cfi16_to_cpu(res); + break; + case 4: + res = cfi32_to_cpu(res); + break; + default: BUG(); + } + return res; +} + +#define MERGESTATUS(x) cfi_merge_status((x), map, cfi) + + /* * Sends a CFI command to a bank of flash for the given geometry. * @@ -326,41 +437,55 @@ static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr) } } -static inline void cfi_udelay(int us) +static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr) { - unsigned long t = us * HZ / 1000000; - if (t) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(t); - return; - } - udelay(us); - cond_resched(); -} + map_word val = map_read(map, addr); -static inline void cfi_spin_lock(spinlock_t *mutex) -{ - spin_lock_bh(mutex); + if (map_bankwidth_is_1(map)) { + return val.x[0] & 0xff; + } else if (map_bankwidth_is_2(map)) { + return cfi16_to_cpu(val.x[0]); + } else { + /* No point in a 64-bit byteswap since that would just be + swapping the responses from different chips, and we are + only interested in one chip (a representative sample) */ + return cfi32_to_cpu(val.x[0]); + } } -static inline void cfi_spin_unlock(spinlock_t *mutex) +static inline void cfi_udelay(int us) { - spin_unlock_bh(mutex); + if (us >= 1000) { + msleep((us+999)/1000); + } else { + udelay(us); + cond_resched(); + } } struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, const char* name); - struct cfi_fixup { uint16_t mfr; uint16_t id; - void (*fixup)(struct map_info *map, void* param); + void (*fixup)(struct mtd_info *mtd, void* param); void* param; }; #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff -void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups); +#define CFI_MFR_AMD 0x0001 +#define CFI_MFR_ATMEL 0x001F +#define CFI_MFR_ST 0x0020 /* STMicroelectronics */ + +void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); + +typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk); + +int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, + loff_t ofs, size_t len, void *thunk); + #endif /* __MTD_CFI_H__ */