1/* 2 * Routines common to all CFI-type probes. 3 * (C) 2001, 2001 Red Hat, Inc. 4 * GPL'd 5 * $Id: gen_probe.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang Exp $ 6 */ 7 8#include <linux/kernel.h> 9#include <linux/mtd/mtd.h> 10#include <linux/mtd/map.h> 11#include <linux/mtd/cfi.h> 12#include <linux/mtd/gen_probe.h> 13 14static struct mtd_info *check_cmd_set(struct map_info *, int); 15static struct cfi_private *genprobe_ident_chips(struct map_info *map, 16 struct chip_probe *cp); 17static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 18 struct cfi_private *cfi); 19 20struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) 21{ 22 struct mtd_info *mtd = NULL; 23 struct cfi_private *cfi; 24 25 /* First probe the map to see if we have CFI stuff there. */ 26 cfi = genprobe_ident_chips(map, cp); 27 28 if (!cfi) 29 return NULL; 30 31 map->fldrv_priv = cfi; 32 /* OK we liked it. Now find a driver for the command set it talks */ 33 34 mtd = check_cmd_set(map, 1); /* First the primary cmdset */ 35 if (!mtd) 36 mtd = check_cmd_set(map, 0); /* Then the secondary */ 37 38 if (mtd) 39 return mtd; 40 41 printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n"); 42 43 kfree(cfi->cfiq); 44 kfree(cfi); 45 map->fldrv_priv = NULL; 46 return NULL; 47} 48EXPORT_SYMBOL(mtd_do_chip_probe); 49 50 51struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) 52{ 53 unsigned long base=0; 54 struct cfi_private cfi; 55 struct cfi_private *retcfi; 56 struct flchip chip[MAX_CFI_CHIPS]; 57 int i; 58 59 memset(&cfi, 0, sizeof(cfi)); 60 61 /* Call the probetype-specific code with all permutations of 62 interleave and device type, etc. */ 63 if (!genprobe_new_chip(map, cp, &cfi)) { 64 /* The probe didn't like it */ 65 printk(KERN_WARNING "%s: Found no %s device at location zero\n", 66 cp->name, map->name); 67 return NULL; 68 } 69 70#if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD 71 probe routines won't ever return a broken CFI structure anyway, 72 because they make them up themselves. 73 */ 74 if (cfi.cfiq->NumEraseRegions == 0) { 75 printk(KERN_WARNING "Number of erase regions is zero\n"); 76 kfree(cfi.cfiq); 77 return NULL; 78 } 79#endif 80 chip[0].start = 0; 81 chip[0].state = FL_READY; 82 cfi.chipshift = cfi.cfiq->DevSize; 83 84 switch(cfi.interleave) { 85#ifdef CFIDEV_INTERLEAVE_1 86 case 1: 87 break; 88#endif 89#ifdef CFIDEV_INTERLEAVE_2 90 case 2: 91 cfi.chipshift++; 92 break; 93#endif 94#ifdef CFIDEV_INTERLEAVE_4 95 case 4: 96 cfi.chipshift+=2; 97 break; 98#endif 99 default: 100 BUG(); 101 } 102 103 cfi.numchips = 1; 104 105 /* 106 * Now probe for other chips, checking sensibly for aliases while 107 * we're at it. The new_chip probe above should have let the first 108 * chip in read mode. 109 */ 110 111 for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size; 112 base += (1<<cfi.chipshift)) 113 cp->probe_chip(map, base, &chip[0], &cfi); 114 115 /* 116 * Now allocate the space for the structures we need to return to 117 * our caller, and copy the appropriate data into them. 118 */ 119 120 retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); 121 122 if (!retcfi) { 123 printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); 124 kfree(cfi.cfiq); 125 return NULL; 126 } 127 128 memcpy(retcfi, &cfi, sizeof(cfi)); 129 memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips); 130 131 /* Fix up the stuff that breaks when you move it */ 132 for (i=0; i< retcfi->numchips; i++) { 133 init_waitqueue_head(&retcfi->chips[i].wq); 134 spin_lock_init(&retcfi->chips[i]._spinlock); 135 retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock; 136 } 137 138 return retcfi; 139} 140 141 142static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 143 struct cfi_private *cfi) 144{ 145 switch (map->buswidth) { 146#ifdef CFIDEV_BUSWIDTH_1 147 case CFIDEV_BUSWIDTH_1: 148 cfi->interleave = CFIDEV_INTERLEAVE_1; 149 150 cfi->device_type = CFI_DEVICETYPE_X8; 151 if (cp->probe_chip(map, 0, NULL, cfi)) 152 return 1; 153 154 cfi->device_type = CFI_DEVICETYPE_X16; 155 if (cp->probe_chip(map, 0, NULL, cfi)) 156 return 1; 157 break; 158#endif /* CFIDEV_BUSWITDH_1 */ 159 160#ifdef CFIDEV_BUSWIDTH_2 161 case CFIDEV_BUSWIDTH_2: 162#ifdef CFIDEV_INTERLEAVE_1 163 cfi->interleave = CFIDEV_INTERLEAVE_1; 164 165 cfi->device_type = CFI_DEVICETYPE_X16; 166 if (cp->probe_chip(map, 0, NULL, cfi)) 167 return 1; 168#endif /* CFIDEV_INTERLEAVE_1 */ 169#ifdef CFIDEV_INTERLEAVE_2 170 cfi->interleave = CFIDEV_INTERLEAVE_2; 171 172 cfi->device_type = CFI_DEVICETYPE_X8; 173 if (cp->probe_chip(map, 0, NULL, cfi)) 174 return 1; 175 176 cfi->device_type = CFI_DEVICETYPE_X16; 177 if (cp->probe_chip(map, 0, NULL, cfi)) 178 return 1; 179#endif /* CFIDEV_INTERLEAVE_2 */ 180 break; 181#endif /* CFIDEV_BUSWIDTH_2 */ 182 183#ifdef CFIDEV_BUSWIDTH_4 184 case CFIDEV_BUSWIDTH_4: 185#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE) 186 cfi->interleave = CFIDEV_INTERLEAVE_1; 187 188 cfi->device_type = CFI_DEVICETYPE_X32; 189 if (cp->probe_chip(map, 0, NULL, cfi)) 190 return 1; 191#endif /* CFIDEV_INTERLEAVE_1 */ 192#ifdef CFIDEV_INTERLEAVE_2 193 cfi->interleave = CFIDEV_INTERLEAVE_2; 194 195#ifdef SOMEONE_ACTUALLY_MAKES_THESE 196 cfi->device_type = CFI_DEVICETYPE_X32; 197 if (cp->probe_chip(map, 0, NULL, cfi)) 198 return 1; 199#endif 200 cfi->device_type = CFI_DEVICETYPE_X16; 201 if (cp->probe_chip(map, 0, NULL, cfi)) 202 return 1; 203 204 cfi->device_type = CFI_DEVICETYPE_X8; 205 if (cp->probe_chip(map, 0, NULL, cfi)) 206 return 1; 207#endif /* CFIDEV_INTERLEAVE_2 */ 208#ifdef CFIDEV_INTERLEAVE_4 209 cfi->interleave = CFIDEV_INTERLEAVE_4; 210 211#ifdef SOMEONE_ACTUALLY_MAKES_THESE 212 cfi->device_type = CFI_DEVICETYPE_X32; 213 if (cp->probe_chip(map, 0, NULL, cfi)) 214 return 1; 215#endif 216 cfi->device_type = CFI_DEVICETYPE_X16; 217 if (cp->probe_chip(map, 0, NULL, cfi)) 218 return 1; 219 220 cfi->device_type = CFI_DEVICETYPE_X8; 221 if (cp->probe_chip(map, 0, NULL, cfi)) 222 return 1; 223#endif /* CFIDEV_INTERLEAVE_4 */ 224 break; 225#endif /* CFIDEV_BUSWIDTH_4 */ 226 227 default: 228 printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth); 229 return 0; 230 } 231 return 0; 232} 233 234 235typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); 236 237extern cfi_cmdset_fn_t cfi_cmdset_0001; 238extern cfi_cmdset_fn_t cfi_cmdset_0002; 239 240static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 241 int primary) 242{ 243 struct cfi_private *cfi = map->fldrv_priv; 244 __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 245#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE) 246 char probename[32]; 247 cfi_cmdset_fn_t *probe_function; 248 249 sprintf(probename, "cfi_cmdset_%4.4X", type); 250 251 probe_function = inter_module_get_request(probename, probename); 252 253 if (probe_function) { 254 struct mtd_info *mtd; 255 256 mtd = (*probe_function)(map, primary); 257 /* If it was happy, it'll have increased its own use count */ 258 inter_module_put(probename); 259 return mtd; 260 } 261#endif 262 printk(KERN_NOTICE "Support for command set %04X not present\n", 263 type); 264 265 return NULL; 266} 267 268static struct mtd_info *check_cmd_set(struct map_info *map, int primary) 269{ 270 struct cfi_private *cfi = map->fldrv_priv; 271 __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 272 273 if (type == P_ID_NONE || type == P_ID_RESERVED) 274 return NULL; 275 276 switch(type){ 277 /* Urgh. Ifdefs. The version with weak symbols was 278 * _much_ nicer. Shame it didn't seem to work on 279 * anything but x86, really. 280 * But we can't rely in inter_module_get() because 281 * that'd mean we depend on link order. 282 */ 283#ifdef CONFIG_MTD_CFI_INTELEXT 284 case 0x0001: 285 case 0x0003: 286 return cfi_cmdset_0001(map, primary); 287#endif 288#ifdef CONFIG_MTD_CFI_AMDSTD 289 case 0x0002: 290 return cfi_cmdset_0002(map, primary); 291#endif 292#ifdef CONFIG_MTD_CFI_SSTSTD 293 case 0x0701: 294 return cfi_cmdset_0701(map, primary); 295#endif 296 } 297 298 return cfi_cmdset_unknown(map, primary); 299} 300 301MODULE_LICENSE("GPL"); 302MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 303MODULE_DESCRIPTION("Helper routines for flash chip probe code"); 304