linux-old/drivers/mtd/chips/gen_probe.c
<<
>>
Prefs
   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.9 2002/09/05 05:15:32 acurtis 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"gen_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         * NOTE: Here, we're checking if there is room for another chip
 111         *       the same size within the mapping. Therefore, 
 112         *       base + chipsize <= map->size is the correct thing to do, 
 113         *       because, base + chipsize would be the  _first_ byte of the
 114         *       next chip, not the one we're currently pondering.
 115         */
 116
 117        for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
 118             base += (1<<cfi.chipshift))
 119                cp->probe_chip(map, base, &chip[0], &cfi);
 120
 121        /*
 122         * Now allocate the space for the structures we need to return to 
 123         * our caller, and copy the appropriate data into them.
 124         */
 125
 126        retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
 127
 128        if (!retcfi) {
 129                printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
 130                kfree(cfi.cfiq);
 131                return NULL;
 132        }
 133
 134        memcpy(retcfi, &cfi, sizeof(cfi));
 135        memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
 136
 137        /* Fix up the stuff that breaks when you move it */
 138        for (i=0; i< retcfi->numchips; i++) {
 139                init_waitqueue_head(&retcfi->chips[i].wq);
 140                spin_lock_init(&retcfi->chips[i]._spinlock);
 141                retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
 142        }
 143
 144        return retcfi;
 145}
 146
 147        
 148static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
 149                             struct cfi_private *cfi)
 150{
 151        switch (map->buswidth) {
 152#ifdef CFIDEV_BUSWIDTH_1                
 153        case CFIDEV_BUSWIDTH_1:
 154                cfi->interleave = CFIDEV_INTERLEAVE_1;
 155
 156                cfi->device_type = CFI_DEVICETYPE_X8;
 157                if (cp->probe_chip(map, 0, NULL, cfi))
 158                        return 1;
 159
 160                cfi->device_type = CFI_DEVICETYPE_X16;
 161                if (cp->probe_chip(map, 0, NULL, cfi))
 162                        return 1;
 163                break;                  
 164#endif /* CFIDEV_BUSWITDH_1 */
 165
 166#ifdef CFIDEV_BUSWIDTH_2                
 167        case CFIDEV_BUSWIDTH_2:
 168#ifdef CFIDEV_INTERLEAVE_1
 169                cfi->interleave = CFIDEV_INTERLEAVE_1;
 170
 171                cfi->device_type = CFI_DEVICETYPE_X16;
 172                if (cp->probe_chip(map, 0, NULL, cfi))
 173                        return 1;
 174#endif /* CFIDEV_INTERLEAVE_1 */
 175#ifdef CFIDEV_INTERLEAVE_2
 176                cfi->interleave = CFIDEV_INTERLEAVE_2;
 177
 178                cfi->device_type = CFI_DEVICETYPE_X8;
 179                if (cp->probe_chip(map, 0, NULL, cfi))
 180                        return 1;
 181
 182                cfi->device_type = CFI_DEVICETYPE_X16;
 183                if (cp->probe_chip(map, 0, NULL, cfi))
 184                        return 1;
 185#endif /* CFIDEV_INTERLEAVE_2 */
 186                break;                  
 187#endif /* CFIDEV_BUSWIDTH_2 */
 188
 189#ifdef CFIDEV_BUSWIDTH_4
 190        case CFIDEV_BUSWIDTH_4:
 191#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
 192                cfi->interleave = CFIDEV_INTERLEAVE_1;
 193
 194                cfi->device_type = CFI_DEVICETYPE_X32;
 195                if (cp->probe_chip(map, 0, NULL, cfi))
 196                        return 1;
 197#endif /* CFIDEV_INTERLEAVE_1 */
 198#ifdef CFIDEV_INTERLEAVE_2
 199                cfi->interleave = CFIDEV_INTERLEAVE_2;
 200
 201#ifdef SOMEONE_ACTUALLY_MAKES_THESE
 202                cfi->device_type = CFI_DEVICETYPE_X32;
 203                if (cp->probe_chip(map, 0, NULL, cfi))
 204                        return 1;
 205#endif
 206                cfi->device_type = CFI_DEVICETYPE_X16;
 207                if (cp->probe_chip(map, 0, NULL, cfi))
 208                        return 1;
 209
 210                cfi->device_type = CFI_DEVICETYPE_X8;
 211                if (cp->probe_chip(map, 0, NULL, cfi))
 212                        return 1;
 213#endif /* CFIDEV_INTERLEAVE_2 */
 214#ifdef CFIDEV_INTERLEAVE_4
 215                cfi->interleave = CFIDEV_INTERLEAVE_4;
 216
 217#ifdef SOMEONE_ACTUALLY_MAKES_THESE
 218                cfi->device_type = CFI_DEVICETYPE_X32;
 219                if (cp->probe_chip(map, 0, NULL, cfi))
 220                        return 1;
 221#endif
 222                cfi->device_type = CFI_DEVICETYPE_X16;
 223                if (cp->probe_chip(map, 0, NULL, cfi))
 224                        return 1;
 225
 226                cfi->device_type = CFI_DEVICETYPE_X8;
 227                if (cp->probe_chip(map, 0, NULL, cfi))
 228                        return 1;
 229#endif /* CFIDEV_INTERLEAVE_4 */
 230                break;
 231#endif /* CFIDEV_BUSWIDTH_4 */
 232
 233#ifdef CFIDEV_BUSWIDTH_8
 234        case CFIDEV_BUSWIDTH_8:
 235#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
 236                cfi->interleave = CFIDEV_INTERLEAVE_2;
 237
 238                cfi->device_type = CFI_DEVICETYPE_X32;
 239                if (cp->probe_chip(map, 0, NULL, cfi))
 240                        return 1;
 241#endif /* CFIDEV_INTERLEAVE_2 */
 242#ifdef CFIDEV_INTERLEAVE_4
 243                cfi->interleave = CFIDEV_INTERLEAVE_4;
 244
 245#ifdef SOMEONE_ACTUALLY_MAKES_THESE
 246                cfi->device_type = CFI_DEVICETYPE_X32;
 247                if (cp->probe_chip(map, 0, NULL, cfi))
 248                        return 1;
 249#endif
 250                cfi->device_type = CFI_DEVICETYPE_X16;
 251                if (cp->probe_chip(map, 0, NULL, cfi))
 252                        return 1;
 253#endif /* CFIDEV_INTERLEAVE_4 */
 254#ifdef CFIDEV_INTERLEAVE_8
 255                cfi->interleave = CFIDEV_INTERLEAVE_8;
 256
 257                cfi->device_type = CFI_DEVICETYPE_X16;
 258                if (cp->probe_chip(map, 0, NULL, cfi))
 259                        return 1;
 260
 261                cfi->device_type = CFI_DEVICETYPE_X8;
 262                if (cp->probe_chip(map, 0, NULL, cfi))
 263                        return 1;
 264#endif /* CFIDEV_INTERLEAVE_8 */
 265                break;
 266#endif /* CFIDEV_BUSWIDTH_8 */
 267
 268        default:
 269                printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
 270                return 0;
 271        }
 272        return 0;
 273}
 274
 275
 276typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
 277
 278extern cfi_cmdset_fn_t cfi_cmdset_0001;
 279extern cfi_cmdset_fn_t cfi_cmdset_0002;
 280extern cfi_cmdset_fn_t cfi_cmdset_0020;
 281
 282static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 
 283                                                  int primary)
 284{
 285        struct cfi_private *cfi = map->fldrv_priv;
 286        __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
 287#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)
 288        char probename[32];
 289        cfi_cmdset_fn_t *probe_function;
 290
 291        sprintf(probename, "cfi_cmdset_%4.4X", type);
 292                
 293        probe_function = inter_module_get_request(probename, probename);
 294
 295        if (probe_function) {
 296                struct mtd_info *mtd;
 297
 298                mtd = (*probe_function)(map, primary);
 299                /* If it was happy, it'll have increased its own use count */
 300                inter_module_put(probename);
 301                return mtd;
 302        }
 303#endif
 304        printk(KERN_NOTICE "Support for command set %04X not present\n",
 305               type);
 306
 307        return NULL;
 308}
 309
 310static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
 311{
 312        struct cfi_private *cfi = map->fldrv_priv;
 313        __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
 314        
 315        if (type == P_ID_NONE || type == P_ID_RESERVED)
 316                return NULL;
 317
 318        switch(type){
 319                /* Urgh. Ifdefs. The version with weak symbols was
 320                 * _much_ nicer. Shame it didn't seem to work on
 321                 * anything but x86, really.
 322                 * But we can't rely in inter_module_get() because
 323                 * that'd mean we depend on link order.
 324                 */
 325#ifdef CONFIG_MTD_CFI_INTELEXT
 326        case 0x0001:
 327        case 0x0003:
 328                return cfi_cmdset_0001(map, primary);
 329#endif
 330#ifdef CONFIG_MTD_CFI_AMDSTD
 331        case 0x0002:
 332                return cfi_cmdset_0002(map, primary);
 333#endif
 334#ifdef CONFIG_MTD_CFI_STAA
 335        case 0x0020:
 336                return cfi_cmdset_0020(map, primary);
 337#endif
 338        }
 339
 340        return cfi_cmdset_unknown(map, primary);
 341}
 342
 343MODULE_LICENSE("GPL");
 344MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 345MODULE_DESCRIPTION("Helper routines for flash chip probe code");
 346