1 /*******************************************************************
2 * Simple Flash mapping for RDC3210 *
5 * Dante Su (dante_su@gemtek.com.tw) *
6 * Copyright (C) 2005 Gemtek Corporation *
7 *******************************************************************/
9 #include <linux/module.h>
10 #include <linux/types.h>
11 #include <linux/kernel.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>
20 static struct mtd_info *rdc3210_mtd;
22 struct map_info rdc3210_map =
24 .name = "RDC3210 Flash",
25 .size = CONFIG_MTD_RDC3210_SIZE,
26 .bankwidth = CONFIG_MTD_RDC3210_BUSWIDTH,
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[] =
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 */
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!
47 { name: "bootldr", offset: 0x001F0000, size: 0x00010000 },
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 */
56 { name: "bootldr", offset: 0x007E0000, size: 0x00010000 }, /* 64 KB */
58 #error Unsupported configuration!
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,
130 static __u32 crc32(__u8 * buf, __u32 len)
136 for (i = 0; i < len; i++) {
137 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
143 static void erase_callback(struct erase_info *done)
145 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
149 static int erase_write (struct mtd_info *mtd, unsigned long pos,
150 int len, const char *buf)
152 struct erase_info erase;
153 DECLARE_WAITQUEUE(wait, current);
154 wait_queue_head_t wait_q;
159 * First, let's erase the flash block.
162 init_waitqueue_head(&wait_q);
164 erase.callback = erase_callback;
167 erase.priv = (u_long)&wait_q;
169 set_current_state(TASK_INTERRUPTIBLE);
170 add_wait_queue(&wait_q, &wait);
172 ret = mtd->erase(mtd, &erase);
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);
182 schedule(); /* Wait for erase to finish. */
183 remove_wait_queue(&wait_q, &wait);
186 * Next, writhe data to flash.
189 ret = mtd->write (mtd, pos, len, &retlen, buf);
197 static int __init init_rdc3210_map(void)
199 rdc3210_map.phys = -rdc3210_map.size;
200 printk(KERN_NOTICE "flash device: %x at %x\n", rdc3210_map.size, rdc3210_map.phys);
202 #if CONFIG_MTD_RDC3210_SIZE == 0x800000
203 simple_map_init(&rdc3210_map);
206 rdc3210_map.map_priv_1 = (unsigned long)(rdc3210_map.virt = ioremap_nocache(rdc3210_map.phys, rdc3210_map.size));
208 if (!rdc3210_map.map_priv_1)
210 printk("Failed to ioremap\n");
213 rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
214 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP /* Dante: This is for fixed map */
217 rdc3210_mtd->owner = THIS_MODULE;
218 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
221 #else /* Dante: This is for dynamic mapping */
227 u32 kernelsz, ramdisksz;
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
240 int len, tmp, tmp2, tmp3, tmp4, hdr_type = 0;
242 if(!memcmp(hdr->magic, GTIMG_MAGIC, 4))
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;
250 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
251 else if (!memcmp(hdr2->magic, "CSYS", 4))
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;
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");
268 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
269 tmp = (tmp3 == tmp4) ? tmp4 + tmp2 : tmp4;
270 if ((ptmp = (gt_imghdr_t *)vmalloc(tmp)) == NULL)
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);
278 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp, &len, (__u8 *)ptmp) || len != tmp)
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);
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;
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;
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;
305 /* 3. Adjust NVRAM */
306 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
307 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
312 rdc3210_parts[2].name = "rootfs_data";
313 rdc3210_parts[2].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
321 tmp -= rdc3210_parts[2].size;
322 rdc3210_parts[2].offset = tmp - (tmp % tmp2);
324 rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
326 else if (hdr_type == 2)
332 /* 4. Adjust Linux (Kernel + ROMFS) */
333 rdc3210_parts[0].size = rdc3210_parts[len + hdr_type + 1].offset - rdc3210_parts[0].offset;
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))
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)))
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);
360 if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
364 rdc3210_mtd->owner = THIS_MODULE;
365 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
369 iounmap((void *)rdc3210_map.map_priv_1);
370 rdc3210_map.map_priv_1 = 0L;
371 rdc3210_map.virt = NULL;
375 static void __exit cleanup_rdc3210_map(void)
379 del_mtd_partitions(rdc3210_mtd);
380 map_destroy(rdc3210_mtd);
383 if (rdc3210_map.map_priv_1)
385 iounmap((void *)rdc3210_map.map_priv_1);
386 rdc3210_map.map_priv_1 = 0L;
387 rdc3210_map.virt = NULL;
391 module_init(init_rdc3210_map);
392 module_exit(cleanup_rdc3210_map);