Merge with 2.4.0-test3-pre4.
[linux-2.6/linux-mips.git] / drivers / mtd / docprobe.c
blobb2c4380d35ae09f54e4aad5afbbc016be2da61c3
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/kernel.h>
31 #include <linux/module.h>
32 #include <linux/kmod.h>
33 #include <asm/errno.h>
34 #include <asm/io.h>
35 #include <asm/uaccess.h>
36 #include <linux/miscdevice.h>
37 #include <linux/pci.h>
38 #include <linux/delay.h>
39 #include <linux/malloc.h>
40 #include <linux/sched.h>
41 #include <linux/init.h>
42 #include <linux/types.h>
44 #include <linux/mtd/mtd.h>
45 #include <linux/mtd/nand.h>
46 #include <linux/mtd/doc2000.h>
48 /* Where to look for the devices? */
50 #if defined (__alpha__) || defined(__i386__)
51 static unsigned long __initdata doc_locations[] = {
52 0xc8000, 0xca000, 0xcc000, 0xce000,
53 0xd0000, 0xd2000, 0xd4000, 0xd6000,
54 0xd8000, 0xda000, 0xdc000, 0xde000,
55 0xe0000, 0xe2000, 0xe4000, 0xe6000,
56 0xe8000, 0xea000, 0xec000, 0xee000, 0 };
57 #elif defined(__ppc__)
58 static unsigned long __initdata doc_locations[] = {
59 0xe4000000, 0};
60 #else
61 #warning Unknown architecture for DiskOnChip. No default probe locations defined
62 #endif
64 #ifdef CONFIG_MTD_DOC2000
65 extern void DoC2k_init(struct mtd_info *);
66 #endif
67 #ifdef CONFIG_MTD_DOC2001
68 extern void DoCMil_init(struct mtd_info *);
69 #endif
71 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
73 static inline int __init doccheck(unsigned long potential, unsigned long physadr)
75 unsigned long window=potential;
76 unsigned char tmp, ChipID;
77 #ifndef DOC_PASSIVE_PROBE
78 unsigned char tmp2;
79 #endif
81 /* Routine copied from the Linux DOC driver */
83 /* Check for 0x55 0xAA signature at beginning of window */
84 if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
85 return 0;
87 #ifndef DOC_PASSIVE_PROBE
88 /* It's not possible to cleanly detect the DiskOnChip - the
89 * bootup procedure will put the device into reset mode, and
90 * it's not possible to talk to it without actually writing
91 * to the DOCControl register. So we store the current contents
92 * of the DOCControl register's location, in case we later decide
93 * that it's not a DiskOnChip, and want to put it back how we
94 * found it.
96 tmp2 = ReadDOC(window, DOCControl);
98 /* Reset the DiskOnChip ASIC */
99 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
100 window, DOCControl);
101 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
102 window, DOCControl);
104 /* Enable the DiskOnChip ASIC */
105 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
106 window, DOCControl);
107 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
108 window, DOCControl);
109 #endif /* !DOC_PASSIVE_PROBE */
111 ChipID = ReadDOC(window, ChipID);
113 switch (ChipID) {
114 case DOC_ChipID_Doc2k:
115 /* Check the TOGGLE bit in the ECC register */
116 tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
117 if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
118 return ChipID;
119 break;
121 case DOC_ChipID_DocMil:
122 /* Check the TOGGLE bit in the ECC register */
123 tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
124 if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
125 return ChipID;
126 break;
128 default:
129 printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
130 ChipID, physadr);
132 #ifndef DOC_PASSIVE_PROBE
133 /* Put back the contents of the DOCControl register, in case it's not
134 * actually a DiskOnChip.
136 WriteDOC(tmp2, window, DOCControl);
137 #endif
138 return 0;
141 printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
143 #ifndef DOC_PASSIVE_PROBE
144 /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
145 WriteDOC(tmp2, window, DOCControl);
146 #endif
147 return 0;
151 static void DoC_Probe(unsigned long physadr)
153 unsigned long docptr;
154 struct DiskOnChip *this;
155 struct mtd_info *mtd;
156 int ChipID;
157 char namebuf[15];
158 char *name = namebuf;
159 void (*initroutine)(struct mtd_info *) = NULL;
160 int initroutinedynamic = 0;
162 docptr = (unsigned long)ioremap(physadr, 0x2000);
164 if (!docptr)
165 return;
167 if ((ChipID = doccheck(docptr, physadr))) {
169 mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
171 if (!mtd) {
172 printk("Cannot allocate memory for data structures. Dropping.\n");
173 iounmap((void *)docptr);
174 return;
177 this = (struct DiskOnChip *)(&mtd[1]);
179 memset((char *)mtd,0, sizeof(struct mtd_info));
180 memset((char *)this, 0, sizeof(struct DiskOnChip));
182 mtd->priv = this;
183 this->virtadr = docptr;
184 this->physadr = physadr;
185 this->ChipID = ChipID;
186 sprintf(namebuf, "with ChipID %2.2X", ChipID);
188 switch(ChipID) {
189 case DOC_ChipID_Doc2k:
190 name="2000";
191 #ifdef CONFIG_MTD_DOC2000
192 initroutine = &DoC2k_init;
193 #elif CONFIG_MODULES
194 initroutinedynamic=1;
195 initroutine = (void *)get_module_symbol(NULL, "DoC2k_init");
196 #ifdef CONFIG_KMOD
197 if (!initroutine) {
198 request_module("doc2000");
199 initroutine = (void *)get_module_symbol("doc2000", "DoC2k_init");
201 #endif /* CONFIG_KMOD */
202 #endif
203 break;
205 case DOC_ChipID_DocMil:
206 name="Millennium";
207 #ifdef CONFIG_MTD_DOC2001
208 initroutine = &DocMil_init;
209 #elif CONFIG_MODULES
210 initroutinedynamic=1;
211 initroutine = (void *)get_module_symbol(NULL, "DoCMil_init");
212 #ifdef CONFIG_KMOD
213 if (!initroutine) {
214 request_module("doc2001");
215 initroutine = (void *)get_module_symbol("doc2001", "DoCMil_init");
217 #endif /* CONFIG_KMOD */
218 #endif
219 break;
221 if (initroutine) {
222 (*initroutine)(mtd);
223 #if defined(CONFIG_MODULES) && LINUX_VERSION_CODE >= 0x20400
224 if (initroutinedynamic)
225 put_module_symbol(initroutine);
226 #endif
227 return;
229 printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr);
231 iounmap((void *)docptr);
235 /****************************************************************************
237 * Module stuff
239 ****************************************************************************/
241 #if LINUX_VERSION_CODE < 0x20300
242 #ifdef MODULE
243 #define init_doc init_module
244 #endif
245 #define __exit
246 #endif
248 int __init init_doc(void)
250 int i;
252 printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
253 #ifdef PRERELEASE
254 printk(KERN_INFO "$Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $\n");
255 #endif
257 for (i=0; doc_locations[i]; i++) {
258 DoC_Probe(doc_locations[i]);
261 return 0;
266 #if LINUX_VERSION_CODE > 0x20300
267 module_init(init_doc);
268 #endif