at v2.6.35 12 kB view raw
1 2/* Overhauled routines for dealing with different mmap regions of flash */ 3 4#ifndef __LINUX_MTD_MAP_H__ 5#define __LINUX_MTD_MAP_H__ 6 7#include <linux/types.h> 8#include <linux/list.h> 9#include <linux/string.h> 10#include <linux/bug.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#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work" 129static inline int map_bankwidth(void *map) 130{ 131 BUG(); 132 return 0; 133} 134#define map_bankwidth_is_large(map) (0) 135#define map_words(map) (0) 136#define MAX_MAP_BANKWIDTH 1 137#endif 138 139static inline int map_bankwidth_supported(int w) 140{ 141 switch (w) { 142#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 143 case 1: 144#endif 145#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 146 case 2: 147#endif 148#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 149 case 4: 150#endif 151#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 152 case 8: 153#endif 154#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 155 case 16: 156#endif 157#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 158 case 32: 159#endif 160 return 1; 161 162 default: 163 return 0; 164 } 165} 166 167#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG ) 168 169typedef union { 170 unsigned long x[MAX_MAP_LONGS]; 171} map_word; 172 173/* The map stuff is very simple. You fill in your struct map_info with 174 a handful of routines for accessing the device, making sure they handle 175 paging etc. correctly if your device needs it. Then you pass it off 176 to a chip probe routine -- either JEDEC or CFI probe or both -- via 177 do_map_probe(). If a chip is recognised, the probe code will invoke the 178 appropriate chip driver (if present) and return a struct mtd_info. 179 At which point, you fill in the mtd->module with your own module 180 address, and register it with the MTD core code. Or you could partition 181 it and register the partitions instead, or keep it for your own private 182 use; whatever. 183 184 The mtd->priv field will point to the struct map_info, and any further 185 private data required by the chip driver is linked from the 186 mtd->priv->fldrv_priv field. This allows the map driver to get at 187 the destructor function map->fldrv_destroy() when it's tired 188 of living. 189*/ 190 191struct map_info { 192 const char *name; 193 unsigned long size; 194 resource_size_t phys; 195#define NO_XIP (-1UL) 196 197 void __iomem *virt; 198 void *cached; 199 200 int bankwidth; /* in octets. This isn't necessarily the width 201 of actual bus cycles -- it's the repeat interval 202 in bytes, before you are talking to the first chip again. 203 */ 204 205#ifdef CONFIG_MTD_COMPLEX_MAPPINGS 206 map_word (*read)(struct map_info *, unsigned long); 207 void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); 208 209 void (*write)(struct map_info *, const map_word, unsigned long); 210 void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); 211 212 /* We can perhaps put in 'point' and 'unpoint' methods, if we really 213 want to enable XIP for non-linear mappings. Not yet though. */ 214#endif 215 /* It's possible for the map driver to use cached memory in its 216 copy_from implementation (and _only_ with copy_from). However, 217 when the chip driver knows some flash area has changed contents, 218 it will signal it to the map driver through this routine to let 219 the map driver invalidate the corresponding cache as needed. 220 If there is no cache to care about this can be set to NULL. */ 221 void (*inval_cache)(struct map_info *, unsigned long, ssize_t); 222 223 /* set_vpp() must handle being reentered -- enable, enable, disable 224 must leave it enabled. */ 225 void (*set_vpp)(struct map_info *, int); 226 227 unsigned long pfow_base; 228 unsigned long map_priv_1; 229 unsigned long map_priv_2; 230 void *fldrv_priv; 231 struct mtd_chip_driver *fldrv; 232}; 233 234struct mtd_chip_driver { 235 struct mtd_info *(*probe)(struct map_info *map); 236 void (*destroy)(struct mtd_info *); 237 struct module *module; 238 char *name; 239 struct list_head list; 240}; 241 242void register_mtd_chip_driver(struct mtd_chip_driver *); 243void unregister_mtd_chip_driver(struct mtd_chip_driver *); 244 245struct mtd_info *do_map_probe(const char *name, struct map_info *map); 246void map_destroy(struct mtd_info *mtd); 247 248#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) 249#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) 250 251#define INVALIDATE_CACHED_RANGE(map, from, size) \ 252 do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) 253 254 255static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) 256{ 257 int i; 258 for (i=0; i<map_words(map); i++) { 259 if (val1.x[i] != val2.x[i]) 260 return 0; 261 } 262 return 1; 263} 264 265static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2) 266{ 267 map_word r; 268 int i; 269 270 for (i=0; i<map_words(map); i++) { 271 r.x[i] = val1.x[i] & val2.x[i]; 272 } 273 return r; 274} 275 276static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2) 277{ 278 map_word r; 279 int i; 280 281 for (i=0; i<map_words(map); i++) { 282 r.x[i] = val1.x[i] & ~val2.x[i]; 283 } 284 return r; 285} 286 287static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) 288{ 289 map_word r; 290 int i; 291 292 for (i=0; i<map_words(map); i++) { 293 r.x[i] = val1.x[i] | val2.x[i]; 294 } 295 return r; 296} 297 298#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) 299 300static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) 301{ 302 int i; 303 304 for (i=0; i<map_words(map); i++) { 305 if (val1.x[i] & val2.x[i]) 306 return 1; 307 } 308 return 0; 309} 310 311static inline map_word map_word_load(struct map_info *map, const void *ptr) 312{ 313 map_word r; 314 315 if (map_bankwidth_is_1(map)) 316 r.x[0] = *(unsigned char *)ptr; 317 else if (map_bankwidth_is_2(map)) 318 r.x[0] = get_unaligned((uint16_t *)ptr); 319 else if (map_bankwidth_is_4(map)) 320 r.x[0] = get_unaligned((uint32_t *)ptr); 321#if BITS_PER_LONG >= 64 322 else if (map_bankwidth_is_8(map)) 323 r.x[0] = get_unaligned((uint64_t *)ptr); 324#endif 325 else if (map_bankwidth_is_large(map)) 326 memcpy(r.x, ptr, map->bankwidth); 327 328 return r; 329} 330 331static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len) 332{ 333 int i; 334 335 if (map_bankwidth_is_large(map)) { 336 char *dest = (char *)&orig; 337 memcpy(dest+start, buf, len); 338 } else { 339 for (i=start; i < start+len; i++) { 340 int bitpos; 341#ifdef __LITTLE_ENDIAN 342 bitpos = i*8; 343#else /* __BIG_ENDIAN */ 344 bitpos = (map_bankwidth(map)-1-i)*8; 345#endif 346 orig.x[0] &= ~(0xff << bitpos); 347 orig.x[0] |= buf[i-start] << bitpos; 348 } 349 } 350 return orig; 351} 352 353#if BITS_PER_LONG < 64 354#define MAP_FF_LIMIT 4 355#else 356#define MAP_FF_LIMIT 8 357#endif 358 359static inline map_word map_word_ff(struct map_info *map) 360{ 361 map_word r; 362 int i; 363 364 if (map_bankwidth(map) < MAP_FF_LIMIT) { 365 int bw = 8 * map_bankwidth(map); 366 r.x[0] = (1 << bw) - 1; 367 } else { 368 for (i=0; i<map_words(map); i++) 369 r.x[i] = ~0UL; 370 } 371 return r; 372} 373 374static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) 375{ 376 map_word r; 377 378 if (map_bankwidth_is_1(map)) 379 r.x[0] = __raw_readb(map->virt + ofs); 380 else if (map_bankwidth_is_2(map)) 381 r.x[0] = __raw_readw(map->virt + ofs); 382 else if (map_bankwidth_is_4(map)) 383 r.x[0] = __raw_readl(map->virt + ofs); 384#if BITS_PER_LONG >= 64 385 else if (map_bankwidth_is_8(map)) 386 r.x[0] = __raw_readq(map->virt + ofs); 387#endif 388 else if (map_bankwidth_is_large(map)) 389 memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); 390 else 391 BUG(); 392 393 return r; 394} 395 396static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs) 397{ 398 if (map_bankwidth_is_1(map)) 399 __raw_writeb(datum.x[0], map->virt + ofs); 400 else if (map_bankwidth_is_2(map)) 401 __raw_writew(datum.x[0], map->virt + ofs); 402 else if (map_bankwidth_is_4(map)) 403 __raw_writel(datum.x[0], map->virt + ofs); 404#if BITS_PER_LONG >= 64 405 else if (map_bankwidth_is_8(map)) 406 __raw_writeq(datum.x[0], map->virt + ofs); 407#endif 408 else if (map_bankwidth_is_large(map)) 409 memcpy_toio(map->virt+ofs, datum.x, map->bankwidth); 410 mb(); 411} 412 413static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 414{ 415 if (map->cached) 416 memcpy(to, (char *)map->cached + from, len); 417 else 418 memcpy_fromio(to, map->virt + from, len); 419} 420 421static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 422{ 423 memcpy_toio(map->virt + to, from, len); 424} 425 426#ifdef CONFIG_MTD_COMPLEX_MAPPINGS 427#define map_read(map, ofs) (map)->read(map, ofs) 428#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) 429#define map_write(map, datum, ofs) (map)->write(map, datum, ofs) 430#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) 431 432extern void simple_map_init(struct map_info *); 433#define map_is_linear(map) (map->phys != NO_XIP) 434 435#else 436#define map_read(map, ofs) inline_map_read(map, ofs) 437#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len) 438#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs) 439#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len) 440 441 442#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) 443#define map_is_linear(map) ({ (void)(map); 1; }) 444 445#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ 446 447#endif /* __LINUX_MTD_MAP_H__ */