18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Routines common to all CFI-type probes. 38c2ecf20Sopenharmony_ci * (C) 2001-2003 Red Hat, Inc. 48c2ecf20Sopenharmony_ci * GPL'd 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 118c2ecf20Sopenharmony_ci#include <linux/mtd/map.h> 128c2ecf20Sopenharmony_ci#include <linux/mtd/cfi.h> 138c2ecf20Sopenharmony_ci#include <linux/mtd/gen_probe.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct mtd_info *check_cmd_set(struct map_info *, int); 168c2ecf20Sopenharmony_cistatic struct cfi_private *genprobe_ident_chips(struct map_info *map, 178c2ecf20Sopenharmony_ci struct chip_probe *cp); 188c2ecf20Sopenharmony_cistatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 198c2ecf20Sopenharmony_ci struct cfi_private *cfi); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct mtd_info *mtd; 248c2ecf20Sopenharmony_ci struct cfi_private *cfi; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci /* First probe the map to see if we have CFI stuff there. */ 278c2ecf20Sopenharmony_ci cfi = genprobe_ident_chips(map, cp); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (!cfi) 308c2ecf20Sopenharmony_ci return NULL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci map->fldrv_priv = cfi; 338c2ecf20Sopenharmony_ci /* OK we liked it. Now find a driver for the command set it talks */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci mtd = check_cmd_set(map, 1); /* First the primary cmdset */ 368c2ecf20Sopenharmony_ci if (!mtd) 378c2ecf20Sopenharmony_ci mtd = check_cmd_set(map, 0); /* Then the secondary */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (mtd) { 408c2ecf20Sopenharmony_ci if (mtd->size > map->size) { 418c2ecf20Sopenharmony_ci printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", 428c2ecf20Sopenharmony_ci (unsigned long)mtd->size >> 10, 438c2ecf20Sopenharmony_ci (unsigned long)map->size >> 10); 448c2ecf20Sopenharmony_ci mtd->size = map->size; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci return mtd; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci kfree(cfi->cfiq); 528c2ecf20Sopenharmony_ci kfree(cfi); 538c2ecf20Sopenharmony_ci map->fldrv_priv = NULL; 548c2ecf20Sopenharmony_ci return NULL; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mtd_do_chip_probe); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct cfi_private cfi; 628c2ecf20Sopenharmony_ci struct cfi_private *retcfi; 638c2ecf20Sopenharmony_ci unsigned long *chip_map; 648c2ecf20Sopenharmony_ci int i, j, mapsize; 658c2ecf20Sopenharmony_ci int max_chips; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci memset(&cfi, 0, sizeof(cfi)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Call the probetype-specific code with all permutations of 708c2ecf20Sopenharmony_ci interleave and device type, etc. */ 718c2ecf20Sopenharmony_ci if (!genprobe_new_chip(map, cp, &cfi)) { 728c2ecf20Sopenharmony_ci /* The probe didn't like it */ 738c2ecf20Sopenharmony_ci pr_debug("%s: Found no %s device at location zero\n", 748c2ecf20Sopenharmony_ci cp->name, map->name); 758c2ecf20Sopenharmony_ci return NULL; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD 798c2ecf20Sopenharmony_ci probe routines won't ever return a broken CFI structure anyway, 808c2ecf20Sopenharmony_ci because they make them up themselves. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci if (cfi.cfiq->NumEraseRegions == 0) { 838c2ecf20Sopenharmony_ci printk(KERN_WARNING "Number of erase regions is zero\n"); 848c2ecf20Sopenharmony_ci kfree(cfi.cfiq); 858c2ecf20Sopenharmony_ci return NULL; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci#endif 888c2ecf20Sopenharmony_ci cfi.chipshift = cfi.cfiq->DevSize; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (cfi_interleave_is_1(&cfi)) { 918c2ecf20Sopenharmony_ci ; 928c2ecf20Sopenharmony_ci } else if (cfi_interleave_is_2(&cfi)) { 938c2ecf20Sopenharmony_ci cfi.chipshift++; 948c2ecf20Sopenharmony_ci } else if (cfi_interleave_is_4((&cfi))) { 958c2ecf20Sopenharmony_ci cfi.chipshift += 2; 968c2ecf20Sopenharmony_ci } else if (cfi_interleave_is_8(&cfi)) { 978c2ecf20Sopenharmony_ci cfi.chipshift += 3; 988c2ecf20Sopenharmony_ci } else { 998c2ecf20Sopenharmony_ci BUG(); 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci cfi.numchips = 1; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Allocate memory for bitmap of valid chips. 1068c2ecf20Sopenharmony_ci * Align bitmap storage size to full byte. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci max_chips = map->size >> cfi.chipshift; 1098c2ecf20Sopenharmony_ci if (!max_chips) { 1108c2ecf20Sopenharmony_ci printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n"); 1118c2ecf20Sopenharmony_ci max_chips = 1; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); 1158c2ecf20Sopenharmony_ci chip_map = kzalloc(mapsize, GFP_KERNEL); 1168c2ecf20Sopenharmony_ci if (!chip_map) { 1178c2ecf20Sopenharmony_ci kfree(cfi.cfiq); 1188c2ecf20Sopenharmony_ci return NULL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci set_bit(0, chip_map); /* Mark first chip valid */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * Now probe for other chips, checking sensibly for aliases while 1258c2ecf20Sopenharmony_ci * we're at it. The new_chip probe above should have let the first 1268c2ecf20Sopenharmony_ci * chip in read mode. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci for (i = 1; i < max_chips; i++) { 1308c2ecf20Sopenharmony_ci cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * Now allocate the space for the structures we need to return to 1358c2ecf20Sopenharmony_ci * our caller, and copy the appropriate data into them. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci retcfi = kmalloc(struct_size(retcfi, chips, cfi.numchips), GFP_KERNEL); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!retcfi) { 1418c2ecf20Sopenharmony_ci kfree(cfi.cfiq); 1428c2ecf20Sopenharmony_ci kfree(chip_map); 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci memcpy(retcfi, &cfi, sizeof(cfi)); 1478c2ecf20Sopenharmony_ci memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { 1508c2ecf20Sopenharmony_ci if(test_bit(i, chip_map)) { 1518c2ecf20Sopenharmony_ci struct flchip *pchip = &retcfi->chips[j++]; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci pchip->start = (i << cfi.chipshift); 1548c2ecf20Sopenharmony_ci pchip->state = FL_READY; 1558c2ecf20Sopenharmony_ci init_waitqueue_head(&pchip->wq); 1568c2ecf20Sopenharmony_ci mutex_init(&pchip->mutex); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci kfree(chip_map); 1618c2ecf20Sopenharmony_ci return retcfi; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 1668c2ecf20Sopenharmony_ci struct cfi_private *cfi) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ 1698c2ecf20Sopenharmony_ci int max_chips = map_bankwidth(map); /* And minimum 1 */ 1708c2ecf20Sopenharmony_ci int nr_chips, type; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!cfi_interleave_supported(nr_chips)) 1758c2ecf20Sopenharmony_ci continue; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci cfi->interleave = nr_chips; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Minimum device size. Don't look for one 8-bit device 1808c2ecf20Sopenharmony_ci in a 16-bit bus, etc. */ 1818c2ecf20Sopenharmony_ci type = map_bankwidth(map) / nr_chips; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci for (; type <= CFI_DEVICETYPE_X32; type<<=1) { 1848c2ecf20Sopenharmony_ci cfi->device_type = type; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (cp->probe_chip(map, 0, NULL, cfi)) 1878c2ecf20Sopenharmony_ci return 1; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_citypedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0001; 1968c2ecf20Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0002; 1978c2ecf20Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0020; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 2008c2ecf20Sopenharmony_ci int primary) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct cfi_private *cfi = map->fldrv_priv; 2038c2ecf20Sopenharmony_ci __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 2048c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 2058c2ecf20Sopenharmony_ci cfi_cmdset_fn_t *probe_function; 2068c2ecf20Sopenharmony_ci char *probename; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci probename = kasprintf(GFP_KERNEL, "cfi_cmdset_%4.4X", type); 2098c2ecf20Sopenharmony_ci if (!probename) 2108c2ecf20Sopenharmony_ci return NULL; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci probe_function = __symbol_get(probename); 2138c2ecf20Sopenharmony_ci if (!probe_function) { 2148c2ecf20Sopenharmony_ci request_module("cfi_cmdset_%4.4X", type); 2158c2ecf20Sopenharmony_ci probe_function = __symbol_get(probename); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci kfree(probename); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (probe_function) { 2208c2ecf20Sopenharmony_ci struct mtd_info *mtd; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci mtd = (*probe_function)(map, primary); 2238c2ecf20Sopenharmony_ci /* If it was happy, it'll have increased its own use count */ 2248c2ecf20Sopenharmony_ci symbol_put_addr(probe_function); 2258c2ecf20Sopenharmony_ci return mtd; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci#endif 2288c2ecf20Sopenharmony_ci printk(KERN_NOTICE "Support for command set %04X not present\n", type); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return NULL; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic struct mtd_info *check_cmd_set(struct map_info *map, int primary) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct cfi_private *cfi = map->fldrv_priv; 2368c2ecf20Sopenharmony_ci __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (type == P_ID_NONE || type == P_ID_RESERVED) 2398c2ecf20Sopenharmony_ci return NULL; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci switch(type){ 2428c2ecf20Sopenharmony_ci /* We need these for the !CONFIG_MODULES case, 2438c2ecf20Sopenharmony_ci because symbol_get() doesn't work there */ 2448c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_CFI_INTELEXT 2458c2ecf20Sopenharmony_ci case P_ID_INTEL_EXT: 2468c2ecf20Sopenharmony_ci case P_ID_INTEL_STD: 2478c2ecf20Sopenharmony_ci case P_ID_INTEL_PERFORMANCE: 2488c2ecf20Sopenharmony_ci return cfi_cmdset_0001(map, primary); 2498c2ecf20Sopenharmony_ci#endif 2508c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_CFI_AMDSTD 2518c2ecf20Sopenharmony_ci case P_ID_AMD_STD: 2528c2ecf20Sopenharmony_ci case P_ID_SST_OLD: 2538c2ecf20Sopenharmony_ci case P_ID_WINBOND: 2548c2ecf20Sopenharmony_ci return cfi_cmdset_0002(map, primary); 2558c2ecf20Sopenharmony_ci#endif 2568c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_CFI_STAA 2578c2ecf20Sopenharmony_ci case P_ID_ST_ADV: 2588c2ecf20Sopenharmony_ci return cfi_cmdset_0020(map, primary); 2598c2ecf20Sopenharmony_ci#endif 2608c2ecf20Sopenharmony_ci default: 2618c2ecf20Sopenharmony_ci return cfi_cmdset_unknown(map, primary); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2668c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 2678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Helper routines for flash chip probe code"); 268