1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <asm/io.h>
15#include <asm/byteorder.h>
16
17#include <linux/errno.h>
18#include <linux/slab.h>
19#include <linux/delay.h>
20#include <linux/interrupt.h>
21#include <linux/mtd/xip.h>
22#include <linux/mtd/mtd.h>
23#include <linux/mtd/map.h>
24#include <linux/mtd/cfi.h>
25
26int __xipram cfi_qry_present(struct map_info *map, __u32 base,
27 struct cfi_private *cfi)
28{
29 int osf = cfi->interleave * cfi->device_type;
30 map_word val[3];
31 map_word qry[3];
32
33 qry[0] = cfi_build_cmd('Q', map, cfi);
34 qry[1] = cfi_build_cmd('R', map, cfi);
35 qry[2] = cfi_build_cmd('Y', map, cfi);
36
37 val[0] = map_read(map, base + osf*0x10);
38 val[1] = map_read(map, base + osf*0x11);
39 val[2] = map_read(map, base + osf*0x12);
40
41 if (!map_word_equal(map, qry[0], val[0]))
42 return 0;
43
44 if (!map_word_equal(map, qry[1], val[1]))
45 return 0;
46
47 if (!map_word_equal(map, qry[2], val[2]))
48 return 0;
49
50 return 1;
51}
52EXPORT_SYMBOL_GPL(cfi_qry_present);
53
54int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
55 struct cfi_private *cfi)
56{
57 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
58 cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
59 if (cfi_qry_present(map, base, cfi))
60 return 1;
61
62
63 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
64 cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
65 cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
66 if (cfi_qry_present(map, base, cfi))
67 return 1;
68
69 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
70 cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
71 if (cfi_qry_present(map, base, cfi))
72 return 1;
73
74 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
75 cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
76 cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
77 cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
78 if (cfi_qry_present(map, base, cfi))
79 return 1;
80
81 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
82 cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL);
83 cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL);
84 cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
85 if (cfi_qry_present(map, base, cfi))
86 return 1;
87
88 return 0;
89}
90EXPORT_SYMBOL_GPL(cfi_qry_mode_on);
91
92void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
93 struct cfi_private *cfi)
94{
95 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
96 cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
97
98
99 if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E))
100 cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
101}
102EXPORT_SYMBOL_GPL(cfi_qry_mode_off);
103
104struct cfi_extquery *
105__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
106{
107 struct cfi_private *cfi = map->fldrv_priv;
108 __u32 base = 0;
109 int ofs_factor = cfi->interleave * cfi->device_type;
110 int i;
111 struct cfi_extquery *extp = NULL;
112
113 if (!adr)
114 goto out;
115
116 printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr);
117
118 extp = kmalloc(size, GFP_KERNEL);
119 if (!extp) {
120 printk(KERN_ERR "Failed to allocate memory\n");
121 goto out;
122 }
123
124#ifdef CONFIG_MTD_XIP
125 local_irq_disable();
126#endif
127
128
129 cfi_qry_mode_on(base, map, cfi);
130
131 for (i=0; i<size; i++) {
132 ((unsigned char *)extp)[i] =
133 cfi_read_query(map, base+((adr+i)*ofs_factor));
134 }
135
136
137 cfi_qry_mode_off(base, map, cfi);
138
139#ifdef CONFIG_MTD_XIP
140 (void) map_read(map, base);
141 xip_iprefetch();
142 local_irq_enable();
143#endif
144
145 out: return extp;
146}
147
148EXPORT_SYMBOL(cfi_read_pri);
149
150void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
151{
152 struct map_info *map = mtd->priv;
153 struct cfi_private *cfi = map->fldrv_priv;
154 struct cfi_fixup *f;
155
156 for (f=fixups; f->fixup; f++) {
157 if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
158 ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
159 f->fixup(mtd);
160 }
161 }
162}
163
164EXPORT_SYMBOL(cfi_fixup);
165
166int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
167 loff_t ofs, size_t len, void *thunk)
168{
169 struct map_info *map = mtd->priv;
170 struct cfi_private *cfi = map->fldrv_priv;
171 unsigned long adr;
172 int chipnum, ret = 0;
173 int i, first;
174 struct mtd_erase_region_info *regions = mtd->eraseregions;
175
176 if (ofs > mtd->size)
177 return -EINVAL;
178
179 if ((len + ofs) > mtd->size)
180 return -EINVAL;
181
182
183
184
185
186 i = 0;
187
188
189
190
191
192
193
194 while (i < mtd->numeraseregions && ofs >= regions[i].offset)
195 i++;
196 i--;
197
198
199
200
201
202
203
204 if (ofs & (regions[i].erasesize-1))
205 return -EINVAL;
206
207
208 first = i;
209
210
211
212
213
214 while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
215 i++;
216
217
218
219
220 i--;
221
222 if ((ofs + len) & (regions[i].erasesize-1))
223 return -EINVAL;
224
225 chipnum = ofs >> cfi->chipshift;
226 adr = ofs - (chipnum << cfi->chipshift);
227
228 i=first;
229
230 while(len) {
231 int size = regions[i].erasesize;
232
233 ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
234
235 if (ret)
236 return ret;
237
238 adr += size;
239 ofs += size;
240 len -= size;
241
242 if (ofs == regions[i].offset + size * regions[i].numblocks)
243 i++;
244
245 if (adr >> cfi->chipshift) {
246 adr = 0;
247 chipnum++;
248
249 if (chipnum >= cfi->numchips)
250 break;
251 }
252 }
253
254 return 0;
255}
256
257EXPORT_SYMBOL(cfi_varsize_frob);
258
259MODULE_LICENSE("GPL");
260