Support for Netgear WNR3500L v2
[tomato.git] / release / src-rt / linux / linux-2.6 / arch / mips / brcm-boards / bcm947xx / setup.c
blobdb4aa1a98af81079bae169641055010062e38355
1 /*
2 * HND MIPS boards setup routines
4 * Copyright (C) 2009, 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.
12 * $Id: setup.c,v 1.14 2010/02/26 04:43:25 Exp $
15 #include <linux/types.h>
16 #include <linux/config.h>
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/serial.h>
20 #include <linux/serialP.h>
21 #include <linux/serial_core.h>
22 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
23 #include <linux/blkdev.h>
24 #include <linux/ide.h>
25 #endif
26 #include <asm/bootinfo.h>
27 #include <asm/cpu.h>
28 #include <asm/time.h>
29 #include <asm/reboot.h>
31 #ifdef CONFIG_MTD_PARTITIONS
32 #include <linux/mtd/mtd.h>
33 #include <linux/mtd/partitions.h>
34 #include <linux/romfs_fs.h>
35 #include <linux/cramfs_fs.h>
36 #include <linux/squashfs_fs.h>
37 #endif
39 #include <typedefs.h>
40 #include <osl.h>
41 #include <bcmutils.h>
42 #include <bcmnvram.h>
43 #include <siutils.h>
44 #include <hndsoc.h>
45 #include <hndcpu.h>
46 #include <mips33_core.h>
47 #include <mips74k_core.h>
48 #include <sbchipc.h>
49 #include <hndchipc.h>
50 #include <trxhdr.h>
51 #ifdef HNDCTF
52 #include <ctf/hndctf.h>
53 #endif /* HNDCTF */
54 #include "bcm947xx.h"
55 #ifdef NFLASH_SUPPORT
56 #include "nflash.h"
57 #endif
59 extern void bcm947xx_time_init(void);
60 extern void bcm947xx_timer_setup(struct irqaction *irq);
62 #ifdef CONFIG_KGDB
63 extern void set_debug_traps(void);
64 extern void rs_kgdb_hook(struct uart_port *);
65 extern void breakpoint(void);
66 #endif
68 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
69 extern struct ide_ops std_ide_ops;
70 #endif
72 /* Global SB handle */
73 si_t *bcm947xx_sih = NULL;
74 spinlock_t bcm947xx_sih_lock = SPIN_LOCK_UNLOCKED;
75 EXPORT_SYMBOL(bcm947xx_sih);
76 EXPORT_SYMBOL(bcm947xx_sih_lock);
78 /* CPU freq */
79 int bcm947xx_cpu_clk;
80 EXPORT_SYMBOL(bcm947xx_cpu_clk);
82 /* Convenience */
83 #define sih bcm947xx_sih
84 #define sih_lock bcm947xx_sih_lock
86 #ifdef HNDCTF
87 ctf_t *kcih = NULL;
88 EXPORT_SYMBOL(kcih);
89 ctf_attach_t ctf_attach_fn = NULL;
90 EXPORT_SYMBOL(ctf_attach_fn);
91 #endif /* HNDCTF */
93 /* Kernel command line */
94 extern char arcs_cmdline[CL_SIZE];
96 void
97 bcm947xx_machine_restart(char *command)
99 printk("Please stand by while rebooting the system...\n");
101 /* Set the watchdog timer to reset immediately */
102 local_irq_disable();
103 hnd_cpu_reset(sih);
106 void
107 bcm947xx_machine_halt(void)
109 printk("System halted\n");
111 /* Disable interrupts and watchdog and spin forever */
112 local_irq_disable();
113 si_watchdog(sih, 0);
114 while (1);
117 #ifdef CONFIG_SERIAL_CORE
119 static int num_ports = 0;
121 static void __init
122 serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
124 struct uart_port rs;
126 memset(&rs, 0, sizeof(rs));
127 rs.line = num_ports++;
128 rs.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
129 rs.iotype = UPIO_MEM;
131 rs.mapbase = (unsigned int) regs;
132 rs.membase = regs;
133 rs.irq = irq + 2;
134 rs.uartclk = baud_base;
135 rs.regshift = reg_shift;
137 if (early_serial_setup(&rs) != 0) {
138 printk(KERN_ERR "Serial setup failed!\n");
142 static void __init
143 serial_setup(si_t *sih)
145 si_serial_init(sih, serial_add);
147 #ifdef CONFIG_KGDB
148 /* Use the last port for kernel debugging */
149 if (rs.membase)
150 rs_kgdb_hook(&rs);
151 #endif
154 #endif /* CONFIG_SERIAL_CORE */
156 void __init
157 brcm_setup(void)
159 char *value;
161 /* Get global SB handle */
162 sih = si_kattach(SI_OSH);
164 /* Initialize clocks and interrupts */
165 si_mips_init(sih, SBMIPS_VIRTIRQ_BASE);
167 if (BCM330X(current_cpu_data.processor_id) &&
168 (read_c0_diag() & BRCM_PFC_AVAIL)) {
170 * Now that the sih is inited set the proper PFC value
172 printk("Setting the PFC to its default value\n");
173 enable_pfc(PFC_AUTO);
177 #ifdef CONFIG_SERIAL_CORE
178 /* Initialize UARTs */
179 serial_setup(sih);
180 #endif /* CONFIG_SERIAL_CORE */
182 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
183 ide_ops = &std_ide_ops;
184 #endif
186 #ifdef NFLASH_SUPPORT
187 if ((sih->ccrev >= 38) && ((sih->chipst & (1 << 4)) != 0)) {
188 if (strncmp(arcs_cmdline, "root=/dev/mtdblock", strlen("root=/dev/mtdblock")) == 0)
189 strcpy(arcs_cmdline, "root=/dev/mtdblock15 console=ttyS0,115200");
191 #endif
192 /* Override default command line arguments */
193 value = nvram_get("kernel_args");
194 if (value && strlen(value) && strncmp(value, "empty", 5))
195 strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
198 /* Generic setup */
199 _machine_restart = bcm947xx_machine_restart;
200 _machine_halt = bcm947xx_machine_halt;
201 pm_power_off = bcm947xx_machine_halt;
203 board_time_init = bcm947xx_time_init;
206 const char *
207 get_system_type(void)
209 static char s[32];
210 char cn[8];
212 if (bcm947xx_sih) {
213 bcm_chipname(bcm947xx_sih->chip, cn, 8);
214 sprintf(s, "Broadcom BCM%s chip rev %d pkg %d", cn,
215 bcm947xx_sih->chiprev, bcm947xx_sih->chippkg);
216 return s;
218 else
219 return "Broadcom BCM947XX";
222 void __init
223 bus_error_init(void)
227 void __init
228 plat_mem_setup(void)
230 brcm_setup();
231 return;
234 #ifdef CONFIG_MTD_PARTITIONS
236 enum {
237 RT_UNKNOWN,
238 RT_DIR320, // D-Link DIR-320
239 RT_WNR3500L, // Netgear WNR3500v2/U/L
240 RT_WNR2000V2 // Netgear WNR2000v2
243 static int get_router(void)
245 uint boardnum = bcm_strtoul(nvram_safe_get("boardnum"), NULL, 0);
246 uint boardrev = bcm_strtoul(nvram_safe_get("boardrev"), NULL, 0);
247 uint boardtype = bcm_strtoul(nvram_safe_get("boardtype"), NULL, 0);
249 if ((boardnum == 1 || boardnum == 3500) && boardtype == 0x4CF && (boardrev == 0x1213 || boardrev == 2)) {
250 return RT_WNR3500L;
252 else if (boardnum == 1 && boardtype == 0xE4CD && boardrev == 0x1700) {
253 return RT_WNR2000V2;
255 else if (boardnum == 0 && boardtype == 0x48E && boardrev == 0x35) {
256 return RT_DIR320;
259 return RT_UNKNOWN;
262 static size_t get_erasesize(struct mtd_info *mtd, size_t offset, size_t size)
264 int i;
265 struct mtd_erase_region_info *regions;
266 size_t erasesize = 0;
268 if (mtd->numeraseregions > 1) {
269 regions = mtd->eraseregions;
271 // Find the first erase regions which is part of this partition
272 for (i = 0; i < mtd->numeraseregions && offset >= regions[i].offset; i++);
274 for (i--; i < mtd->numeraseregions && offset + size > regions[i].offset; i++) {
275 if (erasesize < regions[i].erasesize)
276 erasesize = regions[i].erasesize;
279 else {
280 erasesize = mtd->erasesize;
283 return erasesize;
287 new layout -- zzz 04/2006
289 +--------------+
290 | boot |
291 +---+----------+ < search for HDR0
292 | | |
293 | | (kernel) |
294 | l | |
295 | i +----------+ < + trx->offset[1]
296 | n | |
297 | u | rootfs |
298 | x | |
299 + +----------+ < + trx->len
300 | | jffs2 |
301 +---+----------+ < size - NVRAM_SPACE - board_data_size()
302 | board_data |
303 +--------------+ < size - NVRAM_SPACE
304 | nvram |
305 +--------------+ < size
308 static struct mtd_partition bcm947xx_parts[] = {
309 { name: "pmon", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
310 { name: "linux", offset: 0, size: 0, },
311 { name: "rootfs", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
312 { name: "jffs2", offset: 0, size: 0, },
313 { name: "nvram", offset: 0, size: 0, },
314 { name: "board_data", offset: 0, size: 0, },
315 { name: NULL, },
318 #define PART_BOOT 0
319 #define PART_LINUX 1
320 #define PART_ROOTFS 2
321 #define PART_JFFS2 3
322 #define PART_NVRAM 4
323 #define PART_BOARD 5
325 struct mtd_partition *
326 init_mtd_partitions(struct mtd_info *mtd, size_t size)
328 int router;
329 struct trx_header *trx;
330 unsigned char buf[512];
331 size_t off, trxoff, boardoff;
332 size_t crclen;
333 size_t len;
334 size_t trxsize;
336 crclen = 0;
338 /* Find and size nvram */
339 bcm947xx_parts[PART_NVRAM].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
340 bcm947xx_parts[PART_NVRAM].offset = size - bcm947xx_parts[PART_NVRAM].size;
342 /* Size board_data */
343 boardoff = bcm947xx_parts[PART_NVRAM].offset;
344 router = get_router();
345 switch (router) {
346 case RT_DIR320:
347 if (get_erasesize(mtd, bcm947xx_parts[PART_NVRAM].offset, bcm947xx_parts[PART_NVRAM].size) == 0x2000) {
348 bcm947xx_parts[PART_NVRAM].size = ROUNDUP(NVRAM_SPACE, 0x2000);
349 bcm947xx_parts[PART_NVRAM].offset = size - bcm947xx_parts[PART_NVRAM].size;
350 bcm947xx_parts[PART_BOARD].size = 0x2000; // 8 KB
351 bcm947xx_parts[PART_BOARD].offset = bcm947xx_parts[PART_NVRAM].offset - bcm947xx_parts[PART_BOARD].size;
353 else bcm947xx_parts[PART_BOARD].name = NULL;
354 break;
355 case RT_WNR3500L:
356 case RT_WNR2000V2:
357 bcm947xx_parts[PART_BOARD].size = mtd->erasesize;
358 boardoff -= bcm947xx_parts[PART_BOARD].size;
359 bcm947xx_parts[PART_BOARD].offset = boardoff;
360 boardoff -= 5 * mtd->erasesize;
361 if (size <= 4 * 1024 * 1024) {
362 // 4MB flash
363 bcm947xx_parts[PART_JFFS2].offset = boardoff;
364 bcm947xx_parts[PART_JFFS2].size = bcm947xx_parts[PART_BOARD].offset - bcm947xx_parts[PART_JFFS2].offset;
366 else {
367 // 8MB or larger flash, exclude 1 block for Netgear CRC
368 crclen = mtd->erasesize;
370 break;
371 default:
372 bcm947xx_parts[PART_BOARD].name = NULL;
373 break;
376 trxsize = 0;
377 trx = (struct trx_header *) buf;
378 for (off = 0; off < size; off += mtd->erasesize) {
380 * Read block 0 to test for rootfs
382 if ((mtd->read(mtd, off, sizeof(buf), &len, buf)) || (len != sizeof(buf)))
383 continue;
385 /* Try looking at TRX header for rootfs offset */
386 if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
387 /* Size pmon */
388 bcm947xx_parts[PART_BOOT].size = off;
390 /* Size linux (kernel and rootfs) */
391 bcm947xx_parts[PART_LINUX].offset = off;
392 bcm947xx_parts[PART_LINUX].size = boardoff - off;
394 trxsize = ROUNDUP(le32_to_cpu(trx->len), mtd->erasesize); // kernel + rootfs
396 /* Find and size rootfs */
397 trxoff = (le32_to_cpu(trx->offsets[2]) > off) ? trx->offsets[2] : trx->offsets[1];
398 bcm947xx_parts[PART_ROOTFS].offset = trxoff + off;
399 bcm947xx_parts[PART_ROOTFS].size = trxsize - trxoff;
401 /* Find and size jffs2 */
402 if (bcm947xx_parts[PART_JFFS2].size == 0) {
403 bcm947xx_parts[PART_JFFS2].offset = off + trxsize;
404 if ((boardoff - crclen) > bcm947xx_parts[PART_JFFS2].offset) {
405 bcm947xx_parts[PART_JFFS2].size = boardoff - crclen - bcm947xx_parts[PART_JFFS2].offset;
409 break;
413 if (trxsize == 0) {
414 // uh, now what...
415 printk(KERN_NOTICE "%s: Unable to find a valid linux partition\n", mtd->name);
418 #if 0
419 int i;
420 for (i = 0; bcm947xx_parts[i].name; ++i) {
421 printk(KERN_NOTICE "%8x %8x (%8x) %s\n",
422 bcm947xx_parts[i].offset,
423 (bcm947xx_parts[i].offset + bcm947xx_parts[i].size) - 1,
424 bcm947xx_parts[i].size,
425 bcm947xx_parts[i].name);
427 #endif
429 return bcm947xx_parts;
432 EXPORT_SYMBOL(init_mtd_partitions);
434 #ifdef NFLASH_SUPPORT
435 static struct mtd_partition bcm947xx_nflash_parts[] =
438 .name = "boot",
439 .size = 0,
440 .offset = 0,
441 .mask_flags = MTD_WRITEABLE
444 .name = "nvram",
445 .size = 0,
446 .offset = 0
448 #if 1
450 .name = "board_data",
451 .offset = 0,
452 .size = 0,
455 .name = "POT1",
456 .offset = 0,
457 .size = 0,
460 .name = "POT2",
461 .offset = 0,
462 .size = 0,
465 .name = "T_Meter1",
466 .offset = 0,
467 .size = 0,
470 .name = "T_Meter2",
471 .offset = 0,
472 .size = 0,
475 .name = "ML1",
476 .offset = 0,
477 .size = 0,
480 .name = "ML2",
481 .offset = 0,
482 .size = 0,
485 .name = "ML3",
486 .offset = 0,
487 .size = 0,
490 .name = "ML4",
491 .offset = 0,
492 .size = 0,
495 .name = "ML5",
496 .offset = 0,
497 .size = 0,
500 .name = "ML6",
501 .offset = 0,
502 .size = 0,
505 .name = "ML7",
506 .offset = 0,
507 .size = 0,
509 #endif
511 .name = "linux",
512 .size = 0,
513 .offset = 0
516 .name = "rootfs",
517 .size = 0,
518 .offset = 0,
519 .mask_flags = MTD_WRITEABLE
522 .name = 0,
523 .size = 0,
524 .offset = 0
528 struct mtd_partition * init_nflash_mtd_partitions(struct mtd_info *mtd, size_t size)
530 struct romfs_super_block *romfsb;
531 struct cramfs_super *cramfsb;
532 struct squashfs_super_block *squashfsb;
533 struct trx_header *trx;
534 unsigned char buf[NFL_SECTOR_SIZE];
535 uint blocksize, mask, blk_offset, off, shift = 0;
536 chipcregs_t *cc;
537 uint32 bootsz, *bisz;
538 int ret, i;
539 uint32 top;
540 int idx;
542 romfsb = (struct romfs_super_block *) buf;
543 cramfsb = (struct cramfs_super *) buf;
544 squashfsb = (struct squashfs_super_block *) buf;
545 trx = (struct trx_header *) buf;
547 if ((cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX)) == NULL)
548 return NULL;
550 /* Look at every block boundary till 16MB; higher space is reserved for application data. */
551 blocksize = mtd->erasesize;
552 for (off = NFL_BOOT_SIZE; off < NFL_BOOT_OS_SIZE; off += blocksize) {
553 mask = blocksize - 1;
554 blk_offset = off & ~mask;
555 if (nflash_checkbadb(sih, cc, blk_offset) != 0)
556 continue;
557 memset(buf, 0xe5, sizeof(buf));
558 if ((ret = nflash_read(sih, cc, off, sizeof(buf), buf)) != sizeof(buf)) {
559 printk(KERN_NOTICE
560 "%s: nflash_read return %d\n", mtd->name, ret);
561 continue;
564 /* Try looking at TRX header for rootfs offset */
565 if (le32_to_cpu(trx->magic) == TRX_MAGIC && off >= 0x500000) {
566 mask = NFL_SECTOR_SIZE - 1;
567 off = off + (le32_to_cpu(trx->offsets[1]) & ~mask) - blocksize;
568 shift = (le32_to_cpu(trx->offsets[1]) & mask);
569 romfsb = (unsigned char *)romfsb + shift;
570 cramfsb = (unsigned char *)cramfsb + shift;
571 squashfsb = (unsigned char *)squashfsb + shift;
572 continue;
575 /* romfs is at block zero too */
576 if (romfsb->word0 == ROMSB_WORD0 &&
577 romfsb->word1 == ROMSB_WORD1) {
578 printk(KERN_NOTICE
579 "%s: romfs filesystem found at block %d\n",
580 mtd->name, off / BLOCK_SIZE);
581 goto done;
584 /* so is cramfs */
585 if (cramfsb->magic == CRAMFS_MAGIC) {
586 printk(KERN_NOTICE
587 "%s: cramfs filesystem found at block %d\n",
588 mtd->name, off / BLOCK_SIZE);
589 goto done;
592 if (squashfsb->s_magic == SQUASHFS_MAGIC) {
593 printk(KERN_NOTICE
594 "%s: squash filesystem with lzma found at block %d\n",
595 mtd->name, off / BLOCK_SIZE);
596 goto done;
600 printk(KERN_NOTICE
601 "%s: Couldn't find valid ROM disk image\n",
602 mtd->name);
604 done:
606 /* Default is 256K boot partition */
607 bootsz = 256 * 1024;
609 /* Do we have a self-describing binary image? */
610 bisz = (uint32 *)KSEG1ADDR(SI_FLASH1 + BISZ_OFFSET);
611 if (bisz[BISZ_MAGIC_IDX] == BISZ_MAGIC) {
612 int isz = bisz[BISZ_DATAEND_IDX] - bisz[BISZ_TXTST_IDX];
614 if (isz > (1024 * 1024))
615 bootsz = 2048 * 1024;
616 else if (isz > (512 * 1024))
617 bootsz = 1024 * 1024;
618 else if (isz > (256 * 1024))
619 bootsz = 512 * 1024;
620 else if (isz <= (128 * 1024))
621 bootsz = 128 * 1024;
623 if (bootsz > mtd->erasesize) {
624 /* Prepare double space in case of bad blocks */
625 bootsz = (bootsz << 1);
626 } else {
627 /* CFE occupies at least one block */
628 bootsz = mtd->erasesize;
631 printf("Boot partition size = %d(0x%x)\n", bootsz, bootsz);
633 /* Size pmon */
634 bcm947xx_nflash_parts[0].size = bootsz;
636 /* Setup NVRAM MTD partition */
637 bcm947xx_nflash_parts[1].offset = bootsz;
638 bcm947xx_nflash_parts[1].size = NFL_BOOT_SIZE - bootsz;
640 i = (sizeof(bcm947xx_nflash_parts)/sizeof(struct mtd_partition)) - 2;
641 top = NFL_BOOT_OS_SIZE;
643 #if 1
644 for (idx = 2; idx <= i - 2; idx++)
646 if (strncmp(bcm947xx_nflash_parts[idx].name, "board_data", 10) == 0)
647 bcm947xx_nflash_parts[idx].size = 0x40000; /* 256K */
648 else if (strncmp(bcm947xx_nflash_parts[idx].name, "POT", 3) == 0)
649 bcm947xx_nflash_parts[idx].size = 0x40000; /* 256K */
650 else if (strncmp(bcm947xx_nflash_parts[idx].name, "T_Meter", 7) == 0)
651 bcm947xx_nflash_parts[idx].size = 0x40000; /* 256K */
652 else if (strncmp(bcm947xx_nflash_parts[idx].name, "ML", 2) == 0)
653 bcm947xx_nflash_parts[idx].size = 0x40000; /* 256K */
654 else if (strncmp(bcm947xx_nflash_parts[idx].name, "linux", 5) == 0)
655 break;
656 else if (strncmp(bcm947xx_nflash_parts[idx].name, "rootfs", 6) == 0)
657 break;
658 else
660 printk(KERN_ERR "%s: Unknow MTD name %s\n",
661 __FUNCTION__, bcm947xx_nflash_parts[idx].name);
662 break;
665 bcm947xx_nflash_parts[idx].offset = bcm947xx_nflash_parts[idx - 1].offset
666 + bcm947xx_nflash_parts[idx - 1].size;
668 #endif
670 /* Find and size rootfs */
671 if (off < size) {
672 bcm947xx_nflash_parts[i].offset = off + shift;
673 bcm947xx_nflash_parts[i].size =
674 top - bcm947xx_nflash_parts[i].offset;
677 /* Size linux (kernel and rootfs) */
678 bcm947xx_nflash_parts[i - 1].offset =
679 bcm947xx_nflash_parts[i - 2].offset + bcm947xx_nflash_parts[i - 2].size;
680 bcm947xx_nflash_parts[i - 1].size =
681 top - bcm947xx_nflash_parts[i - 1].offset;
683 return bcm947xx_nflash_parts;
686 EXPORT_SYMBOL(init_nflash_mtd_partitions);
687 #endif /* NFLASH_SUPPORT */
690 #endif