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