Revert last change. Bug noticed by Linus.
[linux-2.6/linux-mips.git] / drivers / mtd / docprobe.c
blob5feb649015742759bebd66202caaa472399d2898
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@mvhi.com> */
6 /* $Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $ */
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.
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.
25 If you have this problem, uncomment the following line:
26 #define DOC_PASSIVE_PROBE
30 #include <linux/config.h>
31 #include <linux/kernel.h>
32 #include <linux/module.h>
33 #include <linux/kmod.h>
34 #include <asm/errno.h>
35 #include <asm/io.h>
36 #include <asm/uaccess.h>
37 #include <linux/miscdevice.h>
38 #include <linux/pci.h>
39 #include <linux/delay.h>
40 #include <linux/malloc.h>
41 #include <linux/sched.h>
42 #include <linux/init.h>
43 #include <linux/types.h>
45 #include <linux/mtd/mtd.h>
46 #include <linux/mtd/nand.h>
47 #include <linux/mtd/doc2000.h>
49 /* Where to look for the devices? */
51 #if defined (__alpha__) || defined(__i386__)
52 static unsigned long __initdata doc_locations[] = {
53 0xc8000, 0xca000, 0xcc000, 0xce000,
54 0xd0000, 0xd2000, 0xd4000, 0xd6000,
55 0xd8000, 0xda000, 0xdc000, 0xde000,
56 0xe0000, 0xe2000, 0xe4000, 0xe6000,
57 0xe8000, 0xea000, 0xec000, 0xee000, 0 };
58 #elif defined(__ppc__)
59 static unsigned long __initdata doc_locations[] = {
60 0xe4000000, 0};
61 #else
62 #warning Unknown architecture for DiskOnChip. No default probe locations defined
63 #endif
65 #ifdef CONFIG_MTD_DOC2000
66 extern void DoC2k_init(struct mtd_info *);
67 #endif
68 #ifdef CONFIG_MTD_DOC2001
69 extern void DoCMil_init(struct mtd_info *);
70 #endif
72 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
74 static inline int __init doccheck(unsigned long potential, unsigned long physadr)
76 unsigned long window=potential;
77 unsigned char tmp, ChipID;
78 #ifndef DOC_PASSIVE_PROBE
79 unsigned char tmp2;
80 #endif
82 /* Routine copied from the Linux DOC driver */
84 /* Check for 0x55 0xAA signature at beginning of window */
85 if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
86 return 0;
88 #ifndef DOC_PASSIVE_PROBE
89 /* It's not possible to cleanly detect the DiskOnChip - the
90 * bootup procedure will put the device into reset mode, and
91 * it's not possible to talk to it without actually writing
92 * to the DOCControl register. So we store the current contents
93 * of the DOCControl register's location, in case we later decide
94 * that it's not a DiskOnChip, and want to put it back how we
95 * found it.
97 tmp2 = ReadDOC(window, DOCControl);
99 /* Reset the DiskOnChip ASIC */
100 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
101 window, DOCControl);
102 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
103 window, DOCControl);
105 /* Enable the DiskOnChip ASIC */
106 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
107 window, DOCControl);
108 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
109 window, DOCControl);
110 #endif /* !DOC_PASSIVE_PROBE */
112 ChipID = ReadDOC(window, ChipID);
114 switch (ChipID) {
115 case DOC_ChipID_Doc2k:
116 /* Check the TOGGLE bit in the ECC register */
117 tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
118 if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
119 return ChipID;
120 break;
122 case DOC_ChipID_DocMil:
123 /* Check the TOGGLE bit in the ECC register */
124 tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
125 if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
126 return ChipID;
127 break;
129 default:
130 printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
131 ChipID, physadr);
133 #ifndef DOC_PASSIVE_PROBE
134 /* Put back the contents of the DOCControl register, in case it's not
135 * actually a DiskOnChip.
137 WriteDOC(tmp2, window, DOCControl);
138 #endif
139 return 0;
142 printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
144 #ifndef DOC_PASSIVE_PROBE
145 /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
146 WriteDOC(tmp2, window, DOCControl);
147 #endif
148 return 0;
152 static void DoC_Probe(unsigned long physadr)
154 unsigned long docptr;
155 struct DiskOnChip *this;
156 struct mtd_info *mtd;
157 int ChipID;
158 char namebuf[15];
159 char *name = namebuf;
160 void (*initroutine)(struct mtd_info *) = NULL;
161 int initroutinedynamic = 0;
163 docptr = (unsigned long)ioremap(physadr, 0x2000);
165 if (!docptr)
166 return;
168 if ((ChipID = doccheck(docptr, physadr))) {
170 mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
172 if (!mtd) {
173 printk("Cannot allocate memory for data structures. Dropping.\n");
174 iounmap((void *)docptr);
175 return;
178 this = (struct DiskOnChip *)(&mtd[1]);
180 memset((char *)mtd,0, sizeof(struct mtd_info));
181 memset((char *)this, 0, sizeof(struct DiskOnChip));
183 mtd->priv = this;
184 this->virtadr = docptr;
185 this->physadr = physadr;
186 this->ChipID = ChipID;
187 sprintf(namebuf, "with ChipID %2.2X", ChipID);
189 switch(ChipID) {
190 case DOC_ChipID_Doc2k:
191 name="2000";
192 #ifdef CONFIG_MTD_DOC2000
193 initroutine = &DoC2k_init;
194 #elif CONFIG_MODULES
195 initroutinedynamic=1;
196 initroutine = (void *)get_module_symbol(NULL, "DoC2k_init");
197 #ifdef CONFIG_KMOD
198 if (!initroutine) {
199 request_module("doc2000");
200 initroutine = (void *)get_module_symbol("doc2000", "DoC2k_init");
202 #endif /* CONFIG_KMOD */
203 #endif
204 break;
206 case DOC_ChipID_DocMil:
207 name="Millennium";
208 #ifdef CONFIG_MTD_DOC2001
209 initroutine = &DocMil_init;
210 #elif CONFIG_MODULES
211 initroutinedynamic=1;
212 initroutine = (void *)get_module_symbol(NULL, "DoCMil_init");
213 #ifdef CONFIG_KMOD
214 if (!initroutine) {
215 request_module("doc2001");
216 initroutine = (void *)get_module_symbol("doc2001", "DoCMil_init");
218 #endif /* CONFIG_KMOD */
219 #endif
220 break;
222 if (initroutine) {
223 (*initroutine)(mtd);
224 #if defined(CONFIG_MODULES) && LINUX_VERSION_CODE >= 0x20400
225 if (initroutinedynamic)
226 put_module_symbol(initroutine);
227 #endif
228 return;
230 printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr);
232 iounmap((void *)docptr);
236 /****************************************************************************
238 * Module stuff
240 ****************************************************************************/
242 #if LINUX_VERSION_CODE < 0x20300
243 #ifdef MODULE
244 #define init_doc init_module
245 #endif
246 #define __exit
247 #endif
249 int __init init_doc(void)
251 int i;
253 printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
254 #ifdef PRERELEASE
255 printk(KERN_INFO "$Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $\n");
256 #endif
258 for (i=0; doc_locations[i]; i++) {
259 DoC_Probe(doc_locations[i]);
262 return 0;
267 #if LINUX_VERSION_CODE > 0x20300
268 module_init(init_doc);
269 #endif