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