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