brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / drivers / mtd / devices / docprobe.c
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
69 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
70 MODULE_PARM(doc_config_location, "l");
71 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
72
73 static 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
102 static 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
183 static int docfound;
184
185 static 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
262 int __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
285 module_init(init_doc);
286
287 MODULE_LICENSE("GPL");
288 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
289 MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
290