55bfe32372810acb8cd8c5bc265268c9e45f826d
[oweals/openwrt.git] / target / linux / amazon / files / drivers / mtd / maps / amazon.c
1 /*
2  * Handle mapping of the flash memory access routines
3  * on Amazon  based devices.
4  *
5  * Copyright(C) 2004 peng.liu@infineon.com
6  *
7  * This code is GPLed
8  *
9  */
10 // 000005:fchang 2005/6/2 Modified by Bingtao to double check if the EBU is enabled/disabled
11 // 506231:tc.chen 2005/06/23 increase firmware partition size form 192KB to 256KB
12 // 050701:linmars 2005/07/01 fix flash size wrong alignment after increase firmware partition
13 // 165001:henryhsu 2005/8/18 Remove the support for Intel flash because of 2.1 not enough rootfs partition size
14 // 165001:henryhsu 2005/9/7 Rolback to support INtel flash
15 // 509071:tc.chen 2005/09/07 Reduced flash writing time
16 // 511046:linmars 2005/11/04 change bootloader size from 128 into 64
17 // 511241:linmars 2005/11/24 merge TaiChen's IRM patch 
18
19 // copyright 2005 infineon
20
21 // copyright 2007 john crispin <blogic@openwrt.org>
22 // copyright 2007 felix fietkau <nbd@openwrt.org>
23 // copyright 2009 hauke mehrtens <hauke@hauke-m.de>
24
25 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/kernel.h>
28 #include <asm/io.h>
29
30 #include <linux/init.h>
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/map.h>
33 #include <linux/mtd/partitions.h>
34 #include <linux/mtd/cfi.h>
35 #include <linux/mutex.h>
36 #include <linux/platform_device.h>
37 #include <asm/amazon/amazon.h>
38
39 #define AMAZON_PCI_ARB_CTL_ALT 0xb100205c
40 #define AMAZON_MTD_REG32( addr )          (*(volatile u32 *)(addr))
41
42
43 static struct map_info amazon_map = {
44         .name = "AMAZON_FLASH",
45         .bankwidth = 2,
46 };
47
48 static map_word amazon_read16(struct map_info * map, unsigned long ofs)
49 {
50         map_word temp;
51         ofs ^= 2;
52         temp.x[0] = *((__u16 *) (map->virt + ofs));
53         return temp;
54 }
55
56 static void amazon_write16(struct map_info *map, map_word d, unsigned long adr)
57 {
58         adr ^= 2;
59         *((__u16 *) (map->virt + adr)) = d.x[0];
60 }
61
62 void amazon_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
63 {
64         u8 *p;
65         u8 *to_8;
66         from = (unsigned long) (from + map->virt);
67         p = (u8 *) from;
68         to_8 = (u8 *) to;
69         while(len--){
70                 *to_8++ = *p++;
71         }
72 }
73
74 void amazon_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
75 {
76         u8 *p =  (u8*) from;
77         u8 *to_8;
78         to += (unsigned long) map->virt;
79         to_8 = (u8*)to;
80         while(len--){
81                 *p++ = *to_8++;
82         }
83 }
84
85 #define UBOOT_SIZE              0x40000
86
87 static struct mtd_partition     amazon_partitions[3] = {
88          {
89                   name:"U-Boot",                /* U-Boot firmware */
90                   offset:0x00000000,
91                   size:UBOOT_SIZE ,             /* 128k */
92           },
93          {
94                   name:"kernel",                /* firmware */
95                   offset:UBOOT_SIZE,
96                   size:0x00100000,              /* 192K */
97           },
98          {
99                   name:"rootfs",                /* default partition */
100                   offset:0x00200000,
101                   size:0x00200000,
102           },
103 };
104
105 unsigned long uImage_size = 0x10000d;
106
107 int find_uImage_size(unsigned long start_offset)
108 {
109         unsigned long magic;
110         unsigned long temp;
111         amazon_copy_from(&amazon_map, &magic, start_offset, 4);
112         if (!(ntohl(magic) == 0x27051956)) {
113                 printk(KERN_INFO "amazon_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", ntohl(magic), start_offset);
114                 return 0;
115         }
116         amazon_copy_from(&amazon_map, &temp, start_offset + 12, 4);
117         printk(KERN_INFO "amazon_mtd: kernel size is %ld \n", temp + 0x40);
118         return temp + 0x40;
119 }
120
121 static int __init amazon_mtd_probe(struct platform_device *dev)
122 {
123         unsigned long uimage_size;
124         struct mtd_info *mymtd = NULL;
125         struct mtd_partition *parts = NULL;
126
127         *AMAZON_EBU_BUSCON0 = 0x1d7ff;
128         
129         amazon_map.read = amazon_read16;
130         amazon_map.write = amazon_write16;
131         amazon_map.copy_from = amazon_copy_from;
132         amazon_map.copy_to = amazon_copy_to;
133
134         amazon_map.phys = dev->resource->start;
135         amazon_map.size = dev->resource->end - amazon_map.phys + 1;
136         amazon_map.virt = ioremap_nocache(amazon_map.phys, amazon_map.size);
137         
138         if (!amazon_map.virt) {
139                 printk(KERN_WARNING "amazon_mtd: Failed to ioremap!\n");
140                 return -EIO;
141         }
142         
143         mymtd = (struct mtd_info *) do_map_probe("cfi_probe", &amazon_map);
144         if (!mymtd) {
145                 iounmap(amazon_map.virt);
146                 printk(KERN_WARNING "amazon_mtd: probing failed\n");
147                 return -ENXIO;
148         }
149
150         mymtd->owner = THIS_MODULE;
151         parts = &amazon_partitions[0];
152
153         /* Some Samsung devices are containing a 16 MB flash chip with a bigger U-Boot partition. */
154         if(mymtd->size == 0x01000000 && mymtd->erasesize == 0x00020000) {
155                 printk(KERN_INFO "amazon_mtd: Found big flash chip!\n");
156                 amazon_partitions[0].size = 0x60000;
157                 amazon_partitions[1].offset = 0x60000;
158                 uimage_size = find_uImage_size(amazon_partitions[1].offset);
159                 amazon_partitions[1].size = uimage_size;
160                 amazon_partitions[2].offset = 0x60000 + uimage_size;
161                 amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - mymtd->erasesize;
162         } else {
163                 printk(KERN_INFO "amazon_mtd: Found small flash chip!\n");
164                 uimage_size = find_uImage_size(amazon_partitions[1].offset);
165                 amazon_partitions[1].size = uimage_size;
166                 amazon_partitions[2].offset = UBOOT_SIZE + uimage_size;
167                 amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - (2 * mymtd->erasesize);
168         }
169
170         add_mtd_partitions(mymtd, parts, 3);
171
172         printk(KERN_INFO "amazon_mtd: added %s flash with %dMB\n",
173                 amazon_map.name, ((int)mymtd->size) >> 20);
174         return 0;
175 }
176
177 static struct platform_driver amazon_mtd_driver = {
178         .probe = amazon_mtd_probe,
179         .driver = {
180                 .name = "amazon_mtd",
181                 .owner = THIS_MODULE,
182         },
183 };
184
185 static int __init amazon_mtd_init(void)
186 {
187         int ret = platform_driver_register(&amazon_mtd_driver);
188         if (ret)
189                 printk(KERN_WARNING "amazon_mtd: error registering platfom driver!\n");
190         return ret;
191 }
192
193 static void __exit amazon_mtd_cleanup(void)
194 {
195         platform_driver_unregister(&amazon_mtd_driver);
196 }
197
198 module_init(amazon_mtd_init);
199 module_exit(amazon_mtd_cleanup);
200
201 MODULE_LICENSE("GPL");
202 MODULE_AUTHOR("john crispin blogic@openwrt.org");
203 MODULE_DESCRIPTION("MTD map driver for AMAZON boards");
204