[rdc] rework board detection
[openwrt/svn-archive/archive.git] / target / linux / rdc / files-2.6.30 / arch / x86 / mach-rdc321x / boards / ar525w.c
1 /*
2 * ar525w RDC321x platform devices
3 *
4 * Copyright (C) 2007-2009 OpenWrt.org
5 * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
6 * Copyright (C) 2008-2009 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25 #include <linux/init.h>
26 #include <linux/mtd/physmap.h>
27 #include <linux/input.h>
28 #include <linux/vmalloc.h>
29 #include <linux/mtd/mtd.h>
30
31 #include <asm/rdc_boards.h>
32
33 struct image_header {
34 char magic[4]; /* ASICII: GMTK */
35 u32 checksum; /* CRC32 */
36 u32 version; /* x.x.x.x */
37 u32 kernelsz; /* The size of the kernel image */
38 u32 imagesz; /* The length of this image file ( kernel + romfs + this header) */
39 u32 pid; /* Product ID */
40 u32 fastcksum; /* Partial CRC32 on (First(256), medium(256), last(512)) */
41 u32 reserved;
42 };
43
44 static struct gpio_led ar525w_leds[] = {
45 { .name = "rdc321x:dmz", .gpio = 1, .active_low = 1},
46 };
47 static struct gpio_button ar525w_btns[] = {
48 {
49 .gpio = 6,
50 .code = BTN_0,
51 .desc = "Reset",
52 .active_low = 1,
53 }
54 };
55
56 static u32 __initdata crctab[257] = {
57 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
58 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
59 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
60 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
61 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
62 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
63 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
64 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
65 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
66 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
67 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
68 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
69 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
70 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
71 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
72 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
73 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
74 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
75 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
76 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
77 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
78 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
79 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
80 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
81 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
82 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
83 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
84 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
85 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
86 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
87 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
88 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
89 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
90 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
91 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
92 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
93 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
94 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
95 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
96 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
97 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
98 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
99 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
100 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
101 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
102 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
103 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
104 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
105 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
106 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
107 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
108 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
109 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
110 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
111 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
112 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
113 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
114 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
115 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
116 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
117 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
118 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
119 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
120 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
121 0
122 };
123
124 static u32 __init crc32(u8 * buf, u32 len)
125 {
126 register int i;
127 u32 sum;
128 register u32 s0;
129 s0 = ~0;
130 for (i = 0; i < len; i++) {
131 s0 = (s0 >> 8) ^ crctab[(u8) (s0 & 0xFF) ^ buf[i]];
132 }
133 sum = ~s0;
134 return sum;
135 }
136
137 static int __init fixup_ar525w_header(struct mtd_info *master, struct image_header *header)
138 {
139 char *buffer;
140 int res;
141 u32 bufferlength = header->kernelsz + sizeof(struct image_header);
142 u32 len;
143 char crcbuf[0x400];
144
145 printk(KERN_INFO "Fixing up AR525W header, old image size: %u, new image size: %u\n",
146 header->imagesz, bufferlength);
147
148 buffer = vmalloc(bufferlength);
149 if (!buffer) {
150 printk(KERN_ERR "Can't allocate %u bytes\n", bufferlength);
151 return -ENOMEM;
152 }
153
154 res = master->read(master, 0x0, bufferlength, &len, buffer);
155 if (res || len != bufferlength)
156 goto out;
157
158 header = (struct image_header *) buffer;
159 header->imagesz = bufferlength;
160 header->checksum = 0;
161 header->fastcksum = 0;
162
163 memcpy(crcbuf, buffer, 0x100);
164 memcpy(crcbuf + 0x100, buffer + (bufferlength >> 1) - ((bufferlength & 0x6) >> 1), 0x100);
165 memcpy(crcbuf + 0x200, buffer + bufferlength - 0x200, 0x200);
166
167 header->fastcksum = crc32(crcbuf, sizeof(crcbuf));
168 header->checksum = crc32(buffer, bufferlength);
169
170 if (master->unlock)
171 master->unlock(master, 0, master->erasesize);
172 res = erase_write (master, 0, master->erasesize, buffer);
173 if (res)
174 printk(KERN_ERR "Can't rewrite image header\n");
175
176 out:
177 vfree(buffer);
178 return res;
179 }
180
181 static int __init parse_ar525w_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long plat_data)
182 {
183 struct image_header header;
184 int res;
185 size_t len;
186 struct mtd_partition *rdc_flash_parts;
187 struct rdc_platform_data *pdata = (struct rdc_platform_data *) plat_data;
188
189 if (master->size != 0x400000) //4MB
190 return -ENOSYS;
191
192 res = master->read(master, 0x0, sizeof(header), &len, (char *)&header);
193 if (res)
194 return res;
195
196 if (strncmp(header.magic, "GMTK", 4))
197 return -ENOSYS;
198
199 if (header.kernelsz > 0x400000 || header.kernelsz < master->erasesize) {
200 printk(KERN_ERR "AR525W image header found, but seems corrupt, kernel size %u\n", header.kernelsz);
201 return -EINVAL;
202 }
203
204 if (header.kernelsz + sizeof(header) != header.imagesz) {
205 res = fixup_ar525w_header(master, &header);
206 if (res)
207 return res;
208 }
209
210 rdc_flash_parts = kzalloc(sizeof(struct mtd_partition) * 3, GFP_KERNEL);
211
212 rdc_flash_parts[0].name = "firmware";
213 rdc_flash_parts[0].offset = 0x0;
214 rdc_flash_parts[0].size = 0x3E0000;
215 rdc_flash_parts[1].name = "rootfs";
216 rdc_flash_parts[1].offset = header.kernelsz + sizeof(header);
217 rdc_flash_parts[1].size = rdc_flash_parts[0].size - rdc_flash_parts[1].offset;
218 rdc_flash_parts[2].name = "bootloader";
219 rdc_flash_parts[2].offset = 0x3E0000;
220 rdc_flash_parts[2].size = 0x20000;
221
222 *pparts = rdc_flash_parts;
223
224 pdata->led_data.num_leds = ARRAY_SIZE(ar525w_leds);
225 pdata->led_data.leds = ar525w_leds;
226 pdata->button_data.nbuttons = ARRAY_SIZE(ar525w_btns);
227 pdata->button_data.buttons = ar525w_btns;
228
229 return 3;
230 }
231
232 static struct mtd_part_parser __initdata ar525w_parser = {
233 .owner = THIS_MODULE,
234 .parse_fn = parse_ar525w_partitions,
235 .name = "AR525W",
236 };
237
238 static int __init ar525w_setup(void)
239 {
240 return register_mtd_parser(&ar525w_parser);
241 }
242
243 arch_initcall(ar525w_setup);