• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/mtd/devices/
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
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
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
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
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
220static int docfound;
221
222extern void DoC2k_init(struct mtd_info *);
223extern void DoCMil_init(struct mtd_info *);
224extern void DoCMilPlus_init(struct mtd_info *);
225
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;
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
313static 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
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