++ SB_ERROR(("sb_pcie_mdiowrite: timed out\n"));
++ /* Disable mdio access to SERDES */
++ W_REG(si->osh, (&pcieregs->mdiocontrol), 0);
++ ASSERT(0);
++ return 1;
++
++}
++
++/* indirect way to read pcie config regs */
++uint
++sb_pcie_readreg(void *sb, void* arg1, uint offset)
++{
++ sb_info_t *si;
++ sb_t *sbh;
++ uint retval = 0xFFFFFFFF;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
++
++ sbh = (sb_t *)sb;
++ si = SB_INFO(sbh);
++ ASSERT(PCIE(si));
++
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT(pcieregs);
++
++ addrtype = (uint)((uintptr)arg1);
++ switch (addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG(si->osh, (&pcieregs->configaddr), offset);
++ retval = R_REG(si->osh, &(pcieregs->configdata));
++ break;
++ case PCIE_PCIEREGS:
++ W_REG(si->osh, &(pcieregs->pcieaddr), offset);
++ retval = R_REG(si->osh, &(pcieregs->pciedata));
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++ return retval;
++}
++
++/* indirect way to write pcie config/mdio/pciecore regs */
++uint
++sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val)
++{
++ sb_info_t *si;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
++
++ si = SB_INFO(sbh);
++ ASSERT(PCIE(si));
++
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT(pcieregs);
++
++ addrtype = (uint)((uintptr)arg1);
++
++ switch (addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG(si->osh, (&pcieregs->configaddr), offset);
++ W_REG(si->osh, (&pcieregs->configdata), val);
++ break;
++ case PCIE_PCIEREGS:
++ W_REG(si->osh, (&pcieregs->pcieaddr), offset);
++ W_REG(si->osh, (&pcieregs->pciedata), val);
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++ return 0;
++}
++
++/* Build device path. Support SB, PCI, and JTAG for now. */
++int
++sb_devpath(sb_t *sbh, char *path, int size)
++{
++ ASSERT(path);
++ ASSERT(size >= SB_DEVPATH_BUFSZ);
++
++ switch (BUSTYPE((SB_INFO(sbh))->sb.bustype)) {
++ case SB_BUS:
++ case JTAG_BUS:
++ sprintf(path, "sb/%u/", sb_coreidx(sbh));
++ break;
++ case PCI_BUS:
++ ASSERT((SB_INFO(sbh))->osh);
++ sprintf(path, "pci/%u/%u/", OSL_PCI_BUS((SB_INFO(sbh))->osh),
++ OSL_PCI_SLOT((SB_INFO(sbh))->osh));
++ break;
++ case PCMCIA_BUS:
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_BUS() not implemented, bus 1 assumed\n"));
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_SLOT() not implemented, slot 1 assumed\n"));
++ sprintf(path, "pc/%u/%u/", 1, 1);
++ break;
++ case SDIO_BUS:
++ SB_ERROR(("sb_devpath: device 0 assumed\n"));
++ sprintf(path, "sd/%u/", sb_coreidx(sbh));
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++
++ return 0;
++}
++
++/*
++ * Fixup SROMless PCI device's configuration.
++ * The current core may be changed upon return.
++ */
++static int
++sb_pci_fixcfg(sb_info_t *si)
++{
++ uint origidx, pciidx;
++ sbpciregs_t *pciregs;
++ sbpcieregs_t *pcieregs;
++ uint16 val16, *reg16;
++ char name[SB_DEVPATH_BUFSZ+16], *value;
++ char devpath[SB_DEVPATH_BUFSZ];
++
++ ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS);
++
++ /* Fixup PI in SROM shadow area to enable the correct PCI core access */
++ /* save the current index */
++ origidx = sb_coreidx(&si->sb);
++
++ /* check 'pi' is correct and fix it if not */
++ if (si->sb.buscoretype == SB_PCIE) {
++ pcieregs = (sbpcieregs_t *)sb_setcore(&si->sb, SB_PCIE, 0);
++ ASSERT(pcieregs);
++ reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
++ } else if (si->sb.buscoretype == SB_PCI) {
++ pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0);
++ ASSERT(pciregs);
++ reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
++ } else {
++ ASSERT(0);
++ return -1;
++ }
++ pciidx = sb_coreidx(&si->sb);
++ val16 = R_REG(si->osh, reg16);
++ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) {
++ val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK);
++ W_REG(si->osh, reg16, val16);
++ }
++
++ /* restore the original index */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /*
++ * Fixup bar0window in PCI config space to make the core indicated
++ * by the nvram variable the current core.
++ * !Do it last, it may change the current core!
++ */
++ if (sb_devpath(&si->sb, devpath, sizeof(devpath)))
++ return -1;
++ sprintf(name, "%sb0w", devpath);
++ if ((value = getvar(NULL, name))) {
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32),
++ bcm_strtoul(value, NULL, 16));
++ /* update curidx since the current core is changed */
++ si->curidx = _sb_coreidx(si);
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_pci_fixcfg: bad core index\n"));
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++static uint
++sb_chipc_capability(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ /* Make sure that there is ChipCommon core present */
++ if (si->coreid[SB_CC_IDX] == SB_CC)
++ return (sb_corereg(si, SB_CC_IDX, OFFSETOF(chipcregs_t, capabilities),
++ 0, 0));
++ return 0;
++}
++
++/* Return ADDR64 capability of the backplane */
++bool
++sb_backplane64(sb_t *sbh)
++{
++ return ((sb_chipc_capability(sbh) & CAP_BKPLN64) != 0);
++}
++
++void
++sb_btcgpiowar(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++ chipcregs_t *cc;
++ si = SB_INFO(sbh);
++
++ /* Make sure that there is ChipCommon core present &&
++ * UART_TX is strapped to 1
++ */
++ if (!(sb_chipc_capability(sbh) & CAP_UARTGPIO))
++ return;
++
++ /* sb_corereg cannot be used as we have to guarantee 8-bit read/writes */
++ INTR_OFF(si, intr_val);
++
++ origidx = sb_coreidx(sbh);
++
++ cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
++ if (cc == NULL)
++ goto end;
++
++ W_REG(si->osh, &cc->uart0mcr, R_REG(si->osh, &cc->uart0mcr) | 0x04);
++
++end:
++ /* restore the original index */
++ sb_setcoreidx(sbh, origidx);
++
++ INTR_RESTORE(si, intr_val);
++}
++
++/* check if the device is removed */
++bool
++sb_deviceremoved(sb_t *sbh)
++{
++ uint32 w;
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ ASSERT(si->osh);
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_VID, sizeof(uint32));
++ if ((w & 0xFFFF) != VENDOR_BROADCOM)
++ return TRUE;
++ else
++ return FALSE;
++ default:
++ return FALSE;
++ }
++ return FALSE;
++}
++
++/* Return the RAM size of the SOCRAM core */
++uint32
++sb_socram_size(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++
++ sbsocramregs_t *regs;
++ bool wasup;
++ uint corerev;
++ uint32 coreinfo;
++ uint memsize = 0;
++
++ si = SB_INFO(sbh);
++ ASSERT(si);
++
++ /* Block ints and save current core */
++ INTR_OFF(si, intr_val);
++ origidx = sb_coreidx(sbh);
++
++ /* Switch to SOCRAM core */
++ if (!(regs = sb_setcore(sbh, SB_SOCRAM, 0)))
++ goto done;
++
++ /* Get info for determining size */
++ if (!(wasup = sb_iscoreup(sbh)))
++ sb_core_reset(sbh, 0, 0);
++ corerev = sb_corerev(sbh);
++ coreinfo = R_REG(si->osh, ®s->coreinfo);
++
++ /* Calculate size from coreinfo based on rev */
++ switch (corerev) {
++ case 0:
++ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
++ break;
++ default: /* rev >= 1 */
++ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
++ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
++ break;
++ }
++
++ /* Return to previous state and core */
++ if (!wasup)
++ sb_core_disable(sbh, 0);
++ sb_setcoreidx(sbh, origidx);
++
++done:
++ INTR_RESTORE(si, intr_val);
++ return memsize;
++}
++
++
+diff -urN linux.old/arch/mips/bcm947xx/setup.c linux.dev/arch/mips/bcm947xx/setup.c
+--- linux.old/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/setup.c 2006-04-27 23:22:53.000000000 +0200
+@@ -0,0 +1,241 @@
++/*
++ * Generic setup routines for Broadcom MIPS boards
++ *
++ * Copyright (C) 2005 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/serialP.h>
++#include <linux/ide.h>
++#include <asm/bootinfo.h>
++#include <asm/cpu.h>
++#include <asm/time.h>
++#include <asm/reboot.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++#include <sbhndmips.h>
++#include <hndmips.h>
++#include <trxhdr.h>
++
++/* Virtual IRQ base, after last hw IRQ */
++#define SBMIPS_VIRTIRQ_BASE 6
++
++/* # IRQs, hw and sw IRQs */
++#define SBMIPS_NUMIRQS 8
++
++/* Global SB handle */
++sb_t *bcm947xx_sbh = NULL;
++spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++extern void bcm947xx_time_init(void);
++extern void bcm947xx_timer_setup(struct irqaction *irq);
++
++#ifdef CONFIG_REMOTE_DEBUG
++extern void set_debug_traps(void);
++extern void rs_kgdb_hook(struct serial_state *);
++extern void breakpoint(void);
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
++extern struct ide_ops std_ide_ops;
++#endif
++
++/* Kernel command line */
++char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE;
++extern void sb_serial_init(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
++
++void
++bcm947xx_machine_restart(char *command)
++{
++ printk("Please stand by while rebooting the system...\n");
++
++ /* Set the watchdog timer to reset immediately */
++ __cli();
++ sb_watchdog(sbh, 1);
++ while (1);
++}
++
++void
++bcm947xx_machine_halt(void)
++{
++ printk("System halted\n");
++
++ /* Disable interrupts and watchdog and spin forever */
++ __cli();
++ sb_watchdog(sbh, 0);
++ while (1);
++}
++
++#ifdef CONFIG_SERIAL
++
++static int ser_line = 0;
++
++typedef struct {
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++} serial_port;
++
++static serial_port ports[4];
++static int num_ports = 0;
++
++static void
++serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
++{
++ ports[num_ports].regs = regs;
++ ports[num_ports].irq = irq;
++ ports[num_ports].baud_base = baud_base;
++ ports[num_ports].reg_shift = reg_shift;
++ num_ports++;
++}
++
++static void
++do_serial_add(serial_port *port)
++{
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++ struct serial_struct s;
++
++ regs = port->regs;
++ irq = port->irq;
++ baud_base = port->baud_base;
++ reg_shift = port->reg_shift;
++
++ memset(&s, 0, sizeof(s));
++
++ s.line = ser_line++;
++ s.iomem_base = regs;
++ s.irq = irq + 2;
++ s.baud_base = baud_base / 16;
++ s.flags = ASYNC_BOOT_AUTOCONF;
++ s.io_type = SERIAL_IO_MEM;
++ s.iomem_reg_shift = reg_shift;
++
++ if (early_serial_setup(&s) != 0) {
++ printk(KERN_ERR "Serial setup failed!\n");
++ }
++}
++
++#endif /* CONFIG_SERIAL */
++
++void __init
++brcm_setup(void)
++{
++ char *s;
++ int i;
++ char *value;
++
++ /* Get global SB handle */
++ sbh = sb_kattach();
++
++ /* Initialize clocks and interrupts */
++ sb_mips_init(sbh, SBMIPS_VIRTIRQ_BASE);
++
++ if (BCM330X(current_cpu_data.processor_id) &&
++ (read_c0_diag() & BRCM_PFC_AVAIL)) {
++ /*
++ * Now that the sbh is inited set the proper PFC value
++ */
++ printk("Setting the PFC to its default value\n");
++ enable_pfc(PFC_AUTO);
++ }
++
++
++#ifdef CONFIG_SERIAL
++ sb_serial_init(sbh, serial_add);
++
++ /* reverse serial ports if nvram variable starts with console=ttyS1 */
++ /* Initialize UARTs */
++ s = nvram_get("kernel_args");
++ if (!s) s = "";
++ if (!strncmp(s, "console=ttyS1", 13)) {
++ for (i = num_ports; i; i--)
++ do_serial_add(&ports[i - 1]);
++ } else {
++ for (i = 0; i < num_ports; i++)
++ do_serial_add(&ports[i]);
++ }
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
++ ide_ops = &std_ide_ops;
++#endif
++
++ /* Override default command line arguments */
++ value = nvram_get("kernel_cmdline");
++ if (value && strlen(value) && strncmp(value, "empty", 5))
++ strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
++
++
++ /* Generic setup */
++ _machine_restart = bcm947xx_machine_restart;
++ _machine_halt = bcm947xx_machine_halt;
++ _machine_power_off = bcm947xx_machine_halt;
++
++ board_time_init = bcm947xx_time_init;
++ board_timer_setup = bcm947xx_timer_setup;
++}
++
++const char *
++get_system_type(void)
++{
++ static char s[32];
++
++ if (bcm947xx_sbh) {
++ sprintf(s, "Broadcom BCM%X chip rev %d", sb_chip(bcm947xx_sbh),
++ sb_chiprev(bcm947xx_sbh));
++ return s;
++ }
++ else
++ return "Broadcom BCM947XX";
++}
++
++void __init
++bus_error_init(void)
++{
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/sflash.c linux.dev/arch/mips/bcm947xx/sflash.c
+--- linux.old/arch/mips/bcm947xx/sflash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sflash.c 2006-04-27 22:11:27.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sflash.c,v 1.1.1.13 2006/02/27 03:43:16 honor Exp $
++ */
++
++#include <osl.h>
++#include <typedefs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <mipsinc.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sflash.h>
++
++/* Private global state */
++static struct sflash sflash;
++
++/* Issue a serial flash command */
++static INLINE void
++sflash_cmd(chipcregs_t *cc, uint opcode)
++{
++ W_REG(NULL, &cc->flashcontrol, SFLASH_START | opcode);
++ while (R_REG(NULL, &cc->flashcontrol) & SFLASH_BUSY);
++}
++
++/* Initialize serial flash access */
++struct sflash *
++sflash_init(chipcregs_t *cc)
++{
++ uint32 id, id2;
++
++ bzero(&sflash, sizeof(sflash));
++
++ sflash.type = R_REG(NULL, &cc->capabilities) & CAP_FLASH_MASK;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Probe for ST chips */
++ sflash_cmd(cc, SFLASH_ST_DP);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id = R_REG(NULL, &cc->flashdata);
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 64;
++ break;
++ case 0x16:
++ /* ST M25P64 64 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 128;
++ break;
++ case 0xbf:
++ W_REG(NULL, &cc->flashaddress, 1);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id2 = R_REG(NULL, &cc->flashdata);
++ if (id2 == 0x44) {
++ /* SST M25VF80 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ }
++ break;
++ }
++ break;
++
++ case SFLASH_AT:
++ /* Probe for Atmel chips */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ id = R_REG(NULL, &cc->flashdata) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ sflash.blocksize = 1024;
++ sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ sflash.size = sflash.blocksize * sflash.numblocks;
++ return sflash.size ? &sflash : NULL;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int
++sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
++{
++ int cnt;
++ uint32 *from, *to;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((uint32)buf & 3))
++ cnt = 4 - ((uint32)buf & 3);
++ else
++ cnt = len;
++
++ from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
++ to = (uint32 *)buf;
++
++ if (cnt < 4) {
++ bcopy(from, to, cnt);
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *to++ = *from++;
++ cnt -= 4;
++ }
++
++ return (len - cnt);
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int
++sflash_poll(chipcregs_t *cc, uint offset)
++{
++ if (offset >= sflash.size)
++ return -22;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Check for ST Write In Progress bit */
++ sflash_cmd(cc, SFLASH_ST_RDSR);
++ return R_REG(NULL, &cc->flashdata) & SFLASH_ST_WIP;
++ case SFLASH_AT:
++ /* Check for Atmel Ready bit */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ return !(R_REG(NULL, &cc->flashdata) & SFLASH_AT_READY);
++ }
++
++ return 0;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int
++sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ int ret = 0;
++ bool is4712b0;
++ uint32 page, byte, mask;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ mask = R_REG(NULL, &cc->chipid);
++ is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) &&
++ ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
++ /* Enable writes */
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ W_REG(NULL, &cc->flashaddress, offset);
++ W_REG(NULL, &cc->flashdata, *buf++);
++ /* Set chip select */
++ OR_REG(NULL, &cc->gpioout, mask);
++ /* Issue a page program with the first byte */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ AND_REG(NULL, &cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -11;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs if needed */
++ if ((offset & 255) != 1) {
++ /* Drop cs */
++ AND_REG(NULL, &cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -12;
++ }
++ }
++ } else {
++ ret = 1;
++ W_REG(NULL, &cc->flashaddress, offset);
++ W_REG(NULL, &cc->flashdata, *buf);
++ /* Page program */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ }
++ break;
++ case SFLASH_AT:
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < sfl->blocksize)) {
++ W_REG(NULL, &cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ SPINWAIT(sflash_poll(cc, offset), 1000);
++ ASSERT(!sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
++ W_REG(NULL, &cc->flashaddress, byte++);
++ W_REG(NULL, &cc->flashdata, *buf++);
++ sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ W_REG(NULL, &cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int
++sflash_erase(chipcregs_t *cc, uint offset)
++{
++ struct sflash *sfl;
++
++ if (offset >= sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ W_REG(NULL, &cc->flashaddress, offset);
++ sflash_cmd(cc, SFLASH_ST_SE);
++ return sfl->blocksize;
++ case SFLASH_AT:
++ W_REG(NULL, &cc->flashaddress, offset << 1);
++ sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int
++sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ uchar *block = NULL, *cur_ptr, *blk_ptr;
++ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ uint blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &sflash;
++ if ((offset + len) > sfl->size)
++ return -1;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ if (!(block = MALLOC(NULL, blocksize)))
++ return -1;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while (blk_len) {
++ copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
++ goto done;
++ while (sflash_poll(cc, (uint) cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ if ((bytes = sflash_write(cc,
++ (uint) cur_offset,
++ (uint) cur_length,
++ (uchar *) cur_ptr)) < 0) {
++ ret = bytes;
++ goto done;
++ }
++ while (sflash_poll(cc, (uint) cur_offset));
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ if (block)
++ MFREE(NULL, block, blocksize);
++ return ret;
++}
+diff -urN linux.old/arch/mips/bcm947xx/time.c linux.dev/arch/mips/bcm947xx/time.c
+--- linux.old/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/time.c 2006-04-28 00:45:40.000000000 +0200
+@@ -0,0 +1,119 @@
++/*
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: time.c,v 1.1.1.10 2006/02/27 03:42:55 honor Exp $
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/serial_reg.h>
++#include <linux/interrupt.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/time.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbutils.h>
++#include <hndmips.h>
++#include <mipsinc.h>
++#include <hndcpu.h>
++
++/* Global SB handle */
++extern void *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++extern int panic_timeout;
++static int watchdog = 0;
++static u8 *mcr = NULL;
++
++void __init
++bcm947xx_time_init(void)
++{
++ unsigned int hz;
++ extifregs_t *eir;
++
++ /*
++ * Use deterministic values for initial counter interrupt
++ * so that calibrate delay avoids encountering a counter wrap.
++ */
++ write_c0_count(0);
++ write_c0_compare(0xffff);
++
++ if (!(hz = sb_cpu_clock(sbh)))
++ hz = 100000000;
++
++ printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
++ (hz + 500000) / 1000000);
++
++ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
++ mips_hpt_frequency = hz / 2;
++
++ /* Set watchdog interval in ms */
++ watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
++
++ /* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
++ if (watchdog > 0) {
++ if (watchdog < 3000)
++ watchdog = 3000;
++ }
++
++ /* Set panic timeout in seconds */
++ panic_timeout = watchdog / 1000;
++
++ /* Setup blink */
++ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
++ sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF);
++ unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1)));
++ mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1);
++ }
++}
++
++static void
++bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ /* Generic MIPS timer code */
++ timer_interrupt(irq, dev_id, regs);
++
++ /* Set the watchdog timer to reset after the specified number of ms */
++ if (watchdog > 0)
++ sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
++
++#ifdef CONFIG_HWSIM
++ (*((int *)0xa0000f1c))++;
++#else
++ /* Blink one of the LEDs in the external UART */
++ if (mcr && !(jiffies % (HZ/2)))
++ writeb(readb(mcr) ^ UART_MCR_OUT2, mcr);
++#endif
++}
++
++static struct irqaction bcm947xx_timer_irqaction = {
++ bcm947xx_timer_interrupt,
++ SA_INTERRUPT,
++ 0,
++ "timer",
++ NULL,
++ NULL
++};
++
++void __init
++bcm947xx_timer_setup(struct irqaction *irq)
++{
++ /* Enable the timer interrupt */
++ setup_irq(7, &bcm947xx_timer_irqaction);
++}
+diff -urN linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared.in
+--- linux.old/arch/mips/config-shared.in 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/config-shared.in 2006-04-27 19:24:19.000000000 +0200
+@@ -208,6 +208,14 @@
+ fi
+ define_bool CONFIG_MIPS_RTC y
+ fi
++dep_bool 'Support for Broadcom MIPS-based boards' CONFIG_MIPS_BRCM $CONFIG_EXPERIMENTAL
++dep_bool 'Support for Broadcom BCM947XX' CONFIG_BCM947XX $CONFIG_MIPS_BRCM
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ bool ' Support for Broadcom BCM4710' CONFIG_BCM4710
++ bool ' Support for Broadcom BCM4310' CONFIG_BCM4310
++ bool ' Support for Broadcom BCM4704' CONFIG_BCM4704
++ bool ' Support for Broadcom BCM5365' CONFIG_BCM5365
++fi
+ bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+ bool 'Support for TANBAC TB0226 (Mbase)' CONFIG_TANBAC_TB0226
+ bool 'Support for TANBAC TB0229 (VR4131DIMM)' CONFIG_TANBAC_TB0229
+@@ -229,6 +237,11 @@
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
+ #
++# Provide an option for a default kernel command line
++#
++string 'Default kernel command string' CONFIG_CMDLINE ""
++
++#
+ # Select some configuration options automatically based on user selections.
+ #
+ if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
+@@ -554,6 +567,13 @@
+ define_bool CONFIG_SWAP_IO_SPACE_L y
+ define_bool CONFIG_BOOT_ELF32 y
+ fi
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ define_bool CONFIG_PCI y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_NEW_TIME_C y
++ define_bool CONFIG_NEW_IRQ y
++ define_bool CONFIG_HND y
++fi
+ if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
+ define_bool CONFIG_ARC32 y
+ define_bool CONFIG_ARC_MEMORY y
+@@ -1042,7 +1062,11 @@
+
+ bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
+ bool 'Enable run-time debugging' CONFIG_RUNTIME_DEBUG
+-bool 'Remote GDB kernel debugging' CONFIG_KGDB
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
++else
++ bool 'Remote GDB kernel debugging' CONFIG_KGDB
++fi
+ dep_bool ' Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_KGDB
+ if [ "$CONFIG_KGDB" = "y" ]; then
+ define_bool CONFIG_DEBUG_INFO y
+diff -urN linux.old/arch/mips/kernel/cpu-probe.c linux.dev/arch/mips/kernel/cpu-probe.c
+--- linux.old/arch/mips/kernel/cpu-probe.c 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/kernel/cpu-probe.c 2006-04-27 19:24:19.000000000 +0200
+@@ -162,7 +162,7 @@
+
+ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
+ {
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_R2000:
+ c->cputype = CPU_R2000;
+ c->isa_level = MIPS_CPU_ISA_I;
+@@ -172,7 +172,7 @@
+ c->tlbsize = 64;
+ break;
+ case PRID_IMP_R3000:
+- if ((c->processor_id & 0xff) == PRID_REV_R3000A)
++ if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A)
+ if (cpu_has_confreg())
+ c->cputype = CPU_R3081E;
+ else
+@@ -187,12 +187,12 @@
+ break;
+ case PRID_IMP_R4000:
+ if (read_c0_config() & CONF_SC) {
+- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
++ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
+ c->cputype = CPU_R4400PC;
+ else
+ c->cputype = CPU_R4000PC;
+ } else {
+- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
++ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
+ c->cputype = CPU_R4400SC;
+ else
+ c->cputype = CPU_R4000SC;
+@@ -438,7 +438,7 @@
+ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_4KC:
+ c->cputype = CPU_4KC;
+ c->isa_level = MIPS_CPU_ISA_M32;
+@@ -479,10 +479,10 @@
+ {
+ decode_config1(c);
+ c->options |= MIPS_CPU_PREFETCH;
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_AU1_REV1:
+ case PRID_IMP_AU1_REV2:
+- switch ((c->processor_id >> 24) & 0xff) {
++ switch ((c->processor_id >> 24) & PRID_REV_MASK) {
+ case 0:
+ c->cputype = CPU_AU1000;
+ break;
+@@ -510,10 +510,34 @@
+ }
+ }
+
++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
++{
++ decode_config1(c);
++ c->options |= MIPS_CPU_PREFETCH;
++ switch (c->processor_id & PRID_IMP_MASK) {
++ case PRID_IMP_BCM4710:
++ c->cputype = CPU_BCM4710;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
++ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
++ break;
++ case PRID_IMP_4KC:
++ case PRID_IMP_BCM3302:
++ c->cputype = CPU_BCM3302;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
++ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
++ break;
++ default:
++ c->cputype = CPU_UNKNOWN;
++ break;
++ }
++}
++
+ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_SB1:
+ c->cputype = CPU_SB1;
+ c->isa_level = MIPS_CPU_ISA_M64;
+@@ -535,7 +559,7 @@
+ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_SR71000:
+ c->cputype = CPU_SR71000;
+ c->isa_level = MIPS_CPU_ISA_M64;
+@@ -560,7 +584,7 @@
+ c->cputype = CPU_UNKNOWN;
+
+ c->processor_id = read_c0_prid();
+- switch (c->processor_id & 0xff0000) {
++ switch (c->processor_id & PRID_COMP_MASK) {
+
+ case PRID_COMP_LEGACY:
+ cpu_probe_legacy(c);
+@@ -571,6 +595,9 @@
+ case PRID_COMP_ALCHEMY:
+ cpu_probe_alchemy(c);
+ break;
++ case PRID_COMP_BROADCOM:
++ cpu_probe_broadcom(c);
++ break;
+ case PRID_COMP_SIBYTE:
+ cpu_probe_sibyte(c);
+ break;
+diff -urN linux.old/arch/mips/kernel/head.S linux.dev/arch/mips/kernel/head.S
+--- linux.old/arch/mips/kernel/head.S 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/kernel/head.S 2006-04-27 19:24:19.000000000 +0200
+@@ -28,12 +28,20 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+
++#ifdef CONFIG_BCM4710
++#undef eret
++#define eret nop; nop; eret
++#endif
++
+ .text
++ j kernel_entry
++ nop
++
+ /*
+ * Reserved space for exception handlers.
+ * Necessary for machines which link their kernels at KSEG0.
+ */
+- .fill 0x400
++ .fill 0x3f4
+
+ /* The following two symbols are used for kernel profiling. */
+ EXPORT(stext)
+diff -urN linux.old/arch/mips/kernel/proc.c linux.dev/arch/mips/kernel/proc.c
+--- linux.old/arch/mips/kernel/proc.c 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/kernel/proc.c 2006-04-27 19:24:19.000000000 +0200
+@@ -78,9 +78,10 @@
+ [CPU_AU1550] "Au1550",
+ [CPU_24K] "MIPS 24K",
+ [CPU_AU1200] "Au1200",
++ [CPU_BCM4710] "BCM4710",
++ [CPU_BCM3302] "BCM3302",
+ };
+
+-
+ static int show_cpuinfo(struct seq_file *m, void *v)
+ {
+ unsigned int version = current_cpu_data.processor_id;
+diff -urN linux.old/arch/mips/kernel/setup.c linux.dev/arch/mips/kernel/setup.c
+--- linux.old/arch/mips/kernel/setup.c 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/kernel/setup.c 2006-04-27 19:24:19.000000000 +0200
+@@ -493,6 +493,7 @@
+ void swarm_setup(void);
+ void hp_setup(void);
+ void au1x00_setup(void);
++ void brcm_setup(void);
+ void frame_info_init(void);
+
+ frame_info_init();
+@@ -691,6 +692,11 @@
+ pmc_yosemite_setup();
+ break;
+ #endif
++#if defined(CONFIG_BCM4710) || defined(CONFIG_BCM4310)
++ case MACH_GROUP_BRCM:
++ brcm_setup();
++ break;
++#endif
+ default:
+ panic("Unsupported architecture");
+ }
+diff -urN linux.old/arch/mips/kernel/traps.c linux.dev/arch/mips/kernel/traps.c
+--- linux.old/arch/mips/kernel/traps.c 2006-04-27 18:04:37.000000000 +0200
++++ linux.dev/arch/mips/kernel/traps.c 2006-04-27 19:24:19.000000000 +0200
+@@ -920,6 +920,7 @@
+ void __init trap_init(void)
+ {
+ extern char except_vec1_generic;
++ extern char except_vec2_generic;
+ extern char except_vec3_generic, except_vec3_r4000;
+ extern char except_vec_ejtag_debug;
+ extern char except_vec4;
+@@ -927,6 +928,7 @@
+
+ /* Copy the generic exception handler code to it's final destination. */
+ memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
++ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
+
+ /*
+ * Setup default vectors
+@@ -985,6 +987,12 @@
+ set_except_vector(13, handle_tr);
+ set_except_vector(22, handle_mdmx);
+
++ if (current_cpu_data.cputype == CPU_SB1) {
++ /* Enable timer interrupt and scd mapped interrupt */
++ clear_c0_status(0xf000);
++ set_c0_status(0xc00);
++ }