11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Routines common to all CFI-type probes. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 2001-2003 Red Hat, Inc. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GPL'd 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/map.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/cfi.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/gen_probe.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *check_cmd_set(struct map_info *, int); 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cfi_private *genprobe_ident_chips(struct map_info *map, 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct chip_probe *cp); 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi); 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mtd_info *mtd = NULL; 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi; 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First probe the map to see if we have CFI stuff there. */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi = genprobe_ident_chips(map, cp); 281f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cfi) 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map->fldrv_priv = cfi; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK we liked it. Now find a driver for the command set it talks */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd = check_cmd_set(map, 1); /* First the primary cmdset */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mtd) 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd = check_cmd_set(map, 0); /* Then the secondary */ 381f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 390f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse if (mtd) { 400f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse if (mtd->size > map->size) { 41f6a673b3f4f93c1c50e1b18f29254b0531b722a8David Woodhouse printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", 42c9ac5977299dd106ddb759e7e10035770dff185bDavid Woodhouse (unsigned long)mtd->size >> 10, 430f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse (unsigned long)map->size >> 10); 440f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse mtd->size = map->size; 450f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse } 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mtd; 470f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse } 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); 501f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cfi->cfiq); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cfi); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map->fldrv_priv = NULL; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mtd_do_chip_probe); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private cfi; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *retcfi; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long *chip_map; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, mapsize; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_chips; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&cfi, 0, sizeof(cfi)); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner /* Call the probetype-specific code with all permutations of 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interleave and device type, etc. */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!genprobe_new_chip(map, cp, &cfi)) { 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The probe didn't like it */ 733a3688b6af103e2c86a7cfc2050988655e184eccJean Delvare pr_debug("%s: Found no %s device at location zero\n", 743a3688b6af103e2c86a7cfc2050988655e184eccJean Delvare cp->name, map->name); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 761f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds probe routines won't ever return a broken CFI structure anyway, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds because they make them up themselves. 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cfi.cfiq->NumEraseRegions == 0) { 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "Number of erase regions is zero\n"); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cfi.cfiq); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi.chipshift = cfi.cfiq->DevSize; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cfi_interleave_is_1(&cfi)) { 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (cfi_interleave_is_2(&cfi)) { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi.chipshift++; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (cfi_interleave_is_4((&cfi))) { 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi.chipshift += 2; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (cfi_interleave_is_8(&cfi)) { 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi.chipshift += 3; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1011f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi.numchips = 1; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner /* 1051f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner * Allocate memory for bitmap of valid chips. 1061f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner * Align bitmap storage size to full byte. 1071f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_chips = map->size >> cfi.chipshift; 1090f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse if (!max_chips) { 1100f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n"); 1110f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse max_chips = 1; 1120f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse } 1130f5ae3d2e9f49af55eb2a9b7cb54b4c0c2373017David Woodhouse 114c8872b069c536976b81bccfc95dda945594bc504Julia Lawall mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); 11595b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan chip_map = kzalloc(mapsize, GFP_KERNEL); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!chip_map) { 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cfi.cfiq); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(0, chip_map); /* Mark first chip valid */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now probe for other chips, checking sensibly for aliases while 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we're at it. The new_chip probe above should have let the first 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip in read mode. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < max_chips; i++) { 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1351f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner * Now allocate the space for the structures we need to return to 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our caller, and copy the appropriate data into them. 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retcfi) { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cfi.cfiq); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(chip_map); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(retcfi, &cfi, sizeof(cfi)); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(test_bit(i, chip_map)) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct flchip *pchip = &retcfi->chips[j++]; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pchip->start = (i << cfi.chipshift); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pchip->state = FL_READY; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&pchip->wq); 158c4e773764cead9358fd4b036d1b883fff3968513Stefani Seibold mutex_init(&pchip->mutex); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(chip_map); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retcfi; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_chips = map_bankwidth(map); /* And minimum 1 */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nr_chips, type; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1746170b43401a3230756ff76287ee07db0d75edddeRussell King for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cfi_interleave_supported(nr_chips)) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi->interleave = nr_chips; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Minimum device size. Don't look for one 8-bit device 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in a 16-bit bus, etc. */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = map_bankwidth(map) / nr_chips; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; type <= CFI_DEVICETYPE_X32; type<<=1) { 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi->device_type = type; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->probe_chip(map, 0, NULL, cfi)) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern cfi_cmdset_fn_t cfi_cmdset_0001; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern cfi_cmdset_fn_t cfi_cmdset_0002; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern cfi_cmdset_fn_t cfi_cmdset_0020; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixnerstatic inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int primary) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 206a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse#ifdef CONFIG_MODULES 207615191bb1dfc6980e7c7a85225444d860d74b343David Woodhouse char probename[16+sizeof(MODULE_SYMBOL_PREFIX)]; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfi_cmdset_fn_t *probe_function; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210615191bb1dfc6980e7c7a85225444d860d74b343David Woodhouse sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type); 2111f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 2125fc3dbc418e01345e25e96b3192a1c46051c3fdcDavid Woodhouse probe_function = __symbol_get(probename); 213a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse if (!probe_function) { 214615191bb1dfc6980e7c7a85225444d860d74b343David Woodhouse request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1); 2155fc3dbc418e01345e25e96b3192a1c46051c3fdcDavid Woodhouse probe_function = __symbol_get(probename); 216a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (probe_function) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mtd_info *mtd; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mtd = (*probe_function)(map, primary); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If it was happy, it'll have increased its own use count */ 223a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse symbol_put_addr(probe_function); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mtd; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 227a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse printk(KERN_NOTICE "Support for command set %04X not present\n", type); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_info *check_cmd_set(struct map_info *map, int primary) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cfi_private *cfi = map->fldrv_priv; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 2361f948b43f7b5cf721cf0d03f507843efc1a9bfadThomas Gleixner 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == P_ID_NONE || type == P_ID_RESERVED) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(type){ 241a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse /* We need these for the !CONFIG_MODULES case, 242a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse because symbol_get() doesn't work there */ 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MTD_CFI_INTELEXT 24458598861227877bb481b9035d2a07283577a2274Guillaume LECERF case P_ID_INTEL_EXT: 24558598861227877bb481b9035d2a07283577a2274Guillaume LECERF case P_ID_INTEL_STD: 24658598861227877bb481b9035d2a07283577a2274Guillaume LECERF case P_ID_INTEL_PERFORMANCE: 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cfi_cmdset_0001(map, primary); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MTD_CFI_AMDSTD 25058598861227877bb481b9035d2a07283577a2274Guillaume LECERF case P_ID_AMD_STD: 25183dcd3bb1139060fedb15235f8614d2bac82e18dGuillaume LECERF case P_ID_SST_OLD: 2528046112818b70329e930b1d4557ef0876c1ad2bbGuillaume LECERF case P_ID_WINBOND: 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cfi_cmdset_0002(map, primary); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MTD_CFI_STAA 25658598861227877bb481b9035d2a07283577a2274Guillaume LECERF case P_ID_ST_ADV: 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cfi_cmdset_0020(map, primary); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 259a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse default: 260a15bdeef108d282e540e202fc3c3e4bdf9692074David Woodhouse return cfi_cmdset_unknown(map, primary); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Helper routines for flash chip probe code"); 267