File: /usr/src/linux/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.22 2001/07/06 09:29:07 dwmw2 Exp $
5      */
6     
7     #ifndef __MTD_CFI_H__
8     #define __MTD_CFI_H__
9     
10     #include <linux/config.h>
11     #include <linux/delay.h>
12     #include <linux/types.h>
13     #include <linux/interrupt.h>
14     #include <linux/mtd/flashchip.h>
15     #include <linux/mtd/cfi_endian.h>
16     
17     /*
18      * You can optimize the code size and performance by defining only 
19      * the geometry(ies) available on your hardware.
20      * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
21      * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes)
22      *
23      * By default, all (known) geometries are supported.
24      */
25     
26     #ifndef CONFIG_MTD_CFI_GEOMETRY
27     
28     #define CFIDEV_INTERLEAVE_1 (1)
29     #define CFIDEV_INTERLEAVE_2 (2)
30     #define CFIDEV_INTERLEAVE_4 (4)
31     
32     #define CFIDEV_BUSWIDTH_1 (1)
33     #define CFIDEV_BUSWIDTH_2 (2)
34     #define CFIDEV_BUSWIDTH_4 (4)
35     
36     #else
37     
38     #ifdef CONFIG_MTD_CFI_I1
39     #define CFIDEV_INTERLEAVE_1 (1)
40     #endif
41     #ifdef CONFIG_MTD_CFI_I2
42     #define CFIDEV_INTERLEAVE_2 (2)
43     #endif
44     #ifdef CONFIG_MTD_CFI_I4
45     #define CFIDEV_INTERLEAVE_4 (4)
46     #endif
47     
48     #ifdef CONFIG_MTD_CFI_B1
49     #define CFIDEV_BUSWIDTH_1 (1)
50     #endif
51     #ifdef CONFIG_MTD_CFI_B2
52     #define CFIDEV_BUSWIDTH_2 (2)
53     #endif
54     #ifdef CONFIG_MTD_CFI_B4
55     #define CFIDEV_BUSWIDTH_4 (4)
56     #endif
57     
58     #endif
59     
60     /*
61      * The following macros are used to select the code to execute:
62      *   cfi_buswidth_is_*()
63      *   cfi_interleave_is_*()
64      *   [where * is either 1, 2 or 4]
65      * Those macros should be used with 'if' statements.  If only one of few
66      * geometry arrangements are selected, they expand to constants thus allowing
67      * the compiler (most of them being 0) to optimize away all the unneeded code,
68      * while still validating the syntax (which is not possible with embedded 
69      * #if ... #endif constructs).
70      */
71     
72     #ifdef CFIDEV_INTERLEAVE_1
73     # ifdef CFIDEV_INTERLEAVE
74     #  undef CFIDEV_INTERLEAVE
75     #  define CFIDEV_INTERLEAVE (cfi->interleave)
76     # else
77     #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
78     # endif
79     # define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
80     #else
81     # define cfi_interleave_is_1() (0)
82     #endif
83     
84     #ifdef CFIDEV_INTERLEAVE_2
85     # ifdef CFIDEV_INTERLEAVE
86     #  undef CFIDEV_INTERLEAVE
87     #  define CFIDEV_INTERLEAVE (cfi->interleave)
88     # else
89     #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
90     # endif
91     # define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
92     #else
93     # define cfi_interleave_is_2() (0)
94     #endif
95     
96     #ifdef CFIDEV_INTERLEAVE_4
97     # ifdef CFIDEV_INTERLEAVE
98     #  undef CFIDEV_INTERLEAVE
99     #  define CFIDEV_INTERLEAVE (cfi->interleave)
100     # else
101     #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
102     # endif
103     # define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
104     #else
105     # define cfi_interleave_is_4() (0)
106     #endif
107     
108     #ifndef CFIDEV_INTERLEAVE
109     #error You must define at least one interleave to support!
110     #endif
111     
112     #ifdef CFIDEV_BUSWIDTH_1
113     # ifdef CFIDEV_BUSWIDTH
114     #  undef CFIDEV_BUSWIDTH
115     #  define CFIDEV_BUSWIDTH (map->buswidth)
116     # else
117     #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
118     # endif
119     # define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
120     #else
121     # define cfi_buswidth_is_1() (0)
122     #endif
123     
124     #ifdef CFIDEV_BUSWIDTH_2
125     # ifdef CFIDEV_BUSWIDTH
126     #  undef CFIDEV_BUSWIDTH
127     #  define CFIDEV_BUSWIDTH (map->buswidth)
128     # else
129     #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
130     # endif
131     # define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
132     #else
133     # define cfi_buswidth_is_2() (0)
134     #endif
135     
136     #ifdef CFIDEV_BUSWIDTH_4
137     # ifdef CFIDEV_BUSWIDTH
138     #  undef CFIDEV_BUSWIDTH
139     #  define CFIDEV_BUSWIDTH (map->buswidth)
140     # else
141     #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
142     # endif
143     # define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
144     #else
145     # define cfi_buswidth_is_4() (0)
146     #endif
147     
148     #ifndef CFIDEV_BUSWIDTH
149     #error You must define at least one bus width to support!
150     #endif
151     
152     /* NB: these values must represents the number of bytes needed to meet the 
153      *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
154      *     These numbers are used in calculations.
155      */
156     #define CFI_DEVICETYPE_X8  (8 / 8)
157     #define CFI_DEVICETYPE_X16 (16 / 8)
158     #define CFI_DEVICETYPE_X32 (32 / 8)
159     
160     /* NB: We keep these structures in memory in HOST byteorder, except
161      * where individually noted.
162      */
163     
164     /* Basic Query Structure */
165     struct cfi_ident {
166       __u8  qry[3];
167       __u16 P_ID;
168       __u16 P_ADR;
169       __u16 A_ID;
170       __u16 A_ADR;
171       __u8  VccMin;
172       __u8  VccMax;
173       __u8  VppMin;
174       __u8  VppMax;
175       __u8  WordWriteTimeoutTyp;
176       __u8  BufWriteTimeoutTyp;
177       __u8  BlockEraseTimeoutTyp;
178       __u8  ChipEraseTimeoutTyp;
179       __u8  WordWriteTimeoutMax;
180       __u8  BufWriteTimeoutMax;
181       __u8  BlockEraseTimeoutMax;
182       __u8  ChipEraseTimeoutMax;
183       __u8  DevSize;
184       __u16 InterfaceDesc;
185       __u16 MaxBufWriteSize;
186       __u8  NumEraseRegions;
187       __u32 EraseRegionInfo[0]; /* Not host ordered */
188     } __attribute__((packed));
189     
190     /* Extended Query Structure for both PRI and ALT */
191     
192     struct cfi_extquery {
193       __u8  pri[3];
194       __u8  MajorVersion;
195       __u8  MinorVersion;
196     } __attribute__((packed));
197     
198     /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
199     
200     struct cfi_pri_intelext {
201       __u8  pri[3];
202       __u8  MajorVersion;
203       __u8  MinorVersion;
204       __u32 FeatureSupport;
205       __u8  SuspendCmdSupport;
206       __u16 BlkStatusRegMask;
207       __u8  VccOptimal;
208       __u8  VppOptimal;
209     } __attribute__((packed));
210     
211     struct cfi_pri_query {
212       __u8  NumFields;
213       __u32 ProtField[1]; /* Not host ordered */
214     } __attribute__((packed));
215     
216     struct cfi_bri_query {
217       __u8  PageModeReadCap;
218       __u8  NumFields;
219       __u32 ConfField[1]; /* Not host ordered */
220     } __attribute__((packed));
221     
222     #define P_ID_NONE 0
223     #define P_ID_INTEL_EXT 1
224     #define P_ID_AMD_STD 2
225     #define P_ID_INTEL_STD 3
226     #define P_ID_AMD_EXT 4
227     #define P_ID_MITSUBISHI_STD 256
228     #define P_ID_MITSUBISHI_EXT 257
229     #define P_ID_RESERVED 65535
230     
231     
232     #define CFI_MODE_CFI	0
233     #define CFI_MODE_JEDEC	1
234     
235     struct cfi_private {
236     	__u16 cmdset;
237     	void *cmdset_priv;
238     	int interleave;
239     	int device_type;
240     	int cfi_mode;		/* Are we a JEDEC device pretending to be CFI? */
241     	int addr_unlock1;
242     	int addr_unlock2;
243     	int fast_prog;
244     	struct mtd_info *(*cmdset_setup)(struct map_info *);
245     	struct cfi_ident *cfiq; /* For now only one. We insist that all devs
246     				  must be of the same type. */
247     	__u8 mfr, id;
248     	int numchips;
249     	unsigned long chipshift; /* Because they're of the same type */
250     	const char *im_name;	 /* inter_module name for cmdset_setup */
251     	struct flchip chips[0];  /* per-chip data structure for each chip */
252     };
253     
254     #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
255     
256     /*
257      * Returns the command address according to the given geometry.
258      */
259     static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
260     {
261     	return (cmd_ofs * type) * interleave;
262     }
263     
264     /*
265      * Transforms the CFI command for the given geometry (bus width & interleave.
266      */
267     static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
268     {
269     	__u32 val = 0;
270     
271     	if (cfi_buswidth_is_1()) {
272     		/* 1 x8 device */
273     		val = cmd;
274     	} else if (cfi_buswidth_is_2()) {
275     		if (cfi_interleave_is_1()) {
276     			/* 1 x16 device in x16 mode */
277     			val = cpu_to_cfi16(cmd);
278     		} else if (cfi_interleave_is_2()) {
279     			/* 2 (x8, x16 or x32) devices in x8 mode */
280     			val = cpu_to_cfi16((cmd << 8) | cmd);
281     		}
282     	} else if (cfi_buswidth_is_4()) {
283     		if (cfi_interleave_is_1()) {
284     			/* 1 x32 device in x32 mode */
285     			val = cpu_to_cfi32(cmd);
286     		} else if (cfi_interleave_is_2()) {
287     			/* 2 x16 device in x16 mode */
288     			val = cpu_to_cfi32((cmd << 16) | cmd);
289     		} else if (cfi_interleave_is_4()) {
290     			/* 4 (x8, x16 or x32) devices in x8 mode */
291     			val = (cmd << 16) | cmd;
292     			val = cpu_to_cfi32((val << 8) | val);
293     		}
294     	}
295     	return val;
296     }
297     #define CMD(x)  cfi_build_cmd((x), map, cfi)
298     
299     /*
300      * Read a value according to the bus width.
301      */
302     
303     static inline __u32 cfi_read(struct map_info *map, __u32 addr)
304     {
305     	if (cfi_buswidth_is_1()) {
306     		return map->read8(map, addr);
307     	} else if (cfi_buswidth_is_2()) {
308     		return map->read16(map, addr);
309     	} else if (cfi_buswidth_is_4()) {
310     		return map->read32(map, addr);
311     	} else {
312     		return 0;
313     	}
314     }
315     
316     /*
317      * Write a value according to the bus width.
318      */
319     
320     static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
321     {
322     	if (cfi_buswidth_is_1()) {
323     		map->write8(map, val, addr);
324     	} else if (cfi_buswidth_is_2()) {
325     		map->write16(map, val, addr);
326     	} else if (cfi_buswidth_is_4()) {
327     		map->write32(map, val, addr);
328     	}
329     }
330     
331     /*
332      * Sends a CFI command to a bank of flash for the given geometry.
333      *
334      * Returns the offset in flash where the command was written.
335      * If prev_val is non-null, it will be set to the value at the command address,
336      * before the command was written.
337      */
338     static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
339     				struct map_info *map, struct cfi_private *cfi,
340     				int type, __u32 *prev_val)
341     {
342     	__u32 val;
343     	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
344     
345     	val = cfi_build_cmd(cmd, map, cfi);
346     
347     	if (prev_val)
348     		*prev_val = cfi_read(map, addr);
349     
350     	cfi_write(map, val, addr);
351     
352     	return addr - base;
353     }
354     
355     static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
356     {
357     	if (cfi_buswidth_is_1()) {
358     		return map->read8(map, addr);
359     	} else if (cfi_buswidth_is_2()) {
360     		return cfi16_to_cpu(map->read16(map, addr));
361     	} else if (cfi_buswidth_is_4()) {
362     		return cfi32_to_cpu(map->read32(map, addr));
363     	} else {
364     		return 0;
365     	}
366     }
367     
368     static inline void cfi_udelay(int us)
369     {
370     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
371     	if (current->need_resched)
372     		schedule();
373     	else
374     #endif
375     		udelay(us);
376     }
377     static inline void cfi_spin_lock(spinlock_t *mutex)
378     {
379     	spin_lock_bh(mutex);
380     }
381     
382     static inline void cfi_spin_unlock(spinlock_t *mutex)
383     {
384     	spin_unlock_bh(mutex);
385     }
386     
387     
388     #endif /* __MTD_CFI_H__ */
389