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