Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al.
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify
5 : : * it under the terms of the GNU General Public License as published by
6 : : * the Free Software Foundation; either version 2 of the License, or
7 : : * (at your option) any later version.
8 : : *
9 : : * This program is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU General Public License
15 : : * along with this program; if not, write to the Free Software
16 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 : : *
18 : : */
19 : :
20 : : /* Overhauled routines for dealing with different mmap regions of flash */
21 : :
22 : : #ifndef __LINUX_MTD_MAP_H__
23 : : #define __LINUX_MTD_MAP_H__
24 : :
25 : : #include <linux/types.h>
26 : : #include <linux/list.h>
27 : : #include <linux/string.h>
28 : : #include <linux/bug.h>
29 : : #include <linux/kernel.h>
30 : :
31 : : #include <asm/unaligned.h>
32 : : #include <asm/io.h>
33 : : #include <asm/barrier.h>
34 : :
35 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
36 : : #define map_bankwidth(map) 1
37 : : #define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
38 : : #define map_bankwidth_is_large(map) (0)
39 : : #define map_words(map) (1)
40 : : #define MAX_MAP_BANKWIDTH 1
41 : : #else
42 : : #define map_bankwidth_is_1(map) (0)
43 : : #endif
44 : :
45 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
46 : : # ifdef map_bankwidth
47 : : # undef map_bankwidth
48 : : # define map_bankwidth(map) ((map)->bankwidth)
49 : : # else
50 : : # define map_bankwidth(map) 2
51 : : # define map_bankwidth_is_large(map) (0)
52 : : # define map_words(map) (1)
53 : : # endif
54 : : #define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
55 : : #undef MAX_MAP_BANKWIDTH
56 : : #define MAX_MAP_BANKWIDTH 2
57 : : #else
58 : : #define map_bankwidth_is_2(map) (0)
59 : : #endif
60 : :
61 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
62 : : # ifdef map_bankwidth
63 : : # undef map_bankwidth
64 : : # define map_bankwidth(map) ((map)->bankwidth)
65 : : # else
66 : : # define map_bankwidth(map) 4
67 : : # define map_bankwidth_is_large(map) (0)
68 : : # define map_words(map) (1)
69 : : # endif
70 : : #define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
71 : : #undef MAX_MAP_BANKWIDTH
72 : : #define MAX_MAP_BANKWIDTH 4
73 : : #else
74 : : #define map_bankwidth_is_4(map) (0)
75 : : #endif
76 : :
77 : : /* ensure we never evaluate anything shorted than an unsigned long
78 : : * to zero, and ensure we'll never miss the end of an comparison (bjd) */
79 : :
80 : : #define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long))
81 : :
82 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
83 : : # ifdef map_bankwidth
84 : : # undef map_bankwidth
85 : : # define map_bankwidth(map) ((map)->bankwidth)
86 : : # if BITS_PER_LONG < 64
87 : : # undef map_bankwidth_is_large
88 : : # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
89 : : # undef map_words
90 : : # define map_words(map) map_calc_words(map)
91 : : # endif
92 : : # else
93 : : # define map_bankwidth(map) 8
94 : : # define map_bankwidth_is_large(map) (BITS_PER_LONG < 64)
95 : : # define map_words(map) map_calc_words(map)
96 : : # endif
97 : : #define map_bankwidth_is_8(map) (map_bankwidth(map) == 8)
98 : : #undef MAX_MAP_BANKWIDTH
99 : : #define MAX_MAP_BANKWIDTH 8
100 : : #else
101 : : #define map_bankwidth_is_8(map) (0)
102 : : #endif
103 : :
104 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
105 : : # ifdef map_bankwidth
106 : : # undef map_bankwidth
107 : : # define map_bankwidth(map) ((map)->bankwidth)
108 : : # undef map_bankwidth_is_large
109 : : # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
110 : : # undef map_words
111 : : # define map_words(map) map_calc_words(map)
112 : : # else
113 : : # define map_bankwidth(map) 16
114 : : # define map_bankwidth_is_large(map) (1)
115 : : # define map_words(map) map_calc_words(map)
116 : : # endif
117 : : #define map_bankwidth_is_16(map) (map_bankwidth(map) == 16)
118 : : #undef MAX_MAP_BANKWIDTH
119 : : #define MAX_MAP_BANKWIDTH 16
120 : : #else
121 : : #define map_bankwidth_is_16(map) (0)
122 : : #endif
123 : :
124 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
125 : : # ifdef map_bankwidth
126 : : # undef map_bankwidth
127 : : # define map_bankwidth(map) ((map)->bankwidth)
128 : : # undef map_bankwidth_is_large
129 : : # define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
130 : : # undef map_words
131 : : # define map_words(map) map_calc_words(map)
132 : : # else
133 : : # define map_bankwidth(map) 32
134 : : # define map_bankwidth_is_large(map) (1)
135 : : # define map_words(map) map_calc_words(map)
136 : : # endif
137 : : #define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
138 : : #undef MAX_MAP_BANKWIDTH
139 : : #define MAX_MAP_BANKWIDTH 32
140 : : #else
141 : : #define map_bankwidth_is_32(map) (0)
142 : : #endif
143 : :
144 : : #ifndef map_bankwidth
145 : : #warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
146 : : static inline int map_bankwidth(void *map)
147 : : {
148 : : BUG();
149 : : return 0;
150 : : }
151 : : #define map_bankwidth_is_large(map) (0)
152 : : #define map_words(map) (0)
153 : : #define MAX_MAP_BANKWIDTH 1
154 : : #endif
155 : :
156 : : static inline int map_bankwidth_supported(int w)
157 : : {
158 : : switch (w) {
159 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
160 : : case 1:
161 : : #endif
162 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
163 : : case 2:
164 : : #endif
165 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
166 : : case 4:
167 : : #endif
168 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
169 : : case 8:
170 : : #endif
171 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
172 : : case 16:
173 : : #endif
174 : : #ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
175 : : case 32:
176 : : #endif
177 : : return 1;
178 : :
179 : : default:
180 : : return 0;
181 : : }
182 : : }
183 : :
184 : : #define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
185 : :
186 : : typedef union {
187 : : unsigned long x[MAX_MAP_LONGS];
188 : : } map_word;
189 : :
190 : : /* The map stuff is very simple. You fill in your struct map_info with
191 : : a handful of routines for accessing the device, making sure they handle
192 : : paging etc. correctly if your device needs it. Then you pass it off
193 : : to a chip probe routine -- either JEDEC or CFI probe or both -- via
194 : : do_map_probe(). If a chip is recognised, the probe code will invoke the
195 : : appropriate chip driver (if present) and return a struct mtd_info.
196 : : At which point, you fill in the mtd->module with your own module
197 : : address, and register it with the MTD core code. Or you could partition
198 : : it and register the partitions instead, or keep it for your own private
199 : : use; whatever.
200 : :
201 : : The mtd->priv field will point to the struct map_info, and any further
202 : : private data required by the chip driver is linked from the
203 : : mtd->priv->fldrv_priv field. This allows the map driver to get at
204 : : the destructor function map->fldrv_destroy() when it's tired
205 : : of living.
206 : : */
207 : :
208 : : struct map_info {
209 : : const char *name;
210 : : unsigned long size;
211 : : resource_size_t phys;
212 : : #define NO_XIP (-1UL)
213 : :
214 : : void __iomem *virt;
215 : : void *cached;
216 : :
217 : : int swap; /* this mapping's byte-swapping requirement */
218 : : int bankwidth; /* in octets. This isn't necessarily the width
219 : : of actual bus cycles -- it's the repeat interval
220 : : in bytes, before you are talking to the first chip again.
221 : : */
222 : :
223 : : #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
224 : : map_word (*read)(struct map_info *, unsigned long);
225 : : void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
226 : :
227 : : void (*write)(struct map_info *, const map_word, unsigned long);
228 : : void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
229 : :
230 : : /* We can perhaps put in 'point' and 'unpoint' methods, if we really
231 : : want to enable XIP for non-linear mappings. Not yet though. */
232 : : #endif
233 : : /* It's possible for the map driver to use cached memory in its
234 : : copy_from implementation (and _only_ with copy_from). However,
235 : : when the chip driver knows some flash area has changed contents,
236 : : it will signal it to the map driver through this routine to let
237 : : the map driver invalidate the corresponding cache as needed.
238 : : If there is no cache to care about this can be set to NULL. */
239 : : void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
240 : :
241 : : /* set_vpp() must handle being reentered -- enable, enable, disable
242 : : must leave it enabled. */
243 : : void (*set_vpp)(struct map_info *, int);
244 : :
245 : : unsigned long pfow_base;
246 : : unsigned long map_priv_1;
247 : : unsigned long map_priv_2;
248 : : struct device_node *device_node;
249 : : void *fldrv_priv;
250 : : struct mtd_chip_driver *fldrv;
251 : : };
252 : :
253 : : struct mtd_chip_driver {
254 : : struct mtd_info *(*probe)(struct map_info *map);
255 : : void (*destroy)(struct mtd_info *);
256 : : struct module *module;
257 : : char *name;
258 : : struct list_head list;
259 : : };
260 : :
261 : : void register_mtd_chip_driver(struct mtd_chip_driver *);
262 : : void unregister_mtd_chip_driver(struct mtd_chip_driver *);
263 : :
264 : : struct mtd_info *do_map_probe(const char *name, struct map_info *map);
265 : : void map_destroy(struct mtd_info *mtd);
266 : :
267 : : #define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
268 : : #define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
269 : :
270 : : #define INVALIDATE_CACHED_RANGE(map, from, size) \
271 : : do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
272 : :
273 : :
274 : : static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
275 : : {
276 : : int i;
277 [ # # ][ # # ]: 0 : for (i=0; i<map_words(map); i++) {
[ # # ][ # # ]
278 [ # # ][ # # ]: 0 : if (val1.x[i] != val2.x[i])
[ # # ][ # # ]
279 : : return 0;
280 : : }
281 : : return 1;
282 : : }
283 : :
284 : : static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
285 : : {
286 : : map_word r;
287 : : int i;
288 : :
289 [ # # ][ # # ]: 0 : for (i=0; i<map_words(map); i++) {
[ # # ][ # # ]
290 : 0 : r.x[i] = val1.x[i] & val2.x[i];
291 : : }
292 : : return r;
293 : : }
294 : :
295 : : static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
296 : : {
297 : : map_word r;
298 : : int i;
299 : :
300 : : for (i=0; i<map_words(map); i++) {
301 : : r.x[i] = val1.x[i] & ~val2.x[i];
302 : : }
303 : : return r;
304 : : }
305 : :
306 : : static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
307 : : {
308 : : map_word r;
309 : : int i;
310 : :
311 : : for (i=0; i<map_words(map); i++) {
312 : : r.x[i] = val1.x[i] | val2.x[i];
313 : : }
314 : : return r;
315 : : }
316 : :
317 : : #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
318 : :
319 : : static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
320 : : {
321 : : int i;
322 : :
323 [ # # ][ # # ]: 0 : for (i=0; i<map_words(map); i++) {
[ # # ][ # # ]
324 [ # # ][ # # ]: 0 : if (val1.x[i] & val2.x[i])
[ # # ][ # # ]
325 : : return 1;
326 : : }
327 : : return 0;
328 : : }
329 : :
330 : : static inline map_word map_word_load(struct map_info *map, const void *ptr)
331 : : {
332 : : map_word r;
333 : :
334 [ # # ]: 0 : if (map_bankwidth_is_1(map))
335 : 0 : r.x[0] = *(unsigned char *)ptr;
336 [ # # ]: 0 : else if (map_bankwidth_is_2(map))
337 : 0 : r.x[0] = get_unaligned((uint16_t *)ptr);
338 [ # # ]: 0 : else if (map_bankwidth_is_4(map))
339 : : r.x[0] = get_unaligned((uint32_t *)ptr);
340 : : #if BITS_PER_LONG >= 64
341 : : else if (map_bankwidth_is_8(map))
342 : : r.x[0] = get_unaligned((uint64_t *)ptr);
343 : : #endif
344 : : else if (map_bankwidth_is_large(map))
345 : : memcpy(r.x, ptr, map->bankwidth);
346 : : else
347 : 0 : BUG();
348 : :
349 : : return r;
350 : : }
351 : :
352 : : static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len)
353 : : {
354 : : int i;
355 : :
356 : : if (map_bankwidth_is_large(map)) {
357 : : char *dest = (char *)&orig;
358 : : memcpy(dest+start, buf, len);
359 : : } else {
360 [ # # ][ # # ]: 0 : for (i=start; i < start+len; i++) {
[ # # ]
361 : : int bitpos;
362 : : #ifdef __LITTLE_ENDIAN
363 : 0 : bitpos = i*8;
364 : : #else /* __BIG_ENDIAN */
365 : : bitpos = (map_bankwidth(map)-1-i)*8;
366 : : #endif
367 : 0 : orig.x[0] &= ~(0xff << bitpos);
368 : 0 : orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
369 : : }
370 : : }
371 : : return orig;
372 : : }
373 : :
374 : : #if BITS_PER_LONG < 64
375 : : #define MAP_FF_LIMIT 4
376 : : #else
377 : : #define MAP_FF_LIMIT 8
378 : : #endif
379 : :
380 : : static inline map_word map_word_ff(struct map_info *map)
381 : : {
382 : : map_word r;
383 : : int i;
384 : :
385 [ # # ][ # # ]: 0 : if (map_bankwidth(map) < MAP_FF_LIMIT) {
[ # # ][ # # ]
386 : 0 : int bw = 8 * map_bankwidth(map);
387 : 0 : r.x[0] = (1UL << bw) - 1;
388 : : } else {
389 : : for (i=0; i<map_words(map); i++)
390 : : r.x[i] = ~0UL;
391 : : }
392 : : return r;
393 : : }
394 : :
395 : : static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
396 : : {
397 : : map_word r;
398 : :
399 [ # # ][ # # ]: 0 : if (map_bankwidth_is_1(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
400 : 0 : r.x[0] = readb_relaxed(map->virt + ofs);
401 [ # # ][ # # ]: 0 : else if (map_bankwidth_is_2(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
402 : 0 : r.x[0] = readw_relaxed(map->virt + ofs);
403 [ # # ][ # # ]: 0 : else if (map_bankwidth_is_4(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
404 : 0 : r.x[0] = readl_relaxed(map->virt + ofs);
405 : : #if BITS_PER_LONG >= 64
406 : : else if (map_bankwidth_is_8(map))
407 : : r.x[0] = __raw_readq(map->virt + ofs);
408 : : #endif
409 : : else if (map_bankwidth_is_large(map))
410 : : memcpy_fromio(r.x, map->virt+ofs, map->bankwidth);
411 : : else
412 : 0 : BUG();
413 : :
414 : : return r;
415 : : }
416 : :
417 : : static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
418 : : {
419 [ # # ][ # # ]: 0 : if (map_bankwidth_is_1(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
420 : 0 : writeb_relaxed(datum.x[0], map->virt + ofs);
421 [ # # ][ # # ]: 0 : else if (map_bankwidth_is_2(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
422 : 0 : writew_relaxed(datum.x[0], map->virt + ofs);
423 [ # # ][ # # ]: 0 : else if (map_bankwidth_is_4(map))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
424 : 0 : writel_relaxed(datum.x[0], map->virt + ofs);
425 : : #if BITS_PER_LONG >= 64
426 : : else if (map_bankwidth_is_8(map))
427 : : __raw_writeq(datum.x[0], map->virt + ofs);
428 : : #endif
429 : : else if (map_bankwidth_is_large(map))
430 : : memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
431 : : else
432 : 0 : BUG();
433 : 0 : mb();
434 : : }
435 : :
436 : : static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
437 : : {
438 [ # # ]: 0 : if (map->cached)
439 : 0 : memcpy(to, (char *)map->cached + from, len);
440 : : else
441 : 0 : memcpy_fromio(to, map->virt + from, len);
442 : : }
443 : :
444 : : static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
445 : : {
446 : : memcpy_toio(map->virt + to, from, len);
447 : : }
448 : :
449 : : #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
450 : : #define map_read(map, ofs) (map)->read(map, ofs)
451 : : #define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
452 : : #define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
453 : : #define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
454 : :
455 : : extern void simple_map_init(struct map_info *);
456 : : #define map_is_linear(map) (map->phys != NO_XIP)
457 : :
458 : : #else
459 : : #define map_read(map, ofs) inline_map_read(map, ofs)
460 : : #define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len)
461 : : #define map_write(map, datum, ofs) inline_map_write(map, datum, ofs)
462 : : #define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len)
463 : :
464 : :
465 : : #define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
466 : : #define map_is_linear(map) ({ (void)(map); 1; })
467 : :
468 : : #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
469 : :
470 : : #endif /* __LINUX_MTD_MAP_H__ */
|