Use sn9 mtd driver
[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/squashfs_fs.h>
18 #include <linux/jffs2.h>
19 //#include <linux/crc32.h>
20
21 #define WINDOW_ADDR 0xFFC00000
22 #define WINDOW_SIZE 0x00400000
23
24 #define BUSWIDTH 2
25
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);
31
32 static struct mtd_info *rdc3210_mtd;
33
34 __u8 rdc3210_map_read8(struct map_info *map, unsigned long ofs)
35 {
36 return *(__u8 *)(map->map_priv_1 + ofs);
37 }
38
39 __u16 rdc3210_map_read16(struct map_info *map, unsigned long ofs)
40 {
41 return *(__u16 *)(map->map_priv_1 + ofs);
42 }
43
44 __u32 rdc3210_map_read32(struct map_info *map, unsigned long ofs)
45 {
46 return *(__u32 *)(map->map_priv_1 + ofs);
47 }
48
49 void rdc3210_map_write8(struct map_info *map, __u8 d, unsigned long adr)
50 {
51 *(__u8 *)(map->map_priv_1 + adr) = d;
52 }
53
54 void rdc3210_map_write16(struct map_info *map, __u16 d, unsigned long adr)
55 {
56 *(__u16 *)(map->map_priv_1 + adr) = d;
57 }
58
59 void rdc3210_map_write32(struct map_info *map, __u32 d, unsigned long adr)
60 {
61 *(__u32 *)(map->map_priv_1 + adr) = d;
62 }
63
64 void rdc3210_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
65 {
66 int i;
67 u16 *dst = (u16 *)(to);
68 u16 *src = (u16 *)(map->map_priv_1 + from);
69
70 for(i = 0; i < (len / 2); ++i)
71 dst[i] = src[i];
72
73 if(len & 1)
74 {
75 printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
76 //dst[len - 1] = B0(src[i]);
77 }
78 }
79
80 void rdc3210_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
81 {
82 int i;
83 u16 *dst = (u16 *)(map->map_priv_1 + to);
84 u16 *src = (u16 *)(from);
85
86 for(i = 0; i < (len / 2); ++i)
87 dst[i] = src[i];
88
89 if(len & 1)
90 {
91 printk("# WARNNING!!! rdc3210_map_copy_from has odd length\n");
92 //dst[len - 1] = B0(src[i]);
93 }
94 }
95
96 struct map_info rdc3210_map =
97 {
98 .name = "RDC3210 Flash",
99 .size = WINDOW_SIZE,
100 .phys = WINDOW_ADDR,
101 .bankwidth = BUSWIDTH,
102 };
103
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[] =
106 {
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 */
112 #endif
113 { name: "bootldr", offset: 0x003E0000, size: 0x00020000 }, /* 128 KB */
114 };
115
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,
181 0
182 };
183
184 static __u32 crc32(__u8 * buf, __u32 len)
185 {
186 register int i;
187 __u32 sum;
188 register __u32 s0;
189 s0 = ~0;
190 for (i = 0; i < len; i++) {
191 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
192 }
193 sum = ~s0;
194 return sum;
195 }
196
197 static void erase_callback(struct erase_info *done)
198 {
199 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
200 wake_up(wait_q);
201 }
202
203 static int erase_write (struct mtd_info *mtd, unsigned long pos,
204 int len, const char *buf)
205 {
206 struct erase_info erase;
207 DECLARE_WAITQUEUE(wait, current);
208 wait_queue_head_t wait_q;
209 size_t retlen;
210 int ret;
211
212 /*
213 * First, let's erase the flash block.
214 */
215
216 init_waitqueue_head(&wait_q);
217 erase.mtd = mtd;
218 erase.callback = erase_callback;
219 erase.addr = pos;
220 erase.len = len;
221 erase.priv = (u_long)&wait_q;
222
223 set_current_state(TASK_INTERRUPTIBLE);
224 add_wait_queue(&wait_q, &wait);
225
226 ret = mtd->erase(mtd, &erase);
227 if (ret) {
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);
233 return ret;
234 }
235
236 schedule(); /* Wait for erase to finish. */
237 remove_wait_queue(&wait_q, &wait);
238
239 /*
240 * Next, writhe data to flash.
241 */
242
243 ret = mtd->write (mtd, pos, len, &retlen, buf);
244 if (ret)
245 return ret;
246 if (retlen != len)
247 return -EIO;
248 return 0;
249 }
250
251 static int __init init_rdc3210_map(void)
252 {
253 printk(KERN_NOTICE "flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
254
255 rdc3210_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
256
257 if (!rdc3210_map.map_priv_1)
258 {
259 printk("Failed to ioremap\n");
260 return -EIO;
261 }
262 rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
263 #if RDC3210_STATIC_MAP /* Dante: This is for fixed map */
264 if (rdc3210_mtd)
265 {
266 rdc3210_mtd->module = THIS_MODULE;
267 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
268 return 0;
269 }
270 #else /* Dante: This is for dynamic mapping */
271
272 #include "imghdr.h"
273
274 if (rdc3210_mtd)
275 { // Dante
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;
280 int len;
281
282 if(memcmp(hdr->magic, GTIMG_MAGIC, 4))
283 {
284 printk("Invalid MAGIC for Firmware Image!!!\n");
285 return -EIO;
286 }
287
288 #if 0
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;
293
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;
302 #endif
303 #if RDC3210_NVRAM_IS_JFFS2
304 /* 3. Adjust NVRAM */
305 tmp = hdr->reserved;
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;
310
311 /* 4. Adjust Linux (Kernel + ROMFS) */
312 rdc3210_parts[0].size = rdc3210_parts[3].offset - rdc3210_parts[0].offset;
313
314 /* 5. Adjust ROMFS */
315 tmp = hdr->kernelsz + sizeof(gt_imghdr_t);
316 #else
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;
321
322 /* 4. Adjust Linux (Kernel + ROMFS) */
323 rdc3210_parts[0].size = rdc3210_parts[2].offset - rdc3210_parts[0].offset;
324
325 /* 5. Adjust ROMFS */
326 tmp2 = rdc3210_mtd->erasesize;
327 #endif
328 if ((ptmp = (gt_imghdr_t *)kmalloc(tmp4, GFP_KERNEL)) == NULL)
329 {
330 iounmap((void *)rdc3210_map.map_priv_1);
331 return -ENOMEM;
332 }
333 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp4, &len, (__u8 *)ptmp) || len != tmp4)
334 {
335 kfree(ptmp);
336 goto oh_snap;
337 }
338 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
339 tmp4 = tmp3;
340 else if (!hdr->reserved)
341 {
342 __u8 buf[1024];
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))
353 {
354 kfree(ptmp);
355 iounmap((void *)rdc3210_map.map_priv_1);
356 return len;
357 }
358 if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
359 }
360 kfree(ptmp);
361 rdc3210_parts[1].offset = rdc3210_parts[0].offset + tmp4;
362 rdc3210_parts[1].size = rdc3210_parts[2].offset - rdc3210_parts[1].offset;
363
364 rdc3210_mtd->owner = THIS_MODULE;
365 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
366 return 0;
367 }
368 #endif
369 oh_snap:
370 iounmap((void *)rdc3210_map.map_priv_1);
371 return -ENXIO;
372 }
373
374 static void __exit cleanup_rdc3210_map(void)
375 {
376 if (rdc3210_mtd)
377 {
378 del_mtd_partitions(rdc3210_mtd);
379 map_destroy(rdc3210_mtd);
380 }
381
382 if (rdc3210_map.map_priv_1)
383 {
384 iounmap((void *)rdc3210_map.map_priv_1);
385 rdc3210_map.map_priv_1 = 0L;
386 }
387 }
388
389 module_init(init_rdc3210_map);
390 module_exit(cleanup_rdc3210_map);