diff options
Diffstat (limited to 'include/linux/mtd/map.h')
-rw-r--r-- | include/linux/mtd/map.h | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h new file mode 100644 index 000000000000..f0268b99c900 --- /dev/null +++ b/include/linux/mtd/map.h | |||
@@ -0,0 +1,412 @@ | |||
1 | |||
2 | /* Overhauled routines for dealing with different mmap regions of flash */ | ||
3 | /* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */ | ||
4 | |||
5 | #ifndef __LINUX_MTD_MAP_H__ | ||
6 | #define __LINUX_MTD_MAP_H__ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/list.h> | ||
11 | #include <linux/mtd/compatmac.h> | ||
12 | #include <asm/unaligned.h> | ||
13 | #include <asm/system.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/bug.h> | ||
16 | |||
17 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 | ||
18 | #define map_bankwidth(map) 1 | ||
19 | #define map_bankwidth_is_1(map) (map_bankwidth(map) == 1) | ||
20 | #define map_bankwidth_is_large(map) (0) | ||
21 | #define map_words(map) (1) | ||
22 | #define MAX_MAP_BANKWIDTH 1 | ||
23 | #else | ||
24 | #define map_bankwidth_is_1(map) (0) | ||
25 | #endif | ||
26 | |||
27 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 | ||
28 | # ifdef map_bankwidth | ||
29 | # undef map_bankwidth | ||
30 | # define map_bankwidth(map) ((map)->bankwidth) | ||
31 | # else | ||
32 | # define map_bankwidth(map) 2 | ||
33 | # define map_bankwidth_is_large(map) (0) | ||
34 | # define map_words(map) (1) | ||
35 | # endif | ||
36 | #define map_bankwidth_is_2(map) (map_bankwidth(map) == 2) | ||
37 | #undef MAX_MAP_BANKWIDTH | ||
38 | #define MAX_MAP_BANKWIDTH 2 | ||
39 | #else | ||
40 | #define map_bankwidth_is_2(map) (0) | ||
41 | #endif | ||
42 | |||
43 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 | ||
44 | # ifdef map_bankwidth | ||
45 | # undef map_bankwidth | ||
46 | # define map_bankwidth(map) ((map)->bankwidth) | ||
47 | # else | ||
48 | # define map_bankwidth(map) 4 | ||
49 | # define map_bankwidth_is_large(map) (0) | ||
50 | # define map_words(map) (1) | ||
51 | # endif | ||
52 | #define map_bankwidth_is_4(map) (map_bankwidth(map) == 4) | ||
53 | #undef MAX_MAP_BANKWIDTH | ||
54 | #define MAX_MAP_BANKWIDTH 4 | ||
55 | #else | ||
56 | #define map_bankwidth_is_4(map) (0) | ||
57 | #endif | ||
58 | |||
59 | /* ensure we never evaluate anything shorted than an unsigned long | ||
60 | * to zero, and ensure we'll never miss the end of an comparison (bjd) */ | ||
61 | |||
62 | #define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long)) | ||
63 | |||
64 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 | ||
65 | # ifdef map_bankwidth | ||
66 | # undef map_bankwidth | ||
67 | # define map_bankwidth(map) ((map)->bankwidth) | ||
68 | # if BITS_PER_LONG < 64 | ||
69 | # undef map_bankwidth_is_large | ||
70 | # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) | ||
71 | # undef map_words | ||
72 | # define map_words(map) map_calc_words(map) | ||
73 | # endif | ||
74 | # else | ||
75 | # define map_bankwidth(map) 8 | ||
76 | # define map_bankwidth_is_large(map) (BITS_PER_LONG < 64) | ||
77 | # define map_words(map) map_calc_words(map) | ||
78 | # endif | ||
79 | #define map_bankwidth_is_8(map) (map_bankwidth(map) == 8) | ||
80 | #undef MAX_MAP_BANKWIDTH | ||
81 | #define MAX_MAP_BANKWIDTH 8 | ||
82 | #else | ||
83 | #define map_bankwidth_is_8(map) (0) | ||
84 | #endif | ||
85 | |||
86 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 | ||
87 | # ifdef map_bankwidth | ||
88 | # undef map_bankwidth | ||
89 | # define map_bankwidth(map) ((map)->bankwidth) | ||
90 | # undef map_bankwidth_is_large | ||
91 | # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) | ||
92 | # undef map_words | ||
93 | # define map_words(map) map_calc_words(map) | ||
94 | # else | ||
95 | # define map_bankwidth(map) 16 | ||
96 | # define map_bankwidth_is_large(map) (1) | ||
97 | # define map_words(map) map_calc_words(map) | ||
98 | # endif | ||
99 | #define map_bankwidth_is_16(map) (map_bankwidth(map) == 16) | ||
100 | #undef MAX_MAP_BANKWIDTH | ||
101 | #define MAX_MAP_BANKWIDTH 16 | ||
102 | #else | ||
103 | #define map_bankwidth_is_16(map) (0) | ||
104 | #endif | ||
105 | |||
106 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 | ||
107 | # ifdef map_bankwidth | ||
108 | # undef map_bankwidth | ||
109 | # define map_bankwidth(map) ((map)->bankwidth) | ||
110 | # undef map_bankwidth_is_large | ||
111 | # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) | ||
112 | # undef map_words | ||
113 | # define map_words(map) map_calc_words(map) | ||
114 | # else | ||
115 | # define map_bankwidth(map) 32 | ||
116 | # define map_bankwidth_is_large(map) (1) | ||
117 | # define map_words(map) map_calc_words(map) | ||
118 | # endif | ||
119 | #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32) | ||
120 | #undef MAX_MAP_BANKWIDTH | ||
121 | #define MAX_MAP_BANKWIDTH 32 | ||
122 | #else | ||
123 | #define map_bankwidth_is_32(map) (0) | ||
124 | #endif | ||
125 | |||
126 | #ifndef map_bankwidth | ||
127 | #error "No bus width supported. What's the point?" | ||
128 | #endif | ||
129 | |||
130 | static inline int map_bankwidth_supported(int w) | ||
131 | { | ||
132 | switch (w) { | ||
133 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 | ||
134 | case 1: | ||
135 | #endif | ||
136 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 | ||
137 | case 2: | ||
138 | #endif | ||
139 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 | ||
140 | case 4: | ||
141 | #endif | ||
142 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 | ||
143 | case 8: | ||
144 | #endif | ||
145 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 | ||
146 | case 16: | ||
147 | #endif | ||
148 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 | ||
149 | case 32: | ||
150 | #endif | ||
151 | return 1; | ||
152 | |||
153 | default: | ||
154 | return 0; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | #define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG ) | ||
159 | |||
160 | typedef union { | ||
161 | unsigned long x[MAX_MAP_LONGS]; | ||
162 | } map_word; | ||
163 | |||
164 | /* The map stuff is very simple. You fill in your struct map_info with | ||
165 | a handful of routines for accessing the device, making sure they handle | ||
166 | paging etc. correctly if your device needs it. Then you pass it off | ||
167 | to a chip probe routine -- either JEDEC or CFI probe or both -- via | ||
168 | do_map_probe(). If a chip is recognised, the probe code will invoke the | ||
169 | appropriate chip driver (if present) and return a struct mtd_info. | ||
170 | At which point, you fill in the mtd->module with your own module | ||
171 | address, and register it with the MTD core code. Or you could partition | ||
172 | it and register the partitions instead, or keep it for your own private | ||
173 | use; whatever. | ||
174 | |||
175 | The mtd->priv field will point to the struct map_info, and any further | ||
176 | private data required by the chip driver is linked from the | ||
177 | mtd->priv->fldrv_priv field. This allows the map driver to get at | ||
178 | the destructor function map->fldrv_destroy() when it's tired | ||
179 | of living. | ||
180 | */ | ||
181 | |||
182 | struct map_info { | ||
183 | char *name; | ||
184 | unsigned long size; | ||
185 | unsigned long phys; | ||
186 | #define NO_XIP (-1UL) | ||
187 | |||
188 | void __iomem *virt; | ||
189 | void *cached; | ||
190 | |||
191 | int bankwidth; /* in octets. This isn't necessarily the width | ||
192 | of actual bus cycles -- it's the repeat interval | ||
193 | in bytes, before you are talking to the first chip again. | ||
194 | */ | ||
195 | |||
196 | #ifdef CONFIG_MTD_COMPLEX_MAPPINGS | ||
197 | map_word (*read)(struct map_info *, unsigned long); | ||
198 | void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); | ||
199 | |||
200 | void (*write)(struct map_info *, const map_word, unsigned long); | ||
201 | void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); | ||
202 | |||
203 | /* We can perhaps put in 'point' and 'unpoint' methods, if we really | ||
204 | want to enable XIP for non-linear mappings. Not yet though. */ | ||
205 | #endif | ||
206 | /* It's possible for the map driver to use cached memory in its | ||
207 | copy_from implementation (and _only_ with copy_from). However, | ||
208 | when the chip driver knows some flash area has changed contents, | ||
209 | it will signal it to the map driver through this routine to let | ||
210 | the map driver invalidate the corresponding cache as needed. | ||
211 | If there is no cache to care about this can be set to NULL. */ | ||
212 | void (*inval_cache)(struct map_info *, unsigned long, ssize_t); | ||
213 | |||
214 | /* set_vpp() must handle being reentered -- enable, enable, disable | ||
215 | must leave it enabled. */ | ||
216 | void (*set_vpp)(struct map_info *, int); | ||
217 | |||
218 | unsigned long map_priv_1; | ||
219 | unsigned long map_priv_2; | ||
220 | void *fldrv_priv; | ||
221 | struct mtd_chip_driver *fldrv; | ||
222 | }; | ||
223 | |||
224 | struct mtd_chip_driver { | ||
225 | struct mtd_info *(*probe)(struct map_info *map); | ||
226 | void (*destroy)(struct mtd_info *); | ||
227 | struct module *module; | ||
228 | char *name; | ||
229 | struct list_head list; | ||
230 | }; | ||
231 | |||
232 | void register_mtd_chip_driver(struct mtd_chip_driver *); | ||
233 | void unregister_mtd_chip_driver(struct mtd_chip_driver *); | ||
234 | |||
235 | struct mtd_info *do_map_probe(const char *name, struct map_info *map); | ||
236 | void map_destroy(struct mtd_info *mtd); | ||
237 | |||
238 | #define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) | ||
239 | #define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) | ||
240 | |||
241 | #define INVALIDATE_CACHED_RANGE(map, from, size) \ | ||
242 | do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) | ||
243 | |||
244 | |||
245 | static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) | ||
246 | { | ||
247 | int i; | ||
248 | for (i=0; i<map_words(map); i++) { | ||
249 | if (val1.x[i] != val2.x[i]) | ||
250 | return 0; | ||
251 | } | ||
252 | return 1; | ||
253 | } | ||
254 | |||
255 | static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2) | ||
256 | { | ||
257 | map_word r; | ||
258 | int i; | ||
259 | |||
260 | for (i=0; i<map_words(map); i++) { | ||
261 | r.x[i] = val1.x[i] & val2.x[i]; | ||
262 | } | ||
263 | return r; | ||
264 | } | ||
265 | |||
266 | static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) | ||
267 | { | ||
268 | map_word r; | ||
269 | int i; | ||
270 | |||
271 | for (i=0; i<map_words(map); i++) { | ||
272 | r.x[i] = val1.x[i] | val2.x[i]; | ||
273 | } | ||
274 | return r; | ||
275 | } | ||
276 | #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) | ||
277 | |||
278 | static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) | ||
279 | { | ||
280 | int i; | ||
281 | |||
282 | for (i=0; i<map_words(map); i++) { | ||
283 | if (val1.x[i] & val2.x[i]) | ||
284 | return 1; | ||
285 | } | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static inline map_word map_word_load(struct map_info *map, const void *ptr) | ||
290 | { | ||
291 | map_word r; | ||
292 | |||
293 | if (map_bankwidth_is_1(map)) | ||
294 | r.x[0] = *(unsigned char *)ptr; | ||
295 | else if (map_bankwidth_is_2(map)) | ||
296 | r.x[0] = get_unaligned((uint16_t *)ptr); | ||
297 | else if (map_bankwidth_is_4(map)) | ||
298 | r.x[0] = get_unaligned((uint32_t *)ptr); | ||
299 | #if BITS_PER_LONG >= 64 | ||
300 | else if (map_bankwidth_is_8(map)) | ||
301 | r.x[0] = get_unaligned((uint64_t *)ptr); | ||
302 | #endif | ||
303 | else if (map_bankwidth_is_large(map)) | ||
304 | memcpy(r.x, ptr, map->bankwidth); | ||
305 | |||
306 | return r; | ||
307 | } | ||
308 | |||
309 | static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len) | ||
310 | { | ||
311 | int i; | ||
312 | |||
313 | if (map_bankwidth_is_large(map)) { | ||
314 | char *dest = (char *)&orig; | ||
315 | memcpy(dest+start, buf, len); | ||
316 | } else { | ||
317 | for (i=start; i < start+len; i++) { | ||
318 | int bitpos; | ||
319 | #ifdef __LITTLE_ENDIAN | ||
320 | bitpos = i*8; | ||
321 | #else /* __BIG_ENDIAN */ | ||
322 | bitpos = (map_bankwidth(map)-1-i)*8; | ||
323 | #endif | ||
324 | orig.x[0] &= ~(0xff << bitpos); | ||
325 | orig.x[0] |= buf[i-start] << bitpos; | ||
326 | } | ||
327 | } | ||
328 | return orig; | ||
329 | } | ||
330 | |||
331 | static inline map_word map_word_ff(struct map_info *map) | ||
332 | { | ||
333 | map_word r; | ||
334 | int i; | ||
335 | |||
336 | for (i=0; i<map_words(map); i++) { | ||
337 | r.x[i] = ~0UL; | ||
338 | } | ||
339 | return r; | ||
340 | } | ||
341 | static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) | ||
342 | { | ||
343 | map_word r; | ||
344 | |||
345 | if (map_bankwidth_is_1(map)) | ||
346 | r.x[0] = __raw_readb(map->virt + ofs); | ||
347 | else if (map_bankwidth_is_2(map)) | ||
348 | r.x[0] = __raw_readw(map->virt + ofs); | ||
349 | else if (map_bankwidth_is_4(map)) | ||
350 | r.x[0] = __raw_readl(map->virt + ofs); | ||
351 | #if BITS_PER_LONG >= 64 | ||
352 | else if (map_bankwidth_is_8(map)) | ||
353 | r.x[0] = __raw_readq(map->virt + ofs); | ||
354 | #endif | ||
355 | else if (map_bankwidth_is_large(map)) | ||
356 | memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); | ||
357 | |||
358 | return r; | ||
359 | } | ||
360 | |||
361 | static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs) | ||
362 | { | ||
363 | if (map_bankwidth_is_1(map)) | ||
364 | __raw_writeb(datum.x[0], map->virt + ofs); | ||
365 | else if (map_bankwidth_is_2(map)) | ||
366 | __raw_writew(datum.x[0], map->virt + ofs); | ||
367 | else if (map_bankwidth_is_4(map)) | ||
368 | __raw_writel(datum.x[0], map->virt + ofs); | ||
369 | #if BITS_PER_LONG >= 64 | ||
370 | else if (map_bankwidth_is_8(map)) | ||
371 | __raw_writeq(datum.x[0], map->virt + ofs); | ||
372 | #endif | ||
373 | else if (map_bankwidth_is_large(map)) | ||
374 | memcpy_toio(map->virt+ofs, datum.x, map->bankwidth); | ||
375 | mb(); | ||
376 | } | ||
377 | |||
378 | static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) | ||
379 | { | ||
380 | if (map->cached) | ||
381 | memcpy(to, (char *)map->cached + from, len); | ||
382 | else | ||
383 | memcpy_fromio(to, map->virt + from, len); | ||
384 | } | ||
385 | |||
386 | static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) | ||
387 | { | ||
388 | memcpy_toio(map->virt + to, from, len); | ||
389 | } | ||
390 | |||
391 | #ifdef CONFIG_MTD_COMPLEX_MAPPINGS | ||
392 | #define map_read(map, ofs) (map)->read(map, ofs) | ||
393 | #define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) | ||
394 | #define map_write(map, datum, ofs) (map)->write(map, datum, ofs) | ||
395 | #define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) | ||
396 | |||
397 | extern void simple_map_init(struct map_info *); | ||
398 | #define map_is_linear(map) (map->phys != NO_XIP) | ||
399 | |||
400 | #else | ||
401 | #define map_read(map, ofs) inline_map_read(map, ofs) | ||
402 | #define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len) | ||
403 | #define map_write(map, datum, ofs) inline_map_write(map, datum, ofs) | ||
404 | #define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len) | ||
405 | |||
406 | |||
407 | #define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) | ||
408 | #define map_is_linear(map) (1) | ||
409 | |||
410 | #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ | ||
411 | |||
412 | #endif /* __LINUX_MTD_MAP_H__ */ | ||