Make jffs2 images work with rdc, add a sitecom wl-153 profile and kernel config,...
[lede.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 #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:  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!
46 #endif
47         { name: "bootldr", offset:  0x001F0000, size: 0x00010000 },
48 #else
49 #error Unsupported configuration!
50 #endif
51 };
52
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,
118         0
119 };
120
121 static __u32 crc32(__u8 * buf, __u32 len)
122 {
123         register int i;
124         __u32 sum;
125         register __u32 s0;
126         s0 = ~0;
127         for (i = 0; i < len; i++) {
128                 s0 = (s0 >> 8) ^ crctab[(__u8) (s0 & 0xFF) ^ buf[i]];
129         }
130         sum = ~s0;
131         return sum;
132 }
133
134 static void erase_callback(struct erase_info *done)
135 {
136         wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
137         wake_up(wait_q);
138 }
139
140 static int erase_write (struct mtd_info *mtd, unsigned long pos, 
141                         int len, const char *buf)
142 {
143         struct erase_info erase;
144         DECLARE_WAITQUEUE(wait, current);
145         wait_queue_head_t wait_q;
146         size_t retlen;
147         int ret;
148
149         /*
150          * First, let's erase the flash block.
151          */
152
153         init_waitqueue_head(&wait_q);
154         erase.mtd = mtd;
155         erase.callback = erase_callback;
156         erase.addr = pos;
157         erase.len = len;
158         erase.priv = (u_long)&wait_q;
159
160         set_current_state(TASK_INTERRUPTIBLE);
161         add_wait_queue(&wait_q, &wait);
162
163         ret = mtd->erase(mtd, &erase);
164         if (ret) {
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);
170                 return ret;
171         }
172
173         schedule();  /* Wait for erase to finish. */
174         remove_wait_queue(&wait_q, &wait);
175
176         /*
177          * Next, writhe data to flash.
178          */
179
180         ret = mtd->write (mtd, pos, len, &retlen, buf);
181         if (ret)
182                 return ret;
183         if (retlen != len)
184                 return -EIO;
185         return 0;
186 }
187
188 static int __init init_rdc3210_map(void)
189 {
190         rdc3210_map.phys = -rdc3210_map.size;
191         printk(KERN_NOTICE "flash device: %x at %x\n", rdc3210_map.size, rdc3210_map.phys);
192         
193         rdc3210_map.map_priv_1 = (unsigned long)(rdc3210_map.virt = ioremap_nocache(rdc3210_map.phys, rdc3210_map.size));
194
195         if (!rdc3210_map.map_priv_1) 
196         {
197                 printk("Failed to ioremap\n");
198                 return -EIO;
199         }
200         rdc3210_mtd = do_map_probe("cfi_probe", &rdc3210_map);
201 #ifdef CONFIG_MTD_RDC3210_STATIC_MAP    /* Dante: This is for fixed map */
202         if (rdc3210_mtd) 
203         {
204                 rdc3210_mtd->module = THIS_MODULE;
205                 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
206                 return 0;
207         }
208 #else   /* Dante: This is for dynamic mapping */
209
210 #include "imghdr.h"
211
212         typedef struct {
213                 u8      magic[4];
214                 u32     kernelsz, ramdisksz;
215                 u8      magic2[4];
216                 u32     sz2;
217         }sc_imghdr_t;
218
219         if (rdc3210_mtd) 
220         {       // Dante
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
224                         , *ptmp
225 #endif
226                         ;
227                 int     len, tmp, tmp2, tmp3, tmp4, hdr_type = 0;
228                 
229                 if(!memcmp(hdr->magic, GTIMG_MAGIC, 4))
230                 {
231                         hdr_type = 1;
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;
236                 }
237 #ifndef CONFIG_MTD_RDC3210_ALLOW_JFFS2
238                 else if (!memcmp(hdr2->magic, "CSYS", 4))
239                 {
240                         hdr_type = 2;
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;
245                 }
246 #endif
247                 else
248                 {
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");
253                         return -EIO;
254                 }
255 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
256                 tmp = (tmp3 == tmp4) ? tmp4 + tmp2 : tmp4;
257                 if ((ptmp = (gt_imghdr_t *)vmalloc(tmp)) == NULL)
258                 {
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);
263                         return -ENOMEM;
264                 }
265                 if (rdc3210_mtd->read(rdc3210_mtd, 0, tmp, &len, (__u8 *)ptmp) || len != tmp)
266                 {
267                         vfree(ptmp);
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);
272                         return -EIO;
273                 }
274 #endif
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;
280                 
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;
285 #else
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;
290 #endif
291                 if (hdr_type == 1) {
292                 /* 3. Adjust NVRAM */
293 #ifdef CONFIG_MTD_RDC3210_ALLOW_JFFS2
294                 if (*(__u32 *)(((unsigned char *)ptmp)+tmp3) == SQUASHFS_MAGIC)
295                 {
296                         len = 1;
297                         tmp4 = tmp3;
298                         tmp = hdr->imagesz;
299                 rdc3210_parts[2].name   = "rootfs_data";
300                 rdc3210_parts[2].offset = rdc3210_parts[0].offset + (((tmp / tmp2) + ((tmp % tmp2) ? 1 : 0)) * tmp2);
301                 }
302                 else
303 #else
304                         tmp4 = tmp3;
305 #endif
306                 {
307                         len = 0;
308                 tmp -= rdc3210_parts[2].size;
309                 rdc3210_parts[2].offset = tmp - (tmp % tmp2);
310                 }
311                 rdc3210_parts[2].size   = rdc3210_parts[3].offset - rdc3210_parts[2].offset;
312                 }
313                 else if (hdr_type == 2)
314                 {
315                         len = 0;
316                         tmp4 = tmp3;
317                 }
318                 
319                 /* 4. Adjust Linux (Kernel + ROMFS) */
320                 rdc3210_parts[0].size   = rdc3210_parts[len + hdr_type + 1].offset - rdc3210_parts[0].offset;
321
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))
327                 {
328                         __u8    buf[1024];
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)))
339                         {
340                                 vfree(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);
345                                 return len;
346                         }
347                         if (rdc3210_mtd->sync) rdc3210_mtd->sync(rdc3210_mtd);
348                 }
349                 vfree(ptmp);
350 #endif
351                 rdc3210_mtd->owner = THIS_MODULE;
352                 add_mtd_partitions(rdc3210_mtd, rdc3210_parts, sizeof(rdc3210_parts)/sizeof(rdc3210_parts[0]));
353                 return 0;
354         }
355 #endif
356         iounmap((void *)rdc3210_map.map_priv_1);
357         rdc3210_map.map_priv_1 = 0L;
358         rdc3210_map.virt = NULL;
359         return -ENXIO;
360 }
361
362 static void __exit cleanup_rdc3210_map(void)
363 {
364         if (rdc3210_mtd) 
365         {
366                 del_mtd_partitions(rdc3210_mtd);
367                 map_destroy(rdc3210_mtd);
368         }
369         
370         if (rdc3210_map.map_priv_1) 
371         {
372                 iounmap((void *)rdc3210_map.map_priv_1);
373                 rdc3210_map.map_priv_1 = 0L;
374                 rdc3210_map.virt = NULL;
375         }
376 }
377
378 module_init(init_rdc3210_map);
379 module_exit(cleanup_rdc3210_map);