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