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
: 0x00010000, size
: 0x001E0000 },
42 { name
: "romfs", offset
: 0x000D0000, size
: 0x00120000 },
43 { name
: "nvram", offset
: 0x00000000, size
: 0x00010000 }, /* 64 KB */
44 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
45 #error Unsupported configuration!
47 { name
: "bootldr", offset
: 0x001F0000, size
: 0x00010000 },
49 #error Unsupported configuration!
53 static __u32 crctab
[257] = {
54 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
55 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
56 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
57 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
58 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
59 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
60 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
61 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
62 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
63 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
64 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
65 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
66 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
67 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
68 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
69 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
70 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
71 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
72 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
73 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
74 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
75 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
76 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
77 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
78 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
79 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
80 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
81 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
82 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
83 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
84 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
85 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
86 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
87 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
88 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
89 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
90 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
91 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
92 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
93 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
94 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
95 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
96 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
97 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
98 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
99 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
100 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
101 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
102 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
103 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
104 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
105 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
106 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
107 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
108 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
109 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
110 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
111 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
112 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
113 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
114 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
115 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
116 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
117 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
121 static __u32
crc32(__u8
* buf
, __u32 len
)
127 for (i
= 0; i
< len
; i
++) {
128 s0
= (s0
>> 8) ^ crctab
[(__u8
) (s0
& 0xFF) ^ buf
[i
]];
134 static void erase_callback(struct erase_info
*done
)
136 wait_queue_head_t
*wait_q
= (wait_queue_head_t
*)done
->priv
;
140 static int erase_write (struct mtd_info
*mtd
, unsigned long pos
,
141 int len
, const char *buf
)
143 struct erase_info erase
;
144 DECLARE_WAITQUEUE(wait
, current
);
145 wait_queue_head_t wait_q
;
150 * First, let's erase the flash block.
153 init_waitqueue_head(&wait_q
);
155 erase
.callback
= erase_callback
;
158 erase
.priv
= (u_long
)&wait_q
;
160 set_current_state(TASK_INTERRUPTIBLE
);
161 add_wait_queue(&wait_q
, &wait
);
163 ret
= mtd
->erase(mtd
, &erase
);
165 set_current_state(TASK_RUNNING
);
166 remove_wait_queue(&wait_q
, &wait
);
167 printk (KERN_WARNING
"erase of region [0x%lx, 0x%x] "
168 "on \"%s\" failed\n",
169 pos
, len
, mtd
->name
);
173 schedule(); /* Wait for erase to finish. */
174 remove_wait_queue(&wait_q
, &wait
);
177 * Next, writhe data to flash.
180 ret
= mtd
->write (mtd
, pos
, len
, &retlen
, buf
);
188 static int __init
init_rdc3210_map(void)
190 rdc3210_map
.phys
= -rdc3210_map
.size
;
191 printk(KERN_NOTICE
"flash device: %x at %x\n", rdc3210_map
.size
, rdc3210_map
.phys
);
193 rdc3210_map
.map_priv_1
= (unsigned long)(rdc3210_map
.virt
= ioremap_nocache(rdc3210_map
.phys
, rdc3210_map
.size
));
195 if (!rdc3210_map
.map_priv_1
)
197 printk("Failed to ioremap\n");
200 rdc3210_mtd
= do_map_probe("cfi_probe", &rdc3210_map
);
201 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP /* Dante: This is for fixed map */
204 rdc3210_mtd
->module
= THIS_MODULE
;
205 add_mtd_partitions(rdc3210_mtd
, rdc3210_parts
, sizeof(rdc3210_parts
)/sizeof(rdc3210_parts
[0]));
208 #else /* Dante: This is for dynamic mapping */
214 u32 kernelsz
, ramdisksz
;
221 sc_imghdr_t
*hdr2
= (sc_imghdr_t
*)(rdc3210_map
.map_priv_1
);
222 gt_imghdr_t
*hdr
= (gt_imghdr_t
*)hdr2
223 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
227 int len
, tmp
, tmp2
, tmp3
, tmp4
, hdr_type
= 0;
229 if(!memcmp(hdr
->magic
, GTIMG_MAGIC
, 4))
232 tmp
= hdr
->kernelsz
+ sizeof(gt_imghdr_t
);
233 tmp2
= rdc3210_mtd
->erasesize
;
234 tmp3
= ((tmp
/ 32) + ((tmp
% 32) ? 1 : 0)) * 32;
235 tmp4
= ((tmp
/ tmp2
) + ((tmp
% tmp2
) ? 1 : 0)) * tmp2
;
237 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
238 else if (!memcmp(hdr2
->magic
, "CSYS", 4))
241 tmp
= hdr2
->ramdisksz
+ hdr2
->kernelsz
+ sizeof(sc_imghdr_t
);
242 tmp2
= rdc3210_mtd
->erasesize
;
243 tmp3
= ((tmp
/ 32) + ((tmp
% 32) ? 1 : 0)) * 32;
244 tmp4
= ((tmp
/ tmp2
) + ((tmp
% tmp2
) ? 1 : 0)) * tmp2
;
249 iounmap((void *)rdc3210_map
.map_priv_1
);
250 rdc3210_map
.map_priv_1
= 0L;
251 rdc3210_map
.virt
= NULL
;
252 printk("Invalid MAGIC for Firmware Image!!!\n");
255 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
256 tmp
= (tmp3
== tmp4
) ? tmp4
+ tmp2
: tmp4
;
257 if ((ptmp
= (gt_imghdr_t
*)vmalloc(tmp
)) == NULL
)
259 iounmap((void *)rdc3210_map
.map_priv_1
);
260 rdc3210_map
.map_priv_1
= 0L;
261 rdc3210_map
.virt
= NULL
;
262 printk("Can't allocate 0x%08x for flash-reading buffer!\n", tmp
);
265 if (rdc3210_mtd
->read(rdc3210_mtd
, 0, tmp
, &len
, (__u8
*)ptmp
) || len
!= tmp
)
268 iounmap((void *)rdc3210_map
.map_priv_1
);
269 rdc3210_map
.map_priv_1
= 0L;
270 rdc3210_map
.virt
= NULL
;
271 printk("Can't read that much flash! Read 0x%08x of it.\n", len
);
275 #ifdef CONFIG_MTD_RDC3210_FACTORY_PRESENT
276 /* 1. Adjust Redboot */
277 tmp
= rdc3210_mtd
->size
- rdc3210_parts
[4].size
;
278 rdc3210_parts
[4].offset
= tmp
- (tmp
% tmp2
);
279 rdc3210_parts
[4].size
= rdc3210_mtd
->size
- rdc3210_parts
[4].offset
;
281 /* 2. Adjust Factory Default */
282 tmp
-= rdc3210_parts
[3].size
;
283 rdc3210_parts
[3].offset
= tmp
- (tmp
% tmp2
);
284 rdc3210_parts
[3].size
= rdc3210_parts
[4].offset
- rdc3210_parts
[3].offset
;
286 /* 1. Adjust Redboot */
287 tmp
= rdc3210_mtd
->size
- rdc3210_parts
[3].size
;
288 rdc3210_parts
[3].offset
= tmp
- (tmp
% tmp2
);
289 rdc3210_parts
[3].size
= rdc3210_mtd
->size
- rdc3210_parts
[3].offset
;
292 /* 3. Adjust NVRAM */
293 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
294 if (*(__u32
*)(((unsigned char *)ptmp
)+tmp3
) == SQUASHFS_MAGIC
)
299 rdc3210_parts
[2].name
= "rootfs_data";
300 rdc3210_parts
[2].offset
= rdc3210_parts
[0].offset
+ (((tmp
/ tmp2
) + ((tmp
% tmp2
) ? 1 : 0)) * tmp2
);
308 tmp
-= rdc3210_parts
[2].size
;
309 rdc3210_parts
[2].offset
= tmp
- (tmp
% tmp2
);
311 rdc3210_parts
[2].size
= rdc3210_parts
[3].offset
- rdc3210_parts
[2].offset
;
313 else if (hdr_type
== 2)
319 /* 4. Adjust Linux (Kernel + ROMFS) */
320 rdc3210_parts
[0].size
= rdc3210_parts
[len
+ hdr_type
+ 1].offset
- rdc3210_parts
[0].offset
;
322 /* 5. Adjust ROMFS */
323 rdc3210_parts
[1].offset
= rdc3210_parts
[0].offset
+ tmp4
;
324 rdc3210_parts
[1].size
= rdc3210_parts
[hdr_type
+ 1].offset
- rdc3210_parts
[1].offset
;
325 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
326 if (!(hdr
->reserved
|| len
))
329 ptmp
->reserved
= hdr
->imagesz
;
330 ptmp
->imagesz
= tmp4
;
331 ptmp
->checksum
= ptmp
->fastcksum
= 0;
332 memcpy(buf
, ptmp
, 0x100);
333 memcpy(buf
+ 0x100, ((__u8
*)ptmp
) + ((tmp4
>> 1) - ((tmp4
& 0x6) >> 1)), 0x100);
334 memcpy(buf
+ 0x200, ((__u8
*)ptmp
) + (tmp4
- 0x200), 0x200);
335 ptmp
->fastcksum
= crc32(buf
, sizeof(buf
));
336 ptmp
->checksum
= crc32((__u8
*)ptmp
, tmp4
);
337 if (rdc3210_mtd
->unlock
) rdc3210_mtd
->unlock(rdc3210_mtd
, 0, tmp2
);
338 if ((len
= erase_write(rdc3210_mtd
, 0, tmp2
, (char *)ptmp
)))
341 iounmap((void *)rdc3210_map
.map_priv_1
);
342 rdc3210_map
.map_priv_1
= 0L;
343 rdc3210_map
.virt
= NULL
;
344 printk("Couldn't erase! Got %d.\n", len
);
347 if (rdc3210_mtd
->sync
) rdc3210_mtd
->sync(rdc3210_mtd
);
351 rdc3210_mtd
->owner
= THIS_MODULE
;
352 add_mtd_partitions(rdc3210_mtd
, rdc3210_parts
, sizeof(rdc3210_parts
)/sizeof(rdc3210_parts
[0]));
356 iounmap((void *)rdc3210_map
.map_priv_1
);
357 rdc3210_map
.map_priv_1
= 0L;
358 rdc3210_map
.virt
= NULL
;
362 static void __exit
cleanup_rdc3210_map(void)
366 del_mtd_partitions(rdc3210_mtd
);
367 map_destroy(rdc3210_mtd
);
370 if (rdc3210_map
.map_priv_1
)
372 iounmap((void *)rdc3210_map
.map_priv_1
);
373 rdc3210_map
.map_priv_1
= 0L;
374 rdc3210_map
.virt
= NULL
;
378 module_init(init_rdc3210_map
);
379 module_exit(cleanup_rdc3210_map
);