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 /* Where to look for the devices? */
54 #ifndef CONFIG_MTD_DOCPROBE_ADDRESS
55 #define CONFIG_MTD_DOCPROBE_ADDRESS 0
56 #endif
57
58
59 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
60 module_param(doc_config_location, ulong, 0);
61 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
62
63 static unsigned long __initdata doc_locations[] = {
64 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
65 #ifdef CONFIG_MTD_DOCPROBE_HIGH
66 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
67 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
68 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
69 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
70 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
71 #else /* CONFIG_MTD_DOCPROBE_HIGH */
72 0xc8000, 0xca000, 0xcc000, 0xce000,
73 0xd0000, 0xd2000, 0xd4000, 0xd6000,
74 0xd8000, 0xda000, 0xdc000, 0xde000,
75 0xe0000, 0xe2000, 0xe4000, 0xe6000,
76 0xe8000, 0xea000, 0xec000, 0xee000,
77 #endif /* CONFIG_MTD_DOCPROBE_HIGH */
78 #else
79 #warning Unknown architecture for DiskOnChip. No default probe locations defined
80 #endif
81 0xffffffff };
82
83 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
84
doccheck(void __iomem * potential,unsigned long physadr)85 static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
86 {
87 void __iomem *window=potential;
88 unsigned char tmp, tmpb, tmpc, ChipID;
89 #ifndef DOC_PASSIVE_PROBE
90 unsigned char tmp2;
91 #endif
92
93 /* Routine copied from the Linux DOC driver */
94
95 #ifdef CONFIG_MTD_DOCPROBE_55AA
96 /* Check for 0x55 0xAA signature at beginning of window,
97 this is no longer true once we remove the IPL (for Millennium */
98 if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
99 return 0;
100 #endif /* CONFIG_MTD_DOCPROBE_55AA */
101
102 #ifndef DOC_PASSIVE_PROBE
103 /* It's not possible to cleanly detect the DiskOnChip - the
104 * bootup procedure will put the device into reset mode, and
105 * it's not possible to talk to it without actually writing
106 * to the DOCControl register. So we store the current contents
107 * of the DOCControl register's location, in case we later decide
108 * that it's not a DiskOnChip, and want to put it back how we
109 * found it.
110 */
111 tmp2 = ReadDOC(window, DOCControl);
112
113 /* Reset the DiskOnChip ASIC */
114 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
115 window, DOCControl);
116 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
117 window, DOCControl);
118
119 /* Enable the DiskOnChip ASIC */
120 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
121 window, DOCControl);
122 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
123 window, DOCControl);
124 #endif /* !DOC_PASSIVE_PROBE */
125
126 /* We need to read the ChipID register four times. For some
127 newer DiskOnChip 2000 units, the first three reads will
128 return the DiskOnChip Millennium ident. Don't ask. */
129 ChipID = ReadDOC(window, ChipID);
130
131 switch (ChipID) {
132 case DOC_ChipID_Doc2k:
133 /* Check the TOGGLE bit in the ECC register */
134 tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
135 tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
136 tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
137 if (tmp != tmpb && tmp == tmpc)
138 return ChipID;
139 break;
140
141 case DOC_ChipID_DocMil:
142 /* Check for the new 2000 with Millennium ASIC */
143 ReadDOC(window, ChipID);
144 ReadDOC(window, ChipID);
145 if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
146 ChipID = DOC_ChipID_Doc2kTSOP;
147
148 /* Check the TOGGLE bit in the ECC register */
149 tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
150 tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
151 tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
152 if (tmp != tmpb && tmp == tmpc)
153 return ChipID;
154 break;
155
156 case DOC_ChipID_DocMilPlus16:
157 case DOC_ChipID_DocMilPlus32:
158 case 0:
159 /* Possible Millennium+, need to do more checks */
160 #ifndef DOC_PASSIVE_PROBE
161 /* Possibly release from power down mode */
162 for (tmp = 0; (tmp < 4); tmp++)
163 ReadDOC(window, Mplus_Power);
164
165 /* Reset the DiskOnChip ASIC */
166 tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
167 DOC_MODE_BDECT;
168 WriteDOC(tmp, window, Mplus_DOCControl);
169 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
170
171 mdelay(1);
172 /* Enable the DiskOnChip ASIC */
173 tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
174 DOC_MODE_BDECT;
175 WriteDOC(tmp, window, Mplus_DOCControl);
176 WriteDOC(~tmp, window, Mplus_CtrlConfirm);
177 mdelay(1);
178 #endif /* !DOC_PASSIVE_PROBE */
179
180 ChipID = ReadDOC(window, ChipID);
181
182 switch (ChipID) {
183 case DOC_ChipID_DocMilPlus16:
184 case DOC_ChipID_DocMilPlus32:
185 /* Check the TOGGLE bit in the toggle register */
186 tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
187 tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
188 tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
189 if (tmp != tmpb && tmp == tmpc)
190 return ChipID;
191 default:
192 break;
193 }
194 /* FALL TRHU */
195
196 default:
197
198 #ifdef CONFIG_MTD_DOCPROBE_55AA
199 printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
200 ChipID, physadr);
201 #endif
202 #ifndef DOC_PASSIVE_PROBE
203 /* Put back the contents of the DOCControl register, in case it's not
204 * actually a DiskOnChip.
205 */
206 WriteDOC(tmp2, window, DOCControl);
207 #endif
208 return 0;
209 }
210
211 printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
212
213 #ifndef DOC_PASSIVE_PROBE
214 /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
215 WriteDOC(tmp2, window, DOCControl);
216 #endif
217 return 0;
218 }
219
220 static int docfound;
221
222 extern void DoC2k_init(struct mtd_info *);
223 extern void DoCMil_init(struct mtd_info *);
224 extern void DoCMilPlus_init(struct mtd_info *);
225
DoC_Probe(unsigned long physadr)226 static void __init DoC_Probe(unsigned long physadr)
227 {
228 void __iomem *docptr;
229 struct DiskOnChip *this;
230 struct mtd_info *mtd;
231 int ChipID;
232 char namebuf[15];
233 char *name = namebuf;
234 void (*initroutine)(struct mtd_info *) = NULL;
235
236 docptr = ioremap(physadr, DOC_IOREMAP_LEN);
237
238 if (!docptr)
239 return;
240
241 if ((ChipID = doccheck(docptr, physadr))) {
242 if (ChipID == DOC_ChipID_Doc2kTSOP) {
243 /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
244 printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
245 iounmap(docptr);
246 return;
247 }
248 docfound = 1;
249 mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
250
251 if (!mtd) {
252 printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
253 iounmap(docptr);
254 return;
255 }
256
257 this = (struct DiskOnChip *)(&mtd[1]);
258
259 memset((char *)mtd,0, sizeof(struct mtd_info));
260 memset((char *)this, 0, sizeof(struct DiskOnChip));
261
262 mtd->priv = this;
263 this->virtadr = docptr;
264 this->physadr = physadr;
265 this->ChipID = ChipID;
266 sprintf(namebuf, "with ChipID %2.2X", ChipID);
267
268 switch(ChipID) {
269 case DOC_ChipID_Doc2kTSOP:
270 name="2000 TSOP";
271 initroutine = symbol_request(DoC2k_init);
272 break;
273
274 case DOC_ChipID_Doc2k:
275 name="2000";
276 initroutine = symbol_request(DoC2k_init);
277 break;
278
279 case DOC_ChipID_DocMil:
280 name="Millennium";
281 #ifdef DOC_SINGLE_DRIVER
282 initroutine = symbol_request(DoC2k_init);
283 #else
284 initroutine = symbol_request(DoCMil_init);
285 #endif /* DOC_SINGLE_DRIVER */
286 break;
287
288 case DOC_ChipID_DocMilPlus16:
289 case DOC_ChipID_DocMilPlus32:
290 name="MillenniumPlus";
291 initroutine = symbol_request(DoCMilPlus_init);
292 break;
293 }
294
295 if (initroutine) {
296 (*initroutine)(mtd);
297 symbol_put_addr(initroutine);
298 return;
299 }
300 printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
301 kfree(mtd);
302 }
303 iounmap(docptr);
304 }
305
306
307 /****************************************************************************
308 *
309 * Module stuff
310 *
311 ****************************************************************************/
312
init_doc(void)313 static int __init init_doc(void)
314 {
315 int i;
316
317 if (doc_config_location) {
318 printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
319 DoC_Probe(doc_config_location);
320 } else {
321 for (i=0; (doc_locations[i] != 0xffffffff); i++) {
322 DoC_Probe(doc_locations[i]);
323 }
324 }
325 /* No banner message any more. Print a message if no DiskOnChip
326 found, so the user knows we at least tried. */
327 if (!docfound)
328 printk(KERN_INFO "No recognised DiskOnChip devices found\n");
329 return -EAGAIN;
330 }
331
332 module_init(init_doc);
333
334 MODULE_LICENSE("GPL");
335 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
336 MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
337
338