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