pci_module_init() is deprecated for a long time - this won't hurt .21 and will be...
[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         { 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);