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 LT |
116 | if (!chip_map) { |
117 | printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); | |
118 | kfree(cfi.cfiq); | |
119 | return NULL; | |
120 | } | |
1da177e4 LT |
121 | |
122 | set_bit(0, chip_map); /* Mark first chip valid */ | |
123 | ||
124 | /* | |
125 | * Now probe for other chips, checking sensibly for aliases while | |
126 | * we're at it. The new_chip probe above should have let the first | |
127 | * chip in read mode. | |
128 | */ | |
129 | ||
130 | for (i = 1; i < max_chips; i++) { | |
131 | cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); | |
132 | } | |
133 | ||
134 | /* | |
1f948b43 | 135 | * Now allocate the space for the structures we need to return to |
1da177e4 LT |
136 | * our caller, and copy the appropriate data into them. |
137 | */ | |
138 | ||
139 | retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); | |
140 | ||
141 | if (!retcfi) { | |
142 | printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); | |
143 | kfree(cfi.cfiq); | |
144 | kfree(chip_map); | |
145 | return NULL; | |
146 | } | |
147 | ||
148 | memcpy(retcfi, &cfi, sizeof(cfi)); | |
149 | memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); | |
150 | ||
151 | for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { | |
152 | if(test_bit(i, chip_map)) { | |
153 | struct flchip *pchip = &retcfi->chips[j++]; | |
154 | ||
155 | pchip->start = (i << cfi.chipshift); | |
156 | pchip->state = FL_READY; | |
157 | init_waitqueue_head(&pchip->wq); | |
c4e77376 | 158 | mutex_init(&pchip->mutex); |
1da177e4 LT |
159 | } |
160 | } | |
161 | ||
162 | kfree(chip_map); | |
163 | return retcfi; | |
164 | } | |
165 | ||
1f948b43 | 166 | |
1da177e4 LT |
167 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, |
168 | struct cfi_private *cfi) | |
169 | { | |
170 | int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ | |
171 | int max_chips = map_bankwidth(map); /* And minimum 1 */ | |
172 | int nr_chips, type; | |
173 | ||
6170b434 | 174 | for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { |
1da177e4 LT |
175 | |
176 | if (!cfi_interleave_supported(nr_chips)) | |
177 | continue; | |
178 | ||
179 | cfi->interleave = nr_chips; | |
180 | ||
181 | /* Minimum device size. Don't look for one 8-bit device | |
182 | in a 16-bit bus, etc. */ | |
183 | type = map_bankwidth(map) / nr_chips; | |
184 | ||
185 | for (; type <= CFI_DEVICETYPE_X32; type<<=1) { | |
186 | cfi->device_type = type; | |
187 | ||
188 | if (cp->probe_chip(map, 0, NULL, cfi)) | |
189 | return 1; | |
190 | } | |
191 | } | |
192 | return 0; | |
193 | } | |
194 | ||
195 | typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); | |
196 | ||
197 | extern cfi_cmdset_fn_t cfi_cmdset_0001; | |
198 | extern cfi_cmdset_fn_t cfi_cmdset_0002; | |
199 | extern cfi_cmdset_fn_t cfi_cmdset_0020; | |
200 | ||
1f948b43 | 201 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, |
1da177e4 LT |
202 | int primary) |
203 | { | |
204 | struct cfi_private *cfi = map->fldrv_priv; | |
205 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | |
a15bdeef | 206 | #ifdef CONFIG_MODULES |
b92021b0 | 207 | char probename[sizeof(VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X))]; |
1da177e4 LT |
208 | cfi_cmdset_fn_t *probe_function; |
209 | ||
b92021b0 | 210 | sprintf(probename, VMLINUX_SYMBOL_STR(cfi_cmdset_%4.4X), type); |
1f948b43 | 211 | |
5fc3dbc4 | 212 | probe_function = __symbol_get(probename); |
a15bdeef | 213 | if (!probe_function) { |
f9827dde | 214 | request_module("cfi_cmdset_%4.4X", type); |
5fc3dbc4 | 215 | probe_function = __symbol_get(probename); |
a15bdeef | 216 | } |
1da177e4 LT |
217 | |
218 | if (probe_function) { | |
219 | struct mtd_info *mtd; | |
220 | ||
221 | mtd = (*probe_function)(map, primary); | |
222 | /* If it was happy, it'll have increased its own use count */ | |
a15bdeef | 223 | symbol_put_addr(probe_function); |
1da177e4 LT |
224 | return mtd; |
225 | } | |
226 | #endif | |
a15bdeef | 227 | printk(KERN_NOTICE "Support for command set %04X not present\n", type); |
1da177e4 LT |
228 | |
229 | return NULL; | |
230 | } | |
231 | ||
232 | static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |
233 | { | |
234 | struct cfi_private *cfi = map->fldrv_priv; | |
235 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | |
1f948b43 | 236 | |
1da177e4 LT |
237 | if (type == P_ID_NONE || type == P_ID_RESERVED) |
238 | return NULL; | |
239 | ||
240 | switch(type){ | |
a15bdeef DW |
241 | /* We need these for the !CONFIG_MODULES case, |
242 | because symbol_get() doesn't work there */ | |
1da177e4 | 243 | #ifdef CONFIG_MTD_CFI_INTELEXT |
58598861 GL |
244 | case P_ID_INTEL_EXT: |
245 | case P_ID_INTEL_STD: | |
246 | case P_ID_INTEL_PERFORMANCE: | |
1da177e4 LT |
247 | return cfi_cmdset_0001(map, primary); |
248 | #endif | |
249 | #ifdef CONFIG_MTD_CFI_AMDSTD | |
58598861 | 250 | case P_ID_AMD_STD: |
83dcd3bb | 251 | case P_ID_SST_OLD: |
80461128 | 252 | case P_ID_WINBOND: |
1da177e4 LT |
253 | return cfi_cmdset_0002(map, primary); |
254 | #endif | |
255 | #ifdef CONFIG_MTD_CFI_STAA | |
58598861 | 256 | case P_ID_ST_ADV: |
1da177e4 LT |
257 | return cfi_cmdset_0020(map, primary); |
258 | #endif | |
a15bdeef DW |
259 | default: |
260 | return cfi_cmdset_unknown(map, primary); | |
1da177e4 | 261 | } |
1da177e4 LT |
262 | } |
263 | ||
264 | MODULE_LICENSE("GPL"); | |
265 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | |
266 | MODULE_DESCRIPTION("Helper routines for flash chip probe code"); |