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