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>
19 #define SQUASHFS_MAGIC 0x73717368
21 static struct mtd_info
*rdc3210_mtd
;
23 struct map_info rdc3210_map
=
25 .name
= "RDC3210 Flash",
26 .size
= CONFIG_MTD_RDC3210_SIZE
,
27 .bankwidth
= CONFIG_MTD_RDC3210_BUSWIDTH
,
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
[] =
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 */
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!
48 { name
: "bootldr", offset
: 0x001F0000, size
: 0x00010000 },
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 */
57 { name
: "bootldr", offset
: 0x007E0000, size
: 0x00010000 }, /* 64 KB */
59 #error Unsupported configuration!
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,
131 static __u32
crc32(__u8
* buf
, __u32 len
)
137 for (i
= 0; i
< len
; i
++) {
138 s0
= (s0
>> 8) ^ crctab
[(__u8
) (s0
& 0xFF) ^ buf
[i
]];
144 static void erase_callback(struct erase_info
*done
)
146 wait_queue_head_t
*wait_q
= (wait_queue_head_t
*)done
->priv
;
150 static int erase_write (struct mtd_info
*mtd
, unsigned long pos
,
151 int len
, const char *buf
)
153 struct erase_info erase
;
154 DECLARE_WAITQUEUE(wait
, current
);
155 wait_queue_head_t wait_q
;
160 * First, let's erase the flash block.
163 init_waitqueue_head(&wait_q
);
165 erase
.callback
= erase_callback
;
168 erase
.priv
= (u_long
)&wait_q
;
170 set_current_state(TASK_INTERRUPTIBLE
);
171 add_wait_queue(&wait_q
, &wait
);
173 ret
= mtd
->erase(mtd
, &erase
);
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
);
183 schedule(); /* Wait for erase to finish. */
184 remove_wait_queue(&wait_q
, &wait
);
187 * Next, writhe data to flash.
190 ret
= mtd
->write (mtd
, pos
, len
, &retlen
, buf
);
198 static int __init
init_rdc3210_map(void)
200 rdc3210_map
.phys
= -rdc3210_map
.size
;
201 printk(KERN_NOTICE
"flash device: %lx at %x\n", rdc3210_map
.size
, rdc3210_map
.phys
);
203 #if CONFIG_MTD_RDC3210_SIZE == 0x800000
204 simple_map_init(&rdc3210_map
);
207 rdc3210_map
.map_priv_1
= (unsigned long)(rdc3210_map
.virt
= ioremap_nocache(rdc3210_map
.phys
, rdc3210_map
.size
));
209 if (!rdc3210_map
.map_priv_1
)
211 printk("Failed to ioremap\n");
214 rdc3210_mtd
= do_map_probe("cfi_probe", &rdc3210_map
);
215 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP /* Dante: This is for fixed map */
218 rdc3210_mtd
->owner
= THIS_MODULE
;
219 add_mtd_partitions(rdc3210_mtd
, rdc3210_parts
, sizeof(rdc3210_parts
)/sizeof(rdc3210_parts
[0]));
222 #else /* Dante: This is for dynamic mapping */
228 u32 kernelsz
, ramdisksz
;
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
241 int len
, tmp
, tmp2
, tmp3
, tmp4
, hdr_type
= 0;
243 if(!memcmp(hdr
->magic
, GTIMG_MAGIC
, 4))
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
;
251 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
252 else if (!memcmp(hdr2
->magic
, "CSYS", 4))
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
;
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");
269 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
270 tmp
= (tmp3
== tmp4
) ? tmp4
+ tmp2
: tmp4
;
271 if ((ptmp
= (gt_imghdr_t
*)vmalloc(tmp
)) == NULL
)
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
);
279 if (rdc3210_mtd
->read(rdc3210_mtd
, 0, tmp
, &len
, (__u8
*)ptmp
) || len
!= tmp
)
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
);
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
;
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
;
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
;
306 /* 3. Adjust NVRAM */
307 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
308 if (*(__u32
*)(((unsigned char *)ptmp
)+tmp3
) == SQUASHFS_MAGIC
)
313 rdc3210_parts
[2].name
= "rootfs_data";
314 rdc3210_parts
[2].offset
= rdc3210_parts
[0].offset
+ (((tmp
/ tmp2
) + ((tmp
% tmp2
) ? 1 : 0)) * tmp2
);
322 tmp
-= rdc3210_parts
[2].size
;
323 rdc3210_parts
[2].offset
= tmp
- (tmp
% tmp2
);
325 rdc3210_parts
[2].size
= rdc3210_parts
[3].offset
- rdc3210_parts
[2].offset
;
327 else if (hdr_type
== 2)
333 /* 4. Adjust Linux (Kernel + ROMFS) */
334 rdc3210_parts
[0].size
= rdc3210_parts
[len
+ hdr_type
+ 1].offset
- rdc3210_parts
[0].offset
;
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
))
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
)))
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
);
361 if (rdc3210_mtd
->sync
) rdc3210_mtd
->sync(rdc3210_mtd
);
365 rdc3210_mtd
->owner
= THIS_MODULE
;
366 add_mtd_partitions(rdc3210_mtd
, rdc3210_parts
, sizeof(rdc3210_parts
)/sizeof(rdc3210_parts
[0]));
370 iounmap((void *)rdc3210_map
.map_priv_1
);
371 rdc3210_map
.map_priv_1
= 0L;
372 rdc3210_map
.virt
= NULL
;
376 static void __exit
cleanup_rdc3210_map(void)
380 del_mtd_partitions(rdc3210_mtd
);
381 map_destroy(rdc3210_mtd
);
384 if (rdc3210_map
.map_priv_1
)
386 iounmap((void *)rdc3210_map
.map_priv_1
);
387 rdc3210_map
.map_priv_1
= 0L;
388 rdc3210_map
.virt
= NULL
;
392 module_init(init_rdc3210_map
);
393 module_exit(cleanup_rdc3210_map
);