[MTD] Use mutex instead of semaphore in dataflash driver
[linux-2.6.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)
85         0x2f000000,
86         0xff000000,
87 #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
88         0xff000000,
89 ##else
90 #warning Unknown architecture for DiskOnChip. No default probe locations defined
91 #endif
92         0xffffffff };
93
94 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
95
96 static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
97 {
98         void __iomem *window=potential;
99         unsigned char tmp, tmpb, tmpc, ChipID;
100 #ifndef DOC_PASSIVE_PROBE
101         unsigned char tmp2;
102 #endif
103
104         /* Routine copied from the Linux DOC driver */
105
106 #ifdef CONFIG_MTD_DOCPROBE_55AA
107         /* Check for 0x55 0xAA signature at beginning of window,
108            this is no longer true once we remove the IPL (for Millennium */
109         if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
110                 return 0;
111 #endif /* CONFIG_MTD_DOCPROBE_55AA */
112
113 #ifndef DOC_PASSIVE_PROBE
114         /* It's not possible to cleanly detect the DiskOnChip - the
115          * bootup procedure will put the device into reset mode, and
116          * it's not possible to talk to it without actually writing
117          * to the DOCControl register. So we store the current contents
118          * of the DOCControl register's location, in case we later decide
119          * that it's not a DiskOnChip, and want to put it back how we
120          * found it.
121          */
122         tmp2 = ReadDOC(window, DOCControl);
123
124         /* Reset the DiskOnChip ASIC */
125         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
126                  window, DOCControl);
127         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
128                  window, DOCControl);
129
130         /* Enable the DiskOnChip ASIC */
131         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
132                  window, DOCControl);
133         WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
134                  window, DOCControl);
135 #endif /* !DOC_PASSIVE_PROBE */
136
137         /* We need to read the ChipID register four times. For some
138            newer DiskOnChip 2000 units, the first three reads will
139            return the DiskOnChip Millennium ident. Don't ask. */
140         ChipID = ReadDOC(window, ChipID);
141
142         switch (ChipID) {
143         case DOC_ChipID_Doc2k:
144                 /* Check the TOGGLE bit in the ECC register */
145                 tmp  = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
146                 tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
147                 tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
148                 if (tmp != tmpb && tmp == tmpc)
149                                 return ChipID;
150                 break;
151
152         case DOC_ChipID_DocMil:
153                 /* Check for the new 2000 with Millennium ASIC */
154                 ReadDOC(window, ChipID);
155                 ReadDOC(window, ChipID);
156                 if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
157                         ChipID = DOC_ChipID_Doc2kTSOP;
158
159                 /* Check the TOGGLE bit in the ECC register */
160                 tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
161                 tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
162                 tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
163                 if (tmp != tmpb && tmp == tmpc)
164                                 return ChipID;
165                 break;
166
167         case DOC_ChipID_DocMilPlus16:
168         case DOC_ChipID_DocMilPlus32:
169         case 0:
170                 /* Possible Millennium+, need to do more checks */
171 #ifndef DOC_PASSIVE_PROBE
172                 /* Possibly release from power down mode */
173                 for (tmp = 0; (tmp < 4); tmp++)
174                         ReadDOC(window, Mplus_Power);
175
176                 /* Reset the DiskOnChip ASIC */
177                 tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
178                         DOC_MODE_BDECT;
179                 WriteDOC(tmp, window, Mplus_DOCControl);
180                 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
181
182                 mdelay(1);
183                 /* Enable the DiskOnChip ASIC */
184                 tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
185                         DOC_MODE_BDECT;
186                 WriteDOC(tmp, window, Mplus_DOCControl);
187                 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
188                 mdelay(1);
189 #endif /* !DOC_PASSIVE_PROBE */
190
191                 ChipID = ReadDOC(window, ChipID);
192
193                 switch (ChipID) {
194                 case DOC_ChipID_DocMilPlus16:
195                 case DOC_ChipID_DocMilPlus32:
196                         /* Check the TOGGLE bit in the toggle register */
197                         tmp  = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
198                         tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
199                         tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
200                         if (tmp != tmpb && tmp == tmpc)
201                                         return ChipID;
202                 default:
203                         break;
204                 }
205                 /* FALL TRHU */
206
207         default:
208
209 #ifdef CONFIG_MTD_DOCPROBE_55AA
210                 printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
211                        ChipID, physadr);
212 #endif
213 #ifndef DOC_PASSIVE_PROBE
214                 /* Put back the contents of the DOCControl register, in case it's not
215                  * actually a DiskOnChip.
216                  */
217                 WriteDOC(tmp2, window, DOCControl);
218 #endif
219                 return 0;
220         }
221
222         printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
223
224 #ifndef DOC_PASSIVE_PROBE
225         /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
226         WriteDOC(tmp2, window, DOCControl);
227 #endif
228         return 0;
229 }
230
231 static int docfound;
232
233 extern void DoC2k_init(struct mtd_info *);
234 extern void DoCMil_init(struct mtd_info *);
235 extern void DoCMilPlus_init(struct mtd_info *);
236
237 static void __init DoC_Probe(unsigned long physadr)
238 {
239         void __iomem *docptr;
240         struct DiskOnChip *this;
241         struct mtd_info *mtd;
242         int ChipID;
243         char namebuf[15];
244         char *name = namebuf;
245         void (*initroutine)(struct mtd_info *) = NULL;
246
247         docptr = ioremap(physadr, DOC_IOREMAP_LEN);
248
249         if (!docptr)
250                 return;
251
252         if ((ChipID = doccheck(docptr, physadr))) {
253                 if (ChipID == DOC_ChipID_Doc2kTSOP) {
254                         /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
255                         printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
256                         iounmap(docptr);
257                         return;
258                 }
259                 docfound = 1;
260                 mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
261
262                 if (!mtd) {
263                         printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
264                         iounmap(docptr);
265                         return;
266                 }
267
268                 this = (struct DiskOnChip *)(&mtd[1]);
269
270                 memset((char *)mtd,0, sizeof(struct mtd_info));
271                 memset((char *)this, 0, sizeof(struct DiskOnChip));
272
273                 mtd->priv = this;
274                 this->virtadr = docptr;
275                 this->physadr = physadr;
276                 this->ChipID = ChipID;
277                 sprintf(namebuf, "with ChipID %2.2X", ChipID);
278
279                 switch(ChipID) {
280                 case DOC_ChipID_Doc2kTSOP:
281                         name="2000 TSOP";
282                         initroutine = symbol_request(DoC2k_init);
283                         break;
284
285                 case DOC_ChipID_Doc2k:
286                         name="2000";
287                         initroutine = symbol_request(DoC2k_init);
288                         break;
289
290                 case DOC_ChipID_DocMil:
291                         name="Millennium";
292 #ifdef DOC_SINGLE_DRIVER
293                         initroutine = symbol_request(DoC2k_init);
294 #else
295                         initroutine = symbol_request(DoCMil_init);
296 #endif /* DOC_SINGLE_DRIVER */
297                         break;
298
299                 case DOC_ChipID_DocMilPlus16:
300                 case DOC_ChipID_DocMilPlus32:
301                         name="MillenniumPlus";
302                         initroutine = symbol_request(DoCMilPlus_init);
303                         break;
304                 }
305
306                 if (initroutine) {
307                         (*initroutine)(mtd);
308                         symbol_put_addr(initroutine);
309                         return;
310                 }
311                 printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
312                 kfree(mtd);
313         }
314         iounmap(docptr);
315 }
316
317
318 /****************************************************************************
319  *
320  * Module stuff
321  *
322  ****************************************************************************/
323
324 static int __init init_doc(void)
325 {
326         int i;
327
328         if (doc_config_location) {
329                 printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
330                 DoC_Probe(doc_config_location);
331         } else {
332                 for (i=0; (doc_locations[i] != 0xffffffff); i++) {
333                         DoC_Probe(doc_locations[i]);
334                 }
335         }
336         /* No banner message any more. Print a message if no DiskOnChip
337            found, so the user knows we at least tried. */
338         if (!docfound)
339                 printk(KERN_INFO "No recognised DiskOnChip devices found\n");
340         return -EAGAIN;
341 }
342
343 module_init(init_doc);
344
345 MODULE_LICENSE("GPL");
346 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
347 MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
348