| 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 <asm/system.h> |
|---|
| 9 | #include <asm/io.h> |
|---|
| 10 | |
|---|
| 11 | /* The map stuff is very simple. You fill in your struct map_info with |
|---|
| 12 | a handful of routines for accessing the device, making sure they handle |
|---|
| 13 | paging etc. correctly if your device needs it. Then you pass it off |
|---|
| 14 | to a chip driver which deals with a mapped device - generally either |
|---|
| 15 | do_cfi_probe() or do_ram_probe(), either of which will return a |
|---|
| 16 | struct mtd_info if they liked what they saw. At which point, you |
|---|
| 17 | fill in the mtd->module with your own module address, and register |
|---|
| 18 | it. |
|---|
| 19 | |
|---|
| 20 | The mtd->priv field will point to the struct map_info, and any further |
|---|
| 21 | private data required by the chip driver is linked from the |
|---|
| 22 | mtd->priv->fldrv_priv field. This allows the map driver to get at |
|---|
| 23 | the destructor function map->fldrv_destroy() when it's tired |
|---|
| 24 | of living. |
|---|
| 25 | */ |
|---|
| 26 | |
|---|
| 27 | struct map_info { |
|---|
| 28 | char *name; |
|---|
| 29 | unsigned long size; |
|---|
| 30 | unsigned long phys; |
|---|
| 31 | #define NO_XIP (-1UL) |
|---|
| 32 | |
|---|
| 33 | void *virt; |
|---|
| 34 | void *cached; |
|---|
| 35 | |
|---|
| 36 | int buswidth; /* in octets */ |
|---|
| 37 | |
|---|
| 38 | #ifdef CONFIG_MTD_COMPLEX_MAPPINGS |
|---|
| 39 | __u8 (*read8)(struct map_info *, unsigned long); |
|---|
| 40 | __u16 (*read16)(struct map_info *, unsigned long); |
|---|
| 41 | __u32 (*read32)(struct map_info *, unsigned long); |
|---|
| 42 | __u64 (*read64)(struct map_info *, unsigned long); |
|---|
| 43 | /* If it returned a 'long' I'd call it readl. |
|---|
| 44 | * It doesn't. |
|---|
| 45 | * I won't. |
|---|
| 46 | * dwmw2 */ |
|---|
| 47 | |
|---|
| 48 | void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); |
|---|
| 49 | void (*write8)(struct map_info *, __u8, unsigned long); |
|---|
| 50 | void (*write16)(struct map_info *, __u16, unsigned long); |
|---|
| 51 | void (*write32)(struct map_info *, __u32, unsigned long); |
|---|
| 52 | void (*write64)(struct map_info *, __u64, unsigned long); |
|---|
| 53 | void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); |
|---|
| 54 | |
|---|
| 55 | /* We can perhaps put in 'point' and 'unpoint' methods, if we really |
|---|
| 56 | want to enable XIP for non-linear mappings. Not yet though. */ |
|---|
| 57 | #endif |
|---|
| 58 | /* set_vpp() must handle being reentered -- enable, enable, disable |
|---|
| 59 | must leave it enabled. */ |
|---|
| 60 | void (*set_vpp)(struct map_info *, int); |
|---|
| 61 | |
|---|
| 62 | unsigned long map_priv_1; |
|---|
| 63 | unsigned long map_priv_2; |
|---|
| 64 | void *fldrv_priv; |
|---|
| 65 | struct mtd_chip_driver *fldrv; |
|---|
| 66 | }; |
|---|
| 67 | |
|---|
| 68 | struct mtd_chip_driver { |
|---|
| 69 | struct mtd_info *(*probe)(struct map_info *map); |
|---|
| 70 | void (*destroy)(struct mtd_info *); |
|---|
| 71 | struct module *module; |
|---|
| 72 | char *name; |
|---|
| 73 | struct list_head list; |
|---|
| 74 | }; |
|---|
| 75 | |
|---|
| 76 | void register_mtd_chip_driver(struct mtd_chip_driver *); |
|---|
| 77 | void unregister_mtd_chip_driver(struct mtd_chip_driver *); |
|---|
| 78 | |
|---|
| 79 | struct mtd_info *do_map_probe(const char *name, struct map_info *map); |
|---|
| 80 | void map_destroy(struct mtd_info *mtd); |
|---|
| 81 | |
|---|
| 82 | #define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) |
|---|
| 83 | #define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) |
|---|
| 84 | |
|---|
| 85 | #define INVALIDATE_CACHED_RANGE(map, from, size) \ |
|---|
| 86 | do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) |
|---|
| 87 | |
|---|
| 88 | |
|---|
| 89 | static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) |
|---|
| 90 | { |
|---|
| 91 | int i; |
|---|
| 92 | for (i=0; i<map_words(map); i++) { |
|---|
| 93 | if (val1.x[i] != val2.x[i]) |
|---|
| 94 | return 0; |
|---|
| 95 | } |
|---|
| 96 | return 1; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2) |
|---|
| 100 | { |
|---|
| 101 | map_word r; |
|---|
| 102 | int i; |
|---|
| 103 | |
|---|
| 104 | for (i=0; i<map_words(map); i++) { |
|---|
| 105 | r.x[i] = val1.x[i] & val2.x[i]; |
|---|
| 106 | } |
|---|
| 107 | return r; |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) |
|---|
| 111 | { |
|---|
| 112 | map_word r; |
|---|
| 113 | int i; |
|---|
| 114 | |
|---|
| 115 | for (i=0; i<map_words(map); i++) { |
|---|
| 116 | r.x[i] = val1.x[i] | val2.x[i]; |
|---|
| 117 | } |
|---|
| 118 | return r; |
|---|
| 119 | } |
|---|
| 120 | #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) |
|---|
| 121 | |
|---|
| 122 | static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) |
|---|
| 123 | { |
|---|
| 124 | int i; |
|---|
| 125 | |
|---|
| 126 | for (i=0; i<map_words(map); i++) { |
|---|
| 127 | if (val1.x[i] & val2.x[i]) |
|---|
| 128 | return 1; |
|---|
| 129 | } |
|---|
| 130 | return 0; |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | static inline map_word map_word_load(struct map_info *map, const void *ptr) |
|---|
| 134 | { |
|---|
| 135 | map_word r; |
|---|
| 136 | |
|---|
| 137 | if (map_bankwidth_is_1(map)) |
|---|
| 138 | r.x[0] = *(unsigned char *)ptr; |
|---|
| 139 | else if (map_bankwidth_is_2(map)) |
|---|
| 140 | r.x[0] = get_unaligned((uint16_t *)ptr); |
|---|
| 141 | else if (map_bankwidth_is_4(map)) |
|---|
| 142 | r.x[0] = get_unaligned((uint32_t *)ptr); |
|---|
| 143 | #if BITS_PER_LONG >= 64 |
|---|
| 144 | else if (map_bankwidth_is_8(map)) |
|---|
| 145 | r.x[0] = get_unaligned((uint64_t *)ptr); |
|---|
| 146 | #endif |
|---|
| 147 | else if (map_bankwidth_is_large(map)) |
|---|
| 148 | memcpy(r.x, ptr, map->bankwidth); |
|---|
| 149 | |
|---|
| 150 | return r; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len) |
|---|
| 154 | { |
|---|
| 155 | int i; |
|---|
| 156 | |
|---|
| 157 | if (map_bankwidth_is_large(map)) { |
|---|
| 158 | char *dest = (char *)&orig; |
|---|
| 159 | memcpy(dest+start, buf, len); |
|---|
| 160 | } else { |
|---|
| 161 | for (i=start; i < start+len; i++) { |
|---|
| 162 | int bitpos; |
|---|
| 163 | #ifdef __LITTLE_ENDIAN |
|---|
| 164 | bitpos = i*8; |
|---|
| 165 | #else /* __BIG_ENDIAN */ |
|---|
| 166 | bitpos = (map_bankwidth(map)-1-i)*8; |
|---|
| 167 | #endif |
|---|
| 168 | orig.x[0] &= ~(0xff << bitpos); |
|---|
| 169 | orig.x[0] |= buf[i-start] << bitpos; |
|---|
| 170 | } |
|---|
| 171 | } |
|---|
| 172 | return orig; |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | static inline map_word map_word_ff(struct map_info *map) |
|---|
| 176 | { |
|---|
| 177 | map_word r; |
|---|
| 178 | int i; |
|---|
| 179 | |
|---|
| 180 | for (i=0; i<map_words(map); i++) { |
|---|
| 181 | r.x[i] = ~0UL; |
|---|
| 182 | } |
|---|
| 183 | return r; |
|---|
| 184 | } |
|---|
| 185 | static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) |
|---|
| 186 | { |
|---|
| 187 | map_word r; |
|---|
| 188 | |
|---|
| 189 | if (map_bankwidth_is_1(map)) |
|---|
| 190 | r.x[0] = __raw_readb(map->virt + ofs); |
|---|
| 191 | else if (map_bankwidth_is_2(map)) |
|---|
| 192 | r.x[0] = __raw_readw(map->virt + ofs); |
|---|
| 193 | else if (map_bankwidth_is_4(map)) |
|---|
| 194 | r.x[0] = __raw_readl(map->virt + ofs); |
|---|
| 195 | #if BITS_PER_LONG >= 64 |
|---|
| 196 | else if (map_bankwidth_is_8(map)) |
|---|
| 197 | r.x[0] = __raw_readq(map->virt + ofs); |
|---|
| 198 | #endif |
|---|
| 199 | else if (map_bankwidth_is_large(map)) |
|---|
| 200 | memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); |
|---|
| 201 | |
|---|
| 202 | return r; |
|---|
| 203 | } |
|---|
| 204 | |
|---|
| 205 | static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs) |
|---|
| 206 | { |
|---|
| 207 | if (map_bankwidth_is_1(map)) |
|---|
| 208 | __raw_writeb(datum.x[0], map->virt + ofs); |
|---|
| 209 | else if (map_bankwidth_is_2(map)) |
|---|
| 210 | __raw_writew(datum.x[0], map->virt + ofs); |
|---|
| 211 | else if (map_bankwidth_is_4(map)) |
|---|
| 212 | __raw_writel(datum.x[0], map->virt + ofs); |
|---|
| 213 | #if BITS_PER_LONG >= 64 |
|---|
| 214 | else if (map_bankwidth_is_8(map)) |
|---|
| 215 | __raw_writeq(datum.x[0], map->virt + ofs); |
|---|
| 216 | #endif |
|---|
| 217 | else if (map_bankwidth_is_large(map)) |
|---|
| 218 | memcpy_toio(map->virt+ofs, datum.x, map->bankwidth); |
|---|
| 219 | mb(); |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) |
|---|
| 223 | { |
|---|
| 224 | if (map->cached) |
|---|
| 225 | memcpy(to, (char *)map->cached + from, len); |
|---|
| 226 | else |
|---|
| 227 | memcpy_fromio(to, map->virt + from, len); |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
|---|
| 231 | { |
|---|
| 232 | memcpy_toio(map->virt + to, from, len); |
|---|
| 233 | } |
|---|
| 234 | |
|---|
| 235 | #ifdef CONFIG_MTD_COMPLEX_MAPPINGS |
|---|
| 236 | #define map_read(map, ofs) (map)->read(map, ofs) |
|---|
| 237 | #define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) |
|---|
| 238 | #define map_write(map, datum, ofs) (map)->write(map, datum, ofs) |
|---|
| 239 | #define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) |
|---|
| 240 | |
|---|
| 241 | extern void simple_map_init(struct map_info *); |
|---|
| 242 | #define map_is_linear(map) (map->phys != NO_XIP) |
|---|
| 243 | |
|---|
| 244 | #else |
|---|
| 245 | #define map_read(map, ofs) inline_map_read(map, ofs) |
|---|
| 246 | #define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len) |
|---|
| 247 | #define map_write(map, datum, ofs) inline_map_write(map, datum, ofs) |
|---|
| 248 | #define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len) |
|---|
| 249 | |
|---|
| 250 | |
|---|
| 251 | #define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) |
|---|
| 252 | #define map_is_linear(map) (1) |
|---|
| 253 | |
|---|
| 254 | #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ |
|---|
| 255 | |
|---|
| 256 | #endif /* __LINUX_MTD_MAP_H__ */ |
|---|