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