source: src/linux/universal/linux-3.18/drivers/mtd/maps/bcm947xx-flash.c @ 25572

Last change on this file since 25572 was 25572, checked in by BrainSlayer, 3 years ago

required for unifi, otherwise jffs will brick boarddata

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