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