Fix WARN_ON() on bitfield ops
[cascardo/linux.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.46 2005/11/07 11:14:25 gleixner 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 old Millennium-only driver has been retained just in case there
35    are problems with the new code. If the combined driver doesn't work
36    for you, you can try the old one by undefining DOC_SINGLE_DRIVER
37    below and also enabling it in your configuration. If this fixes the
38    problems, please send a report to the MTD mailing list at
39    <linux-mtd@lists.infradead.org>.
40 */
41 #define DOC_SINGLE_DRIVER
42
43 #include <linux/kernel.h>
44 #include <linux/module.h>
45 #include <asm/errno.h>
46 #include <asm/io.h>
47 #include <linux/delay.h>
48 #include <linux/slab.h>
49 #include <linux/init.h>
50 #include <linux/types.h>
51
52 #include <linux/mtd/mtd.h>
53 #include <linux/mtd/nand.h>
54 #include <linux/mtd/doc2000.h>
55 #include <linux/mtd/compatmac.h>
56
57 /* Where to look for the devices? */
58 #ifndef CONFIG_MTD_DOCPROBE_ADDRESS
59 #define CONFIG_MTD_DOCPROBE_ADDRESS 0
60 #endif
61
62
63 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
64 module_param(doc_config_location, ulong, 0);
65 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
66
67 static unsigned long __initdata doc_locations[] = {
68 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
69 #ifdef CONFIG_MTD_DOCPROBE_HIGH
70         0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
71         0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
72         0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
73         0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
74         0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
75 #else /*  CONFIG_MTD_DOCPROBE_HIGH */
76         0xc8000, 0xca000, 0xcc000, 0xce000,
77         0xd0000, 0xd2000, 0xd4000, 0xd6000,
78         0xd8000, 0xda000, 0xdc000, 0xde000,
79         0xe0000, 0xe2000, 0xe4000, 0xe6000,
80         0xe8000, 0xea000, 0xec000, 0xee000,
81 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
82 #elif defined(__PPC__)
83         0xe4000000,
84 #elif defined(CONFIG_MOMENCO_OCELOT_G)
85         0xff000000,
86 ##else
87 #warning Unknown architecture for DiskOnChip. No default probe locations defined
88 #endif
89         0xffffffff };
90
91 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
92
93 static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
94 {
95         void __iomem *window=potential;
96         unsigned char tmp, tmpb, tmpc, ChipID;
97 #ifndef DOC_PASSIVE_PROBE
98         unsigned char tmp2;
99 #endif
100
101         /* Routine copied from the Linux DOC driver */
102
103 #ifdef CONFIG_MTD_DOCPROBE_55AA
104         /* Check for 0x55 0xAA signature at beginning of window,
105            this is no longer true once we remove the IPL (for Millennium */
106         if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
107                 return 0;
108 #endif /* CONFIG_MTD_DOCPROBE_55AA */
109
110 #ifndef DOC_PASSIVE_PROBE
111         /* It's not possible to cleanly detect the DiskOnChip - the
112          * bootup procedure will put the device into reset mode, and
113          * it's not possible to talk to it without actually writing
114          * to the DOCControl register. So we store the current contents
115          * of the DOCControl register's location, in case we later decide
116          * that it's not a DiskOnChip, and want to put it back how we
117          * found it.
118          */
119         tmp2 = ReadDOC(window, DOCControl);
120
121         /* Reset the DiskOnChip ASIC */
122         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
123                  window, DOCControl);
124         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
125                  window, DOCControl);
126
127         /* Enable the DiskOnChip ASIC */
128         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
129                  window, DOCControl);
130         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
131                  window, DOCControl);
132 #endif /* !DOC_PASSIVE_PROBE */
133
134         /* We need to read the ChipID register four times. For some
135            newer DiskOnChip 2000 units, the first three reads will
136            return the DiskOnChip Millennium ident. Don't ask. */
137         ChipID = ReadDOC(window, ChipID);
138
139         switch (ChipID) {
140         case DOC_ChipID_Doc2k:
141                 /* Check the TOGGLE bit in the ECC register */
142                 tmp  = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
143                 tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
144                 tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
145                 if (tmp != tmpb && tmp == tmpc)
146                                 return ChipID;
147                 break;
148
149         case DOC_ChipID_DocMil:
150                 /* Check for the new 2000 with Millennium ASIC */
151                 ReadDOC(window, ChipID);
152                 ReadDOC(window, ChipID);
153                 if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
154                         ChipID = DOC_ChipID_Doc2kTSOP;
155
156                 /* Check the TOGGLE bit in the ECC register */
157                 tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
158                 tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
159                 tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
160                 if (tmp != tmpb && tmp == tmpc)
161                                 return ChipID;
162                 break;
163
164         case DOC_ChipID_DocMilPlus16:
165         case DOC_ChipID_DocMilPlus32:
166         case 0:
167                 /* Possible Millennium+, need to do more checks */
168 #ifndef DOC_PASSIVE_PROBE
169                 /* Possibly release from power down mode */
170                 for (tmp = 0; (tmp < 4); tmp++)
171                         ReadDOC(window, Mplus_Power);
172
173                 /* Reset the DiskOnChip ASIC */
174                 tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
175                         DOC_MODE_BDECT;
176                 WriteDOC(tmp, window, Mplus_DOCControl);
177                 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
178
179                 mdelay(1);
180                 /* Enable the DiskOnChip ASIC */
181                 tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
182                         DOC_MODE_BDECT;
183                 WriteDOC(tmp, window, Mplus_DOCControl);
184                 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
185                 mdelay(1);
186 #endif /* !DOC_PASSIVE_PROBE */
187
188                 ChipID = ReadDOC(window, ChipID);
189
190                 switch (ChipID) {
191                 case DOC_ChipID_DocMilPlus16:
192                 case DOC_ChipID_DocMilPlus32:
193                         /* Check the TOGGLE bit in the toggle register */
194                         tmp  = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
195                         tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
196                         tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
197                         if (tmp != tmpb && tmp == tmpc)
198                                         return ChipID;
199                 default:
200                         break;
201                 }
202                 /* FALL TRHU */
203
204         default:
205
206 #ifdef CONFIG_MTD_DOCPROBE_55AA
207                 printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
208                        ChipID, physadr);
209 #endif
210 #ifndef DOC_PASSIVE_PROBE
211                 /* Put back the contents of the DOCControl register, in case it's not
212                  * actually a DiskOnChip.
213                  */
214                 WriteDOC(tmp2, window, DOCControl);
215 #endif
216                 return 0;
217         }
218
219         printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
220
221 #ifndef DOC_PASSIVE_PROBE
222         /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
223         WriteDOC(tmp2, window, DOCControl);
224 #endif
225         return 0;
226 }
227
228 static int docfound;
229
230 extern void DoC2k_init(struct mtd_info *);
231 extern void DoCMil_init(struct mtd_info *);
232 extern void DoCMilPlus_init(struct mtd_info *);
233
234 static void __init DoC_Probe(unsigned long physadr)
235 {
236         void __iomem *docptr;
237         struct DiskOnChip *this;
238         struct mtd_info *mtd;
239         int ChipID;
240         char namebuf[15];
241         char *name = namebuf;
242         void (*initroutine)(struct mtd_info *) = NULL;
243
244         docptr = ioremap(physadr, DOC_IOREMAP_LEN);
245
246         if (!docptr)
247                 return;
248
249         if ((ChipID = doccheck(docptr, physadr))) {
250                 if (ChipID == DOC_ChipID_Doc2kTSOP) {
251                         /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
252                         printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
253                         iounmap(docptr);
254                         return;
255                 }
256                 docfound = 1;
257                 mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
258
259                 if (!mtd) {
260                         printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
261                         iounmap(docptr);
262                         return;
263                 }
264
265                 this = (struct DiskOnChip *)(&mtd[1]);
266
267                 memset((char *)mtd,0, sizeof(struct mtd_info));
268                 memset((char *)this, 0, sizeof(struct DiskOnChip));
269
270                 mtd->priv = this;
271                 this->virtadr = docptr;
272                 this->physadr = physadr;
273                 this->ChipID = ChipID;
274                 sprintf(namebuf, "with ChipID %2.2X", ChipID);
275
276                 switch(ChipID) {
277                 case DOC_ChipID_Doc2kTSOP:
278                         name="2000 TSOP";
279                         initroutine = symbol_request(DoC2k_init);
280                         break;
281
282                 case DOC_ChipID_Doc2k:
283                         name="2000";
284                         initroutine = symbol_request(DoC2k_init);
285                         break;
286
287                 case DOC_ChipID_DocMil:
288                         name="Millennium";
289 #ifdef DOC_SINGLE_DRIVER
290                         initroutine = symbol_request(DoC2k_init);
291 #else
292                         initroutine = symbol_request(DoCMil_init);
293 #endif /* DOC_SINGLE_DRIVER */
294                         break;
295
296                 case DOC_ChipID_DocMilPlus16:
297                 case DOC_ChipID_DocMilPlus32:
298                         name="MillenniumPlus";
299                         initroutine = symbol_request(DoCMilPlus_init);
300                         break;
301                 }
302
303                 if (initroutine) {
304                         (*initroutine)(mtd);
305                         symbol_put_addr(initroutine);
306                         return;
307                 }
308                 printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
309                 kfree(mtd);
310         }
311         iounmap(docptr);
312 }
313
314
315 /****************************************************************************
316  *
317  * Module stuff
318  *
319  ****************************************************************************/
320
321 static int __init init_doc(void)
322 {
323         int i;
324
325         if (doc_config_location) {
326                 printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
327                 DoC_Probe(doc_config_location);
328         } else {
329                 for (i=0; (doc_locations[i] != 0xffffffff); i++) {
330                         DoC_Probe(doc_locations[i]);
331                 }
332         }
333         /* No banner message any more. Print a message if no DiskOnChip
334            found, so the user knows we at least tried. */
335         if (!docfound)
336                 printk(KERN_INFO "No recognised DiskOnChip devices found\n");
337         return -EAGAIN;
338 }
339
340 module_init(init_doc);
341
342 MODULE_LICENSE("GPL");
343 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
344 MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
345