linux-old/drivers/mtd/devices/docprobe.c
<<
>>
Prefs
   1
   2/* Linux driver for Disk-On-Chip devices                        */
   3/* Probe routines common to all DoC devices                     */
   4/* (C) 1999 Machine Vision Holdings, Inc.                       */
   5/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>          */
   6
   7/* $Id: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $       */
   8
   9
  10
  11/* DOC_PASSIVE_PROBE:
  12   In order to ensure that the BIOS checksum is correct at boot time, and 
  13   hence that the onboard BIOS extension gets executed, the DiskOnChip 
  14   goes into reset mode when it is read sequentially: all registers 
  15   return 0xff until the chip is woken up again by writing to the 
  16   DOCControl register. 
  17
  18   Unfortunately, this means that the probe for the DiskOnChip is unsafe, 
  19   because one of the first things it does is write to where it thinks 
  20   the DOCControl register should be - which may well be shared memory 
  21   for another device. I've had machines which lock up when this is 
  22   attempted. Hence the possibility to do a passive probe, which will fail 
  23   to detect a chip in reset mode, but is at least guaranteed not to lock
  24   the machine.
  25
  26   If you have this problem, uncomment the following line:
  27#define DOC_PASSIVE_PROBE
  28*/
  29
  30
  31/* DOC_SINGLE_DRIVER:
  32   Millennium driver has been merged into DOC2000 driver.
  33
  34   The newly-merged driver doesn't appear to work for writing. It's the
  35   same with the DiskOnChip 2000 and the Millennium. If you have a 
  36   Millennium and you want write support to work, remove the definition
  37   of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver.
  38
  39   Otherwise, it's left on in the hope that it'll annoy someone with
  40   a Millennium enough that they go through and work out what the 
  41   difference is :)
  42*/
  43#define DOC_SINGLE_DRIVER
  44
  45#include <linux/config.h>
  46#include <linux/kernel.h>
  47#include <linux/module.h>
  48#include <asm/errno.h>
  49#include <asm/io.h>
  50#include <asm/uaccess.h>
  51#include <linux/miscdevice.h>
  52#include <linux/pci.h>
  53#include <linux/delay.h>
  54#include <linux/slab.h>
  55#include <linux/sched.h>
  56#include <linux/init.h>
  57#include <linux/types.h>
  58
  59#include <linux/mtd/mtd.h>
  60#include <linux/mtd/nand.h>
  61#include <linux/mtd/doc2000.h>
  62
  63/* Where to look for the devices? */
  64#ifndef CONFIG_MTD_DOCPROBE_ADDRESS
  65#define CONFIG_MTD_DOCPROBE_ADDRESS 0
  66#endif
  67
  68
  69static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
  70MODULE_PARM(doc_config_location, "l");
  71MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
  72
  73static unsigned long __initdata doc_locations[] = {
  74#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
  75#ifdef CONFIG_MTD_DOCPROBE_HIGH
  76        0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
  77        0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
  78        0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
  79        0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
  80        0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
  81#else /*  CONFIG_MTD_DOCPROBE_HIGH */
  82        0xc8000, 0xca000, 0xcc000, 0xce000, 
  83        0xd0000, 0xd2000, 0xd4000, 0xd6000,
  84        0xd8000, 0xda000, 0xdc000, 0xde000, 
  85        0xe0000, 0xe2000, 0xe4000, 0xe6000, 
  86        0xe8000, 0xea000, 0xec000, 0xee000,
  87#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
  88#elif defined(__PPC__)
  89        0xe4000000,
  90#elif defined(CONFIG_MOMENCO_OCELOT)
  91        0x2f000000,
  92        0xff000000,
  93#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
  94        0xff000000,
  95##else
  96#warning Unknown architecture for DiskOnChip. No default probe locations defined
  97#endif
  98        0 };
  99
 100/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
 101
 102static inline int __init doccheck(unsigned long potential, unsigned long physadr)
 103{
 104        unsigned long window=potential;
 105        unsigned char tmp, ChipID;
 106#ifndef DOC_PASSIVE_PROBE
 107        unsigned char tmp2;
 108#endif
 109
 110        /* Routine copied from the Linux DOC driver */
 111
 112#ifdef CONFIG_MTD_DOCPROBE_55AA
 113        /* Check for 0x55 0xAA signature at beginning of window,
 114           this is no longer true once we remove the IPL (for Millennium */
 115        if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
 116                return 0;
 117#endif /* CONFIG_MTD_DOCPROBE_55AA */
 118
 119#ifndef DOC_PASSIVE_PROBE       
 120        /* It's not possible to cleanly detect the DiskOnChip - the
 121         * bootup procedure will put the device into reset mode, and
 122         * it's not possible to talk to it without actually writing
 123         * to the DOCControl register. So we store the current contents
 124         * of the DOCControl register's location, in case we later decide
 125         * that it's not a DiskOnChip, and want to put it back how we
 126         * found it. 
 127         */
 128        tmp2 = ReadDOC(window, DOCControl);
 129        
 130        /* Reset the DiskOnChip ASIC */
 131        WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
 132                 window, DOCControl);
 133        WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
 134                 window, DOCControl);
 135        
 136        /* Enable the DiskOnChip ASIC */
 137        WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
 138                 window, DOCControl);
 139        WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
 140                 window, DOCControl);
 141#endif /* !DOC_PASSIVE_PROBE */ 
 142
 143        ChipID = ReadDOC(window, ChipID);
 144  
 145        switch (ChipID) {
 146        case DOC_ChipID_Doc2k:
 147                /* Check the TOGGLE bit in the ECC register */
 148                tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
 149                if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
 150                                return ChipID;
 151                break;
 152                
 153        case DOC_ChipID_DocMil:
 154                /* Check the TOGGLE bit in the ECC register */
 155                tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
 156                if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
 157                                return ChipID;
 158                break;
 159                
 160        default:
 161#ifndef CONFIG_MTD_DOCPROBE_55AA
 162                printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
 163                       ChipID, physadr);
 164#endif
 165#ifndef DOC_PASSIVE_PROBE
 166                /* Put back the contents of the DOCControl register, in case it's not
 167                 * actually a DiskOnChip.
 168                 */
 169                WriteDOC(tmp2, window, DOCControl);
 170#endif
 171                return 0;
 172        }
 173
 174        printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
 175
 176#ifndef DOC_PASSIVE_PROBE
 177        /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
 178        WriteDOC(tmp2, window, DOCControl);
 179#endif
 180        return 0;
 181}   
 182
 183static int docfound;
 184
 185static void __init DoC_Probe(unsigned long physadr)
 186{
 187        unsigned long docptr;
 188        struct DiskOnChip *this;
 189        struct mtd_info *mtd;
 190        int ChipID;
 191        char namebuf[15];
 192        char *name = namebuf;
 193        char *im_funcname = NULL;
 194        char *im_modname = NULL;
 195        void (*initroutine)(struct mtd_info *) = NULL;
 196
 197        docptr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
 198        
 199        if (!docptr)
 200                return;
 201        
 202        if ((ChipID = doccheck(docptr, physadr))) {
 203                docfound = 1;
 204                mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
 205
 206                if (!mtd) {
 207                        printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
 208                        iounmap((void *)docptr);
 209                        return;
 210                }
 211                
 212                this = (struct DiskOnChip *)(&mtd[1]);
 213                
 214                memset((char *)mtd,0, sizeof(struct mtd_info));
 215                memset((char *)this, 0, sizeof(struct DiskOnChip));
 216
 217                mtd->priv = this;
 218                this->virtadr = docptr;
 219                this->physadr = physadr;
 220                this->ChipID = ChipID;
 221                sprintf(namebuf, "with ChipID %2.2X", ChipID);
 222
 223                switch(ChipID) {
 224                case DOC_ChipID_Doc2k:
 225                        name="2000";
 226                        im_funcname = "DoC2k_init";
 227                        im_modname = "doc2000";
 228                        break;
 229                        
 230                case DOC_ChipID_DocMil:
 231                        name="Millennium";
 232#ifdef DOC_SINGLE_DRIVER
 233                        im_funcname = "DoC2k_init";
 234                        im_modname = "doc2000";
 235#else
 236                        im_funcname = "DoCMil_init";
 237                        im_modname = "doc2001";
 238#endif /* DOC_SINGLE_DRIVER */
 239                        break;
 240                }
 241
 242                if (im_funcname)
 243                        initroutine = inter_module_get_request(im_funcname, im_modname);
 244
 245                if (initroutine) {
 246                        (*initroutine)(mtd);
 247                        inter_module_put(im_funcname);
 248                        return;
 249                }
 250                printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
 251        }
 252        iounmap((void *)docptr);
 253}
 254
 255
 256/****************************************************************************
 257 *
 258 * Module stuff
 259 *
 260 ****************************************************************************/
 261
 262int __init init_doc(void)
 263{
 264        int i;
 265        
 266        if (doc_config_location) {
 267                printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
 268                DoC_Probe(doc_config_location);
 269        } else {
 270                for (i=0; doc_locations[i]; i++) {
 271                        DoC_Probe(doc_locations[i]);
 272                }
 273        }
 274        /* No banner message any more. Print a message if no DiskOnChip
 275           found, so the user knows we at least tried. */
 276        if (!docfound)
 277                printk(KERN_INFO "No recognised DiskOnChip devices found\n");
 278        /* So it looks like we've been used and we get unloaded */
 279        MOD_INC_USE_COUNT;
 280        MOD_DEC_USE_COUNT;
 281        return 0;
 282        
 283}
 284
 285module_init(init_doc);
 286
 287MODULE_LICENSE("GPL");
 288MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 289MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
 290
 291