Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Routines common to all CFI-type probes. | |
3 | * (C) 2001-2003 Red Hat, Inc. | |
4 | * GPL'd | |
1da177e4 LT |
5 | */ |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/slab.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/mtd/mtd.h> | |
11 | #include <linux/mtd/map.h> | |
12 | #include <linux/mtd/cfi.h> | |
13 | #include <linux/mtd/gen_probe.h> | |
14 | ||
15 | static struct mtd_info *check_cmd_set(struct map_info *, int); | |
16 | static struct cfi_private *genprobe_ident_chips(struct map_info *map, | |
17 | struct chip_probe *cp); | |
18 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, | |
19 | struct cfi_private *cfi); | |
20 | ||
21 | struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) | |
22 | { | |
23 | struct mtd_info *mtd = NULL; | |
24 | struct cfi_private *cfi; | |
25 | ||
26 | /* First probe the map to see if we have CFI stuff there. */ | |
27 | cfi = genprobe_ident_chips(map, cp); | |
1f948b43 | 28 | |
1da177e4 LT |
29 | if (!cfi) |
30 | return NULL; | |
31 | ||
32 | map->fldrv_priv = cfi; | |
33 | /* OK we liked it. Now find a driver for the command set it talks */ | |
34 | ||
35 | mtd = check_cmd_set(map, 1); /* First the primary cmdset */ | |
36 | if (!mtd) | |
37 | mtd = check_cmd_set(map, 0); /* Then the secondary */ | |
1f948b43 | 38 | |
0f5ae3d2 DW |
39 | if (mtd) { |
40 | if (mtd->size > map->size) { | |
f6a673b3 | 41 | printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", |
c9ac5977 | 42 | (unsigned long)mtd->size >> 10, |
0f5ae3d2 DW |
43 | (unsigned long)map->size >> 10); |
44 | mtd->size = map->size; | |
45 | } | |
1da177e4 | 46 | return mtd; |
0f5ae3d2 | 47 | } |
1da177e4 LT |
48 | |
49 | printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); | |
1f948b43 | 50 | |
1da177e4 LT |
51 | kfree(cfi->cfiq); |
52 | kfree(cfi); | |
53 | map->fldrv_priv = NULL; | |
54 | return NULL; | |
55 | } | |
56 | EXPORT_SYMBOL(mtd_do_chip_probe); | |
57 | ||
58 | ||
59 | static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) | |
60 | { | |
61 | struct cfi_private cfi; | |
62 | struct cfi_private *retcfi; | |
63 | unsigned long *chip_map; | |
64 | int i, j, mapsize; | |
65 | int max_chips; | |
66 | ||
67 | memset(&cfi, 0, sizeof(cfi)); | |
68 | ||
1f948b43 | 69 | /* Call the probetype-specific code with all permutations of |
1da177e4 LT |
70 | interleave and device type, etc. */ |
71 | if (!genprobe_new_chip(map, cp, &cfi)) { | |
72 | /* The probe didn't like it */ | |
3a3688b6 JD |
73 | pr_debug("%s: Found no %s device at location zero\n", |
74 | cp->name, map->name); | |
1da177e4 | 75 | return NULL; |
1f948b43 | 76 | } |
1da177e4 LT |
77 | |
78 | #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD | |
79 | probe routines won't ever return a broken CFI structure anyway, | |
80 | because they make them up themselves. | |
81 | */ | |
82 | if (cfi.cfiq->NumEraseRegions == 0) { | |
83 | printk(KERN_WARNING "Number of erase regions is zero\n"); | |
84 | kfree(cfi.cfiq); | |
85 | return NULL; | |
86 | } | |
87 | #endif | |
88 | cfi.chipshift = cfi.cfiq->DevSize; | |
89 | ||
90 | if (cfi_interleave_is_1(&cfi)) { | |
91 | ; | |
92 | } else if (cfi_interleave_is_2(&cfi)) { | |
93 | cfi.chipshift++; | |
94 | } else if (cfi_interleave_is_4((&cfi))) { | |
95 | cfi.chipshift += 2; | |
96 | } else if (cfi_interleave_is_8(&cfi)) { | |
97 | cfi.chipshift += 3; | |
98 | } else { | |
99 | BUG(); | |
100 | } | |
1f948b43 | 101 | |
1da177e4 LT |
102 | cfi.numchips = 1; |
103 | ||
1f948b43 TG |
104 | /* |
105 | * Allocate memory for bitmap of valid chips. | |
106 | * Align bitmap storage size to full byte. | |
107 | */ | |
1da177e4 | 108 | max_chips = map->size >> cfi.chipshift; |
0f5ae3d2 DW |
109 | if (!max_chips) { |
110 | printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n"); | |
111 | max_chips = 1; | |
112 | } | |
113 | ||
c8872b06 | 114 | mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); |
95b93a0c | 115 | chip_map = kzalloc(mapsize, GFP_KERNEL); |
1da177e4 | 116 | if (!chip_map) { |
1da177e4 LT |
117 | kfree(cfi.cfiq); |
118 | return NULL; | |
119 | } | |
1da177e4 LT |
120 | |
121 | set_bit(0, chip_map); /* Mark first chip valid */ | |
122 | ||
123 | /* | |
124 | * Now probe for other chips, checking sensibly for aliases while | |
125 | * we're at it. The new_chip probe above should have let the first | |
126 | * chip in read mode. | |
127 | */ | |
128 | ||
129 | for (i = 1; i < max_chips; i++) { | |
130 | cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); | |
131 | } | |
132 | ||
133 | /* | |
1f948b43 | 134 | * Now allocate the space for the structures we need to return to |
1da177e4 LT |
135 | * our caller, and copy the appropriate data into them. |
136 | */ | |
137 | ||
138 | retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); | |
139 | ||
140 | if (!retcfi) { | |
1da177e4 LT |
141 | kfree(cfi.cfiq); |
142 | kfree(chip_map); | |
143 | return NULL; | |
144 | } | |
145 | ||
146 | memcpy(retcfi, &cfi, sizeof(cfi)); | |
147 | memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); | |
148 | ||
149 | for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { | |
150 | if(test_bit(i, chip_map)) { | |
151 | struct flchip *pchip = &retcfi->chips[j++]; | |
152 | ||
153 | pchip->start = (i << cfi.chipshift); | |
154 | pchip->state = FL_READY; | |
155 | init_waitqueue_head(&pchip->wq); | |
c4e77376 | 156 | mutex_init(&pchip->mutex); |
1da177e4 LT |
157 | } |
158 | } | |
159 | ||
160 | kfree(chip_map); | |
161 | return retcfi; | |
162 | } | |
163 | ||
1f948b43 | 164 | |
1da177e4 LT |
165 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, |
166 | struct cfi_private *cfi) | |
167 | { | |
168 | int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ | |
169 | int max_chips = map_bankwidth(map); /* And minimum 1 */ | |
170 | int nr_chips, type; | |
171 | ||
6170b434 | 172 | for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { |
1da177e4 LT |
173 | |
174 | if (!cfi_interleave_supported(nr_chips)) | |
175 | continue; | |
176 | ||
177 | cfi->interleave = nr_chips; | |
178 | ||
179 | /* Minimum device size. Don't look for one 8-bit device | |
180 | in a 16-bit bus, etc. */ | |
181 | type = map_bankwidth(map) / nr_chips; | |
182 | ||
183 | for (; type <= CFI_DEVICETYPE_X32; type<<=1) { | |
184 | cfi->device_type = type; | |
185 | ||
186 | if (cp->probe_chip(map, 0, NULL, cfi)) | |
187 | return 1; | |
188 | } | |
189 | } | |
190 | return 0; | |
191 | } | |
192 | ||
193 | typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); | |
194 | ||
195 | extern cfi_cmdset_fn_t cfi_cmdset_0001; | |
196 | extern cfi_cmdset_fn_t cfi_cmdset_0002; | |
197 | extern cfi_cmdset_fn_t cfi_cmdset_0020; | |
198 | ||
1f948b43 | 199 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, |
1da177e4 LT |
200 | int primary) |
201 | { | |
202 | struct cfi_private *cfi = map->fldrv_priv; | |
203 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | |
a15bdeef | 204 | #ifdef CONFIG_MODULES |
b92021b0 | 205 | char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))]; |
1da177e4 LT |
206 | cfi_cmdset_fn_t *probe_function; |
207 | ||
b92021b0 | 208 | sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type); |
1f948b43 | 209 | |
5fc3dbc4 | 210 | probe_function = __symbol_get(probename); |
a15bdeef | 211 | if (!probe_function) { |
f9827dde | 212 | request_module("cfi_cmdset_%4.4X", type); |
5fc3dbc4 | 213 | probe_function = __symbol_get(probename); |
a15bdeef | 214 | } |
1da177e4 LT |
215 | |
216 | if (probe_function) { | |
217 | struct mtd_info *mtd; | |
218 | ||
219 | mtd = (*probe_function)(map, primary); | |
220 | /* If it was happy, it'll have increased its own use count */ | |
a15bdeef | 221 | symbol_put_addr(probe_function); |
1da177e4 LT |
222 | return mtd; |
223 | } | |
224 | #endif | |
a15bdeef | 225 | printk(KERN_NOTICE "Support for command set %04X not present\n", type); |
1da177e4 LT |
226 | |
227 | return NULL; | |
228 | } | |
229 | ||
230 | static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |
231 | { | |
232 | struct cfi_private *cfi = map->fldrv_priv; | |
233 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | |
1f948b43 | 234 | |
1da177e4 LT |
235 | if (type == P_ID_NONE || type == P_ID_RESERVED) |
236 | return NULL; | |
237 | ||
238 | switch(type){ | |
a15bdeef DW |
239 | /* We need these for the !CONFIG_MODULES case, |
240 | because symbol_get() doesn't work there */ | |
1da177e4 | 241 | #ifdef CONFIG_MTD_CFI_INTELEXT |
58598861 GL |
242 | case P_ID_INTEL_EXT: |
243 | case P_ID_INTEL_STD: | |
244 | case P_ID_INTEL_PERFORMANCE: | |
1da177e4 LT |
245 | return cfi_cmdset_0001(map, primary); |
246 | #endif | |
247 | #ifdef CONFIG_MTD_CFI_AMDSTD | |
58598861 | 248 | case P_ID_AMD_STD: |
83dcd3bb | 249 | case P_ID_SST_OLD: |
80461128 | 250 | case P_ID_WINBOND: |
1da177e4 LT |
251 | return cfi_cmdset_0002(map, primary); |
252 | #endif | |
253 | #ifdef CONFIG_MTD_CFI_STAA | |
58598861 | 254 | case P_ID_ST_ADV: |
1da177e4 LT |
255 | return cfi_cmdset_0020(map, primary); |
256 | #endif | |
a15bdeef DW |
257 | default: |
258 | return cfi_cmdset_unknown(map, primary); | |
1da177e4 | 259 | } |
1da177e4 LT |
260 | } |
261 | ||
262 | MODULE_LICENSE("GPL"); | |
263 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | |
264 | MODULE_DESCRIPTION("Helper routines for flash chip probe code"); |