[rdc] move files-2.6.28 to files
[openwrt/svn-archive/archive.git] / target / linux / rdc / files / drivers / mtd / maps / rdc3210.c
1 /*******************************************************************
2 * Simple Flash mapping for RDC3210 *
3 * *
4 * 2005.03.23 *
5 * Dante Su (dante_su@gemtek.com.tw) *
6 * Copyright (C) 2005 Gemtek Corporation *
7 *******************************************************************/
8
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <asm/io.h>
13 #include <linux/mtd/mtd.h>
14 #include <linux/mtd/map.h>
15 #include <linux/mtd/partitions.h>
16 #include <linux/autoconf.h>
17 #include <linux/sched.h>
18
19 #define SQUASHFS_MAGIC 0x73717368
20
21 static struct mtd_info *rdc3210_mtd;
22
23 struct map_info rdc3210_map =
24 {
25 .name = "RDC3210 Flash",
26 .size = CONFIG_MTD_RDC3210_SIZE,
27 .bankwidth = CONFIG_MTD_RDC3210_BUSWIDTH,
28 };
29
30 /* Dante: This is the default static mapping, however this is nothing but a hint. (Say dynamic mapping) */
31 static struct mtd_partition rdc3210_parts[] =
32 {
33 #if CONFIG_MTD_RDC3210_SIZE == 0x400000
34 { name: "linux", offset: 0, size: 0x003C0000 }, /* 3840 KB = (Kernel + ROMFS) = (768 KB + 3072 KB) */
35 { name: "romfs", offset: 0x000C0000, size: 0x00300000 }, /* 3072 KB */
36 { name: "nvram", offset: 0x003C0000, size: 0x00010000 }, /* 64 KB */
37 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
38 { name: "factory", offset: 0x003D0000, size: 0x00010000 }, /* 64 KB */
39 #endif
40 { name: "bootldr", offset: 0x003E0000, size: 0x00020000 }, /* 128 KB */
41 #elif CONFIG_MTD_RDC3210_SIZE == 0x200000
42 { name: "linux", offset: 0x00008000, size: 0x001E8000 },
43 { name: "romfs", offset: 0x000C8000, size: 0x00128000 },
44 { name: "nvram", offset: 0x00000000, size: 0x00008000 }, /* 64 KB */
45 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
46 #error Unsupported configuration!
47 #endif
48 { name: "bootldr", offset: 0x001F0000, size: 0x00010000 },
49
50 #elif CONFIG_MTD_RDC3210_SIZE == 0x800000
51 { name: "linux", offset: 0, size: 0x001F0000 }, /* 1984 KB */
52 { name: "config", offset: 0x001F0000, size: 0x00010000 }, /* 64 KB */
53 { name: "romfs", offset: 0x00200000, size: 0x005D0000 }, /* 5952 KB */
54 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
55 { name: "factory", offset: 0x007D0000, size: 0x00010000 }, /* 64 KB */
56 #endif
57 { name: "bootldr", offset: 0x007E0000, size: 0x00010000 }, /* 64 KB */
58 #else
59 #error Unsupported configuration!
60 #endif
61 };
62
63 static __u32 crctab[257] = {
64 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
65 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
66 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
67 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
68 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
69 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
70 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
71 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
72 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
73 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
74 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
75 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
76 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
77 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
78 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
79 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
80 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
81 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
82 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
83 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
84 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
85 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
86 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
87 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
88 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
89 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
90 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
91 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
92 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
93 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
94 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
95 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
96 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
97 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
98 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
99 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
100 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
101 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
102 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
103 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
104 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
105 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
106 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
107 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
108 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
109 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
110 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
111 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
112 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
113 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
114 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
115 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
116 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
117 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
118 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
119 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
120 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
121 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
122 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
123 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
124 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
125 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
126 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
127 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
128 0
129 };
130
131 static __u32 crc32(__u8 * buf, __u32 len)
132 {
133 register int i;
134 __u32 sum;
135 register __u32 s0;
136 s0 = ~0;
137 for (i = 0; i < len; i++) {
138 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
139 }
140 sum = ~s0;
141 return sum;
142 }
143
144 static void erase_callback(struct erase_info *done)
145 {
146 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
147 wake_up(wait_q);
148 }
149
150 static int erase_write (struct mtd_info *mtd, unsigned long pos,
151 int len, const char *buf)
152 {
153 struct erase_info erase;
154 DECLARE_WAITQUEUE(wait, current);
155 wait_queue_head_t wait_q;
156 size_t retlen;
157 int ret;
158
159 /*
160 * First, let's erase the flash block.
161 */
162
163 init_waitqueue_head(&wait_q);
164 erase.mtd = mtd;
165 erase.callback = erase_callback;
166 erase.addr = pos;
167 erase.len = len;
168 erase.priv = (u_long)&wait_q;
169
170 set_current_state(TASK_INTERRUPTIBLE);
171 add_wait_queue(&wait_q, &wait);
172
173 ret = mtd->erase(mtd, &erase);
174 if (ret) {
175 set_current_state(TASK_RUNNING);
176 remove_wait_queue(&wait_q, &wait);
177 printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
178 "on \"%s\" failed\n",
179 pos, len, mtd->name);
180 return ret;
181 }
182
183 schedule(); /* Wait for erase to finish. */
184 remove_wait_queue(&wait_q, &wait);
185
186 /*
187 * Next, writhe data to flash.
188 */
189
190 ret = mtd->write (mtd, pos, len, &retlen, buf);
191 if (ret)
192 return ret;
193 if (retlen != len)
194 return -EIO;
195 return 0;
196 }
197
198 static int __init init_rdc3210_map(void)
199 {
200 rdc3210_map.phys = -rdc3210_map.size;
201 printk(KERN_NOTICE "flash device: %lx at %x\n", rdc3210_map.size, rdc3210_map.phys);
202
203 #if CONFIG_MTD_RDC3210_SIZE == 0x800000
204 simple_map_init(&rdc3210_map);
205 #endif
206
207 rdc3210_map.map_priv_1 = (unsigned long)(rdc3210_map.virt = ioremap_nocache(rdc3210_map.phys, rdc3210_map.size));
208
209 if (!rdc3210_map.map_priv_1)
210 {
211 printk("Failed to ioremap\n");
212 return -EIO;
213 }
214 rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
215 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP /* Dante: This is for fixed map */
216 if (rdc3210_mtd)
217 {
218 rdc3210_mtd->owner = THIS_MODULE;
219 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
220 return 0;
221 }
222 #else /* Dante: This is for dynamic mapping */
223
224 #include "imghdr.h"
225
226 typedef struct {
227 u8 magic[4];
228 u32 kernelsz, ramdisksz;
229 u8 magic2[4];
230 u32 sz2;
231 }sc_imghdr_t;
232
233 if (rdc3210_mtd)
234 { // Dante
235 sc_imghdr_t *hdr2= (sc_imghdr_t *)(rdc3210_map.map_priv_1);
236 gt_imghdr_t *hdr = (gt_imghdr_t *)hdr2
237 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
238 , *ptmp
239 #endif
240 ;
241 int len, tmp, tmp2, tmp3, tmp4, hdr_type = 0;
242
243 if(!memcmp(hdr->magic, GTIMG_MAGIC, 4))
244 {
245 hdr_type = 1;
246 tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
247 tmp2 = rdc3210_mtd->erasesize;
248 tmp3 = ((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32;
249 tmp4 = ((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2;
250 }
251 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
252 else if (!memcmp(hdr2->magic, "CSYS", 4))
253 {
254 hdr_type = 2;
255 tmp = hdr2->ramdisksz + hdr2->kernelsz + sizeof(sc_imghdr_t);
256 tmp2 = rdc3210_mtd->erasesize;
257 tmp3 = ((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32;
258 tmp4 = ((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2;
259 }
260 #endif
261 else
262 {
263 iounmap((void *)rdc3210_map.map_priv_1);
264 rdc3210_map.map_priv_1 = 0L;
265 rdc3210_map.virt = NULL;
266 printk("Invalid MAGIC for Firmware Image!!!\n");
267 return -EIO;
268 }
269 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
270 tmp = (tmp3 == tmp4) ? tmp4 + tmp2 : tmp4;
271 if ((ptmp = (gt_imghdr_t *)vmalloc(tmp)) == NULL)
272 {
273 iounmap((void *)rdc3210_map.map_priv_1);
274 rdc3210_map.map_priv_1 = 0L;
275 rdc3210_map.virt = NULL;
276 printk("Can't allocate 0x%08x for flash-reading buffer!\n", tmp);
277 return -ENOMEM;
278 }
279 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp, &len, (__u8 *)ptmp) || len != tmp)
280 {
281 vfree(ptmp);
282 iounmap((void *)rdc3210_map.map_priv_1);
283 rdc3210_map.map_priv_1 = 0L;
284 rdc3210_map.virt = NULL;
285 printk("Can't read that much flash! Read 0x%08x of it.\n", len);
286 return -EIO;
287 }
288 #endif
289 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
290 /* 1. Adjust Redboot */
291 tmp = rdc3210_mtd->size - rdc3210_parts[4].size;
292 rdc3210_parts[4].offset = tmp - (tmp % tmp2);
293 rdc3210_parts[4].size = rdc3210_mtd->size - rdc3210_parts[4].offset;
294
295 /* 2. Adjust Factory Default */
296 tmp -= rdc3210_parts[3].size;
297 rdc3210_parts[3].offset = tmp - (tmp % tmp2);
298 rdc3210_parts[3].size = rdc3210_parts[4].offset - rdc3210_parts[3].offset;
299 #else
300 /* 1. Adjust Redboot */
301 tmp = rdc3210_mtd->size - rdc3210_parts[3].size;
302 rdc3210_parts[3].offset = tmp - (tmp % tmp2);
303 rdc3210_parts[3].size = rdc3210_mtd->size - rdc3210_parts[3].offset;
304 #endif
305 if (hdr_type == 1) {
306 /* 3. Adjust NVRAM */
307 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
308 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
309 {
310 len = 1;
311 tmp4 = tmp3;
312 tmp = hdr->imagesz;
313 rdc3210_parts[2].name = "rootfs_data";
314 rdc3210_parts[2].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
315 }
316 else
317 #else
318 tmp4 = tmp3;
319 #endif
320 {
321 len = 0;
322 tmp -= rdc3210_parts[2].size;
323 rdc3210_parts[2].offset = tmp - (tmp % tmp2);
324 }
325 rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
326 }
327 else if (hdr_type == 2)
328 {
329 len = 0;
330 tmp4 = tmp3;
331 }
332
333 /* 4. Adjust Linux (Kernel + ROMFS) */
334 rdc3210_parts[0].size = rdc3210_parts[len + hdr_type + 1].offset - rdc3210_parts[0].offset;
335
336 /* 5. Adjust ROMFS */
337 rdc3210_parts[1].offset = rdc3210_parts[0].offset + tmp4;
338 rdc3210_parts[1].size = rdc3210_parts[hdr_type + 1].offset - rdc3210_parts[1].offset;
339 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
340 if (!(hdr->reserved || len))
341 {
342 __u8 buf[1024];
343 ptmp->reserved = hdr->imagesz;
344 ptmp->imagesz = tmp4;
345 ptmp->checksum = ptmp->fastcksum = 0;
346 memcpy(buf, ptmp, 0x100);
347 memcpy(buf + 0x100, ((__u8 *)ptmp) + ((tmp4 >> 1) - ((tmp4 & 0x6) >> 1)), 0x100);
348 memcpy(buf + 0x200, ((__u8 *)ptmp) + (tmp4 - 0x200), 0x200);
349 ptmp->fastcksum = crc32(buf, sizeof(buf));
350 ptmp->checksum = crc32((__u8 *)ptmp, tmp4);
351 if (rdc3210_mtd->unlock) rdc3210_mtd->unlock(rdc3210_mtd, 0, tmp2);
352 if ((len = erase_write(rdc3210_mtd, 0, tmp2, (char *)ptmp)))
353 {
354 vfree(ptmp);
355 iounmap((void *)rdc3210_map.map_priv_1);
356 rdc3210_map.map_priv_1 = 0L;
357 rdc3210_map.virt = NULL;
358 printk("Couldn't erase! Got %d.\n", len);
359 return len;
360 }
361 if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
362 }
363 vfree(ptmp);
364 #endif
365 rdc3210_mtd->owner = THIS_MODULE;
366 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
367 return 0;
368 }
369 #endif
370 iounmap((void *)rdc3210_map.map_priv_1);
371 rdc3210_map.map_priv_1 = 0L;
372 rdc3210_map.virt = NULL;
373 return -ENXIO;
374 }
375
376 static void __exit cleanup_rdc3210_map(void)
377 {
378 if (rdc3210_mtd)
379 {
380 del_mtd_partitions(rdc3210_mtd);
381 map_destroy(rdc3210_mtd);
382 }
383
384 if (rdc3210_map.map_priv_1)
385 {
386 iounmap((void *)rdc3210_map.map_priv_1);
387 rdc3210_map.map_priv_1 = 0L;
388 rdc3210_map.virt = NULL;
389 }
390 }
391
392 module_init(init_rdc3210_map);
393 module_exit(cleanup_rdc3210_map);