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