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
);
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
];
97 bcm947xx_machine_restart(char *command
)
99 printk("Please stand by while rebooting the system...\n");
101 /* Set the watchdog timer to reset immediately */
107 bcm947xx_machine_halt(void)
109 printk("System halted\n");
111 /* Disable interrupts and watchdog and spin forever */
117 #ifdef CONFIG_SERIAL_CORE
119 static int num_ports
= 0;
122 serial_add(void *regs
, uint irq
, uint baud_base
, uint reg_shift
)
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
;
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");
143 serial_setup(si_t
*sih
)
145 si_serial_init(sih
, serial_add
);
148 /* Use the last port for kernel debugging */
154 #endif /* CONFIG_SERIAL_CORE */
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 */
180 #endif /* CONFIG_SERIAL_CORE */
182 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
183 ide_ops
= &std_ide_ops
;
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");
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
));
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
;
207 get_system_type(void)
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
);
219 return "Broadcom BCM947XX";
234 #ifdef CONFIG_MTD_PARTITIONS
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)) {
252 else if (boardnum
== 1 && boardtype
== 0xE4CD && boardrev
== 0x1700) {
255 else if (boardnum
== 0 && boardtype
== 0x48E && boardrev
== 0x35) {
262 static size_t get_erasesize(struct mtd_info
*mtd
, size_t offset
, size_t size
)
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
;
280 erasesize
= mtd
->erasesize
;
287 new layout -- zzz 04/2006
291 +---+----------+ < search for HDR0
295 | i +----------+ < + trx->offset[1]
299 + +----------+ < + trx->len
301 +---+----------+ < size - NVRAM_SPACE - board_data_size()
303 +--------------+ < size - NVRAM_SPACE
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, },
320 #define PART_ROOTFS 2
325 struct mtd_partition
*
326 init_mtd_partitions(struct mtd_info
*mtd
, size_t size
)
329 struct trx_header
*trx
;
330 unsigned char buf
[512];
331 size_t off
, trxoff
, boardoff
;
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();
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
;
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) {
363 bcm947xx_parts
[PART_JFFS2
].offset
= boardoff
;
364 bcm947xx_parts
[PART_JFFS2
].size
= bcm947xx_parts
[PART_BOARD
].offset
- bcm947xx_parts
[PART_JFFS2
].offset
;
367 // 8MB or larger flash, exclude 1 block for Netgear CRC
368 crclen
= mtd
->erasesize
;
372 bcm947xx_parts
[PART_BOARD
].name
= NULL
;
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
)))
385 /* Try looking at TRX header for rootfs offset */
386 if (le32_to_cpu(trx
->magic
) == TRX_MAGIC
) {
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
;
415 printk(KERN_NOTICE
"%s: Unable to find a valid linux partition\n", mtd
->name
);
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
);
429 return bcm947xx_parts
;
432 EXPORT_SYMBOL(init_mtd_partitions
);
434 #ifdef NFLASH_SUPPORT
435 static struct mtd_partition bcm947xx_nflash_parts
[] =
441 .mask_flags
= MTD_WRITEABLE
450 .name
= "board_data",
519 .mask_flags
= MTD_WRITEABLE
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;
537 uint32 bootsz
, *bisz
;
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
)
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)
557 memset(buf
, 0xe5, sizeof(buf
));
558 if ((ret
= nflash_read(sih
, cc
, off
, sizeof(buf
), buf
)) != sizeof(buf
)) {
560 "%s: nflash_read return %d\n", mtd
->name
, ret
);
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
;
575 /* romfs is at block zero too */
576 if (romfsb
->word0
== ROMSB_WORD0
&&
577 romfsb
->word1
== ROMSB_WORD1
) {
579 "%s: romfs filesystem found at block %d\n",
580 mtd
->name
, off
/ BLOCK_SIZE
);
585 if (cramfsb
->magic
== CRAMFS_MAGIC
) {
587 "%s: cramfs filesystem found at block %d\n",
588 mtd
->name
, off
/ BLOCK_SIZE
);
592 if (squashfsb
->s_magic
== SQUASHFS_MAGIC
) {
594 "%s: squash filesystem with lzma found at block %d\n",
595 mtd
->name
, off
/ BLOCK_SIZE
);
601 "%s: Couldn't find valid ROM disk image\n",
606 /* Default is 256K boot partition */
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))
620 else if (isz
<= (128 * 1024))
623 if (bootsz
> mtd
->erasesize
) {
624 /* Prepare double space in case of bad blocks */
625 bootsz
= (bootsz
<< 1);
627 /* CFE occupies at least one block */
628 bootsz
= mtd
->erasesize
;
631 printf("Boot partition size = %d(0x%x)\n", bootsz
, bootsz
);
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
;
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)
656 else if (strncmp(bcm947xx_nflash_parts
[idx
].name
, "rootfs", 6) == 0)
660 printk(KERN_ERR
"%s: Unknow MTD name %s\n",
661 __FUNCTION__
, bcm947xx_nflash_parts
[idx
].name
);
665 bcm947xx_nflash_parts
[idx
].offset
= bcm947xx_nflash_parts
[idx
- 1].offset
666 + bcm947xx_nflash_parts
[idx
- 1].size
;
670 /* Find and size rootfs */
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 */