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/squashfs_fs.h>
18 #include <linux/jffs2.h>
19 //#include <linux/crc32.h>
21 #define WINDOW_ADDR 0xFFC00000
22 #define WINDOW_SIZE 0x00400000
26 /* Dante: linked from linux-2.4.x/drivers/mtd/chips/flashdrv.c */
27 extern int flashdrv_get_size(void);
28 extern int flashdrv_get_sector(int addr);
29 extern int flashdrv_get_sector_addr(int sector);
30 extern int flashdrv_get_sector_size(int sector);
32 static struct mtd_info *rdc3210_mtd;
34 __u8 rdc3210_map_read8(struct map_info *map, unsigned long ofs)
36 return *(__u8 *)(map->map_priv_1 + ofs);
39 __u16 rdc3210_map_read16(struct map_info *map, unsigned long ofs)
41 return *(__u16 *)(map->map_priv_1 + ofs);
44 __u32 rdc3210_map_read32(struct map_info *map, unsigned long ofs)
46 return *(__u32 *)(map->map_priv_1 + ofs);
49 void rdc3210_map_write8(struct map_info *map, __u8 d, unsigned long adr)
51 *(__u8 *)(map->map_priv_1 + adr) = d;
54 void rdc3210_map_write16(struct map_info *map, __u16 d, unsigned long adr)
56 *(__u16 *)(map->map_priv_1 + adr) = d;
59 void rdc3210_map_write32(struct map_info *map, __u32 d, unsigned long adr)
61 *(__u32 *)(map->map_priv_1 + adr) = d;
64 void rdc3210_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
67 u16 *dst = (u16 *)(to);
68 u16 *src = (u16 *)(map->map_priv_1 + from);
70 for(i = 0; i < (len / 2); ++i)
75 printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
76 //dst[len - 1] = B0(src[i]);
80 void rdc3210_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
83 u16 *dst = (u16 *)(map->map_priv_1 + to);
84 u16 *src = (u16 *)(from);
86 for(i = 0; i < (len / 2); ++i)
91 printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
92 //dst[len - 1] = B0(src[i]);
96 struct map_info rdc3210_map =
98 .name = "RDC3210 Flash",
101 .bankwidth = BUSWIDTH,
104 /* Dante: This is the default static mapping, however this is nothing but a hint. (Say dynamic mapping) */
105 static struct mtd_partition rdc3210_parts[] =
107 { name: "linux", offset: 0, size: 0x003C0000 }, /* 3840 KB = (Kernel + ROMFS) = (768 KB + 3072 KB) */
108 { name: "romfs", offset: 0x000C0000, size: 0x00300000 }, /* 3072 KB */
109 { name: "nvram", offset: 0x003C0000, size: 0x00010000 }, /* 64 KB */
110 #if RDC3210_STATIC_MAP || RDC3210_FACTORY_PRESENT
111 { name: "factory", offset: 0x003D0000, size: 0x00010000 }, /* 64 KB */
113 { name: "bootldr", offset: 0x003E0000, size: 0x00020000 }, /* 128 KB */
116 static __u32 crctab[257] = {
117 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
118 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
119 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
120 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
121 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
122 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
123 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
124 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
125 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
126 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
127 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
128 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
129 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
130 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
131 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
132 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
133 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
134 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
135 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
136 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
137 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
138 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
139 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
140 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
141 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
142 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
143 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
144 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
145 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
146 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
147 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
148 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
149 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
150 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
151 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
152 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
153 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
154 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
155 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
156 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
157 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
158 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
159 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
160 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
161 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
162 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
163 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
164 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
165 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
166 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
167 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
168 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
169 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
170 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
171 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
172 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
173 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
174 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
175 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
176 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
177 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
178 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
179 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
180 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
184 static __u32 crc32(__u8 * buf, __u32 len)
190 for (i = 0; i < len; i++) {
191 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
197 static void erase_callback(struct erase_info *done)
199 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
203 static int erase_write (struct mtd_info *mtd, unsigned long pos,
204 int len, const char *buf)
206 struct erase_info erase;
207 DECLARE_WAITQUEUE(wait, current);
208 wait_queue_head_t wait_q;
213 * First, let's erase the flash block.
216 init_waitqueue_head(&wait_q);
218 erase.callback = erase_callback;
221 erase.priv = (u_long)&wait_q;
223 set_current_state(TASK_INTERRUPTIBLE);
224 add_wait_queue(&wait_q, &wait);
226 ret = mtd->erase(mtd, &erase);
228 set_current_state(TASK_RUNNING);
229 remove_wait_queue(&wait_q, &wait);
230 printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
231 "on \"%s\" failed\n",
232 pos, len, mtd->name);
236 schedule(); /* Wait for erase to finish. */
237 remove_wait_queue(&wait_q, &wait);
240 * Next, writhe data to flash.
243 ret = mtd->write (mtd, pos, len, &retlen, buf);
251 static int __init init_rdc3210_map(void)
253 printk(KERN_NOTICE "flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
255 rdc3210_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
257 if (!rdc3210_map.map_priv_1)
259 printk("Failed to ioremap\n");
262 rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
263 #if RDC3210_STATIC_MAP /* Dante: This is for fixed map */
266 rdc3210_mtd->module = THIS_MODULE;
267 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
270 #else /* Dante: This is for dynamic mapping */
276 gt_imghdr_t *hdr = (gt_imghdr_t *)(rdc3210_map.map_priv_1), *ptmp;
277 unsigned int tmp = hdr->kernelsz + sizeof(gt_imghdr_t), tmp2 = rdc3210_mtd->erasesize;
278 unsigned int tmp3 = ((tmp / 32) + ((tmp % 32) ? 1 : 0)) * 32;
279 unsigned int tmp4 = ((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2;
282 if(memcmp(hdr->magic, GTIMG_MAGIC, 4))
284 printk("Invalid MAGIC for Firmware Image!!!\n");
289 /* 1. Adjust Redboot */
290 tmp2 = flashdrv_get_size() - rdc3210_parts[4].size;
291 rdc3210_parts[4].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp2));
292 rdc3210_parts[4].size = flashdrv_get_size() - rdc3210_parts[4].offset;
294 /* 2. Adjust Factory Default */
295 tmp2 -= rdc3210_parts[3].size;
296 rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp2));
297 rdc3210_parts[3].size = rdc3210_parts[4].offset - rdc3210_parts[3].offset;
298 /* 1. Adjust Redboot */
299 tmp2 = flashdrv_get_size() - rdc3210_parts[3].size;
300 rdc3210_parts[3].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp2));
301 rdc3210_parts[3].size = flashdrv_get_size() - rdc3210_parts[3].offset;
303 #if RDC3210_NVRAM_IS_JFFS2
304 /* 3. Adjust NVRAM */
306 if (!tmp) tmp = hdr->imagesz;
307 tmp2 = rdc3210_mtd->erasesize;
308 rdc3210_parts[2].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
309 rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
311 /* 4. Adjust Linux (Kernel + ROMFS) */
312 rdc3210_parts[0].size = rdc3210_parts[3].offset - rdc3210_parts[0].offset;
314 /* 5. Adjust ROMFS */
315 tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
317 /* 3. Adjust NVRAM */
318 tmp2 -= rdc3210_parts[2].size;
319 rdc3210_parts[2].offset = flashdrv_get_sector_addr(flashdrv_get_sector(tmp2));
320 rdc3210_parts[2].size = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
322 /* 4. Adjust Linux (Kernel + ROMFS) */
323 rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
325 /* 5. Adjust ROMFS */
326 tmp2 = rdc3210_mtd->erasesize;
328 if ((ptmp = (gt_imghdr_t *)kmalloc(tmp4, GFP_KERNEL)) == NULL)
330 iounmap((void *)rdc3210_map.map_priv_1);
333 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp4, &len, (__u8 *)ptmp) || len != tmp4)
338 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
340 else if (!hdr->reserved)
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);
358 if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
361 rdc3210_parts[1].offset = rdc3210_parts[0].offset + tmp4;
362 rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
364 rdc3210_mtd->owner = THIS_MODULE;
365 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
370 iounmap((void *)rdc3210_map.map_priv_1);
374 static void __exit cleanup_rdc3210_map(void)
378 del_mtd_partitions(rdc3210_mtd);
379 map_destroy(rdc3210_mtd);
382 if (rdc3210_map.map_priv_1)
384 iounmap((void *)rdc3210_map.map_priv_1);
385 rdc3210_map.map_priv_1 = 0L;
389 module_init(init_rdc3210_map);
390 module_exit(cleanup_rdc3210_map);