ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.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.4 2003/05/20 20:59:30 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         .buswidth = 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         .buswidth = 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 = 0;
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 = (unsigned long)
277                 ioremap_nocache(amdaddr, maxsize);
278         if (!nettel_amd_map.virt) {
279                 printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
280                 return(-EIO);
281         }
282         simple_map_init(&nettel_amd_map);
283
284         if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
285                 printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
286                         amd_mtd->size>>10);
287
288                 amd_mtd->owner = THIS_MODULE;
289
290                 /* The high BIOS partition is only present for 2MB units */
291                 num_amd_partitions = NUM_AMD_PARTITIONS;
292                 if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
293                         num_amd_partitions--;
294                 /* Don't add the partition until after the primary INTEL's */
295
296 #ifdef CONFIG_MTD_CFI_INTELEXT
297                 /*
298                  *      Map the Intel flash into memory after the AMD
299                  *      It has to start on a multiple of maxsize.
300                  */
301                 maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
302                 if (maxsize < (32 * 1024 * 1024))
303                         maxsize = (32 * 1024 * 1024);
304                 intel0addr = amdaddr + maxsize;
305 #endif
306         } else {
307 #ifdef CONFIG_MTD_CFI_INTELEXT
308                 /* INTEL boot FLASH */
309                 intelboot++;
310
311                 if (!orig_romcs1par) {
312                         intel0cs = SC520_PAR_BOOTCS;
313                         intel0par = (volatile unsigned long *)
314                                 (nettel_mmcrp + 0xc4);
315                         intel1cs = SC520_PAR_ROMCS1;
316                         intel1par = (volatile unsigned long *)
317                                 (nettel_mmcrp + 0xc0);
318
319                         intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
320                         maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
321                 } else {
322                         /* Kernel base is on ROMCS1, not BOOTCS */
323                         intel0cs = SC520_PAR_ROMCS1;
324                         intel0par = (volatile unsigned long *)
325                                 (nettel_mmcrp + 0xc0);
326                         intel1cs = SC520_PAR_BOOTCS;
327                         intel1par = (volatile unsigned long *)
328                                 (nettel_mmcrp + 0xc4);
329
330                         intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
331                         maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
332                 }
333
334                 /* Destroy useless AMD MTD mapping */
335                 amd_mtd = NULL;
336                 iounmap((void *) nettel_amd_map.virt);
337                 nettel_amd_map.virt = (unsigned long) NULL;
338 #else
339                 /* Only AMD flash supported */
340                 return(-ENXIO);
341 #endif
342         }
343
344 #ifdef CONFIG_MTD_CFI_INTELEXT
345         /*
346          *      We have determined the INTEL FLASH configuration, so lets
347          *      go ahead and probe for them now.
348          */
349
350         /* Set PAR to the maximum size */
351         if (maxsize < (32 * 1024 * 1024))
352                 maxsize = (32 * 1024 * 1024);
353         *intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
354
355         /* Turn other PAR off so the first probe doesn't find it */
356         *intel1par = 0;
357
358         /* Probe for the the size of the first Intel flash */
359         nettel_intel_map.size = maxsize;
360         nettel_intel_map.phys = intel0addr;
361         nettel_intel_map.virt = (unsigned long)
362                 ioremap_nocache(intel0addr, maxsize);
363         if (!nettel_intel_map.virt) {
364                 printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
365                 return(-EIO);
366         }
367         simple_map_init(&nettel_intel_map);
368
369         intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
370         if (! intel_mtd) {
371                 iounmap((void *) nettel_intel_map.virt);
372                 return(-ENXIO);
373         }
374
375         /* Set PAR to the detected size */
376         intel0size = intel_mtd->size;
377         *intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
378
379         /*
380          *      Map second Intel FLASH right after first. Set its size to the
381          *      same maxsize used for the first Intel FLASH.
382          */
383         intel1addr = intel0addr + intel0size;
384         *intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
385         __asm__ ("wbinvd");
386
387         maxsize += intel0size;
388
389         /* Delete the old map and probe again to do both chips */
390         map_destroy(intel_mtd);
391         intel_mtd = NULL;
392         iounmap((void *) nettel_intel_map.virt);
393
394         nettel_intel_map.size = maxsize;
395         nettel_intel_map.virt = (unsigned long)
396                 ioremap_nocache(intel0addr, maxsize);
397         if (!nettel_intel_map.virt) {
398                 printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
399                 return(-EIO);
400         }
401
402         intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
403         if (! intel_mtd) {
404                 iounmap((void *) nettel_intel_map.virt);
405                 return(-ENXIO);
406         }
407
408         intel1size = intel_mtd->size - intel0size;
409         if (intel1size > 0) {
410                 *intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
411                 __asm__ ("wbinvd");
412         } else {
413                 *intel1par = 0;
414         }
415
416         printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
417                 (intel_mtd->size >> 10));
418
419         intel_mtd->owner = THIS_MODULE;
420
421 #ifndef CONFIG_BLK_DEV_INITRD
422         ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
423 #endif
424
425         num_intel_partitions = sizeof(nettel_intel_partitions) /
426                 sizeof(nettel_intel_partitions[0]);
427
428         if (intelboot) {
429                 /*
430                  *      Adjust offset and size of last boot partition.
431                  *      Must allow for BIOS region at end of FLASH.
432                  */
433                 nettel_intel_partitions[1].size = (intel0size + intel1size) -
434                         (1024*1024 + intel_mtd->erasesize);
435                 nettel_intel_partitions[3].size = intel0size + intel1size;
436                 nettel_intel_partitions[4].offset = 
437                         (intel0size + intel1size) - intel_mtd->erasesize;
438                 nettel_intel_partitions[4].size = intel_mtd->erasesize;
439                 nettel_intel_partitions[5].offset =
440                         nettel_intel_partitions[4].offset;
441                 nettel_intel_partitions[5].size =
442                         nettel_intel_partitions[4].size;
443         } else {
444                 /* No BIOS regions when AMD boot */
445                 num_intel_partitions -= 2;
446         }
447         rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
448                 num_intel_partitions);
449 #endif
450
451         if (amd_mtd) {
452                 rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
453                         num_amd_partitions);
454         }
455
456 #ifdef CONFIG_MTD_CFI_INTELEXT
457         register_reboot_notifier(&nettel_notifier_block);
458 #endif
459
460         return(rc);
461 }
462
463 /****************************************************************************/
464
465 void __exit nettel_cleanup(void)
466 {
467 #ifdef CONFIG_MTD_CFI_INTELEXT
468         unregister_reboot_notifier(&nettel_notifier_block);
469 #endif
470         if (amd_mtd) {
471                 del_mtd_partitions(amd_mtd);
472                 map_destroy(amd_mtd);
473         }
474         if (nettel_amd_map.virt) {
475                 iounmap((void *)nettel_amd_map.virt);
476                 nettel_amd_map.virt = 0;
477         }
478 #ifdef CONFIG_MTD_CFI_INTELEXT
479         if (intel_mtd) {
480                 del_mtd_partitions(intel_mtd);
481                 map_destroy(intel_mtd);
482         }
483         if (nettel_intel_map.virt) {
484                 iounmap((void *)nettel_intel_map.virt);
485                 nettel_intel_map.virt = 0;
486         }
487 #endif
488 }
489
490 /****************************************************************************/
491
492 module_init(nettel_init);
493 module_exit(nettel_cleanup);
494
495 MODULE_LICENSE("GPL");
496 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
497 MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
498
499 /****************************************************************************/