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