1 |
1275 |
phoenix |
|
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.1.1.1 2004-04-15 01:52:04 phoenix 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 |
|
|
|
99 |
|
|
|
100 |
|
|
/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
|
101 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|