162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Routines common to all CFI-type probes. 462306a36Sopenharmony_ci * (C) 2001-2003 Red Hat, Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1162306a36Sopenharmony_ci#include <linux/mtd/map.h> 1262306a36Sopenharmony_ci#include <linux/mtd/cfi.h> 1362306a36Sopenharmony_ci#include <linux/mtd/gen_probe.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic struct mtd_info *check_cmd_set(struct map_info *, int); 1662306a36Sopenharmony_cistatic struct cfi_private *genprobe_ident_chips(struct map_info *map, 1762306a36Sopenharmony_ci struct chip_probe *cp); 1862306a36Sopenharmony_cistatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 1962306a36Sopenharmony_ci struct cfi_private *cfi); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct mtd_info *mtd; 2462306a36Sopenharmony_ci struct cfi_private *cfi; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* First probe the map to see if we have CFI stuff there. */ 2762306a36Sopenharmony_ci cfi = genprobe_ident_chips(map, cp); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (!cfi) 3062306a36Sopenharmony_ci return NULL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci map->fldrv_priv = cfi; 3362306a36Sopenharmony_ci /* OK we liked it. Now find a driver for the command set it talks */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci mtd = check_cmd_set(map, 1); /* First the primary cmdset */ 3662306a36Sopenharmony_ci if (!mtd) 3762306a36Sopenharmony_ci mtd = check_cmd_set(map, 0); /* Then the secondary */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (mtd) { 4062306a36Sopenharmony_ci if (mtd->size > map->size) { 4162306a36Sopenharmony_ci printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n", 4262306a36Sopenharmony_ci (unsigned long)mtd->size >> 10, 4362306a36Sopenharmony_ci (unsigned long)map->size >> 10); 4462306a36Sopenharmony_ci mtd->size = map->size; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci return mtd; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci kfree(cfi->cfiq); 5262306a36Sopenharmony_ci kfree(cfi); 5362306a36Sopenharmony_ci map->fldrv_priv = NULL; 5462306a36Sopenharmony_ci return NULL; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL(mtd_do_chip_probe); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct cfi_private cfi; 6262306a36Sopenharmony_ci struct cfi_private *retcfi; 6362306a36Sopenharmony_ci unsigned long *chip_map; 6462306a36Sopenharmony_ci int max_chips; 6562306a36Sopenharmony_ci int i, j; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci memset(&cfi, 0, sizeof(cfi)); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Call the probetype-specific code with all permutations of 7062306a36Sopenharmony_ci interleave and device type, etc. */ 7162306a36Sopenharmony_ci if (!genprobe_new_chip(map, cp, &cfi)) { 7262306a36Sopenharmony_ci /* The probe didn't like it */ 7362306a36Sopenharmony_ci pr_debug("%s: Found no %s device at location zero\n", 7462306a36Sopenharmony_ci cp->name, map->name); 7562306a36Sopenharmony_ci return NULL; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD 7962306a36Sopenharmony_ci probe routines won't ever return a broken CFI structure anyway, 8062306a36Sopenharmony_ci because they make them up themselves. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci if (cfi.cfiq->NumEraseRegions == 0) { 8362306a36Sopenharmony_ci printk(KERN_WARNING "Number of erase regions is zero\n"); 8462306a36Sopenharmony_ci kfree(cfi.cfiq); 8562306a36Sopenharmony_ci return NULL; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci#endif 8862306a36Sopenharmony_ci cfi.chipshift = cfi.cfiq->DevSize; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (cfi_interleave_is_1(&cfi)) { 9162306a36Sopenharmony_ci ; 9262306a36Sopenharmony_ci } else if (cfi_interleave_is_2(&cfi)) { 9362306a36Sopenharmony_ci cfi.chipshift++; 9462306a36Sopenharmony_ci } else if (cfi_interleave_is_4((&cfi))) { 9562306a36Sopenharmony_ci cfi.chipshift += 2; 9662306a36Sopenharmony_ci } else if (cfi_interleave_is_8(&cfi)) { 9762306a36Sopenharmony_ci cfi.chipshift += 3; 9862306a36Sopenharmony_ci } else { 9962306a36Sopenharmony_ci BUG(); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci cfi.numchips = 1; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * Allocate memory for bitmap of valid chips. 10662306a36Sopenharmony_ci * Align bitmap storage size to full byte. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci max_chips = map->size >> cfi.chipshift; 10962306a36Sopenharmony_ci if (!max_chips) { 11062306a36Sopenharmony_ci printk(KERN_WARNING "NOR chip too large to fit in mapping. Attempting to cope...\n"); 11162306a36Sopenharmony_ci max_chips = 1; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci chip_map = bitmap_zalloc(max_chips, GFP_KERNEL); 11562306a36Sopenharmony_ci if (!chip_map) { 11662306a36Sopenharmony_ci kfree(cfi.cfiq); 11762306a36Sopenharmony_ci return NULL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci set_bit(0, chip_map); /* Mark first chip valid */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * Now probe for other chips, checking sensibly for aliases while 12462306a36Sopenharmony_ci * we're at it. The new_chip probe above should have let the first 12562306a36Sopenharmony_ci * chip in read mode. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 1; i < max_chips; i++) { 12962306a36Sopenharmony_ci cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * Now allocate the space for the structures we need to return to 13462306a36Sopenharmony_ci * our caller, and copy the appropriate data into them. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci retcfi = kmalloc(struct_size(retcfi, chips, cfi.numchips), GFP_KERNEL); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!retcfi) { 14062306a36Sopenharmony_ci kfree(cfi.cfiq); 14162306a36Sopenharmony_ci bitmap_free(chip_map); 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci memcpy(retcfi, &cfi, sizeof(cfi)); 14662306a36Sopenharmony_ci memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { 14962306a36Sopenharmony_ci if(test_bit(i, chip_map)) { 15062306a36Sopenharmony_ci struct flchip *pchip = &retcfi->chips[j++]; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci pchip->start = (i << cfi.chipshift); 15362306a36Sopenharmony_ci pchip->state = FL_READY; 15462306a36Sopenharmony_ci init_waitqueue_head(&pchip->wq); 15562306a36Sopenharmony_ci mutex_init(&pchip->mutex); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci bitmap_free(chip_map); 16062306a36Sopenharmony_ci return retcfi; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, 16562306a36Sopenharmony_ci struct cfi_private *cfi) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */ 16862306a36Sopenharmony_ci int max_chips = map_bankwidth(map); /* And minimum 1 */ 16962306a36Sopenharmony_ci int nr_chips, type; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!cfi_interleave_supported(nr_chips)) 17462306a36Sopenharmony_ci continue; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci cfi->interleave = nr_chips; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Minimum device size. Don't look for one 8-bit device 17962306a36Sopenharmony_ci in a 16-bit bus, etc. */ 18062306a36Sopenharmony_ci type = map_bankwidth(map) / nr_chips; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci for (; type <= CFI_DEVICETYPE_X32; type<<=1) { 18362306a36Sopenharmony_ci cfi->device_type = type; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (cp->probe_chip(map, 0, NULL, cfi)) 18662306a36Sopenharmony_ci return 1; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_citypedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0001; 19562306a36Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0002; 19662306a36Sopenharmony_ciextern cfi_cmdset_fn_t cfi_cmdset_0020; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 19962306a36Sopenharmony_ci int primary) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct cfi_private *cfi = map->fldrv_priv; 20262306a36Sopenharmony_ci __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 20362306a36Sopenharmony_ci#ifdef CONFIG_MODULES 20462306a36Sopenharmony_ci cfi_cmdset_fn_t *probe_function; 20562306a36Sopenharmony_ci char *probename; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci probename = kasprintf(GFP_KERNEL, "cfi_cmdset_%4.4X", type); 20862306a36Sopenharmony_ci if (!probename) 20962306a36Sopenharmony_ci return NULL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci probe_function = __symbol_get(probename); 21262306a36Sopenharmony_ci if (!probe_function) { 21362306a36Sopenharmony_ci request_module("cfi_cmdset_%4.4X", type); 21462306a36Sopenharmony_ci probe_function = __symbol_get(probename); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci kfree(probename); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (probe_function) { 21962306a36Sopenharmony_ci struct mtd_info *mtd; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mtd = (*probe_function)(map, primary); 22262306a36Sopenharmony_ci /* If it was happy, it'll have increased its own use count */ 22362306a36Sopenharmony_ci symbol_put_addr(probe_function); 22462306a36Sopenharmony_ci return mtd; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci#endif 22762306a36Sopenharmony_ci printk(KERN_NOTICE "Support for command set %04X not present\n", type); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return NULL; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic struct mtd_info *check_cmd_set(struct map_info *map, int primary) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct cfi_private *cfi = map->fldrv_priv; 23562306a36Sopenharmony_ci __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (type == P_ID_NONE || type == P_ID_RESERVED) 23862306a36Sopenharmony_ci return NULL; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci switch(type){ 24162306a36Sopenharmony_ci /* We need these for the !CONFIG_MODULES case, 24262306a36Sopenharmony_ci because symbol_get() doesn't work there */ 24362306a36Sopenharmony_ci#ifdef CONFIG_MTD_CFI_INTELEXT 24462306a36Sopenharmony_ci case P_ID_INTEL_EXT: 24562306a36Sopenharmony_ci case P_ID_INTEL_STD: 24662306a36Sopenharmony_ci case P_ID_INTEL_PERFORMANCE: 24762306a36Sopenharmony_ci return cfi_cmdset_0001(map, primary); 24862306a36Sopenharmony_ci#endif 24962306a36Sopenharmony_ci#ifdef CONFIG_MTD_CFI_AMDSTD 25062306a36Sopenharmony_ci case P_ID_AMD_STD: 25162306a36Sopenharmony_ci case P_ID_SST_OLD: 25262306a36Sopenharmony_ci case P_ID_WINBOND: 25362306a36Sopenharmony_ci return cfi_cmdset_0002(map, primary); 25462306a36Sopenharmony_ci#endif 25562306a36Sopenharmony_ci#ifdef CONFIG_MTD_CFI_STAA 25662306a36Sopenharmony_ci case P_ID_ST_ADV: 25762306a36Sopenharmony_ci return cfi_cmdset_0020(map, primary); 25862306a36Sopenharmony_ci#endif 25962306a36Sopenharmony_ci default: 26062306a36Sopenharmony_ci return cfi_cmdset_unknown(map, primary); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 26562306a36Sopenharmony_ciMODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 26662306a36Sopenharmony_ciMODULE_DESCRIPTION("Helper routines for flash chip probe code"); 267