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