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