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 
8 /* DOC_PASSIVE_PROBE:
9    In order to ensure that the BIOS checksum is correct at boot time, and
10    hence that the onboard BIOS extension gets executed, the DiskOnChip
11    goes into reset mode when it is read sequentially: all registers
12    return 0xff until the chip is woken up again by writing to the
13    DOCControl register.
14 
15    Unfortunately, this means that the probe for the DiskOnChip is unsafe,
16    because one of the first things it does is write to where it thinks
17    the DOCControl register should be - which may well be shared memory
18    for another device. I've had machines which lock up when this is
19    attempted. Hence the possibility to do a passive probe, which will fail
20    to detect a chip in reset mode, but is at least guaranteed not to lock
21    the machine.
22 
23    If you have this problem, uncomment the following line:
24 #define DOC_PASSIVE_PROBE
25 */
26 
27 
28 /* DOC_SINGLE_DRIVER:
29    Millennium driver has been merged into DOC2000 driver.
30 
31    The old Millennium-only driver has been retained just in case there
32    are problems with the new code. If the combined driver doesn't work
33    for you, you can try the old one by undefining DOC_SINGLE_DRIVER
34    below and also enabling it in your configuration. If this fixes the
35    problems, please send a report to the MTD mailing list at
36    <linux-mtd@lists.infradead.org>.
37 */
38 #define DOC_SINGLE_DRIVER
39 
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <asm/errno.h>
43 #include <asm/io.h>
44 #include <linux/delay.h>
45 #include <linux/slab.h>
46 #include <linux/init.h>
47 #include <linux/types.h>
48 
49 #include <linux/mtd/mtd.h>
50 #include <linux/mtd/nand.h>
51 #include <linux/mtd/doc2000.h>
52 
53 
54 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
55 module_param(doc_config_location, ulong, 0);
56 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
57 
58 static unsigned long __initdata doc_locations[] = {
59 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
60 #ifdef CONFIG_MTD_DOCPROBE_HIGH
61 	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
62 	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
63 	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
64 	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
65 	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
66 #else /*  CONFIG_MTD_DOCPROBE_HIGH */
67 	0xc8000, 0xca000, 0xcc000, 0xce000,
68 	0xd0000, 0xd2000, 0xd4000, 0xd6000,
69 	0xd8000, 0xda000, 0xdc000, 0xde000,
70 	0xe0000, 0xe2000, 0xe4000, 0xe6000,
71 	0xe8000, 0xea000, 0xec000, 0xee000,
72 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
73 #else
74 #warning Unknown architecture for DiskOnChip. No default probe locations defined
75 #endif
76 	0xffffffff };
77 
78 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
79 
doccheck(void __iomem * potential,unsigned long physadr)80 static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
81 {
82 	void __iomem *window=potential;
83 	unsigned char tmp, tmpb, tmpc, ChipID;
84 #ifndef DOC_PASSIVE_PROBE
85 	unsigned char tmp2;
86 #endif
87 
88 	/* Routine copied from the Linux DOC driver */
89 
90 #ifdef CONFIG_MTD_DOCPROBE_55AA
91 	/* Check for 0x55 0xAA signature at beginning of window,
92 	   this is no longer true once we remove the IPL (for Millennium */
93 	if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
94 		return 0;
95 #endif /* CONFIG_MTD_DOCPROBE_55AA */
96 
97 #ifndef DOC_PASSIVE_PROBE
98 	/* It's not possible to cleanly detect the DiskOnChip - the
99 	 * bootup procedure will put the device into reset mode, and
100 	 * it's not possible to talk to it without actually writing
101 	 * to the DOCControl register. So we store the current contents
102 	 * of the DOCControl register's location, in case we later decide
103 	 * that it's not a DiskOnChip, and want to put it back how we
104 	 * found it.
105 	 */
106 	tmp2 = ReadDOC(window, DOCControl);
107 
108 	/* Reset the DiskOnChip ASIC */
109 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
110 		 window, DOCControl);
111 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
112 		 window, DOCControl);
113 
114 	/* Enable the DiskOnChip ASIC */
115 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
116 		 window, DOCControl);
117 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
118 		 window, DOCControl);
119 #endif /* !DOC_PASSIVE_PROBE */
120 
121 	/* We need to read the ChipID register four times. For some
122 	   newer DiskOnChip 2000 units, the first three reads will
123 	   return the DiskOnChip Millennium ident. Don't ask. */
124 	ChipID = ReadDOC(window, ChipID);
125 
126 	switch (ChipID) {
127 	case DOC_ChipID_Doc2k:
128 		/* Check the TOGGLE bit in the ECC register */
129 		tmp  = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
130 		tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
131 		tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
132 		if (tmp != tmpb && tmp == tmpc)
133 				return ChipID;
134 		break;
135 
136 	case DOC_ChipID_DocMil:
137 		/* Check for the new 2000 with Millennium ASIC */
138 		ReadDOC(window, ChipID);
139 		ReadDOC(window, ChipID);
140 		if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
141 			ChipID = DOC_ChipID_Doc2kTSOP;
142 
143 		/* Check the TOGGLE bit in the ECC register */
144 		tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
145 		tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
146 		tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
147 		if (tmp != tmpb && tmp == tmpc)
148 				return ChipID;
149 		break;
150 
151 	case DOC_ChipID_DocMilPlus16:
152 	case DOC_ChipID_DocMilPlus32:
153 	case 0:
154 		/* Possible Millennium+, need to do more checks */
155 #ifndef DOC_PASSIVE_PROBE
156 		/* Possibly release from power down mode */
157 		for (tmp = 0; (tmp < 4); tmp++)
158 			ReadDOC(window, Mplus_Power);
159 
160 		/* Reset the DiskOnChip ASIC */
161 		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
162 			DOC_MODE_BDECT;
163 		WriteDOC(tmp, window, Mplus_DOCControl);
164 		WriteDOC(~tmp, window, Mplus_CtrlConfirm);
165 
166 		mdelay(1);
167 		/* Enable the DiskOnChip ASIC */
168 		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
169 			DOC_MODE_BDECT;
170 		WriteDOC(tmp, window, Mplus_DOCControl);
171 		WriteDOC(~tmp, window, Mplus_CtrlConfirm);
172 		mdelay(1);
173 #endif /* !DOC_PASSIVE_PROBE */
174 
175 		ChipID = ReadDOC(window, ChipID);
176 
177 		switch (ChipID) {
178 		case DOC_ChipID_DocMilPlus16:
179 		case DOC_ChipID_DocMilPlus32:
180 			/* Check the TOGGLE bit in the toggle register */
181 			tmp  = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
182 			tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
183 			tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
184 			if (tmp != tmpb && tmp == tmpc)
185 					return ChipID;
186 		default:
187 			break;
188 		}
189 		/* FALL TRHU */
190 
191 	default:
192 
193 #ifdef CONFIG_MTD_DOCPROBE_55AA
194 		printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
195 		       ChipID, physadr);
196 #endif
197 #ifndef DOC_PASSIVE_PROBE
198 		/* Put back the contents of the DOCControl register, in case it's not
199 		 * actually a DiskOnChip.
200 		 */
201 		WriteDOC(tmp2, window, DOCControl);
202 #endif
203 		return 0;
204 	}
205 
206 	printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
207 
208 #ifndef DOC_PASSIVE_PROBE
209 	/* Put back the contents of the DOCControl register: it's not a DiskOnChip */
210 	WriteDOC(tmp2, window, DOCControl);
211 #endif
212 	return 0;
213 }
214 
215 static int docfound;
216 
217 extern void DoC2k_init(struct mtd_info *);
218 extern void DoCMil_init(struct mtd_info *);
219 extern void DoCMilPlus_init(struct mtd_info *);
220 
DoC_Probe(unsigned long physadr)221 static void __init DoC_Probe(unsigned long physadr)
222 {
223 	void __iomem *docptr;
224 	struct DiskOnChip *this;
225 	struct mtd_info *mtd;
226 	int ChipID;
227 	char namebuf[15];
228 	char *name = namebuf;
229 	void (*initroutine)(struct mtd_info *) = NULL;
230 
231 	docptr = ioremap(physadr, DOC_IOREMAP_LEN);
232 
233 	if (!docptr)
234 		return;
235 
236 	if ((ChipID = doccheck(docptr, physadr))) {
237 		if (ChipID == DOC_ChipID_Doc2kTSOP) {
238 			/* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
239 			printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
240 			iounmap(docptr);
241 			return;
242 		}
243 		docfound = 1;
244 		mtd = kzalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
245 		if (!mtd) {
246 			printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
247 			iounmap(docptr);
248 			return;
249 		}
250 
251 		this = (struct DiskOnChip *)(&mtd[1]);
252 		mtd->priv = this;
253 		this->virtadr = docptr;
254 		this->physadr = physadr;
255 		this->ChipID = ChipID;
256 		sprintf(namebuf, "with ChipID %2.2X", ChipID);
257 
258 		switch(ChipID) {
259 		case DOC_ChipID_Doc2kTSOP:
260 			name="2000 TSOP";
261 			initroutine = symbol_request(DoC2k_init);
262 			break;
263 
264 		case DOC_ChipID_Doc2k:
265 			name="2000";
266 			initroutine = symbol_request(DoC2k_init);
267 			break;
268 
269 		case DOC_ChipID_DocMil:
270 			name="Millennium";
271 #ifdef DOC_SINGLE_DRIVER
272 			initroutine = symbol_request(DoC2k_init);
273 #else
274 			initroutine = symbol_request(DoCMil_init);
275 #endif /* DOC_SINGLE_DRIVER */
276 			break;
277 
278 		case DOC_ChipID_DocMilPlus16:
279 		case DOC_ChipID_DocMilPlus32:
280 			name="MillenniumPlus";
281 			initroutine = symbol_request(DoCMilPlus_init);
282 			break;
283 		}
284 
285 		if (initroutine) {
286 			(*initroutine)(mtd);
287 			symbol_put_addr(initroutine);
288 			return;
289 		}
290 		printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
291 		kfree(mtd);
292 	}
293 	iounmap(docptr);
294 }
295 
296 
297 /****************************************************************************
298  *
299  * Module stuff
300  *
301  ****************************************************************************/
302 
init_doc(void)303 static int __init init_doc(void)
304 {
305 	int i;
306 
307 	if (doc_config_location) {
308 		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
309 		DoC_Probe(doc_config_location);
310 	} else {
311 		for (i=0; (doc_locations[i] != 0xffffffff); i++) {
312 			DoC_Probe(doc_locations[i]);
313 		}
314 	}
315 	/* No banner message any more. Print a message if no DiskOnChip
316 	   found, so the user knows we at least tried. */
317 	if (!docfound)
318 		printk(KERN_INFO "No recognised DiskOnChip devices found\n");
319 	return -EAGAIN;
320 }
321 
322 module_init(init_doc);
323 
324 MODULE_LICENSE("GPL");
325 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
326 MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
327 
328