2 * HND MIPS boards setup routines
4 * Copyright (C) 2009, Broadcom Corporation
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>
26 #include <asm/bootinfo.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>
46 #include <mips33_core.h>
47 #include <mips74k_core.h>
52 #include <ctf/hndctf.h>
59 extern void bcm947xx_time_init(void);
60 extern void bcm947xx_timer_setup(struct irqaction
*irq
);
63 extern void set_debug_traps(void);
64 extern void rs_kgdb_hook(struct uart_port
*);
65 extern void breakpoint(void);
68 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
69 extern struct ide_ops std_ide_ops
;
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 Tomato RAF features */
80 EXPORT_SYMBOL(bcm947xx_cpu_clk
);
83 #define sih bcm947xx_sih
84 #define sih_lock bcm947xx_sih_lock
89 ctf_attach_t ctf_attach_fn
= NULL
;
90 EXPORT_SYMBOL(ctf_attach_fn
);
93 /* Kernel command line */
94 extern char arcs_cmdline
[CL_SIZE
];
95 static int lanports_enable
= 0;
96 static int wombo_reset
= GPIO_PIN_NOTDEFINED
;
99 bcm947xx_reboot_handler(void)
101 if (lanports_enable
) {
102 uint lp
= 1 << lanports_enable
;
103 si_gpioout(sih
, lp
, 0, GPIO_DRV_PRIORITY
);
104 si_gpioouten(sih
, lp
, lp
, GPIO_DRV_PRIORITY
);
108 /* gpio 0 is also valid wombo_reset */
109 if (wombo_reset
!= GPIO_PIN_NOTDEFINED
) {
110 int reset
= 1 << wombo_reset
;
112 si_gpioout(sih
, reset
, 0, GPIO_DRV_PRIORITY
);
113 si_gpioouten(sih
, reset
, reset
, GPIO_DRV_PRIORITY
);
119 bcm947xx_machine_restart(char *command
)
121 printk("Please stand by while rebooting the system...\n");
123 /* Set the watchdog timer to reset immediately */
125 bcm947xx_reboot_handler();
130 bcm947xx_machine_halt(void)
132 printk("System halted\n");
134 /* Disable interrupts and watchdog and spin forever */
136 bcm947xx_reboot_handler();
141 #ifdef CONFIG_SERIAL_CORE
143 static int num_ports
= 0;
146 serial_add(void *regs
, uint irq
, uint baud_base
, uint reg_shift
)
150 memset(&rs
, 0, sizeof(rs
));
151 rs
.line
= num_ports
++;
152 rs
.flags
= UPF_BOOT_AUTOCONF
| UPF_SHARE_IRQ
;
153 rs
.iotype
= UPIO_MEM
;
155 rs
.mapbase
= (unsigned int) regs
;
158 rs
.uartclk
= baud_base
;
159 rs
.regshift
= reg_shift
;
161 if (early_serial_setup(&rs
) != 0) {
162 printk(KERN_ERR
"Serial setup failed!\n");
167 serial_setup(si_t
*sih
)
169 si_serial_init(sih
, serial_add
);
172 /* Use the last port for kernel debugging */
178 #endif /* CONFIG_SERIAL_CORE */
185 /* Get global SB handle */
186 sih
= si_kattach(SI_OSH
);
188 /* Initialize clocks and interrupts */
189 si_mips_init(sih
, SBMIPS_VIRTIRQ_BASE
);
191 if (BCM330X(current_cpu_data
.processor_id
) &&
192 (read_c0_diag() & BRCM_PFC_AVAIL
)) {
194 * Now that the sih is inited set the proper PFC value
196 printk("Setting the PFC to its default value\n");
197 enable_pfc(PFC_AUTO
);
201 #ifdef CONFIG_SERIAL_CORE
202 /* Initialize UARTs */
204 #endif /* CONFIG_SERIAL_CORE */
206 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
207 ide_ops
= &std_ide_ops
;
210 #ifdef NFLASH_SUPPORT
211 if ((sih
->ccrev
>= 38) && ((sih
->chipst
& (1 << 4)) != 0)) {
212 if (strncmp(arcs_cmdline
, "root=/dev/mtdblock", strlen("root=/dev/mtdblock")) == 0)
213 strcpy(arcs_cmdline
, "root=/dev/mtdblock15 console=ttyS0,115200");
216 /* Override default command line arguments */
217 value
= nvram_get("kernel_args");
218 if (value
&& strlen(value
) && strncmp(value
, "empty", 5))
219 strncpy(arcs_cmdline
, value
, sizeof(arcs_cmdline
));
221 if ((lanports_enable
= getgpiopin(NULL
, "lanports_enable", GPIO_PIN_NOTDEFINED
)) ==
226 if ((wombo_reset
= getgpiopin(NULL
, "wombo_reset", GPIO_PIN_NOTDEFINED
)) !=
227 GPIO_PIN_NOTDEFINED
) {
228 int reset
= 1 << wombo_reset
;
230 printk("wombo_reset set to gpio %d\n", wombo_reset
);
232 si_gpioout(sih
, reset
, 0, GPIO_DRV_PRIORITY
);
233 si_gpioouten(sih
, reset
, reset
, GPIO_DRV_PRIORITY
);
236 si_gpioout(sih
, reset
, reset
, GPIO_DRV_PRIORITY
);
241 _machine_restart
= bcm947xx_machine_restart
;
242 _machine_halt
= bcm947xx_machine_halt
;
243 pm_power_off
= bcm947xx_machine_halt
;
245 board_time_init
= bcm947xx_time_init
;
249 get_system_type(void)
255 bcm_chipname(bcm947xx_sih
->chip
, cn
, 8);
256 sprintf(s
, "Broadcom BCM%s chip rev %d pkg %d", cn
,
257 bcm947xx_sih
->chiprev
, bcm947xx_sih
->chippkg
);
261 return "Broadcom BCM947XX";
276 #ifdef CONFIG_MTD_PARTITIONS
280 RT_DIR320
, // D-Link DIR-320
281 RT_WNR3500L
, // Netgear WNR3500v2/U/L
282 RT_WNR2000V2
, // Netgear WNR2000v2
283 RT_BELKIN_F7D
// Belkin F7D3301, F7D3302, F7D4302, F7D8235V3
286 static int get_router(void)
288 uint boardnum
= bcm_strtoul(nvram_safe_get("boardnum"), NULL
, 0);
289 uint boardrev
= bcm_strtoul(nvram_safe_get("boardrev"), NULL
, 0);
290 uint boardtype
= bcm_strtoul(nvram_safe_get("boardtype"), NULL
, 0);
292 if ((boardnum
== 1 || boardnum
== 3500) && boardtype
== 0x4CF && (boardrev
== 0x1213 || boardrev
== 2)) {
295 else if (boardnum
== 1 && boardtype
== 0xE4CD && boardrev
== 0x1700) {
299 else if (boardnum
== 0 && boardtype
== 0x48E && boardrev
== 0x35) {
303 else if (boardtype
== 0xA4CF && (boardrev
== 0x1102 || boardrev
== 0x1100)) {
304 return RT_BELKIN_F7D
;
310 static size_t get_erasesize(struct mtd_info
*mtd
, size_t offset
, size_t size
)
313 struct mtd_erase_region_info
*regions
;
314 size_t erasesize
= 0;
316 if (mtd
->numeraseregions
> 1) {
317 regions
= mtd
->eraseregions
;
319 // Find the first erase regions which is part of this partition
320 for (i
= 0; i
< mtd
->numeraseregions
&& offset
>= regions
[i
].offset
; i
++);
322 for (i
--; i
< mtd
->numeraseregions
&& offset
+ size
> regions
[i
].offset
; i
++) {
323 if (erasesize
< regions
[i
].erasesize
)
324 erasesize
= regions
[i
].erasesize
;
328 erasesize
= mtd
->erasesize
;
336 new layout -- zzz 04/2006
340 +---+----------+ < search for HDR0
344 | i +----------+ < + trx->offset[1]
348 + +----------+ < + trx->len
350 +---+----------+ < size - NVRAM_SPACE - board_data_size()
352 +--------------+ < size - NVRAM_SPACE
354 +--------------+ < size
357 static struct mtd_partition bcm947xx_parts
[] = {
358 { name
: "pmon", offset
: 0, size
: 0, mask_flags
: MTD_WRITEABLE
, },
359 { name
: "linux", offset
: 0, size
: 0, },
360 { name
: "rootfs", offset
: 0, size
: 0, mask_flags
: MTD_WRITEABLE
, },
361 { name
: "jffs2", offset
: 0, size
: 0, },
362 { name
: "nvram", offset
: 0, size
: 0, },
363 { name
: "board_data", offset
: 0, size
: 0, },
369 #define PART_ROOTFS 2
374 struct mtd_partition
*
375 init_mtd_partitions(struct mtd_info
*mtd
, size_t size
)
378 struct trx_header
*trx
;
379 unsigned char buf
[512];
380 size_t off
, trxoff
, boardoff
;
387 /* Find and size nvram */
388 bcm947xx_parts
[PART_NVRAM
].size
= ROUNDUP(NVRAM_SPACE
, mtd
->erasesize
);
389 bcm947xx_parts
[PART_NVRAM
].offset
= size
- bcm947xx_parts
[PART_NVRAM
].size
;
391 /* Size board_data */
392 boardoff
= bcm947xx_parts
[PART_NVRAM
].offset
;
393 router
= get_router();
397 if (get_erasesize(mtd
, bcm947xx_parts
[PART_NVRAM
].offset
, bcm947xx_parts
[PART_NVRAM
].size
) == 0x2000) {
398 bcm947xx_parts
[PART_NVRAM
].size
= ROUNDUP(NVRAM_SPACE
, 0x2000);
399 bcm947xx_parts
[PART_NVRAM
].offset
= size
- bcm947xx_parts
[PART_NVRAM
].size
;
400 bcm947xx_parts
[PART_BOARD
].size
= 0x2000; // 8 KB
401 bcm947xx_parts
[PART_BOARD
].offset
= bcm947xx_parts
[PART_NVRAM
].offset
- bcm947xx_parts
[PART_BOARD
].size
;
403 else bcm947xx_parts
[PART_BOARD
].name
= NULL
;
408 bcm947xx_parts
[PART_BOARD
].size
= mtd
->erasesize
;
409 boardoff
-= bcm947xx_parts
[PART_BOARD
].size
;
410 bcm947xx_parts
[PART_BOARD
].offset
= boardoff
;
411 boardoff
-= 5 * mtd
->erasesize
;
412 if (size
<= 4 * 1024 * 1024) {
414 bcm947xx_parts
[PART_JFFS2
].offset
= boardoff
;
415 bcm947xx_parts
[PART_JFFS2
].size
= bcm947xx_parts
[PART_BOARD
].offset
- bcm947xx_parts
[PART_JFFS2
].offset
;
418 // 8MB or larger flash, exclude 1 block for Netgear CRC
419 crclen
= mtd
->erasesize
;
423 bcm947xx_parts
[PART_BOARD
].name
= NULL
;
428 trx
= (struct trx_header
*) buf
;
429 for (off
= 0; off
< size
; off
+= mtd
->erasesize
) {
431 * Read block 0 to test for rootfs
433 if ((mtd
->read(mtd
, off
, sizeof(buf
), &len
, buf
)) || (len
!= sizeof(buf
)))
436 /* Try looking at TRX header for rootfs offset */
437 switch (le32_to_cpu(trx
->magic
)) {
438 case TRX_MAGIC_F7D3301
:
439 case TRX_MAGIC_F7D3302
:
440 case TRX_MAGIC_F7D4302
:
441 case TRX_MAGIC_F5D8235V3
:
443 if (router
!= RT_BELKIN_F7D
)
447 trxsize
= ROUNDUP(le32_to_cpu(trx
->len
), mtd
->erasesize
); // kernel + rootfs
453 bcm947xx_parts
[PART_BOOT
].size
= off
;
455 /* Size linux (kernel and rootfs) */
456 bcm947xx_parts
[PART_LINUX
].offset
= off
;
457 bcm947xx_parts
[PART_LINUX
].size
= boardoff
- off
;
459 /* Find and size rootfs */
460 trxoff
= (le32_to_cpu(trx
->offsets
[2]) > off
) ? trx
->offsets
[2] : trx
->offsets
[1];
461 bcm947xx_parts
[PART_ROOTFS
].offset
= trxoff
+ off
;
462 bcm947xx_parts
[PART_ROOTFS
].size
= trxsize
- trxoff
;
464 /* Find and size jffs2 */
465 if (bcm947xx_parts
[PART_JFFS2
].size
== 0) {
466 bcm947xx_parts
[PART_JFFS2
].offset
= off
+ trxsize
;
467 if ((boardoff
- crclen
) > bcm947xx_parts
[PART_JFFS2
].offset
) {
468 bcm947xx_parts
[PART_JFFS2
].size
= boardoff
- crclen
- bcm947xx_parts
[PART_JFFS2
].offset
;
478 printk(KERN_NOTICE
"%s: Unable to find a valid linux partition\n", mtd
->name
);
483 for (i
= 0; bcm947xx_parts
[i
].name
; ++i
) {
484 printk(KERN_NOTICE
"%8x %8x (%8x) %s\n",
485 bcm947xx_parts
[i
].offset
,
486 (bcm947xx_parts
[i
].offset
+ bcm947xx_parts
[i
].size
) - 1,
487 bcm947xx_parts
[i
].size
,
488 bcm947xx_parts
[i
].name
);
492 return bcm947xx_parts
;
495 EXPORT_SYMBOL(init_mtd_partitions
);
497 #ifdef NFLASH_SUPPORT
498 static struct mtd_partition bcm947xx_nflash_parts
[] =
504 .mask_flags
= MTD_WRITEABLE
513 .name
= "board_data",
582 .mask_flags
= MTD_WRITEABLE
591 struct mtd_partition
* init_nflash_mtd_partitions(struct mtd_info
*mtd
, size_t size
)
593 struct romfs_super_block
*romfsb
;
594 struct cramfs_super
*cramfsb
;
595 struct squashfs_super_block
*squashfsb
;
596 struct trx_header
*trx
;
597 unsigned char buf
[NFL_SECTOR_SIZE
];
598 uint blocksize
, mask
, blk_offset
, off
, shift
= 0;
600 uint32 bootsz
, *bisz
;
605 romfsb
= (struct romfs_super_block
*) buf
;
606 cramfsb
= (struct cramfs_super
*) buf
;
607 squashfsb
= (struct squashfs_super_block
*) buf
;
608 trx
= (struct trx_header
*) buf
;
610 if ((cc
= (chipcregs_t
*)si_setcoreidx(sih
, SI_CC_IDX
)) == NULL
)
613 /* Look at every block boundary till 16MB; higher space is reserved for application data. */
614 blocksize
= mtd
->erasesize
;
615 for (off
= NFL_BOOT_SIZE
; off
< NFL_BOOT_OS_SIZE
; off
+= blocksize
) {
616 mask
= blocksize
- 1;
617 blk_offset
= off
& ~mask
;
618 if (nflash_checkbadb(sih
, cc
, blk_offset
) != 0)
620 memset(buf
, 0xe5, sizeof(buf
));
621 if ((ret
= nflash_read(sih
, cc
, off
, sizeof(buf
), buf
)) != sizeof(buf
)) {
623 "%s: nflash_read return %d\n", mtd
->name
, ret
);
627 /* Try looking at TRX header for rootfs offset */
628 if (le32_to_cpu(trx
->magic
) == TRX_MAGIC
&& off
>= 0x500000) {
629 mask
= NFL_SECTOR_SIZE
- 1;
630 off
= off
+ (le32_to_cpu(trx
->offsets
[1]) & ~mask
) - blocksize
;
631 shift
= (le32_to_cpu(trx
->offsets
[1]) & mask
);
632 romfsb
= (unsigned char *)romfsb
+ shift
;
633 cramfsb
= (unsigned char *)cramfsb
+ shift
;
634 squashfsb
= (unsigned char *)squashfsb
+ shift
;
638 /* romfs is at block zero too */
639 if (romfsb
->word0
== ROMSB_WORD0
&&
640 romfsb
->word1
== ROMSB_WORD1
) {
642 "%s: romfs filesystem found at block %d\n",
643 mtd
->name
, off
/ BLOCK_SIZE
);
648 if (cramfsb
->magic
== CRAMFS_MAGIC
) {
650 "%s: cramfs filesystem found at block %d\n",
651 mtd
->name
, off
/ BLOCK_SIZE
);
655 if (squashfsb
->s_magic
== SQUASHFS_MAGIC
) {
657 "%s: squash filesystem with lzma found at block %d\n",
658 mtd
->name
, off
/ BLOCK_SIZE
);
664 "%s: Couldn't find valid ROM disk image\n",
669 /* Default is 256K boot partition */
672 /* Do we have a self-describing binary image? */
673 bisz
= (uint32
*)KSEG1ADDR(SI_FLASH1
+ BISZ_OFFSET
);
674 if (bisz
[BISZ_MAGIC_IDX
] == BISZ_MAGIC
) {
675 int isz
= bisz
[BISZ_DATAEND_IDX
] - bisz
[BISZ_TXTST_IDX
];
677 if (isz
> (1024 * 1024))
678 bootsz
= 2048 * 1024;
679 else if (isz
> (512 * 1024))
680 bootsz
= 1024 * 1024;
681 else if (isz
> (256 * 1024))
683 else if (isz
<= (128 * 1024))
686 if (bootsz
> mtd
->erasesize
) {
687 /* Prepare double space in case of bad blocks */
688 bootsz
= (bootsz
<< 1);
690 /* CFE occupies at least one block */
691 bootsz
= mtd
->erasesize
;
694 printf("Boot partition size = %d(0x%x)\n", bootsz
, bootsz
);
697 bcm947xx_nflash_parts
[0].size
= bootsz
;
699 /* Setup NVRAM MTD partition */
700 bcm947xx_nflash_parts
[1].offset
= bootsz
;
701 bcm947xx_nflash_parts
[1].size
= NFL_BOOT_SIZE
- bootsz
;
703 i
= (sizeof(bcm947xx_nflash_parts
)/sizeof(struct mtd_partition
)) - 2;
704 top
= NFL_BOOT_OS_SIZE
;
707 for (idx
= 2; idx
<= i
- 2; idx
++)
709 if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "board_data", 10) == 0)
710 bcm947xx_nflash_parts
[idx
].size
= 0x40000; /* 256K */
711 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "POT", 3) == 0)
712 bcm947xx_nflash_parts
[idx
].size
= 0x40000; /* 256K */
713 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "T_Meter", 7) == 0)
714 bcm947xx_nflash_parts
[idx
].size
= 0x40000; /* 256K */
715 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "ML", 2) == 0)
716 bcm947xx_nflash_parts
[idx
].size
= 0x40000; /* 256K */
717 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "linux", 5) == 0)
719 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "rootfs", 6) == 0)
723 printk(KERN_ERR
"%s: Unknow MTD name %s\n",
724 __FUNCTION__
, bcm947xx_nflash_parts
[idx
].name
);
728 bcm947xx_nflash_parts
[idx
].offset
= bcm947xx_nflash_parts
[idx
- 1].offset
729 + bcm947xx_nflash_parts
[idx
- 1].size
;
733 /* Find and size rootfs */
735 bcm947xx_nflash_parts
[i
].offset
= off
+ shift
;
736 bcm947xx_nflash_parts
[i
].size
=
737 top
- bcm947xx_nflash_parts
[i
].offset
;
740 /* Size linux (kernel and rootfs) */
741 bcm947xx_nflash_parts
[i
- 1].offset
=
742 bcm947xx_nflash_parts
[i
- 2].offset
+ bcm947xx_nflash_parts
[i
- 2].size
;
743 bcm947xx_nflash_parts
[i
- 1].size
=
744 top
- bcm947xx_nflash_parts
[i
- 1].offset
;
746 return bcm947xx_nflash_parts
;
749 EXPORT_SYMBOL(init_nflash_mtd_partitions
);
750 #endif /* NFLASH_SUPPORT */