Pull bugzilla-3774 into release branch
[linux-2.6] / drivers / mtd / maps / nettel.c
1 /****************************************************************************/
2
3 /*
4  *      nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards.
5  *
6  *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
7  *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
8  *
9  *      $Id: nettel.c,v 1.12 2005/11/29 14:30:00 gleixner Exp $
10  */
11
12 /****************************************************************************/
13
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/map.h>
20 #include <linux/mtd/partitions.h>
21 #include <linux/mtd/cfi.h>
22 #include <linux/reboot.h>
23 #include <linux/err.h>
24 #include <linux/kdev_t.h>
25 #include <linux/root_dev.h>
26 #include <asm/io.h>
27
28 /****************************************************************************/
29
30 #define INTEL_BUSWIDTH          1
31 #define AMD_WINDOW_MAXSIZE      0x00200000
32 #define AMD_BUSWIDTH            1
33
34 /*
35  *      PAR masks and shifts, assuming 64K pages.
36  */
37 #define SC520_PAR_ADDR_MASK     0x00003fff
38 #define SC520_PAR_ADDR_SHIFT    16
39 #define SC520_PAR_TO_ADDR(par) \
40         (((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT)
41
42 #define SC520_PAR_SIZE_MASK     0x01ffc000
43 #define SC520_PAR_SIZE_SHIFT    2
44 #define SC520_PAR_TO_SIZE(par) \
45         ((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024))
46
47 #define SC520_PAR(cs, addr, size) \
48         ((cs) | \
49         ((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \
50         (((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK))
51
52 #define SC520_PAR_BOOTCS        0x8a000000
53 #define SC520_PAR_ROMCS1        0xaa000000
54 #define SC520_PAR_ROMCS2        0xca000000      /* Cache disabled, 64K page */
55
56 static void *nettel_mmcrp = NULL;
57
58 #ifdef CONFIG_MTD_CFI_INTELEXT
59 static struct mtd_info *intel_mtd;
60 #endif
61 static struct mtd_info *amd_mtd;
62
63 /****************************************************************************/
64
65 /****************************************************************************/
66
67 #ifdef CONFIG_MTD_CFI_INTELEXT
68 static struct map_info nettel_intel_map = {
69         .name = "SnapGear Intel",
70         .size = 0,
71         .bankwidth = INTEL_BUSWIDTH,
72 };
73
74 static struct mtd_partition nettel_intel_partitions[] = {
75         {
76                 .name = "SnapGear kernel",
77                 .offset = 0,
78                 .size = 0x000e0000
79         },
80         {
81                 .name = "SnapGear filesystem",
82                 .offset = 0x00100000,
83         },
84         {
85                 .name = "SnapGear config",
86                 .offset = 0x000e0000,
87                 .size = 0x00020000
88         },
89         {
90                 .name = "SnapGear Intel",
91                 .offset = 0
92         },
93         {
94                 .name = "SnapGear BIOS Config",
95                 .offset = 0x007e0000,
96                 .size = 0x00020000
97         },
98         {
99                 .name = "SnapGear BIOS",
100                 .offset = 0x007e0000,
101                 .size = 0x00020000
102         },
103 };
104 #endif
105
106 static struct map_info nettel_amd_map = {
107         .name = "SnapGear AMD",
108         .size = AMD_WINDOW_MAXSIZE,
109         .bankwidth = AMD_BUSWIDTH,
110 };
111
112 static struct mtd_partition nettel_amd_partitions[] = {
113         {
114                 .name = "SnapGear BIOS config",
115                 .offset = 0x000e0000,
116                 .size = 0x00010000
117         },
118         {
119                 .name = "SnapGear BIOS",
120                 .offset = 0x000f0000,
121                 .size = 0x00010000
122         },
123         {
124                 .name = "SnapGear AMD",
125                 .offset = 0
126         },
127         {
128                 .name = "SnapGear high BIOS",
129                 .offset = 0x001f0000,
130                 .size = 0x00010000
131         }
132 };
133
134 #define NUM_AMD_PARTITIONS ARRAY_SIZE(nettel_amd_partitions)
135
136 /****************************************************************************/
137
138 #ifdef CONFIG_MTD_CFI_INTELEXT
139
140 /*
141  *      Set the Intel flash back to read mode since some old boot
142  *      loaders don't.
143  */
144 static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
145 {
146         struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
147         unsigned long b;
148
149         /* Make sure all FLASH chips are put back into read mode */
150         for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
151                 cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
152                         cfi->device_type, NULL);
153         }
154         return(NOTIFY_OK);
155 }
156
157 static struct notifier_block nettel_notifier_block = {
158         nettel_reboot_notifier, NULL, 0
159 };
160
161 /*
162  *      Erase the configuration file system.
163  *      Used to support the software reset button.
164  */
165 static void nettel_erasecallback(struct erase_info *done)
166 {
167         wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
168         wake_up(wait_q);
169 }
170
171 static struct erase_info nettel_erase;
172
173 int nettel_eraseconfig(void)
174 {
175         struct mtd_info *mtd;
176         DECLARE_WAITQUEUE(wait, current);
177         wait_queue_head_t wait_q;
178         int ret;
179
180         init_waitqueue_head(&wait_q);
181         mtd = get_mtd_device(NULL, 2);
182         if (!IS_ERR(mtd)) {
183                 nettel_erase.mtd = mtd;
184                 nettel_erase.callback = nettel_erasecallback;
185                 nettel_erase.callback = NULL;
186                 nettel_erase.addr = 0;
187                 nettel_erase.len = mtd->size;
188                 nettel_erase.priv = (u_long) &wait_q;
189                 nettel_erase.priv = 0;
190
191                 set_current_state(TASK_INTERRUPTIBLE);
192                 add_wait_queue(&wait_q, &wait);
193
194                 ret = mtd->erase(mtd, &nettel_erase);
195                 if (ret) {
196                         set_current_state(TASK_RUNNING);
197                         remove_wait_queue(&wait_q, &wait);
198                         put_mtd_device(mtd);
199                         return(ret);
200                 }
201
202                 schedule();  /* Wait for erase to finish. */
203                 remove_wait_queue(&wait_q, &wait);
204
205                 put_mtd_device(mtd);
206         }
207
208         return(0);
209 }
210
211 #else
212
213 int nettel_eraseconfig(void)
214 {
215         return(0);
216 }
217
218 #endif
219
220 /****************************************************************************/
221
222 int __init nettel_init(void)
223 {
224         volatile unsigned long *amdpar;
225         unsigned long amdaddr, maxsize;
226         int num_amd_partitions=0;
227 #ifdef CONFIG_MTD_CFI_INTELEXT
228         volatile unsigned long *intel0par, *intel1par;
229         unsigned long orig_bootcspar, orig_romcs1par;
230         unsigned long intel0addr, intel0size;
231         unsigned long intel1addr, intel1size;
232         int intelboot, intel0cs, intel1cs;
233         int num_intel_partitions;
234 #endif
235         int rc = 0;
236
237         nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096);
238         if (nettel_mmcrp == NULL) {
239                 printk("SNAPGEAR: failed to disable MMCR cache??\n");
240                 return(-EIO);
241         }
242
243         /* Set CPU clock to be 33.000MHz */
244         *((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01;
245
246         amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4);
247
248 #ifdef CONFIG_MTD_CFI_INTELEXT
249         intelboot = 0;
250         intel0cs = SC520_PAR_ROMCS1;
251         intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0);
252         intel1cs = SC520_PAR_ROMCS2;
253         intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc);
254
255         /*
256          *      Save the CS settings then ensure ROMCS1 and ROMCS2 are off,
257          *      otherwise they might clash with where we try to map BOOTCS.
258          */
259         orig_bootcspar = *amdpar;
260         orig_romcs1par = *intel0par;
261         *intel0par = 0;
262         *intel1par = 0;
263 #endif
264
265         /*
266          *      The first thing to do is determine if we have a separate
267          *      boot FLASH device. Typically this is a small (1 to 2MB)
268          *      AMD FLASH part. It seems that device size is about the
269          *      only way to tell if this is the case...
270          */
271         amdaddr = 0x20000000;
272         maxsize = AMD_WINDOW_MAXSIZE;
273
274         *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
275         __asm__ ("wbinvd");
276
277         nettel_amd_map.phys = amdaddr;
278         nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
279         if (!nettel_amd_map.virt) {
280                 printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
281                 iounmap(nettel_mmcrp);
282                 return(-EIO);
283         }
284         simple_map_init(&nettel_amd_map);
285
286         if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
287                 printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
288                         amd_mtd->size>>10);
289
290                 amd_mtd->owner = THIS_MODULE;
291
292                 /* The high BIOS partition is only present for 2MB units */
293                 num_amd_partitions = NUM_AMD_PARTITIONS;
294                 if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
295                         num_amd_partitions--;
296                 /* Don't add the partition until after the primary INTEL's */
297
298 #ifdef CONFIG_MTD_CFI_INTELEXT
299                 /*
300                  *      Map the Intel flash into memory after the AMD
301                  *      It has to start on a multiple of maxsize.
302                  */
303                 maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
304                 if (maxsize < (32 * 1024 * 1024))
305                         maxsize = (32 * 1024 * 1024);
306                 intel0addr = amdaddr + maxsize;
307 #endif
308         } else {
309 #ifdef CONFIG_MTD_CFI_INTELEXT
310                 /* INTEL boot FLASH */
311                 intelboot++;
312
313                 if (!orig_romcs1par) {
314                         intel0cs = SC520_PAR_BOOTCS;
315                         intel0par = (volatile unsigned long *)
316                                 (nettel_mmcrp + 0xc4);
317                         intel1cs = SC520_PAR_ROMCS1;
318                         intel1par = (volatile unsigned long *)
319                                 (nettel_mmcrp + 0xc0);
320
321                         intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
322                         maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
323                 } else {
324                         /* Kernel base is on ROMCS1, not BOOTCS */
325                         intel0cs = SC520_PAR_ROMCS1;
326                         intel0par = (volatile unsigned long *)
327                                 (nettel_mmcrp + 0xc0);
328                         intel1cs = SC520_PAR_BOOTCS;
329                         intel1par = (volatile unsigned long *)
330                                 (nettel_mmcrp + 0xc4);
331
332                         intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
333                         maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
334                 }
335
336                 /* Destroy useless AMD MTD mapping */
337                 amd_mtd = NULL;
338                 iounmap(nettel_amd_map.virt);
339                 nettel_amd_map.virt = NULL;
340 #else
341                 /* Only AMD flash supported */
342                 rc = -ENXIO;
343                 goto out_unmap2;
344 #endif
345         }
346
347 #ifdef CONFIG_MTD_CFI_INTELEXT
348         /*
349          *      We have determined the INTEL FLASH configuration, so lets
350          *      go ahead and probe for them now.
351          */
352
353         /* Set PAR to the maximum size */
354         if (maxsize < (32 * 1024 * 1024))
355                 maxsize = (32 * 1024 * 1024);
356         *intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
357
358         /* Turn other PAR off so the first probe doesn't find it */
359         *intel1par = 0;
360
361         /* Probe for the size of the first Intel flash */
362         nettel_intel_map.size = maxsize;
363         nettel_intel_map.phys = intel0addr;
364         nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
365         if (!nettel_intel_map.virt) {
366                 printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
367                 rc = -EIO;
368                 goto out_unmap2;
369         }
370         simple_map_init(&nettel_intel_map);
371
372         intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
373         if (!intel_mtd) {
374                 rc = -ENXIO;
375                 goto out_unmap1;
376         }
377
378         /* Set PAR to the detected size */
379         intel0size = intel_mtd->size;
380         *intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
381
382         /*
383          *      Map second Intel FLASH right after first. Set its size to the
384          *      same maxsize used for the first Intel FLASH.
385          */
386         intel1addr = intel0addr + intel0size;
387         *intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
388         __asm__ ("wbinvd");
389
390         maxsize += intel0size;
391
392         /* Delete the old map and probe again to do both chips */
393         map_destroy(intel_mtd);
394         intel_mtd = NULL;
395         iounmap(nettel_intel_map.virt);
396
397         nettel_intel_map.size = maxsize;
398         nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
399         if (!nettel_intel_map.virt) {
400                 printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
401                 rc = -EIO;
402                 goto out_unmap2;
403         }
404
405         intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
406         if (! intel_mtd) {
407                 rc = -ENXIO;
408                 goto out_unmap1;
409         }
410
411         intel1size = intel_mtd->size - intel0size;
412         if (intel1size > 0) {
413                 *intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
414                 __asm__ ("wbinvd");
415         } else {
416                 *intel1par = 0;
417         }
418
419         printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
420                 (intel_mtd->size >> 10));
421
422         intel_mtd->owner = THIS_MODULE;
423
424 #ifndef CONFIG_BLK_DEV_INITRD
425         ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
426 #endif
427
428         num_intel_partitions = sizeof(nettel_intel_partitions) /
429                 sizeof(nettel_intel_partitions[0]);
430
431         if (intelboot) {
432                 /*
433                  *      Adjust offset and size of last boot partition.
434                  *      Must allow for BIOS region at end of FLASH.
435                  */
436                 nettel_intel_partitions[1].size = (intel0size + intel1size) -
437                         (1024*1024 + intel_mtd->erasesize);
438                 nettel_intel_partitions[3].size = intel0size + intel1size;
439                 nettel_intel_partitions[4].offset =
440                         (intel0size + intel1size) - intel_mtd->erasesize;
441                 nettel_intel_partitions[4].size = intel_mtd->erasesize;
442                 nettel_intel_partitions[5].offset =
443                         nettel_intel_partitions[4].offset;
444                 nettel_intel_partitions[5].size =
445                         nettel_intel_partitions[4].size;
446         } else {
447                 /* No BIOS regions when AMD boot */
448                 num_intel_partitions -= 2;
449         }
450         rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
451                 num_intel_partitions);
452 #endif
453
454         if (amd_mtd) {
455                 rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
456                         num_amd_partitions);
457         }
458
459 #ifdef CONFIG_MTD_CFI_INTELEXT
460         register_reboot_notifier(&nettel_notifier_block);
461 #endif
462
463         return(rc);
464
465 #ifdef CONFIG_MTD_CFI_INTELEXT
466 out_unmap1:
467         iounmap(nettel_intel_map.virt);
468 #endif
469
470 out_unmap2:
471         iounmap(nettel_mmcrp);
472         iounmap(nettel_amd_map.virt);
473
474         return(rc);
475
476 }
477
478 /****************************************************************************/
479
480 void __exit nettel_cleanup(void)
481 {
482 #ifdef CONFIG_MTD_CFI_INTELEXT
483         unregister_reboot_notifier(&nettel_notifier_block);
484 #endif
485         if (amd_mtd) {
486                 del_mtd_partitions(amd_mtd);
487                 map_destroy(amd_mtd);
488         }
489         if (nettel_mmcrp) {
490                 iounmap(nettel_mmcrp);
491                 nettel_mmcrp = NULL;
492         }
493         if (nettel_amd_map.virt) {
494                 iounmap(nettel_amd_map.virt);
495                 nettel_amd_map.virt = NULL;
496         }
497 #ifdef CONFIG_MTD_CFI_INTELEXT
498         if (intel_mtd) {
499                 del_mtd_partitions(intel_mtd);
500                 map_destroy(intel_mtd);
501         }
502         if (nettel_intel_map.virt) {
503                 iounmap(nettel_intel_map.virt);
504                 nettel_intel_map.virt = NULL;
505         }
506 #endif
507 }
508
509 /****************************************************************************/
510
511 module_init(nettel_init);
512 module_exit(nettel_cleanup);
513
514 MODULE_LICENSE("GPL");
515 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
516 MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
517
518 /****************************************************************************/