ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / linux / mtd / cfi.h
1
2 /* Common Flash Interface structures 
3  * See http://support.intel.com/design/flash/technote/index.htm
4  * $Id: cfi.h,v 1.35 2003/05/28 15:37:32 dwmw2 Exp $
5  */
6
7 #ifndef __MTD_CFI_H__
8 #define __MTD_CFI_H__
9
10 #include <linux/config.h>
11 #include <linux/version.h>
12 #include <linux/delay.h>
13 #include <linux/types.h>
14 #include <linux/interrupt.h>
15 #include <linux/mtd/flashchip.h>
16 #include <linux/mtd/cfi_endian.h>
17
18 /*
19  * You can optimize the code size and performance by defining only 
20  * the geometry(ies) available on your hardware.
21  * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
22  * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
23  *
24  * By default, all (known) geometries are supported.
25  */
26
27 #ifndef CONFIG_MTD_CFI_GEOMETRY
28
29 /* The default case - support all but 64-bit, which has
30    a performance penalty */
31
32 #define CFIDEV_INTERLEAVE_1 (1)
33 #define CFIDEV_INTERLEAVE_2 (2)
34 #define CFIDEV_INTERLEAVE_4 (4)
35
36 #define CFIDEV_BUSWIDTH_1 (1)
37 #define CFIDEV_BUSWIDTH_2 (2)
38 #define CFIDEV_BUSWIDTH_4 (4)
39
40 typedef __u32 cfi_word;
41
42 #else
43
44 /* Explicitly configured buswidth/interleave support */
45
46 #ifdef CONFIG_MTD_CFI_I1
47 #define CFIDEV_INTERLEAVE_1 (1)
48 #endif
49 #ifdef CONFIG_MTD_CFI_I2
50 #define CFIDEV_INTERLEAVE_2 (2)
51 #endif
52 #ifdef CONFIG_MTD_CFI_I4
53 #define CFIDEV_INTERLEAVE_4 (4)
54 #endif
55 #ifdef CONFIG_MTD_CFI_I8
56 #define CFIDEV_INTERLEAVE_8 (8)
57 #endif
58
59 #ifdef CONFIG_MTD_CFI_B1
60 #define CFIDEV_BUSWIDTH_1 (1)
61 #endif
62 #ifdef CONFIG_MTD_CFI_B2
63 #define CFIDEV_BUSWIDTH_2 (2)
64 #endif
65 #ifdef CONFIG_MTD_CFI_B4
66 #define CFIDEV_BUSWIDTH_4 (4)
67 #endif
68 #ifdef CONFIG_MTD_CFI_B8
69 #define CFIDEV_BUSWIDTH_8 (8)
70 #endif
71
72 /* pick the largest necessary */
73 #ifdef CONFIG_MTD_CFI_B8
74 typedef __u64 cfi_word;
75
76 /* This only works if asm/io.h is included first */
77 #ifndef __raw_readll
78 #define __raw_readll(addr)      (*(volatile __u64 *)(addr))
79 #endif
80 #ifndef __raw_writell
81 #define __raw_writell(v, addr)  (*(volatile __u64 *)(addr) = (v))
82 #endif
83 #define CFI_WORD_64
84 #else  /* CONFIG_MTD_CFI_B8 */
85 /* All others can use 32-bits. It's probably more efficient than
86    the smaller types anyway */
87 typedef __u32 cfi_word;
88 #endif /* CONFIG_MTD_CFI_B8 */
89
90 #endif
91
92 /*
93  * The following macros are used to select the code to execute:
94  *   cfi_buswidth_is_*()
95  *   cfi_interleave_is_*()
96  *   [where * is either 1, 2, 4, or 8]
97  * Those macros should be used with 'if' statements.  If only one of few
98  * geometry arrangements are selected, they expand to constants thus allowing
99  * the compiler (most of them being 0) to optimize away all the unneeded code,
100  * while still validating the syntax (which is not possible with embedded 
101  * #if ... #endif constructs).
102  * The exception to this is the 64-bit versions, which need an extension
103  * to the cfi_word type, and cause compiler warnings about shifts being
104  * out of range.
105  */
106
107 #ifdef CFIDEV_INTERLEAVE_1
108 # ifdef CFIDEV_INTERLEAVE
109 #  undef CFIDEV_INTERLEAVE
110 #  define CFIDEV_INTERLEAVE (cfi->interleave)
111 # else
112 #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
113 # endif
114 # define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
115 #else
116 # define cfi_interleave_is_1() (0)
117 #endif
118
119 #ifdef CFIDEV_INTERLEAVE_2
120 # ifdef CFIDEV_INTERLEAVE
121 #  undef CFIDEV_INTERLEAVE
122 #  define CFIDEV_INTERLEAVE (cfi->interleave)
123 # else
124 #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
125 # endif
126 # define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
127 #else
128 # define cfi_interleave_is_2() (0)
129 #endif
130
131 #ifdef CFIDEV_INTERLEAVE_4
132 # ifdef CFIDEV_INTERLEAVE
133 #  undef CFIDEV_INTERLEAVE
134 #  define CFIDEV_INTERLEAVE (cfi->interleave)
135 # else
136 #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
137 # endif
138 # define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
139 #else
140 # define cfi_interleave_is_4() (0)
141 #endif
142
143 #ifdef CFIDEV_INTERLEAVE_8
144 # ifdef CFIDEV_INTERLEAVE
145 #  undef CFIDEV_INTERLEAVE
146 #  define CFIDEV_INTERLEAVE (cfi->interleave)
147 # else
148 #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
149 # endif
150 # define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
151 #else
152 # define cfi_interleave_is_8() (0)
153 #endif
154
155 #ifndef CFIDEV_INTERLEAVE
156 #error You must define at least one interleave to support!
157 #endif
158
159 #ifdef CFIDEV_BUSWIDTH_1
160 # ifdef CFIDEV_BUSWIDTH
161 #  undef CFIDEV_BUSWIDTH
162 #  define CFIDEV_BUSWIDTH (map->buswidth)
163 # else
164 #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
165 # endif
166 # define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
167 #else
168 # define cfi_buswidth_is_1() (0)
169 #endif
170
171 #ifdef CFIDEV_BUSWIDTH_2
172 # ifdef CFIDEV_BUSWIDTH
173 #  undef CFIDEV_BUSWIDTH
174 #  define CFIDEV_BUSWIDTH (map->buswidth)
175 # else
176 #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
177 # endif
178 # define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
179 #else
180 # define cfi_buswidth_is_2() (0)
181 #endif
182
183 #ifdef CFIDEV_BUSWIDTH_4
184 # ifdef CFIDEV_BUSWIDTH
185 #  undef CFIDEV_BUSWIDTH
186 #  define CFIDEV_BUSWIDTH (map->buswidth)
187 # else
188 #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
189 # endif
190 # define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
191 #else
192 # define cfi_buswidth_is_4() (0)
193 #endif
194
195 #ifdef CFIDEV_BUSWIDTH_8
196 # ifdef CFIDEV_BUSWIDTH
197 #  undef CFIDEV_BUSWIDTH
198 #  define CFIDEV_BUSWIDTH (map->buswidth)
199 # else
200 #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
201 # endif
202 # define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
203 #else
204 # define cfi_buswidth_is_8() (0)
205 #endif
206
207 #ifndef CFIDEV_BUSWIDTH
208 #error You must define at least one bus width to support!
209 #endif
210
211 /* NB: these values must represents the number of bytes needed to meet the 
212  *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
213  *     These numbers are used in calculations.
214  */
215 #define CFI_DEVICETYPE_X8  (8 / 8)
216 #define CFI_DEVICETYPE_X16 (16 / 8)
217 #define CFI_DEVICETYPE_X32 (32 / 8)
218 #define CFI_DEVICETYPE_X64 (64 / 8)
219
220 /* NB: We keep these structures in memory in HOST byteorder, except
221  * where individually noted.
222  */
223
224 /* Basic Query Structure */
225 struct cfi_ident {
226   __u8  qry[3];
227   __u16 P_ID;
228   __u16 P_ADR;
229   __u16 A_ID;
230   __u16 A_ADR;
231   __u8  VccMin;
232   __u8  VccMax;
233   __u8  VppMin;
234   __u8  VppMax;
235   __u8  WordWriteTimeoutTyp;
236   __u8  BufWriteTimeoutTyp;
237   __u8  BlockEraseTimeoutTyp;
238   __u8  ChipEraseTimeoutTyp;
239   __u8  WordWriteTimeoutMax;
240   __u8  BufWriteTimeoutMax;
241   __u8  BlockEraseTimeoutMax;
242   __u8  ChipEraseTimeoutMax;
243   __u8  DevSize;
244   __u16 InterfaceDesc;
245   __u16 MaxBufWriteSize;
246   __u8  NumEraseRegions;
247   __u32 EraseRegionInfo[0]; /* Not host ordered */
248 } __attribute__((packed));
249
250 /* Extended Query Structure for both PRI and ALT */
251
252 struct cfi_extquery {
253   __u8  pri[3];
254   __u8  MajorVersion;
255   __u8  MinorVersion;
256 } __attribute__((packed));
257
258 /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
259
260 struct cfi_pri_intelext {
261   __u8  pri[3];
262   __u8  MajorVersion;
263   __u8  MinorVersion;
264   __u32 FeatureSupport;
265   __u8  SuspendCmdSupport;
266   __u16 BlkStatusRegMask;
267   __u8  VccOptimal;
268   __u8  VppOptimal;
269   __u8  NumProtectionFields;
270   __u16 ProtRegAddr;
271   __u8  FactProtRegSize;
272   __u8  UserProtRegSize;
273 } __attribute__((packed));
274
275 struct cfi_pri_query {
276   __u8  NumFields;
277   __u32 ProtField[1]; /* Not host ordered */
278 } __attribute__((packed));
279
280 struct cfi_bri_query {
281   __u8  PageModeReadCap;
282   __u8  NumFields;
283   __u32 ConfField[1]; /* Not host ordered */
284 } __attribute__((packed));
285
286 #define P_ID_NONE 0
287 #define P_ID_INTEL_EXT 1
288 #define P_ID_AMD_STD 2
289 #define P_ID_INTEL_STD 3
290 #define P_ID_AMD_EXT 4
291 #define P_ID_MITSUBISHI_STD 256
292 #define P_ID_MITSUBISHI_EXT 257
293 #define P_ID_RESERVED 65535
294
295
296 #define CFI_MODE_CFI    1
297 #define CFI_MODE_JEDEC  0
298
299 struct cfi_private {
300         __u16 cmdset;
301         void *cmdset_priv;
302         int interleave;
303         int device_type;
304         int cfi_mode;           /* Are we a JEDEC device pretending to be CFI? */
305         int addr_unlock1;
306         int addr_unlock2;
307         int fast_prog;
308         struct mtd_info *(*cmdset_setup)(struct map_info *);
309         struct cfi_ident *cfiq; /* For now only one. We insist that all devs
310                                   must be of the same type. */
311         int mfr, id;
312         int numchips;
313         unsigned long chipshift; /* Because they're of the same type */
314         const char *im_name;     /* inter_module name for cmdset_setup */
315         struct flchip chips[0];  /* per-chip data structure for each chip */
316 };
317
318 #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
319
320 /*
321  * Returns the command address according to the given geometry.
322  */
323 static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
324 {
325         return (cmd_ofs * type) * interleave;
326 }
327
328 /*
329  * Transforms the CFI command for the given geometry (bus width & interleave.
330  */
331 static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
332 {
333         cfi_word val = 0;
334
335         if (cfi_buswidth_is_1()) {
336                 /* 1 x8 device */
337                 val = cmd;
338         } else if (cfi_buswidth_is_2()) {
339                 if (cfi_interleave_is_1()) {
340                         /* 1 x16 device in x16 mode */
341                         val = cpu_to_cfi16(cmd);
342                 } else if (cfi_interleave_is_2()) {
343                         /* 2 (x8, x16 or x32) devices in x8 mode */
344                         val = cpu_to_cfi16((cmd << 8) | cmd);
345                 }
346         } else if (cfi_buswidth_is_4()) {
347                 if (cfi_interleave_is_1()) {
348                         /* 1 x32 device in x32 mode */
349                         val = cpu_to_cfi32(cmd);
350                 } else if (cfi_interleave_is_2()) {
351                         /* 2 x16 device in x16 mode */
352                         val = cpu_to_cfi32((cmd << 16) | cmd);
353                 } else if (cfi_interleave_is_4()) {
354                         /* 4 (x8, x16 or x32) devices in x8 mode */
355                         val = (cmd << 16) | cmd;
356                         val = cpu_to_cfi32((val << 8) | val);
357                 }
358 #ifdef CFI_WORD_64
359         } else if (cfi_buswidth_is_8()) {
360                 if (cfi_interleave_is_1()) {
361                         /* 1 x64 device in x64 mode */
362                         val = cpu_to_cfi64(cmd);
363                 } else if (cfi_interleave_is_2()) {
364                         /* 2 x32 device in x32 mode */
365                         val = cmd;
366                         val = cpu_to_cfi64((val << 32) | val);
367                 } else if (cfi_interleave_is_4()) {
368                         /* 4 (x16, x32 or x64) devices in x16 mode */
369                         val = (cmd << 16) | cmd;
370                         val = cpu_to_cfi64((val << 32) | val);
371                 } else if (cfi_interleave_is_8()) {
372                         /* 8 (x8, x16 or x32) devices in x8 mode */
373                         val = (cmd << 8) | cmd;
374                         val = (val << 16) | val;
375                         val = (val << 32) | val;
376                         val = cpu_to_cfi64(val);
377                 }
378 #endif /* CFI_WORD_64 */
379         }
380         return val;
381 }
382 #define CMD(x)  cfi_build_cmd((x), map, cfi)
383
384 /*
385  * Read a value according to the bus width.
386  */
387
388 static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
389 {
390         if (cfi_buswidth_is_1()) {
391                 return map_read8(map, addr);
392         } else if (cfi_buswidth_is_2()) {
393                 return map_read16(map, addr);
394         } else if (cfi_buswidth_is_4()) {
395                 return map_read32(map, addr);
396         } else if (cfi_buswidth_is_8()) {
397                 return map_read64(map, addr);
398         } else {
399                 return 0;
400         }
401 }
402
403 /*
404  * Write a value according to the bus width.
405  */
406
407 static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
408 {
409         if (cfi_buswidth_is_1()) {
410                 map_write8(map, val, addr);
411         } else if (cfi_buswidth_is_2()) {
412                 map_write16(map, val, addr);
413         } else if (cfi_buswidth_is_4()) {
414                 map_write32(map, val, addr);
415         } else if (cfi_buswidth_is_8()) {
416                 map_write64(map, val, addr);
417         }
418 }
419
420 /*
421  * Sends a CFI command to a bank of flash for the given geometry.
422  *
423  * Returns the offset in flash where the command was written.
424  * If prev_val is non-null, it will be set to the value at the command address,
425  * before the command was written.
426  */
427 static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
428                                 struct map_info *map, struct cfi_private *cfi,
429                                 int type, cfi_word *prev_val)
430 {
431         cfi_word val;
432         __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
433
434         val = cfi_build_cmd(cmd, map, cfi);
435
436         if (prev_val)
437                 *prev_val = cfi_read(map, addr);
438
439         cfi_write(map, val, addr);
440
441         return addr - base;
442 }
443
444 static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
445 {
446         if (cfi_buswidth_is_1()) {
447                 return map_read8(map, addr);
448         } else if (cfi_buswidth_is_2()) {
449                 return cfi16_to_cpu(map_read16(map, addr));
450         } else if (cfi_buswidth_is_4()) {
451                 return cfi32_to_cpu(map_read32(map, addr));
452         } else if (cfi_buswidth_is_8()) {
453                 return cfi64_to_cpu(map_read64(map, addr));
454         } else {
455                 return 0;
456         }
457 }
458
459 static inline void cfi_udelay(int us)
460 {
461 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
462         unsigned long t = us * HZ / 1000000;
463         if (t) {
464                 set_current_state(TASK_UNINTERRUPTIBLE);
465                 schedule_timeout(t);
466                 return;
467         }
468 #endif
469         udelay(us);
470         cond_resched();
471 }
472
473 static inline void cfi_spin_lock(spinlock_t *mutex)
474 {
475         spin_lock_bh(mutex);
476 }
477
478 static inline void cfi_spin_unlock(spinlock_t *mutex)
479 {
480         spin_unlock_bh(mutex);
481 }
482
483 #endif /* __MTD_CFI_H__ */