source: src/linux/universal/linux-3.5/drivers/mtd/maps/bcm947xx-flash.c @ 31672

Last change on this file since 31672 was 31672, checked in by brainslayer, 2 months ago

fix fs detection

File size: 19.8 KB
Line 
1/*
2 * Flash mapping for BCM947XX boards
3 *
4 * Copyright (C) 2008, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: bcm947xx-flash.c,v 1.5 2008/03/25 01:27:49 Exp $
13 */
14
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <asm/io.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/map.h>
22#include <linux/mtd/partitions.h>
23#include "../mtdcore.h"
24#include <linux/squashfs_fs.h>
25#include <linux/jffs2.h>
26#include <linux/crc32.h>
27#include <linux/vmalloc.h>
28
29#include <typedefs.h>
30#include <bcmnvram.h>
31#include <bcmutils.h>
32#include <hndsoc.h>
33#include <sbchipc.h>
34#include <siutils.h>
35#include <trxhdr.h>
36
37/* Global SB handle */
38extern void *bcm947xx_sih;
39extern spinlock_t bcm947xx_sih_lock;
40
41/* Convenience */
42#define sih bcm947xx_sih
43#define sih_lock bcm947xx_sih_lock
44
45
46#define WINDOW_ADDR 0x1fc00000
47#define WINDOW_SIZE 0x400000
48#define BUSWIDTH 2
49
50/* e.g., flash=2M or flash=4M */
51static int flash = 0;
52module_param(flash, int, 0);
53static int __init
54bcm947xx_setup(char *str)
55{
56        flash = memparse(str, &str);
57        return 1;
58}
59__setup("flash=", bcm947xx_setup);
60
61static struct mtd_info *bcm947xx_mtd;
62
63
64#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
65#define init_bcm947xx_map init_module
66#define cleanup_bcm947xx_map cleanup_module
67#endif
68
69
70#define ROUTER_NETGEAR_WGR614L           1
71#define ROUTER_NETGEAR_WNR834B           2
72#define ROUTER_NETGEAR_WNDR3300          3
73#define ROUTER_NETGEAR_WNR3500L          4
74#define ROUTER_NETGEAR_WNR2000V2         5
75#define ROUTER_NETGEAR_WNDR3400          6
76#define ROUTER_NETGEAR_WNDR4000          7
77#define ROUTER_BELKIN_F5D8235V3          8
78#define ROUTER_BELKIN_F7D3301_3302_4302  9
79
80/* Belkin series */
81#define TRX_MAGIC_F7D3301              0x20100322      /* Belkin Share Max; router's birthday ? */
82#define TRX_MAGIC_F7D3302              0x20090928      /* Belkin Share; router's birthday ? */
83#define TRX_MAGIC_F7D4302              0x20091006      /* Belkin Play; router's birthday ? */
84#define TRX_MAGIC_F5D8235V3            0x00017116      /* Belkin F5D8235-4v3 */
85#define TRX_MAGIC_QA                   0x12345678      /* cfe: It's QA firmware */
86
87/* Netgear wgr614 */
88#define WGR614_CHECKSUM_BLOCK_START    0x003A0000
89#define WGR614_CHECKSUM_OFF            0x003AFFF8
90#define WGR614_FAKE_LEN                0x00000004  //we fake checksum only over 4 bytes (HDR0)
91#define WGR614_FAKE_CHK                0x02C0010E
92
93static int get_router (void)
94{
95        uint boardnum = bcm_strtoul( nvram_safe_get( "boardnum" ), NULL, 0 );   
96               
97        if ( (boardnum == 8 || boardnum == 01)
98          && nvram_match ("boardtype", "0x0472")
99          && nvram_match ("cardbus", "1") ) {
100                return ROUTER_NETGEAR_WNR834B;    //Netgear WNR834B, Netgear WNR834Bv2
101        }
102
103        if ( boardnum == 01
104          && nvram_match ("boardtype", "0x0472")
105          && nvram_match ("boardrev", "0x23") ) {
106                return ROUTER_NETGEAR_WNDR3300;  //Netgear WNDR-3300   
107        }       
108       
109        if ( (boardnum == 83258 || boardnum == 01)  //or 001 or 0x01
110          && (nvram_match ("boardtype", "0x048e") || nvram_match ("boardtype", "0x48E"))
111          && (nvram_match ("boardrev", "0x11") || nvram_match ("boardrev", "0x10"))
112          && (nvram_match ("boardflags", "0x750") || nvram_match ("boardflags", "0x0750"))
113          &&  nvram_match ("sdram_init", "0x000A") ) {
114                return ROUTER_NETGEAR_WGR614L;  //Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5
115        }
116       
117        if ( (boardnum == 1 || boardnum == 3500)
118          && nvram_match ("boardtype", "0x04CF")
119          && (nvram_match ("boardrev", "0x1213") || nvram_match ("boardrev", "02")) ) {
120                return ROUTER_NETGEAR_WNR3500L;  //Netgear WNR3500v2/U/L
121        }
122       
123        if ( boardnum == 1
124          && nvram_match ("boardtype", "0xE4CD")
125          && nvram_match ("boardrev", "0x1700") ) {
126                return ROUTER_NETGEAR_WNR2000V2;  //Netgear WNR2000v2   
127        }
128       
129        if ( boardnum == 01
130          && nvram_match("boardtype", "0xb4cf")
131          && nvram_match("boardrev", "0x1100")) {
132                return ROUTER_NETGEAR_WNDR3400;  //Netgear WNDR3400     
133        }
134       
135        if ( boardnum == 01
136          && nvram_match("boardtype", "0xF52C")
137          && nvram_match("boardrev", "0x1101")) {
138                return ROUTER_NETGEAR_WNDR4000;  //Netgear WNDR4000     
139        }
140       
141        if (nvram_match("boardtype", "0xa4cf")
142          && nvram_match("boardrev", "0x1100")) {
143                return ROUTER_BELKIN_F5D8235V3;  //F5D8235v3
144        }       
145       
146        if (nvram_match("boardtype", "0xa4cf")
147          && nvram_match("boardrev", "0x1102")) {
148                return ROUTER_BELKIN_F7D3301_3302_4302;  //Belkin F7D3301v1 /F7D3302v1 / F7D4302v1
149        }
150       
151        return 0;
152}
153
154static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
155{
156        if (len==1) {
157                memcpy_fromio(to, map->virt + from, len);
158        } else {
159                int i;
160                u16 *dest = (u16 *) to;
161                u16 *src  = (u16 *) (map->virt + from);
162                for (i = 0; i < (len / 2); i++) {
163                        dest[i] = src[i];
164                }
165                if (len & 1)
166                        *((u8 *)dest+len-1) = src[i] & 0xff;
167        }
168}
169
170
171struct map_info bcm947xx_map = {
172        name: "Physically mapped flash",
173        size: WINDOW_SIZE,
174        bankwidth: BUSWIDTH,
175        phys: WINDOW_ADDR,
176};
177
178
179#ifdef CONFIG_MTD
180
181static struct mtd_partition bcm947xx_parts[] = {
182        { name: "cfe",  offset: 0, size: 0, },
183        { name: "linux", offset: 0, size: 0, },
184        { name: "rootfs", offset: 0, size: 0, },
185        { name: "nvram", offset: 0, size: 0, },
186        { name: "ddwrt", offset: 0, size: 0, },
187        { name: "board_data", offset: 0, size: 0, },
188        { name: NULL, },
189};
190extern int cfenvram;
191static struct mtd_partition nflash_parts[] = {
192        { name: "cfe",  offset: 0, size: 0, },
193        { name: "nvram", offset: 0, size: 0, },
194        { name: "nvram_cfe", offset: 0, size: 0, },
195        { name: NULL, },
196};
197
198#define NVRAM_MAGIC             0x48534C46      /* 'FLSH' */
199static int onlyboot=0;
200static int __init
201find_cfe_size(struct mtd_info *mtd, size_t size)
202{
203        struct trx_header *trx;
204        static unsigned char buf[513];
205        int off;
206        size_t len;
207        int blocksize;
208
209        trx = (struct trx_header *) buf;
210        printk(KERN_INFO "try to find cfe size up to %d\n",size);
211        if (mtd==NULL)
212            {
213            printk(KERN_INFO "mtd is NULL\n");
214            return -1;
215            }
216        blocksize = mtd->erasesize;
217        if (blocksize < 0x10000)
218                blocksize = 0x10000;
219//      printk(KERN_EMERG "blocksize is %d\n",blocksize);
220        for (off = 0x10000; off < size; off += 1024) {
221                memset(buf, 0xe5, sizeof(buf));
222//              printk(KERN_EMERG "scan at 0x%08x\n",off);
223                /*
224                 * Read into buffer
225                 */
226                if (mtd_read(mtd, off, sizeof(buf), &len, buf) ||
227                    len != sizeof(buf))
228                        continue;
229                       
230                switch (le32_to_cpu(trx->magic)) {
231                 /* found a TRX header */       
232                case TRX_MAGIC:
233                        goto found;
234                        break;
235                /* found a Belkin TRX header */
236                case TRX_MAGIC_F7D3301:
237                case TRX_MAGIC_F7D3302:
238                case TRX_MAGIC_F7D4302:
239                case TRX_MAGIC_F5D8235V3:
240                case TRX_MAGIC_QA:
241                        if (get_router() == ROUTER_BELKIN_F7D3301_3302_4302
242                                || get_router() == ROUTER_BELKIN_F5D8235V3) {
243                                printk(KERN_EMERG  "Found Belkin TRX magic\n");
244                                goto found;
245                        }
246                        break;
247                case NVRAM_MAGIC:
248                        printk(KERN_NOTICE "no filesys. assume nflash devices\n");
249                        onlyboot=1;
250                        off = size;
251                        goto found;
252                        break;
253               
254                }
255
256        }
257
258        printk(KERN_EMERG
259               "%s: Couldn't find bootloader size\n",
260               mtd->name);
261        return -1;
262
263 found:
264        printk(KERN_EMERG  "bootloader size: %d\n", off);
265        printk(KERN_EMERG  "nvram size: %d\n", NVRAM_SPACE);
266        return off;
267
268}
269
270
271/*
272 * Copied from mtdblock.c
273 *
274 * Cache stuff...
275 *
276 * Since typical flash erasable sectors are much larger than what Linux's
277 * buffer cache can handle, we must implement read-modify-write on flash
278 * sectors for each block write requests.  To avoid over-erasing flash sectors
279 * and to speed things up, we locally cache a whole flash sector while it is
280 * being written to until a different sector is required.
281 */
282
283static void erase_callback(struct erase_info *done)
284{
285        wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
286        wake_up(wait_q);
287}
288
289static int erase_write (struct mtd_info *mtd, unsigned long pos,
290                        int len, const char *buf)
291{
292        struct erase_info erase;
293        DECLARE_WAITQUEUE(wait, current);
294        wait_queue_head_t wait_q;
295        size_t retlen;
296        int ret;
297
298        /*
299         * First, let's erase the flash block.
300         */
301
302        init_waitqueue_head(&wait_q);
303        erase.mtd = mtd;
304        erase.callback = erase_callback;
305        erase.addr = pos;
306        erase.len = len;
307        erase.priv = (u_long)&wait_q;
308
309        set_current_state(TASK_INTERRUPTIBLE);
310        add_wait_queue(&wait_q, &wait);
311
312        ret = mtd_erase(mtd, &erase);
313        if (ret) {
314                set_current_state(TASK_RUNNING);
315                remove_wait_queue(&wait_q, &wait);
316                printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
317                                     "on \"%s\" failed\n",
318                        pos, len, mtd->name);
319                return ret;
320        }
321
322        schedule();  /* Wait for erase to finish. */
323        remove_wait_queue(&wait_q, &wait);
324
325        /*
326         * Next, writhe data to flash.
327         */
328
329        ret = mtd_write (mtd, pos, len, &retlen, buf);
330        if (ret)
331                return ret;
332        if (retlen != len)
333                return -EIO;
334        return 0;
335}
336
337
338
339
340static int __init
341find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
342{
343        struct trx_header trx, *trx2;
344        unsigned char buf[512], *block;
345        int off, blocksize;
346        u32 i, crc = ~0;
347        size_t len;
348        struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
349
350        blocksize = mtd->erasesize;
351        if (blocksize < 0x10000)
352                blocksize = 0x10000;
353
354        for (off = 0; off < size; off += 64*1024) {
355                memset(&trx, 0xe5, sizeof(trx));
356//              printk(KERN_EMERG "scan root at 0x%08x\n",off);
357
358                /*
359                 * Read into buffer
360                 */
361                if (mtd_read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
362                    len != sizeof(trx))
363                        continue;
364
365                switch (le32_to_cpu(trx.magic)) {
366                 /* found a TRX header */       
367                case TRX_MAGIC:
368                        goto found;
369                        break;
370                /* found a Belkin TRX header */
371                case TRX_MAGIC_F7D3301:
372                case TRX_MAGIC_F7D3302:
373                case TRX_MAGIC_F7D4302:
374                case TRX_MAGIC_F5D8235V3:
375                case TRX_MAGIC_QA:
376                        if (get_router() == ROUTER_BELKIN_F7D3301_3302_4302
377                                || get_router() == ROUTER_BELKIN_F5D8235V3) {
378                                printk(KERN_EMERG  "Found Belkin TRX magic\n");
379                                goto found;
380                        }
381                        break;
382                }
383        }
384
385        printk(KERN_EMERG
386               "%s: Couldn't find root filesystem\n",
387               mtd->name);
388        return -1;
389
390 found:
391        part->offset = le32_to_cpu(trx.offsets[2]) ? :
392                le32_to_cpu(trx.offsets[1]);
393        part->size = le32_to_cpu(trx.len);
394
395        part->size -= part->offset;
396        part->offset += off;
397 
398        if (part->size == 0)
399                return 0;
400       
401        if (mtd_read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
402                return 0;
403
404        if (*((__u32 *) buf) == SQUASHFS_MAGIC) {
405                printk(KERN_EMERG  "%s: Filesystem type: squashfs, size=0x%x\n", mtd->name, (u32) le64_to_cpu(sb.bytes_used));
406
407                /* Update the squashfs partition size based on the superblock info */
408                part->size = le64_to_cpu(sb.bytes_used);
409                //part->size = part->size + 1024; /* uncomment for belkin v2000 ! */
410                len = part->offset + part->size;
411                len +=  (mtd->erasesize - 1);
412                len &= ~(mtd->erasesize - 1);
413                part->size = len - part->offset;
414                printk(KERN_EMERG "partition size = %d\n",part->size);
415        } else if (*((__u16 *) buf) == JFFS2_MAGIC_BITMASK) {
416                printk(KERN_EMERG  "%s: Filesystem type: jffs2\n", mtd->name);
417
418                /* Move the squashfs outside of the trx */
419                part->size = 0;
420        } else {
421                printk(KERN_EMERG  "%s: Filesystem type: unknown\n", mtd->name);
422                return 0;
423        }
424
425        if (trx.len != part->offset + part->size - off) {
426                /* Update the trx offsets and length */
427                trx.len = part->offset + part->size - off;
428//              printk(KERN_EMERG "update crc32\n");
429                /* Update the trx crc32 */
430                for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
431//                      printk(KERN_EMERG "read from %d\n",off + i);
432                        if (mtd_read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
433                                return 0;
434                        crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
435                }
436                trx.crc32 = crc;
437
438//                      printk(KERN_EMERG "malloc\n",off + i);
439                /* read first eraseblock from the trx */
440                trx2 = block = vmalloc(mtd->erasesize);
441                if (mtd_read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
442                        printk(KERN_EMERG "Error accessing the first trx eraseblock\n");
443                        vfree(block);
444                        return 0;
445                }
446               
447                printk(KERN_EMERG "Updating TRX offsets and length:\n");
448                printk(KERN_EMERG "old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
449                printk(KERN_EMERG "new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n",   trx.offsets[0],   trx.offsets[1],   trx.offsets[2],   trx.len, trx.crc32);
450
451                /* Write updated trx header to the flash */
452                memcpy(block, &trx, sizeof(trx));
453                mtd_unlock(mtd, off, mtd->erasesize);
454                erase_write(mtd, off, mtd->erasesize, block);
455                mtd_sync(mtd);
456                vfree(block);
457                printk(KERN_EMERG "Done\n");
458               
459                /* Write fake Netgear checksum to the flash */         
460                if (get_router() == ROUTER_NETGEAR_WGR614L) {
461                /*
462                 * Read into buffer
463                 */
464                block = vmalloc(mtd->erasesize);
465                if (mtd_read(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize, &len, block) ||
466                    len != mtd->erasesize) {
467                        printk(KERN_EMERG "Error accessing the WGR614 checksum eraseblock\n");
468                        vfree(block);
469                        }
470                        else {
471                        char imageInfo[8];
472                        u32 fake_len = le32_to_cpu(WGR614_FAKE_LEN);
473                        u32 fake_chk = le32_to_cpu(WGR614_FAKE_CHK);
474                        memcpy(&imageInfo[0], (char *)&fake_len, 4);
475                        memcpy(&imageInfo[4], (char *)&fake_chk, 4);
476                        char *tmp;     
477                        tmp = block + ((WGR614_CHECKSUM_OFF - WGR614_CHECKSUM_BLOCK_START) % mtd->erasesize);
478                        memcpy( tmp, imageInfo, sizeof( imageInfo ) );
479                        mtd_unlock(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize);
480                        erase_write(mtd, WGR614_CHECKSUM_BLOCK_START, mtd->erasesize, block);
481                        mtd_sync(mtd);
482                        vfree(block);
483                        printk(KERN_EMERG "Done fixing WGR614 checksum\n");               
484                        }
485                }       
486               
487               
488        }
489       
490        return part->size;
491}
492
493struct mtd_partition * __init
494init_mtd_partitions(struct mtd_info *mtd, size_t size)
495{
496        int cfe_size;
497
498        int board_data_size = 0; // e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this part from our mapping
499        int jffs_exclude_size = 0;  // to prevent overwriting len/checksum on e.g. Netgear WGR614v8/L/WW
500       
501        switch (get_router()) {
502                case ROUTER_NETGEAR_WGR614L:
503                case ROUTER_NETGEAR_WNR834B:
504                case ROUTER_NETGEAR_WNDR3300:
505                case ROUTER_NETGEAR_WNR3500L:
506                        board_data_size = 4 * 0x10000;  //Netgear: checksum is @ 0x003AFFF8 for 4M flash
507                        jffs_exclude_size = 0x10000;    //or checksum is @ 0x007AFFF8 for 8M flash
508                        break; 
509                case ROUTER_NETGEAR_WNR2000V2: 
510                        board_data_size = 0x10000;
511                        break;
512                case ROUTER_NETGEAR_WNDR3400:   //Netgear: checksum is @ 0x0070FFF8 @ 8M flash, but can be overwritten
513                case ROUTER_NETGEAR_WNDR4000:   //Netgear: checksum is @ 0x0073FFF8 @ 8M flash, but can be overwritten
514                        board_data_size = 0x10000;
515                        break;
516        }
517
518        if ((cfe_size = find_cfe_size(mtd,size)) < 0)
519                return NULL;
520        if (onlyboot)
521        {
522        nflash_parts[0].offset = 0;
523        nflash_parts[0].size   = cfe_size;
524        if (cfenvram)
525        {
526        nflash_parts[1].offset = size - mtd->erasesize * 3;
527        nflash_parts[1].size   = mtd->erasesize;
528        nflash_parts[2].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
529        nflash_parts[2].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
530        }else{
531        nflash_parts[1].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
532        nflash_parts[1].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
533        nflash_parts[2].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
534        nflash_parts[2].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
535        }
536        return nflash_parts;
537        }
538        /* boot loader */
539        bcm947xx_parts[0].offset = 0;
540        bcm947xx_parts[0].size   = cfe_size;
541       
542
543        /* nvram */
544        if (cfe_size != 384 * 1024) {
545                bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
546                bcm947xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
547        } else {
548                /* nvram (old 128kb config partition on netgear wgt634u) */
549                bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
550                bcm947xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
551        }
552
553        if (board_data_size != 0) {
554                bcm947xx_parts[5].size = board_data_size;       
555                bcm947xx_parts[5].offset = bcm947xx_parts[3].offset - board_data_size; 
556        } else {
557                bcm947xx_parts[5].name = NULL; 
558        }
559
560        /* linux (kernel and rootfs) */
561        if (cfe_size != 384 * 1024) {
562                bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
563                bcm947xx_parts[1].size   = (bcm947xx_parts[3].offset - bcm947xx_parts[1].offset) - board_data_size;
564        } else {
565                /* do not count the elf loader, which is on one block */
566                bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
567                        bcm947xx_parts[3].size + mtd->erasesize;
568                bcm947xx_parts[1].size   = (((size - bcm947xx_parts[0].size) - (2*bcm947xx_parts[3].size)) - mtd->erasesize) - board_data_size;
569        }
570
571
572        /* find and size rootfs */
573        if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
574                /* entirely jffs2 */
575                bcm947xx_parts[4].name = NULL;
576                bcm947xx_parts[2].size = (size - bcm947xx_parts[2].offset) - bcm947xx_parts[3].size;
577        } else {
578                /* legacy setup */
579                /* calculate leftover flash, and assign it to the jffs2 partition */
580                if (cfe_size != 384 * 1024) {
581                        bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
582                                bcm947xx_parts[2].size;
583                        if ((((unsigned int)bcm947xx_parts[4].offset) % mtd->erasesize) > 0) {
584                                bcm947xx_parts[4].offset += mtd->erasesize -
585                                        (((unsigned int)bcm947xx_parts[4].offset) % mtd->erasesize);
586                        }
587                        bcm947xx_parts[4].size = ((bcm947xx_parts[3].offset - bcm947xx_parts[4].offset) - board_data_size) - jffs_exclude_size;
588                } else {
589                        bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
590                                bcm947xx_parts[2].size;
591                        if ((((unsigned int)bcm947xx_parts[4].offset) % mtd->erasesize) > 0) {
592                                bcm947xx_parts[4].offset += mtd->erasesize -
593                                        (((unsigned int)bcm947xx_parts[4].offset) % mtd->erasesize);
594                        }
595                        bcm947xx_parts[4].size = (((size - bcm947xx_parts[3].size) - bcm947xx_parts[4].offset) - board_data_size) - jffs_exclude_size;
596                }
597                /* do not make zero size jffs2 partition  */
598                if (bcm947xx_parts[4].size < mtd->erasesize) {
599                        bcm947xx_parts[4].name = NULL;
600                }
601        }
602
603        return bcm947xx_parts;
604}
605
606#endif
607
608static int __init
609init_bcm947xx_map(void)
610{
611        ulong flags;
612        uint coreidx;
613        chipcregs_t *cc;
614        uint32 fltype;
615        uint window_addr = 0, window_size = 0;
616        size_t size;
617        int ret = 0;
618#ifdef CONFIG_MTD
619        struct mtd_partition *parts;
620        int i;
621#endif
622
623        spin_lock_irqsave(&sih_lock, flags);
624        coreidx = si_coreidx(sih);
625
626        /* Check strapping option if chipcommon exists */
627        if ((cc = si_setcore(sih, CC_CORE_ID, 0))) {
628                fltype = readl(&cc->capabilities) & CC_CAP_FLASH_MASK;
629                if (fltype == PFLASH) {
630                        bcm947xx_map.map_priv_2 = 1;
631                        window_addr = 0x1c000000;
632                        bcm947xx_map.size = window_size = 32 * 1024 * 1024;
633                        if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
634                                bcm947xx_map.bankwidth = 1;
635                }
636        } else {
637                fltype = PFLASH;
638                bcm947xx_map.map_priv_2 = 0;
639                window_addr = WINDOW_ADDR;
640                bcm947xx_map.size = window_size = WINDOW_SIZE;
641        }
642
643        si_setcoreidx(sih, coreidx);
644        spin_unlock_irqrestore(&sih_lock, flags);
645
646        if (fltype != PFLASH) {
647                printk(KERN_ERR "pflash: found no supported devices\n");
648                ret = -ENODEV;
649                goto fail;
650        }
651
652        bcm947xx_map.virt = ioremap(window_addr, window_size);
653        if (bcm947xx_map.virt == NULL) {
654                printk(KERN_ERR "pflash: ioremap failed\n");
655                ret = -EIO;
656                goto fail;
657        }
658
659        if ((bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map)) == NULL) {
660                printk(KERN_ERR "pflash: cfi_probe failed\n");
661                ret = -ENXIO;
662                goto fail;
663        }
664
665        bcm947xx_mtd->owner = THIS_MODULE;
666
667        /* override copy_from routine */
668//      bcm947xx_map.copy_from = bcm47xx_map_copy_from;
669
670        /* Allow size override for testing */
671        size = flash ? : bcm947xx_mtd->size;
672
673        printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
674
675#ifdef CONFIG_MTD
676        parts = init_mtd_partitions(bcm947xx_mtd, size);
677        for (i = 0; parts[i].name; i++);
678        ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
679        if (ret) {
680                printk(KERN_ERR "pflash: add_mtd_partitions failed\n");
681                goto fail;
682        }
683#endif
684
685        return 0;
686
687 fail:
688        if (bcm947xx_mtd)
689                map_destroy(bcm947xx_mtd);
690        if (bcm947xx_map.map_priv_1)
691                iounmap((void *) bcm947xx_map.map_priv_1);
692        bcm947xx_map.map_priv_1 = 0;
693        return ret;
694}
695
696static void __exit
697cleanup_bcm947xx_map(void)
698{
699#ifdef CONFIG_MTD
700        del_mtd_partitions(bcm947xx_mtd);
701#endif
702        map_destroy(bcm947xx_mtd);
703        iounmap((void *) bcm947xx_map.map_priv_1);
704        bcm947xx_map.map_priv_1 = 0;
705}
706
707module_init(init_bcm947xx_map);
708module_exit(cleanup_bcm947xx_map);
Note: See TracBrowser for help on using the repository browser.