Merge branch 'fix/asoc' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[deliverable/linux.git] / drivers / mtd / devices / docprobe.c
CommitLineData
1da177e4
LT
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
1da177e4
LT
7
8/* DOC_PASSIVE_PROBE:
e5580fbe
TG
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
1da177e4
LT
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
e5580fbe 33 for you, you can try the old one by undefining DOC_SINGLE_DRIVER
1da177e4 34 below and also enabling it in your configuration. If this fixes the
e5580fbe 35 problems, please send a report to the MTD mailing list at
1da177e4
LT
36 <linux-mtd@lists.infradead.org>.
37*/
38#define DOC_SINGLE_DRIVER
39
1da177e4
LT
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>
1da177e4
LT
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
59static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
60module_param(doc_config_location, ulong, 0);
61MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
62
63static unsigned long __initdata doc_locations[] = {
64#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
65#ifdef CONFIG_MTD_DOCPROBE_HIGH
e5580fbe 66 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
1da177e4 67 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
e5580fbe
TG
68 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
69 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
1da177e4
LT
70 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
71#else /* CONFIG_MTD_DOCPROBE_HIGH */
e5580fbe 72 0xc8000, 0xca000, 0xcc000, 0xce000,
1da177e4 73 0xd0000, 0xd2000, 0xd4000, 0xd6000,
e5580fbe
TG
74 0xd8000, 0xda000, 0xdc000, 0xde000,
75 0xe0000, 0xe2000, 0xe4000, 0xe6000,
1da177e4
LT
76 0xe8000, 0xea000, 0xec000, 0xee000,
77#endif /* CONFIG_MTD_DOCPROBE_HIGH */
440fdb53 78#else
1da177e4
LT
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
85static 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
e5580fbe 102#ifndef DOC_PASSIVE_PROBE
1da177e4
LT
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
e5580fbe 109 * found it.
1da177e4
LT
110 */
111 tmp2 = ReadDOC(window, DOCControl);
e5580fbe 112
1da177e4 113 /* Reset the DiskOnChip ASIC */
e5580fbe 114 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
1da177e4 115 window, DOCControl);
e5580fbe 116 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
1da177e4 117 window, DOCControl);
e5580fbe 118
1da177e4 119 /* Enable the DiskOnChip ASIC */
e5580fbe 120 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
1da177e4 121 window, DOCControl);
e5580fbe 122 WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
1da177e4 123 window, DOCControl);
e5580fbe 124#endif /* !DOC_PASSIVE_PROBE */
1da177e4
LT
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);
e5580fbe 130
1da177e4
LT
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;
e5580fbe 140
1da177e4
LT
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;
e5580fbe 155
1da177e4
LT
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);
e5580fbe 170
1da177e4
LT
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);
e5580fbe 178#endif /* !DOC_PASSIVE_PROBE */
1da177e4
LT
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;
e5580fbe 218}
1da177e4
LT
219
220static int docfound;
221
396674e5 222extern void DoC2k_init(struct mtd_info *);
396674e5 223extern void DoCMil_init(struct mtd_info *);
396674e5 224extern void DoCMilPlus_init(struct mtd_info *);
396674e5 225
1da177e4
LT
226static 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;
1da177e4
LT
234 void (*initroutine)(struct mtd_info *) = NULL;
235
236 docptr = ioremap(physadr, DOC_IOREMAP_LEN);
e5580fbe 237
1da177e4
LT
238 if (!docptr)
239 return;
e5580fbe 240
1da177e4
LT
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 }
e5580fbe 256
1da177e4 257 this = (struct DiskOnChip *)(&mtd[1]);
e5580fbe 258
1da177e4
LT
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";
ecde2631 271 initroutine = symbol_request(DoC2k_init);
1da177e4 272 break;
e5580fbe 273
1da177e4
LT
274 case DOC_ChipID_Doc2k:
275 name="2000";
ecde2631 276 initroutine = symbol_request(DoC2k_init);
1da177e4 277 break;
e5580fbe 278
1da177e4
LT
279 case DOC_ChipID_DocMil:
280 name="Millennium";
281#ifdef DOC_SINGLE_DRIVER
ecde2631 282 initroutine = symbol_request(DoC2k_init);
1da177e4 283#else
ecde2631 284 initroutine = symbol_request(DoCMil_init);
1da177e4
LT
285#endif /* DOC_SINGLE_DRIVER */
286 break;
287
288 case DOC_ChipID_DocMilPlus16:
289 case DOC_ChipID_DocMilPlus32:
290 name="MillenniumPlus";
ecde2631 291 initroutine = symbol_request(DoCMilPlus_init);
1da177e4
LT
292 break;
293 }
294
1da177e4
LT
295 if (initroutine) {
296 (*initroutine)(mtd);
5e535429 297 symbol_put_addr(initroutine);
1da177e4
LT
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
313static int __init init_doc(void)
314{
315 int i;
e5580fbe 316
1da177e4
LT
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
332module_init(init_doc);
333
334MODULE_LICENSE("GPL");
335MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
336MODULE_DESCRIPTION("Probe code for DiskOnChip 2000 and Millennium devices");
337
This page took 0.666094 seconds and 5 git commands to generate.