]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | |
61ecfa87 | 2 | /* Common Flash Interface structures |
1da177e4 | 3 | * See http://support.intel.com/design/flash/technote/index.htm |
1da177e4 LT |
4 | */ |
5 | ||
6 | #ifndef __MTD_CFI_H__ | |
7 | #define __MTD_CFI_H__ | |
8 | ||
1da177e4 LT |
9 | #include <linux/delay.h> |
10 | #include <linux/types.h> | |
11 | #include <linux/interrupt.h> | |
12 | #include <linux/mtd/flashchip.h> | |
13 | #include <linux/mtd/map.h> | |
14 | #include <linux/mtd/cfi_endian.h> | |
2e489e07 | 15 | #include <linux/mtd/xip.h> |
1da177e4 LT |
16 | |
17 | #ifdef CONFIG_MTD_CFI_I1 | |
18 | #define cfi_interleave(cfi) 1 | |
19 | #define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1) | |
20 | #else | |
21 | #define cfi_interleave_is_1(cfi) (0) | |
22 | #endif | |
23 | ||
24 | #ifdef CONFIG_MTD_CFI_I2 | |
25 | # ifdef cfi_interleave | |
26 | # undef cfi_interleave | |
27 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
28 | # else | |
29 | # define cfi_interleave(cfi) 2 | |
30 | # endif | |
31 | #define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2) | |
32 | #else | |
33 | #define cfi_interleave_is_2(cfi) (0) | |
34 | #endif | |
35 | ||
36 | #ifdef CONFIG_MTD_CFI_I4 | |
37 | # ifdef cfi_interleave | |
38 | # undef cfi_interleave | |
39 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
40 | # else | |
41 | # define cfi_interleave(cfi) 4 | |
42 | # endif | |
43 | #define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4) | |
44 | #else | |
45 | #define cfi_interleave_is_4(cfi) (0) | |
46 | #endif | |
47 | ||
48 | #ifdef CONFIG_MTD_CFI_I8 | |
49 | # ifdef cfi_interleave | |
50 | # undef cfi_interleave | |
51 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
52 | # else | |
53 | # define cfi_interleave(cfi) 8 | |
54 | # endif | |
55 | #define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8) | |
56 | #else | |
57 | #define cfi_interleave_is_8(cfi) (0) | |
58 | #endif | |
59 | ||
241651d0 DW |
60 | #ifndef cfi_interleave |
61 | #warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work. | |
62 | static inline int cfi_interleave(void *cfi) | |
63 | { | |
64 | BUG(); | |
65 | return 0; | |
66 | } | |
67 | #endif | |
68 | ||
1da177e4 LT |
69 | static inline int cfi_interleave_supported(int i) |
70 | { | |
71 | switch (i) { | |
72 | #ifdef CONFIG_MTD_CFI_I1 | |
73 | case 1: | |
74 | #endif | |
75 | #ifdef CONFIG_MTD_CFI_I2 | |
76 | case 2: | |
77 | #endif | |
78 | #ifdef CONFIG_MTD_CFI_I4 | |
79 | case 4: | |
80 | #endif | |
81 | #ifdef CONFIG_MTD_CFI_I8 | |
82 | case 8: | |
83 | #endif | |
84 | return 1; | |
85 | ||
86 | default: | |
87 | return 0; | |
88 | } | |
89 | } | |
90 | ||
91 | ||
61ecfa87 TG |
92 | /* NB: these values must represents the number of bytes needed to meet the |
93 | * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. | |
1da177e4 LT |
94 | * These numbers are used in calculations. |
95 | */ | |
96 | #define CFI_DEVICETYPE_X8 (8 / 8) | |
97 | #define CFI_DEVICETYPE_X16 (16 / 8) | |
98 | #define CFI_DEVICETYPE_X32 (32 / 8) | |
99 | #define CFI_DEVICETYPE_X64 (64 / 8) | |
100 | ||
de7921f0 BS |
101 | |
102 | /* Device Interface Code Assignments from the "Common Flash Memory Interface | |
103 | * Publication 100" dated December 1, 2001. | |
104 | */ | |
105 | #define CFI_INTERFACE_X8_ASYNC 0x0000 | |
106 | #define CFI_INTERFACE_X16_ASYNC 0x0001 | |
107 | #define CFI_INTERFACE_X8_BY_X16_ASYNC 0x0002 | |
108 | #define CFI_INTERFACE_X32_ASYNC 0x0003 | |
109 | #define CFI_INTERFACE_X16_BY_X32_ASYNC 0x0005 | |
110 | #define CFI_INTERFACE_NOT_ALLOWED 0xffff | |
111 | ||
112 | ||
1da177e4 LT |
113 | /* NB: We keep these structures in memory in HOST byteorder, except |
114 | * where individually noted. | |
115 | */ | |
116 | ||
117 | /* Basic Query Structure */ | |
118 | struct cfi_ident { | |
119 | uint8_t qry[3]; | |
120 | uint16_t P_ID; | |
121 | uint16_t P_ADR; | |
122 | uint16_t A_ID; | |
123 | uint16_t A_ADR; | |
124 | uint8_t VccMin; | |
125 | uint8_t VccMax; | |
126 | uint8_t VppMin; | |
127 | uint8_t VppMax; | |
128 | uint8_t WordWriteTimeoutTyp; | |
129 | uint8_t BufWriteTimeoutTyp; | |
130 | uint8_t BlockEraseTimeoutTyp; | |
131 | uint8_t ChipEraseTimeoutTyp; | |
132 | uint8_t WordWriteTimeoutMax; | |
133 | uint8_t BufWriteTimeoutMax; | |
134 | uint8_t BlockEraseTimeoutMax; | |
135 | uint8_t ChipEraseTimeoutMax; | |
136 | uint8_t DevSize; | |
137 | uint16_t InterfaceDesc; | |
138 | uint16_t MaxBufWriteSize; | |
139 | uint8_t NumEraseRegions; | |
140 | uint32_t EraseRegionInfo[0]; /* Not host ordered */ | |
141 | } __attribute__((packed)); | |
142 | ||
143 | /* Extended Query Structure for both PRI and ALT */ | |
144 | ||
145 | struct cfi_extquery { | |
146 | uint8_t pri[3]; | |
147 | uint8_t MajorVersion; | |
148 | uint8_t MinorVersion; | |
149 | } __attribute__((packed)); | |
150 | ||
151 | /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ | |
152 | ||
153 | struct cfi_pri_intelext { | |
154 | uint8_t pri[3]; | |
155 | uint8_t MajorVersion; | |
156 | uint8_t MinorVersion; | |
157 | uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature | |
158 | block follows - FIXME - not currently supported */ | |
159 | uint8_t SuspendCmdSupport; | |
160 | uint16_t BlkStatusRegMask; | |
161 | uint8_t VccOptimal; | |
162 | uint8_t VppOptimal; | |
163 | uint8_t NumProtectionFields; | |
164 | uint16_t ProtRegAddr; | |
165 | uint8_t FactProtRegSize; | |
166 | uint8_t UserProtRegSize; | |
167 | uint8_t extra[0]; | |
168 | } __attribute__((packed)); | |
169 | ||
72b56a2d NP |
170 | struct cfi_intelext_otpinfo { |
171 | uint32_t ProtRegAddr; | |
172 | uint16_t FactGroups; | |
173 | uint8_t FactProtRegSize; | |
174 | uint16_t UserGroups; | |
175 | uint8_t UserProtRegSize; | |
176 | } __attribute__((packed)); | |
177 | ||
1da177e4 LT |
178 | struct cfi_intelext_blockinfo { |
179 | uint16_t NumIdentBlocks; | |
180 | uint16_t BlockSize; | |
181 | uint16_t MinBlockEraseCycles; | |
182 | uint8_t BitsPerCell; | |
183 | uint8_t BlockCap; | |
184 | } __attribute__((packed)); | |
185 | ||
186 | struct cfi_intelext_regioninfo { | |
187 | uint16_t NumIdentPartitions; | |
188 | uint8_t NumOpAllowed; | |
189 | uint8_t NumOpAllowedSimProgMode; | |
190 | uint8_t NumOpAllowedSimEraMode; | |
191 | uint8_t NumBlockTypes; | |
192 | struct cfi_intelext_blockinfo BlockTypes[1]; | |
193 | } __attribute__((packed)); | |
194 | ||
638d9838 NP |
195 | struct cfi_intelext_programming_regioninfo { |
196 | uint8_t ProgRegShift; | |
197 | uint8_t Reserved1; | |
198 | uint8_t ControlValid; | |
199 | uint8_t Reserved2; | |
200 | uint8_t ControlInvalid; | |
201 | uint8_t Reserved3; | |
202 | } __attribute__((packed)); | |
203 | ||
1da177e4 LT |
204 | /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ |
205 | ||
206 | struct cfi_pri_amdstd { | |
207 | uint8_t pri[3]; | |
208 | uint8_t MajorVersion; | |
209 | uint8_t MinorVersion; | |
210 | uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ | |
211 | uint8_t EraseSuspend; | |
212 | uint8_t BlkProt; | |
213 | uint8_t TmpBlkUnprotect; | |
214 | uint8_t BlkProtUnprot; | |
215 | uint8_t SimultaneousOps; | |
216 | uint8_t BurstMode; | |
217 | uint8_t PageMode; | |
218 | uint8_t VppMin; | |
219 | uint8_t VppMax; | |
220 | uint8_t TopBottom; | |
221 | } __attribute__((packed)); | |
222 | ||
5b0c5c2c HS |
223 | /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ |
224 | ||
225 | struct cfi_pri_atmel { | |
226 | uint8_t pri[3]; | |
227 | uint8_t MajorVersion; | |
228 | uint8_t MinorVersion; | |
229 | uint8_t Features; | |
230 | uint8_t BottomBoot; | |
231 | uint8_t BurstMode; | |
232 | uint8_t PageMode; | |
233 | } __attribute__((packed)); | |
234 | ||
1da177e4 LT |
235 | struct cfi_pri_query { |
236 | uint8_t NumFields; | |
237 | uint32_t ProtField[1]; /* Not host ordered */ | |
238 | } __attribute__((packed)); | |
239 | ||
240 | struct cfi_bri_query { | |
241 | uint8_t PageModeReadCap; | |
242 | uint8_t NumFields; | |
243 | uint32_t ConfField[1]; /* Not host ordered */ | |
244 | } __attribute__((packed)); | |
245 | ||
246 | #define P_ID_NONE 0x0000 | |
247 | #define P_ID_INTEL_EXT 0x0001 | |
248 | #define P_ID_AMD_STD 0x0002 | |
249 | #define P_ID_INTEL_STD 0x0003 | |
250 | #define P_ID_AMD_EXT 0x0004 | |
251 | #define P_ID_WINBOND 0x0006 | |
252 | #define P_ID_ST_ADV 0x0020 | |
253 | #define P_ID_MITSUBISHI_STD 0x0100 | |
254 | #define P_ID_MITSUBISHI_EXT 0x0101 | |
255 | #define P_ID_SST_PAGE 0x0102 | |
54b93a49 | 256 | #define P_ID_SST_OLD 0x0701 |
1da177e4 LT |
257 | #define P_ID_INTEL_PERFORMANCE 0x0200 |
258 | #define P_ID_INTEL_DATA 0x0210 | |
259 | #define P_ID_RESERVED 0xffff | |
260 | ||
261 | ||
262 | #define CFI_MODE_CFI 1 | |
263 | #define CFI_MODE_JEDEC 0 | |
264 | ||
265 | struct cfi_private { | |
266 | uint16_t cmdset; | |
267 | void *cmdset_priv; | |
268 | int interleave; | |
269 | int device_type; | |
270 | int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */ | |
271 | int addr_unlock1; | |
272 | int addr_unlock2; | |
273 | struct mtd_info *(*cmdset_setup)(struct map_info *); | |
274 | struct cfi_ident *cfiq; /* For now only one. We insist that all devs | |
275 | must be of the same type. */ | |
276 | int mfr, id; | |
277 | int numchips; | |
278 | unsigned long chipshift; /* Because they're of the same type */ | |
279 | const char *im_name; /* inter_module name for cmdset_setup */ | |
280 | struct flchip chips[0]; /* per-chip data structure for each chip */ | |
281 | }; | |
282 | ||
283 | /* | |
284 | * Returns the command address according to the given geometry. | |
285 | */ | |
467622ef EB |
286 | static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, |
287 | struct map_info *map, struct cfi_private *cfi) | |
1da177e4 | 288 | { |
467622ef EB |
289 | unsigned bankwidth = map_bankwidth(map); |
290 | unsigned interleave = cfi_interleave(cfi); | |
291 | unsigned type = cfi->device_type; | |
292 | uint32_t addr; | |
293 | ||
294 | addr = (cmd_ofs * type) * interleave; | |
295 | ||
296 | /* Modify the unlock address if we are in compatiblity mode. | |
297 | * For 16bit devices on 8 bit busses | |
298 | * and 32bit devices on 16 bit busses | |
299 | * set the low bit of the alternating bit sequence of the address. | |
300 | */ | |
1449c5d0 | 301 | if (((type * interleave) > bankwidth) && ((cmd_ofs & 0xff) == 0xaa)) |
467622ef EB |
302 | addr |= (type >> 1)*interleave; |
303 | ||
304 | return addr; | |
1da177e4 LT |
305 | } |
306 | ||
307 | /* | |
308 | * Transforms the CFI command for the given geometry (bus width & interleave). | |
309 | * It looks too long to be inline, but in the common case it should almost all | |
61ecfa87 | 310 | * get optimised away. |
1da177e4 | 311 | */ |
f77814dd | 312 | static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) |
1da177e4 LT |
313 | { |
314 | map_word val = { {0} }; | |
315 | int wordwidth, words_per_bus, chip_mode, chips_per_word; | |
316 | unsigned long onecmd; | |
317 | int i; | |
318 | ||
61ecfa87 | 319 | /* We do it this way to give the compiler a fighting chance |
1da177e4 LT |
320 | of optimising away all the crap for 'bankwidth' larger than |
321 | an unsigned long, in the common case where that support is | |
322 | disabled */ | |
323 | if (map_bankwidth_is_large(map)) { | |
324 | wordwidth = sizeof(unsigned long); | |
325 | words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 | |
326 | } else { | |
327 | wordwidth = map_bankwidth(map); | |
328 | words_per_bus = 1; | |
329 | } | |
61ecfa87 | 330 | |
1da177e4 LT |
331 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); |
332 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); | |
333 | ||
334 | /* First, determine what the bit-pattern should be for a single | |
335 | device, according to chip mode and endianness... */ | |
336 | switch (chip_mode) { | |
337 | default: BUG(); | |
338 | case 1: | |
339 | onecmd = cmd; | |
340 | break; | |
341 | case 2: | |
342 | onecmd = cpu_to_cfi16(cmd); | |
343 | break; | |
344 | case 4: | |
345 | onecmd = cpu_to_cfi32(cmd); | |
346 | break; | |
347 | } | |
348 | ||
61ecfa87 | 349 | /* Now replicate it across the size of an unsigned long, or |
1da177e4 LT |
350 | just to the bus width as appropriate */ |
351 | switch (chips_per_word) { | |
352 | default: BUG(); | |
353 | #if BITS_PER_LONG >= 64 | |
354 | case 8: | |
355 | onecmd |= (onecmd << (chip_mode * 32)); | |
356 | #endif | |
357 | case 4: | |
358 | onecmd |= (onecmd << (chip_mode * 16)); | |
359 | case 2: | |
360 | onecmd |= (onecmd << (chip_mode * 8)); | |
361 | case 1: | |
362 | ; | |
363 | } | |
364 | ||
61ecfa87 | 365 | /* And finally, for the multi-word case, replicate it |
1da177e4 LT |
366 | in all words in the structure */ |
367 | for (i=0; i < words_per_bus; i++) { | |
368 | val.x[i] = onecmd; | |
369 | } | |
370 | ||
371 | return val; | |
372 | } | |
373 | #define CMD(x) cfi_build_cmd((x), map, cfi) | |
374 | ||
c927cd3a | 375 | |
61ecfa87 | 376 | static inline unsigned long cfi_merge_status(map_word val, struct map_info *map, |
c927cd3a TG |
377 | struct cfi_private *cfi) |
378 | { | |
379 | int wordwidth, words_per_bus, chip_mode, chips_per_word; | |
380 | unsigned long onestat, res = 0; | |
381 | int i; | |
382 | ||
61ecfa87 | 383 | /* We do it this way to give the compiler a fighting chance |
c927cd3a TG |
384 | of optimising away all the crap for 'bankwidth' larger than |
385 | an unsigned long, in the common case where that support is | |
386 | disabled */ | |
387 | if (map_bankwidth_is_large(map)) { | |
388 | wordwidth = sizeof(unsigned long); | |
389 | words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 | |
390 | } else { | |
391 | wordwidth = map_bankwidth(map); | |
392 | words_per_bus = 1; | |
393 | } | |
61ecfa87 | 394 | |
c927cd3a TG |
395 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); |
396 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); | |
397 | ||
398 | onestat = val.x[0]; | |
399 | /* Or all status words together */ | |
400 | for (i=1; i < words_per_bus; i++) { | |
401 | onestat |= val.x[i]; | |
402 | } | |
403 | ||
404 | res = onestat; | |
405 | switch(chips_per_word) { | |
406 | default: BUG(); | |
407 | #if BITS_PER_LONG >= 64 | |
408 | case 8: | |
409 | res |= (onestat >> (chip_mode * 32)); | |
410 | #endif | |
411 | case 4: | |
412 | res |= (onestat >> (chip_mode * 16)); | |
413 | case 2: | |
414 | res |= (onestat >> (chip_mode * 8)); | |
415 | case 1: | |
416 | ; | |
417 | } | |
418 | ||
419 | /* Last, determine what the bit-pattern should be for a single | |
420 | device, according to chip mode and endianness... */ | |
421 | switch (chip_mode) { | |
422 | case 1: | |
423 | break; | |
424 | case 2: | |
425 | res = cfi16_to_cpu(res); | |
426 | break; | |
427 | case 4: | |
428 | res = cfi32_to_cpu(res); | |
429 | break; | |
430 | default: BUG(); | |
431 | } | |
432 | return res; | |
433 | } | |
434 | ||
435 | #define MERGESTATUS(x) cfi_merge_status((x), map, cfi) | |
436 | ||
437 | ||
1da177e4 LT |
438 | /* |
439 | * Sends a CFI command to a bank of flash for the given geometry. | |
440 | * | |
441 | * Returns the offset in flash where the command was written. | |
442 | * If prev_val is non-null, it will be set to the value at the command address, | |
443 | * before the command was written. | |
444 | */ | |
445 | static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base, | |
446 | struct map_info *map, struct cfi_private *cfi, | |
447 | int type, map_word *prev_val) | |
448 | { | |
449 | map_word val; | |
467622ef | 450 | uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, map, cfi); |
1da177e4 LT |
451 | val = cfi_build_cmd(cmd, map, cfi); |
452 | ||
453 | if (prev_val) | |
454 | *prev_val = map_read(map, addr); | |
455 | ||
456 | map_write(map, val, addr); | |
457 | ||
458 | return addr - base; | |
459 | } | |
460 | ||
461 | static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr) | |
462 | { | |
463 | map_word val = map_read(map, addr); | |
464 | ||
465 | if (map_bankwidth_is_1(map)) { | |
466 | return val.x[0]; | |
467 | } else if (map_bankwidth_is_2(map)) { | |
468 | return cfi16_to_cpu(val.x[0]); | |
987d2401 TP |
469 | } else { |
470 | /* No point in a 64-bit byteswap since that would just be | |
471 | swapping the responses from different chips, and we are | |
472 | only interested in one chip (a representative sample) */ | |
473 | return cfi32_to_cpu(val.x[0]); | |
474 | } | |
475 | } | |
476 | ||
477 | static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr) | |
478 | { | |
479 | map_word val = map_read(map, addr); | |
480 | ||
481 | if (map_bankwidth_is_1(map)) { | |
482 | return val.x[0] & 0xff; | |
483 | } else if (map_bankwidth_is_2(map)) { | |
484 | return cfi16_to_cpu(val.x[0]); | |
1da177e4 LT |
485 | } else { |
486 | /* No point in a 64-bit byteswap since that would just be | |
487 | swapping the responses from different chips, and we are | |
488 | only interested in one chip (a representative sample) */ | |
489 | return cfi32_to_cpu(val.x[0]); | |
490 | } | |
491 | } | |
492 | ||
493 | static inline void cfi_udelay(int us) | |
494 | { | |
495 | if (us >= 1000) { | |
496 | msleep((us+999)/1000); | |
497 | } else { | |
498 | udelay(us); | |
499 | cond_resched(); | |
500 | } | |
501 | } | |
502 | ||
c314dfdc DW |
503 | int __xipram cfi_qry_present(struct map_info *map, __u32 base, |
504 | struct cfi_private *cfi); | |
505 | int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, | |
506 | struct cfi_private *cfi); | |
507 | void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, | |
508 | struct cfi_private *cfi); | |
2e489e07 | 509 | |
1da177e4 LT |
510 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, |
511 | const char* name); | |
512 | struct cfi_fixup { | |
513 | uint16_t mfr; | |
514 | uint16_t id; | |
515 | void (*fixup)(struct mtd_info *mtd, void* param); | |
516 | void* param; | |
517 | }; | |
518 | ||
ae731822 WS |
519 | #define CFI_MFR_ANY 0xFFFF |
520 | #define CFI_ID_ANY 0xFFFF | |
521 | #define CFI_MFR_CONTINUATION 0x007F | |
1da177e4 | 522 | |
f3e69c65 GL |
523 | #define CFI_MFR_AMD 0x0001 |
524 | #define CFI_MFR_ATMEL 0x001F | |
ae731822 WS |
525 | #define CFI_MFR_EON 0x001C |
526 | #define CFI_MFR_FUJITSU 0x0004 | |
527 | #define CFI_MFR_HYUNDAI 0x00AD | |
f3e69c65 GL |
528 | #define CFI_MFR_INTEL 0x0089 |
529 | #define CFI_MFR_MACRONIX 0x00C2 | |
ae731822 WS |
530 | #define CFI_MFR_NEC 0x0010 |
531 | #define CFI_MFR_PMC 0x009D | |
f3e69c65 | 532 | #define CFI_MFR_SAMSUNG 0x00EC |
ae731822 | 533 | #define CFI_MFR_SHARP 0x00B0 |
f3e69c65 GL |
534 | #define CFI_MFR_SST 0x00BF |
535 | #define CFI_MFR_ST 0x0020 /* STMicroelectronics */ | |
ae731822 WS |
536 | #define CFI_MFR_TOSHIBA 0x0098 |
537 | #define CFI_MFR_WINBOND 0x00DA | |
1da177e4 LT |
538 | |
539 | void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); | |
540 | ||
541 | typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, | |
542 | unsigned long adr, int len, void *thunk); | |
543 | ||
544 | int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |
545 | loff_t ofs, size_t len, void *thunk); | |
546 | ||
547 | ||
548 | #endif /* __MTD_CFI_H__ */ |