0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/mtd/mtd.h>
0011 #include <linux/mtd/map.h>
0012 #include <linux/mtd/cfi.h>
0013 #include <linux/mtd/gen_probe.h>
0014
0015 static struct mtd_info *check_cmd_set(struct map_info *, int);
0016 static struct cfi_private *genprobe_ident_chips(struct map_info *map,
0017 struct chip_probe *cp);
0018 static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
0019 struct cfi_private *cfi);
0020
0021 struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
0022 {
0023 struct mtd_info *mtd;
0024 struct cfi_private *cfi;
0025
0026
0027 cfi = genprobe_ident_chips(map, cp);
0028
0029 if (!cfi)
0030 return NULL;
0031
0032 map->fldrv_priv = cfi;
0033
0034
0035 mtd = check_cmd_set(map, 1);
0036 if (!mtd)
0037 mtd = check_cmd_set(map, 0);
0038
0039 if (mtd) {
0040 if (mtd->size > map->size) {
0041 printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
0042 (unsigned long)mtd->size >> 10,
0043 (unsigned long)map->size >> 10);
0044 mtd->size = map->size;
0045 }
0046 return mtd;
0047 }
0048
0049 printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
0050
0051 kfree(cfi->cfiq);
0052 kfree(cfi);
0053 map->fldrv_priv = NULL;
0054 return NULL;
0055 }
0056 EXPORT_SYMBOL(mtd_do_chip_probe);
0057
0058
0059 static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
0060 {
0061 struct cfi_private cfi;
0062 struct cfi_private *retcfi;
0063 unsigned long *chip_map;
0064 int max_chips;
0065 int i, j;
0066
0067 memset(&cfi, 0, sizeof(cfi));
0068
0069
0070
0071 if (!genprobe_new_chip(map, cp, &cfi)) {
0072
0073 pr_debug("%s: Found no %s device at location zero\n",
0074 cp->name, map->name);
0075 return NULL;
0076 }
0077
0078 #if 0
0079
0080
0081
0082 if (cfi.cfiq->NumEraseRegions == 0) {
0083 printk(KERN_WARNING "Number of erase regions is zero\n");
0084 kfree(cfi.cfiq);
0085 return NULL;
0086 }
0087 #endif
0088 cfi.chipshift = cfi.cfiq->DevSize;
0089
0090 if (cfi_interleave_is_1(&cfi)) {
0091 ;
0092 } else if (cfi_interleave_is_2(&cfi)) {
0093 cfi.chipshift++;
0094 } else if (cfi_interleave_is_4((&cfi))) {
0095 cfi.chipshift += 2;
0096 } else if (cfi_interleave_is_8(&cfi)) {
0097 cfi.chipshift += 3;
0098 } else {
0099 BUG();
0100 }
0101
0102 cfi.numchips = 1;
0103
0104
0105
0106
0107
0108 max_chips = map->size >> cfi.chipshift;
0109 if (!max_chips) {
0110 printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n");
0111 max_chips = 1;
0112 }
0113
0114 chip_map = bitmap_zalloc(max_chips, GFP_KERNEL);
0115 if (!chip_map) {
0116 kfree(cfi.cfiq);
0117 return NULL;
0118 }
0119
0120 set_bit(0, chip_map);
0121
0122
0123
0124
0125
0126
0127
0128 for (i = 1; i < max_chips; i++) {
0129 cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
0130 }
0131
0132
0133
0134
0135
0136
0137 retcfi = kmalloc(struct_size(retcfi, chips, cfi.numchips), GFP_KERNEL);
0138
0139 if (!retcfi) {
0140 kfree(cfi.cfiq);
0141 bitmap_free(chip_map);
0142 return NULL;
0143 }
0144
0145 memcpy(retcfi, &cfi, sizeof(cfi));
0146 memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
0147
0148 for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
0149 if(test_bit(i, chip_map)) {
0150 struct flchip *pchip = &retcfi->chips[j++];
0151
0152 pchip->start = (i << cfi.chipshift);
0153 pchip->state = FL_READY;
0154 init_waitqueue_head(&pchip->wq);
0155 mutex_init(&pchip->mutex);
0156 }
0157 }
0158
0159 bitmap_free(chip_map);
0160 return retcfi;
0161 }
0162
0163
0164 static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
0165 struct cfi_private *cfi)
0166 {
0167 int min_chips = (map_bankwidth(map)/4?:1);
0168 int max_chips = map_bankwidth(map);
0169 int nr_chips, type;
0170
0171 for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
0172
0173 if (!cfi_interleave_supported(nr_chips))
0174 continue;
0175
0176 cfi->interleave = nr_chips;
0177
0178
0179
0180 type = map_bankwidth(map) / nr_chips;
0181
0182 for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
0183 cfi->device_type = type;
0184
0185 if (cp->probe_chip(map, 0, NULL, cfi))
0186 return 1;
0187 }
0188 }
0189 return 0;
0190 }
0191
0192 typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
0193
0194 extern cfi_cmdset_fn_t cfi_cmdset_0001;
0195 extern cfi_cmdset_fn_t cfi_cmdset_0002;
0196 extern cfi_cmdset_fn_t cfi_cmdset_0020;
0197
0198 static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
0199 int primary)
0200 {
0201 struct cfi_private *cfi = map->fldrv_priv;
0202 __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
0203 #ifdef CONFIG_MODULES
0204 cfi_cmdset_fn_t *probe_function;
0205 char *probename;
0206
0207 probename = kasprintf(GFP_KERNEL, "cfi_cmdset_%4.4X", type);
0208 if (!probename)
0209 return NULL;
0210
0211 probe_function = __symbol_get(probename);
0212 if (!probe_function) {
0213 request_module("cfi_cmdset_%4.4X", type);
0214 probe_function = __symbol_get(probename);
0215 }
0216 kfree(probename);
0217
0218 if (probe_function) {
0219 struct mtd_info *mtd;
0220
0221 mtd = (*probe_function)(map, primary);
0222
0223 symbol_put_addr(probe_function);
0224 return mtd;
0225 }
0226 #endif
0227 printk(KERN_NOTICE "Support for command set %04X not present\n", type);
0228
0229 return NULL;
0230 }
0231
0232 static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
0233 {
0234 struct cfi_private *cfi = map->fldrv_priv;
0235 __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
0236
0237 if (type == P_ID_NONE || type == P_ID_RESERVED)
0238 return NULL;
0239
0240 switch(type){
0241
0242
0243 #ifdef CONFIG_MTD_CFI_INTELEXT
0244 case P_ID_INTEL_EXT:
0245 case P_ID_INTEL_STD:
0246 case P_ID_INTEL_PERFORMANCE:
0247 return cfi_cmdset_0001(map, primary);
0248 #endif
0249 #ifdef CONFIG_MTD_CFI_AMDSTD
0250 case P_ID_AMD_STD:
0251 case P_ID_SST_OLD:
0252 case P_ID_WINBOND:
0253 return cfi_cmdset_0002(map, primary);
0254 #endif
0255 #ifdef CONFIG_MTD_CFI_STAA
0256 case P_ID_ST_ADV:
0257 return cfi_cmdset_0020(map, primary);
0258 #endif
0259 default:
0260 return cfi_cmdset_unknown(map, primary);
0261 }
0262 }
0263
0264 MODULE_LICENSE("GPL");
0265 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
0266 MODULE_DESCRIPTION("Helper routines for flash chip probe code");