ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / mtd / maps / sa1100-flash.c
1 /*
2  * Flash memory access on SA11x0 based devices
3  * 
4  * (C) 2000 Nicolas Pitre <nico@cam.org>
5  * 
6  * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $
7  */
8
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/ioport.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/errno.h>
16 #include <linux/slab.h>
17
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/map.h>
20 #include <linux/mtd/partitions.h>
21 #include <linux/mtd/concat.h>
22
23 #include <asm/hardware.h>
24 #include <asm/mach-types.h>
25 #include <asm/io.h>
26 #include <asm/sizes.h>
27
28 #include <asm/arch/h3600.h>
29
30 #ifndef CONFIG_ARCH_SA1100
31 #error This is for SA1100 architecture only
32 #endif
33
34 /*
35  * This isnt complete yet, so...
36  */
37 #define CONFIG_MTD_SA1100_STATICMAP 1
38
39 #ifdef CONFIG_MTD_SA1100_STATICMAP
40 /*
41  * Here are partition information for all known SA1100-based devices.
42  * See include/linux/mtd/partitions.h for definition of the mtd_partition
43  * structure.
44  *
45  * Please note:
46  *  1. We no longer support static flash mappings via the machine io_desc
47  *     structure.
48  *  2. The flash size given should be the largest flash size that can
49  *     be accommodated.
50  *
51  * The MTD layer will detect flash chip aliasing and reduce the size of
52  * the map accordingly.
53  *
54  * Please keep these in alphabetical order, and formatted as per existing
55  * entries.  Thanks.
56  */
57
58 #ifdef CONFIG_SA1100_ADSBITSY
59 static struct mtd_partition adsbitsy_partitions[] = {
60         {
61                 .name           = "bootROM",
62                 .size           = 0x80000,
63                 .offset         = 0,
64                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
65         }, {
66                 .name           = "zImage",
67                 .size           = 0x100000,
68                 .offset         = MTDPART_OFS_APPEND,
69                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
70         }, {
71                 .name           = "ramdisk.gz",
72                 .size           = 0x300000,
73                 .offset         = MTDPART_OFS_APPEND,
74                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
75         }, {
76                 .name           = "User FS",
77                 .size           = MTDPART_SIZ_FULL,
78                 .offset         = MTDPART_OFS_APPEND,
79         }
80 };
81 #endif
82
83 #ifdef CONFIG_SA1100_ASSABET
84 /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
85 static struct mtd_partition assabet4_partitions[] = {
86         {
87                 .name           = "bootloader",
88                 .size           = 0x00020000,
89                 .offset         = 0,
90                 .mask_flags     = MTD_WRITEABLE,
91         }, {
92                 .name           = "bootloader params",
93                 .size           = 0x00020000,
94                 .offset         = MTDPART_OFS_APPEND,
95                 .mask_flags     = MTD_WRITEABLE,
96         }, {
97                 .name           = "jffs",
98                 .size           = MTDPART_SIZ_FULL,
99                 .offset         = MTDPART_OFS_APPEND,
100         }
101 };
102
103 /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
104 static struct mtd_partition assabet5_partitions[] = {
105         {
106                 .name           = "bootloader",
107                 .size           = 0x00040000,
108                 .offset         = 0,
109                 .mask_flags     = MTD_WRITEABLE,
110         }, {
111                 .name           = "bootloader params",
112                 .size           = 0x00040000,
113                 .offset         = MTDPART_OFS_APPEND,
114                 .mask_flags     = MTD_WRITEABLE,
115         }, {
116                 .name           = "jffs",
117                 .size           = MTDPART_SIZ_FULL,
118                 .offset         = MTDPART_OFS_APPEND,
119         }
120 };
121
122 #define assabet_partitions      assabet5_partitions
123 #endif
124
125 #ifdef CONFIG_SA1100_BADGE4
126 /*
127  * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
128  *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
129  *   Sixty-three 32 KiW Main Blocks (4032 Ki b)
130  *
131  * <or>
132  *
133  * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
134  *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
135  *   One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
136  */
137 static struct mtd_partition badge4_partitions[] = {
138         {
139                 .name           = "BLOB boot loader",
140                 .offset         = 0,
141                 .size           = 0x0000A000
142         }, {
143                 .name           = "params",
144                 .offset         = MTDPART_OFS_APPEND,
145                 .size           = 0x00006000
146         }, {
147                 .name           = "root",
148                 .offset         = MTDPART_OFS_APPEND,
149                 .size           = MTDPART_SIZ_FULL
150         }
151 };
152 #endif
153
154
155 #ifdef CONFIG_SA1100_CERF
156 #ifdef CONFIG_SA1100_CERF_FLASH_32MB
157 #  define CERF_FLASH_SIZE       0x02000000
158 #elif defined CONFIG_SA1100_CERF_FLASH_16MB
159 #  define CERF_FLASH_SIZE       0x01000000
160 #elif defined CONFIG_SA1100_CERF_FLASH_8MB
161 #  define CERF_FLASH_SIZE       0x00800000
162 #else
163 #  error "Undefined flash size for CERF in sa1100-flash.c"
164 #endif
165
166 static struct mtd_partition cerf_partitions[] = {
167         {
168                 .name           = "Bootloader",
169                 .size           = 0x00020000,
170                 .offset         = 0x00000000,
171         }, {
172                 .name           = "Params",
173                 .size           = 0x00040000,
174                 .offset         = 0x00020000,
175         }, {
176                 .name           = "Kernel",
177                 .size           = 0x00100000,
178                 .offset         = 0x00060000,
179         }, {
180                 .name           = "Filesystem",
181                 .size           = CERF_FLASH_SIZE-0x00160000,
182                 .offset         = 0x00160000,
183         }
184 };
185 #endif
186
187 #ifdef CONFIG_SA1100_CONSUS
188 static struct mtd_partition consus_partitions[] = {
189         {
190                 .name           = "Consus boot firmware",
191                 .offset         = 0,
192                 .size           = 0x00040000,
193                 .mask_flags     = MTD_WRITABLE, /* force read-only */
194         }, {
195                 .name           = "Consus kernel",
196                 .offset         = 0x00040000,
197                 .size           = 0x00100000,
198                 .mask_flags     = 0,
199         }, {
200                 .name           = "Consus disk",
201                 .offset         = 0x00140000,
202                 /* The rest (up to 16M) for jffs.  We could put 0 and
203                    make it find the size automatically, but right now
204                    i have 32 megs.  jffs will use all 32 megs if given
205                    the chance, and this leads to horrible problems
206                    when you try to re-flash the image because blob
207                    won't erase the whole partition. */
208                 .size           = 0x01000000 - 0x00140000,
209                 .mask_flags     = 0,
210         }, {
211                 /* this disk is a secondary disk, which can be used as
212                    needed, for simplicity, make it the size of the other
213                    consus partition, although realistically it could be
214                    the remainder of the disk (depending on the file
215                    system used) */
216                  .name          = "Consus disk2",
217                  .offset        = 0x01000000,
218                  .size          = 0x01000000 - 0x00140000,
219                  .mask_flags    = 0,
220         }
221 };
222 #endif
223
224 #ifdef CONFIG_SA1100_FLEXANET
225 /* Flexanet has two 28F128J3A flash parts in bank 0: */
226 #define FLEXANET_FLASH_SIZE             0x02000000
227 static struct mtd_partition flexanet_partitions[] = {
228         {
229                 .name           = "bootloader",
230                 .size           = 0x00040000,
231                 .offset         = 0,
232                 .mask_flags     = MTD_WRITEABLE,
233         }, {
234                 .name           = "bootloader params",
235                 .size           = 0x00040000,
236                 .offset         = MTDPART_OFS_APPEND,
237                 .mask_flags     = MTD_WRITEABLE,
238         }, {
239                 .name           = "kernel",
240                 .size           = 0x000C0000,
241                 .offset         = MTDPART_OFS_APPEND,
242                 .mask_flags     = MTD_WRITEABLE,
243         }, {
244                 .name           = "altkernel",
245                 .size           = 0x000C0000,
246                 .offset         = MTDPART_OFS_APPEND,
247                 .mask_flags     = MTD_WRITEABLE,
248         }, {
249                 .name           = "root",
250                 .size           = 0x00400000,
251                 .offset         = MTDPART_OFS_APPEND,
252                 .mask_flags     = MTD_WRITEABLE,
253         }, {
254                 .name           = "free1",
255                 .size           = 0x00300000,
256                 .offset         = MTDPART_OFS_APPEND,
257                 .mask_flags     = MTD_WRITEABLE,
258         }, {
259                 .name           = "free2",
260                 .size           = 0x00300000,
261                 .offset         = MTDPART_OFS_APPEND,
262                 .mask_flags     = MTD_WRITEABLE,
263         }, {
264                 .name           = "free3",
265                 .size           = MTDPART_SIZ_FULL,
266                 .offset         = MTDPART_OFS_APPEND,
267                 .mask_flags     = MTD_WRITEABLE,
268         }
269 };
270 #endif
271
272 #ifdef CONFIG_SA1100_FREEBIRD
273 static struct mtd_partition freebird_partitions[] = {
274 #ifdef CONFIG_SA1100_FREEBIRD_NEW
275         {
276                 .name           = "firmware",
277                 .size           = 0x00040000,
278                 .offset         = 0,
279                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
280         }, {
281                 .name           = "kernel",
282                 .size           = 0x00080000,
283                 .offset         = 0x00040000,
284         }, {
285                 .name           = "params",
286                 .size           = 0x00040000,
287                 .offset         = 0x000C0000,
288         }, {
289                 .name           = "initrd",
290                 .size           = 0x00100000,
291                 .offset         = 0x00100000,
292         }, {
293                 .name           = "root cramfs",
294                 .size           = 0x00300000,
295                 .offset         = 0x00200000,
296         }, {
297                 .name           = "usr cramfs",
298                 .size           = 0x00C00000,
299                 .offset         = 0x00500000,
300         }, {
301                 .name           = "local",
302                 .size           = MTDPART_SIZ_FULL,
303                 .offset         = 0x01100000,
304         }
305 #else
306         {
307                 .size           = 0x00040000,
308                 .offset         = 0,
309         }, {
310                 .size           = 0x000c0000,
311                 .offset         = MTDPART_OFS_APPEND,
312         }, {
313                 .size           = 0x00400000,
314                 .offset         = MTDPART_OFS_APPEND,
315         }, {
316                 .size           = MTDPART_SIZ_FULL,
317                 .offset         = MTDPART_OFS_APPEND,
318         }
319 #endif
320 };
321 #endif
322
323 #ifdef CONFIG_SA1100_FRODO
324 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
325 static struct mtd_partition frodo_partitions[] =
326 {
327         {
328                 .name           = "bootloader",
329                 .size           = 0x00040000,
330                 .offset         = 0x00000000,
331                 .mask_flags     = MTD_WRITEABLE
332         }, {
333                 .name           = "bootloader params",
334                 .size           = 0x00040000,
335                 .offset         = MTDPART_OFS_APPEND,
336                 .mask_flags     = MTD_WRITEABLE
337         }, {
338                 .name           = "kernel",
339                 .size           = 0x00100000,
340                 .offset         = MTDPART_OFS_APPEND,
341                 .mask_flags     = MTD_WRITEABLE
342         }, {
343                 .name           = "ramdisk",
344                 .size           = 0x00400000,
345                 .offset         = MTDPART_OFS_APPEND,
346                 .mask_flags     = MTD_WRITEABLE
347         }, {
348                 .name           = "file system",
349                 .size           = MTDPART_SIZ_FULL,
350                 .offset         = MTDPART_OFS_APPEND
351         }
352 };
353 #endif
354
355 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
356 static struct mtd_partition graphicsclient_partitions[] = {
357         {
358                 .name           = "zImage",
359                 .size           = 0x100000,
360                 .offset         = 0,
361                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
362         }, {
363                 .name           = "ramdisk.gz",
364                 .size           = 0x300000,
365                 .offset         = MTDPART_OFS_APPEND,
366                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
367         }, {
368                 .name           = "User FS",
369                 .size           = MTDPART_SIZ_FULL,
370                 .offset         = MTDPART_OFS_APPEND,
371         }
372 };
373 #endif
374
375 #ifdef CONFIG_SA1100_GRAPHICSMASTER
376 static struct mtd_partition graphicsmaster_partitions[] = {
377         {
378                 .name           = "zImage",
379                 .size           = 0x100000,
380                 .offset         = 0,
381                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
382         },
383         {
384                 .name           = "ramdisk.gz",
385                 .size           = 0x300000,
386                 .offset         = MTDPART_OFS_APPEND,
387                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
388         },
389         {
390                 .name           = "User FS",
391                 .size           = MTDPART_SIZ_FULL,
392                 .offset         = MTDPART_OFS_APPEND,
393         }
394 };
395 #endif
396
397 #ifdef CONFIG_SA1100_H3XXX
398 static struct mtd_partition h3xxx_partitions[] = {
399         {
400                 .name           = "H3XXX boot firmware",
401                 .size           = 0x00040000,
402                 .offset         = 0,
403                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
404         }, {
405 #ifdef CONFIG_MTD_2PARTS_IPAQ
406                 .name           = "H3XXX root jffs2",
407                 .size           = MTDPART_SIZ_FULL,
408                 .offset         = 0x00040000,
409 #else
410                 .name           = "H3XXX kernel",
411                 .size           = 0x00080000,
412                 .offset         = 0x00040000,
413         }, {
414                 .name           = "H3XXX params",
415                 .size           = 0x00040000,
416                 .offset         = 0x000C0000,
417         }, {
418 #ifdef CONFIG_JFFS2_FS
419                 .name           = "H3XXX root jffs2",
420                 .size           = MTDPART_SIZ_FULL,
421                 .offset         = 0x00100000,
422 #else
423                 .name           = "H3XXX initrd",
424                 .size           = 0x00100000,
425                 .offset         = 0x00100000,
426         }, {
427                 .name           = "H3XXX root cramfs",
428                 .size           = 0x00300000,
429                 .offset         = 0x00200000,
430         }, {
431                 .name           = "H3XXX usr cramfs",
432                 .size           = 0x00800000,
433                 .offset         = 0x00500000,
434         }, {
435                 .name           = "H3XXX usr local",
436                 .size           = MTDPART_SIZ_FULL,
437                 .offset         = 0x00d00000,
438 #endif
439 #endif
440         }
441 };
442
443 static void h3xxx_set_vpp(struct map_info *map, int vpp)
444 {
445         assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
446 }
447 #else
448 #define h3xxx_set_vpp NULL
449 #endif
450
451 #ifdef CONFIG_SA1100_HACKKIT
452 static struct mtd_partition hackkit_partitions[] = {
453         {
454                 .name           = "BLOB",
455                 .size           = 0x00040000,
456                 .offset         = 0x00000000,
457                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
458         }, {
459                 .name           = "config",
460                 .size           = 0x00040000,
461                 .offset         = MTDPART_OFS_APPEND,
462         }, {
463                 .name           = "kernel",
464                 .size           = 0x00100000,
465                 .offset         = MTDPART_OFS_APPEND,
466         }, {
467                 .name           = "initrd",
468                 .size           = 0x00180000,
469                 .offset         = MTDPART_OFS_APPEND,
470         }, {
471                 .name           = "rootfs",
472                 .size           = 0x700000,
473                 .offset         = MTDPART_OFS_APPEND,
474         }, {
475                 .name           = "data",
476                 .size           = MTDPART_SIZ_FULL,
477                 .offset         = MTDPART_OFS_APPEND,
478         }
479 };
480 #endif
481
482 #ifdef CONFIG_SA1100_HUW_WEBPANEL
483 static struct mtd_partition huw_webpanel_partitions[] = {
484         {
485                 .name           = "Loader",
486                 .size           = 0x00040000,
487                 .offset         = 0,
488         }, {
489                 .name           = "Sector 1",
490                 .size           = 0x00040000,
491                 .offset         = MTDPART_OFS_APPEND,
492         }, {
493                 .size           = MTDPART_SIZ_FULL,
494                 .offset         = MTDPART_OFS_APPEND,
495         }
496 };
497 #endif
498
499 #ifdef CONFIG_SA1100_JORNADA720
500 static struct mtd_partition jornada720_partitions[] = {
501         {
502                 .name           = "JORNADA720 boot firmware",
503                 .size           = 0x00040000,
504                 .offset         = 0,
505                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
506         }, {
507                 .name           = "JORNADA720 kernel",
508                 .size           = 0x000c0000,
509                 .offset         = 0x00040000,
510         }, {
511                 .name           = "JORNADA720 params",
512                 .size           = 0x00040000,
513                 .offset         = 0x00100000,
514         }, {
515                 .name           = "JORNADA720 initrd",
516                 .size           = 0x00100000,
517                 .offset         = 0x00140000,
518         }, {
519                 .name           = "JORNADA720 root cramfs",
520                 .size           = 0x00300000,
521                 .offset         = 0x00240000,
522         }, {
523                 .name           = "JORNADA720 usr cramfs",
524                 .size           = 0x00800000,
525                 .offset         = 0x00540000,
526         }, {
527                 .name           = "JORNADA720 usr local",
528                 .size           = 0,  /* will expand to the end of the flash */
529                 .offset         = 0x00d00000,
530         }
531 };
532
533 static void jornada720_set_vpp(struct map_info *map, int vpp)
534 {
535         if (vpp)
536                 PPSR |= 0x80;
537         else
538                 PPSR &= ~0x80;
539         PPDR |= 0x80;
540 }
541 #else
542 #define jornada720_set_vpp NULL
543 #endif
544
545 #ifdef CONFIG_SA1100_PANGOLIN
546 static struct mtd_partition pangolin_partitions[] = {
547         {
548                 .name           = "boot firmware",
549                 .size           = 0x00080000,
550                 .offset         = 0x00000000,
551                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
552         }, {
553                 .name           = "kernel",
554                 .size           = 0x00100000,
555                 .offset         = 0x00080000,
556         }, {
557                 .name           = "initrd",
558                 .size           = 0x00280000,
559                 .offset         = 0x00180000,
560         }, {
561                 .name           = "initrd-test",
562                 .size           = 0x03C00000,
563                 .offset         = 0x00400000,
564         }
565 };
566 #endif
567
568 #ifdef CONFIG_SA1100_PT_SYSTEM3
569 /* erase size is 0x40000 == 256k partitions have to have this boundary */
570 static struct mtd_partition system3_partitions[] = {
571         {
572                 .name           = "BLOB",
573                 .size           = 0x00040000,
574                 .offset         = 0x00000000,
575                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
576         }, {
577                 .name           = "config",
578                 .size           = 0x00040000,
579                 .offset         = MTDPART_OFS_APPEND,
580         }, {
581                 .name           = "kernel",
582                 .size           = 0x00100000,
583                 .offset         = MTDPART_OFS_APPEND,
584         }, {
585                 .name           = "root",
586                 .size           = MTDPART_SIZ_FULL,
587                 .offset         = MTDPART_OFS_APPEND,
588         }
589 };
590 #endif
591
592 #ifdef CONFIG_SA1100_SHANNON
593 static struct mtd_partition shannon_partitions[] = {
594         {
595                 .name           = "BLOB boot loader",
596                 .offset         = 0,
597                 .size           = 0x20000
598         },
599         {
600                 .name           = "kernel",
601                 .offset         = MTDPART_OFS_APPEND,
602                 .size           = 0xe0000
603         },
604         { 
605                 .name           = "initrd",
606                 .offset         = MTDPART_OFS_APPEND,   
607                 .size           = MTDPART_SIZ_FULL
608         }
609 };
610
611 #endif
612
613 #ifdef CONFIG_SA1100_SHERMAN
614 static struct mtd_partition sherman_partitions[] = {
615         {
616                 .size           = 0x50000,
617                 .offset         = 0,
618         }, {
619                 .size           = 0x70000,
620                 .offset         = MTDPART_OFS_APPEND,
621         }, {
622                 .size           = 0x600000,
623                 .offset         = MTDPART_OFS_APPEND,
624         }, {
625                 .size           = 0xA0000,
626                 .offset         = MTDPART_OFS_APPEND,
627         }
628 };
629 #endif
630
631 #ifdef CONFIG_SA1100_SIMPAD
632 static struct mtd_partition simpad_partitions[] = {
633         {
634                 .name           = "SIMpad boot firmware",
635                 .size           = 0x00080000,
636                 .offset         = 0,
637                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
638         }, {
639                 .name           = "SIMpad kernel",
640                 .size           = 0x00100000,
641                 .offset         = MTDPART_OFS_APPEND,
642         }, {
643 #ifdef CONFIG_ROOT_CRAMFS
644                 .name           = "SIMpad root cramfs",
645                 .size           =0x00D80000,
646                 .offset         = MTDPART_OFS_APPEND
647
648         }, {
649                 .name           = "SIMpad local jffs2",
650                 .size           = MTDPART_SIZ_FULL,
651                 .offset         = MTDPART_OFS_APPEND
652 #else
653                 .name           = "SIMpad root jffs2",
654                 .size           = MTDPART_SIZ_FULL,
655                 .offset         = MTDPART_OFS_APPEND
656 #endif
657         }
658 };
659 #endif /* CONFIG_SA1100_SIMPAD */
660
661 #ifdef CONFIG_SA1100_STORK
662 static struct mtd_partition stork_partitions[] = {
663         {
664                 .name           = "STORK boot firmware",
665                 .size           = 0x00040000,
666                 .offset         = 0,
667                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
668         }, {
669                 .name           = "STORK params",
670                 .size           = 0x00040000,
671                 .offset         = 0x00040000,
672         }, {
673                 .name           = "STORK kernel",
674                 .size           = 0x00100000,
675                 .offset         = 0x00080000,
676         }, {
677 #ifdef CONFIG_JFFS2_FS
678                 .name           = "STORK root jffs2",
679                 .offset         = 0x00180000,
680                 .size           = MTDPART_SIZ_FULL,
681 #else
682                 .name           = "STORK initrd",
683                 .size           = 0x00100000,
684                 .offset         = 0x00180000,
685         }, {
686                 .name           = "STORK root cramfs",
687                 .size           = 0x00300000,
688                 .offset         = 0x00280000,
689         }, {
690                 .name           = "STORK usr cramfs",
691                 .size           = 0x00800000,
692                 .offset         = 0x00580000,
693         }, {
694                 .name           = "STORK usr local",
695                 .offset         = 0x00d80000,
696                 .size           = MTDPART_SIZ_FULL,
697 #endif
698         }
699 };
700 #endif
701
702 #ifdef CONFIG_SA1100_TRIZEPS
703 static struct mtd_partition trizeps_partitions[] = {
704         {
705                 .name           = "Bootloader",
706                 .size           = 0x00100000,
707                 .offset         = 0,
708         }, {
709                 .name           = "Kernel",
710                 .size           = 0x00100000,
711                 .offset         = MTDPART_OFS_APPEND,
712         }, {
713                 .name           = "root",
714                 .size           = MTDPART_SIZ_FULL,
715                 .offset         = MTDPART_OFS_APPEND,
716         }
717 };
718 #endif
719
720 #ifdef CONFIG_SA1100_YOPY
721 static struct mtd_partition yopy_partitions[] = {
722         {
723                 .name           = "boot firmware",
724                 .size           = 0x00040000,
725                 .offset         = 0x00000000,
726                 .mask_flags     = MTD_WRITEABLE,  /* force read-only */
727         }, {
728                 .name           = "kernel",
729                 .size           = 0x00080000,
730                 .offset         = 0x00080000,
731         }, {
732                 .name           = "initrd",
733                 .size           = 0x00300000,
734                 .offset         = 0x00100000,
735         }, {
736                 .name           = "root",
737                 .size           = 0x01000000,
738                 .offset         = 0x00400000,
739         }
740 };
741 #endif
742
743 static int __init sa1100_static_partitions(struct mtd_partition **parts)
744 {
745         int nb_parts = 0;
746
747 #ifdef CONFIG_SA1100_ADSBITSY
748         if (machine_is_adsbitsy()) {
749                 *parts       = adsbitsy_partitions;
750                 nb_parts     = ARRAY_SIZE(adsbitsy_partitions);
751         }
752 #endif
753 #ifdef CONFIG_SA1100_ASSABET
754         if (machine_is_assabet()) {
755                 *parts       = assabet_partitions;
756                 nb_parts     = ARRAY_SIZE(assabet_partitions);
757         }
758 #endif
759 #ifdef CONFIG_SA1100_BADGE4
760         if (machine_is_badge4()) {
761                 *parts       = badge4_partitions;
762                 nb_parts     = ARRAY_SIZE(badge4_partitions);
763         }
764 #endif
765 #ifdef CONFIG_SA1100_CERF
766         if (machine_is_cerf()) {
767                 *parts       = cerf_partitions;
768                 nb_parts     = ARRAY_SIZE(cerf_partitions);
769         }
770 #endif
771 #ifdef CONFIG_SA1100_CONSUS
772         if (machine_is_consus()) {
773                 *parts       = consus_partitions;
774                 nb_parts     = ARRAY_SIZE(consus_partitions);
775         }
776 #endif
777 #ifdef CONFIG_SA1100_FLEXANET
778         if (machine_is_flexanet()) {
779                 *parts       = flexanet_partitions;
780                 nb_parts     = ARRAY_SIZE(flexanet_partitions);
781         }
782 #endif
783 #ifdef CONFIG_SA1100_FREEBIRD
784         if (machine_is_freebird()) {
785                 *parts       = freebird_partitions;
786                 nb_parts     = ARRAY_SIZE(freebird_partitions);
787         }
788 #endif
789 #ifdef CONFIG_SA1100_FRODO
790         if (machine_is_frodo()) {
791                 *parts       = frodo_partitions;
792                 nb_parts     = ARRAY_SIZE(frodo_partitions);
793         }
794 #endif  
795 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
796         if (machine_is_graphicsclient()) {
797                 *parts       = graphicsclient_partitions;
798                 nb_parts     = ARRAY_SIZE(graphicsclient_partitions);
799         }
800 #endif
801 #ifdef CONFIG_SA1100_GRAPHICSMASTER
802         if (machine_is_graphicsmaster()) {
803                 *parts       = graphicsmaster_partitions;
804                 nb_parts     = ARRAY_SIZE(graphicsmaster_partitions);
805         }
806 #endif
807 #ifdef CONFIG_SA1100_H3XXX
808         if (machine_is_h3xxx()) {
809                 *parts       = h3xxx_partitions;
810                 nb_parts     = ARRAY_SIZE(h3xxx_partitions);
811         }
812 #endif
813 #ifdef CONFIG_SA1100_HACKKIT
814         if (machine_is_hackkit()) {
815                 *parts = hackkit_partitions;
816                 nb_parts = ARRAY_SIZE(hackkit_partitions);
817         }
818 #endif
819 #ifdef CONFIG_SA1100_HUW_WEBPANEL
820         if (machine_is_huw_webpanel()) {
821                 *parts       = huw_webpanel_partitions;
822                 nb_parts     = ARRAY_SIZE(huw_webpanel_partitions);
823         }
824 #endif
825 #ifdef CONFIG_SA1100_JORNADA720
826         if (machine_is_jornada720()) {
827                 *parts       = jornada720_partitions;
828                 nb_parts     = ARRAY_SIZE(jornada720_partitions);
829         }
830 #endif
831 #ifdef CONFIG_SA1100_PANGOLIN
832         if (machine_is_pangolin()) {
833                 *parts       = pangolin_partitions;
834                 nb_parts     = ARRAY_SIZE(pangolin_partitions);
835         }
836 #endif
837 #ifdef CONFIG_SA1100_PT_SYSTEM3
838         if (machine_is_pt_system3()) {
839                 *parts       = system3_partitions;
840                 nb_parts     = ARRAY_SIZE(system3_partitions);
841         }
842 #endif
843 #ifdef CONFIG_SA1100_SHANNON
844         if (machine_is_shannon()) {
845                 *parts       = shannon_partitions;
846                 nb_parts     = ARRAY_SIZE(shannon_partitions);
847         }
848 #endif
849 #ifdef CONFIG_SA1100_SHERMAN
850         if (machine_is_sherman()) {
851                 *parts       = sherman_partitions;
852                 nb_parts     = ARRAY_SIZE(sherman_partitions);
853         }
854 #endif
855 #ifdef CONFIG_SA1100_SIMPAD
856         if (machine_is_simpad()) {
857                 *parts       = simpad_partitions;
858                 nb_parts     = ARRAY_SIZE(simpad_partitions);
859         }
860 #endif
861 #ifdef CONFIG_SA1100_STORK
862         if (machine_is_stork()) {
863                 *parts       = stork_partitions;
864                 nb_parts     = ARRAY_SIZE(stork_partitions);
865         }
866 #endif
867 #ifdef CONFIG_SA1100_TRIZEPS
868         if (machine_is_trizeps()) {
869                 *parts       = trizeps_partitions;
870                 nb_parts     = ARRAY_SIZE(trizeps_partitions);
871         }
872 #endif
873 #ifdef CONFIG_SA1100_YOPY
874         if (machine_is_yopy()) {
875                 *parts       = yopy_partitions;
876                 nb_parts     = ARRAY_SIZE(yopy_partitions);
877         }
878 #endif
879
880         return nb_parts;
881 }
882 #endif
883
884 struct sa_info {
885         unsigned long base;
886         unsigned long size;
887         int width;
888         void *vbase;
889         void (*set_vpp)(struct map_info *, int);
890         struct map_info *map;
891         struct mtd_info *mtd;
892         struct resource *res;
893 };
894
895 #define NR_SUBMTD 4
896
897 static struct sa_info info[NR_SUBMTD];
898
899 static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
900 {
901         struct mtd_info *subdev[nr];
902         struct map_info *maps;
903         int i, found = 0, ret = 0;
904
905         /*
906          * Allocate the map_info structs in one go.
907          */
908         maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
909         if (!maps)
910                 return -ENOMEM;
911
912         memset(maps, 0, sizeof(struct map_info) * nr);
913
914         /*
915          * Claim and then map the memory regions.
916          */
917         for (i = 0; i < nr; i++) {
918                 if (sa[i].base == (unsigned long)-1)
919                         break;
920
921                 sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
922                 if (!sa[i].res) {
923                         ret = -EBUSY;
924                         break;
925                 }
926
927                 sa[i].map = maps + i;
928
929                 sa[i].vbase = ioremap(sa[i].base, sa[i].size);
930                 if (!sa[i].vbase) {
931                         ret = -ENOMEM;
932                         break;
933                 }
934
935                 sa[i].map->virt = (unsigned long)sa[i].vbase;
936                 sa[i].map->phys = sa[i].base;
937                 sa[i].map->set_vpp = sa[i].set_vpp;
938                 sa[i].map->buswidth = sa[i].width;
939                 sa[i].map->size = sa[i].size;
940
941                 simple_map_init(sa[i].map);
942
943                 /*
944                  * Now let's probe for the actual flash.  Do it here since
945                  * specific machine settings might have been set above.
946                  */
947                 sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
948                 if (sa[i].mtd == NULL) {
949                         ret = -ENXIO;
950                         break;
951                 }
952                 sa[i].mtd->owner = THIS_MODULE;
953                 subdev[i] = sa[i].mtd;
954
955                 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
956                         "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
957                         sa[i].width * 8);
958                 found += 1;
959         }
960
961         /*
962          * ENXIO is special.  It means we didn't find a chip when
963          * we probed.  We need to tear down the mapping, free the
964          * resource and mark it as such.
965          */
966         if (ret == -ENXIO) {
967                 iounmap(sa[i].vbase);
968                 sa[i].vbase = NULL;
969                 release_resource(sa[i].res);
970                 sa[i].res = NULL;
971         }
972
973         /*
974          * If we found one device, don't bother with concat support.
975          * If we found multiple devices, use concat if we have it
976          * available, otherwise fail.
977          */
978         if (ret == 0 || ret == -ENXIO) {
979                 if (found == 1) {
980                         *rmtd = subdev[0];
981                         ret = 0;
982                 } else if (found > 1) {
983                         /*
984                          * We detected multiple devices.  Concatenate
985                          * them together.
986                          */
987 #ifdef CONFIG_MTD_CONCAT
988                         *rmtd = mtd_concat_create(subdev, found,
989                                                   "sa1100 flash");
990                         if (*rmtd == NULL)
991                                 ret = -ENXIO;
992 #else
993                         printk(KERN_ERR "SA1100 flash: multiple devices "
994                                "found but MTD concat support disabled.\n");
995                         ret = -ENXIO;
996 #endif
997                 }
998         }
999
1000         /*
1001          * If we failed, clean up.
1002          */
1003         if (ret) {
1004                 do {
1005                         if (sa[i].mtd)
1006                                 map_destroy(sa[i].mtd);
1007                         if (sa[i].vbase)
1008                                 iounmap(sa[i].vbase);
1009                         if (sa[i].res)
1010                                 release_resource(sa[i].res);
1011                 } while (i--);
1012
1013                 kfree(maps);
1014         }
1015
1016         return ret;
1017 }
1018
1019 static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
1020 {
1021         int i;
1022
1023         del_mtd_partitions(mtd);
1024
1025 #ifdef CONFIG_MTD_CONCAT
1026         if (mtd != sa[0].mtd)
1027                 mtd_concat_destroy(mtd);
1028 #endif
1029
1030         for (i = NR_SUBMTD; i >= 0; i--) {
1031                 if (sa[i].mtd)
1032                         map_destroy(sa[i].mtd);
1033                 if (sa[i].vbase)
1034                         iounmap(sa[i].vbase);
1035                 if (sa[i].res)
1036                         release_resource(sa[i].res);
1037         }
1038         kfree(sa[0].map);
1039 }
1040
1041 /*
1042  * A Thought: can we automatically detect the flash?
1043  *  - Check to see if the region is busy (yes -> failure)
1044  *  - Is the MSC setup for flash (no -> failure)
1045  *  - Probe for flash
1046  */
1047
1048 static struct map_info sa1100_probe_map __initdata = {
1049         .name           = "SA1100-flash",
1050 };
1051
1052 static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
1053 {
1054         struct mtd_info *mtd;
1055
1056         printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
1057                 phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
1058
1059         if (check_mem_region(phys, 0x08000000)) {
1060                 printk("busy\n");
1061                 return;
1062         }
1063
1064         if ((msc & 3) == 1) {
1065                 printk("wrong type\n");
1066                 return;
1067         }
1068
1069         sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
1070         sa1100_probe_map.size = SZ_1M;
1071         sa1100_probe_map.phys = phys;
1072         sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
1073         if (sa1100_probe_map.virt == 0)
1074                 goto fail;
1075         simple_map_init(&sa1100_probe_map);
1076
1077         /* Shame cfi_probe blurts out kernel messages... */
1078         mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
1079         if (mtd)
1080                 map_destroy(mtd);
1081         iounmap((void *)sa1100_probe_map.virt);
1082
1083         if (!mtd)
1084                 goto fail;
1085
1086         printk("pass\n");
1087         return;
1088
1089  fail:
1090         printk("failed\n");
1091 }
1092
1093 static void __init sa1100_probe_flash(void)
1094 {
1095         printk(KERN_INFO "-- SA11xx Flash probe.  Please report results.\n");
1096         sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
1097         sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
1098         sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
1099         sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
1100         sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
1101         sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
1102         printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
1103 }
1104
1105 static int __init sa1100_locate_flash(void)
1106 {
1107         int i, nr = -ENODEV;
1108
1109         sa1100_probe_flash();
1110
1111         if (machine_is_adsbitsy()) {
1112                 info[0].base = SA1100_CS1_PHYS;
1113                 info[0].size = SZ_32M;
1114                 nr = 1;
1115         }
1116         if (machine_is_assabet()) {
1117                 info[0].base = SA1100_CS0_PHYS;
1118                 info[0].size = SZ_32M;
1119                 info[1].base = SA1100_CS1_PHYS; /* neponset */
1120                 info[1].size = SZ_32M;
1121                 nr = 2;
1122         }
1123         if (machine_is_badge4()) {
1124                 info[0].base = SA1100_CS0_PHYS;
1125                 info[0].size = SZ_64M;
1126                 nr = 1;
1127         }
1128         if (machine_is_cerf()) {
1129                 info[0].base = SA1100_CS0_PHYS;
1130                 info[0].size = SZ_32M;
1131                 nr = 1;
1132         }
1133         if (machine_is_consus()) {
1134                 info[0].base = SA1100_CS0_PHYS;
1135                 info[0].size = SZ_32M;
1136                 nr = 1;
1137         }
1138         if (machine_is_flexanet()) {
1139                 info[0].base = SA1100_CS0_PHYS;
1140                 info[0].size = SZ_32M;
1141                 nr = 1;
1142         }
1143         if (machine_is_freebird()) {
1144                 info[0].base = SA1100_CS0_PHYS;
1145                 info[0].size = SZ_32M;
1146                 nr = 1;
1147         }
1148         if (machine_is_frodo()) {
1149                 info[0].base = SA1100_CS0_PHYS;
1150                 info[0].size = SZ_32M;
1151                 nr = 1;
1152         }
1153         if (machine_is_graphicsclient()) {
1154                 info[0].base = SA1100_CS1_PHYS;
1155                 info[0].size = SZ_32M;
1156                 nr = 1;
1157         }
1158         if (machine_is_graphicsmaster()) {
1159                 info[0].base = SA1100_CS1_PHYS;
1160                 info[0].size = SZ_16M;
1161                 nr = 1;
1162         }
1163         if (machine_is_h3xxx()) {
1164                 info[0].set_vpp = h3xxx_set_vpp;
1165                 info[0].base = SA1100_CS0_PHYS;
1166                 info[0].size = SZ_32M;
1167                 nr = 1;
1168         }
1169         if (machine_is_huw_webpanel()) {
1170                 info[0].base = SA1100_CS0_PHYS;
1171                 info[0].size = SZ_16M;
1172                 nr = 1;
1173         }
1174         if (machine_is_itsy()) {
1175                 info[0].base = SA1100_CS0_PHYS;
1176                 info[0].size = SZ_32M;
1177                 nr = 1;
1178         }
1179         if (machine_is_jornada720()) {
1180                 info[0].set_vpp = jornada720_set_vpp;
1181                 info[0].base = SA1100_CS0_PHYS;
1182                 info[0].size = SZ_32M;
1183                 nr = 1;
1184         }
1185         if (machine_is_nanoengine()) {
1186                 info[0].base = SA1100_CS0_PHYS;
1187                 info[1].size = SZ_32M;
1188                 nr = 1;
1189         }
1190         if (machine_is_pangolin()) {
1191                 info[0].base = SA1100_CS0_PHYS;
1192                 info[0].size = SZ_64M;
1193                 nr = 1;
1194         }
1195         if (machine_is_pfs168()) {
1196                 info[0].base = SA1100_CS0_PHYS;
1197                 info[0].size = SZ_32M;
1198                 nr = 1;
1199         }
1200         if (machine_is_pleb()) {
1201                 info[0].base = SA1100_CS0_PHYS;
1202                 info[0].size = SZ_4M;
1203                 info[1].base = SA1100_CS1_PHYS;
1204                 info[1].size = SZ_4M;
1205                 nr = 2;
1206         }
1207         if (machine_is_pt_system3()) {
1208                 info[0].base = SA1100_CS0_PHYS;
1209                 info[0].size = SZ_16M;
1210                 nr = 1;
1211         }
1212         if (machine_is_shannon()) {
1213                 info[0].base = SA1100_CS0_PHYS;
1214                 info[0].size = SZ_4M;
1215                 nr = 1;
1216         }
1217         if (machine_is_sherman()) {
1218                 info[0].base = SA1100_CS0_PHYS;
1219                 info[0].size = SZ_32M;
1220                 nr = 1;
1221         }
1222         if (machine_is_simpad()) {
1223                 info[0].base = SA1100_CS0_PHYS;
1224                 info[0].size = SZ_16M;
1225                 info[1].base = SA1100_CS1_PHYS;
1226                 info[1].size = SZ_16M;
1227                 nr = 2;
1228         }
1229         if (machine_is_stork()) {
1230                 info[0].base = SA1100_CS0_PHYS;
1231                 info[0].size = SZ_32M;
1232                 nr = 1;
1233         }
1234         if (machine_is_trizeps()) {
1235                 info[0].base = SA1100_CS0_PHYS;
1236                 info[0].size = SZ_16M;
1237                 nr = 1;
1238         }
1239         if (machine_is_victor()) {
1240                 info[0].base = SA1100_CS0_PHYS;
1241                 info[0].size = SZ_2M;
1242                 nr = 1;
1243         }
1244         if (machine_is_yopy()) {
1245                 info[0].base = SA1100_CS0_PHYS;
1246                 info[0].size = SZ_64M;
1247                 info[1].base = SA1100_CS1_PHYS;
1248                 info[1].size = SZ_64M;
1249                 nr = 2;
1250         }
1251
1252         if (nr < 0)
1253                 return nr;
1254
1255         /*
1256          * Retrieve the buswidth from the MSC registers.
1257          * We currently only implement CS0 and CS1 here.
1258          */
1259         for (i = 0; i < nr; i++) {
1260                 switch (info[i].base) {
1261                 default:
1262                         printk(KERN_WARNING "SA1100 flash: unknown base address "
1263                                 "0x%08lx, assuming CS0\n", info[i].base);
1264                 case SA1100_CS0_PHYS:
1265                         info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
1266                         break;
1267
1268                 case SA1100_CS1_PHYS:
1269                         info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
1270                         break;
1271                 }
1272         }
1273
1274         return nr;
1275 }
1276
1277 static struct mtd_partition *parsed_parts;
1278 const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
1279
1280 static void __init sa1100_locate_partitions(struct mtd_info *mtd)
1281 {
1282         const char *part_type = NULL;
1283         int nr_parts = 0;
1284
1285         do {
1286                 /*
1287                  * Partition selection stuff.
1288                  */
1289 #ifdef CONFIG_MTD_PARTITIONS
1290                 nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
1291                 if (nr_parts > 0) {
1292                         part_type = "dynamic";
1293                         break;
1294                 }
1295 #endif
1296 #ifdef CONFIG_MTD_SA1100_STATICMAP
1297                 nr_parts = sa1100_static_partitions(&parsed_parts);
1298                 if (nr_parts > 0) {
1299                         part_type = "static";
1300                         break;
1301                 }
1302 #endif
1303         } while (0);
1304
1305         if (nr_parts == 0) {
1306                 printk(KERN_NOTICE "SA1100 flash: no partition info "
1307                         "available, registering whole flash\n");
1308                 add_mtd_device(mtd);
1309         } else {
1310                 printk(KERN_NOTICE "SA1100 flash: using %s partition "
1311                         "definition\n", part_type);
1312                 add_mtd_partitions(mtd, parsed_parts, nr_parts);
1313         }
1314
1315         /* Always succeeds. */
1316 }
1317
1318 static void __exit sa1100_destroy_partitions(void)
1319 {
1320         if (parsed_parts)
1321                 kfree(parsed_parts);
1322 }
1323
1324 static struct mtd_info *mymtd;
1325
1326 static int __init sa1100_mtd_init(void)
1327 {
1328         int ret;
1329         int nr;
1330
1331         nr = sa1100_locate_flash();
1332         if (nr < 0)
1333                 return nr;
1334
1335         ret = sa1100_setup_mtd(info, nr, &mymtd);
1336         if (ret == 0)
1337                 sa1100_locate_partitions(mymtd);
1338
1339         return ret;
1340 }
1341
1342 static void __exit sa1100_mtd_cleanup(void)
1343 {
1344         sa1100_destroy_mtd(info, mymtd);
1345         sa1100_destroy_partitions();
1346 }
1347
1348 module_init(sa1100_mtd_init);
1349 module_exit(sa1100_mtd_cleanup);
1350
1351 MODULE_AUTHOR("Nicolas Pitre");
1352 MODULE_DESCRIPTION("SA1100 CFI map driver");
1353 MODULE_LICENSE("GPL");